Prechádzať zdrojové kódy

Merge pull request #1637 from causefx/v2-develop

V2 develop
causefx 5 rokov pred
rodič
commit
3853bf89c1
100 zmenil súbory, kde vykonal 3905 pridanie a 1861 odobranie
  1. 186 33
      api/classes/organizr.class.php
  2. 2 1
      api/composer.json
  3. 396 12
      api/composer.lock
  4. 12 0
      api/config/default.php
  5. 2 2
      api/functions/homepage-functions.php
  6. 6 1
      api/functions/normal-functions.php
  7. 10 0
      api/functions/organizr-functions.php
  8. 78 4
      api/functions/sso-functions.php
  9. 9 2
      api/homepage/calendar.php
  10. 9 2
      api/homepage/couchpotato.php
  11. 12 9
      api/homepage/deluge.php
  12. 9 2
      api/homepage/emby.php
  13. 9 2
      api/homepage/healthchecks.php
  14. 22 4
      api/homepage/html.php
  15. 19 12
      api/homepage/jackett.php
  16. 11 4
      api/homepage/jdownloader.php
  17. 9 2
      api/homepage/jellyfin.php
  18. 10 7
      api/homepage/lidarr.php
  19. 9 2
      api/homepage/misc.php
  20. 10 3
      api/homepage/monitorr.php
  21. 12 6
      api/homepage/netdata.php
  22. 35 2
      api/homepage/nzbget.php
  23. 9 2
      api/homepage/octoprint.php
  24. 9 2
      api/homepage/ombi.php
  25. 9 2
      api/homepage/pihole.php
  26. 36 5
      api/homepage/plex.php
  27. 9 2
      api/homepage/qbittorrent.php
  28. 10 7
      api/homepage/radarr.php
  29. 11 3
      api/homepage/rtorrent.php
  30. 48 3
      api/homepage/sabnzbd.php
  31. 9 2
      api/homepage/sickrage.php
  32. 10 7
      api/homepage/sonarr.php
  33. 10 3
      api/homepage/speedtest.php
  34. 9 2
      api/homepage/tautulli.php
  35. 10 3
      api/homepage/trakt.php
  36. 11 4
      api/homepage/transmission.php
  37. 17 10
      api/homepage/unifi.php
  38. 9 2
      api/homepage/weather.php
  39. 111 66
      api/pages/dependencies.php
  40. 1 1
      api/plugins/api/bookmark.php
  41. 50 17
      api/plugins/bookmark.php
  42. 1 1
      api/plugins/css/bookmark.css
  43. 3 3
      api/plugins/healthChecks.php
  44. 93 8
      api/plugins/js/bookmark-settings.js
  45. 0 9
      api/v2/routes/opencollective.php
  46. 2 6
      api/v2/routes/root.php
  47. 80 31
      api/v2/routes/socks.php
  48. 25 0
      api/v2/routes/sponsors.php
  49. 66 5
      api/vendor/composer/InstalledVersions.php
  50. 1 0
      api/vendor/composer/autoload_namespaces.php
  51. 5 0
      api/vendor/composer/autoload_psr4.php
  52. 38 0
      api/vendor/composer/autoload_static.php
  53. 411 9
      api/vendor/composer/installed.json
  54. 66 5
      api/vendor/composer/installed.php
  55. 2 2
      api/vendor/composer/platform_check.php
  56. 0 23
      api/vendor/guzzlehttp/guzzle/.php_cs
  57. 114 6
      api/vendor/guzzlehttp/guzzle/CHANGELOG.md
  58. 0 18
      api/vendor/guzzlehttp/guzzle/Dockerfile
  59. 1 1
      api/vendor/guzzlehttp/guzzle/LICENSE
  60. 20 31
      api/vendor/guzzlehttp/guzzle/README.md
  61. 53 3
      api/vendor/guzzlehttp/guzzle/UPGRADING.md
  62. 20 7
      api/vendor/guzzlehttp/guzzle/composer.json
  63. 87 0
      api/vendor/guzzlehttp/guzzle/psalm.baseline.xml
  64. 16 0
      api/vendor/guzzlehttp/guzzle/psalm.xml
  65. 93 131
      api/vendor/guzzlehttp/guzzle/src/Client.php
  66. 10 13
      api/vendor/guzzlehttp/guzzle/src/ClientInterface.php
  67. 241 0
      api/vendor/guzzlehttp/guzzle/src/ClientTrait.php
  68. 63 66
      api/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
  69. 9 11
      api/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
  70. 28 18
      api/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
  71. 20 15
      api/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
  72. 91 84
      api/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
  73. 21 9
      api/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
  74. 1 0
      api/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php
  75. 29 10
      api/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
  76. 4 18
      api/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php
  77. 29 57
      api/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
  78. 0 27
      api/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
  79. 1 0
      api/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
  80. 1 0
      api/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
  81. 1 0
      api/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php
  82. 167 152
      api/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
  83. 3 5
      api/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
  84. 13 9
      api/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php
  85. 81 42
      api/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
  86. 41 14
      api/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
  87. 71 50
      api/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
  88. 14 10
      api/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
  89. 154 123
      api/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
  90. 66 72
      api/vendor/guzzlehttp/guzzle/src/HandlerStack.php
  91. 48 32
      api/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
  92. 22 0
      api/vendor/guzzlehttp/guzzle/src/MessageFormatterInterface.php
  93. 53 48
      api/vendor/guzzlehttp/guzzle/src/Middleware.php
  94. 21 22
      api/vendor/guzzlehttp/guzzle/src/Pool.php
  95. 11 15
      api/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
  96. 35 54
      api/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
  97. 32 31
      api/vendor/guzzlehttp/guzzle/src/RequestOptions.php
  98. 32 42
      api/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
  99. 30 21
      api/vendor/guzzlehttp/guzzle/src/TransferStats.php
  100. 0 237
      api/vendor/guzzlehttp/guzzle/src/UriTemplate.php

+ 186 - 33
api/classes/organizr.class.php

@@ -60,7 +60,7 @@ class Organizr
 	
 	// ===================================
 	// Organizr Version
-	public $version = '2.1.235';
+	public $version = '2.1.306';
 	// ===================================
 	// Quick php Version check
 	public $minimumPHP = '7.2';
@@ -220,7 +220,8 @@ class Organizr
 			if ($group !== null) {
 				if ((isset($_SERVER['HTTP_X_FORWARDED_SERVER']) && $_SERVER['HTTP_X_FORWARDED_SERVER'] == 'traefik') || $this->config['traefikAuthEnable']) {
 					$return = (isset($_SERVER['HTTP_X_FORWARDED_HOST']) && isset($_SERVER['HTTP_X_FORWARDED_URI']) && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) ? '?return=' . $_SERVER['HTTP_X_FORWARDED_PROTO'] . '://' . $_SERVER['HTTP_X_FORWARDED_HOST'] . $_SERVER['HTTP_X_FORWARDED_URI'] : '';
-					$redirect = 'Location: ' . $this->getServerPath() . $return;
+					$redirectDomain = ($this->config['traefikDomainOverride'] !== '') ? $this->config['traefikDomainOverride'] : $this->getServerPath();
+					$redirect = 'Location: ' . $redirectDomain . $return;
 				}
 				if ($this->qualifyRequest($group) && $unlocked) {
 					header("X-Organizr-User: $currentUser");
@@ -276,13 +277,13 @@ class Organizr
 	{
 		switch ($request->getMethod()) {
 			case 'POST':
-				if ($request->getHeaderLine('Content-Type') == 'application/json') {
+				if (stripos($request->getHeaderLine('Content-Type'), 'application/json') !== false) {
 					return json_decode(file_get_contents('php://input', 'r'), true);
 				} else {
 					return $request->getParsedBody();
 				}
 			default:
-				if ($request->getHeaderLine('Content-Type') == 'application/json') {
+				if (stripos($request->getHeaderLine('Content-Type'), 'application/json') !== false) {
 					return json_decode(file_get_contents('php://input', 'r'), true);
 				} else {
 					return null;
@@ -422,6 +423,7 @@ class Organizr
 		switch ($type) {
 			case 'js':
 				foreach (glob(dirname(__DIR__, 1) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR . '*.js') as $filename) {
+					$pluginEnabled = false;
 					$keyOriginal = strtoupper(basename($filename, '.js'));
 					$key = str_replace('-SETTINGS', '', $keyOriginal);
 					$continue = false;
@@ -438,15 +440,22 @@ class Organizr
 						case 'PHP-MAILER':
 							$key = 'PHPMAILER';
 							break;
+						case 'NGXC':
+							$key = 'ngxc';
+							break;
 						default:
 							$key = $key;
 					}
-					if ($this->config[$key . '-enabled'] || $settings) {
+					if (isset($this->config[$key . '-enabled'])) {
+						if ($this->config[$key . '-enabled']) {
+							$pluginEnabled = true;
+						}
+					}
+					if ($pluginEnabled || $settings) {
 						if ($continue) {
 							$files .= '<script src="api/plugins/js/' . basename($filename) . '?v=' . $this->fileHash . '" defer="true"></script>';
 						}
 					}
-					
 				}
 				break;
 			case 'css':
@@ -802,6 +811,7 @@ class Organizr
 		$status['version'] = $this->version;
 		$status['os'] = $this->getOS();
 		$status['php'] = phpversion();
+		$status['php_user'] = get_current_user();
 		$status['userConfigPath'] = $this->userConfigPath;
 		return $status;
 	}
@@ -1967,6 +1977,12 @@ class Organizr
 					'value' => $this->config['lockoutTimeout'],
 					'placeholder' => ''
 				),
+				array(
+					'type' => 'switch',
+					'name' => 'lockoutSystem',
+					'label' => 'Inactivity Lock',
+					'value' => $this->config['lockoutSystem']
+				),
 				array(
 					'type' => 'select',
 					'name' => 'lockoutMinAuth',
@@ -1983,9 +1999,18 @@ class Organizr
 				),
 				array(
 					'type' => 'switch',
-					'name' => 'lockoutSystem',
-					'label' => 'Inactivity Lock',
-					'value' => $this->config['lockoutSystem']
+					'name' => 'traefikAuthEnable',
+					'label' => 'Enable Traefik Auth Redirect',
+					'help' => 'This will enable the webserver to forward errors so traefik will accept them',
+					'value' => $this->config['traefikAuthEnable']
+				),
+				array(
+					'type' => 'input',
+					'name' => 'traefikDomainOverride',
+					'label' => 'Traefik Domain for Return Override',
+					'value' => $this->config['traefikDomainOverride'],
+					'help' => 'Please use a FQDN on this URL Override',
+					'placeholder' => 'http(s)://domain'
 				),
 				array(
 					'type' => 'select',
@@ -1994,14 +2019,6 @@ class Organizr
 					'value' => $this->config['debugAreaAuth'],
 					'options' => $this->groupSelect()
 				),
-				array(
-					'type' => 'switch',
-					'name' => 'authDebug',
-					'label' => 'Nginx Auth Debug',
-					'help' => 'Important! Do not keep this enabled for too long as this opens up Authentication while testing.',
-					'value' => $this->config['authDebug'],
-					'class' => 'authDebug'
-				),
 				array(
 					'type' => 'select2',
 					'class' => 'select2-multiple',
@@ -2047,14 +2064,7 @@ class Organizr
 							'value' => 'allow-downloads'
 						),
 					)
-				),
-				array(
-					'type' => 'switch',
-					'name' => 'traefikAuthEnable',
-					'label' => 'Enable Traefik Auth Redirect',
-					'help' => 'This will enable the webserver to forward errors so traefik will accept them',
-					'value' => $this->config['traefikAuthEnable']
-				),
+				)
 			),
 			'Performance' => array(
 				array(
@@ -2381,6 +2391,41 @@ class Organizr
 					'value' => $this->config['ssoOverseerr']
 				)
 			),
+			'Petio' => array(
+				array(
+					'type' => 'input',
+					'name' => 'petioURL',
+					'label' => 'Petio URL',
+					'value' => $this->config['petioURL'],
+					'help' => 'Please make sure to use local IP address and port - You also may use local dns name too.',
+					'placeholder' => 'http(s)://hostname:port'
+				),
+				array(
+					'type' => 'password-alt',
+					'name' => 'petioToken',
+					'label' => 'Token',
+					'value' => $this->config['petioToken']
+				),
+				array(
+					'type' => 'input',
+					'name' => 'petioFallbackUser',
+					'label' => 'Petio Fallback User',
+					'value' => $this->config['petioFallbackUser'],
+					'help' => 'Organizr will request an Petio User Token based off of this user credentials',
+				),
+				array(
+					'type' => 'password-alt',
+					'name' => 'petioFallbackPassword',
+					'label' => 'Petio Fallback Password',
+					'value' => $this->config['petioFallbackPassword'],
+				),
+				array(
+					'type' => 'switch',
+					'name' => 'ssoPetio',
+					'label' => 'Enable',
+					'value' => $this->config['ssoPetio']
+				)
+			),
 			'Ombi' => array(
 				array(
 					'type' => 'input',
@@ -3137,9 +3182,10 @@ class Organizr
 		$this->coookie('delete', 'mpt');
 		$this->coookie('delete', 'Auth');
 		$this->coookie('delete', 'oAuth');
-		$this->coookie('delete', 'jellyfin_credentials');
 		$this->coookie('delete', 'connect.sid');
+		$this->coookie('delete', 'petio_jwt');
 		$this->clearTautulliTokens();
+		$this->clearJellyfinTokens();
 		$this->revokeTokenCurrentUser($this->user['token']);
 		$this->user = null;
 		return true;
@@ -3984,7 +4030,9 @@ class Organizr
 		$items = $this->getSettingsHomepage();
 		foreach ($items as $k => $v) {
 			if (strtolower($v['name']) === strtolower($item)) {
-				return $v;
+				$functionName = $v['settingsArray'];
+				return $this->$functionName();
+				
 			}
 		}
 		$this->setAPIResponse('error', 'Homepage item was not found', 404);
@@ -4926,6 +4974,9 @@ class Organizr
 		$response = Requests::get($url, array(), $options);
 		if ($response->success) {
 			$api = json_decode($response->body, true);
+			foreach ($api as $k => $backer) {
+				$api[$k] = array_merge($api[$k], ['sortName' => strtolower($backer['name'])]);
+			}
 			$this->setAPIResponse('success', '', 200, $api);
 			return $api;
 		}
@@ -4933,6 +4984,64 @@ class Organizr
 		return false;
 	}
 	
+	public function getGithubSponsors()
+	{
+		$url = 'https://github.com/sponsors/causefx';
+		$options = ($this->localURL($url)) ? array('verify' => false) : array();
+		$response = Requests::get($url, array(), $options);
+		if ($response->success) {
+			$sponsors = [];
+			$dom = new PHPHtmlParser\Dom;
+			try {
+				$dom->loadStr($response->body);
+				$contents = $dom->find('#sponsors .clearfix div');
+				foreach ($contents as $content) {
+					$html = $content->innerHtml;
+					preg_match('/(@[a-zA-Z])\w+/', $html, $username);
+					preg_match('/(?i)\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'\".,<>?«»“”‘’]))/', $html, $image);
+					if (isset($image[0]) && isset($username[0])) {
+						$sponsors[] = [
+							'name' => str_replace('@', '', $username[0]),
+							'sortName' => str_replace('@', '', strtolower($username[0])),
+							'image' => str_replace('s=60', 's=200', $image[0]),
+							'isActive' => true,
+							'type' => 'USER',
+							'role' => 'BACKER'
+						];
+					}
+				}
+				$this->setAPIResponse('success', '', 200, $sponsors);
+				return $sponsors;
+			} catch (\PHPHtmlParser\Exceptions\ChildNotFoundException | \PHPHtmlParser\Exceptions\CircularException | \PHPHtmlParser\Exceptions\LogicalException | \PHPHtmlParser\Exceptions\StrictException | \PHPHtmlParser\Exceptions\ContentLengthException | \PHPHtmlParser\Exceptions\NotLoadedException $e) {
+				$this->setAPIResponse('error', 'Error connecting to Github', 409);
+				return false;
+			}
+		}
+		$this->setAPIResponse('error', 'Error connecting to Github', 409);
+		return false;
+	}
+	
+	public function getAllSponsors()
+	{
+		$sponsors = [];
+		$list = [
+			'openCollective' => $this->getOpenCollectiveBackers(),
+			'github' => $this->getGithubSponsors()
+		];
+		foreach ($list as $k => $sponsor) {
+			if ($sponsor) {
+				$sponsors = array_merge($sponsor, $sponsors);
+			}
+		}
+		if ($sponsors) {
+			usort($sponsors, function ($a, $b) {
+				return $a['sortName'] <=> $b['sortName'];
+			});
+		}
+		$this->setAPIResponse('success', '', 200, $sponsors);
+		return $sponsors;
+	}
+	
 	public function getOrganizrSmtpFromAPI()
 	{
 		$url = 'https://api.organizr.app/?cmd=smtp';
@@ -4958,7 +5067,7 @@ class Organizr
 	
 	public function guestHash($start, $end)
 	{
-		$ip = $_SERVER['REMOTE_ADDR'];
+		$ip = $this->userIP();
 		$ip = md5($ip);
 		return substr($ip, $start, $end);
 	}
@@ -5930,7 +6039,20 @@ class Organizr
 		}
 	}
 	
-	public function socks($url, $enabled, $auth, $requestObject, $header = null)
+	public function socksHeadingHTML($app)
+	{
+		return '
+		<h3 lang="en">' . ucwords($app) . ' SOCKS API Connection</h3>
+		<p>Using this feature allows you to access the API without having to reverse proxy it.  Just access it from: </p>
+		<code>' . $this->getServerPath() . 'api/v2/socks/' . $app . '/</code>
+		<p>If you are using multiple URL\'s (using the csv method) you will have to use the url like these: </p>
+		<code>' . $this->getServerPath() . 'api/v2/multiple/socks/' . $app . '/1</code>
+		<br/>
+		<code>' . $this->getServerPath() . 'api/v2/multiple/socks/' . $app . '/2</code>
+		';
+	}
+	
+	public function socks($url, $enabled, $auth, $requestObject, $header = null, $multiple = null)
 	{
 		$error = false;
 		if (!$this->config[$enabled]) {
@@ -5940,14 +6062,35 @@ class Organizr
 		if (!$this->qualifyRequest($this->config[$auth], true)) {
 			$error = true;
 		}
+		if (strpos($this->config[$url], ',') !== false) {
+			if (!$multiple) {
+				$error = true;
+				$this->setAPIResponse('error', 'Multiple URLs found in field, please use /api/v2/multiple/socks endpoint', 409);
+			}
+		} else {
+			if ($multiple) {
+				$error = true;
+				$this->setAPIResponse('error', 'Multiple endpoint accessed but multiple URLs not found in field, please use /api/v2/socks endpoint', 409);
+			}
+		}
 		if (!$error) {
-			$pre = explode('/api/v2/socks/', $requestObject->getUri()->getPath());
+			if ($multiple) {
+				$instance = $multiple - 1;
+				$pre = explode('/api/v2/multiple/socks/', $requestObject->getUri()->getPath());
+				$pre[1] = $this->replace_first('/' . $multiple . '/', '/', $pre[1]);
+				// sent url twice since we arent using tokens
+				$list = $this->csvHomepageUrlToken($this->config[$url], $this->config[$url]);
+				$appURL = $list[$instance]['url'];
+			} else {
+				$pre = explode('/api/v2/socks/', $requestObject->getUri()->getPath());
+				$appURL = $this->config[$url];
+			}
 			$endpoint = explode('/', $pre[1]);
-			$new = str_ireplace($endpoint[0], '', $pre[1]);
+			$new = urldecode(preg_replace('/' . $endpoint[0] . '/', '', $pre[1], 1));
 			$getParams = ($_GET) ? '?' . http_build_query($_GET) : '';
-			$url = $this->qualifyURL($this->config[$url]) . $new . $getParams;
+			$url = $this->qualifyURL($appURL) . $new . $getParams;
 			$url = $this->cleanPath($url);
-			$options = ($this->localURL($url)) ? array('verify' => false) : array();
+			$options = ($this->localURL($appURL)) ? array('verify' => false, 'timeout' => 120) : array('timeout' => 120);
 			$headers = [];
 			$apiData = $this->json_validator($this->apiData($requestObject)) ? json_encode($this->apiData($requestObject)) : $this->apiData($requestObject);
 			if ($header) {
@@ -5956,6 +6099,16 @@ class Organizr
 					$headers[$header] = $headerKey;
 				}
 			}
+			$debugInformation = [
+				'type' => $requestObject->getMethod(),
+				'headerType' => $requestObject->getHeaderLine('Content-Type'),
+				'header' => $header,
+				'headers' => $headers,
+				'url' => $url,
+				'options' => $options,
+				'data' => $apiData
+			];
+			//$this->debug(json_encode($debugInformation));
 			switch ($requestObject->getMethod()) {
 				case 'GET':
 					$call = Requests::get($url, $headers, $options);

+ 2 - 1
api/composer.json

@@ -15,6 +15,7 @@
     "slim/slim": "^4.0",
     "slim/psr7": "^1.1",
     "zircote/swagger-php": "^3.0",
-    "bogstag/oauth2-trakt": "^1.0"
+    "bogstag/oauth2-trakt": "^1.0",
+    "paquettg/php-html-parser": "^3.1"
   }
 }

+ 396 - 12
api/composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "1620f8d6a2da9fd3302c753d432b19bc",
+    "content-hash": "6c33c6a831d0034c65fe02a8df137f7c",
     "packages": [
         {
             "name": "adldap2/adldap2",
@@ -440,37 +440,43 @@
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "6.5.2",
+            "version": "7.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "43ece0e75098b7ecd8d13918293029e555a50f82"
+                "reference": "7427d6f99df41cc01f33cd59832f721c150ffdf3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82",
-                "reference": "43ece0e75098b7ecd8d13918293029e555a50f82",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7427d6f99df41cc01f33cd59832f721c150ffdf3",
+                "reference": "7427d6f99df41cc01f33cd59832f721c150ffdf3",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "guzzlehttp/promises": "^1.0",
                 "guzzlehttp/psr7": "^1.6.1",
-                "php": ">=5.5"
+                "php": "^7.2.5",
+                "psr/http-client": "^1.0"
+            },
+            "provide": {
+                "psr/http-client-implementation": "1.0"
             },
             "require-dev": {
                 "ext-curl": "*",
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+                "php-http/client-integration-tests": "dev-phpunit8",
+                "phpunit/phpunit": "^8.5.5",
                 "psr/log": "^1.1"
             },
             "suggest": {
+                "ext-curl": "Required for CURL handler support",
                 "ext-intl": "Required for Internationalized Domain Name (IDN) support",
                 "psr/log": "Required for using the Log middleware"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "6.5-dev"
+                    "dev-master": "7.1-dev"
                 }
             },
             "autoload": {
@@ -490,6 +496,11 @@
                     "name": "Michael Dowling",
                     "email": "mtdowling@gmail.com",
                     "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://sagikazarmark.hu"
                 }
             ],
             "description": "Guzzle is a PHP HTTP client library",
@@ -500,10 +511,34 @@
                 "framework",
                 "http",
                 "http client",
+                "psr-18",
+                "psr-7",
                 "rest",
                 "web service"
             ],
-            "time": "2019-12-23T11:57:10+00:00"
+            "support": {
+                "issues": "https://github.com/guzzle/guzzle/issues",
+                "source": "https://github.com/guzzle/guzzle/tree/7.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/Nyholm",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/alexeyshockov",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/gmponos",
+                    "type": "github"
+                }
+            ],
+            "time": "2020-09-30T08:51:17+00:00"
         },
         {
             "name": "guzzlehttp/promises",
@@ -686,7 +721,7 @@
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/guzzle": "^6.1"
+                "guzzlehttp/guzzle": "^6.0 || ^7.0"
             },
             "type": "library",
             "autoload": {
@@ -722,7 +757,7 @@
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/guzzle": "^6.1"
+                "guzzlehttp/guzzle": "^6.0 || ^7.0"
             },
             "type": "library",
             "autoload": {
@@ -758,7 +793,7 @@
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/guzzle": "^6.1"
+                "guzzlehttp/guzzle": "^6.0 || ^7.0"
             },
             "type": "library",
             "autoload": {
@@ -904,6 +939,66 @@
             },
             "time": "2020-10-28T02:03:40+00:00"
         },
+        {
+            "name": "myclabs/php-enum",
+            "version": "1.8.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/php-enum.git",
+                "reference": "46cf3d8498b095bd33727b13fd5707263af99421"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/46cf3d8498b095bd33727b13fd5707263af99421",
+                "reference": "46cf3d8498b095bd33727b13fd5707263af99421",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "php": "^7.3 || ^8.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5",
+                "squizlabs/php_codesniffer": "1.*",
+                "vimeo/psalm": "^4.5.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "MyCLabs\\Enum\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP Enum contributors",
+                    "homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
+                }
+            ],
+            "description": "PHP Enum implementation",
+            "homepage": "http://github.com/myclabs/php-enum",
+            "keywords": [
+                "enum"
+            ],
+            "support": {
+                "issues": "https://github.com/myclabs/php-enum/issues",
+                "source": "https://github.com/myclabs/php-enum/tree/1.8.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/mnapoli",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2021-02-15T16:11:48+00:00"
+        },
         {
             "name": "nikic/fast-route",
             "version": "v1.3.0",
@@ -950,6 +1045,124 @@
             ],
             "time": "2018-02-13T20:26:39+00:00"
         },
+        {
+            "name": "paquettg/php-html-parser",
+            "version": "3.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paquettg/php-html-parser.git",
+                "reference": "4e01a438ad5961cc2d7427eb9798d213c8a12629"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paquettg/php-html-parser/zipball/4e01a438ad5961cc2d7427eb9798d213c8a12629",
+                "reference": "4e01a438ad5961cc2d7427eb9798d213c8a12629",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "ext-mbstring": "*",
+                "ext-zlib": "*",
+                "guzzlehttp/guzzle": "^7.0",
+                "guzzlehttp/psr7": "^1.6",
+                "myclabs/php-enum": "^1.7",
+                "paquettg/string-encode": "~1.0.0",
+                "php": ">=7.2",
+                "php-http/httplug": "^2.1"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^2.16",
+                "infection/infection": "^0.13.4",
+                "mockery/mockery": "^1.2",
+                "phan/phan": "^2.4",
+                "phpunit/phpunit": "^7.5.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "PHPHtmlParser\\": "src/PHPHtmlParser"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gilles Paquette",
+                    "email": "paquettg@gmail.com",
+                    "homepage": "http://gillespaquette.ca"
+                }
+            ],
+            "description": "An HTML DOM parser. It allows you to manipulate HTML. Find tags on an HTML page with selectors just like jQuery.",
+            "homepage": "https://github.com/paquettg/php-html-parser",
+            "keywords": [
+                "dom",
+                "html",
+                "parser"
+            ],
+            "support": {
+                "issues": "https://github.com/paquettg/php-html-parser/issues",
+                "source": "https://github.com/paquettg/php-html-parser/tree/3.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/paquettg/php-html-parser",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-11-01T20:34:43+00:00"
+        },
+        {
+            "name": "paquettg/string-encode",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paquettg/string-encoder.git",
+                "reference": "a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paquettg/string-encoder/zipball/a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee",
+                "reference": "a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7.5.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "stringEncode": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gilles Paquette",
+                    "email": "paquettg@gmail.com",
+                    "homepage": "http://gillespaquette.ca"
+                }
+            ],
+            "description": "Facilitating the process of altering string encoding in PHP.",
+            "homepage": "https://github.com/paquettg/string-encoder",
+            "keywords": [
+                "charset",
+                "encoding",
+                "string"
+            ],
+            "support": {
+                "issues": "https://github.com/paquettg/string-encoder/issues",
+                "source": "https://github.com/paquettg/string-encoder/tree/1.0.1"
+            },
+            "time": "2018-12-21T02:25:09+00:00"
+        },
         {
             "name": "paragonie/constant_time_encoding",
             "version": "v2.2.2",
@@ -1139,6 +1352,125 @@
             ],
             "time": "2018-08-29T22:02:48+00:00"
         },
+        {
+            "name": "php-http/httplug",
+            "version": "2.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-http/httplug.git",
+                "reference": "191a0a1b41ed026b717421931f8d3bd2514ffbf9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-http/httplug/zipball/191a0a1b41ed026b717421931f8d3bd2514ffbf9",
+                "reference": "191a0a1b41ed026b717421931f8d3bd2514ffbf9",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0",
+                "php-http/promise": "^1.1",
+                "psr/http-client": "^1.0",
+                "psr/http-message": "^1.0"
+            },
+            "require-dev": {
+                "friends-of-phpspec/phpspec-code-coverage": "^4.1",
+                "phpspec/phpspec": "^5.1 || ^6.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Http\\Client\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Eric GELOEN",
+                    "email": "geloen.eric@gmail.com"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://sagikazarmark.hu"
+                }
+            ],
+            "description": "HTTPlug, the HTTP client abstraction for PHP",
+            "homepage": "http://httplug.io",
+            "keywords": [
+                "client",
+                "http"
+            ],
+            "support": {
+                "issues": "https://github.com/php-http/httplug/issues",
+                "source": "https://github.com/php-http/httplug/tree/master"
+            },
+            "time": "2020-07-13T15:43:23+00:00"
+        },
+        {
+            "name": "php-http/promise",
+            "version": "1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-http/promise.git",
+                "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-http/promise/zipball/4c4c1f9b7289a2ec57cde7f1e9762a5789506f88",
+                "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "friends-of-phpspec/phpspec-code-coverage": "^4.3.2",
+                "phpspec/phpspec": "^5.1.2 || ^6.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Http\\Promise\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Joel Wurtz",
+                    "email": "joel.wurtz@gmail.com"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com"
+                }
+            ],
+            "description": "Promise used for asynchronous HTTP requests",
+            "homepage": "http://httplug.io",
+            "keywords": [
+                "promise"
+            ],
+            "support": {
+                "issues": "https://github.com/php-http/promise/issues",
+                "source": "https://github.com/php-http/promise/tree/1.1.0"
+            },
+            "time": "2020-07-07T09:29:14+00:00"
+        },
         {
             "name": "phpmailer/phpmailer",
             "version": "v6.2.0",
@@ -1325,6 +1657,58 @@
             ],
             "time": "2017-02-14T16:28:37+00:00"
         },
+        {
+            "name": "psr/http-client",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-client.git",
+                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0 || ^8.0",
+                "psr/http-message": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Client\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP clients",
+            "homepage": "https://github.com/php-fig/http-client",
+            "keywords": [
+                "http",
+                "http-client",
+                "psr",
+                "psr-18"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-client/tree/master"
+            },
+            "time": "2020-06-29T06:28:15+00:00"
+        },
         {
             "name": "psr/http-factory",
             "version": "1.0.1",

+ 12 - 0
api/config/default.php

@@ -58,11 +58,16 @@ return array(
 	'overseerrToken' => '',
 	'overseerrFallbackUser' => '',
 	'overseerrFallbackPassword' => '',
+	'petioURL' => '',
+	'petioToken' => '',
+	'petioFallbackUser' => '',
+	'petioFallbackPassword' => '',
 	'ssoPlex' => false,
 	'ssoOmbi' => false,
 	'ssoTautulli' => false,
 	'ssoJellyfin' => false,
 	'ssoOverseerr' => false,
+	'ssoPetio' => false,
 	'sonarrURL' => '',
 	'sonarrUnmonitored' => false,
 	'sonarrToken' => '',
@@ -88,10 +93,14 @@ return array(
 	'jdownloaderCombine' => false,
 	'sabnzbdURL' => '',
 	'sabnzbdToken' => '',
+	'sabnzbdSocksEnabled' => false,
+	'sabnzbdSocksAuth' => '999',
 	'sabnzbdCombine' => false,
 	'nzbgetURL' => '',
 	'nzbgetUsername' => '',
 	'nzbgetPassword' => '',
+	'nzbgetSocksEnabled' => false,
+	'nzbgetSocksAuth' => '999',
 	'nzbgetCombine' => false,
 	'transmissionURL' => '',
 	'transmissionUsername' => '',
@@ -241,10 +250,12 @@ return array(
 	'homepagePlexStreamsAuth' => '1',
 	'homepagePlexStreamsExclude' => '',
 	'homepagePlexRecent' => false,
+	'homepagePlexRecentExclude' => '',
 	'homepageRecentLimit' => '50',
 	'homepagePlexRecentAuth' => '1',
 	'homepagePlexPlaylist' => false,
 	'homepagePlexPlaylistAuth' => '1',
+	'homepagePlexSearchExclude' => '',
 	'homepageEmbyStreams' => false,
 	'homepageEmbyStreamsAuth' => '1',
 	'homepageEmbyRecent' => false,
@@ -340,6 +351,7 @@ return array(
 	'performanceDisableIconDropdown' => false,
 	'performanceDisableImageDropdown' => false,
 	'traefikAuthEnable' => false,
+	'traefikDomainOverride' => '',
 	'homepageTautulliEnabled' => false,
 	'homepageTautulliAuth' => '1',
 	'homepageTautulliLibraryAuth' => '1',

+ 2 - 2
api/functions/homepage-functions.php

@@ -16,7 +16,7 @@ trait HomepageFunctions
 		$list = $this->getHomepageSettingsList();
 		$combined = [];
 		foreach ($list as $item) {
-			$combined[] = $this->$item();
+			$combined[] = $this->$item(true);
 		}
 		return $combined;
 	}
@@ -95,4 +95,4 @@ trait HomepageFunctions
 		}
 		return true;
 	}
-}
+}

+ 6 - 1
api/functions/normal-functions.php

@@ -557,6 +557,11 @@ trait NormalFunctions
 		}
 		return false;
 	}
+	
+	public function replace_first($search_str, $replacement_str, $src_str)
+	{
+		return (false !== ($pos = strpos($src_str, $search_str))) ? substr_replace($src_str, $replacement_str, $pos, strlen($search_str)) : $src_str;
+	}
 }
 
 // Leave for deluge class
@@ -737,4 +742,4 @@ function utf8ize($mixed)
 		return mb_convert_encoding($mixed, "UTF-8", "UTF-8");
 	}
 	return $mixed;
-}
+}

+ 10 - 0
api/functions/organizr-functions.php

@@ -573,6 +573,16 @@ trait OrganizrFunctions
 		}
 	}
 	
+	public function clearJellyfinTokens()
+	{
+		foreach (array_keys($_COOKIE) as $k => $v) {
+			if (strpos($v, 'user-') !== false) {
+				$this->coookie('delete', $v);
+			}
+		}
+		$this->coookie('delete', 'jellyfin_credentials');
+	}
+	
 	public function analyzeIP($ip)
 	{
 		if (strpos($ip, '/') !== false) {

+ 78 - 4
api/functions/sso-functions.php

@@ -2,13 +2,33 @@
 
 trait SSOFunctions
 {
+	public function ssoCookies()
+	{
+		$cookies = array(
+			'myPlexAccessToken' => isset($_COOKIE['mpt']) ? $_COOKIE['mpt'] : false,
+			'id_token' => isset($_COOKIE['Auth']) ? $_COOKIE['Auth'] : false,
+			'jellyfin_credentials' => isset($_COOKIE['jellyfin_credentials']) ? $_COOKIE['jellyfin_credentials'] : false,
+		);
+		// Jellyfin cookie
+		foreach (array_keys($_COOKIE) as $k => $v) {
+			if (strpos($v, 'user-') !== false) {
+				$cookiesToAdd = [
+					$v => $_COOKIE[$v]
+				];
+				$cookies = array_merge($cookies, $cookiesToAdd);
+			}
+		}
+		return $cookies;
+	}
+	
 	public function getSSOUserFor($app, $userobj)
 	{
 		$map = array(
 			'jellyfin' => 'username',
 			'ombi' => 'username',
 			'overseerr' => 'username',
-			'tautulli' => 'username'
+			'tautulli' => 'username',
+			'petio' => 'username'
 		);
 		return (gettype($userobj) == 'string') ? $userobj : $userobj[$map[$app]];
 	}
@@ -36,7 +56,9 @@ trait SSOFunctions
 		if ($this->config['ssoJellyfin']) {
 			$jellyfinToken = $this->getJellyfinToken($this->getSSOUserFor('jellyfin', $userobj), $password);
 			if ($jellyfinToken) {
-				$this->coookie('set', 'jellyfin_credentials', $jellyfinToken, $this->config['rememberMeDays'], false);
+				foreach ($jellyfinToken as $k => $v) {
+					$this->coookie('set', $k, $v, $this->config['rememberMeDays'], false);
+				}
 			}
 		}
 		if ($this->config['ssoOverseerr']) {
@@ -45,6 +67,13 @@ trait SSOFunctions
 				$this->coookie('set', 'connect.sid', $overseerrToken, $this->config['rememberMeDays'], false);
 			}
 		}
+		if ($this->config['ssoPetio']) {
+			$fallback = ($this->config['petioFallbackUser'] !== '' && $this->config['petioFallbackPassword'] !== '');
+			$petioToken = $this->getPetioToken($this->getSSOUserFor('petio', $userobj), $password, $token, $fallback);
+			if ($petioToken) {
+				$this->coookie('set', 'petio_jwt', $petioToken, $this->config['rememberMeDays'], false);
+			}
+		}
 		return true;
 	}
 	
@@ -69,7 +98,10 @@ trait SSOFunctions
 			if ($response->success) {
 				$token = json_decode($response->body, true);
 				$this->writeLog('success', 'Jellyfin Token Function - Grabbed token.', $username);
-				return '{"Servers":[{"ManualAddress":"' . $ssoUrl . '","Id":"' . $token['ServerId'] . '","UserId":"' . $token['User']['Id'] . '","AccessToken":"' . $token['AccessToken'] . '"}]}';
+				$key = 'user-' . $token['User']['Id'] . '-' . $token['ServerId'];
+				$jellyfin[$key] = json_encode($token['User']);
+				$jellyfin['jellyfin_credentials'] = '{"Servers":[{"ManualAddress":"' . $ssoUrl . '","Id":"' . $token['ServerId'] . '","UserId":"' . $token['User']['Id'] . '","AccessToken":"' . $token['AccessToken'] . '"}]}';
+				return $jellyfin;
 			} else {
 				$this->writeLog('error', 'Jellyfin Token Function - Jellyfin did not return Token', $username);
 			}
@@ -197,4 +229,46 @@ trait SSOFunctions
 		}
 	}
 	
-}
+	public function getPetioToken($username, $password, $oAuthToken = null, $fallback = false)
+	{
+		$token = null;
+		try {
+			$url = $this->qualifyURL($this->config['petioURL']);
+			$headers = array(
+				"Content-Type" => "application/json"
+			);
+			$data = array(
+				'user' => [
+					'username' => ($oAuthToken ? '' : $username),
+					'password' => ($oAuthToken ? '' : $password),
+					'type' => 1,
+				],
+				'authToken' => false,
+				'token' => $oAuthToken
+			);
+			$endpoint = ($oAuthToken) ? '/api/login/plex_login' : '/api/login';
+			$options = $this->requestOptions($url, false, 60);
+			$response = Requests::post($url . $endpoint, $headers, json_encode($data), $options);
+			if ($response->success) {
+				$user = json_decode($response->body, true)['user'];
+				$token = json_decode($response->body, true)['token'];
+				$this->writeLog('success', 'Petio Token Function - Grabbed token', $user['username']);
+			} else {
+				if ($fallback) {
+					$this->writeLog('error', 'Petio Token Function - Petio did not return Token - Will retry using fallback credentials', $username);
+				} else {
+					$this->writeLog('error', 'Petio Token Function - Petio did not return Token', $username);
+				}
+			}
+		} catch (Requests_Exception $e) {
+			$this->writeLog('error', 'Petio Token Function - Error: ' . $e->getMessage(), $username);
+		}
+		if ($token) {
+			return $token;
+		} elseif ($fallback) {
+			return $this->getPetioToken($this->config['petioFallbackUser'], $this->decrypt($this->config['petioFallbackPassword']), null, false);
+		} else {
+			return false;
+		}
+	}
+}

+ 9 - 2
api/homepage/calendar.php

@@ -2,13 +2,19 @@
 
 trait CalendarHomepageItem
 {
-	public function calendarSettingsArray()
+	public function calendarSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'iCal',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/calendar.png',
 			'category' => 'HOMEPAGE',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -92,6 +98,7 @@ trait CalendarHomepageItem
 				),
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function calendarHomepagePermissions($key = null)

+ 9 - 2
api/homepage/couchpotato.php

@@ -3,13 +3,19 @@
 trait CouchPotatoHomepageItem
 {
 	
-	public function couchPotatoSettingsArray()
+	public function couchPotatoSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'CouchPotato',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/couchpotato.png',
 			'category' => 'PVR',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -88,6 +94,7 @@ trait CouchPotatoHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function couchPotatoHomepagePermissions($key = null)

+ 12 - 9
api/homepage/deluge.php

@@ -2,13 +2,19 @@
 
 trait DelugeHomepageItem
 {
-	public function delugeSettingsArray()
+	public function delugeSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Deluge',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/deluge.png',
 			'category' => 'Downloader',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'custom' => '
 				<div class="row">
@@ -58,6 +64,7 @@ trait DelugeHomepageItem
 						'type' => 'password',
 						'name' => 'delugePassword',
 						'label' => 'Password',
+						'help' => 'Note that using a blank password might not work correctly.',
 						'value' => $this->config['delugePassword']
 					)
 				),
@@ -90,7 +97,7 @@ trait DelugeHomepageItem
 				'Test Connection' => array(
 					array(
 						'type' => 'blank',
-						'label' => 'Please Save before Testing'
+						'label' => 'Please Save before Testing. Note that using a blank password might not work correctly.'
 					),
 					array(
 						'type' => 'button',
@@ -103,6 +110,7 @@ trait DelugeHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionDeluge()
@@ -111,10 +119,6 @@ trait DelugeHomepageItem
 			$this->setAPIResponse('error', 'Deluge URL is not defined', 422);
 			return false;
 		}
-		if (empty($this->config['delugePassword'])) {
-			$this->setAPIResponse('error', 'Deluge Password is not defined', 422);
-			return false;
-		}
 		try {
 			$deluge = new deluge($this->config['delugeURL'], $this->decrypt($this->config['delugePassword']));
 			$torrents = $deluge->getTorrents(null, 'comment, download_payload_rate, eta, hash, is_finished, is_seed, message, name, paused, progress, queue, state, total_size, upload_payload_rate');
@@ -139,8 +143,7 @@ trait DelugeHomepageItem
 					'homepageDelugeAuth'
 				],
 				'not_empty' => [
-					'delugeURL',
-					'delugePassword'
+					'delugeURL'
 				]
 			]
 		];

+ 9 - 2
api/homepage/emby.php

@@ -2,13 +2,19 @@
 
 trait EmbyHomepageItem
 {
-	public function embySettingsArray()
+	public function embySettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Emby',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/emby.png',
 			'category' => 'Media Server',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -167,6 +173,7 @@ trait EmbyHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionEmby()

+ 9 - 2
api/homepage/healthchecks.php

@@ -2,13 +2,19 @@
 
 trait HealthChecksHomepageItem
 {
-	public function healthChecksSettingsArray()
+	public function healthChecksSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'HealthChecks',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/healthchecks.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -60,6 +66,7 @@ trait HealthChecksHomepageItem
 				),
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function healthChecksHomepagePermissions($key = null)

+ 22 - 4
api/homepage/html.php

@@ -2,13 +2,19 @@
 
 trait HTMLHomepageItem
 {
-	public function htmlOneSettingsArray()
+	public function htmlOneSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'CustomHTML-1',
 			'enabled' => strpos('personal,business', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/custom1.png',
 			'category' => 'Custom',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -42,11 +48,22 @@ trait HTMLHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
-	public function htmlTwoSettingsArray()
+	public function htmlTwoSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
+			'name' => 'CustomHTML-2',
+			'enabled' => strpos('personal,business', $this->config['license']) !== false,
+			'image' => 'plugins/images/tabs/custom2.png',
+			'category' => 'Custom',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'name' => 'CustomHTML-2',
 			'enabled' => strpos('personal,business', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/custom2.png',
@@ -84,6 +101,7 @@ trait HTMLHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function htmlHomepagePermissions($key = null)

+ 19 - 12
api/homepage/jackett.php

@@ -2,13 +2,19 @@
 
 trait JackettHomepageItem
 {
-	public function jackettSettingsArray()
+	public function jackettSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Jackett',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/jackett.png',
 			'category' => 'Utility',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -42,16 +48,17 @@ trait JackettHomepageItem
 					)
 				),
 				'Options' => array(
-				    array(
-                	    'type' => 'switch',
-                		'name' => 'homepageJackettBackholeDownload',
-                		'label' => 'Prefer black hole download',
-                		'help' => 'Prefer black hole download link instead of direct/magnet download',
-                		'value' => $this->config['homepageJackettBackholeDownload']
-                	)
-                ),
+					array(
+						'type' => 'switch',
+						'name' => 'homepageJackettBackholeDownload',
+						'label' => 'Prefer black hole download',
+						'help' => 'Prefer black hole download link instead of direct/magnet download',
+						'value' => $this->config['homepageJackettBackholeDownload']
+					)
+				),
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function jackettHomepagePermissions($key = null)
@@ -124,7 +131,7 @@ trait JackettHomepageItem
 		$this->setAPIResponse('success', null, 200, $api);
 		return $api;
 	}
-
+	
 	public function performJackettBackHoleDownload($url = null)
 	{
 		if (!$this->homepageItemPermissions($this->jackettHomepagePermissions('main'), true)) {
@@ -161,4 +168,4 @@ trait JackettHomepageItem
 		}
 		return $api;
 	}
-}
+}

+ 11 - 4
api/homepage/jdownloader.php

@@ -2,13 +2,19 @@
 
 trait JDownloaderHomepageItem
 {
-	public function jDownloaderSettingsArray()
+	public function jDownloaderSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'JDownloader',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/jdownloader.png',
 			'category' => 'Downloader',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'custom' => '
 				<div class="row">
@@ -21,7 +27,7 @@ trait JDownloaderHomepageItem
                                 <div class="panel-body">
 									<ul class="list-icons">
                                         <li><i class="fa fa-chevron-right text-danger"></i> <a href="https://pypi.org/project/myjd-api/" target="_blank">Download [myjd-api] Module</a></li>
-                                        <li><i class="fa fa-chevron-right text-danger"></i> Add <b>/api/myjd</b> to the URL if you are using <a href="https://pypi.org/project/RSScrawler/" target="_blank">RSScrawler</a></li>
+                                        <li><i class="fa fa-chevron-right text-danger"></i> Add <b>/api/myjd</b> to the URL if you are using <a href="https://pypi.org/project/FeedCrawler/" target="_blank">FeedCrawler</a></li>
                                     </ul>
                                 </div>
                             </div>
@@ -85,6 +91,7 @@ trait JDownloaderHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionJDownloader()
@@ -197,4 +204,4 @@ trait JDownloaderHomepageItem
 		$this->setAPIResponse('success', null, 200, $api);
 		return $api;
 	}
-}
+}

+ 9 - 2
api/homepage/jellyfin.php

@@ -3,13 +3,19 @@
 trait JellyfinHomepageItem
 {
 	
-	public function jellyfinSettingsArray()
+	public function jellyfinSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Jellyfin',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/jellyfin.png',
 			'category' => 'Media Server',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -168,6 +174,7 @@ trait JellyfinHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionJellyfin()

+ 10 - 7
api/homepage/lidarr.php

@@ -2,13 +2,19 @@
 
 trait LidarrHomepageItem
 {
-	public function lidarrSettingsArray()
+	public function lidarrSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Lidarr',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/lidarr.png',
 			'category' => 'PMR',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -49,11 +55,7 @@ trait LidarrHomepageItem
 						'html' => '
 							<div class="panel panel-default">
 								<div class="panel-wrapper collapse in">
-									<div class="panel-body">
-										<h3 lang="en">Lidarr SOCKS API Connection</h3>
-										<p>Using this feature allows you to access the Lidarr API without having to reverse proxy it.  Just access it from: </p>
-										<code>' . $this->getServerPath() . 'api/v2/socks/lidarr/</code>
-									</div>
+									<div class="panel-body">' . $this->socksHeadingHTML('lidarr') . '</div>
 								</div>
 							</div>'
 					),
@@ -145,6 +147,7 @@ trait LidarrHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionLidarr()

+ 9 - 2
api/homepage/misc.php

@@ -2,13 +2,19 @@
 
 trait MiscHomepageItem
 {
-	public function miscSettingsArray()
+	public function miscSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Misc',
 			'enabled' => true,
 			'image' => 'plugins/images/organizr/logo-no-border.png',
 			'category' => 'Custom',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'YouTube' => array(
 					array(
@@ -27,6 +33,7 @@ trait MiscHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 }

+ 10 - 3
api/homepage/monitorr.php

@@ -2,13 +2,19 @@
 
 trait MonitorrHomepageItem
 {
-	public function monitorrSettingsArray()
+	public function monitorrSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Monitorr',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/monitorr.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -67,6 +73,7 @@ trait MonitorrHomepageItem
 				),
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function monitorrHomepagePermissions($key = null)
@@ -168,7 +175,7 @@ trait MonitorrHomepageItem
 						$base64 = 'data:image/' . $ext . ';base64,' . base64_encode($img->body);
 						$statuses[$service]['image'] = $base64;
 					} else {
-						$statuses[$service]['image'] = $cacheDirectory . 'no-list.png';
+						$statuses[$service]['image'] = 'plugins/images/cache/no-list.png';
 					}
 					$linkMatch = [];
 					$linkPattern = '/<a class="servicetile" href="(.*)" target="_blank" style="display: block"><div id="serviceimg"><div><img id="' . strtolower($service) . '-service-img/';

+ 12 - 6
api/homepage/netdata.php

@@ -85,13 +85,19 @@ trait NetDataHomepageItem
 		
 	}
 	
-	public function netdataSettingsArray()
+	public function netdataSettingsArray($infoOnly = false)
 	{
-		$array = array(
+		$homepageInformation = [
 			'name' => 'Netdata',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/netdata.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -124,7 +130,7 @@ trait NetDataHomepageItem
 			)
 		);
 		for ($i = 1; $i <= 7; $i++) {
-			$array['settings']['Chart ' . $i] = array(
+			$homepageSettings['settings']['Chart ' . $i] = array(
 				array(
 					'type' => 'switch',
 					'name' => 'netdata' . $i . 'Enabled',
@@ -194,7 +200,7 @@ trait NetDataHomepageItem
 				),
 			);
 		}
-		$array['settings']['Custom data'] = array(
+		$homepageSettings['settings']['Custom data'] = array(
 			array(
 				'type' => 'html',
 				'label' => '',
@@ -272,7 +278,7 @@ trait NetDataHomepageItem
 				'value' => $this->config['netdataCustom'],
 			)
 		);
-		$array['settings']['Options'] = array(
+		$homepageSettings['settings']['Options'] = array(
 			array(
 				'type' => 'select',
 				'name' => 'homepageNetdataRefresh',
@@ -281,7 +287,7 @@ trait NetDataHomepageItem
 				'options' => $this->timeOptions()
 			),
 		);
-		return $array;
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function netdataHomepagePermissions($key = null)

+ 35 - 2
api/homepage/nzbget.php

@@ -2,13 +2,19 @@
 
 trait NZBGetHomepageItem
 {
-	public function nzbgetSettingsArray()
+	public function nzbgetSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'NZBGet',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/nzbget.png',
 			'category' => 'Downloader',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -47,6 +53,32 @@ trait NZBGetHomepageItem
 						'value' => $this->config['nzbgetPassword']
 					)
 				),
+				'API SOCKS' => array(
+					array(
+						'type' => 'html',
+						'override' => 12,
+						'label' => '',
+						'html' => '
+							<div class="panel panel-default">
+								<div class="panel-wrapper collapse in">
+									<div class="panel-body">' . $this->socksHeadingHTML('nzbget') . '</div>
+								</div>
+							</div>'
+					),
+					array(
+						'type' => 'switch',
+						'name' => 'nzbgetSocksEnabled',
+						'label' => 'Enable',
+						'value' => $this->config['nzbgetSocksEnabled']
+					),
+					array(
+						'type' => 'select',
+						'name' => 'nzbgetSocksAuth',
+						'label' => 'Minimum Authentication',
+						'value' => $this->config['nzbgetSocksAuth'],
+						'options' => $this->groupOptions
+					),
+				),
 				'Misc Options' => array(
 					array(
 						'type' => 'select',
@@ -78,6 +110,7 @@ trait NZBGetHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionNZBGet()

+ 9 - 2
api/homepage/octoprint.php

@@ -2,13 +2,19 @@
 
 trait OctoPrintHomepageItem
 {
-	public function octoprintSettingsArray()
+	public function octoprintSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Octoprint',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/octoprint.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -59,6 +65,7 @@ trait OctoPrintHomepageItem
 				),
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function octoprintHomepagePermissions($key = null)

+ 9 - 2
api/homepage/ombi.php

@@ -3,13 +3,19 @@
 trait OmbiHomepageItem
 {
 	
-	public function ombiSettingsArray()
+	public function ombiSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Ombi',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/ombi.png',
 			'category' => 'Requests',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -150,6 +156,7 @@ trait OmbiHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionOmbi()

+ 9 - 2
api/homepage/pihole.php

@@ -2,13 +2,19 @@
 
 trait PiHoleHomepageItem
 {
-	public function piholeSettingsArray()
+	public function piholeSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Pi-hole',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/pihole.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -67,6 +73,7 @@ trait PiHoleHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionPihole()

+ 36 - 5
api/homepage/plex.php

@@ -3,8 +3,18 @@
 trait PlexHomepageItem
 {
 	
-	public function plexSettingsArray()
+	public function plexSettingsArray($infoOnly = false)
 	{
+		$homepageInformation = [
+			'name' => 'Plex',
+			'enabled' => strpos('personal', $this->config['license']) !== false,
+			'image' => 'plugins/images/tabs/plex.png',
+			'category' => 'Media Server',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
 		if ($this->config['plexID'] !== '' && $this->config['plexToken'] !== '') {
 			$loop = $this->plexLibraryList('key')['libraries'];
 			foreach ($loop as $key => $value) {
@@ -22,7 +32,7 @@ trait PlexHomepageItem
 				),
 			);
 		}
-		return array(
+		$homepageSettings = array(
 			'name' => 'Plex',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/plex.png',
@@ -142,6 +152,15 @@ trait PlexHomepageItem
 						'value' => $this->config['homepagePlexRecentAuth'],
 						'options' => $this->groupOptions
 					),
+					array(
+						'type' => 'select2',
+						'class' => 'select2-multiple',
+						'id' => 'plex-recent-exclude-select',
+						'name' => 'homepagePlexRecentExclude',
+						'label' => 'Libraries to Exclude',
+						'value' => $this->config['homepagePlexRecentExclude'],
+						'options' => $libraryList
+					),
 					array(
 						'type' => 'number',
 						'name' => 'homepageRecentLimit',
@@ -170,6 +189,15 @@ trait PlexHomepageItem
 						'value' => $this->config['mediaSearchAuth'],
 						'options' => $this->groupOptions
 					),
+					array(
+						'type' => 'select2',
+						'class' => 'select2-multiple',
+						'id' => 'plex-search-exclude-select',
+						'name' => 'homepagePlexSearchExclude',
+						'label' => 'Libraries to Exclude',
+						'value' => $this->config['homepagePlexSearchExclude'],
+						'options' => $libraryList
+					),
 					array(
 						'type' => 'select',
 						'name' => 'mediaSearchType',
@@ -282,6 +310,7 @@ trait PlexHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionPlex()
@@ -479,6 +508,7 @@ trait PlexHomepageItem
 			return false;
 		}
 		$ignore = array();
+		$exclude = explode(',', $this->config['homepagePlexRecentExclude']);
 		$resolve = true;
 		$url = $this->qualifyURL($this->config['plexURL']);
 		$urls['movie'] = $url . "/hubs/home/recentlyAdded?X-Plex-Token=" . $this->config['plexToken'] . "&X-Plex-Container-Start=0&X-Plex-Container-Size=" . $this->config['homepageRecentLimit'] . "&type=1";
@@ -492,7 +522,7 @@ trait PlexHomepageItem
 				$items = array();
 				$plex = simplexml_load_string($response->body);
 				foreach ($plex as $child) {
-					if (!in_array($child['type'], $ignore) && isset($child['librarySectionID'])) {
+					if (!in_array($child['type'], $ignore) && !in_array($child['librarySectionID'], $exclude) && isset($child['librarySectionID'])) {
 						$items[] = $this->resolvePlexItem($child);
 					}
 				}
@@ -601,6 +631,7 @@ trait PlexHomepageItem
 			return false;
 		}
 		$ignore = array('artist', 'episode');
+		$exclude = explode(',', $this->config['homepagePlexSearchExclude']);
 		$resolve = true;
 		$url = $this->qualifyURL($this->config['plexURL']);
 		$url = $url . "/search?query=" . rawurlencode($query) . "&X-Plex-Token=" . $this->config['plexToken'];
@@ -611,7 +642,7 @@ trait PlexHomepageItem
 			$items = array();
 			$plex = simplexml_load_string($response->body);
 			foreach ($plex as $child) {
-				if (!in_array($child['type'], $ignore) && isset($child['librarySectionID'])) {
+				if (!in_array($child['type'], $ignore) && !in_array($child['librarySectionID'], $exclude) && isset($child['librarySectionID'])) {
 					$items[] = $this->resolvePlexItem($child);
 				}
 			}
@@ -884,4 +915,4 @@ trait PlexHomepageItem
 		}
 		return false;
 	}
-}
+}

+ 9 - 2
api/homepage/qbittorrent.php

@@ -2,13 +2,19 @@
 
 trait QBitTorrentHomepageItem
 {
-	public function qBittorrentSettingsArray()
+	public function qBittorrentSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'qBittorrent',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/qBittorrent.png',
 			'category' => 'Downloader',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -115,6 +121,7 @@ trait QBitTorrentHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionQBittorrent()

+ 10 - 7
api/homepage/radarr.php

@@ -2,13 +2,19 @@
 
 trait RadarrHomepageItem
 {
-	public function radarrSettingsArray()
+	public function radarrSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Radarr',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/radarr.png',
 			'category' => 'PVR',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -49,11 +55,7 @@ trait RadarrHomepageItem
 						'html' => '
 							<div class="panel panel-default">
 								<div class="panel-wrapper collapse in">
-									<div class="panel-body">
-										<h3 lang="en">Radarr SOCKS API Connection</h3>
-										<p>Using this feature allows you to access the Radarr API without having to reverse proxy it.  Just access it from: </p>
-										<code>' . $this->getServerPath() . 'api/v2/socks/radarr/</code>
-									</div>
+									<div class="panel-body">' . $this->socksHeadingHTML('radarr') . '</div>
 								</div>
 							</div>'
 					),
@@ -197,6 +199,7 @@ trait RadarrHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionRadarr()

+ 11 - 3
api/homepage/rtorrent.php

@@ -2,14 +2,21 @@
 
 trait RTorrentHomepageItem
 {
-	public function rTorrentSettingsArray()
+	public function rTorrentSettingsArray($infoOnly = false)
 	{
-		$xmlStatus = (extension_loaded('xmlrpc')) ? 'Installed' : 'Not Installed';
-		return array(
+		
+		$homepageInformation = [
 			'name' => 'rTorrent',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/rTorrent.png',
 			'category' => 'Downloader',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$xmlStatus = (extension_loaded('xmlrpc')) ? 'Installed' : 'Not Installed';
+		$homepageSettings = array(
 			'settings' => array(
 				'FYI' => array(
 					array(
@@ -150,6 +157,7 @@ trait RTorrentHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionRTorrent()

+ 48 - 3
api/homepage/sabnzbd.php

@@ -3,13 +3,19 @@
 trait SabNZBdHomepageItem
 {
 	
-	public function sabNZBdSettingsArray()
+	public function sabNZBdSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'SabNZBD',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/sabnzbd.png',
 			'category' => 'Downloader',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -42,6 +48,32 @@ trait SabNZBdHomepageItem
 						'value' => $this->config['sabnzbdToken']
 					)
 				),
+				'API SOCKS' => array(
+					array(
+						'type' => 'html',
+						'override' => 12,
+						'label' => '',
+						'html' => '
+							<div class="panel panel-default">
+								<div class="panel-wrapper collapse in">
+									<div class="panel-body">' . $this->socksHeadingHTML('sabnzbd') . '</div>
+								</div>
+							</div>'
+					),
+					array(
+						'type' => 'switch',
+						'name' => 'sabnzbdSocksEnabled',
+						'label' => 'Enable',
+						'value' => $this->config['sabnzbdSocksEnabled']
+					),
+					array(
+						'type' => 'select',
+						'name' => 'sabnzbdSocksAuth',
+						'label' => 'Minimum Authentication',
+						'value' => $this->config['sabnzbdSocksAuth'],
+						'options' => $this->groupOptions
+					),
+				),
 				'Misc Options' => array(
 					array(
 						'type' => 'select',
@@ -73,6 +105,7 @@ trait SabNZBdHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionSabNZBd()
@@ -84,8 +117,20 @@ trait SabNZBdHomepageItem
 				$options = ($this->localURL($url)) ? array('verify' => false) : array();
 				$response = Requests::get($url, array(), $options);
 				if ($response->success) {
-					$this->setAPIResponse('success', 'API Connection succeeded', 200);
+					$data = json_decode($response->body, true);
+					$status = 'success';
+					$responseCode = 200;
+					$message = 'API Connection succeeded';
+					if (isset($data['error'])) {
+						$status = 'error';
+						$responseCode = 500;
+						$message = $data['error'];
+					}
+					$this->setAPIResponse($status, $message, $responseCode, $data);
 					return true;
+				} else {
+					$this->setAPIResponse('error', $response->body, 500);
+					return false;
 				}
 			} catch (Requests_Exception $e) {
 				$this->setAPIResponse('error', $e->getMessage(), 500);

+ 9 - 2
api/homepage/sickrage.php

@@ -2,13 +2,19 @@
 
 trait SickRageHomepageItem
 {
-	public function sickrageSettingsArray()
+	public function sickrageSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'SickRage',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/sickrage.png',
 			'category' => 'PVR',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -101,6 +107,7 @@ trait SickRageHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionSickRage()

+ 10 - 7
api/homepage/sonarr.php

@@ -2,13 +2,19 @@
 
 trait SonarrHomepageItem
 {
-	public function sonarrSettingsArray()
+	public function sonarrSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Sonarr',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/sonarr.png',
 			'category' => 'PVR',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'docs' => 'https://docs.organizr.app/books/setup-features/page/sonarr',
 			'settings' => array(
 				'About' => array(
@@ -66,11 +72,7 @@ trait SonarrHomepageItem
 						'html' => '
 							<div class="panel panel-default">
 								<div class="panel-wrapper collapse in">
-									<div class="panel-body">
-										<h3 lang="en">Sonarr SOCKS API Connection</h3>
-										<p>Using this feature allows you to access the Sonarr API without having to reverse proxy it.  Just access it from: </p>
-										<code>' . $this->getServerPath() . 'api/v2/socks/sonarr/</code>
-									</div>
+									<div class="panel-body">' . $this->socksHeadingHTML('sonarr') . '</div>
 								</div>
 							</div>'
 					),
@@ -196,6 +198,7 @@ trait SonarrHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionSonarr()

+ 10 - 3
api/homepage/speedtest.php

@@ -2,13 +2,19 @@
 
 trait SpeedTestHomepageItem
 {
-	public function speedTestSettingsArray()
+	public function speedTestSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Speedtest',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/speedtest-icon.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -58,6 +64,7 @@ trait SpeedTestHomepageItem
 				),
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function speedTestHomepagePermissions($key = null)
@@ -147,4 +154,4 @@ trait SpeedTestHomepageItem
 		$this->setAPIResponse('success', null, 200, $api);
 		return $api;
 	}
-}
+}

+ 9 - 2
api/homepage/tautulli.php

@@ -2,13 +2,19 @@
 
 trait TautulliHomepageItem
 {
-	public function tautulliSettingsArray()
+	public function tautulliSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Tautulli',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/tautulli.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -163,6 +169,7 @@ trait TautulliHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionTautulli()

+ 10 - 3
api/homepage/trakt.php

@@ -2,13 +2,19 @@
 
 trait TraktHomepageItem
 {
-	public function traktSettingsArray()
+	public function traktSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Trakt',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/trakt.png',
 			'category' => 'Calendar',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'docs' => 'https://docs.organizr.app/books/setup-features/page/trakt',
 			'settings' => array(
 				'About' => array(
@@ -135,6 +141,7 @@ trait TraktHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function traktHomepagePermissions($key = null)
@@ -354,6 +361,6 @@ trait TraktHomepageItem
 		if ($i != 0) {
 			return $gotCalendar;
 		}
-		return false;
+		return [];
 	}
 }

+ 11 - 4
api/homepage/transmission.php

@@ -2,13 +2,19 @@
 
 trait TransmissionHomepageItem
 {
-	public function transmissionSettingsArray()
+	public function transmissionSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Transmission',
 			'enabled' => strpos('personal', $this->config['license']) !== false,
 			'image' => 'plugins/images/tabs/transmission.png',
 			'category' => 'Downloader',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -95,6 +101,7 @@ trait TransmissionHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function testConnectionTransmission()
@@ -104,7 +111,7 @@ trait TransmissionHomepageItem
 			return false;
 		}
 		$digest = $this->qualifyURL($this->config['transmissionURL'], true);
-		$passwordInclude = ($this->config['transmissionUsername'] != '' && $this->config['transmissionPassword'] != '') ? $this->config['transmissionUsername'] . ':' . $this->decrypt($this->config['transmissionPassword']) . "@" : '';
+		$passwordInclude = ($this->config['transmissionUsername'] != '' && $this->config['transmissionPassword'] != '') ? $this->config['transmissionUsername'] . ':' . rawurlencode($this->decrypt($this->config['transmissionPassword'])) . "@" : '';
 		$url = $digest['scheme'] . '://' . $passwordInclude . $digest['host'] . $digest['port'] . $digest['path'] . '/rpc';
 		try {
 			$options = $this->requestOptions($this->config['transmissionURL'], $this->config['transmissionDisableCertCheck'], $this->config['homepageDownloadRefresh']);
@@ -192,7 +199,7 @@ trait TransmissionHomepageItem
 			return false;
 		}
 		$digest = $this->qualifyURL($this->config['transmissionURL'], true);
-		$passwordInclude = ($this->config['transmissionUsername'] != '' && $this->config['transmissionPassword'] != '') ? $this->config['transmissionUsername'] . ':' . $this->decrypt($this->config['transmissionPassword']) . "@" : '';
+		$passwordInclude = ($this->config['transmissionUsername'] != '' && $this->config['transmissionPassword'] != '') ? $this->config['transmissionUsername'] . ':' . rawurlencode($this->decrypt($this->config['transmissionPassword'])) . "@" : '';
 		$url = $digest['scheme'] . '://' . $passwordInclude . $digest['host'] . $digest['port'] . $digest['path'] . '/rpc';
 		try {
 			$options = $this->requestOptions($this->config['transmissionURL'], $this->config['transmissionDisableCertCheck'], $this->config['homepageDownloadRefresh']);

+ 17 - 10
api/homepage/unifi.php

@@ -2,13 +2,19 @@
 
 trait UnifiHomepageItem
 {
-	public function unifiSettingsArray()
+	public function unifiSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'UniFi',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/unifi.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -91,8 +97,9 @@ trait UnifiHomepageItem
 				)
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
-
+	
 	public function unifiHomepagePermissions($key = null)
 	{
 		$permissions = [
@@ -118,7 +125,7 @@ trait UnifiHomepageItem
 			return [];
 		}
 	}
-
+	
 	public function homepageOrderunifi()
 	{
 		if ($this->homepageItemPermissions($this->unifiHomepagePermissions('main'))) {
@@ -134,7 +141,7 @@ trait UnifiHomepageItem
 				';
 		}
 	}
-
+	
 	public function getUnifiSiteName()
 	{
 		if (empty($this->config['unifiURL'])) {
@@ -183,9 +190,9 @@ trait UnifiHomepageItem
 			$this->setAPIResponse('error', $e->getMessage(), 500);
 			return false;
 		}
-
+		
 	}
-
+	
 	public function testConnectionUnifi()
 	{
 		if (empty($this->config['unifiURL'])) {
@@ -227,7 +234,7 @@ trait UnifiHomepageItem
 				$cookie['csrf_token'] = ($response->cookies['csrf_token']->value) ?? false;
 				$cookie['Token'] = ($response->cookies['Token']->value) ?? false;
 				$options['cookies'] = $response->cookies;
-
+				
 			} else {
 				$this->setAPIResponse('error', 'Unifi response error - Check Credentials', 409);
 				return false;
@@ -251,7 +258,7 @@ trait UnifiHomepageItem
 		$this->setAPIResponse('success', 'API Connection succeeded', 200);
 		return true;
 	}
-
+	
 	public function getUnifiHomepageData()
 	{
 		if (!$this->homepageItemPermissions($this->unifiHomepagePermissions('main'), true)) {
@@ -284,7 +291,7 @@ trait UnifiHomepageItem
 				$cookie['csrf_token'] = ($response->cookies['csrf_token']->value) ?? false;
 				$cookie['Token'] = ($response->cookies['Token']->value) ?? false;
 				$options['cookies'] = $response->cookies;
-
+				
 			} else {
 				$this->setAPIResponse('error', 'Unifi response error - Check Credentials', 409);
 				return false;

+ 9 - 2
api/homepage/weather.php

@@ -2,13 +2,19 @@
 
 trait WeatherHomepageItem
 {
-	public function weatherSettingsArray()
+	public function weatherSettingsArray($infoOnly = false)
 	{
-		return array(
+		$homepageInformation = [
 			'name' => 'Weather-Air',
 			'enabled' => true,
 			'image' => 'plugins/images/tabs/wind.png',
 			'category' => 'Monitor',
+			'settingsArray' => __FUNCTION__
+		];
+		if ($infoOnly) {
+			return $homepageInformation;
+		}
+		$homepageSettings = array(
 			'settings' => array(
 				'Enable' => array(
 					array(
@@ -115,6 +121,7 @@ trait WeatherHomepageItem
 				),
 			)
 		);
+		return array_merge($homepageInformation, $homepageSettings);
 	}
 	
 	public function weatherHomepagePermissions($key = null)

+ 111 - 66
api/pages/dependencies.php

@@ -9,73 +9,118 @@ function get_page_dependencies($Organizr)
 <script>
 </script>
 <div class="container-fluid">
-    <div class="row bg-title">
-        <div class="col-lg-3 col-md-4 col-sm-4 col-xs-12">
-            <h4 class="page-title" lang="en">Organizr Dependency Check</h4>
-        </div>
-        <!-- /.col-lg-12 -->
-    </div>
-    <!--.row-->
-    <div class="row">
-        <div class="col-lg-8">
-            <div class="panel panel-danger">
-                <div class="panel-heading"> <i class="ti-alert fa-fw"></i> <span lang="en">Dependencies Missing</span>
-                    <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a> <a href="#" data-perform="panel-dismiss"><i class="ti-close"></i></a> </div>
-                </div>
-                <div class="panel-wrapper collapse in" aria-expanded="true">
-                    <div class="panel-body">
-                        <ul class="common-list" id="depenency-info"></ul>
-                    </div>
-                </div>
-            </div>
-        </div>
-		<div class="col-lg-4">
-            <div class="panel panel-info">
-                <div class="panel-heading"> <i class="ti-alert fa-fw"></i> <span lang="en">PHP Version Check</span>
-                    <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a> <a href="#" data-perform="panel-dismiss"><i class="ti-close"></i></a> </div>
-                </div>
-                <div class="panel-wrapper collapse in" aria-expanded="true">
-                    <table class="table table-hover">
-                        <tbody>
-                            <tr>
-                                <td id="php-version-check" lang="en">Loading...</td>
-                            </tr>
-                        </tbody>
-                    </table>
-                </div>
-            </div>
-        </div>
-		<div class="col-lg-4">
-            <div class="panel panel-info">
-                <div class="panel-heading"> <i class="ti-alert fa-fw"></i> <span lang="en">Web Folder</span>
-                    <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a> <a href="#" data-perform="panel-dismiss"><i class="ti-close"></i></a> </div>
-                </div>
-                <div class="panel-wrapper collapse in" aria-expanded="true">
-                    <table class="table table-hover">
-                        <tbody>
-                            <tr>
-                                <td>' . dirname(__DIR__, 2) . '</td>
-                            </tr>
-                            <tr>
-                                <td id="web-folder" lang="en">Loading...</td>
-                            </tr>
-                        </tbody>
-                    </table>
-                </div>
-            </div>
-        </div>
-        <div class="col-lg-4">
-            <div class="panel panel-info">
-                <div class="panel-heading"> <i class="ti-alert fa-fw"></i> <span lang="en">Browser Information</span>
-                    <div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a> <a href="#" data-perform="panel-dismiss"><i class="ti-close"></i></a> </div>
-                </div>
-                <div class="panel-wrapper collapse in" id="browser-info" aria-expanded="true"></div>
-            </div>
-        </div>
+	<div class="row bg-title">
+		<div class="col-lg-3 col-md-4 col-sm-4 col-xs-12">
+			<h4 class="page-title" lang="en">Organizr Dependency Check</h4>
+		</div>
+		<!-- /.col-lg-12 -->
+	</div>
+	<!--.row-->
+	<div class="row">
+		<div class="col-sm-12">
+			<div class="white-box">
+				<div class="row row-in">
+					<div class="col-lg-4 col-sm-6 row-in-br">
+						<ul class="col-in">
+							<li>
+								<span class="circle circle-md bg-warning dependency-dependencies-check"><i class="fa fa-spin fa-spinner"></i></span>
+							</li>
+							<li class="col-last">
+								<h3 class="counter text-right m-t-15" lang="en">Dependencies</h3>
+							</li>
+							
+						</ul>
+					</div>
+					<div class="col-lg-4 col-sm-6 row-in-br  b-r-none">
+						<ul class="col-in">
+							<li>
+								<span class="circle circle-md bg-warning dependency-phpversion-check"><i class="fa fa-spin fa-spinner"></i></span>
+							</li>
+							<li class="col-last">
+								<h3 class="counter text-right m-t-15" lang="en">PHP Version</h3>
+							</li>
+							
+						</ul>
+					</div>
+					
+					<div class="col-lg-4 col-sm-6  b-0">
+						<ul class="col-in">
+							<li>
+								<span class="circle circle-md bg-warning dependency-permissions-check"><i class="fa fa-spin fa-spinner"></i></span>
+							</li>
+							<li class="col-last">
+								<h3 class="counter text-right m-t-15" lang="en">Permissions</h3>
+							</li>
+							
+						</ul>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+	<div class="row">
+		<div class="col-lg-4 col-sm-6">
+			<div class="panel panel-danger dependency-dependencies-check-listing-header">
+				<div class="panel-heading dependency-dependencies-check-listing"> <i class="ti-alert fa-fw"></i> <span lang="en">Dependencies Missing</span>
+					<div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a></div>
+				</div>
+				<div class="panel-wrapper collapse in" aria-expanded="true">
+					<div class="panel-body">
+						<ul class="common-list" id="depenency-info"></ul>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="col-lg-4 col-sm-6">
+			<div class="panel panel-info">
+				<div class="panel-heading"> <i class="ti-alert fa-fw"></i> <span lang="en">PHP Version Check</span>
+					<div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a></div>
+				</div>
+				<div class="panel-wrapper collapse in" aria-expanded="true">
+					<table class="table table-hover">
+						<tbody>
+							<tr>
+								<td id="php-version-check" lang="en">Loading...</td>
+							</tr>
+							<tr>
+								<td id="php-version-check-user" lang="en">Loading...</td>
+							</tr>
+						</tbody>
+					</table>
+				</div>
+			</div>
+		</div>
+		<div class="col-lg-4 col-sm-6">
+			<div class="panel panel-info">
+				<div class="panel-heading"> <i class="ti-alert fa-fw"></i> <span lang="en">Web Folder</span>
+					<div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-minus"></i></a></div>
+				</div>
+				<div class="panel-wrapper collapse in" aria-expanded="true">
+					<table class="table table-hover">
+						<tbody>
+							<tr>
+								<td>' . dirname(__DIR__, 2) . '</td>
+							</tr>
+							<tr>
+								<td id="web-folder" lang="en">Loading...</td>
+							</tr>
+						</tbody>
+					</table>
+				</div>
+			</div>
+		</div>
+		<div class="col-lg-12">
+			<div class="panel panel-info">
+				<div class="panel-heading"> <i class="ti-alert fa-fw"></i> <span lang="en">Browser Information</span>
+					<div class="pull-right"><a href="#" data-perform="panel-collapse"><i class="ti-plus"></i></a></div>
+				</div>
+				<div class="panel-wrapper collapse" id="browser-info" aria-expanded="false"></div>
+			</div>
+		</div>
 
-    </div>
-    <!--./row-->
+	</div>
+	<!--./row-->
 </div>
 <!-- /.container-fluid -->
 ';
-}
+}

+ 1 - 1
api/plugins/api/bookmark.php

@@ -14,7 +14,7 @@ $app->get('/plugins/bookmark/settings', function ($request, $response, $args) {
 $app->get('/plugins/bookmark/page', function ($request, $response, $args) {
 	$Bookmark = new Bookmark();
 	if ($Bookmark->_checkRequest($request) && $Bookmark->checkRoute($request)) {
-		if ($Bookmark->qualifyRequest(1, true)) {
+		if ($Bookmark->qualifyRequest($Bookmark->_bookmarkGetOrganizrTabInfo(), true)) {
 			$GLOBALS['api']['response']['data'] = $Bookmark->_getPage();
 		}
 	}

+ 50 - 17
api/plugins/bookmark.php

@@ -25,6 +25,31 @@ class Bookmark extends Organizr
 		parent::writeLog($type, "Plugin 'Bookmark': " . $message, $username);
 	}
 	
+	public function _bookmarkGetOrganizrTabInfo()
+	{
+		$response = [
+			array(
+				'function' => 'fetch',
+				'query' => array(
+					'SELECT * FROM tabs',
+					'WHERE url = ?',
+					'api/v2/plugins/bookmark/page'
+				)
+			),
+		];
+		return $this->processQueries($response);
+	}
+	
+	public function _bookmarkGetOrganizrTabGroupId()
+	{
+		$tab = $this->_bookmarkGetOrganizrTabInfo();
+		if ($tab) {
+			return $tab['group_id'];
+		} else {
+			return 999;
+		}
+	}
+	
 	public function _checkRequest($request)
 	{
 		$result = false;
@@ -314,7 +339,7 @@ class Bookmark extends Organizr
 		<div class="panel bg-org panel-info">
 			<div class="panel-heading">
 				<span lang="en">Bookmark Tab Editor</span>
-				<button type="button" class="btn btn-info btn-circle pull-right popup-with-form m-r-5" href="#new-bookmark-tab-form" data-effect="mfp-3d-unfold"><i class="fa fa-plus"></i> </button>
+				<button type="button" class="btn btn-info btn-circle pull-right popup-with-form m-r-5" href="#new-bookmark-tab-form" onclick="newBookmarkTabForm()" data-effect="mfp-3d-unfold"><i class="fa fa-plus"></i> </button>
 				<button onclick="submitBookmarkTabOrder(newBookmarkTabsGlobal)" class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right animated loop-animation rubberBand m-r-20 saveBookmarkTabOrderButton hidden" type="button"><span class="btn-label"><i class="fa fa-save"></i></span><span lang="en">Save Tab Order</span></button>
 			</div>
 			<div class="table-responsive">
@@ -342,12 +367,12 @@ class Bookmark extends Organizr
 			<h1 lang="en">Add New Tab</h1>
 			<fieldset style="border:0;">
 				<div class="form-group">
-					<label class="control-label" for="new-bookmark-tab-form-inputNameNew" lang="en">Tab Name</label>
-					<input type="text" class="form-control" id="new-bookmark-tab-form-inputNameNew" name="name" required="" autofocus>
+					<label class="control-label" for="new-bookmark-tab-form-inputName" lang="en">Tab Name</label>
+					<input type="text" class="form-control" id="new-bookmark-tab-form-inputName" name="name" required="" autofocus>
 				</div>
 				<div class="form-group">
-					<label class="control-label" for="new-bookmark-tab-form-inputURLNew" lang="en">Tab URL</label>
-					<input type="text" class="form-control" id="new-bookmark-tab-form-inputURLNew" name="url"  required="">
+					<label class="control-label" for="new-bookmark-tab-form-inputURL" lang="en">Tab URL</label>
+					<input type="text" class="form-control" id="new-bookmark-tab-form-inputURL" name="url"  required="">
 				</div>
 				<div class="row">
 					<div class="form-group col-lg-4">
@@ -366,17 +391,21 @@ class Bookmark extends Organizr
 					</div>
 				</div>
 				<div class="form-group">
-					<label class="control-label" for="new-bookmark-tab-form-inputImageNew" lang="en">Tab Image</label>
-					<input type="text" class="form-control" id="new-bookmark-tab-form-inputImageNew" name="image" required="">
+					<label class="control-label" for="new-bookmark-tab-form-inputImage" lang="en">Tab Image</label>
+					<input type="text" class="form-control" id="new-bookmark-tab-form-inputImage" name="image" required="">
 				</div>
 				<div class="row">
 					<div class="form-group col-lg-4">
-						<label class="control-label" for="new-bookmark-tab-form-inputBackgroundColorNew" lang="en">Background Color</label>
-						<input type="text" class="form-control" id="new-bookmark-tab-form-inputBackgroundColorNew" name="background_color" required="">
+						<label class="control-label" for="new-bookmark-tab-form-inputBackgroundColor" lang="en">Background Color</label>
+						<input type="text" class="form-control bookmark-pick-a-color" id="new-bookmark-tab-form-inputBackgroundColor" name="background_color" required="" value="#fff">
+					</div>
+					<div class="form-group col-lg-4">
+						<label class="control-label" for="new-bookmark-tab-form-inputTextColor" lang="en">Text Color</label>
+						<input type="text" class="form-control bookmark-pick-a-color" id="new-bookmark-tab-form-inputTextColor" name="text_color" required="" value="#000">
 					</div>
 					<div class="form-group col-lg-4">
-						<label class="control-label" for="new-bookmark-tab-form-inputTextColorNew" lang="en">Text Color</label>
-						<input type="text" class="form-control" id="new-bookmark-tab-form-inputTextColorNew" name="text_color" required="">
+						<label class="control-label" for="new-bookmark-preview" lang="en">Preview</label>
+						<div id="new-bookmark-preview"></div>
 					</div>
 				</div>
 			</fieldset>
@@ -418,12 +447,16 @@ class Bookmark extends Organizr
 				</div>
 				<div class="row">
 					<div class="form-group col-lg-4">
-						<label class="control-label" for="new-bookmark-tab-form-inputBackgroundColor" lang="en">Background Color</label>
-						<input type="text" class="form-control" id="new-bookmark-tab-form-inputBackgroundColor" name="background_color" required="">
+						<label class="control-label" for="edit-bookmark-tab-form-inputBackgroundColor" lang="en">Background Color</label>
+						<input type="text" class="form-control bookmark-pick-a-color" id="edit-bookmark-tab-form-inputBackgroundColor" name="background_color" required="">
 					</div>
 					<div class="form-group col-lg-4">
-						<label class="control-label" for="new-bookmark-tab-form-inputTextColor" lang="en">Text Color</label>
-						<input type="text" class="form-control" id="new-bookmark-tab-form-inputTextColor" name="text_color" required="">
+						<label class="control-label" for="edit-bookmark-tab-form-inputTextColor" lang="en">Text Color</label>
+						<input type="text" class="form-control bookmark-pick-a-color" id="edit-bookmark-tab-form-inputTextColor" name="text_color" required="">
+					</div>
+					<div class="form-group col-lg-4">
+						<label class="control-label" for="edit-bookmark-preview" lang="en">Preview</label>
+						<div id="edit-bookmark-preview"></div>
 					</div>
 				</div>
 			</fieldset>
@@ -709,8 +742,8 @@ class Bookmark extends Organizr
 		<h1 lang="en">Add New Bookmark Category</h1>
 		<fieldset style="border:0;">
 			<div class="form-group">
-				<label class="control-label" for="new-bookmark-category-form-inputNameNew" lang="en">Category Name</label>
-				<input type="text" class="form-control" id="new-bookmark-category-form-inputNameNew" name="category" required="" autofocus>
+				<label class="control-label" for="new-bookmark-category-form-inputName" lang="en">Category Name</label>
+				<input type="text" class="form-control" id="new-bookmark-category-form-inputName" name="category" required="" autofocus>
 			</div>
 		</fieldset>
 		<button class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right row b-none addNewBookmarkCategory" type="button"><span class="btn-label"><i class="fa fa-plus"></i></span><span lang="en">Add Category</span></button>

+ 1 - 1
api/plugins/css/bookmark.css

@@ -67,4 +67,4 @@
     color: white;
     text-align: left;
     font-weight: 500;
-}
+}

+ 3 - 3
api/plugins/healthChecks.php

@@ -72,7 +72,7 @@ class HealthChecks extends Organizr
 	
 	public function _healthCheckPluginUUID($uuid, $pass = false)
 	{
-		if (!$uuid || !$pass || $this->config['HEALTHCHECKS-PingURL'] == '') {
+		if (!$uuid || $this->config['HEALTHCHECKS-PingURL'] == '') {
 			return false;
 		}
 		$url = $this->qualifyURL($this->config['HEALTHCHECKS-PingURL']);
@@ -134,11 +134,11 @@ class HealthChecks extends Organizr
 						$pass = true;
 					}
 				}
-				$this->_healthCheckPluginUUID($v['UUID'], 'true');
+				$this->_healthCheckPluginUUID($v['UUID'], $pass);
 			}
 			$this->setAPIResponse('success', null, 200, $allItems);
 		} else {
 			$this->setAPIResponse('error', 'User does not have access', 401);
 		}
 	}
-}
+}

+ 93 - 8
api/plugins/js/bookmark-settings.js

@@ -55,6 +55,11 @@ function bookmarkTabsLaunch(){
 	$('#settings-main-tab-editor .nav-tabs').append(menuList);
 }
 
+function getColorPickerOptionsWithCallback(func){
+	return ;
+}
+
+var colorPickerInitialized = false;
 function buildBookmarkTabEditor(){
 	organizrAPI2('GET','api/v2/plugins/bookmark/tabs').success(function(data) {
 		try {
@@ -63,6 +68,22 @@ function buildBookmarkTabEditor(){
 			organizrCatchError(e,data);
 		}
 		$('#bookmarkTabEditorTable').html(buildBookmarkTabEditorItem(response.data));
+		
+		// initialize color pickers only first time
+		if(!colorPickerInitialized){
+			$("input.bookmark-pick-a-color").ColorPickerSliders({
+				placement: 'bottom',
+				color: '#987654',
+				hsvpanel: true,
+				previewformat: 'hex',
+				flat: true,
+				onchange: function(container, color){ 
+					generatePreviewBookmarkNewTab();
+					generatePreviewBookmarkEditTab();
+				}
+			});
+			colorPickerInitialized = true;
+		}
 	}).fail(function(xhr) {
 		OrganizrApiError(xhr);
 	});
@@ -135,14 +156,15 @@ function editBookmarkTabForm(id){
 			$('#originalBookmarkTabName').html(response.data.name);
 			$('#edit-bookmark-tab-form [name=url]').val(response.data.url);
 			$('#edit-bookmark-tab-form [name=image]').val(response.data.image);
-			$('#edit-bookmark-tab-form [name=background_color]').val(response.data.background_color);
-			$('#edit-bookmark-tab-form [name=text_color]').val(response.data.text_color);
+			$('#edit-bookmark-tab-form [name=background_color]').val(response.data.background_color).change();
+			$('#edit-bookmark-tab-form [name=text_color]').val(response.data.text_color).change();
 			$('#edit-bookmark-tab-form [name=id]').val(response.data.id);
 			if( response.data.url.indexOf('/?v') > 0){
 				$('#edit-bookmark-tab-form [name=url]').prop('disabled', 'true');
 			}else{
 				$('#edit-bookmark-tab-form [name=url]').prop('disabled', null);
 			}
+			generatePreviewBookmarkEditTab();
 		}catch(e) {
 			organizrCatchError(e,data);
 		}
@@ -151,6 +173,10 @@ function editBookmarkTabForm(id){
 	});
 }
 
+function newBookmarkTabForm(){
+	generatePreviewBookmarkNewTab();
+}
+
 // CHANGE ENABLED TAB
 $(document).on("change", ".bookmarkEnabledSwitch", function () {
 	var id = $(this).parent().parent().attr("data-id");
@@ -362,28 +388,89 @@ function submitBookmarkTabOrder(newTabs){
 $(document).on('change', "#new-bookmark-tab-form-chooseImage", function (e) {
 	var newIcon = $('#new-bookmark-tab-form-chooseImage').val();
 	if(newIcon !== 'Select or type Icon'){
-		$('#new-bookmark-tab-form-inputImageNew').val(newIcon);
+		$('#new-bookmark-tab-form-inputImage').val(newIcon).change();
 	}
 });
 $(document).on('change', "#edit-bookmark-tab-form-chooseImage", function (e) {
 	var newIcon = $('#edit-bookmark-tab-form-chooseImage').val();
 	if(newIcon !== 'Select or type Icon'){
-		$('#edit-bookmark-tab-form-inputImage').val(newIcon);
+		$('#edit-bookmark-tab-form-inputImage').val(newIcon).change();
 	}
 });
 $(document).on('change', "#new-bookmark-tab-form-chooseIcon", function (e) {
 	var newIcon = $('#new-bookmark-tab-form-chooseIcon').val();
 	if(newIcon !== 'Select or type Icon'){
-		$('#new-bookmark-tab-form-inputImageNew').val(newIcon);
+		$('#new-bookmark-tab-form-inputImage').val(newIcon).change();
 	}
 });
 $(document).on('change', "#edit-bookmark-tab-form-chooseIcon", function (e) {
 	var newIcon = $('#edit-bookmark-tab-form-chooseIcon').val();
 	if(newIcon !== 'Select or type Icon'){
-		$('#edit-bookmark-tab-form-inputImage').val(newIcon);
+		$('#edit-bookmark-tab-form-inputImage').val(newIcon).change();
 	}
 });
 
+// TAB PREVIEWS
+function adjustBrightness(hexCode, adjustPercent){
+	hexCode = hexCode.replace('#','');
+    if(hexCode.length != 6 && hexCode.length != 3) return;
+    if(hexCode.length == 3)
+   		hexCode = hexCode[0]+hexCode[0]+hexCode[1]+hexCode[1]+hexCode[2]+hexCode[2];
+    var result = ['#'];
+	for (var i = 0; i < 3; ++i) {
+    	var color = parseInt(hexCode[2*i] + hexCode[2*i+1], 16);
+        var adjustableLimit = adjustPercent < 0 ? color : 255 - color;
+		var adjustAmount = Math.ceil(adjustableLimit * adjustPercent);
+        var hex = (color + adjustAmount).toString(16).padStart(2, '0');
+        result.push(hex);
+    }
+	return result.join('');
+}
+
+function generatePreview(preview, name, image, colorBg, colorText){
+	var result = '<div class="BOOKMARK-category-content"> \
+					<a href="#" target="_SELF"> \
+						<div class="BOOKMARK-tab" style="border-color: ' + adjustBrightness(colorBg, 0.3) + '; background: linear-gradient(90deg, ' + adjustBrightness(colorBg, -0.3) + ' 0%, ' + colorBg + ' 70%, ' + adjustBrightness(colorBg, 0.1) + ' 100%);"> \
+							<span class="BOOKMARK-tab-image">' + iconPrefix(image) + '</span> \
+							<span class="BOOKMARK-tab-title" style="color: ' + colorText + ';">' + name + '</span> \
+						</div> \
+					</a> \
+				</div>';
+
+	preview.html(result);
+	$(".BOOKMARK-tab-image>img, .BOOKMARK-tab-image>i").removeClass("fa-fw");
+}
+
+function generatePreviewBookmarkNewTab(){
+	var preview = $('#new-bookmark-preview');
+	var name = $('#new-bookmark-tab-form-inputName').val();
+	var image = $('#new-bookmark-tab-form-inputImage').val();
+	var colorBg = $('#new-bookmark-tab-form-inputBackgroundColor').val();
+	var colorText = $('#new-bookmark-tab-form-inputTextColor').val();
+
+	generatePreview(preview, name, image, colorBg, colorText);
+}
+
+function generatePreviewBookmarkEditTab(){
+	var preview = $('#edit-bookmark-preview');
+	var name = $('#edit-bookmark-tab-form-inputName').val();
+	var image = $('#edit-bookmark-tab-form-inputImage').val();
+	var colorBg = $('#edit-bookmark-tab-form-inputBackgroundColor').val();
+	var colorText = $('#edit-bookmark-tab-form-inputTextColor').val();
+
+	generatePreview(preview, name, image, colorBg, colorText);
+}
+
+$(document).on('input', "#new-bookmark-tab-form-inputName", generatePreviewBookmarkNewTab);
+$(document).on('input change', "#new-bookmark-tab-form-inputImage", generatePreviewBookmarkNewTab);
+$(document).on('input', "#new-bookmark-tab-form-inputBackgroundColor", generatePreviewBookmarkNewTab);
+$(document).on('input', "#new-bookmark-tab-form-inputTextColor", generatePreviewBookmarkNewTab);
+
+$(document).on('input', "#edit-bookmark-tab-form-inputName", generatePreviewBookmarkEditTab);
+$(document).on('input change', "#edit-bookmark-tab-form-inputImage", generatePreviewBookmarkEditTab);
+$(document).on('input', "#edit-bookmark-tab-form-inputBackgroundColor", generatePreviewBookmarkEditTab);
+$(document).on('input', "#edit-bookmark-tab-form-inputTextColor", generatePreviewBookmarkEditTab);
+
 // CATEGORY MANAGEMENT
 function bookmarkCategoriesLaunch(){
 	var menuList = `<li onclick="changeSettingsMenu('Settings::Tab Editor::Bookmark Categories');loadSettingsPage2('api/v2/plugins/bookmark/settings_tab_editor_bookmark_categories','#settings-tab-editor-tabs','Tab Editor');" role="presentation"><a id="settings-tab-editor-tabs-anchor" href="#settings-tab-editor-tabs" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="true"><span class="visible-xs"><i class="ti-layout-tab-v"></i></span><span class="hidden-xs" lang="en">Bookmark Categories</span></a></li>`;
@@ -567,5 +654,3 @@ function submitBookmarkCategoryOrder(){
 		OrganizrApiError(xhr, 'Update Error');
 	});
 }
-
-// TAB MANAGEMENT

+ 0 - 9
api/v2/routes/opencollective.php

@@ -1,9 +0,0 @@
-<?php
-$app->get('/opencollective', function ($request, $response, $args) {
-	$Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
-	$Organizr->getOpenCollectiveBackers();
-	$response->getBody()->write(jsonE($GLOBALS['api']));
-	return $response
-		->withHeader('Content-Type', 'application/json;charset=UTF-8')
-		->withStatus($GLOBALS['responseCode']);
-});

+ 2 - 6
api/v2/routes/root.php

@@ -114,14 +114,10 @@ $app->get('/launch', function ($request, $response, $args) {
 	$GLOBALS['api']['response']['data']['plugins'] = $Organizr->pluginGlobalList();
 	$GLOBALS['api']['response']['data']['appearance'] = $Organizr->loadAppearance();
 	$GLOBALS['api']['response']['data']['status'] = $Organizr->status();
-	$GLOBALS['api']['response']['data']['sso'] = array(
-		'myPlexAccessToken' => isset($_COOKIE['mpt']) ? $_COOKIE['mpt'] : false,
-		'id_token' => isset($_COOKIE['Auth']) ? $_COOKIE['Auth'] : false,
-		'jellyfin_credentials' => isset($_COOKIE['jellyfin_credentials']) ? $_COOKIE['jellyfin_credentials'] : false
-	);
+	$GLOBALS['api']['response']['data']['sso'] = $Organizr->ssoCookies();
 	$response->getBody()->write(jsonE($GLOBALS['api']));
 	return $response
 		->withHeader('Content-Type', 'application/json;charset=UTF-8')
 		->withStatus($GLOBALS['responseCode']);
 	
-});
+});

+ 80 - 31
api/v2/routes/socks.php

@@ -1,43 +1,92 @@
 <?php
-$app->any('/socks/sonarr/{route:.*}', function ($request, $response) {
+$app->any('/multiple/socks/{app}/{instance}/{route:.*}', function ($request, $response, $args) {
 	$Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
-	$socks = $Organizr->socks(
-		'sonarrURL',
-		'sonarrSocksEnabled',
-		'sonarrSocksAuth',
-		$request,
-		'X-Api-Key'
-	);
+	switch ($args['app']) {
+		case 'sonarr':
+			$url = 'sonarrURL';
+			$enabled = 'sonarrSocksEnabled';
+			$auth = 'sonarrSocksAuth';
+			$header = 'X-Api-Key';
+			break;
+		case 'radarr':
+			$url = 'radarrURL';
+			$enabled = 'radarrSocksEnabled';
+			$auth = 'radarrSocksAuth';
+			$header = 'X-Api-Key';
+			break;
+		case 'lidarr':
+			$url = 'lidarrURL';
+			$enabled = 'lidarrSocksEnabled';
+			$auth = 'lidarrSocksAuth';
+			$header = 'X-Api-Key';
+			break;
+		case 'sabnzbd':
+			$url = 'sabnzbdURL';
+			$enabled = 'sabnzbdSocksEnabled';
+			$auth = 'sabnzbdSocksAuth';
+			$header = null;
+			break;
+		case 'nzbget':
+			$url = 'nzbgetURL';
+			$enabled = 'nzbgetSocksEnabled';
+			$auth = 'nzbgetSocksAuth';
+			$header = 'Authorization';
+			break;
+		default:
+			$Organizr->setAPIResponse('error', 'Application not supported for socks', 404);
+			$response->getBody()->write(jsonE($GLOBALS['api']));
+			return $response
+				->withHeader('Content-Type', 'application/json;charset=UTF-8')
+				->withStatus($GLOBALS['responseCode']);
+	}
+	$socks = $Organizr->socks($url, $enabled, $auth, $request, $header, $args['instance']);
 	$data = $socks ?? jsonE($GLOBALS['api']);
 	$response->getBody()->write($data);
 	return $response
 		->withHeader('Content-Type', 'application/json;charset=UTF-8')
 		->withStatus($GLOBALS['responseCode']);
 });
-$app->any('/socks/radarr/{route:.*}', function ($request, $response) {
+$app->any('/socks/{app}/{route:.*}', function ($request, $response, $args) {
 	$Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
-	$socks = $Organizr->socks(
-		'radarrURL',
-		'radarrSocksEnabled',
-		'radarrSocksAuth',
-		$request,
-		'X-Api-Key'
-	);
-	$data = $socks ?? jsonE($GLOBALS['api']);
-	$response->getBody()->write($data);
-	return $response
-		->withHeader('Content-Type', 'application/json;charset=UTF-8')
-		->withStatus($GLOBALS['responseCode']);
-});
-$app->any('/socks/lidarr/{route:.*}', function ($request, $response) {
-	$Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
-	$socks = $Organizr->socks(
-		'lidarrURL',
-		'lidarrSocksEnabled',
-		'lidarrSocksAuth',
-		$request,
-		'X-Api-Key'
-	);
+	switch ($args['app']) {
+		case 'sonarr':
+			$url = 'sonarrURL';
+			$enabled = 'sonarrSocksEnabled';
+			$auth = 'sonarrSocksAuth';
+			$header = 'X-Api-Key';
+			break;
+		case 'radarr':
+			$url = 'radarrURL';
+			$enabled = 'radarrSocksEnabled';
+			$auth = 'radarrSocksAuth';
+			$header = 'X-Api-Key';
+			break;
+		case 'lidarr':
+			$url = 'lidarrURL';
+			$enabled = 'lidarrSocksEnabled';
+			$auth = 'lidarrSocksAuth';
+			$header = 'X-Api-Key';
+			break;
+		case 'sabnzbd':
+			$url = 'sabnzbdURL';
+			$enabled = 'sabnzbdSocksEnabled';
+			$auth = 'sabnzbdSocksAuth';
+			$header = null;
+			break;
+		case 'nzbget':
+			$url = 'nzbgetURL';
+			$enabled = 'nzbgetSocksEnabled';
+			$auth = 'nzbgetSocksAuth';
+			$header = 'Authorization';
+			break;
+		default:
+			$Organizr->setAPIResponse('error', 'Application not supported for socks', 404);
+			$response->getBody()->write(jsonE($GLOBALS['api']));
+			return $response
+				->withHeader('Content-Type', 'application/json;charset=UTF-8')
+				->withStatus($GLOBALS['responseCode']);
+	}
+	$socks = $Organizr->socks($url, $enabled, $auth, $request, $header);
 	$data = $socks ?? jsonE($GLOBALS['api']);
 	$response->getBody()->write($data);
 	return $response

+ 25 - 0
api/v2/routes/sponsors.php

@@ -0,0 +1,25 @@
+<?php
+$app->get('/sponsors/opencollective', function ($request, $response, $args) {
+	$Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
+	$Organizr->getOpenCollectiveBackers();
+	$response->getBody()->write(jsonE($GLOBALS['api']));
+	return $response
+		->withHeader('Content-Type', 'application/json;charset=UTF-8')
+		->withStatus($GLOBALS['responseCode']);
+});
+$app->get('/sponsors/github', function ($request, $response, $args) {
+	$Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
+	$Organizr->getGithubSponsors();
+	$response->getBody()->write(jsonE($GLOBALS['api']));
+	return $response
+		->withHeader('Content-Type', 'application/json;charset=UTF-8')
+		->withStatus($GLOBALS['responseCode']);
+});
+$app->get('/sponsors/all', function ($request, $response, $args) {
+	$Organizr = ($request->getAttribute('Organizr')) ?? new Organizr();
+	$Organizr->getAllSponsors();
+	$response->getBody()->write(jsonE($GLOBALS['api']));
+	return $response
+		->withHeader('Content-Type', 'application/json;charset=UTF-8')
+		->withStatus($GLOBALS['responseCode']);
+});

+ 66 - 5
api/vendor/composer/InstalledVersions.php

@@ -29,7 +29,7 @@ private static $installed = array (
     'aliases' => 
     array (
     ),
-    'reference' => '4e3765a9a4e63d1a4353ba100264632bad9e38ed',
+    'reference' => '7e9a4efa44fc1396837620eb2d675a4194d97cd5',
     'name' => '__root__',
   ),
   'versions' => 
@@ -41,7 +41,7 @@ private static $installed = array (
       'aliases' => 
       array (
       ),
-      'reference' => '4e3765a9a4e63d1a4353ba100264632bad9e38ed',
+      'reference' => '7e9a4efa44fc1396837620eb2d675a4194d97cd5',
     ),
     'adldap2/adldap2' => 
     array (
@@ -115,12 +115,12 @@ private static $installed = array (
     ),
     'guzzlehttp/guzzle' => 
     array (
-      'pretty_version' => '6.5.2',
-      'version' => '6.5.2.0',
+      'pretty_version' => '7.1.1',
+      'version' => '7.1.1.0',
       'aliases' => 
       array (
       ),
-      'reference' => '43ece0e75098b7ecd8d13918293029e555a50f82',
+      'reference' => '7427d6f99df41cc01f33cd59832f721c150ffdf3',
     ),
     'guzzlehttp/promises' => 
     array (
@@ -194,6 +194,15 @@ private static $installed = array (
       ),
       'reference' => 'badb01e62383430706433191b82506b6df24ad98',
     ),
+    'myclabs/php-enum' => 
+    array (
+      'pretty_version' => '1.8.0',
+      'version' => '1.8.0.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '46cf3d8498b095bd33727b13fd5707263af99421',
+    ),
     'nikic/fast-route' => 
     array (
       'pretty_version' => 'v1.3.0',
@@ -203,6 +212,24 @@ private static $installed = array (
       ),
       'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
     ),
+    'paquettg/php-html-parser' => 
+    array (
+      'pretty_version' => '3.1.1',
+      'version' => '3.1.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '4e01a438ad5961cc2d7427eb9798d213c8a12629',
+    ),
+    'paquettg/string-encode' => 
+    array (
+      'pretty_version' => '1.0.1',
+      'version' => '1.0.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => 'a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee',
+    ),
     'paragonie/constant_time_encoding' => 
     array (
       'pretty_version' => 'v2.2.2',
@@ -230,6 +257,24 @@ private static $installed = array (
       ),
       'reference' => '3f2fd07977541b4d630ea0365ad0eceddee5179c',
     ),
+    'php-http/httplug' => 
+    array (
+      'pretty_version' => '2.2.0',
+      'version' => '2.2.0.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '191a0a1b41ed026b717421931f8d3bd2514ffbf9',
+    ),
+    'php-http/promise' => 
+    array (
+      'pretty_version' => '1.1.0',
+      'version' => '1.1.0.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '4c4c1f9b7289a2ec57cde7f1e9762a5789506f88',
+    ),
     'phpmailer/phpmailer' => 
     array (
       'pretty_version' => 'v6.2.0',
@@ -257,6 +302,22 @@ private static $installed = array (
       ),
       'reference' => 'b7ce3b176482dbbc1245ebf52b181af44c2cf55f',
     ),
+    'psr/http-client' => 
+    array (
+      'pretty_version' => '1.0.1',
+      'version' => '1.0.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
+    ),
+    'psr/http-client-implementation' => 
+    array (
+      'provided' => 
+      array (
+        0 => '1.0',
+      ),
+    ),
     'psr/http-factory' => 
     array (
       'pretty_version' => '1.0.1',

+ 1 - 0
api/vendor/composer/autoload_namespaces.php

@@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
 $baseDir = dirname($vendorDir);
 
 return array(
+    'stringEncode' => array($vendorDir . '/paquettg/string-encode/src'),
     'Requests' => array($vendorDir . '/rmccue/requests/library'),
 );

+ 5 - 0
api/vendor/composer/autoload_psr4.php

@@ -23,18 +23,23 @@ return array(
     'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
     'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'),
     'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
+    'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
     'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
     'PragmaRX\\Google2FA\\Tests\\' => array($vendorDir . '/pragmarx/google2fa/tests'),
     'PragmaRX\\Google2FA\\' => array($vendorDir . '/pragmarx/google2fa/src'),
     'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
     'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
+    'PHPHtmlParser\\' => array($vendorDir . '/paquettg/php-html-parser/src/PHPHtmlParser'),
     'OpenApi\\' => array($vendorDir . '/zircote/swagger-php/src'),
+    'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
     'League\\OAuth2\\Client\\' => array($vendorDir . '/league/oauth2-client/src'),
     'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'),
     'Kryptonit3\\Sonarr\\' => array($vendorDir . '/kryptonit3/sonarr/src'),
     'Kryptonit3\\SickRage\\' => array($vendorDir . '/kryptonit3/sickrage/src'),
     'Kryptonit3\\CouchPotato\\' => array($vendorDir . '/kryptonit3/couchpotato/src'),
     'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
+    'Http\\Promise\\' => array($vendorDir . '/php-http/promise/src'),
+    'Http\\Client\\' => array($vendorDir . '/php-http/httplug/src'),
     'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
     'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
     'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),

+ 38 - 0
api/vendor/composer/autoload_static.php

@@ -52,16 +52,22 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             'Psr\\Log\\' => 8,
             'Psr\\Http\\Server\\' => 16,
             'Psr\\Http\\Message\\' => 17,
+            'Psr\\Http\\Client\\' => 16,
             'Psr\\Container\\' => 14,
             'PragmaRX\\Google2FA\\Tests\\' => 25,
             'PragmaRX\\Google2FA\\' => 19,
             'ParagonIE\\ConstantTime\\' => 23,
             'PHPMailer\\PHPMailer\\' => 20,
+            'PHPHtmlParser\\' => 14,
         ),
         'O' => 
         array (
             'OpenApi\\' => 8,
         ),
+        'M' => 
+        array (
+            'MyCLabs\\Enum\\' => 13,
+        ),
         'L' => 
         array (
             'League\\OAuth2\\Client\\' => 21,
@@ -77,6 +83,11 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             'Illuminate\\Contracts\\' => 21,
         ),
+        'H' => 
+        array (
+            'Http\\Promise\\' => 13,
+            'Http\\Client\\' => 12,
+        ),
         'G' => 
         array (
             'GuzzleHttp\\Psr7\\' => 16,
@@ -178,6 +189,10 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
             0 => __DIR__ . '/..' . '/psr/http-factory/src',
             1 => __DIR__ . '/..' . '/psr/http-message/src',
         ),
+        'Psr\\Http\\Client\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/http-client/src',
+        ),
         'Psr\\Container\\' => 
         array (
             0 => __DIR__ . '/..' . '/psr/container/src',
@@ -198,10 +213,18 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
         ),
+        'PHPHtmlParser\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/paquettg/php-html-parser/src/PHPHtmlParser',
+        ),
         'OpenApi\\' => 
         array (
             0 => __DIR__ . '/..' . '/zircote/swagger-php/src',
         ),
+        'MyCLabs\\Enum\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/myclabs/php-enum/src',
+        ),
         'League\\OAuth2\\Client\\' => 
         array (
             0 => __DIR__ . '/..' . '/league/oauth2-client/src',
@@ -226,6 +249,14 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         array (
             0 => __DIR__ . '/..' . '/illuminate/contracts',
         ),
+        'Http\\Promise\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/php-http/promise/src',
+        ),
+        'Http\\Client\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/php-http/httplug/src',
+        ),
         'GuzzleHttp\\Psr7\\' => 
         array (
             0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src',
@@ -269,6 +300,13 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
     );
 
     public static $prefixesPsr0 = array (
+        's' => 
+        array (
+            'stringEncode' => 
+            array (
+                0 => __DIR__ . '/..' . '/paquettg/string-encode/src',
+            ),
+        ),
         'R' => 
         array (
             'Requests' => 

+ 411 - 9
api/vendor/composer/installed.json

@@ -455,39 +455,45 @@
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "6.5.2",
-            "version_normalized": "6.5.2.0",
+            "version": "7.1.1",
+            "version_normalized": "7.1.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "43ece0e75098b7ecd8d13918293029e555a50f82"
+                "reference": "7427d6f99df41cc01f33cd59832f721c150ffdf3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82",
-                "reference": "43ece0e75098b7ecd8d13918293029e555a50f82",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7427d6f99df41cc01f33cd59832f721c150ffdf3",
+                "reference": "7427d6f99df41cc01f33cd59832f721c150ffdf3",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "guzzlehttp/promises": "^1.0",
                 "guzzlehttp/psr7": "^1.6.1",
-                "php": ">=5.5"
+                "php": "^7.2.5",
+                "psr/http-client": "^1.0"
+            },
+            "provide": {
+                "psr/http-client-implementation": "1.0"
             },
             "require-dev": {
                 "ext-curl": "*",
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+                "php-http/client-integration-tests": "dev-phpunit8",
+                "phpunit/phpunit": "^8.5.5",
                 "psr/log": "^1.1"
             },
             "suggest": {
+                "ext-curl": "Required for CURL handler support",
                 "ext-intl": "Required for Internationalized Domain Name (IDN) support",
                 "psr/log": "Required for using the Log middleware"
             },
-            "time": "2019-12-23T11:57:10+00:00",
+            "time": "2020-09-30T08:51:17+00:00",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "6.5-dev"
+                    "dev-master": "7.1-dev"
                 }
             },
             "installation-source": "dist",
@@ -508,6 +514,11 @@
                     "name": "Michael Dowling",
                     "email": "mtdowling@gmail.com",
                     "homepage": "https://github.com/mtdowling"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://sagikazarmark.hu"
                 }
             ],
             "description": "Guzzle is a PHP HTTP client library",
@@ -518,9 +529,33 @@
                 "framework",
                 "http",
                 "http client",
+                "psr-18",
+                "psr-7",
                 "rest",
                 "web service"
             ],
+            "support": {
+                "issues": "https://github.com/guzzle/guzzle/issues",
+                "source": "https://github.com/guzzle/guzzle/tree/7.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/Nyholm",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/alexeyshockov",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/gmponos",
+                    "type": "github"
+                }
+            ],
             "install-path": "../guzzlehttp/guzzle"
         },
         {
@@ -946,6 +981,69 @@
             },
             "install-path": "../league/oauth2-client"
         },
+        {
+            "name": "myclabs/php-enum",
+            "version": "1.8.0",
+            "version_normalized": "1.8.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/php-enum.git",
+                "reference": "46cf3d8498b095bd33727b13fd5707263af99421"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/php-enum/zipball/46cf3d8498b095bd33727b13fd5707263af99421",
+                "reference": "46cf3d8498b095bd33727b13fd5707263af99421",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "php": "^7.3 || ^8.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5",
+                "squizlabs/php_codesniffer": "1.*",
+                "vimeo/psalm": "^4.5.1"
+            },
+            "time": "2021-02-15T16:11:48+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "MyCLabs\\Enum\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP Enum contributors",
+                    "homepage": "https://github.com/myclabs/php-enum/graphs/contributors"
+                }
+            ],
+            "description": "PHP Enum implementation",
+            "homepage": "http://github.com/myclabs/php-enum",
+            "keywords": [
+                "enum"
+            ],
+            "support": {
+                "issues": "https://github.com/myclabs/php-enum/issues",
+                "source": "https://github.com/myclabs/php-enum/tree/1.8.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/mnapoli",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../myclabs/php-enum"
+        },
         {
             "name": "nikic/fast-route",
             "version": "v1.3.0",
@@ -995,6 +1093,130 @@
             ],
             "install-path": "../nikic/fast-route"
         },
+        {
+            "name": "paquettg/php-html-parser",
+            "version": "3.1.1",
+            "version_normalized": "3.1.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paquettg/php-html-parser.git",
+                "reference": "4e01a438ad5961cc2d7427eb9798d213c8a12629"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paquettg/php-html-parser/zipball/4e01a438ad5961cc2d7427eb9798d213c8a12629",
+                "reference": "4e01a438ad5961cc2d7427eb9798d213c8a12629",
+                "shasum": ""
+            },
+            "require": {
+                "ext-curl": "*",
+                "ext-mbstring": "*",
+                "ext-zlib": "*",
+                "guzzlehttp/guzzle": "^7.0",
+                "guzzlehttp/psr7": "^1.6",
+                "myclabs/php-enum": "^1.7",
+                "paquettg/string-encode": "~1.0.0",
+                "php": ">=7.2",
+                "php-http/httplug": "^2.1"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^2.16",
+                "infection/infection": "^0.13.4",
+                "mockery/mockery": "^1.2",
+                "phan/phan": "^2.4",
+                "phpunit/phpunit": "^7.5.1"
+            },
+            "time": "2020-11-01T20:34:43+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "PHPHtmlParser\\": "src/PHPHtmlParser"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gilles Paquette",
+                    "email": "paquettg@gmail.com",
+                    "homepage": "http://gillespaquette.ca"
+                }
+            ],
+            "description": "An HTML DOM parser. It allows you to manipulate HTML. Find tags on an HTML page with selectors just like jQuery.",
+            "homepage": "https://github.com/paquettg/php-html-parser",
+            "keywords": [
+                "dom",
+                "html",
+                "parser"
+            ],
+            "support": {
+                "issues": "https://github.com/paquettg/php-html-parser/issues",
+                "source": "https://github.com/paquettg/php-html-parser/tree/3.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/paquettg/php-html-parser",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../paquettg/php-html-parser"
+        },
+        {
+            "name": "paquettg/string-encode",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/paquettg/string-encoder.git",
+                "reference": "a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/paquettg/string-encoder/zipball/a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee",
+                "reference": "a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7.5.1"
+            },
+            "time": "2018-12-21T02:25:09+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-0": {
+                    "stringEncode": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Gilles Paquette",
+                    "email": "paquettg@gmail.com",
+                    "homepage": "http://gillespaquette.ca"
+                }
+            ],
+            "description": "Facilitating the process of altering string encoding in PHP.",
+            "homepage": "https://github.com/paquettg/string-encoder",
+            "keywords": [
+                "charset",
+                "encoding",
+                "string"
+            ],
+            "support": {
+                "issues": "https://github.com/paquettg/string-encoder/issues",
+                "source": "https://github.com/paquettg/string-encoder/tree/1.0.1"
+            },
+            "install-path": "../paquettg/string-encode"
+        },
         {
             "name": "paragonie/constant_time_encoding",
             "version": "v2.2.2",
@@ -1193,6 +1415,131 @@
             ],
             "install-path": "../paragonie/sodium_compat"
         },
+        {
+            "name": "php-http/httplug",
+            "version": "2.2.0",
+            "version_normalized": "2.2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-http/httplug.git",
+                "reference": "191a0a1b41ed026b717421931f8d3bd2514ffbf9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-http/httplug/zipball/191a0a1b41ed026b717421931f8d3bd2514ffbf9",
+                "reference": "191a0a1b41ed026b717421931f8d3bd2514ffbf9",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0",
+                "php-http/promise": "^1.1",
+                "psr/http-client": "^1.0",
+                "psr/http-message": "^1.0"
+            },
+            "require-dev": {
+                "friends-of-phpspec/phpspec-code-coverage": "^4.1",
+                "phpspec/phpspec": "^5.1 || ^6.0"
+            },
+            "time": "2020-07-13T15:43:23+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Http\\Client\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Eric GELOEN",
+                    "email": "geloen.eric@gmail.com"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://sagikazarmark.hu"
+                }
+            ],
+            "description": "HTTPlug, the HTTP client abstraction for PHP",
+            "homepage": "http://httplug.io",
+            "keywords": [
+                "client",
+                "http"
+            ],
+            "support": {
+                "issues": "https://github.com/php-http/httplug/issues",
+                "source": "https://github.com/php-http/httplug/tree/master"
+            },
+            "install-path": "../php-http/httplug"
+        },
+        {
+            "name": "php-http/promise",
+            "version": "1.1.0",
+            "version_normalized": "1.1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-http/promise.git",
+                "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-http/promise/zipball/4c4c1f9b7289a2ec57cde7f1e9762a5789506f88",
+                "reference": "4c4c1f9b7289a2ec57cde7f1e9762a5789506f88",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "friends-of-phpspec/phpspec-code-coverage": "^4.3.2",
+                "phpspec/phpspec": "^5.1.2 || ^6.2"
+            },
+            "time": "2020-07-07T09:29:14+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Http\\Promise\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Joel Wurtz",
+                    "email": "joel.wurtz@gmail.com"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com"
+                }
+            ],
+            "description": "Promise used for asynchronous HTTP requests",
+            "homepage": "http://httplug.io",
+            "keywords": [
+                "promise"
+            ],
+            "support": {
+                "issues": "https://github.com/php-http/promise/issues",
+                "source": "https://github.com/php-http/promise/tree/1.1.0"
+            },
+            "install-path": "../php-http/promise"
+        },
         {
             "name": "phpmailer/phpmailer",
             "version": "v6.2.0",
@@ -1388,6 +1735,61 @@
             ],
             "install-path": "../psr/container"
         },
+        {
+            "name": "psr/http-client",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-client.git",
+                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.0 || ^8.0",
+                "psr/http-message": "^1.0"
+            },
+            "time": "2020-06-29T06:28:15+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Client\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP clients",
+            "homepage": "https://github.com/php-fig/http-client",
+            "keywords": [
+                "http",
+                "http-client",
+                "psr",
+                "psr-18"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-client/tree/master"
+            },
+            "install-path": "../psr/http-client"
+        },
         {
             "name": "psr/http-factory",
             "version": "1.0.1",

+ 66 - 5
api/vendor/composer/installed.php

@@ -6,7 +6,7 @@
     'aliases' => 
     array (
     ),
-    'reference' => '4e3765a9a4e63d1a4353ba100264632bad9e38ed',
+    'reference' => '7e9a4efa44fc1396837620eb2d675a4194d97cd5',
     'name' => '__root__',
   ),
   'versions' => 
@@ -18,7 +18,7 @@
       'aliases' => 
       array (
       ),
-      'reference' => '4e3765a9a4e63d1a4353ba100264632bad9e38ed',
+      'reference' => '7e9a4efa44fc1396837620eb2d675a4194d97cd5',
     ),
     'adldap2/adldap2' => 
     array (
@@ -92,12 +92,12 @@
     ),
     'guzzlehttp/guzzle' => 
     array (
-      'pretty_version' => '6.5.2',
-      'version' => '6.5.2.0',
+      'pretty_version' => '7.1.1',
+      'version' => '7.1.1.0',
       'aliases' => 
       array (
       ),
-      'reference' => '43ece0e75098b7ecd8d13918293029e555a50f82',
+      'reference' => '7427d6f99df41cc01f33cd59832f721c150ffdf3',
     ),
     'guzzlehttp/promises' => 
     array (
@@ -171,6 +171,15 @@
       ),
       'reference' => 'badb01e62383430706433191b82506b6df24ad98',
     ),
+    'myclabs/php-enum' => 
+    array (
+      'pretty_version' => '1.8.0',
+      'version' => '1.8.0.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '46cf3d8498b095bd33727b13fd5707263af99421',
+    ),
     'nikic/fast-route' => 
     array (
       'pretty_version' => 'v1.3.0',
@@ -180,6 +189,24 @@
       ),
       'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
     ),
+    'paquettg/php-html-parser' => 
+    array (
+      'pretty_version' => '3.1.1',
+      'version' => '3.1.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '4e01a438ad5961cc2d7427eb9798d213c8a12629',
+    ),
+    'paquettg/string-encode' => 
+    array (
+      'pretty_version' => '1.0.1',
+      'version' => '1.0.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => 'a8708e9fac9d5ddfc8fc2aac6004e2cd05d80fee',
+    ),
     'paragonie/constant_time_encoding' => 
     array (
       'pretty_version' => 'v2.2.2',
@@ -207,6 +234,24 @@
       ),
       'reference' => '3f2fd07977541b4d630ea0365ad0eceddee5179c',
     ),
+    'php-http/httplug' => 
+    array (
+      'pretty_version' => '2.2.0',
+      'version' => '2.2.0.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '191a0a1b41ed026b717421931f8d3bd2514ffbf9',
+    ),
+    'php-http/promise' => 
+    array (
+      'pretty_version' => '1.1.0',
+      'version' => '1.1.0.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '4c4c1f9b7289a2ec57cde7f1e9762a5789506f88',
+    ),
     'phpmailer/phpmailer' => 
     array (
       'pretty_version' => 'v6.2.0',
@@ -234,6 +279,22 @@
       ),
       'reference' => 'b7ce3b176482dbbc1245ebf52b181af44c2cf55f',
     ),
+    'psr/http-client' => 
+    array (
+      'pretty_version' => '1.0.1',
+      'version' => '1.0.1.0',
+      'aliases' => 
+      array (
+      ),
+      'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
+    ),
+    'psr/http-client-implementation' => 
+    array (
+      'provided' => 
+      array (
+        0 => '1.0',
+      ),
+    ),
     'psr/http-factory' => 
     array (
       'pretty_version' => '1.0.1',

+ 2 - 2
api/vendor/composer/platform_check.php

@@ -4,8 +4,8 @@
 
 $issues = array();
 
-if (!(PHP_VERSION_ID >= 70205)) {
-    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.5". You are running ' . PHP_VERSION . '.';
+if (!(PHP_VERSION_ID >= 70300)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.';
 }
 
 if ($issues) {

+ 0 - 23
api/vendor/guzzlehttp/guzzle/.php_cs

@@ -1,23 +0,0 @@
-<?php
-
-$config = PhpCsFixer\Config::create()
-    ->setRiskyAllowed(true)
-    ->setRules([
-        '@PSR2' => true,
-        'array_syntax' => ['syntax' => 'short'],
-        'declare_strict_types' => false,
-        'concat_space' => ['spacing'=>'one'],
-        'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
-        'ordered_imports' => true,
-        // 'phpdoc_align' => ['align'=>'vertical'],
-        // 'native_function_invocation' => true,
-    ])
-    ->setFinder(
-        PhpCsFixer\Finder::create()
-            ->in(__DIR__.'/src')
-            ->in(__DIR__.'/tests')
-            ->name('*.php')
-    )
-;
-
-return $config;

+ 114 - 6
api/vendor/guzzlehttp/guzzle/CHANGELOG.md

@@ -1,5 +1,115 @@
 # Change Log
 
+Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version.
+
+## UNRELEASED
+
+## 7.1.1 - 2020-09-30
+
+### Fixed
+
+- Incorrect EOF detection for response body streams on Windows.
+
+### Changed
+
+- We dont connect curl `sink` on HEAD requests.
+- Removed some PHP 5 workarounds
+
+## 7.1.0 - 2020-09-22
+
+### Added
+
+- `GuzzleHttp\MessageFormatterInterface`
+
+### Fixed
+
+- Fixed issue that caused cookies with no value not to be stored.
+- On redirects, we allow all safe methods like GET, HEAD and OPTIONS.
+- Fixed logging on empty responses.
+- Make sure MessageFormatter::format returns string
+
+### Deprecated
+
+- All functions in `GuzzleHttp` has been deprecated. Use static methods on `Utils` instead.
+- `ClientInterface::getConfig()`
+- `Client::getConfig()`
+- `Client::__call()`
+- `Utils::defaultCaBundle()`
+- `CurlFactory::LOW_CURL_VERSION_NUMBER`
+
+## 7.0.1 - 2020-06-27
+
+* Fix multiply defined functions fatal error [#2699](https://github.com/guzzle/guzzle/pull/2699)
+
+## 7.0.0 - 2020-06-27
+
+No changes since 7.0.0-rc1.
+
+## 7.0.0-rc1 - 2020-06-15
+
+### Changed
+
+* Use error level for logging errors in Middleware [#2629](https://github.com/guzzle/guzzle/pull/2629)
+* Disabled IDN support by default and require ext-intl to use it [#2675](https://github.com/guzzle/guzzle/pull/2675)
+
+## 7.0.0-beta2 - 2020-05-25
+
+### Added
+
+* Using `Utils` class instead of functions in the `GuzzleHttp` namespace. [#2546](https://github.com/guzzle/guzzle/pull/2546)
+* `ClientInterface::MAJOR_VERSION` [#2583](https://github.com/guzzle/guzzle/pull/2583)
+
+### Changed
+
+* Avoid the `getenv` function when unsafe [#2531](https://github.com/guzzle/guzzle/pull/2531)
+* Added real client methods [#2529](https://github.com/guzzle/guzzle/pull/2529)
+* Avoid functions due to global install conflicts [#2546](https://github.com/guzzle/guzzle/pull/2546)
+* Use Symfony intl-idn polyfill [#2550](https://github.com/guzzle/guzzle/pull/2550)
+* Adding methods for HTTP verbs like `Client::get()`, `Client::head()`, `Client::patch()` etc [#2529](https://github.com/guzzle/guzzle/pull/2529)
+* `ConnectException` extends `TransferException` [#2541](https://github.com/guzzle/guzzle/pull/2541)
+* Updated the default User Agent to "GuzzleHttp/7" [#2654](https://github.com/guzzle/guzzle/pull/2654)
+
+### Fixed
+
+* Various intl icu issues [#2626](https://github.com/guzzle/guzzle/pull/2626)
+
+### Removed
+
+* Pool option `pool_size` [#2528](https://github.com/guzzle/guzzle/pull/2528)
+
+## 7.0.0-beta1 - 2019-12-30
+
+The diff might look very big but 95% of Guzzle users will be able to upgrade without modification.
+Please see [the upgrade document](UPGRADING.md) that describes all BC breaking changes.
+
+### Added
+
+* Implement PSR-18 and dropped PHP 5 support [#2421](https://github.com/guzzle/guzzle/pull/2421) [#2474](https://github.com/guzzle/guzzle/pull/2474)
+* PHP 7 types [#2442](https://github.com/guzzle/guzzle/pull/2442) [#2449](https://github.com/guzzle/guzzle/pull/2449) [#2466](https://github.com/guzzle/guzzle/pull/2466) [#2497](https://github.com/guzzle/guzzle/pull/2497) [#2499](https://github.com/guzzle/guzzle/pull/2499)
+* IDN support for redirects [2424](https://github.com/guzzle/guzzle/pull/2424)
+
+### Changed
+
+* Dont allow passing null as third argument to `BadResponseException::__construct()` [#2427](https://github.com/guzzle/guzzle/pull/2427)
+* Use SAPI constant instead of method call [#2450](https://github.com/guzzle/guzzle/pull/2450)
+* Use native function invocation [#2444](https://github.com/guzzle/guzzle/pull/2444)
+* Better defaults for PHP installations with old ICU lib [2454](https://github.com/guzzle/guzzle/pull/2454)
+* Added visibility to all constants [#2462](https://github.com/guzzle/guzzle/pull/2462)
+* Dont allow passing `null` as URI to `Client::request()` and `Client::requestAsync()` [#2461](https://github.com/guzzle/guzzle/pull/2461)
+* Widen the exception argument to throwable [#2495](https://github.com/guzzle/guzzle/pull/2495)
+
+### Fixed
+
+* Logging when Promise rejected with a string [#2311](https://github.com/guzzle/guzzle/pull/2311)
+
+### Removed
+
+* Class `SeekException` [#2162](https://github.com/guzzle/guzzle/pull/2162)
+* `RequestException::getResponseBodySummary()` [#2425](https://github.com/guzzle/guzzle/pull/2425)
+* `CookieJar::getCookieValue()` [#2433](https://github.com/guzzle/guzzle/pull/2433)
+* `uri_template()` and `UriTemplate` [#2440](https://github.com/guzzle/guzzle/pull/2440)
+* Request options `save_to` and `exceptions` [#2464](https://github.com/guzzle/guzzle/pull/2464)
+
 ## 6.5.2 - 2019-12-23
 
 * idn_to_ascii() fix for old PHP versions [#2489](https://github.com/guzzle/guzzle/pull/2489)
@@ -20,7 +130,7 @@
 
 ## 6.4.1 - 2019-10-23
 
-* No `guzzle.phar` was created in 6.4.0 due expired API token. This release will fix that 
+* No `guzzle.phar` was created in 6.4.0 due expired API token. This release will fix that
 * Added `parent::__construct()` to `FileCookieJar` and `SessionCookieJar`
 
 ## 6.4.0 - 2019-10-23
@@ -342,7 +452,7 @@ object).
   * Note: This has been changed in 5.0.3 to now encode query string values by
     default unless the `rawString` argument is provided when setting the query
     string on a URL: Now allowing many more characters to be present in the
-    query string without being percent encoded. See http://tools.ietf.org/html/rfc3986#appendix-A
+    query string without being percent encoded. See https://tools.ietf.org/html/rfc3986#appendix-A
 
 ## 5.0.1 - 2014-10-16
 
@@ -384,7 +494,7 @@ interfaces.
   responses, `GuzzleHttp\Collection`, `GuzzleHttp\Url`,
   `GuzzleHttp\Query`, `GuzzleHttp\Post\PostBody`, and
   `GuzzleHttp\Cookie\SetCookie`. This blog post provides a good outline of
-  why I did this: http://ocramius.github.io/blog/fluent-interfaces-are-evil/.
+  why I did this: https://ocramius.github.io/blog/fluent-interfaces-are-evil/.
   This also makes the Guzzle message interfaces compatible with the current
   PSR-7 message proposal.
 * Removed "functions.php", so that Guzzle is truly PSR-4 compliant. Except
@@ -570,8 +680,6 @@ interfaces.
 
 ## 4.0.0 - 2014-03-29
 
-* For more information on the 4.0 transition, see:
-  http://mtdowling.com/blog/2014/03/15/guzzle-4-rc/
 * For information on changes and upgrading, see:
   https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
 * Added `GuzzleHttp\batch()` as a convenience function for sending requests in
@@ -880,7 +988,7 @@ interfaces.
 
 ## 3.4.0 - 2013-04-11
 
-* Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289
+* Bug fix: URLs are now resolved correctly based on https://tools.ietf.org/html/rfc3986#section-5.2. #289
 * Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289
 * Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263
 * Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264.

+ 0 - 18
api/vendor/guzzlehttp/guzzle/Dockerfile

@@ -1,18 +0,0 @@
-FROM composer:latest as setup
-
-RUN mkdir /guzzle
-
-WORKDIR /guzzle
-
-RUN set -xe \
-    && composer init --name=guzzlehttp/test --description="Simple project for testing Guzzle scripts" --author="Márk Sági-Kazár <mark.sagikazar@gmail.com>" --no-interaction \
-    && composer require guzzlehttp/guzzle
-
-
-FROM php:7.3
-
-RUN mkdir /guzzle
-
-WORKDIR /guzzle
-
-COPY --from=setup /guzzle /guzzle

+ 1 - 1
api/vendor/guzzlehttp/guzzle/LICENSE

@@ -1,4 +1,4 @@
-Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
+Copyright (c) 2011 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 20 - 31
api/vendor/guzzlehttp/guzzle/README.md

@@ -1,8 +1,9 @@
-Guzzle, PHP HTTP client
-=======================
+![Guzzle](.github/logo.png?raw=true)
+
+# Guzzle, PHP HTTP client
 
 [![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)
-[![Build Status](https://img.shields.io/travis/guzzle/guzzle.svg?style=flat-square)](https://travis-ci.org/guzzle/guzzle)
+[![Build Status](https://img.shields.io/github/workflow/status/guzzle/guzzle/CI?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI)
 [![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)
 
 Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
@@ -14,6 +15,7 @@ trivial to integrate with web services.
 - Can send both synchronous and asynchronous requests using the same interface.
 - Uses PSR-7 interfaces for requests, responses, and streams. This allows you
   to utilize other PSR-7 compatible libraries with Guzzle.
+- Supports PSR-18 allowing interoperability between other PSR-18 HTTP Clients.
 - Abstracts away the underlying HTTP transport, allowing you to write
   environment and transport agnostic code; i.e., no hard dependency on cURL,
   PHP streams, sockets, or non-blocking event loops.
@@ -23,11 +25,11 @@ trivial to integrate with web services.
 $client = new \GuzzleHttp\Client();
 $response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
 
-echo $response->getStatusCode(); # 200
-echo $response->getHeaderLine('content-type'); # 'application/json; charset=utf8'
-echo $response->getBody(); # '{"id": 1420053, "name": "guzzle", ...}'
+echo $response->getStatusCode(); // 200
+echo $response->getHeaderLine('content-type'); // 'application/json; charset=utf8'
+echo $response->getBody(); // '{"id": 1420053, "name": "guzzle", ...}'
 
-# Send an asynchronous request.
+// Send an asynchronous request.
 $request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
 $promise = $client->sendAsync($request)->then(function ($response) {
     echo 'I completed! ' . $response->getBody();
@@ -38,39 +40,23 @@ $promise->wait();
 
 ## Help and docs
 
+We use GitHub issues only to discuss bugs and new features. For support please refer to:
+
 - [Documentation](http://guzzlephp.org/)
 - [Stack Overflow](http://stackoverflow.com/questions/tagged/guzzle)
+- [#guzzle](https://app.slack.com/client/T0D2S9JCT/CE6UAAKL4) channel on [PHP-HTTP Slack](http://slack.httplug.io/)
 - [Gitter](https://gitter.im/guzzle/guzzle)
 
 
 ## Installing Guzzle
 
 The recommended way to install Guzzle is through
-[Composer](http://getcomposer.org).
-
-```bash
-# Install Composer
-curl -sS https://getcomposer.org/installer | php
-```
-
-Next, run the Composer command to install the latest stable version of Guzzle:
+[Composer](https://getcomposer.org/).
 
 ```bash
 composer require guzzlehttp/guzzle
 ```
 
-After installing, you need to require Composer's autoloader:
-
-```php
-require 'vendor/autoload.php';
-```
-
-You can then later update Guzzle using composer:
-
- ```bash
-composer update
- ```
-
 
 ## Version Guidance
 
@@ -79,12 +65,15 @@ composer update
 | 3.x     | EOL        | `guzzle/guzzle`     | `Guzzle`     | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No    | >= 5.3.3    |
 | 4.x     | EOL        | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A                 | No    | >= 5.4      |
 | 5.x     | EOL        | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No    | >= 5.4      |
-| 6.x     | Latest     | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes   | >= 5.5      |
+| 6.x     | Security fixes | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes   | >= 5.5      |
+| 7.x     | Latest     | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes   | >= 7.2      |
 
 [guzzle-3-repo]: https://github.com/guzzle/guzzle3
 [guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
 [guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
-[guzzle-6-repo]: https://github.com/guzzle/guzzle
+[guzzle-6-repo]: https://github.com/guzzle/guzzle/tree/6.5
+[guzzle-7-repo]: https://github.com/guzzle/guzzle
 [guzzle-3-docs]: http://guzzle3.readthedocs.org
-[guzzle-5-docs]: http://guzzle.readthedocs.org/en/5.3/
-[guzzle-6-docs]: http://guzzle.readthedocs.org/en/latest/
+[guzzle-5-docs]: http://docs.guzzlephp.org/en/5.3/
+[guzzle-6-docs]: http://docs.guzzlephp.org/en/6.5/
+[guzzle-7-docs]: http://docs.guzzlephp.org/en/latest/

+ 53 - 3
api/vendor/guzzlehttp/guzzle/UPGRADING.md

@@ -1,10 +1,60 @@
 Guzzle Upgrade Guide
 ====================
 
+6.0 to 7.0
+----------
+
+In order to take advantage of the new features of PHP, Guzzle dropped the support
+of PHP 5. The minimum supported PHP version is now PHP 7.2. Type hints and return
+types for functions and methods have been added wherever possible. 
+
+Please make sure:
+- You are calling a function or a method with the correct type.
+- If you extend a class of Guzzle; update all signatures on methods you override.
+
+#### Other backwards compatibility breaking changes
+
+- Class `GuzzleHttp\UriTemplate` is removed.
+- Class `GuzzleHttp\Exception\SeekException` is removed.
+- Classes `GuzzleHttp\Exception\BadResponseException`, `GuzzleHttp\Exception\ClientException`, 
+  `GuzzleHttp\Exception\ServerException` can no longer be initialized with an empty
+  Response as argument.
+- Class `GuzzleHttp\Exception\ConnectException` now extends `GuzzleHttp\Exception\TransferException`
+  instead of `GuzzleHttp\Exception\RequestException`.
+- Function `GuzzleHttp\Exception\ConnectException::getResponse()` is removed.
+- Function `GuzzleHttp\Exception\ConnectException::hasResponse()` is removed.
+- Constant `GuzzleHttp\ClientInterface::VERSION` is removed. Added `GuzzleHttp\ClientInterface::MAJOR_VERSION` instead.
+- Function `GuzzleHttp\Exception\RequestException::getResponseBodySummary` is removed.
+  Use `\GuzzleHttp\Psr7\get_message_body_summary` as an alternative.
+- Function `GuzzleHttp\Cookie\CookieJar::getCookieValue` is removed.
+- Request option `exception` is removed. Please use `http_errors`.
+- Request option `save_to` is removed. Please use `sink`.
+- Pool option `pool_size` is removed. Please use `concurrency`.
+- We now look for environment variables in the `$_SERVER` super global, due to thread safety issues with `getenv`. We continue to fallback to `getenv` in CLI environments, for maximum compatibility.
+- The `get`, `head`, `put`, `post`, `patch`, `delete`, `getAsync`, `headAsync`, `putAsync`, `postAsync`, `patchAsync`, and `deleteAsync` methods are now implemented as genuine methods on `GuzzleHttp\Client`, with strong typing. The original `__call` implementation remains unchanged for now, for maximum backwards compatibility, but won't be invoked under normal operation.
+- The `log` middleware will log the errors with level `error` instead of `notice` 
+- Support for international domain names (IDN) is now disabled by default, and enabling it requires installing ext-intl, linked against a modern version of the C library (ICU 4.6 or higher).
+
+#### Native functions calls
+
+All internal native functions calls of Guzzle are now prefixed with a slash. This
+change makes it impossible for method overloading by other libraries or applications.
+Example:
+
+```php
+// Before:
+curl_version();
+
+// After:
+\curl_version();
+```
+
+For the full diff you can check [here](https://github.com/guzzle/guzzle/compare/6.5.4..master).
+
 5.0 to 6.0
 ----------
 
-Guzzle now uses [PSR-7](http://www.php-fig.org/psr/psr-7/) for HTTP messages.
+Guzzle now uses [PSR-7](https://www.php-fig.org/psr/psr-7/) for HTTP messages.
 Due to the fact that these messages are immutable, this prompted a refactoring
 of Guzzle to use a middleware based system rather than an event system. Any
 HTTP message interaction (e.g., `GuzzleHttp\Message\Request`) need to be
@@ -167,7 +217,7 @@ passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP
 
 ## Removed Fluent Interfaces
 
-[Fluent interfaces were removed](http://ocramius.github.io/blog/fluent-interfaces-are-evil)
+[Fluent interfaces were removed](https://ocramius.github.io/blog/fluent-interfaces-are-evil/)
 from the following classes:
 
 - `GuzzleHttp\Collection`
@@ -820,7 +870,7 @@ HeaderInterface (e.g. toArray(), getAll(), etc.).
 3.3 to 3.4
 ----------
 
-Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
+Base URLs of a client now follow the rules of https://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs.
 
 3.2 to 3.3
 ----------

+ 20 - 7
api/vendor/guzzlehttp/guzzle/composer.json

@@ -9,7 +9,9 @@
         "web service",
         "curl",
         "client",
-        "HTTP client"
+        "HTTP client",
+        "PSR-7",
+        "PSR-18"
     ],
     "homepage": "http://guzzlephp.org/",
     "license": "MIT",
@@ -18,29 +20,40 @@
             "name": "Michael Dowling",
             "email": "mtdowling@gmail.com",
             "homepage": "https://github.com/mtdowling"
+        },
+        {
+            "name": "Márk Sági-Kazár",
+            "email": "mark.sagikazar@gmail.com",
+            "homepage": "https://sagikazarmark.hu"
         }
     ],
     "require": {
-        "php": ">=5.5",
+        "php": "^7.2.5",
         "ext-json": "*",
         "guzzlehttp/promises": "^1.0",
-        "guzzlehttp/psr7": "^1.6.1"
+        "guzzlehttp/psr7": "^1.6.1",
+        "psr/http-client": "^1.0"
+    },
+    "provide": {
+        "psr/http-client-implementation": "1.0"
     },
     "require-dev": {
         "ext-curl": "*",
-        "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+        "php-http/client-integration-tests": "dev-phpunit8",
+        "phpunit/phpunit": "^8.5.5",
         "psr/log": "^1.1"
     },
     "suggest": {
-        "psr/log": "Required for using the Log middleware",
-        "ext-intl": "Required for Internationalized Domain Name (IDN) support"
+        "ext-curl": "Required for CURL handler support",
+        "ext-intl": "Required for Internationalized Domain Name (IDN) support",
+        "psr/log": "Required for using the Log middleware"
     },
     "config": {
         "sort-packages": true
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "6.5-dev"
+            "dev-master": "7.1-dev"
         }
     },
     "autoload": {

+ 87 - 0
api/vendor/guzzlehttp/guzzle/psalm.baseline.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<files psalm-version="3.11.5@3c60609c218d4d4b3b257728b8089094e5c6c6c2">
+  <file src="src/Client.php">
+    <NullArgument occurrences="1">
+      <code>null</code>
+    </NullArgument>
+    <PossiblyUndefinedVariable occurrences="1">
+      <code>$options</code>
+    </PossiblyUndefinedVariable>
+    <UndefinedInterfaceMethod occurrences="1">
+      <code>getBoundary</code>
+    </UndefinedInterfaceMethod>
+  </file>
+  <file src="src/Cookie/CookieJar.php">
+    <PossiblyFalseOperand occurrences="1">
+      <code>$result</code>
+    </PossiblyFalseOperand>
+  </file>
+  <file src="src/Exception/RequestException.php">
+    <ImplicitToStringCast occurrences="1">
+      <code>$uri</code>
+    </ImplicitToStringCast>
+  </file>
+  <file src="src/Handler/CurlFactory.php">
+    <ImplicitToStringCast occurrences="1">
+      <code>$easy-&gt;request-&gt;getUri()</code>
+    </ImplicitToStringCast>
+    <TypeDoesNotContainType occurrences="1">
+      <code>$timeoutRequiresNoSignal &amp;&amp; \strtoupper(\substr(\PHP_OS, 0, 3)) !== 'WIN'</code>
+    </TypeDoesNotContainType>
+  </file>
+  <file src="src/Handler/CurlMultiHandler.php">
+    <InvalidArgument occurrences="1">
+      <code>$this-&gt;active</code>
+    </InvalidArgument>
+    <InvalidPropertyAssignmentValue occurrences="1">
+      <code>$this-&gt;active</code>
+    </InvalidPropertyAssignmentValue>
+    <UndefinedThisPropertyAssignment occurrences="1">
+      <code>$this-&gt;_mh</code>
+    </UndefinedThisPropertyAssignment>
+  </file>
+  <file src="src/Handler/MockHandler.php">
+    <InvalidScalarArgument occurrences="1">
+      <code>$options['delay'] * 1000</code>
+    </InvalidScalarArgument>
+  </file>
+  <file src="src/Handler/StreamHandler.php">
+    <ImplicitToStringCast occurrences="1">
+      <code>$uri</code>
+    </ImplicitToStringCast>
+  </file>
+  <file src="src/HandlerStack.php">
+    <PropertyTypeCoercion occurrences="4">
+      <code>$this-&gt;stack</code>
+      <code>$this-&gt;stack</code>
+      <code>$this-&gt;stack</code>
+      <code>$this-&gt;stack</code>
+    </PropertyTypeCoercion>
+  </file>
+  <file src="src/MessageFormatter.php">
+    <InvalidScalarArgument occurrences="1"/>
+  </file>
+  <file src="src/Middleware.php">
+    <InvalidArgument occurrences="1">
+      <code>$request</code>
+    </InvalidArgument>
+  </file>
+  <file src="src/RedirectMiddleware.php">
+    <ImplicitToStringCast occurrences="1">
+      <code>$location</code>
+    </ImplicitToStringCast>
+  </file>
+  <file src="src/RetryMiddleware.php">
+    <TooManyArguments occurrences="1">
+      <code>($this-&gt;delay)(++$options['retries'], $response)</code>
+    </TooManyArguments>
+  </file>
+  <file src="src/Utils.php">
+    <ForbiddenCode occurrences="1">
+      <code>\var_dump($input)</code>
+    </ForbiddenCode>
+    <PossiblyNullArgument occurrences="1">
+      <code>$info</code>
+    </PossiblyNullArgument>
+  </file>
+</files>

+ 16 - 0
api/vendor/guzzlehttp/guzzle/psalm.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<psalm
+    errorLevel="3"
+    resolveFromConfigFile="true"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="https://getpsalm.org/schema/config"
+    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
+    errorBaseline="psalm.baseline.xml"
+>
+    <projectFiles>
+        <directory name="src" />
+        <ignoreFiles>
+            <directory name="vendor" />
+        </ignoreFiles>
+    </projectFiles>
+</psalm>

+ 93 - 131
api/vendor/guzzlehttp/guzzle/src/Client.php

@@ -1,31 +1,25 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Cookie\CookieJar;
+use GuzzleHttp\Exception\GuzzleException;
 use GuzzleHttp\Exception\InvalidArgumentException;
-use GuzzleHttp\Promise;
-use GuzzleHttp\Psr7;
+use GuzzleHttp\Promise\PromiseInterface;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\UriInterface;
 
 /**
- * @method ResponseInterface get(string|UriInterface $uri, array $options = [])
- * @method ResponseInterface head(string|UriInterface $uri, array $options = [])
- * @method ResponseInterface put(string|UriInterface $uri, array $options = [])
- * @method ResponseInterface post(string|UriInterface $uri, array $options = [])
- * @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
- * @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
- * @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
- * @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
- * @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
- * @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
- * @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
- * @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
+ * @final
  */
-class Client implements ClientInterface
+class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
 {
-    /** @var array Default request options */
+    use ClientTrait;
+
+    /**
+     * @var array Default request options
+     */
     private $config;
 
     /**
@@ -47,9 +41,8 @@ class Client implements ClientInterface
      *   wire. The function is called with a Psr7\Http\Message\RequestInterface
      *   and array of transfer options, and must return a
      *   GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
-     *   Psr7\Http\Message\ResponseInterface on success. "handler" is a
-     *   constructor only option that cannot be overridden in per/request
-     *   options. If no handler is provided, a default handler will be created
+     *   Psr7\Http\Message\ResponseInterface on success.
+     *   If no handler is provided, a default handler will be created
      *   that enables all of the request options below by attaching all of the
      *   default middleware to the handler.
      * - base_uri: (string|UriInterface) Base URI of the client that is merged
@@ -64,8 +57,8 @@ class Client implements ClientInterface
     {
         if (!isset($config['handler'])) {
             $config['handler'] = HandlerStack::create();
-        } elseif (!is_callable($config['handler'])) {
-            throw new \InvalidArgumentException('handler must be a callable');
+        } elseif (!\is_callable($config['handler'])) {
+            throw new InvalidArgumentException('handler must be a callable');
         }
 
         // Convert the base_uri to a UriInterface
@@ -80,19 +73,21 @@ class Client implements ClientInterface
      * @param string $method
      * @param array  $args
      *
-     * @return Promise\PromiseInterface
+     * @return PromiseInterface|ResponseInterface
+     *
+     * @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
      */
     public function __call($method, $args)
     {
-        if (count($args) < 1) {
-            throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
+        if (\count($args) < 1) {
+            throw new InvalidArgumentException('Magic request methods require a URI and optional options array');
         }
 
         $uri = $args[0];
-        $opts = isset($args[1]) ? $args[1] : [];
+        $opts = $args[1] ?? [];
 
-        return substr($method, -5) === 'Async'
-            ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
+        return \substr($method, -5) === 'Async'
+            ? $this->requestAsync(\substr($method, 0, -5), $uri, $opts)
             : $this->request($method, $uri, $opts);
     }
 
@@ -101,10 +96,8 @@ class Client implements ClientInterface
      *
      * @param array $options Request options to apply to the given
      *                       request and to the transfer. See \GuzzleHttp\RequestOptions.
-     *
-     * @return Promise\PromiseInterface
      */
-    public function sendAsync(RequestInterface $request, array $options = [])
+    public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
     {
         // Merge the base URI into the request URI if needed.
         $options = $this->prepareDefaults($options);
@@ -121,12 +114,25 @@ class Client implements ClientInterface
      * @param array $options Request options to apply to the given
      *                       request and to the transfer. See \GuzzleHttp\RequestOptions.
      *
-     * @return ResponseInterface
      * @throws GuzzleException
      */
-    public function send(RequestInterface $request, array $options = [])
+    public function send(RequestInterface $request, array $options = []): ResponseInterface
+    {
+        $options[RequestOptions::SYNCHRONOUS] = true;
+        return $this->sendAsync($request, $options)->wait();
+    }
+
+    /**
+     * The HttpClient PSR (PSR-18) specify this method.
+     *
+     * @inheritDoc
+     */
+    public function sendRequest(RequestInterface $request): ResponseInterface
     {
         $options[RequestOptions::SYNCHRONOUS] = true;
+        $options[RequestOptions::ALLOW_REDIRECTS] = false;
+        $options[RequestOptions::HTTP_ERRORS] = false;
+
         return $this->sendAsync($request, $options)->wait();
     }
 
@@ -141,20 +147,18 @@ class Client implements ClientInterface
      * @param string              $method  HTTP method
      * @param string|UriInterface $uri     URI object or string.
      * @param array               $options Request options to apply. See \GuzzleHttp\RequestOptions.
-     *
-     * @return Promise\PromiseInterface
      */
-    public function requestAsync($method, $uri = '', array $options = [])
+    public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface
     {
         $options = $this->prepareDefaults($options);
         // Remove request modifying parameter because it can be done up-front.
-        $headers = isset($options['headers']) ? $options['headers'] : [];
-        $body = isset($options['body']) ? $options['body'] : null;
-        $version = isset($options['version']) ? $options['version'] : '1.1';
+        $headers = $options['headers'] ?? [];
+        $body = $options['body'] ?? null;
+        $version = $options['version'] ?? '1.1';
         // Merge the URI into the base URI.
-        $uri = $this->buildUri($uri, $options);
-        if (is_array($body)) {
-            $this->invalidBody();
+        $uri = $this->buildUri(Psr7\uri_for($uri), $options);
+        if (\is_array($body)) {
+            throw $this->invalidBody();
         }
         $request = new Psr7\Request($method, $uri, $headers, $body, $version);
         // Remove the option so that they are not doubly-applied.
@@ -174,10 +178,9 @@ class Client implements ClientInterface
      * @param string|UriInterface $uri     URI object or string.
      * @param array               $options Request options to apply. See \GuzzleHttp\RequestOptions.
      *
-     * @return ResponseInterface
      * @throws GuzzleException
      */
-    public function request($method, $uri = '', array $options = [])
+    public function request(string $method, $uri = '', array $options = []): ResponseInterface
     {
         $options[RequestOptions::SYNCHRONOUS] = true;
         return $this->requestAsync($method, $uri, $options)->wait();
@@ -193,31 +196,25 @@ class Client implements ClientInterface
      * @param string|null $option The config option to retrieve.
      *
      * @return mixed
+     *
+     * @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
      */
-    public function getConfig($option = null)
+    public function getConfig(?string $option = null)
     {
         return $option === null
             ? $this->config
             : (isset($this->config[$option]) ? $this->config[$option] : null);
     }
 
-    /**
-     * @param  string|null $uri
-     *
-     * @return UriInterface
-     */
-    private function buildUri($uri, array $config)
+    private function buildUri(UriInterface $uri, array $config): UriInterface
     {
-        // for BC we accept null which would otherwise fail in uri_for
-        $uri = Psr7\uri_for($uri === null ? '' : $uri);
-
         if (isset($config['base_uri'])) {
             $uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
         }
 
         if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
-            $idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
-            $uri = _idn_uri_convert($uri, $idnOptions);
+            $idnOptions = ($config['idn_conversion'] === true) ? \IDNA_DEFAULT : $config['idn_conversion'];
+            $uri = Utils::idnUriConvert($uri, $idnOptions);
         }
 
         return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
@@ -225,46 +222,34 @@ class Client implements ClientInterface
 
     /**
      * Configures the default options for a client.
-     *
-     * @param array $config
-     * @return void
      */
-    private function configureDefaults(array $config)
+    private function configureDefaults(array $config): void
     {
         $defaults = [
             'allow_redirects' => RedirectMiddleware::$defaultSettings,
             'http_errors'     => true,
             'decode_content'  => true,
             'verify'          => true,
-            'cookies'         => false
+            'cookies'         => false,
+            'idn_conversion'  => false,
         ];
 
-        // idn_to_ascii() is a part of ext-intl and might be not available
-        $defaults['idn_conversion'] = function_exists('idn_to_ascii')
-            // Old ICU versions don't have this constant, so we are basically stuck (see https://github.com/guzzle/guzzle/pull/2424
-            // and https://github.com/guzzle/guzzle/issues/2448 for details)
-            && (
-                defined('INTL_IDNA_VARIANT_UTS46')
-                ||
-                PHP_VERSION_ID < 70200
-            );
-
         // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
 
         // We can only trust the HTTP_PROXY environment variable in a CLI
         // process due to the fact that PHP has no reliable mechanism to
         // get environment variables that start with "HTTP_".
-        if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
-            $defaults['proxy']['http'] = getenv('HTTP_PROXY');
+        if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) {
+            $defaults['proxy']['http'] = $proxy;
         }
 
-        if ($proxy = getenv('HTTPS_PROXY')) {
+        if ($proxy = Utils::getenv('HTTPS_PROXY')) {
             $defaults['proxy']['https'] = $proxy;
         }
 
-        if ($noProxy = getenv('NO_PROXY')) {
-            $cleanedNoProxy = str_replace(' ', '', $noProxy);
-            $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
+        if ($noProxy = Utils::getenv('NO_PROXY')) {
+            $cleanedNoProxy = \str_replace(' ', '', $noProxy);
+            $defaults['proxy']['no'] = \explode(',', $cleanedNoProxy);
         }
 
         $this->config = $config + $defaults;
@@ -275,15 +260,15 @@ class Client implements ClientInterface
 
         // Add the default user-agent header.
         if (!isset($this->config['headers'])) {
-            $this->config['headers'] = ['User-Agent' => default_user_agent()];
+            $this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()];
         } else {
             // Add the User-Agent header if one was not already set.
-            foreach (array_keys($this->config['headers']) as $name) {
-                if (strtolower($name) === 'user-agent') {
+            foreach (\array_keys($this->config['headers']) as $name) {
+                if (\strtolower($name) === 'user-agent') {
                     return;
                 }
             }
-            $this->config['headers']['User-Agent'] = default_user_agent();
+            $this->config['headers']['User-Agent'] = Utils::defaultUserAgent();
         }
     }
 
@@ -291,10 +276,8 @@ class Client implements ClientInterface
      * Merges default options into the array.
      *
      * @param array $options Options to modify by reference
-     *
-     * @return array
      */
-    private function prepareDefaults(array $options)
+    private function prepareDefaults(array $options): array
     {
         $defaults = $this->config;
 
@@ -306,13 +289,13 @@ class Client implements ClientInterface
 
         // Special handling for headers is required as they are added as
         // conditional headers and as headers passed to a request ctor.
-        if (array_key_exists('headers', $options)) {
+        if (\array_key_exists('headers', $options)) {
             // Allows default headers to be unset.
             if ($options['headers'] === null) {
                 $defaults['_conditional'] = [];
                 unset($options['headers']);
-            } elseif (!is_array($options['headers'])) {
-                throw new \InvalidArgumentException('headers must be an array');
+            } elseif (!\is_array($options['headers'])) {
+                throw new InvalidArgumentException('headers must be an array');
             }
         }
 
@@ -336,23 +319,9 @@ class Client implements ClientInterface
      * as-is without merging in default options.
      *
      * @param array $options See \GuzzleHttp\RequestOptions.
-     *
-     * @return Promise\PromiseInterface
      */
-    private function transfer(RequestInterface $request, array $options)
+    private function transfer(RequestInterface $request, array $options): PromiseInterface
     {
-        // save_to -> sink
-        if (isset($options['save_to'])) {
-            $options['sink'] = $options['save_to'];
-            unset($options['save_to']);
-        }
-
-        // exceptions -> http_errors
-        if (isset($options['exceptions'])) {
-            $options['http_errors'] = $options['exceptions'];
-            unset($options['exceptions']);
-        }
-
         $request = $this->applyOptions($request, $options);
         /** @var HandlerStack $handler */
         $handler = $options['handler'];
@@ -366,13 +335,8 @@ class Client implements ClientInterface
 
     /**
      * Applies the array of request options to a request.
-     *
-     * @param RequestInterface $request
-     * @param array            $options
-     *
-     * @return RequestInterface
      */
-    private function applyOptions(RequestInterface $request, array &$options)
+    private function applyOptions(RequestInterface $request, array &$options): RequestInterface
     {
         $modify = [
             'set_headers' => [],
@@ -385,13 +349,13 @@ class Client implements ClientInterface
 
         if (isset($options['form_params'])) {
             if (isset($options['multipart'])) {
-                throw new \InvalidArgumentException('You cannot use '
+                throw new InvalidArgumentException('You cannot use '
                     . 'form_params and multipart at the same time. Use the '
                     . 'form_params option if you want to send application/'
                     . 'x-www-form-urlencoded requests, and the multipart '
                     . 'option to send multipart/form-data requests.');
             }
-            $options['body'] = http_build_query($options['form_params'], '', '&');
+            $options['body'] = \http_build_query($options['form_params'], '', '&');
             unset($options['form_params']);
             // Ensure that we don't have the header in different case and set the new value.
             $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
@@ -404,7 +368,7 @@ class Client implements ClientInterface
         }
 
         if (isset($options['json'])) {
-            $options['body'] = \GuzzleHttp\json_encode($options['json']);
+            $options['body'] = Utils::jsonEncode($options['json']);
             unset($options['json']);
             // Ensure that we don't have the header in different case and set the new value.
             $options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
@@ -420,42 +384,42 @@ class Client implements ClientInterface
         }
 
         if (isset($options['body'])) {
-            if (is_array($options['body'])) {
-                $this->invalidBody();
+            if (\is_array($options['body'])) {
+                throw $this->invalidBody();
             }
             $modify['body'] = Psr7\stream_for($options['body']);
             unset($options['body']);
         }
 
-        if (!empty($options['auth']) && is_array($options['auth'])) {
+        if (!empty($options['auth']) && \is_array($options['auth'])) {
             $value = $options['auth'];
-            $type = isset($value[2]) ? strtolower($value[2]) : 'basic';
+            $type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
             switch ($type) {
                 case 'basic':
                     // Ensure that we don't have the header in different case and set the new value.
                     $modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
                     $modify['set_headers']['Authorization'] = 'Basic '
-                        . base64_encode("$value[0]:$value[1]");
+                        . \base64_encode("$value[0]:$value[1]");
                     break;
                 case 'digest':
                     // @todo: Do not rely on curl
-                    $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
-                    $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
+                    $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
+                    $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
                     break;
                 case 'ntlm':
-                    $options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
-                    $options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
+                    $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
+                    $options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
                     break;
             }
         }
 
         if (isset($options['query'])) {
             $value = $options['query'];
-            if (is_array($value)) {
-                $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
+            if (\is_array($value)) {
+                $value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986);
             }
-            if (!is_string($value)) {
-                throw new \InvalidArgumentException('query must be a string or array');
+            if (!\is_string($value)) {
+                throw new InvalidArgumentException('query must be a string or array');
             }
             $modify['query'] = $value;
             unset($options['query']);
@@ -464,8 +428,8 @@ class Client implements ClientInterface
         // Ensure that sink is not an invalid value.
         if (isset($options['sink'])) {
             // TODO: Add more sink validation?
-            if (is_bool($options['sink'])) {
-                throw new \InvalidArgumentException('sink must not be a boolean');
+            if (\is_bool($options['sink'])) {
+                throw new InvalidArgumentException('sink must not be a boolean');
             }
         }
 
@@ -496,14 +460,12 @@ class Client implements ClientInterface
     }
 
     /**
-     * Throw Exception with pre-set message.
-     * @return void
-     * @throws InvalidArgumentException Invalid body.
+     * Return an InvalidArgumentException with pre-set message.
      */
-    private function invalidBody()
+    private function invalidBody(): InvalidArgumentException
     {
-        throw new \InvalidArgumentException('Passing in the "body" request '
-            . 'option as an array to send a POST request has been deprecated. '
+        return new InvalidArgumentException('Passing in the "body" request '
+            . 'option as an array to send a request is not supported. '
             . 'Please use the "form_params" request option to send a '
             . 'application/x-www-form-urlencoded request, or the "multipart" '
             . 'request option to send a multipart/form-data request.');

+ 10 - 13
api/vendor/guzzlehttp/guzzle/src/ClientInterface.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Exception\GuzzleException;
@@ -13,9 +14,9 @@ use Psr\Http\Message\UriInterface;
 interface ClientInterface
 {
     /**
-     * @deprecated Will be removed in Guzzle 7.0.0
+     * The Guzzle major version.
      */
-    const VERSION = '6.5.1';
+    const MAJOR_VERSION = 7;
 
     /**
      * Send an HTTP request.
@@ -24,10 +25,9 @@ interface ClientInterface
      * @param array            $options Request options to apply to the given
      *                                  request and to the transfer.
      *
-     * @return ResponseInterface
      * @throws GuzzleException
      */
-    public function send(RequestInterface $request, array $options = []);
+    public function send(RequestInterface $request, array $options = []): ResponseInterface;
 
     /**
      * Asynchronously send an HTTP request.
@@ -35,10 +35,8 @@ interface ClientInterface
      * @param RequestInterface $request Request to send
      * @param array            $options Request options to apply to the given
      *                                  request and to the transfer.
-     *
-     * @return PromiseInterface
      */
-    public function sendAsync(RequestInterface $request, array $options = []);
+    public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface;
 
     /**
      * Create and send an HTTP request.
@@ -51,10 +49,9 @@ interface ClientInterface
      * @param string|UriInterface $uri     URI object or string.
      * @param array               $options Request options to apply.
      *
-     * @return ResponseInterface
      * @throws GuzzleException
      */
-    public function request($method, $uri, array $options = []);
+    public function request(string $method, $uri, array $options = []): ResponseInterface;
 
     /**
      * Create and send an asynchronous HTTP request.
@@ -67,10 +64,8 @@ interface ClientInterface
      * @param string              $method  HTTP method
      * @param string|UriInterface $uri     URI object or string.
      * @param array               $options Request options to apply.
-     *
-     * @return PromiseInterface
      */
-    public function requestAsync($method, $uri, array $options = []);
+    public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;
 
     /**
      * Get a client configuration option.
@@ -82,6 +77,8 @@ interface ClientInterface
      * @param string|null $option The config option to retrieve.
      *
      * @return mixed
+     *
+     * @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
      */
-    public function getConfig($option = null);
+    public function getConfig(?string $option = null);
 }

+ 241 - 0
api/vendor/guzzlehttp/guzzle/src/ClientTrait.php

@@ -0,0 +1,241 @@
+<?php
+
+namespace GuzzleHttp;
+
+use GuzzleHttp\Exception\GuzzleException;
+use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * Client interface for sending HTTP requests.
+ */
+trait ClientTrait
+{
+    /**
+     * Create and send an HTTP request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well.
+     *
+     * @param string              $method  HTTP method.
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     *
+     * @throws GuzzleException
+     */
+    abstract public function request(string $method, $uri, array $options = []): ResponseInterface;
+
+    /**
+     * Create and send an HTTP GET request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     *
+     * @throws GuzzleException
+     */
+    public function get($uri, array $options = []): ResponseInterface
+    {
+        return $this->request('GET', $uri, $options);
+    }
+
+    /**
+     * Create and send an HTTP HEAD request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     *
+     * @throws GuzzleException
+     */
+    public function head($uri, array $options = []): ResponseInterface
+    {
+        return $this->request('HEAD', $uri, $options);
+    }
+
+    /**
+     * Create and send an HTTP PUT request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     *
+     * @throws GuzzleException
+     */
+    public function put($uri, array $options = []): ResponseInterface
+    {
+        return $this->request('PUT', $uri, $options);
+    }
+
+    /**
+     * Create and send an HTTP POST request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     *
+     * @throws GuzzleException
+     */
+    public function post($uri, array $options = []): ResponseInterface
+    {
+        return $this->request('POST', $uri, $options);
+    }
+
+    /**
+     * Create and send an HTTP PATCH request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     *
+     * @throws GuzzleException
+     */
+    public function patch($uri, array $options = []): ResponseInterface
+    {
+        return $this->request('PATCH', $uri, $options);
+    }
+
+    /**
+     * Create and send an HTTP DELETE request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     *
+     * @throws GuzzleException
+     */
+    public function delete($uri, array $options = []): ResponseInterface
+    {
+        return $this->request('DELETE', $uri, $options);
+    }
+
+    /**
+     * Create and send an asynchronous HTTP request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well. Use an array to provide a URL
+     * template and additional variables to use in the URL template expansion.
+     *
+     * @param string              $method  HTTP method
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     */
+    abstract public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;
+
+    /**
+     * Create and send an asynchronous HTTP GET request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well. Use an array to provide a URL
+     * template and additional variables to use in the URL template expansion.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     */
+    public function getAsync($uri, array $options = []): PromiseInterface
+    {
+        return $this->requestAsync('GET', $uri, $options);
+    }
+
+    /**
+     * Create and send an asynchronous HTTP HEAD request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well. Use an array to provide a URL
+     * template and additional variables to use in the URL template expansion.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     */
+    public function headAsync($uri, array $options = []): PromiseInterface
+    {
+        return $this->requestAsync('HEAD', $uri, $options);
+    }
+
+    /**
+     * Create and send an asynchronous HTTP PUT request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well. Use an array to provide a URL
+     * template and additional variables to use in the URL template expansion.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     */
+    public function putAsync($uri, array $options = []): PromiseInterface
+    {
+        return $this->requestAsync('PUT', $uri, $options);
+    }
+
+    /**
+     * Create and send an asynchronous HTTP POST request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well. Use an array to provide a URL
+     * template and additional variables to use in the URL template expansion.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     */
+    public function postAsync($uri, array $options = []): PromiseInterface
+    {
+        return $this->requestAsync('POST', $uri, $options);
+    }
+
+    /**
+     * Create and send an asynchronous HTTP PATCH request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well. Use an array to provide a URL
+     * template and additional variables to use in the URL template expansion.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     */
+    public function patchAsync($uri, array $options = []): PromiseInterface
+    {
+        return $this->requestAsync('PATCH', $uri, $options);
+    }
+
+    /**
+     * Create and send an asynchronous HTTP DELETE request.
+     *
+     * Use an absolute path to override the base path of the client, or a
+     * relative path to append to the base path of the client. The URL can
+     * contain the query string as well. Use an array to provide a URL
+     * template and additional variables to use in the URL template expansion.
+     *
+     * @param string|UriInterface $uri     URI object or string.
+     * @param array               $options Request options to apply.
+     */
+    public function deleteAsync($uri, array $options = []): PromiseInterface
+    {
+        return $this->requestAsync('DELETE', $uri, $options);
+    }
+}

+ 63 - 66
api/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Cookie;
 
 use Psr\Http\Message\RequestInterface;
@@ -9,20 +10,24 @@ use Psr\Http\Message\ResponseInterface;
  */
 class CookieJar implements CookieJarInterface
 {
-    /** @var SetCookie[] Loaded cookie data */
+    /**
+     * @var SetCookie[] Loaded cookie data
+     */
     private $cookies = [];
 
-    /** @var bool */
+    /**
+     * @var bool
+     */
     private $strictMode;
 
     /**
-     * @param bool $strictMode   Set to true to throw exceptions when invalid
+     * @param bool  $strictMode  Set to true to throw exceptions when invalid
      *                           cookies are added to the cookie jar.
      * @param array $cookieArray Array of SetCookie objects or a hash of
      *                           arrays that can be used with the SetCookie
      *                           constructor
      */
-    public function __construct($strictMode = false, $cookieArray = [])
+    public function __construct(bool $strictMode = false, array $cookieArray = [])
     {
         $this->strictMode = $strictMode;
 
@@ -39,10 +44,8 @@ class CookieJar implements CookieJarInterface
      *
      * @param array  $cookies Cookies to create the jar from
      * @param string $domain  Domain to set the cookies to
-     *
-     * @return self
      */
-    public static function fromArray(array $cookies, $domain)
+    public static function fromArray(array $cookies, string $domain): self
     {
         $cookieJar = new self();
         foreach ($cookies as $name => $value) {
@@ -57,26 +60,15 @@ class CookieJar implements CookieJarInterface
         return $cookieJar;
     }
 
-    /**
-     * @deprecated
-     */
-    public static function getCookieValue($value)
-    {
-        return $value;
-    }
-
     /**
      * Evaluate if this cookie should be persisted to storage
      * that survives between requests.
      *
-     * @param SetCookie $cookie Being evaluated.
-     * @param bool $allowSessionCookies If we should persist session cookies
-     * @return bool
+     * @param SetCookie $cookie              Being evaluated.
+     * @param bool      $allowSessionCookies If we should persist session cookies
      */
-    public static function shouldPersist(
-        SetCookie $cookie,
-        $allowSessionCookies = false
-    ) {
+    public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool
+    {
         if ($cookie->getExpires() || $allowSessionCookies) {
             if (!$cookie->getDiscard()) {
                 return true;
@@ -90,16 +82,13 @@ class CookieJar implements CookieJarInterface
      * Finds and returns the cookie based on the name
      *
      * @param string $name cookie name to search for
+     *
      * @return SetCookie|null cookie that was found or null if not found
      */
-    public function getCookieByName($name)
+    public function getCookieByName(string $name): ?SetCookie
     {
-        // don't allow a non string name
-        if ($name === null || !is_scalar($name)) {
-            return null;
-        }
         foreach ($this->cookies as $cookie) {
-            if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
+            if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
                 return $cookie;
             }
         }
@@ -107,37 +96,43 @@ class CookieJar implements CookieJarInterface
         return null;
     }
 
-    public function toArray()
+    /**
+     * @inheritDoc
+     */
+    public function toArray(): array
     {
-        return array_map(function (SetCookie $cookie) {
+        return \array_map(static function (SetCookie $cookie): array {
             return $cookie->toArray();
         }, $this->getIterator()->getArrayCopy());
     }
 
-    public function clear($domain = null, $path = null, $name = null)
+    /**
+     * @inheritDoc
+     */
+    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
     {
         if (!$domain) {
             $this->cookies = [];
             return;
         } elseif (!$path) {
-            $this->cookies = array_filter(
+            $this->cookies = \array_filter(
                 $this->cookies,
-                function (SetCookie $cookie) use ($domain) {
+                static function (SetCookie $cookie) use ($domain): bool {
                     return !$cookie->matchesDomain($domain);
                 }
             );
         } elseif (!$name) {
-            $this->cookies = array_filter(
+            $this->cookies = \array_filter(
                 $this->cookies,
-                function (SetCookie $cookie) use ($path, $domain) {
+                static function (SetCookie $cookie) use ($path, $domain): bool {
                     return !($cookie->matchesPath($path) &&
                         $cookie->matchesDomain($domain));
                 }
             );
         } else {
-            $this->cookies = array_filter(
+            $this->cookies = \array_filter(
                 $this->cookies,
-                function (SetCookie $cookie) use ($path, $domain, $name) {
+                static function (SetCookie $cookie) use ($path, $domain, $name) {
                     return !($cookie->getName() == $name &&
                         $cookie->matchesPath($path) &&
                         $cookie->matchesDomain($domain));
@@ -146,17 +141,23 @@ class CookieJar implements CookieJarInterface
         }
     }
 
-    public function clearSessionCookies()
+    /**
+     * @inheritDoc
+     */
+    public function clearSessionCookies(): void
     {
-        $this->cookies = array_filter(
+        $this->cookies = \array_filter(
             $this->cookies,
-            function (SetCookie $cookie) {
+            static function (SetCookie $cookie): bool {
                 return !$cookie->getDiscard() && $cookie->getExpires();
             }
         );
     }
 
-    public function setCookie(SetCookie $cookie)
+    /**
+     * @inheritDoc
+     */
+    public function setCookie(SetCookie $cookie): bool
     {
         // If the name string is empty (but not 0), ignore the set-cookie
         // string entirely.
@@ -170,10 +171,9 @@ class CookieJar implements CookieJarInterface
         if ($result !== true) {
             if ($this->strictMode) {
                 throw new \RuntimeException('Invalid cookie: ' . $result);
-            } else {
-                $this->removeCookieIfEmpty($cookie);
-                return false;
             }
+            $this->removeCookieIfEmpty($cookie);
+            return false;
         }
 
         // Resolve conflicts with previously set cookies
@@ -217,27 +217,28 @@ class CookieJar implements CookieJarInterface
         return true;
     }
 
-    public function count()
+    public function count(): int
     {
-        return count($this->cookies);
+        return \count($this->cookies);
     }
 
-    public function getIterator()
+    /**
+     * @return \ArrayIterator<int, SetCookie>
+     */
+    public function getIterator(): \ArrayIterator
     {
-        return new \ArrayIterator(array_values($this->cookies));
+        return new \ArrayIterator(\array_values($this->cookies));
     }
 
-    public function extractCookies(
-        RequestInterface $request,
-        ResponseInterface $response
-    ) {
+    public function extractCookies(RequestInterface $request, ResponseInterface $response): void
+    {
         if ($cookieHeader = $response->getHeader('Set-Cookie')) {
             foreach ($cookieHeader as $cookie) {
                 $sc = SetCookie::fromString($cookie);
                 if (!$sc->getDomain()) {
                     $sc->setDomain($request->getUri()->getHost());
                 }
-                if (0 !== strpos($sc->getPath(), '/')) {
+                if (0 !== \strpos($sc->getPath(), '/')) {
                     $sc->setPath($this->getCookiePathFromRequest($request));
                 }
                 $this->setCookie($sc);
@@ -249,30 +250,28 @@ class CookieJar implements CookieJarInterface
      * Computes cookie path following RFC 6265 section 5.1.4
      *
      * @link https://tools.ietf.org/html/rfc6265#section-5.1.4
-     *
-     * @param RequestInterface $request
-     * @return string
      */
-    private function getCookiePathFromRequest(RequestInterface $request)
+    private function getCookiePathFromRequest(RequestInterface $request): string
     {
         $uriPath = $request->getUri()->getPath();
-        if (''  === $uriPath) {
+        if ('' === $uriPath) {
             return '/';
         }
-        if (0 !== strpos($uriPath, '/')) {
+        if (0 !== \strpos($uriPath, '/')) {
             return '/';
         }
         if ('/' === $uriPath) {
             return '/';
         }
-        if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
+        $lastSlashPos = \strrpos($uriPath, '/');
+        if (0 === $lastSlashPos || false === $lastSlashPos) {
             return '/';
         }
 
-        return substr($uriPath, 0, $lastSlashPos);
+        return \substr($uriPath, 0, $lastSlashPos);
     }
 
-    public function withCookieHeader(RequestInterface $request)
+    public function withCookieHeader(RequestInterface $request): RequestInterface
     {
         $values = [];
         $uri = $request->getUri();
@@ -292,17 +291,15 @@ class CookieJar implements CookieJarInterface
         }
 
         return $values
-            ? $request->withHeader('Cookie', implode('; ', $values))
+            ? $request->withHeader('Cookie', \implode('; ', $values))
             : $request;
     }
 
     /**
      * If a cookie already exists and the server asks to set it again with a
      * null value, the cookie must be deleted.
-     *
-     * @param SetCookie $cookie
      */
-    private function removeCookieIfEmpty(SetCookie $cookie)
+    private function removeCookieIfEmpty(SetCookie $cookie): void
     {
         $cookieValue = $cookie->getValue();
         if ($cookieValue === null || $cookieValue === '') {

+ 9 - 11
api/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Cookie;
 
 use Psr\Http\Message\RequestInterface;
@@ -12,7 +13,8 @@ use Psr\Http\Message\ResponseInterface;
  * necessary. Subclasses are also responsible for storing and retrieving
  * cookies from a file, database, etc.
  *
- * @link http://docs.python.org/2/library/cookielib.html Inspiration
+ * @link https://docs.python.org/2/library/cookielib.html Inspiration
+ * @extends \IteratorAggregate<SetCookie>
  */
 interface CookieJarInterface extends \Countable, \IteratorAggregate
 {
@@ -26,7 +28,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
      *
      * @return RequestInterface returns the modified request.
      */
-    public function withCookieHeader(RequestInterface $request);
+    public function withCookieHeader(RequestInterface $request): RequestInterface;
 
     /**
      * Extract cookies from an HTTP response and store them in the CookieJar.
@@ -37,7 +39,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
     public function extractCookies(
         RequestInterface $request,
         ResponseInterface $response
-    );
+    ): void;
 
     /**
      * Sets a cookie in the cookie jar.
@@ -46,7 +48,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
      *
      * @return bool Returns true on success or false on failure
      */
-    public function setCookie(SetCookie $cookie);
+    public function setCookie(SetCookie $cookie): bool;
 
     /**
      * Remove cookies currently held in the cookie jar.
@@ -61,10 +63,8 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
      * @param string|null $domain Clears cookies matching a domain
      * @param string|null $path   Clears cookies matching a domain and path
      * @param string|null $name   Clears cookies matching a domain, path, and name
-     *
-     * @return CookieJarInterface
      */
-    public function clear($domain = null, $path = null, $name = null);
+    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void;
 
     /**
      * Discard all sessions cookies.
@@ -73,12 +73,10 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
      * field set to true. To be called when the user agent shuts down according
      * to RFC 2965.
      */
-    public function clearSessionCookies();
+    public function clearSessionCookies(): void;
 
     /**
      * Converts the cookie jar to an array.
-     *
-     * @return array
      */
-    public function toArray();
+    public function toArray(): array;
 }

+ 28 - 18
api/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php

@@ -1,33 +1,40 @@
 <?php
+
 namespace GuzzleHttp\Cookie;
 
+use GuzzleHttp\Utils;
+
 /**
  * Persists non-session cookies using a JSON formatted file
  */
 class FileCookieJar extends CookieJar
 {
-    /** @var string filename */
+    /**
+     * @var string filename
+     */
     private $filename;
 
-    /** @var bool Control whether to persist session cookies or not. */
+    /**
+     * @var bool Control whether to persist session cookies or not.
+     */
     private $storeSessionCookies;
 
     /**
      * Create a new FileCookieJar object
      *
-     * @param string $cookieFile        File to store the cookie data
-     * @param bool $storeSessionCookies Set to true to store session cookies
-     *                                  in the cookie jar.
+     * @param string $cookieFile          File to store the cookie data
+     * @param bool   $storeSessionCookies Set to true to store session cookies
+     *                                    in the cookie jar.
      *
      * @throws \RuntimeException if the file cannot be found or created
      */
-    public function __construct($cookieFile, $storeSessionCookies = false)
+    public function __construct(string $cookieFile, bool $storeSessionCookies = false)
     {
         parent::__construct();
         $this->filename = $cookieFile;
         $this->storeSessionCookies = $storeSessionCookies;
 
-        if (file_exists($cookieFile)) {
+        if (\file_exists($cookieFile)) {
             $this->load($cookieFile);
         }
     }
@@ -44,20 +51,21 @@ class FileCookieJar extends CookieJar
      * Saves the cookies to a file.
      *
      * @param string $filename File to save
+     *
      * @throws \RuntimeException if the file cannot be found or created
      */
-    public function save($filename)
+    public function save(string $filename): void
     {
         $json = [];
+        /** @var SetCookie $cookie */
         foreach ($this as $cookie) {
-            /** @var SetCookie $cookie */
             if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
                 $json[] = $cookie->toArray();
             }
         }
 
-        $jsonStr = \GuzzleHttp\json_encode($json);
-        if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {
+        $jsonStr = Utils::jsonEncode($json);
+        if (false === \file_put_contents($filename, $jsonStr, \LOCK_EX)) {
             throw new \RuntimeException("Unable to save file {$filename}");
         }
     }
@@ -68,23 +76,25 @@ class FileCookieJar extends CookieJar
      * Old cookies are kept unless overwritten by newly loaded ones.
      *
      * @param string $filename Cookie file to load.
+     *
      * @throws \RuntimeException if the file cannot be loaded.
      */
-    public function load($filename)
+    public function load(string $filename): void
     {
-        $json = file_get_contents($filename);
+        $json = \file_get_contents($filename);
         if (false === $json) {
             throw new \RuntimeException("Unable to load file {$filename}");
-        } elseif ($json === '') {
+        }
+        if ($json === '') {
             return;
         }
 
-        $data = \GuzzleHttp\json_decode($json, true);
-        if (is_array($data)) {
-            foreach (json_decode($json, true) as $cookie) {
+        $data = Utils::jsonDecode($json, true);
+        if (\is_array($data)) {
+            foreach ($data as $cookie) {
                 $this->setCookie(new SetCookie($cookie));
             }
-        } elseif (strlen($data)) {
+        } elseif (\is_scalar($data) && !empty($data)) {
             throw new \RuntimeException("Invalid cookie file: {$filename}");
         }
     }

+ 20 - 15
api/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Cookie;
 
 /**
@@ -6,21 +7,25 @@ namespace GuzzleHttp\Cookie;
  */
 class SessionCookieJar extends CookieJar
 {
-    /** @var string session key */
+    /**
+     * @var string session key
+     */
     private $sessionKey;
-    
-    /** @var bool Control whether to persist session cookies or not. */
+
+    /**
+     * @var bool Control whether to persist session cookies or not.
+     */
     private $storeSessionCookies;
 
     /**
      * Create a new SessionCookieJar object
      *
-     * @param string $sessionKey        Session key name to store the cookie
-     *                                  data in session
-     * @param bool $storeSessionCookies Set to true to store session cookies
-     *                                  in the cookie jar.
+     * @param string $sessionKey          Session key name to store the cookie
+     *                                    data in session
+     * @param bool   $storeSessionCookies Set to true to store session cookies
+     *                                    in the cookie jar.
      */
-    public function __construct($sessionKey, $storeSessionCookies = false)
+    public function __construct(string $sessionKey, bool $storeSessionCookies = false)
     {
         parent::__construct();
         $this->sessionKey = $sessionKey;
@@ -39,33 +44,33 @@ class SessionCookieJar extends CookieJar
     /**
      * Save cookies to the client session
      */
-    public function save()
+    public function save(): void
     {
         $json = [];
+        /** @var SetCookie $cookie */
         foreach ($this as $cookie) {
-            /** @var SetCookie $cookie */
             if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
                 $json[] = $cookie->toArray();
             }
         }
 
-        $_SESSION[$this->sessionKey] = json_encode($json);
+        $_SESSION[$this->sessionKey] = \json_encode($json);
     }
 
     /**
      * Load the contents of the client session into the data array
      */
-    protected function load()
+    protected function load(): void
     {
         if (!isset($_SESSION[$this->sessionKey])) {
             return;
         }
-        $data = json_decode($_SESSION[$this->sessionKey], true);
-        if (is_array($data)) {
+        $data = \json_decode($_SESSION[$this->sessionKey], true);
+        if (\is_array($data)) {
             foreach ($data as $cookie) {
                 $this->setCookie(new SetCookie($cookie));
             }
-        } elseif (strlen($data)) {
+        } elseif (\strlen($data)) {
             throw new \RuntimeException("Invalid cookie data");
         }
     }

+ 91 - 84
api/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Cookie;
 
 /**
@@ -6,7 +7,9 @@ namespace GuzzleHttp\Cookie;
  */
 class SetCookie
 {
-    /** @var array */
+    /**
+     * @var array
+     */
     private static $defaults = [
         'Name'     => null,
         'Value'    => null,
@@ -19,42 +22,42 @@ class SetCookie
         'HttpOnly' => false
     ];
 
-    /** @var array Cookie data */
+    /**
+     * @var array Cookie data
+     */
     private $data;
 
     /**
-     * Create a new SetCookie object from a string
+     * Create a new SetCookie object from a string.
      *
      * @param string $cookie Set-Cookie header string
-     *
-     * @return self
      */
-    public static function fromString($cookie)
+    public static function fromString(string $cookie): self
     {
         // Create the default return array
         $data = self::$defaults;
         // Explode the cookie string using a series of semicolons
-        $pieces = array_filter(array_map('trim', explode(';', $cookie)));
+        $pieces = \array_filter(\array_map('trim', \explode(';', $cookie)));
         // The name of the cookie (first kvp) must exist and include an equal sign.
-        if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
+        if (!isset($pieces[0]) || \strpos($pieces[0], '=') === false) {
             return new self($data);
         }
 
         // Add the cookie pieces into the parsed data array
         foreach ($pieces as $part) {
-            $cookieParts = explode('=', $part, 2);
-            $key = trim($cookieParts[0]);
+            $cookieParts = \explode('=', $part, 2);
+            $key = \trim($cookieParts[0]);
             $value = isset($cookieParts[1])
-                ? trim($cookieParts[1], " \n\r\t\0\x0B")
+                ? \trim($cookieParts[1], " \n\r\t\0\x0B")
                 : true;
 
             // Only check for non-cookies when cookies have been found
-            if (empty($data['Name'])) {
+            if (!isset($data['Name'])) {
                 $data['Name'] = $key;
                 $data['Value'] = $value;
             } else {
-                foreach (array_keys(self::$defaults) as $search) {
-                    if (!strcasecmp($search, $key)) {
+                foreach (\array_keys(self::$defaults) as $search) {
+                    if (!\strcasecmp($search, $key)) {
                         $data[$search] = $value;
                         continue 2;
                     }
@@ -71,13 +74,19 @@ class SetCookie
      */
     public function __construct(array $data = [])
     {
-        $this->data = array_replace(self::$defaults, $data);
+        /** @var array|null $replaced will be null in case of replace error */
+        $replaced = \array_replace(self::$defaults, $data);
+        if ($replaced === null) {
+            throw new \InvalidArgumentException('Unable to replace the default values for the Cookie.');
+        }
+
+        $this->data = $replaced;
         // Extract the Expires value and turn it into a UNIX timestamp if needed
         if (!$this->getExpires() && $this->getMaxAge()) {
             // Calculate the Expires date
-            $this->setExpires(time() + $this->getMaxAge());
-        } elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
-            $this->setExpires($this->getExpires());
+            $this->setExpires(\time() + $this->getMaxAge());
+        } elseif (null !== ($expires = $this->getExpires()) && !\is_numeric($expires)) {
+            $this->setExpires($expires);
         }
     }
 
@@ -87,23 +96,23 @@ class SetCookie
         foreach ($this->data as $k => $v) {
             if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
                 if ($k === 'Expires') {
-                    $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
+                    $str .= 'Expires=' . \gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
                 } else {
                     $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
                 }
             }
         }
 
-        return rtrim($str, '; ');
+        return \rtrim($str, '; ');
     }
 
-    public function toArray()
+    public function toArray(): array
     {
         return $this->data;
     }
 
     /**
-     * Get the cookie name
+     * Get the cookie name.
      *
      * @return string
      */
@@ -113,19 +122,19 @@ class SetCookie
     }
 
     /**
-     * Set the cookie name
+     * Set the cookie name.
      *
      * @param string $name Cookie name
      */
-    public function setName($name)
+    public function setName($name): void
     {
         $this->data['Name'] = $name;
     }
 
     /**
-     * Get the cookie value
+     * Get the cookie value.
      *
-     * @return string
+     * @return string|null
      */
     public function getValue()
     {
@@ -133,17 +142,17 @@ class SetCookie
     }
 
     /**
-     * Set the cookie value
+     * Set the cookie value.
      *
      * @param string $value Cookie value
      */
-    public function setValue($value)
+    public function setValue($value): void
     {
         $this->data['Value'] = $value;
     }
 
     /**
-     * Get the domain
+     * Get the domain.
      *
      * @return string|null
      */
@@ -153,17 +162,17 @@ class SetCookie
     }
 
     /**
-     * Set the domain of the cookie
+     * Set the domain of the cookie.
      *
      * @param string $domain
      */
-    public function setDomain($domain)
+    public function setDomain($domain): void
     {
         $this->data['Domain'] = $domain;
     }
 
     /**
-     * Get the path
+     * Get the path.
      *
      * @return string
      */
@@ -173,17 +182,17 @@ class SetCookie
     }
 
     /**
-     * Set the path of the cookie
+     * Set the path of the cookie.
      *
      * @param string $path Path of the cookie
      */
-    public function setPath($path)
+    public function setPath($path): void
     {
         $this->data['Path'] = $path;
     }
 
     /**
-     * Maximum lifetime of the cookie in seconds
+     * Maximum lifetime of the cookie in seconds.
      *
      * @return int|null
      */
@@ -193,19 +202,19 @@ class SetCookie
     }
 
     /**
-     * Set the max-age of the cookie
+     * Set the max-age of the cookie.
      *
      * @param int $maxAge Max age of the cookie in seconds
      */
-    public function setMaxAge($maxAge)
+    public function setMaxAge($maxAge): void
     {
         $this->data['Max-Age'] = $maxAge;
     }
 
     /**
-     * The UNIX timestamp when the cookie Expires
+     * The UNIX timestamp when the cookie Expires.
      *
-     * @return mixed
+     * @return string|int|null
      */
     public function getExpires()
     {
@@ -213,19 +222,19 @@ class SetCookie
     }
 
     /**
-     * Set the unix timestamp for which the cookie will expire
+     * Set the unix timestamp for which the cookie will expire.
      *
-     * @param int $timestamp Unix timestamp
+     * @param int|string $timestamp Unix timestamp or any English textual datetime description.
      */
-    public function setExpires($timestamp)
+    public function setExpires($timestamp): void
     {
-        $this->data['Expires'] = is_numeric($timestamp)
+        $this->data['Expires'] = \is_numeric($timestamp)
             ? (int) $timestamp
-            : strtotime($timestamp);
+            : \strtotime($timestamp);
     }
 
     /**
-     * Get whether or not this is a secure cookie
+     * Get whether or not this is a secure cookie.
      *
      * @return bool|null
      */
@@ -235,17 +244,17 @@ class SetCookie
     }
 
     /**
-     * Set whether or not the cookie is secure
+     * Set whether or not the cookie is secure.
      *
      * @param bool $secure Set to true or false if secure
      */
-    public function setSecure($secure)
+    public function setSecure($secure): void
     {
         $this->data['Secure'] = $secure;
     }
 
     /**
-     * Get whether or not this is a session cookie
+     * Get whether or not this is a session cookie.
      *
      * @return bool|null
      */
@@ -255,17 +264,17 @@ class SetCookie
     }
 
     /**
-     * Set whether or not this is a session cookie
+     * Set whether or not this is a session cookie.
      *
      * @param bool $discard Set to true or false if this is a session cookie
      */
-    public function setDiscard($discard)
+    public function setDiscard($discard): void
     {
         $this->data['Discard'] = $discard;
     }
 
     /**
-     * Get whether or not this is an HTTP only cookie
+     * Get whether or not this is an HTTP only cookie.
      *
      * @return bool
      */
@@ -275,11 +284,11 @@ class SetCookie
     }
 
     /**
-     * Set whether or not this is an HTTP only cookie
+     * Set whether or not this is an HTTP only cookie.
      *
      * @param bool $httpOnly Set to true or false if this is HTTP only
      */
-    public function setHttpOnly($httpOnly)
+    public function setHttpOnly($httpOnly): void
     {
         $this->data['HttpOnly'] = $httpOnly;
     }
@@ -298,10 +307,8 @@ class SetCookie
      *   path is a %x2F ("/") character.
      *
      * @param string $requestPath Path to check against
-     *
-     * @return bool
      */
-    public function matchesPath($requestPath)
+    public function matchesPath(string $requestPath): bool
     {
         $cookiePath = $this->getPath();
 
@@ -311,71 +318,71 @@ class SetCookie
         }
 
         // Ensure that the cookie-path is a prefix of the request path.
-        if (0 !== strpos($requestPath, $cookiePath)) {
+        if (0 !== \strpos($requestPath, $cookiePath)) {
             return false;
         }
 
         // Match if the last character of the cookie-path is "/"
-        if (substr($cookiePath, -1, 1) === '/') {
+        if (\substr($cookiePath, -1, 1) === '/') {
             return true;
         }
 
         // Match if the first character not included in cookie path is "/"
-        return substr($requestPath, strlen($cookiePath), 1) === '/';
+        return \substr($requestPath, \strlen($cookiePath), 1) === '/';
     }
 
     /**
-     * Check if the cookie matches a domain value
+     * Check if the cookie matches a domain value.
      *
      * @param string $domain Domain to check against
-     *
-     * @return bool
      */
-    public function matchesDomain($domain)
+    public function matchesDomain(string $domain): bool
     {
+        $cookieDomain = $this->getDomain();
+        if (null === $cookieDomain) {
+            return true;
+        }
+
         // Remove the leading '.' as per spec in RFC 6265.
-        // http://tools.ietf.org/html/rfc6265#section-5.2.3
-        $cookieDomain = ltrim($this->getDomain(), '.');
+        // https://tools.ietf.org/html/rfc6265#section-5.2.3
+        $cookieDomain = \ltrim($cookieDomain, '.');
 
         // Domain not set or exact match.
-        if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
+        if (!$cookieDomain || !\strcasecmp($domain, $cookieDomain)) {
             return true;
         }
 
         // Matching the subdomain according to RFC 6265.
-        // http://tools.ietf.org/html/rfc6265#section-5.1.3
-        if (filter_var($domain, FILTER_VALIDATE_IP)) {
+        // https://tools.ietf.org/html/rfc6265#section-5.1.3
+        if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
             return false;
         }
 
-        return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
+        return (bool) \preg_match('/\.' . \preg_quote($cookieDomain, '/') . '$/', $domain);
     }
 
     /**
-     * Check if the cookie is expired
-     *
-     * @return bool
+     * Check if the cookie is expired.
      */
-    public function isExpired()
+    public function isExpired(): bool
     {
-        return $this->getExpires() !== null && time() > $this->getExpires();
+        return $this->getExpires() !== null && \time() > $this->getExpires();
     }
 
     /**
-     * Check if the cookie is valid according to RFC 6265
+     * Check if the cookie is valid according to RFC 6265.
      *
      * @return bool|string Returns true if valid or an error message if invalid
      */
     public function validate()
     {
-        // Names must not be empty, but can be 0
         $name = $this->getName();
-        if (empty($name) && !is_numeric($name)) {
+        if ($name === '') {
             return 'The cookie name must not be empty';
         }
 
         // Check if any of the invalid characters are present in the cookie name
-        if (preg_match(
+        if (\preg_match(
             '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
             $name
         )) {
@@ -384,17 +391,17 @@ class SetCookie
                 . 'following characters: ()<>@,;:\"/?={}';
         }
 
-        // Value must not be empty, but can be 0
+        // Value must not be null. 0 and empty string are valid. Empty strings
+        // are technically against RFC 6265, but known to happen in the wild.
         $value = $this->getValue();
-        if (empty($value) && !is_numeric($value)) {
+        if ($value === null) {
             return 'The cookie value must not be empty';
         }
 
-        // Domains must not be empty, but can be 0
-        // A "0" is not a valid internet domain, but may be used as server name
-        // in a private network.
+        // Domains must not be empty, but can be 0. "0" is not a valid internet
+        // domain, but may be used as server name in a private network.
         $domain = $this->getDomain();
-        if (empty($domain) && !is_numeric($domain)) {
+        if ($domain === null || $domain === '') {
             return 'The cookie domain must not be empty';
         }
 

+ 21 - 9
api/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
 use Psr\Http\Message\RequestInterface;
@@ -10,18 +11,29 @@ use Psr\Http\Message\ResponseInterface;
 class BadResponseException extends RequestException
 {
     public function __construct(
-        $message,
+        string $message,
         RequestInterface $request,
-        ResponseInterface $response = null,
-        \Exception $previous = null,
+        ResponseInterface $response,
+        \Throwable $previous = null,
         array $handlerContext = []
     ) {
-        if (null === $response) {
-            @trigger_error(
-                'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
-                E_USER_DEPRECATED
-            );
-        }
         parent::__construct($message, $request, $response, $previous, $handlerContext);
     }
+
+    /**
+     * Current exception and the ones that extend it will always have a response.
+     */
+    public function hasResponse(): bool
+    {
+        return true;
+    }
+
+    /**
+     * This function narrows the return type from the parent class and does not allow it to be nullable.
+     */
+    public function getResponse(): ResponseInterface
+    {
+        /** @var ResponseInterface */
+        return parent::getResponse();
+    }
 }

+ 1 - 0
api/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
 /**

+ 29 - 10
api/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php

@@ -1,6 +1,8 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
+use Psr\Http\Client\NetworkExceptionInterface;
 use Psr\Http\Message\RequestInterface;
 
 /**
@@ -8,30 +10,47 @@ use Psr\Http\Message\RequestInterface;
  *
  * Note that no response is present for a ConnectException
  */
-class ConnectException extends RequestException
+class ConnectException extends TransferException implements NetworkExceptionInterface
 {
+    /**
+     * @var RequestInterface
+     */
+    private $request;
+
+    /**
+     * @var array
+     */
+    private $handlerContext;
+
     public function __construct(
-        $message,
+        string $message,
         RequestInterface $request,
-        \Exception $previous = null,
+        \Throwable $previous = null,
         array $handlerContext = []
     ) {
-        parent::__construct($message, $request, null, $previous, $handlerContext);
+        parent::__construct($message, 0, $previous);
+        $this->request = $request;
+        $this->handlerContext = $handlerContext;
     }
 
     /**
-     * @return null
+     * Get the request that caused the exception
      */
-    public function getResponse()
+    public function getRequest(): RequestInterface
     {
-        return null;
+        return $this->request;
     }
 
     /**
-     * @return bool
+     * Get contextual information about the error from the underlying handler.
+     *
+     * The contents of this array will vary depending on which handler you are
+     * using. It may also be just an empty array. Relying on this data will
+     * couple you to a specific handler, but can give more debug information
+     * when needed.
      */
-    public function hasResponse()
+    public function getHandlerContext(): array
     {
-        return false;
+        return $this->handlerContext;
     }
 }

+ 4 - 18
api/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php

@@ -1,23 +1,9 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
-use Throwable;
+use Psr\Http\Client\ClientExceptionInterface;
 
-if (interface_exists(Throwable::class)) {
-    interface GuzzleException extends Throwable
-    {
-    }
-} else {
-    /**
-     * @method string getMessage()
-     * @method \Throwable|null getPrevious()
-     * @method mixed getCode()
-     * @method string getFile()
-     * @method int getLine()
-     * @method array getTrace()
-     * @method string getTraceAsString()
-     */
-    interface GuzzleException
-    {
-    }
+interface GuzzleException extends ClientExceptionInterface
+{
 }

+ 29 - 57
api/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php

@@ -1,7 +1,8 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
-use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Client\RequestExceptionInterface;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\UriInterface;
@@ -9,28 +10,32 @@ use Psr\Http\Message\UriInterface;
 /**
  * HTTP Request exception
  */
-class RequestException extends TransferException
+class RequestException extends TransferException implements RequestExceptionInterface
 {
-    /** @var RequestInterface */
+    /**
+     * @var RequestInterface
+     */
     private $request;
 
-    /** @var ResponseInterface|null */
+    /**
+     * @var ResponseInterface|null
+     */
     private $response;
 
-    /** @var array */
+    /**
+     * @var array
+     */
     private $handlerContext;
 
     public function __construct(
-        $message,
+        string $message,
         RequestInterface $request,
         ResponseInterface $response = null,
-        \Exception $previous = null,
+        \Throwable $previous = null,
         array $handlerContext = []
     ) {
         // Set the code of the exception if the response is set and not future.
-        $code = $response && !($response instanceof PromiseInterface)
-            ? $response->getStatusCode()
-            : 0;
+        $code = $response ? $response->getStatusCode() : 0;
         parent::__construct($message, $code, $previous);
         $this->request = $request;
         $this->response = $response;
@@ -39,13 +44,8 @@ class RequestException extends TransferException
 
     /**
      * Wrap non-RequestExceptions with a RequestException
-     *
-     * @param RequestInterface $request
-     * @param \Exception       $e
-     *
-     * @return RequestException
      */
-    public static function wrapException(RequestInterface $request, \Exception $e)
+    public static function wrapException(RequestInterface $request, \Throwable $e): RequestException
     {
         return $e instanceof RequestException
             ? $e
@@ -57,17 +57,15 @@ class RequestException extends TransferException
      *
      * @param RequestInterface  $request  Request
      * @param ResponseInterface $response Response received
-     * @param \Exception        $previous Previous exception
+     * @param \Throwable        $previous Previous exception
      * @param array             $ctx      Optional handler context.
-     *
-     * @return self
      */
     public static function create(
         RequestInterface $request,
         ResponseInterface $response = null,
-        \Exception $previous = null,
+        \Throwable $previous = null,
         array $ctx = []
-    ) {
+    ): self {
         if (!$response) {
             return new self(
                 'Error completing request',
@@ -78,7 +76,7 @@ class RequestException extends TransferException
             );
         }
 
-        $level = (int) floor($response->getStatusCode() / 100);
+        $level = (int) \floor($response->getStatusCode() / 100);
         if ($level === 4) {
             $label = 'Client error';
             $className = ClientException::class;
@@ -95,7 +93,7 @@ class RequestException extends TransferException
 
         // Client Error: `GET /` resulted in a `404 Not Found` response:
         // <html> ... (truncated)
-        $message = sprintf(
+        $message = \sprintf(
             '%s: `%s %s` resulted in a `%s %s` response',
             $label,
             $request->getMethod(),
@@ -104,7 +102,7 @@ class RequestException extends TransferException
             $response->getReasonPhrase()
         );
 
-        $summary = static::getResponseBodySummary($response);
+        $summary = \GuzzleHttp\Psr7\get_message_body_summary($response);
 
         if ($summary !== null) {
             $message .= ":\n{$summary}\n";
@@ -113,33 +111,15 @@ class RequestException extends TransferException
         return new $className($message, $request, $response, $previous, $ctx);
     }
 
-    /**
-     * Get a short summary of the response
-     *
-     * Will return `null` if the response is not printable.
-     *
-     * @param ResponseInterface $response
-     *
-     * @return string|null
-     */
-    public static function getResponseBodySummary(ResponseInterface $response)
-    {
-        return \GuzzleHttp\Psr7\get_message_body_summary($response);
-    }
-
     /**
      * Obfuscates URI if there is a username and a password present
-     *
-     * @param UriInterface $uri
-     *
-     * @return UriInterface
      */
-    private static function obfuscateUri(UriInterface $uri)
+    private static function obfuscateUri(UriInterface $uri): UriInterface
     {
         $userInfo = $uri->getUserInfo();
 
-        if (false !== ($pos = strpos($userInfo, ':'))) {
-            return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
+        if (false !== ($pos = \strpos($userInfo, ':'))) {
+            return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
         }
 
         return $uri;
@@ -147,30 +127,24 @@ class RequestException extends TransferException
 
     /**
      * Get the request that caused the exception
-     *
-     * @return RequestInterface
      */
-    public function getRequest()
+    public function getRequest(): RequestInterface
     {
         return $this->request;
     }
 
     /**
      * Get the associated response
-     *
-     * @return ResponseInterface|null
      */
-    public function getResponse()
+    public function getResponse(): ?ResponseInterface
     {
         return $this->response;
     }
 
     /**
      * Check if a response was received
-     *
-     * @return bool
      */
-    public function hasResponse()
+    public function hasResponse(): bool
     {
         return $this->response !== null;
     }
@@ -182,10 +156,8 @@ class RequestException extends TransferException
      * using. It may also be just an empty array. Relying on this data will
      * couple you to a specific handler, but can give more debug information
      * when needed.
-     *
-     * @return array
      */
-    public function getHandlerContext()
+    public function getHandlerContext(): array
     {
         return $this->handlerContext;
     }

+ 0 - 27
api/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php

@@ -1,27 +0,0 @@
-<?php
-namespace GuzzleHttp\Exception;
-
-use Psr\Http\Message\StreamInterface;
-
-/**
- * Exception thrown when a seek fails on a stream.
- */
-class SeekException extends \RuntimeException implements GuzzleException
-{
-    private $stream;
-
-    public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
-    {
-        $this->stream = $stream;
-        $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
-        parent::__construct($msg);
-    }
-
-    /**
-     * @return StreamInterface
-     */
-    public function getStream()
-    {
-        return $this->stream;
-    }
-}

+ 1 - 0
api/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
 /**

+ 1 - 0
api/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
 class TooManyRedirectsException extends RequestException

+ 1 - 0
api/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Exception;
 
 class TransferException extends \RuntimeException implements GuzzleException

+ 167 - 152
api/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php

@@ -1,37 +1,49 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
 use GuzzleHttp\Exception\ConnectException;
 use GuzzleHttp\Exception\RequestException;
 use GuzzleHttp\Promise\FulfilledPromise;
-use GuzzleHttp\Psr7;
+use GuzzleHttp\Promise\PromiseInterface;
 use GuzzleHttp\Psr7\LazyOpenStream;
 use GuzzleHttp\TransferStats;
+use GuzzleHttp\Utils;
 use Psr\Http\Message\RequestInterface;
 
 /**
  * Creates curl resources from a request
+ *
+ * @final
  */
 class CurlFactory implements CurlFactoryInterface
 {
-    const CURL_VERSION_STR = 'curl_version';
-    const LOW_CURL_VERSION_NUMBER = '7.21.2';
+    public const CURL_VERSION_STR = 'curl_version';
+
+    /**
+     * @deprecated
+     */
+    public const LOW_CURL_VERSION_NUMBER = '7.21.2';
 
-    /** @var array */
+    /**
+     * @var resource[]
+     */
     private $handles = [];
 
-    /** @var int Total number of idle handles to keep in cache */
+    /**
+     * @var int Total number of idle handles to keep in cache
+     */
     private $maxHandles;
 
     /**
      * @param int $maxHandles Maximum number of idle handles.
      */
-    public function __construct($maxHandles)
+    public function __construct(int $maxHandles)
     {
         $this->maxHandles = $maxHandles;
     }
 
-    public function create(RequestInterface $request, array $options)
+    public function create(RequestInterface $request, array $options): EasyHandle
     {
         if (isset($options['curl']['body_as_string'])) {
             $options['_body_as_string'] = $options['curl']['body_as_string'];
@@ -49,35 +61,35 @@ class CurlFactory implements CurlFactoryInterface
 
         // Add handler options from the request configuration options
         if (isset($options['curl'])) {
-            $conf = array_replace($conf, $options['curl']);
+            $conf = \array_replace($conf, $options['curl']);
         }
 
-        $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
+        $conf[\CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
         $easy->handle = $this->handles
-            ? array_pop($this->handles)
-            : curl_init();
+            ? \array_pop($this->handles)
+            : \curl_init();
         curl_setopt_array($easy->handle, $conf);
 
         return $easy;
     }
 
-    public function release(EasyHandle $easy)
+    public function release(EasyHandle $easy): void
     {
         $resource = $easy->handle;
         unset($easy->handle);
 
-        if (count($this->handles) >= $this->maxHandles) {
-            curl_close($resource);
+        if (\count($this->handles) >= $this->maxHandles) {
+            \curl_close($resource);
         } else {
             // Remove all callback functions as they can hold onto references
             // and are not cleaned up by curl_reset. Using curl_setopt_array
             // does not work for some reason, so removing each one
             // individually.
-            curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
-            curl_setopt($resource, CURLOPT_READFUNCTION, null);
-            curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
-            curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
-            curl_reset($resource);
+            \curl_setopt($resource, \CURLOPT_HEADERFUNCTION, null);
+            \curl_setopt($resource, \CURLOPT_READFUNCTION, null);
+            \curl_setopt($resource, \CURLOPT_WRITEFUNCTION, null);
+            \curl_setopt($resource, \CURLOPT_PROGRESSFUNCTION, null);
+            \curl_reset($resource);
             $this->handles[] = $resource;
         }
     }
@@ -86,17 +98,14 @@ class CurlFactory implements CurlFactoryInterface
      * Completes a cURL transaction, either returning a response promise or a
      * rejected promise.
      *
-     * @param callable             $handler
-     * @param EasyHandle           $easy
-     * @param CurlFactoryInterface $factory Dictates how the handle is released
-     *
-     * @return \GuzzleHttp\Promise\PromiseInterface
+     * @param callable(RequestInterface, array): PromiseInterface $handler
+     * @param CurlFactoryInterface                                $factory Dictates how the handle is released
      */
     public static function finish(
         callable $handler,
         EasyHandle $easy,
         CurlFactoryInterface $factory
-    ) {
+    ): PromiseInterface {
         if (isset($easy->options['on_stats'])) {
             self::invokeStats($easy);
         }
@@ -117,10 +126,10 @@ class CurlFactory implements CurlFactoryInterface
         return new FulfilledPromise($easy->response);
     }
 
-    private static function invokeStats(EasyHandle $easy)
+    private static function invokeStats(EasyHandle $easy): void
     {
-        $curlStats = curl_getinfo($easy->handle);
-        $curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);
+        $curlStats = \curl_getinfo($easy->handle);
+        $curlStats['appconnect_time'] = \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME);
         $stats = new TransferStats(
             $easy->request,
             $easy->response,
@@ -128,21 +137,24 @@ class CurlFactory implements CurlFactoryInterface
             $easy->errno,
             $curlStats
         );
-        call_user_func($easy->options['on_stats'], $stats);
+        ($easy->options['on_stats'])($stats);
     }
 
+    /**
+     * @param callable(RequestInterface, array): PromiseInterface $handler
+     */
     private static function finishError(
         callable $handler,
         EasyHandle $easy,
         CurlFactoryInterface $factory
-    ) {
+    ): PromiseInterface {
         // Get error information and release the handle to the factory.
         $ctx = [
             'errno' => $easy->errno,
-            'error' => curl_error($easy->handle),
-            'appconnect_time' => curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME),
-        ] + curl_getinfo($easy->handle);
-        $ctx[self::CURL_VERSION_STR] = curl_version()['version'];
+            'error' => \curl_error($easy->handle),
+            'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME),
+        ] + \curl_getinfo($easy->handle);
+        $ctx[self::CURL_VERSION_STR] = \curl_version()['version'];
         $factory->release($easy);
 
         // Retry when nothing is present or when curl failed to rewind.
@@ -155,14 +167,14 @@ class CurlFactory implements CurlFactoryInterface
         return self::createRejection($easy, $ctx);
     }
 
-    private static function createRejection(EasyHandle $easy, array $ctx)
+    private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface
     {
         static $connectionErrors = [
-            CURLE_OPERATION_TIMEOUTED  => true,
-            CURLE_COULDNT_RESOLVE_HOST => true,
-            CURLE_COULDNT_CONNECT      => true,
-            CURLE_SSL_CONNECT_ERROR    => true,
-            CURLE_GOT_NOTHING          => true,
+            \CURLE_OPERATION_TIMEOUTED  => true,
+            \CURLE_COULDNT_RESOLVE_HOST => true,
+            \CURLE_COULDNT_CONNECT      => true,
+            \CURLE_SSL_CONNECT_ERROR    => true,
+            \CURLE_GOT_NOTHING          => true,
         ];
 
         // If an exception was encountered during the onHeaders event, then
@@ -178,21 +190,16 @@ class CurlFactory implements CurlFactoryInterface
                 )
             );
         }
-        if (version_compare($ctx[self::CURL_VERSION_STR], self::LOW_CURL_VERSION_NUMBER)) {
-            $message = sprintf(
-                'cURL error %s: %s (%s)',
-                $ctx['errno'],
-                $ctx['error'],
-                'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
-            );
-        } else {
-            $message = sprintf(
-                'cURL error %s: %s (%s) for %s',
-                $ctx['errno'],
-                $ctx['error'],
-                'see https://curl.haxx.se/libcurl/c/libcurl-errors.html',
-                $easy->request->getUri()
-            );
+
+        $message = \sprintf(
+            'cURL error %s: %s (%s)',
+            $ctx['errno'],
+            $ctx['error'],
+            'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
+        );
+        $uriString = (string) $easy->request->getUri();
+        if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) {
+            $message .= \sprintf(' for %s', $uriString);
         }
 
         // Create a connection exception if it was a specific error code.
@@ -203,34 +210,37 @@ class CurlFactory implements CurlFactoryInterface
         return \GuzzleHttp\Promise\rejection_for($error);
     }
 
-    private function getDefaultConf(EasyHandle $easy)
+    /**
+     * @return array<int|string, mixed>
+     */
+    private function getDefaultConf(EasyHandle $easy): array
     {
         $conf = [
-            '_headers'             => $easy->request->getHeaders(),
-            CURLOPT_CUSTOMREQUEST  => $easy->request->getMethod(),
-            CURLOPT_URL            => (string) $easy->request->getUri()->withFragment(''),
-            CURLOPT_RETURNTRANSFER => false,
-            CURLOPT_HEADER         => false,
-            CURLOPT_CONNECTTIMEOUT => 150,
+            '_headers'              => $easy->request->getHeaders(),
+            \CURLOPT_CUSTOMREQUEST  => $easy->request->getMethod(),
+            \CURLOPT_URL            => (string) $easy->request->getUri()->withFragment(''),
+            \CURLOPT_RETURNTRANSFER => false,
+            \CURLOPT_HEADER         => false,
+            \CURLOPT_CONNECTTIMEOUT => 150,
         ];
 
-        if (defined('CURLOPT_PROTOCOLS')) {
-            $conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
+        if (\defined('CURLOPT_PROTOCOLS')) {
+            $conf[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTP | \CURLPROTO_HTTPS;
         }
 
         $version = $easy->request->getProtocolVersion();
         if ($version == 1.1) {
-            $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
+            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
         } elseif ($version == 2.0) {
-            $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
+            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
         } else {
-            $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
+            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
         }
 
         return $conf;
     }
 
-    private function applyMethod(EasyHandle $easy, array &$conf)
+    private function applyMethod(EasyHandle $easy, array &$conf): void
     {
         $body = $easy->request->getBody();
         $size = $body->getSize();
@@ -242,22 +252,22 @@ class CurlFactory implements CurlFactoryInterface
 
         $method = $easy->request->getMethod();
         if ($method === 'PUT' || $method === 'POST') {
-            // See http://tools.ietf.org/html/rfc7230#section-3.3.2
+            // See https://tools.ietf.org/html/rfc7230#section-3.3.2
             if (!$easy->request->hasHeader('Content-Length')) {
-                $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
+                $conf[\CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
             }
         } elseif ($method === 'HEAD') {
-            $conf[CURLOPT_NOBODY] = true;
+            $conf[\CURLOPT_NOBODY] = true;
             unset(
-                $conf[CURLOPT_WRITEFUNCTION],
-                $conf[CURLOPT_READFUNCTION],
-                $conf[CURLOPT_FILE],
-                $conf[CURLOPT_INFILE]
+                $conf[\CURLOPT_WRITEFUNCTION],
+                $conf[\CURLOPT_READFUNCTION],
+                $conf[\CURLOPT_FILE],
+                $conf[\CURLOPT_INFILE]
             );
         }
     }
 
-    private function applyBody(RequestInterface $request, array $options, array &$conf)
+    private function applyBody(RequestInterface $request, array $options, array &$conf): void
     {
         $size = $request->hasHeader('Content-Length')
             ? (int) $request->getHeaderLine('Content-Length')
@@ -268,37 +278,37 @@ class CurlFactory implements CurlFactoryInterface
         if (($size !== null && $size < 1000000) ||
             !empty($options['_body_as_string'])
         ) {
-            $conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
+            $conf[\CURLOPT_POSTFIELDS] = (string) $request->getBody();
             // Don't duplicate the Content-Length header
             $this->removeHeader('Content-Length', $conf);
             $this->removeHeader('Transfer-Encoding', $conf);
         } else {
-            $conf[CURLOPT_UPLOAD] = true;
+            $conf[\CURLOPT_UPLOAD] = true;
             if ($size !== null) {
-                $conf[CURLOPT_INFILESIZE] = $size;
+                $conf[\CURLOPT_INFILESIZE] = $size;
                 $this->removeHeader('Content-Length', $conf);
             }
             $body = $request->getBody();
             if ($body->isSeekable()) {
                 $body->rewind();
             }
-            $conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
+            $conf[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body) {
                 return $body->read($length);
             };
         }
 
         // If the Expect header is not present, prevent curl from adding it
         if (!$request->hasHeader('Expect')) {
-            $conf[CURLOPT_HTTPHEADER][] = 'Expect:';
+            $conf[\CURLOPT_HTTPHEADER][] = 'Expect:';
         }
 
         // cURL sometimes adds a content-type by default. Prevent this.
         if (!$request->hasHeader('Content-Type')) {
-            $conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
+            $conf[\CURLOPT_HTTPHEADER][] = 'Content-Type:';
         }
     }
 
-    private function applyHeaders(EasyHandle $easy, array &$conf)
+    private function applyHeaders(EasyHandle $easy, array &$conf): void
     {
         foreach ($conf['_headers'] as $name => $values) {
             foreach ($values as $value) {
@@ -306,16 +316,16 @@ class CurlFactory implements CurlFactoryInterface
                 if ($value === '') {
                     // cURL requires a special format for empty headers.
                     // See https://github.com/guzzle/guzzle/issues/1882 for more details.
-                    $conf[CURLOPT_HTTPHEADER][] = "$name;";
+                    $conf[\CURLOPT_HTTPHEADER][] = "$name;";
                 } else {
-                    $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
+                    $conf[\CURLOPT_HTTPHEADER][] = "$name: $value";
                 }
             }
         }
 
         // Remove the Accept header if one was not set
         if (!$easy->request->hasHeader('Accept')) {
-            $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
+            $conf[\CURLOPT_HTTPHEADER][] = 'Accept:';
         }
     }
 
@@ -325,41 +335,47 @@ class CurlFactory implements CurlFactoryInterface
      * @param string $name    Case-insensitive header to remove
      * @param array  $options Array of options to modify
      */
-    private function removeHeader($name, array &$options)
+    private function removeHeader(string $name, array &$options): void
     {
-        foreach (array_keys($options['_headers']) as $key) {
-            if (!strcasecmp($key, $name)) {
+        foreach (\array_keys($options['_headers']) as $key) {
+            if (!\strcasecmp($key, $name)) {
                 unset($options['_headers'][$key]);
                 return;
             }
         }
     }
 
-    private function applyHandlerOptions(EasyHandle $easy, array &$conf)
+    private function applyHandlerOptions(EasyHandle $easy, array &$conf): void
     {
         $options = $easy->options;
         if (isset($options['verify'])) {
             if ($options['verify'] === false) {
-                unset($conf[CURLOPT_CAINFO]);
-                $conf[CURLOPT_SSL_VERIFYHOST] = 0;
-                $conf[CURLOPT_SSL_VERIFYPEER] = false;
+                unset($conf[\CURLOPT_CAINFO]);
+                $conf[\CURLOPT_SSL_VERIFYHOST] = 0;
+                $conf[\CURLOPT_SSL_VERIFYPEER] = false;
             } else {
-                $conf[CURLOPT_SSL_VERIFYHOST] = 2;
-                $conf[CURLOPT_SSL_VERIFYPEER] = true;
-                if (is_string($options['verify'])) {
+                $conf[\CURLOPT_SSL_VERIFYHOST] = 2;
+                $conf[\CURLOPT_SSL_VERIFYPEER] = true;
+                if (\is_string($options['verify'])) {
                     // Throw an error if the file/folder/link path is not valid or doesn't exist.
-                    if (!file_exists($options['verify'])) {
+                    if (!\file_exists($options['verify'])) {
                         throw new \InvalidArgumentException(
                             "SSL CA bundle not found: {$options['verify']}"
                         );
                     }
                     // If it's a directory or a link to a directory use CURLOPT_CAPATH.
                     // If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
-                    if (is_dir($options['verify']) ||
-                        (is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
-                        $conf[CURLOPT_CAPATH] = $options['verify'];
+                    if (
+                        \is_dir($options['verify']) ||
+                        (
+                            \is_link($options['verify']) === true &&
+                            ($verifyLink = \readlink($options['verify'])) !== false &&
+                            \is_dir($verifyLink)
+                        )
+                    ) {
+                        $conf[\CURLOPT_CAPATH] = $options['verify'];
                     } else {
-                        $conf[CURLOPT_CAINFO] = $options['verify'];
+                        $conf[\CURLOPT_CAINFO] = $options['verify'];
                     }
                 }
             }
@@ -368,72 +384,74 @@ class CurlFactory implements CurlFactoryInterface
         if (!empty($options['decode_content'])) {
             $accept = $easy->request->getHeaderLine('Accept-Encoding');
             if ($accept) {
-                $conf[CURLOPT_ENCODING] = $accept;
+                $conf[\CURLOPT_ENCODING] = $accept;
             } else {
-                $conf[CURLOPT_ENCODING] = '';
+                $conf[\CURLOPT_ENCODING] = '';
                 // Don't let curl send the header over the wire
-                $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
+                $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
             }
         }
 
-        if (isset($options['sink'])) {
+        // Do not connect a sink for HEAD requests.
+        if ($easy->request->getMethod() !== 'HEAD') {
+            if (!isset($options['sink'])) {
+                // Use a default temp stream if no sink was set.
+                $options['sink'] = \fopen('php://temp', 'w+');
+            }
             $sink = $options['sink'];
-            if (!is_string($sink)) {
+            if (!\is_string($sink)) {
                 $sink = \GuzzleHttp\Psr7\stream_for($sink);
-            } elseif (!is_dir(dirname($sink))) {
+            } elseif (!\is_dir(\dirname($sink))) {
                 // Ensure that the directory exists before failing in curl.
-                throw new \RuntimeException(sprintf(
+                throw new \RuntimeException(\sprintf(
                     'Directory %s does not exist for sink value of %s',
-                    dirname($sink),
+                    \dirname($sink),
                     $sink
                 ));
             } else {
                 $sink = new LazyOpenStream($sink, 'w+');
             }
             $easy->sink = $sink;
-            $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
+            $conf[\CURLOPT_WRITEFUNCTION] = static function ($ch, $write) use ($sink): int {
                 return $sink->write($write);
             };
-        } else {
-            // Use a default temp stream if no sink was set.
-            $conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
-            $easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
         }
+
         $timeoutRequiresNoSignal = false;
         if (isset($options['timeout'])) {
             $timeoutRequiresNoSignal |= $options['timeout'] < 1;
-            $conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
+            $conf[\CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
         }
 
         // CURL default value is CURL_IPRESOLVE_WHATEVER
         if (isset($options['force_ip_resolve'])) {
             if ('v4' === $options['force_ip_resolve']) {
-                $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
+                $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V4;
             } elseif ('v6' === $options['force_ip_resolve']) {
-                $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
+                $conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V6;
             }
         }
 
         if (isset($options['connect_timeout'])) {
             $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
-            $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
+            $conf[\CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
         }
 
-        if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
-            $conf[CURLOPT_NOSIGNAL] = true;
+        if ($timeoutRequiresNoSignal && \strtoupper(\substr(\PHP_OS, 0, 3)) !== 'WIN') {
+            $conf[\CURLOPT_NOSIGNAL] = true;
         }
 
         if (isset($options['proxy'])) {
-            if (!is_array($options['proxy'])) {
-                $conf[CURLOPT_PROXY] = $options['proxy'];
+            if (!\is_array($options['proxy'])) {
+                $conf[\CURLOPT_PROXY] = $options['proxy'];
             } else {
                 $scheme = $easy->request->getUri()->getScheme();
                 if (isset($options['proxy'][$scheme])) {
                     $host = $easy->request->getUri()->getHost();
                     if (!isset($options['proxy']['no']) ||
-                        !\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
+                        !Utils::isHostInNoProxy($host, $options['proxy']['no'])
                     ) {
-                        $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
+                        $conf[\CURLOPT_PROXY] = $options['proxy'][$scheme];
                     }
                 }
             }
@@ -441,58 +459,53 @@ class CurlFactory implements CurlFactoryInterface
 
         if (isset($options['cert'])) {
             $cert = $options['cert'];
-            if (is_array($cert)) {
-                $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
+            if (\is_array($cert)) {
+                $conf[\CURLOPT_SSLCERTPASSWD] = $cert[1];
                 $cert = $cert[0];
             }
-            if (!file_exists($cert)) {
+            if (!\file_exists($cert)) {
                 throw new \InvalidArgumentException(
                     "SSL certificate not found: {$cert}"
                 );
             }
-            $conf[CURLOPT_SSLCERT] = $cert;
+            $conf[\CURLOPT_SSLCERT] = $cert;
         }
 
         if (isset($options['ssl_key'])) {
-            if (is_array($options['ssl_key'])) {
-                if (count($options['ssl_key']) === 2) {
-                    list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];
+            if (\is_array($options['ssl_key'])) {
+                if (\count($options['ssl_key']) === 2) {
+                    [$sslKey, $conf[\CURLOPT_SSLKEYPASSWD]] = $options['ssl_key'];
                 } else {
-                    list($sslKey) = $options['ssl_key'];
+                    [$sslKey] = $options['ssl_key'];
                 }
             }
 
-            $sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];
+            $sslKey = $sslKey ?? $options['ssl_key'];
 
-            if (!file_exists($sslKey)) {
+            if (!\file_exists($sslKey)) {
                 throw new \InvalidArgumentException(
                     "SSL private key not found: {$sslKey}"
                 );
             }
-            $conf[CURLOPT_SSLKEY] = $sslKey;
+            $conf[\CURLOPT_SSLKEY] = $sslKey;
         }
 
         if (isset($options['progress'])) {
             $progress = $options['progress'];
-            if (!is_callable($progress)) {
+            if (!\is_callable($progress)) {
                 throw new \InvalidArgumentException(
                     'progress client option must be callable'
                 );
             }
-            $conf[CURLOPT_NOPROGRESS] = false;
-            $conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
-                $args = func_get_args();
-                // PHP 5.5 pushed the handle onto the start of the args
-                if (is_resource($args[0])) {
-                    array_shift($args);
-                }
-                call_user_func_array($progress, $args);
+            $conf[\CURLOPT_NOPROGRESS] = false;
+            $conf[\CURLOPT_PROGRESSFUNCTION] = static function ($resource, int $downloadSize, int $downloaded, int $uploadSize, int $uploaded) use ($progress) {
+                $progress($downloadSize, $downloaded, $uploadSize, $uploaded);
             };
         }
 
         if (!empty($options['debug'])) {
-            $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
-            $conf[CURLOPT_VERBOSE] = true;
+            $conf[\CURLOPT_STDERR] = Utils::debugResource($options['debug']);
+            $conf[\CURLOPT_VERBOSE] = true;
         }
     }
 
@@ -504,12 +517,14 @@ class CurlFactory implements CurlFactoryInterface
      * stream, and then encountered a "necessary data rewind wasn't possible"
      * error, causing the request to be sent through curl_multi_info_read()
      * without an error status.
+     *
+     * @param callable(RequestInterface, array): PromiseInterface $handler
      */
     private static function retryFailedRewind(
         callable $handler,
         EasyHandle $easy,
         array $ctx
-    ) {
+    ): PromiseInterface {
         try {
             // Only rewind if the body has been read from.
             $body = $easy->request->getBody();
@@ -542,24 +557,24 @@ class CurlFactory implements CurlFactoryInterface
         return $handler($easy->request, $easy->options);
     }
 
-    private function createHeaderFn(EasyHandle $easy)
+    private function createHeaderFn(EasyHandle $easy): callable
     {
         if (isset($easy->options['on_headers'])) {
             $onHeaders = $easy->options['on_headers'];
 
-            if (!is_callable($onHeaders)) {
+            if (!\is_callable($onHeaders)) {
                 throw new \InvalidArgumentException('on_headers must be callable');
             }
         } else {
             $onHeaders = null;
         }
 
-        return function ($ch, $h) use (
+        return static function ($ch, $h) use (
             $onHeaders,
             $easy,
             &$startingResponse
         ) {
-            $value = trim($h);
+            $value = \trim($h);
             if ($value === '') {
                 $startingResponse = true;
                 $easy->createResponse();
@@ -579,7 +594,7 @@ class CurlFactory implements CurlFactoryInterface
             } else {
                 $easy->headers[] = $value;
             }
-            return strlen($h);
+            return \strlen($h);
         };
     }
 }

+ 3 - 5
api/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
 use Psr\Http\Message\RequestInterface;
@@ -11,17 +12,14 @@ interface CurlFactoryInterface
      * @param RequestInterface $request Request
      * @param array            $options Transfer options
      *
-     * @return EasyHandle
      * @throws \RuntimeException when an option cannot be applied
      */
-    public function create(RequestInterface $request, array $options);
+    public function create(RequestInterface $request, array $options): EasyHandle;
 
     /**
      * Release an easy handle, allowing it to be reused or closed.
      *
      * This function must call unset on the easy handle's "handle" property.
-     *
-     * @param EasyHandle $easy
      */
-    public function release(EasyHandle $easy);
+    public function release(EasyHandle $easy): void;
 }

+ 13 - 9
api/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php

@@ -1,7 +1,8 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
-use GuzzleHttp\Psr7;
+use GuzzleHttp\Promise\PromiseInterface;
 use Psr\Http\Message\RequestInterface;
 
 /**
@@ -10,10 +11,14 @@ use Psr\Http\Message\RequestInterface;
  * When using the CurlHandler, custom curl options can be specified as an
  * associative array of curl option constants mapping to values in the
  * **curl** key of the "client" key of the request.
+ *
+ * @final
  */
 class CurlHandler
 {
-    /** @var CurlFactoryInterface */
+    /**
+     * @var CurlFactoryInterface
+     */
     private $factory;
 
     /**
@@ -25,20 +30,19 @@ class CurlHandler
      */
     public function __construct(array $options = [])
     {
-        $this->factory = isset($options['handle_factory'])
-            ? $options['handle_factory']
-            : new CurlFactory(3);
+        $this->factory = $options['handle_factory']
+            ?? new CurlFactory(3);
     }
 
-    public function __invoke(RequestInterface $request, array $options)
+    public function __invoke(RequestInterface $request, array $options): PromiseInterface
     {
         if (isset($options['delay'])) {
-            usleep($options['delay'] * 1000);
+            \usleep($options['delay'] * 1000);
         }
 
         $easy = $this->factory->create($request, $options);
-        curl_exec($easy->handle);
-        $easy->errno = curl_errno($easy->handle);
+        \curl_exec($easy->handle);
+        $easy->errno = \curl_errno($easy->handle);
 
         return CurlFactory::finish($this, $easy, $this->factory);
     }

+ 81 - 42
api/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php

@@ -1,9 +1,11 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
-use GuzzleHttp\Exception\InvalidArgumentException;
 use GuzzleHttp\Promise as P;
 use GuzzleHttp\Promise\Promise;
+use GuzzleHttp\Promise\PromiseInterface;
+use GuzzleHttp\Utils;
 use Psr\Http\Message\RequestInterface;
 
 /**
@@ -14,15 +16,43 @@ use Psr\Http\Message\RequestInterface;
  * **curl** key of the provided request options.
  *
  * @property resource $_mh Internal use only. Lazy loaded multi-handle.
+ *
+ * @final
  */
 class CurlMultiHandler
 {
-    /** @var CurlFactoryInterface */
+    /**
+     * @var CurlFactoryInterface
+     */
     private $factory;
+
+    /**
+     * @var int
+     */
     private $selectTimeout;
+
+    /**
+     * @var resource|null the currently executing resource in `curl_multi_exec`.
+     */
     private $active;
+
+    /**
+     * @var array Request entry handles, indexed by handle id in `addRequest`.
+     *
+     * @see CurlMultiHandler::addRequest
+     */
     private $handles = [];
+
+    /**
+     * @var array<int, float> An array of delay times, indexed by handle id in `addRequest`.
+     *
+     * @see CurlMultiHandler::addRequest
+     */
     private $delays = [];
+
+    /**
+     * @var array<mixed> An associative array of CURLMOPT_* options and corresponding values for curl_multi_setopt()
+     */
     private $options = [];
 
     /**
@@ -33,52 +63,61 @@ class CurlMultiHandler
      *   out while selecting curl handles. Defaults to 1 second.
      * - options: An associative array of CURLMOPT_* options and
      *   corresponding values for curl_multi_setopt()
-     *
-     * @param array $options
      */
     public function __construct(array $options = [])
     {
-        $this->factory = isset($options['handle_factory'])
-            ? $options['handle_factory'] : new CurlFactory(50);
+        $this->factory = $options['handle_factory'] ?? new CurlFactory(50);
 
         if (isset($options['select_timeout'])) {
             $this->selectTimeout = $options['select_timeout'];
-        } elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
-            $this->selectTimeout = $selectTimeout;
+        } elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
+            $this->selectTimeout = (int) $selectTimeout;
         } else {
             $this->selectTimeout = 1;
         }
 
-        $this->options = isset($options['options']) ? $options['options'] : [];
+        $this->options = $options['options'] ?? [];
     }
 
+    /**
+     * @param string $name
+     *
+     * @return resource
+     *
+     * @throws \BadMethodCallException when another field as `_mh` will be gotten
+     * @throws \RuntimeException       when curl can not initialize a multi handle
+     */
     public function __get($name)
     {
-        if ($name === '_mh') {
-            $this->_mh = curl_multi_init();
+        if ($name !== '_mh') {
+            throw new \BadMethodCallException("Can not get other property as '_mh'.");
+        }
 
-            foreach ($this->options as $option => $value) {
-                // A warning is raised in case of a wrong option.
-                curl_multi_setopt($this->_mh, $option, $value);
-            }
+        $multiHandle = \curl_multi_init();
+
+        if (false === $multiHandle) {
+            throw new \RuntimeException('Can not initialize curl multi handle.');
+        }
+
+        $this->_mh = $multiHandle;
 
-            // Further calls to _mh will return the value directly, without entering the
-            // __get() method at all.
-            return $this->_mh;
+        foreach ($this->options as $option => $value) {
+            // A warning is raised in case of a wrong option.
+            curl_multi_setopt($this->_mh, $option, $value);
         }
 
-        throw new \BadMethodCallException();
+        return $this->_mh;
     }
 
     public function __destruct()
     {
         if (isset($this->_mh)) {
-            curl_multi_close($this->_mh);
+            \curl_multi_close($this->_mh);
             unset($this->_mh);
         }
     }
 
-    public function __invoke(RequestInterface $request, array $options)
+    public function __invoke(RequestInterface $request, array $options): PromiseInterface
     {
         $easy = $this->factory->create($request, $options);
         $id = (int) $easy->handle;
@@ -98,15 +137,15 @@ class CurlMultiHandler
     /**
      * Ticks the curl event loop.
      */
-    public function tick()
+    public function tick(): void
     {
         // Add any delayed handles if needed.
         if ($this->delays) {
-            $currentTime = \GuzzleHttp\_current_time();
+            $currentTime = Utils::currentTime();
             foreach ($this->delays as $id => $delay) {
                 if ($currentTime >= $delay) {
                     unset($this->delays[$id]);
-                    curl_multi_add_handle(
+                    \curl_multi_add_handle(
                         $this->_mh,
                         $this->handles[$id]['easy']->handle
                     );
@@ -118,14 +157,14 @@ class CurlMultiHandler
         P\queue()->run();
 
         if ($this->active &&
-            curl_multi_select($this->_mh, $this->selectTimeout) === -1
+            \curl_multi_select($this->_mh, $this->selectTimeout) === -1
         ) {
             // Perform a usleep if a select returns -1.
             // See: https://bugs.php.net/bug.php?id=61141
-            usleep(250);
+            \usleep(250);
         }
 
-        while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
+        while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM);
 
         $this->processMessages();
     }
@@ -133,28 +172,28 @@ class CurlMultiHandler
     /**
      * Runs until all outstanding connections have completed.
      */
-    public function execute()
+    public function execute(): void
     {
         $queue = P\queue();
 
         while ($this->handles || !$queue->isEmpty()) {
             // If there are no transfers, then sleep for the next delay
             if (!$this->active && $this->delays) {
-                usleep($this->timeToNext());
+                \usleep($this->timeToNext());
             }
             $this->tick();
         }
     }
 
-    private function addRequest(array $entry)
+    private function addRequest(array $entry): void
     {
         $easy = $entry['easy'];
         $id = (int) $easy->handle;
         $this->handles[$id] = $entry;
         if (empty($easy->options['delay'])) {
-            curl_multi_add_handle($this->_mh, $easy->handle);
+            \curl_multi_add_handle($this->_mh, $easy->handle);
         } else {
-            $this->delays[$id] = \GuzzleHttp\_current_time() + ($easy->options['delay'] / 1000);
+            $this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000);
         }
     }
 
@@ -165,7 +204,7 @@ class CurlMultiHandler
      *
      * @return bool True on success, false on failure.
      */
-    private function cancel($id)
+    private function cancel($id): bool
     {
         // Cannot cancel if it has been processed.
         if (!isset($this->handles[$id])) {
@@ -174,17 +213,17 @@ class CurlMultiHandler
 
         $handle = $this->handles[$id]['easy']->handle;
         unset($this->delays[$id], $this->handles[$id]);
-        curl_multi_remove_handle($this->_mh, $handle);
-        curl_close($handle);
+        \curl_multi_remove_handle($this->_mh, $handle);
+        \curl_close($handle);
 
         return true;
     }
 
-    private function processMessages()
+    private function processMessages(): void
     {
-        while ($done = curl_multi_info_read($this->_mh)) {
+        while ($done = \curl_multi_info_read($this->_mh)) {
             $id = (int) $done['handle'];
-            curl_multi_remove_handle($this->_mh, $done['handle']);
+            \curl_multi_remove_handle($this->_mh, $done['handle']);
 
             if (!isset($this->handles[$id])) {
                 // Probably was cancelled.
@@ -204,16 +243,16 @@ class CurlMultiHandler
         }
     }
 
-    private function timeToNext()
+    private function timeToNext(): int
     {
-        $currentTime = \GuzzleHttp\_current_time();
-        $nextTime = PHP_INT_MAX;
+        $currentTime = Utils::currentTime();
+        $nextTime = \PHP_INT_MAX;
         foreach ($this->delays as $time) {
             if ($time < $nextTime) {
                 $nextTime = $time;
             }
         }
 
-        return max(0, $nextTime - $currentTime) * 1000000;
+        return ((int) \max(0, $nextTime - $currentTime)) * 1000000;
     }
 }

+ 41 - 14
api/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php

@@ -1,7 +1,9 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
 use GuzzleHttp\Psr7\Response;
+use GuzzleHttp\Utils;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\StreamInterface;
@@ -13,28 +15,44 @@ use Psr\Http\Message\StreamInterface;
  */
 final class EasyHandle
 {
-    /** @var resource cURL resource */
+    /**
+     * @var resource cURL resource
+     */
     public $handle;
 
-    /** @var StreamInterface Where data is being written */
+    /**
+     * @var StreamInterface Where data is being written
+     */
     public $sink;
 
-    /** @var array Received HTTP headers so far */
+    /**
+     * @var array Received HTTP headers so far
+     */
     public $headers = [];
 
-    /** @var ResponseInterface Received response (if any) */
+    /**
+     * @var ResponseInterface|null Received response (if any)
+     */
     public $response;
 
-    /** @var RequestInterface Request being sent */
+    /**
+     * @var RequestInterface Request being sent
+     */
     public $request;
 
-    /** @var array Request options */
+    /**
+     * @var array Request options
+     */
     public $options = [];
 
-    /** @var int cURL error number (if any) */
+    /**
+     * @var int cURL error number (if any)
+     */
     public $errno = 0;
 
-    /** @var \Exception Exception during on_headers (if any) */
+    /**
+     * @var \Throwable|null Exception during on_headers (if any)
+     */
     public $onHeadersException;
 
     /**
@@ -42,16 +60,16 @@ final class EasyHandle
      *
      * @throws \RuntimeException if no headers have been received.
      */
-    public function createResponse()
+    public function createResponse(): void
     {
         if (empty($this->headers)) {
             throw new \RuntimeException('No headers have been received');
         }
 
         // HTTP-version SP status-code SP reason-phrase
-        $startLine = explode(' ', array_shift($this->headers), 3);
-        $headers = \GuzzleHttp\headers_from_lines($this->headers);
-        $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
+        $startLine = \explode(' ', \array_shift($this->headers), 3);
+        $headers = Utils::headersFromLines($this->headers);
+        $normalizedKeys = Utils::normalizeHeaderKeys($headers);
 
         if (!empty($this->options['decode_content'])
             && isset($normalizedKeys['content-encoding'])
@@ -72,16 +90,25 @@ final class EasyHandle
             }
         }
 
+        $statusCode = (int) $startLine[1];
+
         // Attach a response to the easy handle with the parsed headers.
         $this->response = new Response(
-            $startLine[1],
+            $statusCode,
             $headers,
             $this->sink,
-            substr($startLine[0], 5),
+            \substr($startLine[0], 5),
             isset($startLine[2]) ? (string) $startLine[2] : null
         );
     }
 
+    /**
+     * @param string $name
+     *
+     * @return void
+     *
+     * @throws \BadMethodCallException
+     */
     public function __get($name)
     {
         $msg = $name === 'handle'

+ 71 - 50
api/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php

@@ -1,51 +1,72 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
 use GuzzleHttp\Exception\RequestException;
 use GuzzleHttp\HandlerStack;
 use GuzzleHttp\Promise\PromiseInterface;
-use GuzzleHttp\Promise\RejectedPromise;
 use GuzzleHttp\TransferStats;
+use GuzzleHttp\Utils;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\StreamInterface;
 
 /**
  * Handler that returns responses or throw exceptions from a queue.
+ *
+ * @final
  */
 class MockHandler implements \Countable
 {
+    /**
+     * @var array
+     */
     private $queue = [];
+
+    /**
+     * @var RequestInterface|null
+     */
     private $lastRequest;
-    private $lastOptions;
+
+    /**
+     * @var array
+     */
+    private $lastOptions = [];
+
+    /**
+     * @var callable|null
+     */
     private $onFulfilled;
+
+    /**
+     * @var callable|null
+     */
     private $onRejected;
 
     /**
      * Creates a new MockHandler that uses the default handler stack list of
      * middlewares.
      *
-     * @param array $queue Array of responses, callables, or exceptions.
-     * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
-     * @param callable $onRejected  Callback to invoke when the return value is rejected.
-     *
-     * @return HandlerStack
+     * @param array|null    $queue       Array of responses, callables, or exceptions.
+     * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
+     * @param callable|null $onRejected  Callback to invoke when the return value is rejected.
      */
     public static function createWithMiddleware(
         array $queue = null,
         callable $onFulfilled = null,
         callable $onRejected = null
-    ) {
+    ): HandlerStack {
         return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
     }
 
     /**
      * The passed in value must be an array of
-     * {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
+     * {@see \Psr\Http\Message\ResponseInterface} objects, Exceptions,
      * callables, or Promises.
      *
-     * @param array $queue
-     * @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
-     * @param callable $onRejected  Callback to invoke when the return value is rejected.
+     * @param array<int, mixed>|null $queue       The parameters to be passed to the append function, as an indexed array.
+     * @param callable|null          $onFulfilled Callback to invoke when the return value is fulfilled.
+     * @param callable|null          $onRejected  Callback to invoke when the return value is rejected.
      */
     public function __construct(
         array $queue = null,
@@ -56,26 +77,27 @@ class MockHandler implements \Countable
         $this->onRejected = $onRejected;
 
         if ($queue) {
-            call_user_func_array([$this, 'append'], $queue);
+            // array_values included for BC
+            $this->append(...array_values($queue));
         }
     }
 
-    public function __invoke(RequestInterface $request, array $options)
+    public function __invoke(RequestInterface $request, array $options): PromiseInterface
     {
         if (!$this->queue) {
             throw new \OutOfBoundsException('Mock queue is empty');
         }
 
-        if (isset($options['delay']) && is_numeric($options['delay'])) {
-            usleep($options['delay'] * 1000);
+        if (isset($options['delay']) && \is_numeric($options['delay'])) {
+            \usleep((int) $options['delay'] * 1000);
         }
 
         $this->lastRequest = $request;
         $this->lastOptions = $options;
-        $response = array_shift($this->queue);
+        $response = \array_shift($this->queue);
 
         if (isset($options['on_headers'])) {
-            if (!is_callable($options['on_headers'])) {
+            if (!\is_callable($options['on_headers'])) {
                 throw new \InvalidArgumentException('on_headers must be callable');
             }
             try {
@@ -86,29 +108,30 @@ class MockHandler implements \Countable
             }
         }
 
-        if (is_callable($response)) {
-            $response = call_user_func($response, $request, $options);
+        if (\is_callable($response)) {
+            $response = $response($request, $options);
         }
 
-        $response = $response instanceof \Exception
+        $response = $response instanceof \Throwable
             ? \GuzzleHttp\Promise\rejection_for($response)
             : \GuzzleHttp\Promise\promise_for($response);
 
         return $response->then(
-            function ($value) use ($request, $options) {
+            function (?ResponseInterface $value) use ($request, $options) {
                 $this->invokeStats($request, $options, $value);
                 if ($this->onFulfilled) {
-                    call_user_func($this->onFulfilled, $value);
+                    ($this->onFulfilled)($value);
                 }
-                if (isset($options['sink'])) {
+
+                if ($value !== null && isset($options['sink'])) {
                     $contents = (string) $value->getBody();
                     $sink = $options['sink'];
 
-                    if (is_resource($sink)) {
-                        fwrite($sink, $contents);
-                    } elseif (is_string($sink)) {
-                        file_put_contents($sink, $contents);
-                    } elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
+                    if (\is_resource($sink)) {
+                        \fwrite($sink, $contents);
+                    } elseif (\is_string($sink)) {
+                        \file_put_contents($sink, $contents);
+                    } elseif ($sink instanceof StreamInterface) {
                         $sink->write($contents);
                     }
                 }
@@ -118,7 +141,7 @@ class MockHandler implements \Countable
             function ($reason) use ($request, $options) {
                 $this->invokeStats($request, $options, null, $reason);
                 if ($this->onRejected) {
-                    call_user_func($this->onRejected, $reason);
+                    ($this->onRejected)($reason);
                 }
                 return \GuzzleHttp\Promise\rejection_for($reason);
             }
@@ -128,68 +151,66 @@ class MockHandler implements \Countable
     /**
      * Adds one or more variadic requests, exceptions, callables, or promises
      * to the queue.
+     *
+     * @param mixed ...$values
      */
-    public function append()
+    public function append(...$values): void
     {
-        foreach (func_get_args() as $value) {
+        foreach ($values as $value) {
             if ($value instanceof ResponseInterface
-                || $value instanceof \Exception
+                || $value instanceof \Throwable
                 || $value instanceof PromiseInterface
-                || is_callable($value)
+                || \is_callable($value)
             ) {
                 $this->queue[] = $value;
             } else {
-                throw new \InvalidArgumentException('Expected a response or '
-                    . 'exception. Found ' . \GuzzleHttp\describe_type($value));
+                throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found ' . Utils::describeType($value));
             }
         }
     }
 
     /**
      * Get the last received request.
-     *
-     * @return RequestInterface
      */
-    public function getLastRequest()
+    public function getLastRequest(): ?RequestInterface
     {
         return $this->lastRequest;
     }
 
     /**
      * Get the last received request options.
-     *
-     * @return array
      */
-    public function getLastOptions()
+    public function getLastOptions(): array
     {
         return $this->lastOptions;
     }
 
     /**
      * Returns the number of remaining items in the queue.
-     *
-     * @return int
      */
-    public function count()
+    public function count(): int
     {
-        return count($this->queue);
+        return \count($this->queue);
     }
 
-    public function reset()
+    public function reset(): void
     {
         $this->queue = [];
     }
 
+    /**
+     * @param mixed $reason Promise or reason.
+     */
     private function invokeStats(
         RequestInterface $request,
         array $options,
         ResponseInterface $response = null,
         $reason = null
-    ) {
+    ): void {
         if (isset($options['on_stats'])) {
-            $transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;
+            $transferTime = $options['transfer_time'] ?? 0;
             $stats = new TransferStats($request, $response, $transferTime, $reason);
-            call_user_func($options['on_stats'], $stats);
+            ($options['on_stats'])($stats);
         }
     }
 }

+ 14 - 10
api/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php

@@ -1,11 +1,15 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
+use GuzzleHttp\Promise\PromiseInterface;
 use GuzzleHttp\RequestOptions;
 use Psr\Http\Message\RequestInterface;
 
 /**
  * Provides basic proxies for handlers.
+ *
+ * @final
  */
 class Proxy
 {
@@ -13,16 +17,16 @@ class Proxy
      * Sends synchronous requests to a specific handler while sending all other
      * requests to another handler.
      *
-     * @param callable $default Handler used for normal responses
-     * @param callable $sync    Handler used for synchronous responses.
+     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses
+     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync    Handler used for synchronous responses.
      *
-     * @return callable Returns the composed handler.
+     * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
      */
     public static function wrapSync(
         callable $default,
         callable $sync
-    ) {
-        return function (RequestInterface $request, array $options) use ($default, $sync) {
+    ): callable {
+        return static function (RequestInterface $request, array $options) use ($default, $sync): PromiseInterface {
             return empty($options[RequestOptions::SYNCHRONOUS])
                 ? $default($request, $options)
                 : $sync($request, $options);
@@ -37,16 +41,16 @@ class Proxy
      * performance benefits of curl while still supporting true streaming
      * through the StreamHandler.
      *
-     * @param callable $default   Handler used for non-streaming responses
-     * @param callable $streaming Handler used for streaming responses
+     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default   Handler used for non-streaming responses
+     * @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses
      *
-     * @return callable Returns the composed handler.
+     * @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
      */
     public static function wrapStreaming(
         callable $default,
         callable $streaming
-    ) {
-        return function (RequestInterface $request, array $options) use ($default, $streaming) {
+    ): callable {
+        return static function (RequestInterface $request, array $options) use ($default, $streaming): PromiseInterface {
             return empty($options['stream'])
                 ? $default($request, $options)
                 : $streaming($request, $options);

+ 154 - 123
api/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp\Handler;
 
 use GuzzleHttp\Exception\ConnectException;
@@ -7,15 +8,22 @@ use GuzzleHttp\Promise\FulfilledPromise;
 use GuzzleHttp\Promise\PromiseInterface;
 use GuzzleHttp\Psr7;
 use GuzzleHttp\TransferStats;
+use GuzzleHttp\Utils;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\StreamInterface;
+use Psr\Http\Message\UriInterface;
 
 /**
  * HTTP handler that uses PHP's HTTP stream wrapper.
+ *
+ * @final
  */
 class StreamHandler
 {
+    /**
+     * @var array
+     */
     private $lastHeaders = [];
 
     /**
@@ -23,17 +31,15 @@ class StreamHandler
      *
      * @param RequestInterface $request Request to send.
      * @param array            $options Request transfer options.
-     *
-     * @return PromiseInterface
      */
-    public function __invoke(RequestInterface $request, array $options)
+    public function __invoke(RequestInterface $request, array $options): PromiseInterface
     {
         // Sleep if there is a delay specified.
         if (isset($options['delay'])) {
-            usleep($options['delay'] * 1000);
+            \usleep($options['delay'] * 1000);
         }
 
-        $startTime = isset($options['on_stats']) ? \GuzzleHttp\_current_time() : null;
+        $startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
 
         try {
             // Does not support the expect header.
@@ -57,14 +63,15 @@ class StreamHandler
             // Determine if the error was a networking error.
             $message = $e->getMessage();
             // This list can probably get more comprehensive.
-            if (strpos($message, 'getaddrinfo') // DNS lookup failed
-                || strpos($message, 'Connection refused')
-                || strpos($message, "couldn't connect to host") // error on HHVM
-                || strpos($message, "connection attempt failed")
+            if (false !== \strpos($message, 'getaddrinfo') // DNS lookup failed
+                || false !== \strpos($message, 'Connection refused')
+                || false !== \strpos($message, "couldn't connect to host") // error on HHVM
+                || false !== \strpos($message, "connection attempt failed")
             ) {
                 $e = new ConnectException($e->getMessage(), $request, $e);
+            } else {
+                $e = RequestException::wrapException($request, $e);
             }
-            $e = RequestException::wrapException($request, $e);
             $this->invokeStats($options, $request, $startTime, null, $e);
 
             return \GuzzleHttp\Promise\rejection_for($e);
@@ -74,40 +81,43 @@ class StreamHandler
     private function invokeStats(
         array $options,
         RequestInterface $request,
-        $startTime,
+        ?float $startTime,
         ResponseInterface $response = null,
-        $error = null
-    ) {
+        \Throwable $error = null
+    ): void {
         if (isset($options['on_stats'])) {
             $stats = new TransferStats(
                 $request,
                 $response,
-                \GuzzleHttp\_current_time() - $startTime,
+                Utils::currentTime() - $startTime,
                 $error,
                 []
             );
-            call_user_func($options['on_stats'], $stats);
+            ($options['on_stats'])($stats);
         }
     }
 
+    /**
+     * @param resource $stream
+     */
     private function createResponse(
         RequestInterface $request,
         array $options,
         $stream,
-        $startTime
-    ) {
+        ?float $startTime
+    ): PromiseInterface {
         $hdrs = $this->lastHeaders;
         $this->lastHeaders = [];
-        $parts = explode(' ', array_shift($hdrs), 3);
-        $ver = explode('/', $parts[0])[1];
-        $status = $parts[1];
-        $reason = isset($parts[2]) ? $parts[2] : null;
-        $headers = \GuzzleHttp\headers_from_lines($hdrs);
-        list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
+        $parts = \explode(' ', \array_shift($hdrs), 3);
+        $ver = \explode('/', $parts[0])[1];
+        $status = (int) $parts[1];
+        $reason = $parts[2] ?? null;
+        $headers = Utils::headersFromLines($hdrs);
+        [$stream, $headers] = $this->checkDecode($options, $headers, $stream);
         $stream = Psr7\stream_for($stream);
         $sink = $stream;
 
-        if (strcasecmp('HEAD', $request->getMethod())) {
+        if (\strcasecmp('HEAD', $request->getMethod())) {
             $sink = $this->createSink($stream, $options);
         }
 
@@ -138,26 +148,28 @@ class StreamHandler
         return new FulfilledPromise($response);
     }
 
-    private function createSink(StreamInterface $stream, array $options)
+    private function createSink(StreamInterface $stream, array $options): StreamInterface
     {
         if (!empty($options['stream'])) {
             return $stream;
         }
 
-        $sink = isset($options['sink'])
-            ? $options['sink']
-            : fopen('php://temp', 'r+');
+        $sink = $options['sink']
+            ?? \fopen('php://temp', 'r+');
 
-        return is_string($sink)
+        return \is_string($sink)
             ? new Psr7\LazyOpenStream($sink, 'w+')
             : Psr7\stream_for($sink);
     }
 
-    private function checkDecode(array $options, array $headers, $stream)
+    /**
+     * @param resource $stream
+     */
+    private function checkDecode(array $options, array $headers, $stream): array
     {
         // Automatically decode responses when instructed.
         if (!empty($options['decode_content'])) {
-            $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
+            $normalizedKeys = Utils::normalizeHeaderKeys($headers);
             if (isset($normalizedKeys['content-encoding'])) {
                 $encoding = $headers[$normalizedKeys['content-encoding']];
                 if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
@@ -190,19 +202,16 @@ class StreamHandler
     /**
      * Drains the source stream into the "sink" client option.
      *
-     * @param StreamInterface $source
-     * @param StreamInterface $sink
-     * @param string          $contentLength Header specifying the amount of
-     *                                       data to read.
+     * @param string $contentLength Header specifying the amount of
+     *                              data to read.
      *
-     * @return StreamInterface
      * @throws \RuntimeException when the sink option is invalid.
      */
     private function drain(
         StreamInterface $source,
         StreamInterface $sink,
-        $contentLength
-    ) {
+        string $contentLength
+    ): StreamInterface {
         // If a content-length header is provided, then stop reading once
         // that number of bytes has been read. This can prevent infinitely
         // reading from a stream when dealing with servers that do not honor
@@ -210,7 +219,7 @@ class StreamHandler
         Psr7\copy_to_stream(
             $source,
             $sink,
-            (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
+            (\strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
         );
 
         $sink->seek(0);
@@ -225,12 +234,13 @@ class StreamHandler
      * @param callable $callback Callable that returns stream resource
      *
      * @return resource
+     *
      * @throws \RuntimeException on error
      */
     private function createResource(callable $callback)
     {
-        $errors = null;
-        set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
+        $errors = [];
+        \set_error_handler(static function ($_, $msg, $file, $line) use (&$errors): bool {
             $errors[] = [
                 'message' => $msg,
                 'file'    => $file,
@@ -240,26 +250,29 @@ class StreamHandler
         });
 
         $resource = $callback();
-        restore_error_handler();
+        \restore_error_handler();
 
         if (!$resource) {
             $message = 'Error creating resource: ';
             foreach ($errors as $err) {
                 foreach ($err as $key => $value) {
-                    $message .= "[$key] $value" . PHP_EOL;
+                    $message .= "[$key] $value" . \PHP_EOL;
                 }
             }
-            throw new \RuntimeException(trim($message));
+            throw new \RuntimeException(\trim($message));
         }
 
         return $resource;
     }
 
+    /**
+     * @return resource
+     */
     private function createStream(RequestInterface $request, array $options)
     {
         static $methods;
         if (!$methods) {
-            $methods = array_flip(get_class_methods(__CLASS__));
+            $methods = \array_flip(\get_class_methods(__CLASS__));
         }
 
         // HTTP/1.1 streams using the PHP stream wrapper require a
@@ -278,7 +291,7 @@ class StreamHandler
         $params = [];
         $context = $this->getDefaultContext($request);
 
-        if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
+        if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) {
             throw new \InvalidArgumentException('on_headers must be callable');
         }
 
@@ -292,42 +305,47 @@ class StreamHandler
         }
 
         if (isset($options['stream_context'])) {
-            if (!is_array($options['stream_context'])) {
+            if (!\is_array($options['stream_context'])) {
                 throw new \InvalidArgumentException('stream_context must be an array');
             }
-            $context = array_replace_recursive(
+            $context = \array_replace_recursive(
                 $context,
                 $options['stream_context']
             );
         }
 
         // Microsoft NTLM authentication only supported with curl handler
-        if (isset($options['auth'])
-            && is_array($options['auth'])
-            && isset($options['auth'][2])
-            && 'ntlm' == $options['auth'][2]
-        ) {
+        if (isset($options['auth'][2]) && 'ntlm' === $options['auth'][2]) {
             throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
         }
 
         $uri = $this->resolveHost($request, $options);
 
-        $context = $this->createResource(
-            function () use ($context, $params) {
-                return stream_context_create($context, $params);
+        $contextResource = $this->createResource(
+            static function () use ($context, $params) {
+                return \stream_context_create($context, $params);
             }
         );
 
         return $this->createResource(
-            function () use ($uri, &$http_response_header, $context, $options) {
-                $resource = fopen((string) $uri, 'r', null, $context);
+            function () use ($uri, &$http_response_header, $contextResource, $context, $options, $request) {
+                $resource = \fopen((string) $uri, 'r', false, $contextResource);
                 $this->lastHeaders = $http_response_header;
 
+                if (false === $resource) {
+                    throw new ConnectException(
+                        sprintf('Connection refused for URI %s', $uri),
+                        $request,
+                        null,
+                        $context
+                    );
+                }
+
                 if (isset($options['read_timeout'])) {
                     $readTimeout = $options['read_timeout'];
                     $sec = (int) $readTimeout;
                     $usec = ($readTimeout - $sec) * 100000;
-                    stream_set_timeout($resource, $sec, $usec);
+                    \stream_set_timeout($resource, $sec, $usec);
                 }
 
                 return $resource;
@@ -335,42 +353,43 @@ class StreamHandler
         );
     }
 
-    private function resolveHost(RequestInterface $request, array $options)
+    private function resolveHost(RequestInterface $request, array $options): UriInterface
     {
         $uri = $request->getUri();
 
-        if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
+        if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) {
             if ('v4' === $options['force_ip_resolve']) {
-                $records = dns_get_record($uri->getHost(), DNS_A);
-                if (!isset($records[0]['ip'])) {
+                $records = \dns_get_record($uri->getHost(), \DNS_A);
+                if (false === $records || !isset($records[0]['ip'])) {
                     throw new ConnectException(
-                        sprintf(
+                        \sprintf(
                             "Could not resolve IPv4 address for host '%s'",
                             $uri->getHost()
                         ),
                         $request
                     );
                 }
-                $uri = $uri->withHost($records[0]['ip']);
-            } elseif ('v6' === $options['force_ip_resolve']) {
-                $records = dns_get_record($uri->getHost(), DNS_AAAA);
-                if (!isset($records[0]['ipv6'])) {
+                return $uri->withHost($records[0]['ip']);
+            }
+            if ('v6' === $options['force_ip_resolve']) {
+                $records = \dns_get_record($uri->getHost(), \DNS_AAAA);
+                if (false === $records || !isset($records[0]['ipv6'])) {
                     throw new ConnectException(
-                        sprintf(
+                        \sprintf(
                             "Could not resolve IPv6 address for host '%s'",
                             $uri->getHost()
                         ),
                         $request
                     );
                 }
-                $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
+                return $uri->withHost('[' . $records[0]['ipv6'] . ']');
             }
         }
 
         return $uri;
     }
 
-    private function getDefaultContext(RequestInterface $request)
+    private function getDefaultContext(RequestInterface $request): array
     {
         $headers = '';
         foreach ($request->getHeaders() as $name => $value) {
@@ -399,20 +418,23 @@ class StreamHandler
             }
         }
 
-        $context['http']['header'] = rtrim($context['http']['header']);
+        $context['http']['header'] = \rtrim($context['http']['header']);
 
         return $context;
     }
 
-    private function add_proxy(RequestInterface $request, &$options, $value, &$params)
+    /**
+     * @param mixed $value as passed via Request transfer options.
+     */
+    private function add_proxy(RequestInterface $request, array &$options, $value, array &$params): void
     {
-        if (!is_array($value)) {
+        if (!\is_array($value)) {
             $options['http']['proxy'] = $value;
         } else {
             $scheme = $request->getUri()->getScheme();
             if (isset($value[$scheme])) {
                 if (!isset($value['no'])
-                    || !\GuzzleHttp\is_host_in_noproxy(
+                    || !Utils::isHostInNoProxy(
                         $request->getUri()->getHost(),
                         $value['no']
                     )
@@ -423,31 +445,34 @@ class StreamHandler
         }
     }
 
-    private function add_timeout(RequestInterface $request, &$options, $value, &$params)
+    /**
+     * @param mixed $value as passed via Request transfer options.
+     */
+    private function add_timeout(RequestInterface $request, array &$options, $value, array &$params): void
     {
         if ($value > 0) {
             $options['http']['timeout'] = $value;
         }
     }
 
-    private function add_verify(RequestInterface $request, &$options, $value, &$params)
+    /**
+     * @param mixed $value as passed via Request transfer options.
+     */
+    private function add_verify(RequestInterface $request, array &$options, $value, array &$params): void
     {
-        if ($value === true) {
-            // PHP 5.6 or greater will find the system cert by default. When
-            // < 5.6, use the Guzzle bundled cacert.
-            if (PHP_VERSION_ID < 50600) {
-                $options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
-            }
-        } elseif (is_string($value)) {
-            $options['ssl']['cafile'] = $value;
-            if (!file_exists($value)) {
-                throw new \RuntimeException("SSL CA bundle not found: $value");
-            }
-        } elseif ($value === false) {
+        if ($value === false) {
             $options['ssl']['verify_peer'] = false;
             $options['ssl']['verify_peer_name'] = false;
+
             return;
-        } else {
+        }
+
+        if (\is_string($value)) {
+            $options['ssl']['cafile'] = $value;
+            if (!\file_exists($value)) {
+                throw new \RuntimeException("SSL CA bundle not found: $value");
+            }
+        } elseif ($value !== true) {
             throw new \InvalidArgumentException('Invalid verify request option');
         }
 
@@ -456,88 +481,94 @@ class StreamHandler
         $options['ssl']['allow_self_signed'] = false;
     }
 
-    private function add_cert(RequestInterface $request, &$options, $value, &$params)
+    /**
+     * @param mixed $value as passed via Request transfer options.
+     */
+    private function add_cert(RequestInterface $request, array &$options, $value, array &$params): void
     {
-        if (is_array($value)) {
+        if (\is_array($value)) {
             $options['ssl']['passphrase'] = $value[1];
             $value = $value[0];
         }
 
-        if (!file_exists($value)) {
+        if (!\file_exists($value)) {
             throw new \RuntimeException("SSL certificate not found: {$value}");
         }
 
         $options['ssl']['local_cert'] = $value;
     }
 
-    private function add_progress(RequestInterface $request, &$options, $value, &$params)
+    /**
+     * @param mixed $value as passed via Request transfer options.
+     */
+    private function add_progress(RequestInterface $request, array &$options, $value, array &$params): void
     {
-        $this->addNotification(
+        self::addNotification(
             $params,
-            function ($code, $a, $b, $c, $transferred, $total) use ($value) {
-                if ($code == STREAM_NOTIFY_PROGRESS) {
+            static function ($code, $a, $b, $c, $transferred, $total) use ($value) {
+                if ($code == \STREAM_NOTIFY_PROGRESS) {
                     $value($total, $transferred, null, null);
                 }
             }
         );
     }
 
-    private function add_debug(RequestInterface $request, &$options, $value, &$params)
+    /**
+     * @param mixed $value as passed via Request transfer options.
+     */
+    private function add_debug(RequestInterface $request, array &$options, $value, array &$params): void
     {
         if ($value === false) {
             return;
         }
 
         static $map = [
-            STREAM_NOTIFY_CONNECT       => 'CONNECT',
-            STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
-            STREAM_NOTIFY_AUTH_RESULT   => 'AUTH_RESULT',
-            STREAM_NOTIFY_MIME_TYPE_IS  => 'MIME_TYPE_IS',
-            STREAM_NOTIFY_FILE_SIZE_IS  => 'FILE_SIZE_IS',
-            STREAM_NOTIFY_REDIRECTED    => 'REDIRECTED',
-            STREAM_NOTIFY_PROGRESS      => 'PROGRESS',
-            STREAM_NOTIFY_FAILURE       => 'FAILURE',
-            STREAM_NOTIFY_COMPLETED     => 'COMPLETED',
-            STREAM_NOTIFY_RESOLVE       => 'RESOLVE',
+            \STREAM_NOTIFY_CONNECT       => 'CONNECT',
+            \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
+            \STREAM_NOTIFY_AUTH_RESULT   => 'AUTH_RESULT',
+            \STREAM_NOTIFY_MIME_TYPE_IS  => 'MIME_TYPE_IS',
+            \STREAM_NOTIFY_FILE_SIZE_IS  => 'FILE_SIZE_IS',
+            \STREAM_NOTIFY_REDIRECTED    => 'REDIRECTED',
+            \STREAM_NOTIFY_PROGRESS      => 'PROGRESS',
+            \STREAM_NOTIFY_FAILURE       => 'FAILURE',
+            \STREAM_NOTIFY_COMPLETED     => 'COMPLETED',
+            \STREAM_NOTIFY_RESOLVE       => 'RESOLVE',
         ];
         static $args = ['severity', 'message', 'message_code',
             'bytes_transferred', 'bytes_max'];
 
-        $value = \GuzzleHttp\debug_resource($value);
+        $value = Utils::debugResource($value);
         $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
-        $this->addNotification(
+        self::addNotification(
             $params,
-            function () use ($ident, $value, $map, $args) {
-                $passed = func_get_args();
-                $code = array_shift($passed);
-                fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
-                foreach (array_filter($passed) as $i => $v) {
-                    fwrite($value, $args[$i] . ': "' . $v . '" ');
+            static function (int $code, ...$passed) use ($ident, $value, $map, $args): void {
+                \fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
+                foreach (\array_filter($passed) as $i => $v) {
+                    \fwrite($value, $args[$i] . ': "' . $v . '" ');
                 }
-                fwrite($value, "\n");
+                \fwrite($value, "\n");
             }
         );
     }
 
-    private function addNotification(array &$params, callable $notify)
+    private static function addNotification(array &$params, callable $notify): void
     {
         // Wrap the existing function if needed.
         if (!isset($params['notification'])) {
             $params['notification'] = $notify;
         } else {
-            $params['notification'] = $this->callArray([
+            $params['notification'] = self::callArray([
                 $params['notification'],
                 $notify
             ]);
         }
     }
 
-    private function callArray(array $functions)
+    private static function callArray(array $functions): callable
     {
-        return function () use ($functions) {
-            $args = func_get_args();
+        return static function (...$args) use ($functions) {
             foreach ($functions as $fn) {
-                call_user_func_array($fn, $args);
+                $fn(...$args);
             }
         };
     }

+ 66 - 72
api/vendor/guzzlehttp/guzzle/src/HandlerStack.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Promise\PromiseInterface;
@@ -8,16 +9,24 @@ use Psr\Http\Message\ResponseInterface;
 /**
  * Creates a composed Guzzle handler function by stacking middlewares on top of
  * an HTTP handler function.
+ *
+ * @final
  */
 class HandlerStack
 {
-    /** @var callable|null */
+    /**
+     * @var null|callable(RequestInterface, array): PromiseInterface
+     */
     private $handler;
 
-    /** @var array */
+    /**
+     * @var array{(callable(callable(RequestInterface, array): PromiseInterface): callable), (string|null)}[]
+     */
     private $stack = [];
 
-    /** @var callable|null */
+    /**
+     * @var null|callable(RequestInterface, array): PromiseInterface
+     */
     private $cached;
 
     /**
@@ -31,15 +40,13 @@ class HandlerStack
      * The returned handler stack can be passed to a client in the "handler"
      * option.
      *
-     * @param callable $handler HTTP handler function to use with the stack. If no
-     *                          handler is provided, the best handler for your
-     *                          system will be utilized.
-     *
-     * @return HandlerStack
+     * @param null|callable(RequestInterface, array): PromiseInterface $handler HTTP handler function to use with the stack. If no
+     *                                                                          handler is provided, the best handler for your
+     *                                                                          system will be utilized.
      */
-    public static function create(callable $handler = null)
+    public static function create(?callable $handler = null): self
     {
-        $stack = new self($handler ?: choose_handler());
+        $stack = new self($handler ?: Utils::chooseHandler());
         $stack->push(Middleware::httpErrors(), 'http_errors');
         $stack->push(Middleware::redirect(), 'allow_redirects');
         $stack->push(Middleware::cookies(), 'cookies');
@@ -49,7 +56,7 @@ class HandlerStack
     }
 
     /**
-     * @param callable $handler Underlying HTTP handler.
+     * @param null|callable(RequestInterface, array): PromiseInterface $handler Underlying HTTP handler.
      */
     public function __construct(callable $handler = null)
     {
@@ -59,9 +66,6 @@ class HandlerStack
     /**
      * Invokes the handler stack as a composed handler
      *
-     * @param RequestInterface $request
-     * @param array            $options
-     *
      * @return ResponseInterface|PromiseInterface
      */
     public function __invoke(RequestInterface $request, array $options)
@@ -80,12 +84,13 @@ class HandlerStack
     {
         $depth = 0;
         $stack = [];
-        if ($this->handler) {
+
+        if ($this->handler !== null) {
             $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
         }
 
         $result = '';
-        foreach (array_reverse($this->stack) as $tuple) {
+        foreach (\array_reverse($this->stack) as $tuple) {
             $depth++;
             $str = "{$depth}) Name: '{$tuple[1]}', ";
             $str .= "Function: " . $this->debugCallable($tuple[0]);
@@ -93,7 +98,7 @@ class HandlerStack
             $stack[] = $str;
         }
 
-        foreach (array_keys($stack) as $k) {
+        foreach (\array_keys($stack) as $k) {
             $result .= "< {$stack[$k]}\n";
         }
 
@@ -103,10 +108,10 @@ class HandlerStack
     /**
      * Set the HTTP handler that actually returns a promise.
      *
-     * @param callable $handler Accepts a request and array of options and
-     *                          returns a Promise.
+     * @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and
+     *                                                                     returns a Promise.
      */
-    public function setHandler(callable $handler)
+    public function setHandler(callable $handler): void
     {
         $this->handler = $handler;
         $this->cached = null;
@@ -114,33 +119,31 @@ class HandlerStack
 
     /**
      * Returns true if the builder has a handler.
-     *
-     * @return bool
      */
-    public function hasHandler()
+    public function hasHandler(): bool
     {
-        return (bool) $this->handler;
+        return $this->handler !== null ;
     }
 
     /**
      * Unshift a middleware to the bottom of the stack.
      *
-     * @param callable $middleware Middleware function
-     * @param string   $name       Name to register for this middleware.
+     * @param callable(callable): callable $middleware Middleware function
+     * @param string                       $name       Name to register for this middleware.
      */
-    public function unshift(callable $middleware, $name = null)
+    public function unshift(callable $middleware, ?string $name = null): void
     {
-        array_unshift($this->stack, [$middleware, $name]);
+        \array_unshift($this->stack, [$middleware, $name]);
         $this->cached = null;
     }
 
     /**
      * Push a middleware to the top of the stack.
      *
-     * @param callable $middleware Middleware function
-     * @param string   $name       Name to register for this middleware.
+     * @param callable(callable): callable $middleware Middleware function
+     * @param string                       $name       Name to register for this middleware.
      */
-    public function push(callable $middleware, $name = '')
+    public function push(callable $middleware, string $name = ''): void
     {
         $this->stack[] = [$middleware, $name];
         $this->cached = null;
@@ -149,11 +152,11 @@ class HandlerStack
     /**
      * Add a middleware before another middleware by name.
      *
-     * @param string   $findName   Middleware to find
-     * @param callable $middleware Middleware function
-     * @param string   $withName   Name to register for this middleware.
+     * @param string                       $findName   Middleware to find
+     * @param callable(callable): callable $middleware Middleware function
+     * @param string                       $withName   Name to register for this middleware.
      */
-    public function before($findName, callable $middleware, $withName = '')
+    public function before(string $findName, callable $middleware, string $withName = ''): void
     {
         $this->splice($findName, $withName, $middleware, true);
     }
@@ -161,11 +164,11 @@ class HandlerStack
     /**
      * Add a middleware after another middleware by name.
      *
-     * @param string   $findName   Middleware to find
-     * @param callable $middleware Middleware function
-     * @param string   $withName   Name to register for this middleware.
+     * @param string                       $findName   Middleware to find
+     * @param callable(callable): callable $middleware Middleware function
+     * @param string                       $withName   Name to register for this middleware.
      */
-    public function after($findName, callable $middleware, $withName = '')
+    public function after(string $findName, callable $middleware, string $withName = ''): void
     {
         $this->splice($findName, $withName, $middleware, false);
     }
@@ -175,13 +178,13 @@ class HandlerStack
      *
      * @param callable|string $remove Middleware to remove by instance or name.
      */
-    public function remove($remove)
+    public function remove($remove): void
     {
         $this->cached = null;
-        $idx = is_callable($remove) ? 0 : 1;
-        $this->stack = array_values(array_filter(
+        $idx = \is_callable($remove) ? 0 : 1;
+        $this->stack = \array_values(\array_filter(
             $this->stack,
-            function ($tuple) use ($idx, $remove) {
+            static function ($tuple) use ($idx, $remove) {
                 return $tuple[$idx] !== $remove;
             }
         ));
@@ -190,16 +193,17 @@ class HandlerStack
     /**
      * Compose the middleware and handler into a single callable function.
      *
-     * @return callable
+     * @return callable(RequestInterface, array): PromiseInterface
      */
-    public function resolve()
+    public function resolve(): callable
     {
-        if (!$this->cached) {
-            if (!($prev = $this->handler)) {
+        if ($this->cached === null) {
+            if (($prev = $this->handler) === null) {
                 throw new \LogicException('No handler has been specified');
             }
 
-            foreach (array_reverse($this->stack) as $fn) {
+            foreach (\array_reverse($this->stack) as $fn) {
+                /** @var callable(RequestInterface, array): PromiseInterface $prev */
                 $prev = $fn[0]($prev);
             }
 
@@ -209,11 +213,7 @@ class HandlerStack
         return $this->cached;
     }
 
-    /**
-     * @param string $name
-     * @return int
-     */
-    private function findByName($name)
+    private function findByName(string $name): int
     {
         foreach ($this->stack as $k => $v) {
             if ($v[1] === $name) {
@@ -226,13 +226,8 @@ class HandlerStack
 
     /**
      * Splices a function into the middleware list at a specific position.
-     *
-     * @param string   $findName
-     * @param string   $withName
-     * @param callable $middleware
-     * @param bool     $before
      */
-    private function splice($findName, $withName, callable $middleware, $before)
+    private function splice(string $findName, string $withName, callable $middleware, bool $before): void
     {
         $this->cached = null;
         $idx = $this->findByName($findName);
@@ -240,38 +235,37 @@ class HandlerStack
 
         if ($before) {
             if ($idx === 0) {
-                array_unshift($this->stack, $tuple);
+                \array_unshift($this->stack, $tuple);
             } else {
                 $replacement = [$tuple, $this->stack[$idx]];
-                array_splice($this->stack, $idx, 1, $replacement);
+                \array_splice($this->stack, $idx, 1, $replacement);
             }
-        } elseif ($idx === count($this->stack) - 1) {
+        } elseif ($idx === \count($this->stack) - 1) {
             $this->stack[] = $tuple;
         } else {
             $replacement = [$this->stack[$idx], $tuple];
-            array_splice($this->stack, $idx, 1, $replacement);
+            \array_splice($this->stack, $idx, 1, $replacement);
         }
     }
 
     /**
      * Provides a debug string for a given callable.
      *
-     * @param array|callable $fn Function to write as a string.
-     *
-     * @return string
+     * @param callable $fn Function to write as a string.
      */
-    private function debugCallable($fn)
+    private function debugCallable($fn): string
     {
-        if (is_string($fn)) {
+        if (\is_string($fn)) {
             return "callable({$fn})";
         }
 
-        if (is_array($fn)) {
-            return is_string($fn[0])
+        if (\is_array($fn)) {
+            return \is_string($fn[0])
                 ? "callable({$fn[0]}::{$fn[1]})"
-                : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
+                : "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])";
         }
 
-        return 'callable(' . spl_object_hash($fn) . ')';
+        /** @var object $fn */
+        return 'callable(' . \spl_object_hash($fn) . ')';
     }
 }

+ 48 - 32
api/vendor/guzzlehttp/guzzle/src/MessageFormatter.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp;
 
 use Psr\Http\Message\MessageInterface;
@@ -31,25 +32,31 @@ use Psr\Http\Message\ResponseInterface;
  * - {res_headers}:    Response headers
  * - {req_body}:       Request body
  * - {res_body}:       Response body
+ *
+ * @final
  */
-class MessageFormatter
+class MessageFormatter implements MessageFormatterInterface
 {
     /**
      * Apache Common Log Format.
-     * @link http://httpd.apache.org/docs/2.4/logs.html#common
+     *
+     * @link https://httpd.apache.org/docs/2.4/logs.html#common
+     *
      * @var string
      */
-    const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
-    const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
-    const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
+    public const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
+    public const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
+    public const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
 
-    /** @var string Template used to format log messages */
+    /**
+     * @var string Template used to format log messages
+     */
     private $template;
 
     /**
      * @param string $template Log message template
      */
-    public function __construct($template = self::CLF)
+    public function __construct(?string $template = self::CLF)
     {
         $this->template = $template ?: self::CLF;
     }
@@ -57,20 +64,19 @@ class MessageFormatter
     /**
      * Returns a formatted message string.
      *
-     * @param RequestInterface  $request  Request that was sent
-     * @param ResponseInterface $response Response that was received
-     * @param \Exception        $error    Exception that was received
-     *
-     * @return string
+     * @param RequestInterface       $request  Request that was sent
+     * @param ResponseInterface|null $response Response that was received
+     * @param \Throwable|null        $error    Exception that was received
      */
     public function format(
         RequestInterface $request,
-        ResponseInterface $response = null,
-        \Exception $error = null
-    ) {
+        ?ResponseInterface $response = null,
+        ?\Throwable $error = null
+    ): string {
         $cache = [];
 
-        return preg_replace_callback(
+        /** @var string */
+        return \preg_replace_callback(
             '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
             function (array $matches) use ($request, $response, $error, &$cache) {
                 if (isset($cache[$matches[1]])) {
@@ -86,14 +92,14 @@ class MessageFormatter
                         $result = $response ? Psr7\str($response) : '';
                         break;
                     case 'req_headers':
-                        $result = trim($request->getMethod()
+                        $result = \trim($request->getMethod()
                                 . ' ' . $request->getRequestTarget())
                             . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
                             . $this->headers($request);
                         break;
                     case 'res_headers':
                         $result = $response ?
-                            sprintf(
+                            \sprintf(
                                 'HTTP/%s %d %s',
                                 $response->getProtocolVersion(),
                                 $response->getStatusCode(),
@@ -102,17 +108,29 @@ class MessageFormatter
                             : 'NULL';
                         break;
                     case 'req_body':
-                        $result = $request->getBody();
+                        $result = $request->getBody()->__toString();
                         break;
                     case 'res_body':
-                        $result = $response ? $response->getBody() : 'NULL';
+                        if (!$response instanceof ResponseInterface) {
+                            $result = 'NULL';
+                            break;
+                        }
+
+                        $body = $response->getBody();
+
+                        if (!$body->isSeekable()) {
+                            $result = 'RESPONSE_NOT_LOGGEABLE';
+                            break;
+                        }
+
+                        $result = $response->getBody()->__toString();
                         break;
                     case 'ts':
                     case 'date_iso_8601':
-                        $result = gmdate('c');
+                        $result = \gmdate('c');
                         break;
                     case 'date_common_log':
-                        $result = date('d/M/Y:H:i:s O');
+                        $result = \date('d/M/Y:H:i:s O');
                         break;
                     case 'method':
                         $result = $request->getMethod();
@@ -139,7 +157,7 @@ class MessageFormatter
                         $result = $request->getHeaderLine('Host');
                         break;
                     case 'hostname':
-                        $result = gethostname();
+                        $result = \gethostname();
                         break;
                     case 'code':
                         $result = $response ? $response->getStatusCode() : 'NULL';
@@ -152,11 +170,11 @@ class MessageFormatter
                         break;
                     default:
                         // handle prefixed dynamic headers
-                        if (strpos($matches[1], 'req_header_') === 0) {
-                            $result = $request->getHeaderLine(substr($matches[1], 11));
-                        } elseif (strpos($matches[1], 'res_header_') === 0) {
+                        if (\strpos($matches[1], 'req_header_') === 0) {
+                            $result = $request->getHeaderLine(\substr($matches[1], 11));
+                        } elseif (\strpos($matches[1], 'res_header_') === 0) {
                             $result = $response
-                                ? $response->getHeaderLine(substr($matches[1], 11))
+                                ? $response->getHeaderLine(\substr($matches[1], 11))
                                 : 'NULL';
                         }
                 }
@@ -170,16 +188,14 @@ class MessageFormatter
 
     /**
      * Get headers from message as string
-     *
-     * @return string
      */
-    private function headers(MessageInterface $message)
+    private function headers(MessageInterface $message): string
     {
         $result = '';
         foreach ($message->getHeaders() as $name => $values) {
-            $result .= $name . ': ' . implode(', ', $values) . "\r\n";
+            $result .= $name . ': ' . \implode(', ', $values) . "\r\n";
         }
 
-        return trim($result);
+        return \trim($result);
     }
 }

+ 22 - 0
api/vendor/guzzlehttp/guzzle/src/MessageFormatterInterface.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace GuzzleHttp;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+interface MessageFormatterInterface
+{
+    /**
+     * Returns a formatted message string.
+     *
+     * @param RequestInterface       $request  Request that was sent
+     * @param ResponseInterface|null $response Response that was received
+     * @param \Throwable|null        $error    Exception that was received
+     */
+    public function format(
+        RequestInterface $request,
+        ?ResponseInterface $response = null,
+        ?\Throwable $error = null
+    ): string;
+}

+ 53 - 48
api/vendor/guzzlehttp/guzzle/src/Middleware.php

@@ -1,10 +1,11 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Cookie\CookieJarInterface;
 use GuzzleHttp\Exception\RequestException;
-use GuzzleHttp\Promise\RejectedPromise;
-use GuzzleHttp\Psr7;
+use GuzzleHttp\Promise\PromiseInterface;
+use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Log\LoggerInterface;
 
@@ -21,10 +22,10 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function cookies()
+    public static function cookies(): callable
     {
-        return function (callable $handler) {
-            return function ($request, array $options) use ($handler) {
+        return static function (callable $handler): callable {
+            return static function ($request, array $options) use ($handler) {
                 if (empty($options['cookies'])) {
                     return $handler($request, $options);
                 } elseif (!($options['cookies'] instanceof CookieJarInterface)) {
@@ -34,7 +35,7 @@ final class Middleware
                 $request = $cookieJar->withCookieHeader($request);
                 return $handler($request, $options)
                     ->then(
-                        function ($response) use ($cookieJar, $request) {
+                        static function (ResponseInterface $response) use ($cookieJar, $request): ResponseInterface {
                             $cookieJar->extractCookies($request, $response);
                             return $response;
                         }
@@ -47,17 +48,17 @@ final class Middleware
      * Middleware that throws exceptions for 4xx or 5xx responses when the
      * "http_error" request option is set to true.
      *
-     * @return callable Returns a function that accepts the next handler.
+     * @return callable(callable): callable Returns a function that accepts the next handler.
      */
-    public static function httpErrors()
+    public static function httpErrors(): callable
     {
-        return function (callable $handler) {
-            return function ($request, array $options) use ($handler) {
+        return static function (callable $handler): callable {
+            return static function ($request, array $options) use ($handler) {
                 if (empty($options['http_errors'])) {
                     return $handler($request, $options);
                 }
                 return $handler($request, $options)->then(
-                    function (ResponseInterface $response) use ($request) {
+                    static function (ResponseInterface $response) use ($request) {
                         $code = $response->getStatusCode();
                         if ($code < 400) {
                             return $response;
@@ -72,21 +73,22 @@ final class Middleware
     /**
      * Middleware that pushes history data to an ArrayAccess container.
      *
-     * @param array|\ArrayAccess $container Container to hold the history (by reference).
+     * @param array|\ArrayAccess<int, array> $container Container to hold the history (by reference).
+     *
+     * @return callable(callable): callable Returns a function that accepts the next handler.
      *
-     * @return callable Returns a function that accepts the next handler.
      * @throws \InvalidArgumentException if container is not an array or ArrayAccess.
      */
-    public static function history(&$container)
+    public static function history(&$container): callable
     {
-        if (!is_array($container) && !$container instanceof \ArrayAccess) {
+        if (!\is_array($container) && !$container instanceof \ArrayAccess) {
             throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
         }
 
-        return function (callable $handler) use (&$container) {
-            return function ($request, array $options) use ($handler, &$container) {
+        return static function (callable $handler) use (&$container): callable {
+            return static function (RequestInterface $request, array $options) use ($handler, &$container) {
                 return $handler($request, $options)->then(
-                    function ($value) use ($request, &$container, $options) {
+                    static function ($value) use ($request, &$container, $options) {
                         $container[] = [
                             'request'  => $request,
                             'response' => $value,
@@ -95,7 +97,7 @@ final class Middleware
                         ];
                         return $value;
                     },
-                    function ($reason) use ($request, &$container, $options) {
+                    static function ($reason) use ($request, &$container, $options) {
                         $container[] = [
                             'request'  => $request,
                             'response' => null,
@@ -122,10 +124,10 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function tap(callable $before = null, callable $after = null)
+    public static function tap(callable $before = null, callable $after = null): callable
     {
-        return function (callable $handler) use ($before, $after) {
-            return function ($request, array $options) use ($handler, $before, $after) {
+        return static function (callable $handler) use ($before, $after): callable {
+            return static function (RequestInterface $request, array $options) use ($handler, $before, $after) {
                 if ($before) {
                     $before($request, $options);
                 }
@@ -143,9 +145,9 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function redirect()
+    public static function redirect(): callable
     {
-        return function (callable $handler) {
+        return static function (callable $handler): RedirectMiddleware {
             return new RedirectMiddleware($handler);
         };
     }
@@ -165,9 +167,9 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function retry(callable $decider, callable $delay = null)
+    public static function retry(callable $decider, callable $delay = null): callable
     {
-        return function (callable $handler) use ($decider, $delay) {
+        return static function (callable $handler) use ($decider, $delay): RetryMiddleware {
             return new RetryMiddleware($decider, $handler, $delay);
         };
     }
@@ -176,28 +178,35 @@ final class Middleware
      * Middleware that logs requests, responses, and errors using a message
      * formatter.
      *
-     * @param LoggerInterface  $logger Logs messages.
-     * @param MessageFormatter $formatter Formatter used to create message strings.
-     * @param string           $logLevel Level at which to log requests.
+     * @phpstan-param \Psr\Log\LogLevel::* $logLevel  Level at which to log requests.
+     *
+     * @param LoggerInterface                            $logger    Logs messages.
+     * @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings.
+     * @param string                                     $logLevel  Level at which to log requests.
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' /* \Psr\Log\LogLevel::INFO */)
+    public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info'): callable
     {
-        return function (callable $handler) use ($logger, $formatter, $logLevel) {
-            return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
+        // To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter
+        if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) {
+            throw new \LogicException(sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class));
+        }
+
+        return static function (callable $handler) use ($logger, $formatter, $logLevel): callable {
+            return static function (RequestInterface $request, array $options = []) use ($handler, $logger, $formatter, $logLevel) {
                 return $handler($request, $options)->then(
-                    function ($response) use ($logger, $request, $formatter, $logLevel) {
+                    static function ($response) use ($logger, $request, $formatter, $logLevel): ResponseInterface {
                         $message = $formatter->format($request, $response);
                         $logger->log($logLevel, $message);
                         return $response;
                     },
-                    function ($reason) use ($logger, $request, $formatter) {
+                    static function ($reason) use ($logger, $request, $formatter): PromiseInterface {
                         $response = $reason instanceof RequestException
                             ? $reason->getResponse()
                             : null;
-                        $message = $formatter->format($request, $response, $reason);
-                        $logger->notice($message);
+                        $message = $formatter->format($request, $response, \GuzzleHttp\Promise\exception_for($reason));
+                        $logger->error($message);
                         return \GuzzleHttp\Promise\rejection_for($reason);
                     }
                 );
@@ -208,12 +217,10 @@ final class Middleware
     /**
      * This middleware adds a default content-type if possible, a default
      * content-length or transfer-encoding header, and the expect header.
-     *
-     * @return callable
      */
-    public static function prepareBody()
+    public static function prepareBody(): callable
     {
-        return function (callable $handler) {
+        return static function (callable $handler): PrepareBodyMiddleware {
             return new PrepareBodyMiddleware($handler);
         };
     }
@@ -224,12 +231,11 @@ final class Middleware
      *
      * @param callable $fn Function that accepts a RequestInterface and returns
      *                     a RequestInterface.
-     * @return callable
      */
-    public static function mapRequest(callable $fn)
+    public static function mapRequest(callable $fn): callable
     {
-        return function (callable $handler) use ($fn) {
-            return function ($request, array $options) use ($handler, $fn) {
+        return static function (callable $handler) use ($fn): callable {
+            return static function (RequestInterface $request, array $options) use ($handler, $fn) {
                 return $handler($fn($request), $options);
             };
         };
@@ -241,12 +247,11 @@ final class Middleware
      *
      * @param callable $fn Function that accepts a ResponseInterface and
      *                     returns a ResponseInterface.
-     * @return callable
      */
-    public static function mapResponse(callable $fn)
+    public static function mapResponse(callable $fn): callable
     {
-        return function (callable $handler) use ($fn) {
-            return function ($request, array $options) use ($handler, $fn) {
+        return static function (callable $handler) use ($fn): callable {
+            return static function (RequestInterface $request, array $options) use ($handler, $fn) {
                 return $handler($request, $options)->then($fn);
             };
         };

+ 21 - 22
api/vendor/guzzlehttp/guzzle/src/Pool.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Promise\EachPromise;
@@ -16,10 +17,14 @@ use Psr\Http\Message\RequestInterface;
  * When a function is yielded by the iterator, the function is provided the
  * "request_options" array that should be merged on top of any existing
  * options, and the function MUST then return a wait-able promise.
+ *
+ * @final
  */
 class Pool implements PromisorInterface
 {
-    /** @var EachPromise */
+    /**
+     * @var EachPromise
+     */
     private $each;
 
     /**
@@ -27,20 +32,17 @@ class Pool implements PromisorInterface
      * @param array|\Iterator $requests Requests or functions that return
      *                                  requests to send concurrently.
      * @param array           $config   Associative array of options
-     *     - concurrency: (int) Maximum number of requests to send concurrently
-     *     - options: Array of request options to apply to each request.
-     *     - fulfilled: (callable) Function to invoke when a request completes.
-     *     - rejected: (callable) Function to invoke when a request is rejected.
+     *                                  - concurrency: (int) Maximum number of requests to send concurrently
+     *                                  - options: Array of request options to apply to each request.
+     *                                  - fulfilled: (callable) Function to invoke when a request completes.
+     *                                  - rejected: (callable) Function to invoke when a request is rejected.
      */
     public function __construct(
         ClientInterface $client,
         $requests,
         array $config = []
     ) {
-        // Backwards compatibility.
-        if (isset($config['pool_size'])) {
-            $config['concurrency'] = $config['pool_size'];
-        } elseif (!isset($config['concurrency'])) {
+        if (!isset($config['concurrency'])) {
             $config['concurrency'] = 25;
         }
 
@@ -52,11 +54,11 @@ class Pool implements PromisorInterface
         }
 
         $iterable = \GuzzleHttp\Promise\iter_for($requests);
-        $requests = function () use ($iterable, $client, $opts) {
+        $requests = static function () use ($iterable, $client, $opts) {
             foreach ($iterable as $key => $rfn) {
                 if ($rfn instanceof RequestInterface) {
                     yield $key => $client->sendAsync($rfn, $opts);
-                } elseif (is_callable($rfn)) {
+                } elseif (\is_callable($rfn)) {
                     yield $key => $rfn($opts);
                 } else {
                     throw new \InvalidArgumentException('Each value yielded by '
@@ -72,10 +74,8 @@ class Pool implements PromisorInterface
 
     /**
      * Get promise
-     *
-     * @return PromiseInterface
      */
-    public function promise()
+    public function promise(): PromiseInterface
     {
         return $this->each->promise();
     }
@@ -91,41 +91,40 @@ class Pool implements PromisorInterface
      * @param ClientInterface $client   Client used to send the requests
      * @param array|\Iterator $requests Requests to send concurrently.
      * @param array           $options  Passes through the options available in
-     *                                  {@see GuzzleHttp\Pool::__construct}
+     *                                  {@see \GuzzleHttp\Pool::__construct}
      *
      * @return array Returns an array containing the response or an exception
      *               in the same order that the requests were sent.
+     *
      * @throws \InvalidArgumentException if the event format is incorrect.
      */
     public static function batch(
         ClientInterface $client,
         $requests,
         array $options = []
-    ) {
+    ): array {
         $res = [];
         self::cmpCallback($options, 'fulfilled', $res);
         self::cmpCallback($options, 'rejected', $res);
         $pool = new static($client, $requests, $options);
         $pool->promise()->wait();
-        ksort($res);
+        \ksort($res);
 
         return $res;
     }
 
     /**
      * Execute callback(s)
-     *
-     * @return void
      */
-    private static function cmpCallback(array &$options, $name, array &$results)
+    private static function cmpCallback(array &$options, string $name, array &$results): void
     {
         if (!isset($options[$name])) {
-            $options[$name] = function ($v, $k) use (&$results) {
+            $options[$name] = static function ($v, $k) use (&$results) {
                 $results[$k] = $v;
             };
         } else {
             $currentFn = $options[$name];
-            $options[$name] = function ($v, $k) use (&$results, $currentFn) {
+            $options[$name] = static function ($v, $k) use (&$results, $currentFn) {
                 $currentFn($v, $k);
                 $results[$k] = $v;
             };

+ 11 - 15
api/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php

@@ -1,34 +1,32 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Promise\PromiseInterface;
-use GuzzleHttp\Psr7;
 use Psr\Http\Message\RequestInterface;
 
 /**
  * Prepares requests that contain a body, adding the Content-Length,
  * Content-Type, and Expect headers.
+ *
+ * @final
  */
 class PrepareBodyMiddleware
 {
-    /** @var callable  */
+    /**
+     * @var callable(RequestInterface, array): PromiseInterface
+     */
     private $nextHandler;
 
     /**
-     * @param callable $nextHandler Next handler to invoke.
+     * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
      */
     public function __construct(callable $nextHandler)
     {
         $this->nextHandler = $nextHandler;
     }
 
-    /**
-     * @param RequestInterface $request
-     * @param array            $options
-     *
-     * @return PromiseInterface
-     */
-    public function __invoke(RequestInterface $request, array $options)
+    public function __invoke(RequestInterface $request, array $options): PromiseInterface
     {
         $fn = $this->nextHandler;
 
@@ -42,7 +40,7 @@ class PrepareBodyMiddleware
         // Add a default content-type if possible.
         if (!$request->hasHeader('Content-Type')) {
             if ($uri = $request->getBody()->getMetadata('uri')) {
-                if ($type = Psr7\mimetype_from_filename($uri)) {
+                if (is_string($uri) && $type = Psr7\mimetype_from_filename($uri)) {
                     $modify['set_headers']['Content-Type'] = $type;
                 }
             }
@@ -68,20 +66,18 @@ class PrepareBodyMiddleware
 
     /**
      * Add expect header
-     *
-     * @return void
      */
     private function addExpectHeader(
         RequestInterface $request,
         array $options,
         array &$modify
-    ) {
+    ): void {
         // Determine if the Expect header should be used
         if ($request->hasHeader('Expect')) {
             return;
         }
 
-        $expect = isset($options['expect']) ? $options['expect'] : null;
+        $expect = $options['expect'] ?? null;
 
         // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
         if ($expect === false || $request->getProtocolVersion() < 1.1) {

+ 35 - 54
api/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php

@@ -1,10 +1,10 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Exception\BadResponseException;
 use GuzzleHttp\Exception\TooManyRedirectsException;
 use GuzzleHttp\Promise\PromiseInterface;
-use GuzzleHttp\Psr7;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\UriInterface;
@@ -14,13 +14,18 @@ use Psr\Http\Message\UriInterface;
  *
  * Apply this middleware like other middleware using
  * {@see \GuzzleHttp\Middleware::redirect()}.
+ *
+ * @final
  */
 class RedirectMiddleware
 {
-    const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
+    public const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
 
-    const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
+    public const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
 
+    /**
+     * @var array
+     */
     public static $defaultSettings = [
         'max'             => 5,
         'protocols'       => ['http', 'https'],
@@ -29,24 +34,20 @@ class RedirectMiddleware
         'track_redirects' => false,
     ];
 
-    /** @var callable  */
+    /**
+     * @var callable(RequestInterface, array): PromiseInterface
+     */
     private $nextHandler;
 
     /**
-     * @param callable $nextHandler Next handler to invoke.
+     * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
      */
     public function __construct(callable $nextHandler)
     {
         $this->nextHandler = $nextHandler;
     }
 
-    /**
-     * @param RequestInterface $request
-     * @param array            $options
-     *
-     * @return PromiseInterface
-     */
-    public function __invoke(RequestInterface $request, array $options)
+    public function __invoke(RequestInterface $request, array $options): PromiseInterface
     {
         $fn = $this->nextHandler;
 
@@ -56,7 +57,7 @@ class RedirectMiddleware
 
         if ($options['allow_redirects'] === true) {
             $options['allow_redirects'] = self::$defaultSettings;
-        } elseif (!is_array($options['allow_redirects'])) {
+        } elseif (!\is_array($options['allow_redirects'])) {
             throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
         } else {
             // Merge the default settings with the provided settings
@@ -74,10 +75,6 @@ class RedirectMiddleware
     }
 
     /**
-     * @param RequestInterface  $request
-     * @param array             $options
-     * @param ResponseInterface $response
-     *
      * @return ResponseInterface|PromiseInterface
      */
     public function checkRedirect(
@@ -85,7 +82,7 @@ class RedirectMiddleware
         array $options,
         ResponseInterface $response
     ) {
-        if (substr($response->getStatusCode(), 0, 1) != '3'
+        if (\strpos((string) $response->getStatusCode(), '3') !== 0
             || !$response->hasHeader('Location')
         ) {
             return $response;
@@ -95,15 +92,13 @@ class RedirectMiddleware
         $nextRequest = $this->modifyRequest($request, $options, $response);
 
         if (isset($options['allow_redirects']['on_redirect'])) {
-            call_user_func(
-                $options['allow_redirects']['on_redirect'],
+            ($options['allow_redirects']['on_redirect'])(
                 $request,
                 $response,
                 $nextRequest->getUri()
             );
         }
 
-        /** @var PromiseInterface|ResponseInterface $promise */
         $promise = $this($nextRequest, $options);
 
         // Add headers to be able to track history of redirects.
@@ -120,20 +115,19 @@ class RedirectMiddleware
 
     /**
      * Enable tracking on promise.
-     *
-     * @return PromiseInterface
      */
-    private function withTracking(PromiseInterface $promise, $uri, $statusCode)
+    private function withTracking(PromiseInterface $promise, string $uri, int $statusCode): PromiseInterface
     {
         return $promise->then(
-            function (ResponseInterface $response) use ($uri, $statusCode) {
+            static function (ResponseInterface $response) use ($uri, $statusCode) {
                 // Note that we are pushing to the front of the list as this
                 // would be an earlier response than what is currently present
                 // in the history header.
                 $historyHeader = $response->getHeader(self::HISTORY_HEADER);
                 $statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
-                array_unshift($historyHeader, $uri);
-                array_unshift($statusHeader, $statusCode);
+                \array_unshift($historyHeader, $uri);
+                \array_unshift($statusHeader, (string) $statusCode);
+
                 return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
                                 ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
             }
@@ -143,15 +137,12 @@ class RedirectMiddleware
     /**
      * Check for too many redirects
      *
-     * @return void
-     *
      * @throws TooManyRedirectsException Too many redirects.
      */
-    private function guardMax(RequestInterface $request, array &$options)
+    private function guardMax(RequestInterface $request, array &$options): void
     {
-        $current = isset($options['__redirect_count'])
-            ? $options['__redirect_count']
-            : 0;
+        $current = $options['__redirect_count']
+            ?? 0;
         $options['__redirect_count'] = $current + 1;
         $max = $options['allow_redirects']['max'];
 
@@ -163,18 +154,11 @@ class RedirectMiddleware
         }
     }
 
-    /**
-     * @param RequestInterface  $request
-     * @param array             $options
-     * @param ResponseInterface $response
-     *
-     * @return RequestInterface
-     */
     public function modifyRequest(
         RequestInterface $request,
         array $options,
         ResponseInterface $response
-    ) {
+    ): RequestInterface {
         // Request modifications to apply.
         $modify = [];
         $protocols = $options['allow_redirects']['protocols'];
@@ -186,14 +170,17 @@ class RedirectMiddleware
         if ($statusCode == 303 ||
             ($statusCode <= 302 && !$options['allow_redirects']['strict'])
         ) {
-            $modify['method'] = 'GET';
+            $safeMethods = ['GET', 'HEAD', 'OPTIONS'];
+            $requestMethod = $request->getMethod();
+
+            $modify['method'] = in_array($requestMethod, $safeMethods) ? $requestMethod : 'GET';
             $modify['body'] = '';
         }
 
         $uri = $this->redirectUri($request, $response, $protocols);
         if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
-            $idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
-            $uri = _idn_uri_convert($uri, $idnOptions);
+            $idnOptions = ($options['idn_conversion'] === true) ? \IDNA_DEFAULT : $options['idn_conversion'];
+            $uri = Utils::idnUriConvert($uri, $idnOptions);
         }
 
         $modify['uri'] = $uri;
@@ -220,30 +207,24 @@ class RedirectMiddleware
 
     /**
      * Set the appropriate URL on the request based on the location header
-     *
-     * @param RequestInterface  $request
-     * @param ResponseInterface $response
-     * @param array             $protocols
-     *
-     * @return UriInterface
      */
     private function redirectUri(
         RequestInterface $request,
         ResponseInterface $response,
         array $protocols
-    ) {
+    ): UriInterface {
         $location = Psr7\UriResolver::resolve(
             $request->getUri(),
             new Psr7\Uri($response->getHeaderLine('Location'))
         );
 
         // Ensure that the redirect URI is allowed based on the protocols.
-        if (!in_array($location->getScheme(), $protocols)) {
+        if (!\in_array($location->getScheme(), $protocols)) {
             throw new BadResponseException(
-                sprintf(
+                \sprintf(
                     'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
                     $location,
-                    implode(', ', $protocols)
+                    \implode(', ', $protocols)
                 ),
                 $request,
                 $response

+ 32 - 31
api/vendor/guzzlehttp/guzzle/src/RequestOptions.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp;
 
 /**
@@ -31,7 +32,7 @@ final class RequestOptions
      *   response that was received, and the effective URI. Any return value
      *   from the on_redirect function is ignored.
      */
-    const ALLOW_REDIRECTS = 'allow_redirects';
+    public const ALLOW_REDIRECTS = 'allow_redirects';
 
     /**
      * auth: (array) Pass an array of HTTP authentication parameters to use
@@ -40,13 +41,13 @@ final class RequestOptions
      * authentication type in index [2]. Pass null to disable authentication
      * for a request.
      */
-    const AUTH = 'auth';
+    public const AUTH = 'auth';
 
     /**
      * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
      * Body to send in the request.
      */
-    const BODY = 'body';
+    public const BODY = 'body';
 
     /**
      * cert: (string|array) Set to a string to specify the path to a file
@@ -55,42 +56,42 @@ final class RequestOptions
      * file in the first array element followed by the certificate password
      * in the second array element.
      */
-    const CERT = 'cert';
+    public const CERT = 'cert';
 
     /**
      * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
      * Specifies whether or not cookies are used in a request or what cookie
      * jar to use or what cookies to send. This option only works if your
      * handler has the `cookie` middleware. Valid values are `false` and
-     * an instance of {@see GuzzleHttp\Cookie\CookieJarInterface}.
+     * an instance of {@see \GuzzleHttp\Cookie\CookieJarInterface}.
      */
-    const COOKIES = 'cookies';
+    public const COOKIES = 'cookies';
 
     /**
      * connect_timeout: (float, default=0) Float describing the number of
      * seconds to wait while trying to connect to a server. Use 0 to wait
      * indefinitely (the default behavior).
      */
-    const CONNECT_TIMEOUT = 'connect_timeout';
+    public const CONNECT_TIMEOUT = 'connect_timeout';
 
     /**
      * debug: (bool|resource) Set to true or set to a PHP stream returned by
      * fopen()  enable debug output with the HTTP handler used to send a
      * request.
      */
-    const DEBUG = 'debug';
+    public const DEBUG = 'debug';
 
     /**
      * decode_content: (bool, default=true) Specify whether or not
      * Content-Encoding responses (gzip, deflate, etc.) are automatically
      * decoded.
      */
-    const DECODE_CONTENT = 'decode_content';
+    public const DECODE_CONTENT = 'decode_content';
 
     /**
      * delay: (int) The amount of time to delay before sending in milliseconds.
      */
-    const DELAY = 'delay';
+    public const DELAY = 'delay';
 
     /**
      * expect: (bool|integer) Controls the behavior of the
@@ -108,7 +109,7 @@ final class RequestOptions
      * size of the body of a request is greater than 1 MB and a request is
      * using HTTP/1.1.
      */
-    const EXPECT = 'expect';
+    public const EXPECT = 'expect';
 
     /**
      * form_params: (array) Associative array of form field names to values
@@ -116,13 +117,13 @@ final class RequestOptions
      * header to application/x-www-form-urlencoded when no Content-Type header
      * is already present.
      */
-    const FORM_PARAMS = 'form_params';
+    public const FORM_PARAMS = 'form_params';
 
     /**
      * headers: (array) Associative array of HTTP headers. Each value MUST be
      * a string or array of strings.
      */
-    const HEADERS = 'headers';
+    public const HEADERS = 'headers';
 
     /**
      * http_errors: (bool, default=true) Set to false to disable exceptions
@@ -130,7 +131,7 @@ final class RequestOptions
      * exceptions will be thrown for 4xx and 5xx responses. This option only
      * works if your handler has the `httpErrors` middleware.
      */
-    const HTTP_ERRORS = 'http_errors';
+    public const HTTP_ERRORS = 'http_errors';
 
     /**
      * idn: (bool|int, default=true) A combination of IDNA_* constants for
@@ -138,14 +139,14 @@ final class RequestOptions
      * disable IDN support completely, or to true to use the default
      * configuration (IDNA_DEFAULT constant).
      */
-    const IDN_CONVERSION = 'idn_conversion';
+    public const IDN_CONVERSION = 'idn_conversion';
 
     /**
      * json: (mixed) Adds JSON data to a request. The provided value is JSON
      * encoded and a Content-Type header of application/json will be added to
      * the request if no Content-Type header is already present.
      */
-    const JSON = 'json';
+    public const JSON = 'json';
 
     /**
      * multipart: (array) Array of associative arrays, each containing a
@@ -156,14 +157,14 @@ final class RequestOptions
      * the part. If no "filename" key is present, then no "filename" attribute
      * will be added to the part.
      */
-    const MULTIPART = 'multipart';
+    public const MULTIPART = 'multipart';
 
     /**
      * on_headers: (callable) A callable that is invoked when the HTTP headers
      * of the response have been received but the body has not yet begun to
      * download.
      */
-    const ON_HEADERS = 'on_headers';
+    public const ON_HEADERS = 'on_headers';
 
     /**
      * on_stats: (callable) allows you to get access to transfer statistics of
@@ -174,7 +175,7 @@ final class RequestOptions
      * the error encountered. Included in the data is the total amount of time
      * taken to send the request.
      */
-    const ON_STATS = 'on_stats';
+    public const ON_STATS = 'on_stats';
 
     /**
      * progress: (callable) Defines a function to invoke when transfer
@@ -183,14 +184,14 @@ final class RequestOptions
      * number of bytes downloaded so far, the number of bytes expected to be
      * uploaded, the number of bytes uploaded so far.
      */
-    const PROGRESS = 'progress';
+    public const PROGRESS = 'progress';
 
     /**
      * proxy: (string|array) Pass a string to specify an HTTP proxy, or an
      * array to specify different proxies for different protocols (where the
      * key is the protocol and the value is a proxy string).
      */
-    const PROXY = 'proxy';
+    public const PROXY = 'proxy';
 
     /**
      * query: (array|string) Associative array of query string values to add
@@ -198,14 +199,14 @@ final class RequestOptions
      * the string representation. Pass a string value if you need more
      * control than what this method provides
      */
-    const QUERY = 'query';
+    public const QUERY = 'query';
 
     /**
      * sink: (resource|string|StreamInterface) Where the data of the
      * response is written to. Defaults to a PHP temp stream. Providing a
      * string will write data to a file by the given name.
      */
-    const SINK = 'sink';
+    public const SINK = 'sink';
 
     /**
      * synchronous: (bool) Set to true to inform HTTP handlers that you intend
@@ -213,7 +214,7 @@ final class RequestOptions
      * that a promise is still returned if you are using one of the async
      * client methods.
      */
-    const SYNCHRONOUS = 'synchronous';
+    public const SYNCHRONOUS = 'synchronous';
 
     /**
      * ssl_key: (array|string) Specify the path to a file containing a private
@@ -221,13 +222,13 @@ final class RequestOptions
      * containing the path to the SSL key in the first array element followed
      * by the password required for the certificate in the second element.
      */
-    const SSL_KEY = 'ssl_key';
+    public const SSL_KEY = 'ssl_key';
 
     /**
      * stream: Set to true to attempt to stream a response rather than
      * download it all up-front.
      */
-    const STREAM = 'stream';
+    public const STREAM = 'stream';
 
     /**
      * verify: (bool|string, default=true) Describes the SSL certificate
@@ -237,27 +238,27 @@ final class RequestOptions
      * is insecure!). Set to a string to provide the path to a CA bundle on
      * disk to enable verification using a custom certificate.
      */
-    const VERIFY = 'verify';
+    public const VERIFY = 'verify';
 
     /**
      * timeout: (float, default=0) Float describing the timeout of the
      * request in seconds. Use 0 to wait indefinitely (the default behavior).
      */
-    const TIMEOUT = 'timeout';
+    public const TIMEOUT = 'timeout';
 
     /**
      * read_timeout: (float, default=default_socket_timeout ini setting) Float describing
      * the body read timeout, for stream requests.
      */
-    const READ_TIMEOUT = 'read_timeout';
+    public const READ_TIMEOUT = 'read_timeout';
 
     /**
      * version: (float) Specifies the HTTP protocol version to attempt to use.
      */
-    const VERSION = 'version';
+    public const VERSION = 'version';
 
     /**
      * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
      */
-    const FORCE_IP_RESOLVE = 'force_ip_resolve';
+    public const FORCE_IP_RESOLVE = 'force_ip_resolve';
 }

+ 32 - 42
api/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php

@@ -1,36 +1,43 @@
 <?php
+
 namespace GuzzleHttp;
 
 use GuzzleHttp\Promise\PromiseInterface;
-use GuzzleHttp\Promise\RejectedPromise;
-use GuzzleHttp\Psr7;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
 
 /**
  * Middleware that retries requests based on the boolean result of
  * invoking the provided "decider" function.
+ *
+ * @final
  */
 class RetryMiddleware
 {
-    /** @var callable  */
+    /**
+     * @var callable(RequestInterface, array): PromiseInterface
+     */
     private $nextHandler;
 
-    /** @var callable */
+    /**
+     * @var callable
+     */
     private $decider;
 
-    /** @var callable */
+    /**
+     * @var callable(int)
+     */
     private $delay;
 
     /**
-     * @param callable $decider     Function that accepts the number of retries,
-     *                              a request, [response], and [exception] and
-     *                              returns true if the request is to be
-     *                              retried.
-     * @param callable $nextHandler Next handler to invoke.
-     * @param callable $delay       Function that accepts the number of retries
-     *                              and [response] and returns the number of
-     *                              milliseconds to delay.
+     * @param callable                                            $decider     Function that accepts the number of retries,
+     *                                                                         a request, [response], and [exception] and
+     *                                                                         returns true if the request is to be
+     *                                                                         retried.
+     * @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
+     * @param null|callable(int): int                             $delay       Function that accepts the number of retries
+     *                                                                         and returns the number of
+     *                                                                         milliseconds to delay.
      */
     public function __construct(
         callable $decider,
@@ -45,22 +52,14 @@ class RetryMiddleware
     /**
      * Default exponential backoff delay function.
      *
-     * @param int $retries
-     *
      * @return int milliseconds.
      */
-    public static function exponentialDelay($retries)
+    public static function exponentialDelay(int $retries): int
     {
-        return (int) pow(2, $retries - 1) * 1000;
+        return (int) \pow(2, $retries - 1) * 1000;
     }
 
-    /**
-     * @param RequestInterface $request
-     * @param array            $options
-     *
-     * @return PromiseInterface
-     */
-    public function __invoke(RequestInterface $request, array $options)
+    public function __invoke(RequestInterface $request, array $options): PromiseInterface
     {
         if (!isset($options['retries'])) {
             $options['retries'] = 0;
@@ -76,35 +75,29 @@ class RetryMiddleware
 
     /**
      * Execute fulfilled closure
-     *
-     * @return mixed
      */
-    private function onFulfilled(RequestInterface $req, array $options)
+    private function onFulfilled(RequestInterface $request, array $options): callable
     {
-        return function ($value) use ($req, $options) {
-            if (!call_user_func(
-                $this->decider,
+        return function ($value) use ($request, $options) {
+            if (!($this->decider)(
                 $options['retries'],
-                $req,
+                $request,
                 $value,
                 null
             )) {
                 return $value;
             }
-            return $this->doRetry($req, $options, $value);
+            return $this->doRetry($request, $options, $value);
         };
     }
 
     /**
      * Execute rejected closure
-     *
-     * @return callable
      */
-    private function onRejected(RequestInterface $req, array $options)
+    private function onRejected(RequestInterface $req, array $options): callable
     {
         return function ($reason) use ($req, $options) {
-            if (!call_user_func(
-                $this->decider,
+            if (!($this->decider)(
                 $options['retries'],
                 $req,
                 null,
@@ -116,12 +109,9 @@ class RetryMiddleware
         };
     }
 
-    /**
-     * @return self
-     */
-    private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
+    private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null): PromiseInterface
     {
-        $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
+        $options['delay'] = ($this->delay)(++$options['retries'], $response);
 
         return $this($request, $options);
     }

+ 30 - 21
api/vendor/guzzlehttp/guzzle/src/TransferStats.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace GuzzleHttp;
 
 use Psr\Http\Message\RequestInterface;
@@ -11,10 +12,29 @@ use Psr\Http\Message\UriInterface;
  */
 final class TransferStats
 {
+    /**
+     * @var RequestInterface
+     */
     private $request;
+
+    /**
+     * @var ResponseInterface|null
+     */
     private $response;
+
+    /**
+     * @var float|null
+     */
     private $transferTime;
+
+    /**
+     * @var array
+     */
     private $handlerStats;
+
+    /**
+     * @var mixed|null
+     */
     private $handlerErrorData;
 
     /**
@@ -26,10 +46,10 @@ final class TransferStats
      */
     public function __construct(
         RequestInterface $request,
-        ResponseInterface $response = null,
-        $transferTime = null,
+        ?ResponseInterface $response = null,
+        ?float $transferTime = null,
         $handlerErrorData = null,
-        $handlerStats = []
+        array $handlerStats = []
     ) {
         $this->request = $request;
         $this->response = $response;
@@ -38,30 +58,23 @@ final class TransferStats
         $this->handlerStats = $handlerStats;
     }
 
-    /**
-     * @return RequestInterface
-     */
-    public function getRequest()
+    public function getRequest(): RequestInterface
     {
         return $this->request;
     }
 
     /**
      * Returns the response that was received (if any).
-     *
-     * @return ResponseInterface|null
      */
-    public function getResponse()
+    public function getResponse(): ?ResponseInterface
     {
         return $this->response;
     }
 
     /**
      * Returns true if a response was received.
-     *
-     * @return bool
      */
-    public function hasResponse()
+    public function hasResponse(): bool
     {
         return $this->response !== null;
     }
@@ -82,10 +95,8 @@ final class TransferStats
 
     /**
      * Get the effective URI the request was sent to.
-     *
-     * @return UriInterface
      */
-    public function getEffectiveUri()
+    public function getEffectiveUri(): UriInterface
     {
         return $this->request->getUri();
     }
@@ -95,17 +106,15 @@ final class TransferStats
      *
      * @return float|null Time in seconds.
      */
-    public function getTransferTime()
+    public function getTransferTime(): ?float
     {
         return $this->transferTime;
     }
 
     /**
      * Gets an array of all of the handler specific transfer data.
-     *
-     * @return array
      */
-    public function getHandlerStats()
+    public function getHandlerStats(): array
     {
         return $this->handlerStats;
     }
@@ -117,7 +126,7 @@ final class TransferStats
      *
      * @return mixed|null
      */
-    public function getHandlerStat($stat)
+    public function getHandlerStat(string $stat)
     {
         return isset($this->handlerStats[$stat])
             ? $this->handlerStats[$stat]

+ 0 - 237
api/vendor/guzzlehttp/guzzle/src/UriTemplate.php

@@ -1,237 +0,0 @@
-<?php
-namespace GuzzleHttp;
-
-/**
- * Expands URI templates. Userland implementation of PECL uri_template.
- *
- * @link http://tools.ietf.org/html/rfc6570
- */
-class UriTemplate
-{
-    /** @var string URI template */
-    private $template;
-
-    /** @var array Variables to use in the template expansion */
-    private $variables;
-
-    /** @var array Hash for quick operator lookups */
-    private static $operatorHash = [
-        ''  => ['prefix' => '',  'joiner' => ',', 'query' => false],
-        '+' => ['prefix' => '',  'joiner' => ',', 'query' => false],
-        '#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
-        '.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
-        '/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
-        ';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
-        '?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
-        '&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
-    ];
-
-    /** @var array Delimiters */
-    private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
-        '&', '\'', '(', ')', '*', '+', ',', ';', '='];
-
-    /** @var array Percent encoded delimiters */
-    private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',
-        '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
-        '%3B', '%3D'];
-
-    public function expand($template, array $variables)
-    {
-        if (false === strpos($template, '{')) {
-            return $template;
-        }
-
-        $this->template = $template;
-        $this->variables = $variables;
-
-        return preg_replace_callback(
-            '/\{([^\}]+)\}/',
-            [$this, 'expandMatch'],
-            $this->template
-        );
-    }
-
-    /**
-     * Parse an expression into parts
-     *
-     * @param string $expression Expression to parse
-     *
-     * @return array Returns an associative array of parts
-     */
-    private function parseExpression($expression)
-    {
-        $result = [];
-
-        if (isset(self::$operatorHash[$expression[0]])) {
-            $result['operator'] = $expression[0];
-            $expression = substr($expression, 1);
-        } else {
-            $result['operator'] = '';
-        }
-
-        foreach (explode(',', $expression) as $value) {
-            $value = trim($value);
-            $varspec = [];
-            if ($colonPos = strpos($value, ':')) {
-                $varspec['value'] = substr($value, 0, $colonPos);
-                $varspec['modifier'] = ':';
-                $varspec['position'] = (int) substr($value, $colonPos + 1);
-            } elseif (substr($value, -1) === '*') {
-                $varspec['modifier'] = '*';
-                $varspec['value'] = substr($value, 0, -1);
-            } else {
-                $varspec['value'] = (string) $value;
-                $varspec['modifier'] = '';
-            }
-            $result['values'][] = $varspec;
-        }
-
-        return $result;
-    }
-
-    /**
-     * Process an expansion
-     *
-     * @param array $matches Matches met in the preg_replace_callback
-     *
-     * @return string Returns the replacement string
-     */
-    private function expandMatch(array $matches)
-    {
-        static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];
-
-        $replacements = [];
-        $parsed = self::parseExpression($matches[1]);
-        $prefix = self::$operatorHash[$parsed['operator']]['prefix'];
-        $joiner = self::$operatorHash[$parsed['operator']]['joiner'];
-        $useQuery = self::$operatorHash[$parsed['operator']]['query'];
-
-        foreach ($parsed['values'] as $value) {
-            if (!isset($this->variables[$value['value']])) {
-                continue;
-            }
-
-            $variable = $this->variables[$value['value']];
-            $actuallyUseQuery = $useQuery;
-            $expanded = '';
-
-            if (is_array($variable)) {
-                $isAssoc = $this->isAssoc($variable);
-                $kvp = [];
-                foreach ($variable as $key => $var) {
-                    if ($isAssoc) {
-                        $key = rawurlencode($key);
-                        $isNestedArray = is_array($var);
-                    } else {
-                        $isNestedArray = false;
-                    }
-
-                    if (!$isNestedArray) {
-                        $var = rawurlencode($var);
-                        if ($parsed['operator'] === '+' ||
-                            $parsed['operator'] === '#'
-                        ) {
-                            $var = $this->decodeReserved($var);
-                        }
-                    }
-
-                    if ($value['modifier'] === '*') {
-                        if ($isAssoc) {
-                            if ($isNestedArray) {
-                                // Nested arrays must allow for deeply nested
-                                // structures.
-                                $var = strtr(
-                                    http_build_query([$key => $var]),
-                                    $rfc1738to3986
-                                );
-                            } else {
-                                $var = $key . '=' . $var;
-                            }
-                        } elseif ($key > 0 && $actuallyUseQuery) {
-                            $var = $value['value'] . '=' . $var;
-                        }
-                    }
-
-                    $kvp[$key] = $var;
-                }
-
-                if (empty($variable)) {
-                    $actuallyUseQuery = false;
-                } elseif ($value['modifier'] === '*') {
-                    $expanded = implode($joiner, $kvp);
-                    if ($isAssoc) {
-                        // Don't prepend the value name when using the explode
-                        // modifier with an associative array.
-                        $actuallyUseQuery = false;
-                    }
-                } else {
-                    if ($isAssoc) {
-                        // When an associative array is encountered and the
-                        // explode modifier is not set, then the result must be
-                        // a comma separated list of keys followed by their
-                        // respective values.
-                        foreach ($kvp as $k => &$v) {
-                            $v = $k . ',' . $v;
-                        }
-                    }
-                    $expanded = implode(',', $kvp);
-                }
-            } else {
-                if ($value['modifier'] === ':') {
-                    $variable = substr($variable, 0, $value['position']);
-                }
-                $expanded = rawurlencode($variable);
-                if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
-                    $expanded = $this->decodeReserved($expanded);
-                }
-            }
-
-            if ($actuallyUseQuery) {
-                if (!$expanded && $joiner !== '&') {
-                    $expanded = $value['value'];
-                } else {
-                    $expanded = $value['value'] . '=' . $expanded;
-                }
-            }
-
-            $replacements[] = $expanded;
-        }
-
-        $ret = implode($joiner, $replacements);
-        if ($ret && $prefix) {
-            return $prefix . $ret;
-        }
-
-        return $ret;
-    }
-
-    /**
-     * Determines if an array is associative.
-     *
-     * This makes the assumption that input arrays are sequences or hashes.
-     * This assumption is a tradeoff for accuracy in favor of speed, but it
-     * should work in almost every case where input is supplied for a URI
-     * template.
-     *
-     * @param array $array Array to check
-     *
-     * @return bool
-     */
-    private function isAssoc(array $array)
-    {
-        return $array && array_keys($array)[0] !== 0;
-    }
-
-    /**
-     * Removes percent encoding on reserved characters (used with + and #
-     * modifiers).
-     *
-     * @param string $string String to fix
-     *
-     * @return string
-     */
-    private function decodeReserved($string)
-    {
-        return str_replace(self::$delimsPct, self::$delims, $string);
-    }
-}

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov