+
+
+
diff --git a/akamai/vendor/akamai-open/edgegrid-client/phpdox.xml.dist b/akamai/vendor/akamai-open/edgegrid-client/phpdox.xml.dist
new file mode 100644
index 00000000..e9b0ed7f
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/phpdox.xml.dist
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/akamai/vendor/akamai-open/edgegrid-client/phpunit.xml.dist b/akamai/vendor/akamai-open/edgegrid-client/phpunit.xml.dist
new file mode 100644
index 00000000..e612e09c
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/phpunit.xml.dist
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+ ./tests
+
+
+
+
+ ./src
+
+
+
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Authentication.php b/akamai/vendor/akamai-open/edgegrid-client/src/Authentication.php
new file mode 100644
index 00000000..5636f388
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Authentication.php
@@ -0,0 +1,512 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid;
+
+use Akamai\Open\EdgeGrid\Authentication\Nonce;
+use Akamai\Open\EdgeGrid\Authentication\Timestamp;
+use Akamai\Open\EdgeGrid\Exception\ConfigException;
+use Akamai\Open\EdgeGrid\Exception\SignerException\InvalidSignDataException;
+
+/**
+ * Akamai {OPEN} EdgeGrid Request Signer
+ *
+ * @package Akamai {OPEN} EdgeGrid Auth
+ */
+class Authentication
+{
+ /**
+ * @var array Authentication tokens
+ */
+ protected $auth;
+
+ /**
+ * @var string HTTP method
+ */
+ protected $httpMethod;
+
+ /**
+ * @var string HTTP host
+ */
+ protected $host;
+
+ /**
+ * @var array Guzzle config
+ */
+ protected $config = array();
+
+ /**
+ * @var string Request path
+ */
+ protected $path;
+
+ /**
+ * @var Timestamp Request timestamp
+ */
+ protected $timestamp;
+
+ /**
+ * @var Nonce Request nonce
+ */
+ protected $nonce;
+
+ /**
+ * @var int Maximum body size for signing
+ */
+ protected $max_body_size = 131072;
+
+ /**
+ * @var array A list of headers to be included in the signature
+ */
+ protected $headers_to_sign = array();
+
+ /**
+ * Create the Authentication header
+ *
+ * @return string
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+ public function createAuthHeader()
+ {
+ if ($this->timestamp === null) {
+ $this->setTimestamp();
+ }
+
+ if (!$this->timestamp->isValid()) {
+ throw new InvalidSignDataException("Timestamp is invalid. Too old?");
+ }
+
+ if ($this->nonce === null) {
+ $this->nonce = new Nonce();
+ }
+
+ $auth_header =
+ 'EG1-HMAC-SHA256 ' .
+ 'client_token=' . $this->auth['client_token'] . ';' .
+ 'access_token=' . $this->auth['access_token'] . ';' .
+ 'timestamp=' . $this->timestamp . ';' .
+ 'nonce=' . $this->nonce . ';';
+
+ return $auth_header . 'signature=' . $this->signRequest($auth_header);
+ }
+
+ /**
+ * Set request HTTP method
+ *
+ * @param string $method
+ * @return Authentication
+ */
+ public function setHttpMethod($method)
+ {
+ $this->httpMethod = $method;
+ return $this;
+ }
+
+ /**
+ * Get the request host
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * Set request host
+ *
+ * @param mixed $host
+ * @return Authentication
+ */
+ public function setHost($host)
+ {
+ $this->host = $host;
+ if (strpos($host, '/') !== false || strpos($host, '?') !== false) {
+ if (strpos($host, 'http') === false) {
+ $host = 'https://' . $host;
+ }
+ $url = parse_url($host);
+ $this->host = $url['host'];
+
+ if (isset($url['path'])) {
+ $this->setPath($url['path']);
+ }
+
+ if (isset($url['query'])) {
+ if (!isset($url['path'])) { // for example.org?query=string
+ $this->setPath('/');
+ }
+ $this->setQuery($url['query']);
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Guzzle config
+ *
+ * This is a convenient way to pass in the
+ * body/query/headers options
+ *
+ * @param mixed $config
+ * @return Authentication
+ */
+ public function setConfig(array $config)
+ {
+ $this->config = array_merge($this->config, $config);
+ return $this;
+ }
+
+ /**
+ * Set GET args
+ *
+ * If setting to a string, you MUST encode using RFC3986
+ * {@see http_build_query()}
+ *
+ * @param array|string $query
+ * @return $this
+ */
+ public function setQuery($query, $ensure_encoding = true)
+ {
+ if (is_string($query) && $ensure_encoding) {
+ $query_args = array();
+ parse_str($query, $query_args);
+ $query = http_build_query($query_args, null, '&', PHP_QUERY_RFC3986);
+ }
+ $this->config['query'] = $query;
+ return $this;
+ }
+
+ /**
+ * Set request body
+ *
+ * @param string $body
+ * return $this;
+ */
+ public function setBody($body)
+ {
+ $this->config['body'] = $body;
+ return $this;
+ }
+
+ /**
+ * Set request headers
+ *
+ * @param array $headers
+ * @return $this
+ */
+ public function setHeaders(array $headers)
+ {
+ $this->config['headers'] = $headers;
+ return $this;
+ }
+
+ /**
+ * Set request path
+ *
+ * @param mixed $path
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ $url = parse_url($path);
+
+ $this->path = $url['path'];
+ if (isset($url['host'])) {
+ $this->setHost($url['host']);
+ }
+
+ if (isset($url['query'])) {
+ $this->setQuery($url['query']);
+ }
+ return $this;
+ }
+
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Set signing timestamp
+ *
+ * @param mixed $timestamp
+ * @return $this
+ */
+ public function setTimestamp($timestamp = null)
+ {
+ $this->timestamp = $timestamp;
+ if ($timestamp === null) {
+ $this->timestamp = new Timestamp();
+ }
+ return $this;
+ }
+
+ /**
+ * Set signing nonce
+ *
+ * @param Nonce $nonce
+ * @return $this
+ */
+ public function setNonce($nonce = null)
+ {
+ $this->nonce = $nonce;
+ if ($nonce === null) {
+ $this->nonce = new Nonce();
+ }
+ return $this;
+ }
+
+ /**
+ * Set headers to sign
+ *
+ * @param array $headers_to_sign
+ * @return $this
+ */
+ public function setHeadersToSign($headers_to_sign)
+ {
+ $this->headers_to_sign = $headers_to_sign;
+ return $this;
+ }
+
+ /**
+ * Set max body size to sign
+ *
+ * @param int $max_body_size Size (in bytes)
+ * @return $this
+ */
+ public function setMaxBodySize($max_body_size)
+ {
+ $this->max_body_size = $max_body_size;
+ return $this;
+ }
+
+ /**
+ * Set Akamai EdgeGrid Authentication Tokens/Secret
+ *
+ * @param string $client_token
+ * @param string $client_secret
+ * @param string $access_token
+ * @return $this
+ */
+ public function setAuth($client_token, $client_secret, $access_token)
+ {
+ $this->auth = compact('client_token', 'client_secret', 'access_token');
+ return $this;
+ }
+
+ public static function createFromEdgeRcFile($section = "default", $path = null)
+ {
+ if ($section === null) {
+ $section = 'default';
+ }
+
+ $ini = self::parseEdgeRcFile($path);
+
+ if (!isset($ini[$section])) {
+ throw new ConfigException("Section \"$section\" does not exist!");
+ }
+
+ $auth = new static();
+ $auth->setAuth(
+ $ini[$section]['client_token'],
+ $ini[$section]['client_secret'],
+ $ini[$section]['access_token']
+ );
+
+ if (isset($ini[$section]['host'])) {
+ $auth->setHost($ini[$section]['host']);
+ }
+
+ if (isset($ini[$section]['max-size'])) {
+ $auth->setMaxBodySize($ini[$section]['max-size']);
+ }
+
+ return $auth;
+ }
+
+ /**
+ * Returns headers in normalized form
+ *
+ * @return string
+ */
+ protected function canonicalizeHeaders()
+ {
+ $canonical = array();
+ $headers = array();
+ if (isset($this->config['headers'])) {
+ $headers = array_combine(
+ array_map('strtolower', array_keys($this->config['headers'])),
+ array_values($this->config['headers'])
+ );
+ }
+
+ foreach ($this->headers_to_sign as $key) {
+ $key = strtolower($key);
+ if (isset($headers[$key])) {
+ if (is_array($headers[$key]) && sizeof($headers[$key]) >= 1) {
+ $value = trim($headers[$key][0]);
+ } elseif (is_array($headers[$key]) && sizeof($headers[$key]) == 0) {
+ continue;
+ } else {
+ $value = trim($headers[$key]);
+ }
+
+ if (!empty($value)) {
+ $canonical[$key] = preg_replace('/\s+/', ' ', $value);
+ }
+ }
+ }
+
+ ksort($canonical);
+ $serialized_header = '';
+ foreach ($canonical as $key => $value) {
+ $serialized_header .= $key . ':' . $value . "\t";
+ }
+
+ return rtrim($serialized_header);
+ }
+
+ /**
+ * Returns Base64 encoded HMAC-SHA256 Hash
+ *
+ * @param string $data
+ * @param string $key
+ * @return string
+ */
+ protected function makeBase64HmacSha256($data, $key)
+ {
+ $hash = base64_encode(hash_hmac('sha256', (string) $data, $key, true));
+ return $hash;
+ }
+
+ /**
+ * Returns Base64 encoded SHA256 Hash
+ *
+ * @param string $data
+ * @return string
+ */
+ protected function makeBase64Sha256($data)
+ {
+ $hash = base64_encode(hash('sha256', (string) $data, true));
+ return $hash;
+ }
+
+ /**
+ * Returns a hash of the HTTP POST body
+ *
+ * @return string
+ */
+ protected function makeContentHash()
+ {
+ if (empty($this->config['body'])) {
+ return '';
+ } else {
+ // Just substr, it'll return as much as it can
+ return $this->makeBase64Sha256(substr($this->config['body'], 0, $this->max_body_size));
+ }
+ }
+
+ /**
+ * Returns a string with all data that will be signed
+ *
+ * @param string $auth_header
+ * @return string
+ */
+ protected function makeDataToSign($auth_header)
+ {
+ $query = '';
+ if (isset($this->config['query']) && $this->config['query']) {
+ $query .= '?';
+ if (is_string($this->config['query'])) {
+ $query .= $this->config['query'];
+ } else {
+ $query .= http_build_query($this->config['query'], null, '&', PHP_QUERY_RFC3986);
+ }
+ }
+
+ $data = array(
+ strtoupper($this->httpMethod),
+ 'https',
+ $this->host,
+ $this->path . $query,
+ $this->canonicalizeHeaders(),
+ (strtoupper($this->httpMethod) == 'POST') ? $this->makeContentHash() : '',
+ $auth_header
+ );
+
+ return implode("\t", $data);
+ }
+
+ /**
+ * Creates a signing key based on the secret and timestamp
+ *
+ * @return string
+ */
+ protected function makeSigningKey()
+ {
+ $key = self::makeBase64HmacSha256((string) ($this->timestamp), $this->auth['client_secret']);
+ return $key;
+ }
+
+ /**
+ * Returns a signature of the given request, timestamp and auth_header
+ *
+ * @param string $auth_header
+ * @return string
+ */
+ protected function signRequest($auth_header)
+ {
+ return $this->makeBase64HmacSha256(
+ $this->makeDataToSign($auth_header),
+ $this->makeSigningKey()
+ );
+ }
+
+ /**
+ * Parse a .edgerc File
+ *
+ * @param $path
+ * @return array
+ * @throws \Exception
+ */
+ protected static function parseEdgeRcFile($path)
+ {
+ if ($path === null) {
+ if (isset($_SERVER['HOME']) && file_exists($_SERVER['HOME'] . '/.edgerc')) {
+ $path = $_SERVER['HOME'] . "/.edgerc";
+ } elseif (file_exists('./.edgerc')) {
+ $path = './.edgerc';
+ }
+ }
+
+ $file = !$path ? false : realpath($path);
+ if (!$file) {
+ throw new ConfigException("Path to .edgerc file \"$path\" does not exist!");
+ }
+
+ if (!is_readable($file)) {
+ throw new ConfigException("Unable to read .edgerc file!");
+ }
+
+ // Handle : assignments in .edgerc files
+ $ini = file_get_contents($file);
+ $ini = str_replace(':', '=', $ini);
+
+ $ini = parse_ini_string($ini, true, INI_SCANNER_RAW);
+
+ return $ini;
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Authentication/Nonce.php b/akamai/vendor/akamai-open/edgegrid-client/src/Authentication/Nonce.php
new file mode 100644
index 00000000..e258fd5c
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Authentication/Nonce.php
@@ -0,0 +1,52 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid\Authentication;
+
+/**
+ * Generates a random nonce for each request
+ *
+ * @package Akamai {OPEN} EdgeGrid Auth
+ */
+class Nonce
+{
+ /**
+ * @var string The current random function to use
+ */
+ protected $function;
+
+ /**
+ * Constructor
+ *
+ * Determines if PHP 7's random_bytes() can be used
+ */
+ public function __construct()
+ {
+ $this->function = 'openssl_random_pseudo_bytes';
+
+ // Use PHP 7's random_bytes()
+ if (function_exists('random_bytes')) {
+ $this->function = 'random_bytes';
+ }
+ }
+
+ /**
+ * Return the nonce when cast to string
+ *
+ * @return string Returns the nonce
+ */
+ public function __toString()
+ {
+ // because ($this->function)() won't work til PHP 7 :(
+ $function = $this->function;
+ return bin2hex($function(16));
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Authentication/Timestamp.php b/akamai/vendor/akamai-open/edgegrid-client/src/Authentication/Timestamp.php
new file mode 100644
index 00000000..76e07fd5
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Authentication/Timestamp.php
@@ -0,0 +1,74 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid\Authentication;
+
+/**
+ * Generates an Akamai formatted Date for each request
+ *
+ * @package Akamai {OPEN} EdgeGrid Auth
+ */
+class Timestamp
+{
+ /**
+ * @var \DateTime Signing Timestamp
+ */
+ protected $timestamp;
+
+ /**
+ * @var string \DateInterval spec
+ */
+ protected $validFor = 'PT10S';
+
+ /**
+ * Signing Timestamp
+ */
+ public function __construct()
+ {
+ $this->timestamp = new \DateTime("now", new \DateTimeZone('UTC'));
+ }
+
+ /**
+ * Return true is timestamp is less than 10s old
+ *
+ * @return bool
+ */
+ public function isValid()
+ {
+ $now = new \DateTime("now", new \DateTimeZone('UTC'));
+ $timestamp = clone $this->timestamp;
+
+ return $timestamp->add(new \DateInterval($this->validFor)) >= $now;
+ }
+
+ /**
+ * Set how long the current timestamp is considered valid
+ *
+ * @see \DateInterval
+ * @param string $interval A \DateInterval time spec
+ * @return $this
+ */
+ public function setValidFor($interval)
+ {
+ $this->validFor = $interval;
+ return $this;
+ }
+
+ /**
+ * Return the timestamp when cast to string
+ *
+ * @return string Returns the date
+ */
+ public function __toString()
+ {
+ return $this->timestamp->format('Ymd\TH:i:sO');
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Cli.php b/akamai/vendor/akamai-open/edgegrid-client/src/Cli.php
new file mode 100644
index 00000000..0eefd430
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Cli.php
@@ -0,0 +1,325 @@
+setAuth()}.
+ *
+ * @author Davey Shafik
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid;
+
+class Cli
+{
+ /**
+ * @var \League\CLImate\CLImate
+ */
+ protected $climate;
+
+ public function __construct()
+ {
+ $this->climate = new \League\CLImate\CLImate();
+ }
+
+ public function run()
+ {
+ if ($this->parseArguments()) {
+ $this->executeCommand();
+ }
+ }
+
+ protected function parseArguments()
+ {
+ $args = $this->getNamedArgs();
+
+ $this->climate->arguments->add($args);
+
+ if ($_SERVER['argc'] == 1) {
+ $this->help();
+ return false;
+ }
+
+ if ($this->climate->arguments->defined('help')) {
+ $this->help();
+ return;
+ }
+
+ if ($this->climate->arguments->defined('version')) {
+ echo $this->version();
+ return;
+ }
+
+ try {
+ $this->climate->arguments->parse($_SERVER['argv']);
+
+ $padding = sizeof($args);
+ foreach ($this->climate->arguments->toArray() as $arg) {
+ if ($arg == null) {
+ $padding -= 1;
+ }
+ }
+ $argSize = sizeof($_SERVER['argv']) - $padding - 1;
+ for ($i = 0; $i < $argSize; $i++) {
+ $args['arg-' . $i] = [];
+ }
+ $this->climate->arguments->add($args);
+ $this->climate->arguments->parse($_SERVER['argv']);
+ } catch (\Exception $e) {
+ }
+
+ return true;
+ }
+
+ protected function executeCommand()
+ {
+ static $methods = [
+ 'HEAD',
+ 'GET',
+ 'POST',
+ 'PUT',
+ 'DELETE'
+ ];
+
+ \Akamai\Open\EdgeGrid\Client::setDebug(true);
+ \Akamai\Open\EdgeGrid\Client::setVerbose(true);
+
+ $args = $this->climate->arguments->all();
+ $client = new Client();
+
+ if ($this->climate->arguments->defined('auth-type')) {
+ $auth = $this->climate->arguments->get('auth');
+ if ($this->climate->arguments->get('auth-type') == 'edgegrid' ||
+ (!$this->climate->arguments->defined('auth-type'))) {
+ $section = 'default';
+ if ($this->climate->arguments->defined('auth')) {
+ $section = (substr($auth, -1) == ':') ? substr($auth, 0, -1) : $auth;
+ }
+ $client = Client::createFromEdgeRcFile($section);
+ }
+
+ if (in_array($this->climate->arguments->get('auth-type'), ['basic', 'digest'])) {
+ if (!$this->climate->arguments->defined('auth') || $this->climate->arguments->get('auth') === null) {
+ $this->help();
+ return;
+ }
+
+ $auth = [
+ $auth,
+ null,
+ $this->climate->arguments->get('auth-type')
+ ];
+
+ if (strpos(':', $auth[0]) !== false) {
+ list($auth[0], $auth[1]) = explode(':', $auth[0]);
+ }
+
+ $client = new Client(['auth' => $auth]);
+ }
+ }
+
+ $method = 'GET';
+ $options = [];
+ $body = [];
+
+ foreach ($args as $arg) {
+ $value = $arg->value();
+ if (empty($value) || is_bool($value) || $arg->longPrefix()) {
+ continue;
+ }
+
+ if (in_array(strtoupper($value), $methods)) {
+ $method = $arg->value();
+ continue;
+ }
+
+ if (!isset($url) && preg_match('@^(http(s?)://|:).*$@', trim($value))) {
+ $url = $value;
+
+ if ($url{0} == ':') {
+ $url = substr($url, 1);
+ }
+
+ continue;
+ }
+
+ $matches = [];
+ if (preg_match('/^(?.*?):=(?@?)(?.*?)$/', $value, $matches)) {
+ if (!$value = $this->getArgValue($matches)) {
+ return false;
+ }
+
+ $body[$matches['key']] = json_decode($value);
+ continue;
+ }
+
+ if (preg_match('/^(?.*?):(?.*?)$/', $value, $matches)
+ && !preg_match('@^http(s?)://@', $value)) {
+ $options['headers'][$matches['header']] = $matches['value'];
+ continue;
+ }
+
+ if (preg_match('/^(?.*?)=(?@?)(?.*?)$/', $value, $matches)) {
+ if (!$value = $this->getArgValue($matches)) {
+ return false;
+ }
+
+ $body[$matches['key']] = $matches['value'];
+ continue;
+ }
+
+ if (!isset($url)) {
+ $url = $value;
+ continue;
+ }
+
+ $this->help();
+ $this->climate->error("Unknown argument: " . $value);
+
+ return false;
+ }
+
+ $stdin = '';
+ $fp = fopen('php://stdin', 'r');
+ if ($fp) {
+ stream_set_blocking($fp, false);
+ $stdin = fgets($fp);
+ if (!empty(trim($stdin))) {
+ while (!feof($fp)) {
+ $stdin .= fgets($fp);
+ }
+ fclose($fp);
+ }
+ $stdin = rtrim($stdin);
+ }
+
+ if (!empty($stdin) && !empty($body)) {
+ $this->help();
+ $this->climate->error(
+ "error: Request body (from stdin or a file) and request data (key=value) cannot be mixed."
+ );
+ return;
+ }
+
+ if (!empty($stdin)) {
+ $body = $stdin;
+ }
+
+ if (sizeof($body) && !$this->climate->arguments->defined('form')) {
+ if (!isset($options['headers']['Content-Type'])) {
+ $options['headers']['Content-Type'] = 'application/json';
+ }
+ if (!isset($options['headers']['Accept'])) {
+ $options['headers']['Accept'] = 'application/json';
+ }
+ $options['body'] = (!is_string($body)) ? json_encode($body) : $body;
+ }
+
+ if (sizeof($body) && $this->climate->arguments->defined('form')) {
+ if (!isset($options['headers']['Content-Type'])) {
+ $options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';
+ }
+
+ $options['body'] = (!is_string($body)) ? http_build_query($body, null, null, PHP_QUERY_RFC1738) : $body;
+ }
+
+ $options['allow_redirects'] = false;
+ if ($this->climate->arguments->defined('follow')) {
+ $options['allow_redirects'] = true;
+ }
+
+ return $client->request($method, $url, $options);
+ }
+
+ public function help()
+ {
+ $arguments = new \League\CLImate\Argument\Manager();
+ $arguments->description("Akamai {OPEN} Edgegrid Auth for PHP Client (v" .Client::VERSION. ')');
+ $arguments->add($this->getNamedArgs());
+ $arguments->usage($this->climate, $_SERVER['argv']);
+ return;
+ }
+
+ public function version()
+ {
+ return Client::VERSION;
+ }
+
+ /**
+ * @return array
+ */
+ protected function getNamedArgs()
+ {
+ $args = [
+ 'help' => [
+ 'longPrefix' => 'help',
+ 'prefix' => 'h',
+ 'description' => 'Show this help output',
+ 'noValue' => true
+ ],
+ 'auth-type' => [
+ 'longPrefix' => 'auth-type',
+ 'description' => "{basic, digest, edgegrid}"
+ ],
+ 'auth' => [
+ 'longPrefix' => 'auth',
+ 'prefix' => 'a',
+ 'description' => '.edgerc section name, or user[:password]'
+ ],
+ 'json' => [
+ 'longPrefix' => 'json',
+ 'prefix' => 'j',
+ 'description' => '(default) Data items from the command line are serialized as a JSON object.',
+ 'noValue' => true
+ ],
+ 'follow' => [
+ 'longPrefix' => 'follow',
+ 'description' => 'Set this flag if redirects are allowed',
+ 'noValue' => true
+ ],
+ 'form' => [
+ 'longPrefix' => 'form',
+ 'prefix' => 'f',
+ 'description' => 'Data items from the command line are serialized as form fields',
+ 'noValue' => true
+ ],
+ 'version' => [
+ 'longPrefix' => 'version',
+ 'description' => 'Show version',
+ 'noValue' => true
+ ],
+ 'METHOD' => [
+ 'description' => 'HTTP Method (default: GET)'
+ ],
+ 'URL' => [
+ 'required' => true,
+ ]
+ ];
+
+ return $args;
+ }
+
+ protected function getArgValue($matches)
+ {
+ $value = $matches['value'];
+ if (!empty($matches['file'])) {
+ if (!file_exists($matches['value']) || !is_readable($matches['value'])) {
+ $this->climate->error("Unable to read input file: " . $matches['value']);
+ return false;
+ }
+ $value = file_get_contents($matches['value']);
+ }
+
+ return $value;
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Client.php b/akamai/vendor/akamai-open/edgegrid-client/src/Client.php
new file mode 100644
index 00000000..53b5fbe8
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Client.php
@@ -0,0 +1,637 @@
+setAuth()}.
+ *
+ * @author Davey Shafik
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid;
+
+use Akamai\Open\EdgeGrid\Authentication;
+use Akamai\Open\EdgeGrid\Handler\Authentication as AuthenticationHandler;
+use Akamai\Open\EdgeGrid\Handler\Debug as DebugHandler;
+use Akamai\Open\EdgeGrid\Handler\Verbose as VerboseHandler;
+
+/**
+ * Akamai {OPEN} EdgeGrid Client for PHP
+ *
+ * Akamai {OPEN} EdgeGrid Client for PHP. Based on
+ * [Guzzle](http://guzzlephp.org).
+ *
+ * @package Akamai {OPEN} EdgeGrid Client
+ */
+class Client extends \GuzzleHttp\Client implements \Psr\Log\LoggerAwareInterface
+{
+ const VERSION = "0.4.6";
+
+ /**
+ * @const int Default Timeout in seconds
+ */
+ const DEFAULT_REQUEST_TIMEOUT = 300;
+
+ /**
+ * @var bool|array|resource Whether verbose mode is enabled
+ *
+ * - true - Use STDERR
+ * - array - output/error streams (different)
+ * - resource - output/error stream (same)
+ */
+ protected static $staticVerbose = false;
+
+ /**
+ * @var bool|resource Whether debug mode is enabled
+ */
+ protected static $staticDebug = false;
+
+ /**
+ * @var \Akamai\Open\EdgeGrid\Authentication
+ */
+ protected $authentication;
+
+ /**
+ * @var \Akamai\Open\EdgeGrid\Handler\Verbose
+ */
+ protected $verboseHandler;
+
+ /**
+ * @var \Akamai\Open\EdgeGrid\Handler\Debug
+ */
+ protected $debugHandler;
+
+ /**
+ * @var bool|array|resource Whether verbose mode is enabled
+ *
+ * - true - Use STDOUT
+ * - array - output/error streams (different)
+ * - resource - output/error stream (same)
+ */
+ protected $verbose = false;
+
+ /**
+ * @var bool|resource Whether debugging is enabled
+ */
+ protected $debug = false;
+
+ /**
+ * @var bool Whether to override the static verbose setting
+ */
+ protected $verboseOverride = false;
+
+ /**
+ * @var bool Whether to override the static debug setting
+ */
+ protected $debugOverride = false;
+
+ /**
+ * @var \Closure Logging Handler
+ */
+ protected $logger;
+
+ /**
+ * \GuzzleHttp\Client-compatible constructor
+ *
+ * @param array $config Config options array
+ * @param Authentication|null $authentication
+ */
+ public function __construct(
+ $config = [],
+ Authentication $authentication = null
+ ) {
+ $config = $this->setAuthenticationHandler($config, $authentication);
+ $config = $this->setBasicOptions($config);
+ $config['headers']['User-Agent'] = 'Akamai-Open-Edgegrid-PHP/' .
+ self::VERSION . ' ' . \GuzzleHttp\default_user_agent();
+
+ parent::__construct($config);
+ }
+
+ /**
+ * Make an Asynchronous request
+ *
+ * @param string $method
+ * @param string $uri
+ * @param array $options
+ * @return \GuzzleHttp\Promise\PromiseInterface
+ * @throws \GuzzleHttp\Exception\GuzzleException
+ */
+ public function requestAsync($method, $uri = null, array $options = [])
+ {
+ $options = $this->setRequestOptions($options);
+
+ $query = parse_url($uri, PHP_URL_QUERY);
+ if (!empty($query)) {
+ $uri = substr($uri, 0, ((strlen($query)+1)) * -1);
+ parse_str($query, $options['query']);
+ }
+
+ return parent::requestAsync($method, $uri, $options);
+ }
+
+ public function sendAsync(\Psr\Http\Message\RequestInterface $request, array $options = [])
+ {
+ $options = $this->setRequestOptions($options);
+
+ return parent::sendAsync($request, $options);
+ }
+
+
+ /**
+ * Set Akamai {OPEN} Authentication Credentials
+ *
+ * @param string $client_token
+ * @param string $client_secret
+ * @param string $access_token
+ * @return $this
+ */
+ public function setAuth($client_token, $client_secret, $access_token)
+ {
+ $this->authentication->setAuth($client_token, $client_secret, $access_token);
+
+ return $this;
+ }
+
+ /**
+ * Specify the headers to include when signing the request
+ *
+ * This is specified by the API, currently no APIs use this
+ * feature.
+ *
+ * @param array $headers
+ * @return $this
+ */
+ public function setHeadersToSign(array $headers)
+ {
+ $this->authentication->setHeadersToSign($headers);
+
+ return $this;
+ }
+
+ /**
+ * Set the max body size
+ *
+ * @param int $max_body_size
+ * @return $this
+ */
+ public function setMaxBodySize($max_body_size)
+ {
+ $this->authentication->setMaxBodySize($max_body_size);
+
+ return $this;
+ }
+
+ /**
+ * Set Request Host
+ *
+ * @param string $host
+ * @return $this
+ */
+ public function setHost($host)
+ {
+ if (substr($host, -1) == '/') {
+ $host = substr($host, 0, -1);
+ }
+
+ $headers = $this->getConfig('headers');
+ $headers['Host'] = $host;
+ $this->setConfigOption('headers', $headers);
+
+ if (strpos('/', $host) === false) {
+ $host = 'https://' . $host;
+ }
+ $this->setConfigOption('base_uri', $host);
+
+ return $this;
+ }
+
+ /**
+ * Set the HTTP request timeout
+ *
+ * @param int $timeout_in_seconds
+ * @return $this
+ */
+ public function setTimeout($timeout_in_seconds)
+ {
+ $this->setConfigOption('timeout', $timeout_in_seconds);
+
+ return $this;
+ }
+
+ /**
+ * Print formatted JSON responses to output
+ *
+ * @param bool|resource $enable
+ * @return $this
+ */
+ public function setInstanceVerbose($enable)
+ {
+ $this->verboseOverride = true;
+ $this->verbose = $enable;
+ return $this;
+ }
+
+ /**
+ * Print HTTP requests/responses to output
+ *
+ * @param bool|resource $enable
+ * @return $this
+ */
+ public function setInstanceDebug($enable)
+ {
+ $this->debugOverride = true;
+ $this->debug = $enable;
+ return $this;
+ }
+
+ /**
+ * Set a PSR-3 compatible logger (or use monolog by default)
+ *
+ * @param \Psr\Log\LoggerInterface $logger
+ * @param string $messageFormat Message format
+ * @return $this
+ */
+ public function setLogger(
+ \Psr\Log\LoggerInterface $logger = null,
+ $messageFormat = \GuzzleHttp\MessageFormatter::CLF
+ ) {
+ if ($logger === null) {
+ $handler = new \Monolog\Handler\ErrorLogHandler(\Monolog\Handler\ErrorLogHandler::SAPI);
+ $handler->setFormatter(new \Monolog\Formatter\LineFormatter("%message%"));
+ $logger = new \Monolog\Logger('HTTP Log', [$handler]);
+ }
+
+ $formatter = new \GuzzleHttp\MessageFormatter($messageFormat);
+
+ $handler = \GuzzleHttp\Middleware::log($logger, $formatter);
+ $this->logger = $handler;
+
+ $handlerStack = $this->getConfig('handler');
+ $this->setLogHandler($handlerStack, $handler);
+
+ return $this;
+ }
+
+ /**
+ * Add logger using a given filename/format
+ *
+ * @param string $filename
+ * @param string $format
+ */
+ public function setSimpleLog($filename, $format = "{code}")
+ {
+ if ($this->logger && !($this->logger instanceof \Monolog\Logger)) {
+ return false;
+ }
+
+ $handler = new \Monolog\Handler\StreamHandler($filename);
+ $handler->setFormatter(new \Monolog\Formatter\LineFormatter("%message%"));
+ $log = new \Monolog\Logger('HTTP Log', [$handler]);
+
+ return $this->setLogger($log, $format);
+ }
+
+ /**
+ * Factory method to create a client using credentials from `.edgerc`
+ *
+ * Automatically checks your HOME directory, and the current working
+ * directory for credentials, if no path is supplied.
+ *
+ * @param string $section Credential section to use
+ * @param string $path Path to .edgerc credentials file
+ * @param array $config Options to pass to the constructor/guzzle
+ * @return \Akamai\Open\EdgeGrid\Client
+ */
+ public static function createFromEdgeRcFile($section = 'default', $path = null, $config = [])
+ {
+ $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile($section, $path);
+
+ if ($host = $auth->getHost()) {
+ $config['base_uri'] = 'https://' . $host;
+ }
+
+ $client = new static($config, $auth);
+ return $client;
+ }
+
+ /**
+ * Print HTTP requests/responses to STDOUT
+ *
+ * @param bool|resource $enable
+ */
+ public static function setDebug($enable)
+ {
+ self::$staticDebug = $enable;
+ }
+
+ /**
+ * Print formatted JSON responses to STDOUT
+ *
+ * @param bool|resource $enable
+ */
+ public static function setVerbose($enable)
+ {
+ self::$staticVerbose = $enable;
+ }
+
+ /**
+ * Handle debug option
+ *
+ * @return bool|resource
+ */
+ protected function getDebugOption($config)
+ {
+ if (isset($config['debug'])) {
+ return ($config['debug'] === true) ? fopen('php://stderr', 'a') : $config['debug'];
+ }
+
+ if (($this->debugOverride && $this->debug)) {
+ return ($this->debug === true) ? fopen('php://stderr', 'a') : $this->debug;
+ } elseif ((!$this->debugOverride && static::$staticDebug)) {
+ return (static::$staticDebug === true) ? fopen('php://stderr', 'a') : static::$staticDebug;
+ }
+
+ return false;
+ }
+
+ /**
+ * Debugging status for the current request
+ *
+ * @return bool|resource
+ */
+ protected function isDebug()
+ {
+ if (($this->debugOverride && !$this->debug) || (!($this->debugOverride) && !static::$staticDebug)) {
+ return false;
+ }
+
+ if ($this->debugOverride && $this->debug) {
+ return $this->debug;
+ }
+
+ return static::$staticDebug;
+ }
+
+ /**
+ * Verbose status for the current request
+ *
+ * @return array|bool|resource
+ */
+ protected function isVerbose()
+ {
+ if (($this->verboseOverride && !$this->verbose) || (!($this->verboseOverride) && !static::$staticVerbose)) {
+ return false;
+ }
+
+ if ($this->verboseOverride && $this->verbose) {
+ return $this->verbose;
+ }
+
+ return static::$staticVerbose;
+ }
+
+ /**
+ * Set the Authentication instance
+ *
+ * @param Authentication|null $authentication
+ */
+ protected function setAuthentication(array $config, Authentication $authentication = null)
+ {
+ $this->authentication = $authentication;
+ if ($authentication === null) {
+ $this->authentication = new Authentication();
+ }
+
+ if (isset($config['timestamp'])) {
+ $this->authentication->setTimestamp($config['timestamp']);
+ }
+
+ if (isset($config['nonce'])) {
+ $this->authentication->setNonce($config['nonce']);
+ }
+ }
+
+ /**
+ * Set the Authentication Handler
+ *
+ * @param array $config
+ * @param Authentication|null $authentication
+ * @return array
+ */
+ protected function setAuthenticationHandler($config, Authentication $authentication = null)
+ {
+ $this->setAuthentication($config, $authentication);
+
+ $authenticationHandler = new AuthenticationHandler();
+ $authenticationHandler->setSigner($this->authentication);
+ if (!isset($config['handler'])) {
+ $config['handler'] = \GuzzleHttp\HandlerStack::create();
+ }
+ try {
+ if (!($config['handler'] instanceof \GuzzleHttp\HandlerStack)) {
+ $config['handler'] = \GuzzleHttp\HandlerStack::create($config['handler']);
+ }
+ $config['handler']->before("history", $authenticationHandler, 'authentication');
+ } catch (\InvalidArgumentException $e) {
+ // history middleware not added yet
+ $config['handler']->push($authenticationHandler, 'authentication');
+ }
+ return $config;
+ }
+
+ /**
+ * @param $config
+ * @return mixed
+ */
+ protected function setBasicOptions($config)
+ {
+ if (!isset($config['timeout'])) {
+ $config['timeout'] = static::DEFAULT_REQUEST_TIMEOUT;
+ }
+
+ if (isset($config['base_uri']) && strpos($config['base_uri'], 'http') === false) {
+ $config['base_uri'] = 'https://' . $config['base_uri'];
+ return $config;
+ }
+ return $config;
+ }
+
+ /**
+ * Set values on the private \GuzzleHttp\Client->config
+ *
+ * This is a terrible hack, and illustrates why making
+ * anything private makes it difficult to extend, and impossible
+ * when there is no setter.
+ *
+ * @param string $what Config option to set
+ * @param mixed $value Value to set the option to
+ * @return void
+ */
+ protected function setConfigOption($what, $value)
+ {
+ $closure = function () use ($what, $value) {
+ /* @var $this \GuzzleHttp\Client */
+ $this->config[$what] = $value;
+ };
+
+ $closure = $closure->bindTo($this, \GuzzleHttp\Client::CLASS);
+ $closure();
+ }
+
+ /**
+ * Add the Debug handler to the HandlerStack
+ *
+ * @param array $options Guzzle Options
+ * @param bool|resource|null $fp Stream to write to
+ * @return array
+ */
+ protected function setDebugHandler($options, $fp = null)
+ {
+ try {
+ if (is_bool($fp)) {
+ $fp = null;
+ }
+
+ $handler = $this->getConfig('handler');
+ // if we have a default handler, and we've already created a DebugHandler
+ // we can bail out now (or we will add another one to the stack)
+ if ($handler && $this->debugHandler) {
+ return $options;
+ }
+
+ if (isset($options['handler'])) {
+ $handler = $options['handler'];
+ }
+
+ if ($handler === null) {
+ $handler = \GuzzleHttp\HandlerStack::create();
+ }
+
+ if (!$this->debugHandler) {
+ $this->debugHandler = new DebugHandler($fp);
+ }
+
+ $handler->after("allow_redirects", $this->debugHandler, "debug");
+ } catch (\InvalidArgumentException $e) {
+ $handler->push($this->debugHandler, "debug");
+ }
+
+ $options['handler'] = $handler;
+
+ return $options;
+ }
+
+ /**
+ * Add the Log handler to the HandlerStack
+ *
+ * @param \GuzzleHttp\HandlerStack $handlerStack
+ * @param callable $logHandler
+ */
+ protected function setLogHandler(\GuzzleHttp\HandlerStack $handlerStack, callable $logHandler)
+ {
+ try {
+ $handlerStack->after("history", $logHandler, "logger");
+ } catch (\InvalidArgumentException $e) {
+ try {
+ $handlerStack->before("allow_redirects", $logHandler, "logger");
+ } catch (\InvalidArgumentException $e) {
+ $handlerStack->push($logHandler, "logger");
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add the Verbose handler to the HandlerStack
+ *
+ * @param array $options Guzzle Options
+ * @param bool|resource|array|null $fp Stream to write to
+ * @return array
+ */
+ protected function setVerboseHandler($options, $fp = null)
+ {
+ try {
+ if (is_bool($fp) || $fp === null) {
+ $fp = ['outputStream' => null, 'errorStream' => null];
+ } elseif (!is_array($fp)) {
+ $fp = ['outputStream' => $fp, 'errorStream' => $fp];
+ }
+
+ $handler = $this->getConfig('handler');
+ // if we have a default handler, and we've already created a VerboseHandler
+ // we can bail out now (or we will add another one to the stack)
+ if ($handler && $this->verboseHandler) {
+ return $options;
+ }
+
+ if (isset($options['handler'])) {
+ $handler = $options['handler'];
+ }
+
+ if ($handler === null) {
+ $handler = \GuzzleHttp\HandlerStack::create();
+ }
+
+ if (!$this->verboseHandler) {
+ $this->verboseHandler = new VerboseHandler(array_shift($fp), array_shift($fp));
+ }
+
+ $handler->after("allow_redirects", $this->verboseHandler, "verbose");
+ } catch (\InvalidArgumentException $e) {
+ $handler->push($this->verboseHandler, "verbose");
+ }
+
+ $options['handler'] = $handler;
+
+ return $options;
+ }
+
+ /**
+ * @param array $options
+ * @return array
+ */
+ protected function setRequestOptions(array $options)
+ {
+ if (isset($options['timestamp'])) {
+ $this->authentication->setTimestamp($options['timestamp']);
+ } elseif (!$this->getConfig('timestamp')) {
+ $this->authentication->setTimestamp();
+ }
+
+ if (isset($options['nonce'])) {
+ $this->authentication->setNonce($options['nonce']);
+ }
+
+ if (isset($options['handler'])) {
+ $options = $this->setAuthenticationHandler($options, $this->authentication);
+ }
+
+ if ($fp = $this->isVerbose()) {
+ $options = $this->setVerboseHandler($options, $fp);
+ }
+
+ $options['debug'] = $this->getDebugOption($options);
+ if ($fp = $this->isDebug()) {
+ $options = $this->setDebugHandler($options, $fp);
+ }
+
+ if ($this->logger && isset($options['handler'])) {
+ $this->setLogHandler($options['handler'], $this->logger);
+ return $options;
+ }
+
+ return $options;
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Exception.php b/akamai/vendor/akamai-open/edgegrid-client/src/Exception.php
new file mode 100644
index 00000000..b7fd0327
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Exception.php
@@ -0,0 +1,21 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+
+namespace Akamai\Open\EdgeGrid;
+
+class Exception extends \Exception
+{
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Exception/ConfigException.php b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/ConfigException.php
new file mode 100644
index 00000000..13ecbea7
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/ConfigException.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+
+namespace Akamai\Open\EdgeGrid\Exception;
+
+use Akamai\Open\EdgeGrid\Exception;
+
+class ConfigException extends Exception
+{
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Exception/HandlerException.php b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/HandlerException.php
new file mode 100644
index 00000000..a1eb9f6a
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/HandlerException.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+
+namespace Akamai\Open\EdgeGrid\Exception;
+
+use Akamai\Open\EdgeGrid\Exception;
+
+class HandlerException extends Exception
+{
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Exception/HandlerException/IOException.php b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/HandlerException/IOException.php
new file mode 100644
index 00000000..37c92408
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/HandlerException/IOException.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+
+namespace Akamai\Open\EdgeGrid\Exception\HandlerException;
+
+use Akamai\Open\EdgeGrid\Exception\HandlerException;
+
+class IOException extends HandlerException
+{
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Exception/SignerException.php b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/SignerException.php
new file mode 100644
index 00000000..67bca691
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/SignerException.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+
+namespace Akamai\Open\EdgeGrid\Exception;
+
+use Akamai\Open\EdgeGrid\Exception;
+
+class SignerException extends Exception
+{
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Exception/SignerException/InvalidSignDataException.php b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/SignerException/InvalidSignDataException.php
new file mode 100644
index 00000000..07ca6f22
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Exception/SignerException/InvalidSignDataException.php
@@ -0,0 +1,23 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+
+namespace Akamai\Open\EdgeGrid\Exception\SignerException;
+
+use Akamai\Open\EdgeGrid\Exception\SignerException;
+
+class InvalidSignDataException extends SignerException
+{
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Authentication.php b/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Authentication.php
new file mode 100644
index 00000000..38ffebc8
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Authentication.php
@@ -0,0 +1,117 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid\Handler;
+
+use Akamai\Open\EdgeGrid\Authentication as Signer;
+use Akamai\Open\EdgeGrid\Exception\HandlerException;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Akamai {OPEN} EdgeGrid Auth Guzzle Middleware Handler
+ *
+ * @package Akamai {OPEN} EdgeGrid Auth
+ *
+ * @method $this createAuthHeader()
+ * @method $this setHttpMethod($method)
+ * @method $this getHost()
+ * @method $this setHost($host)
+ * @method $this setConfig(array $config)
+ * @method $this setQuery($query, $ensure_encoding = true)
+ * @method $this setBody($body)
+ * @method $this setHeaders(array $headers) *
+ * @method $this setPath($path)
+ * @method $this setTimestamp($timestamp = null)
+ * @method $this setNonce($nonce = null)
+ * @method $this setHeadersToSign($headers_to_sign)
+ * @method $this setMaxBodySize($max_body_size)
+ * @method $this setAuth($client_token, $client_secret, $access_token)
+ */
+class Authentication
+{
+ /**
+ * @var \Akamai\Open\EdgeGrid\Authentication
+ */
+ protected $signer;
+
+ public function setSigner(\Akamai\Open\EdgeGrid\Authentication $auth = null)
+ {
+ $this->signer = $auth;
+ if ($this->signer === null) {
+ $this->signer = new Signer();
+ }
+ }
+
+ public function __invoke(callable $handler)
+ {
+ return function (
+ RequestInterface $request,
+ array $config
+ ) use ($handler) {
+ if ($request->getUri()->getScheme() !== 'https' ||
+ strpos($request->getUri()->getHost(), 'akamaiapis.net') === false
+ ) {
+ return $handler($request, $config);
+ }
+
+ if (!$this->signer) {
+ throw new HandlerException("Signer not set, make sure to call setSigner first");
+ }
+
+ $request->getBody()->rewind();
+
+ $this->signer->setHttpMethod($request->getMethod())
+ ->setHost($request->getUri()->getHost())
+ ->setPath($request->getUri()->getPath())
+ ->setQuery($request->getUri()->getQuery())
+ ->setHeaders($request->getHeaders())
+ ->setBody($request->getBody()->getContents());
+
+ $request = $request->withHeader('Authorization', $this->signer->createAuthHeader());
+
+ return $handler($request, $config);
+ };
+ }
+
+ /**
+ * Proxy to the underlying signer object
+ *
+ * @param $method
+ * @param $args
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ if (!isset($this->signer)) {
+ throw new HandlerException("Signer not set, make sure to call setSigner first");
+ }
+
+ $return = call_user_func_array([$this->signer, $method], $args);
+ if ($return == $this->signer) {
+ return $this;
+ }
+
+ return $return;
+ }
+
+ public static function createFromEdgeRcFile($section = "default", $file = null)
+ {
+ $signer = Signer::createFromEdgeRcFile($section, $file);
+ $auth = new static();
+ $auth->setSigner($signer);
+
+ return $auth;
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Debug.php b/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Debug.php
new file mode 100644
index 00000000..e0bc92b8
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Debug.php
@@ -0,0 +1,143 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid\Handler;
+
+use Akamai\Open\EdgeGrid\Exception\HandlerException\IOException;
+
+/**
+ * Debug Response Guzzle Middleware Handler
+ *
+ * @package Akamai {OPEN} EdgeGrid Auth
+ */
+class Debug
+{
+ protected static $messages = [
+ 403 => [
+ "This indicates a problem with authorization.\n",
+ "Please ensure that the credentials you created for this script\n",
+ "have the necessary permissions in the Luna portal.\n",
+ ],
+ 400 => [
+ "This indicates a problem with authentication or headers.",
+ "Please ensure that the .edgerc file is formatted correctly.",
+ "If you still have issues, please use gen_edgerc.php to generate the credentials",
+ ],
+ 401 => 400,
+ 404 => [
+ "This means that the page does not exist as requested.\n",
+ "Please ensure that the URL you're calling is correctly formatted\n",
+ "or look at other examples to make sure yours matches.\n",
+ ]
+ ];
+
+ protected $fp;
+
+ public function __construct($resource = null)
+ {
+ $fp = $resource;
+
+ if (!is_resource($fp) && $fp !== null) {
+ $fp = @fopen($fp, 'a+');
+ if (!$fp) {
+ throw new IOException("Unable to use resource: " . (string) $resource);
+ }
+ }
+
+ if ($fp === null) {
+ $fp = fopen('php://stderr', 'a');
+ }
+
+ $this->fp = $fp;
+ }
+
+ /**
+ * Handle the request/response
+ *
+ * @param callable $handler
+ * @return \Closure
+ */
+ public function __invoke(callable $handler)
+ {
+ $colors = [
+ 'red' => "",
+ 'yellow' => "",
+ 'cyan' => "",
+ 'reset' => "",
+ ];
+
+ if (PHP_SAPI == 'cli') {
+ $colors = [
+ 'red' => "\x1b[31;01m",
+ 'yellow' => "\x1b[33;01m",
+ 'cyan' => "\x1b[36;01m",
+ 'reset' => "\x1b[39;49;00m",
+ ];
+ }
+
+ return function (\Psr\Http\Message\RequestInterface $request, array $config) use ($handler, $colors) {
+ return $handler($request, $config)->then(
+ function (\Psr\Http\Message\ResponseInterface $response) use ($colors, $request) {
+ $statusCode = $response->getStatusCode();
+ if ($statusCode > 399 && $statusCode < 600) {
+ $body = trim($response->getBody());
+ $result = json_decode($body);
+ if ($result !== null) {
+ if (isset($result->detail)) {
+ $detail = $result->detail;
+ } else {
+ $detail = json_encode($result, JSON_PRETTY_PRINT);
+ }
+ } else {
+ $detail = (!empty(trim($body))) ? $body : "No response body returned";
+ }
+
+ $out = [];
+ $out[] = "{$colors['red']}===> [ERROR] Call to %s failed with a %s result";
+
+ if (isset(self::$messages[$statusCode])) {
+ $message = self::$messages[$statusCode];
+ if (is_int($message) && isset(self::$messages[$message])) {
+ $message = self::$messages[$message];
+ }
+
+ foreach ($message as $line) {
+ $out[] = "===> [ERROR] " . $line;
+ }
+ }
+
+ $out[] = "===> [ERROR] Problem details:";
+ $out[] = $detail;
+
+ $out = sprintf(
+ implode("\n", $out),
+ $request->getUri()->getPath(),
+ $response->getStatusCode() . ' ' . $response->getReasonPhrase(),
+ $detail
+ );
+
+ fputs($this->fp, $out);
+ fputs($this->fp, "{$colors['reset']}\n");
+ }
+
+ return $response;
+ },
+ function (\Exception $reason) {
+ return new \GuzzleHttp\Promise\RejectedPromise($reason);
+ }
+ );
+ };
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Verbose.php b/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Verbose.php
new file mode 100644
index 00000000..3d2d33ac
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/src/Handler/Verbose.php
@@ -0,0 +1,177 @@
+
+ * @copyright Copyright 2015 Akamai Technologies, Inc. All rights reserved.
+ * @license Apache 2.0
+ * @link https://github.com/akamai-open/edgegrid-auth-php
+ * @link https://developer.akamai.com
+ * @link https://developer.akamai.com/introduction/Client_Auth.html
+ */
+namespace Akamai\Open\EdgeGrid\Handler;
+
+use Akamai\Open\EdgeGrid\Exception\HandlerException\IOException;
+
+/**
+ * Verbose Response Guzzle Middleware Handler
+ *
+ * @package Akamai {OPEN} EdgeGrid Auth
+ */
+class Verbose
+{
+ protected $outputStream;
+
+ protected $errorStream;
+
+ public function __construct($outputStream = null, $errorStream = null)
+ {
+ $errorStreamException = null;
+ if (!is_resource($errorStream) && $errorStream !== null) {
+ $fp = @fopen($errorStream, 'a+');
+ if (!$fp) {
+ $errorStreamException = new IOException("Unable to use error stream: " . (string) $errorStream);
+ }
+ $errorStream = $fp;
+ }
+
+ if (!is_resource($outputStream) && $outputStream !== null) {
+ $fp = @fopen($outputStream, 'a+');
+ if (!$fp) {
+ throw new IOException("Unable to use output stream: " . (string) $outputStream);
+ }
+ $outputStream = $fp;
+ }
+
+ if ($errorStreamException instanceof \Exception) {
+ throw $errorStreamException;
+ }
+
+ if ($outputStream !== null && $errorStream === null) {
+ $errorStream = $outputStream;
+ }
+
+ if ($outputStream === null && $errorStream === null) {
+ $errorStream = fopen('php://stderr', 'a');
+ }
+
+ if ($outputStream === null) {
+ $outputStream = fopen('php://output', 'a');
+ }
+
+ $this->outputStream = $outputStream;
+ $this->errorStream = $errorStream;
+ }
+
+ /**
+ * Handle the request/response
+ *
+ * @param callable $handler
+ * @return \Closure
+ */
+ public function __invoke(callable $handler)
+ {
+ $colors = [
+ 'red' => "",
+ 'yellow' => "",
+ 'cyan' => "",
+ 'reset' => "",
+ ];
+
+ if (PHP_SAPI == 'cli') {
+ $colors = [
+ 'red' => "\x1b[31;01m",
+ 'yellow' => "\x1b[33;01m",
+ 'cyan' => "\x1b[36;01m",
+ 'reset' => "\x1b[39;49;00m",
+ ];
+ }
+
+ return function (
+ \Psr\Http\Message\RequestInterface $request,
+ array $config
+ ) use (
+ $handler,
+ $colors
+ ) {
+ fputs($this->outputStream, "{$colors['cyan']}===> [VERBOSE] Request: \n");
+ fputs($this->outputStream, "{$colors['yellow']}" . $this->getBody($request));
+ fputs($this->outputStream, "{$colors['reset']}\n");
+
+ return $handler($request, $config)->then(
+ function (\Psr\Http\Message\ResponseInterface $response) use ($colors) {
+ $statusCode = $response->getStatusCode();
+ if ($statusCode > 299 && $statusCode < 400) {
+ fputs($this->outputStream, "{$colors['cyan']}===> [VERBOSE] Redirected: ");
+ fputs($this->outputStream, $response->getHeader('Location')[0]);
+ fputs($this->outputStream, "{$colors['reset']}\n");
+ } else {
+ $responseBody = $this->getBody($response);
+
+ if ($statusCode > 399 && $statusCode < 600) {
+ fputs($this->errorStream, "{$colors['red']}===> [ERROR] An error occurred: \n");
+ fputs($this->errorStream, "{$colors['yellow']}" . $responseBody);
+ fputs($this->errorStream, "{$colors['reset']}\n");
+ } else {
+ fputs($this->outputStream, "{$colors['cyan']}===> [VERBOSE] Response: \n");
+ fputs($this->outputStream, "{$colors['yellow']}" . $responseBody);
+ fputs($this->outputStream, "{$colors['reset']}\n");
+ }
+ }
+
+ return $response;
+ },
+ function (\Exception $reason) use ($colors) {
+ fputs($this->outputStream, "{$colors['red']}===> [ERROR] An error occurred: \n");
+ fputs($this->outputStream, "{$colors['yellow']}");
+
+ $code = $reason->getCode();
+ if (!empty($code)) {
+ $code .= ': ';
+ }
+
+ $message = $reason->getMessage();
+
+ fputs($this->outputStream, ((!empty($code)) ? $code : "") . $message);
+
+ $response = $reason instanceof \GuzzleHttp\Exception\RequestException
+ ? $reason->getResponse()
+ : false;
+
+ if ($response instanceof \Psr\Http\Message\ResponseInterface) {
+ $body = $response->getBody()->getContents();
+ if (!empty($body)) {
+ fputs($this->outputStream, "\n{$colors['yellow']}" . $body);
+ }
+ }
+
+ fputs($this->outputStream, "{$colors['reset']}\n");
+
+ return new \GuzzleHttp\Promise\RejectedPromise($reason);
+ }
+ );
+ };
+ }
+
+ protected function getBody(\Psr\Http\Message\MessageInterface $message)
+ {
+ $body = trim($message->getBody());
+
+ if ($message->getBody()->getSize() == 0 || empty($body)) {
+ if ($message instanceof \Psr\Http\Message\ResponseInterface) {
+ return "No response body returned";
+ }
+ return "No request body sent";
+ }
+ $result = json_decode($body);
+ if ($result !== null) {
+ return json_encode($result, JSON_PRETTY_PRINT);
+ }
+
+ return $body;
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/Authentication/NonceTest.php b/akamai/vendor/akamai-open/edgegrid-client/tests/Authentication/NonceTest.php
new file mode 100644
index 00000000..bc0485ab
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/Authentication/NonceTest.php
@@ -0,0 +1,52 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Akamai\Open\EdgeGrid\Tests\Client\Authentication;
+
+class NonceTest extends \PHPUnit_Framework_TestCase
+{
+ public function testMakeNonce()
+ {
+ $nonce = new \Akamai\Open\EdgeGrid\Authentication\Nonce();
+
+ $nonces = [];
+ for ($i = 0; $i < 100; $i++) {
+ $nonces[] = (string) $nonce;
+ }
+
+ $this->assertEquals(100, count(array_unique($nonces)));
+ }
+
+ public function testMakeNonceRandomBytes()
+ {
+ if (!function_exists('random_bytes')) {
+ include __DIR__ . '/../random_bytes.php';
+ }
+
+ $nonce = new \Akamai\Open\EdgeGrid\Authentication\Nonce();
+ $closure = function () {
+ return $this->function;
+ };
+ $tester = $closure->bindTo($nonce, $nonce);
+
+ $this->assertEquals('random_bytes', $tester());
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/Authentication/TimestampTest.php b/akamai/vendor/akamai-open/edgegrid-client/tests/Authentication/TimestampTest.php
new file mode 100644
index 00000000..200b9034
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/Authentication/TimestampTest.php
@@ -0,0 +1,45 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Akamai\Open\EdgeGrid\Tests\Client\Authentication;
+
+class TimestampTest extends \PHPUnit_Framework_TestCase
+{
+
+ public function testTimestampFormat()
+ {
+ $timestamp = new \Akamai\Open\EdgeGrid\Authentication\Timestamp();
+
+ $check = \DateTimeImmutable::createFromFormat('Ymd\TH:i:sO', (string) $timestamp, new \DateTimeZone('UTC'));
+ $check = $check->setTimezone(new \DateTimeZone('UTC'));
+ $this->assertEquals($check, \PHPUnit_Framework_Assert::readAttribute($timestamp, 'timestamp'));
+ }
+
+
+ public function testIsValid()
+ {
+ $timestamp = new \Akamai\Open\EdgeGrid\Authentication\Timestamp();
+ $this->assertTrue($timestamp->isValid());
+ $timestamp->setValidFor('PT0S');
+ sleep(1);
+ $this->assertFalse($timestamp->isValid());
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/AuthenticationTest.php b/akamai/vendor/akamai-open/edgegrid-client/tests/AuthenticationTest.php
new file mode 100644
index 00000000..01298ca4
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/AuthenticationTest.php
@@ -0,0 +1,468 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Akamai\Open\EdgeGrid\Tests\Client;
+
+class AuthenticationTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider createAuthHeaderDataProvider
+ */
+ public function testCreateAuthHeader(
+ $auth,
+ $body,
+ $expected,
+ $headers,
+ $headersToSign,
+ $host,
+ $maxBody,
+ $method,
+ $name,
+ $nonce,
+ $path,
+ $query,
+ $timestamp
+ ) {
+ $this->setName($name);
+
+ $mockTimestamp = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Timestamp::CLASS);
+ $mockTimestamp->__toString()->willReturn($timestamp);
+ $mockTimestamp->isValid()->willReturn(true);
+ $mockNonce = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Nonce::CLASS);
+ $mockNonce->__toString()->willReturn($nonce);
+
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setAuth($auth['client_token'], $auth['client_secret'], $auth['access_token']);
+ $authentication->setHttpMethod($method);
+ $authentication->setHeaders($headers);
+ $authentication->setHeadersToSign($headersToSign);
+ $authentication->setQuery($query);
+ $authentication->setPath($path);
+ $authentication->setHost($host);
+ $authentication->setBody($body);
+ $authentication->setMaxBodySize($maxBody);
+ $authentication->setTimestamp($mockTimestamp->reveal());
+ $authentication->setNonce($mockNonce->reveal());
+
+ $result = $authentication->createAuthHeader();
+
+ $this->assertEquals($expected, $result);
+ }
+
+ public function testDefaultTimestamp()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setAuth("test", "test", "test");
+ $authentication->setHttpMethod("GET");
+ $authentication->setPath("/test");
+ $authentication->setHost("https://example.org");
+ $authentication->createAuthHeader();
+
+ $this->assertInstanceOf(
+ \Akamai\Open\EdgeGrid\Authentication\Timestamp::CLASS,
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'timestamp')
+ );
+ }
+
+ public function testDefaultNonce()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setAuth("test", "test", "test");
+ $authentication->setHttpMethod("GET");
+ $authentication->setPath("/test");
+ $authentication->setHost("https://example.org");
+ $authentication->createAuthHeader();
+ $authentication->setNonce();
+
+ $this->assertInstanceOf(
+ \Akamai\Open\EdgeGrid\Authentication\Nonce::CLASS,
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'nonce')
+ );
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\SignerException\InvalidSignDataException
+ * @expectedExceptionMessage Timestamp is invalid. Too old?
+ */
+ public function testTimestampTimeout()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setAuth("test", "test", "test");
+ $authentication->setHttpMethod("GET");
+ $authentication->setPath("/test");
+ $authentication->setHost("https://example.org");
+
+ $timestamp = new \Akamai\Open\EdgeGrid\Authentication\Timestamp();
+ $timestamp->setValidFor('PT0S');
+ $authentication->setTimestamp($timestamp);
+ sleep(1);
+ $authentication->createAuthHeader();
+ }
+
+ public function testSignHeadersArray()
+ {
+ $closure = function () {
+
+ return $this->canonicalizeHeaders();
+ };
+
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setAuth("test", "test", "test");
+ $authentication->setHttpMethod("GET");
+ $authentication->setPath("/test");
+ $authentication->setHost("https://example.org");
+ $authentication->setHeaders([
+ 'X-Test-1' => ["Value1", "value2"]
+ ]);
+
+ $authentication->setHeadersToSign(['X-Test-1']);
+ $tester = $closure->bindTo($authentication, $authentication);
+ $this->assertEquals("x-test-1:Value1", $tester());
+
+ $authentication->setHeaders([
+ 'X-Test-1' => []
+ ]);
+ $authentication->setHeadersToSign(['X-Test-1']);
+ $this->assertEmpty($tester());
+ }
+
+ public function testSetHost()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setHost("example.org");
+ $this->assertEquals(
+ "example.org",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+
+ $this->assertNull(\PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayNotHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setHost("http://example.com");
+ $this->assertEquals(
+ "example.com",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+
+ $this->assertNull(\PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayNotHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ }
+
+ public function testSetHostWithPath()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+
+ $authentication->setHost("example.net/path");
+ $this->assertEquals(
+ "example.net",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/path', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayNotHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+
+ $authentication->setHost("http://example.org/newpath");
+ $this->assertEquals(
+ "example.org",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/newpath', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayNotHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ }
+
+ public function testSetHostWithQuery()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+
+ $authentication->setHost("example.net/path?query=string");
+ $this->assertEquals(
+ "example.net",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/path', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ $this->assertEquals(
+ 'query=string',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'config')['query']
+ );
+
+ $authentication->setHost("http://example.org/newpath?query=newstring");
+ $this->assertEquals(
+ "example.org",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/newpath', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ $this->assertEquals(
+ 'query=newstring',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'config')['query']
+ );
+
+ $authentication->setHost("http://example.org?query=newstring");
+ $this->assertEquals(
+ "example.org",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ $this->assertEquals(
+ 'query=newstring',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'config')['query']
+ );
+
+ $authentication->setHost("http://example.net/?query=string");
+ $this->assertEquals(
+ "example.net",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ $this->assertEquals(
+ 'query=string',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'config')['query']
+ );
+ }
+
+ public function testSetPath()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+
+ $authentication->setPath("/path");
+ $this->assertEmpty(
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/path', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayNotHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setPath("https://example.net/path");
+ $this->assertEquals(
+ "example.net",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/path', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayNotHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setPath("/newpath?query=string");
+ $this->assertEmpty(
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/newpath', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ $this->assertEquals(
+ 'query=string',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'config')['query']
+ );
+
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setPath("https://example.net/path?query=newstring");
+ $this->assertEquals(
+ "example.net",
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals('/path', \PHPUnit_Framework_Assert::readAttribute($authentication, 'path'));
+ $this->assertArrayHasKey('query', \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ $this->assertEquals(
+ 'query=newstring',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'config')['query']
+ );
+ }
+
+ /**
+ * @dataProvider createFromEdgeRcProvider
+ */
+ public function testCreateFromEdgeRcDefault($section, $file)
+ {
+ $_SERVER['HOME'] = __DIR__ . '/edgerc';
+ $authentication = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile($section, $file);
+
+ $this->assertInstanceOf(\Akamai\Open\EdgeGrid\Authentication::CLASS, $authentication);
+ $this->assertEquals(
+ [
+ 'client_token' => "akab-client-token-xxx-xxxxxxxxxxxxxxxx",
+ 'client_secret' => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
+ 'access_token' => "akab-access-token-xxx-xxxxxxxxxxxxxxxx"
+ ],
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'auth')
+ );
+ $this->assertEquals(
+ 'akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals(2048, \PHPUnit_Framework_Assert::readAttribute($authentication, 'max_body_size'));
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\ConfigException
+ * @expectedExceptionMessage Section "default" does not exist!
+ */
+ public function testCreateFromEdgeRcUseCwd()
+ {
+ $_SERVER['HOME'] = "/non-existant";
+ $unlink = false;
+ if (!file_exists('./.edgerc')) {
+ touch('./.edgerc');
+ $unlink = true;
+ }
+
+ try {
+ $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile();
+ $this->assertInstanceOf(\Akamai\Open\EdgeGrid\Authentication::CLASS, $auth);
+ } finally {
+ if ($unlink) {
+ unlink('./.edgerc');
+ }
+ }
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\ConfigException
+ * @expectedExceptionMessage Path to .edgerc file "/non-existant/.edgerc" does not exist!
+ */
+ public function testCreateFromEdgeRcNonExistant()
+ {
+ $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile(null, "/non-existant/.edgerc");
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\ConfigException
+ * @expectedExceptionMessage Unable to read .edgerc file!
+ */
+ public function testCreateFromEdgeRcNonReadable()
+ {
+ $filename = tempnam(sys_get_temp_dir(), '.');
+ touch(tempnam(sys_get_temp_dir(), '.'));
+ chmod($filename, 0000);
+
+ try {
+ $auth = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile(null, $filename);
+ } finally {
+ chmod($filename, 0777);
+ unlink($filename);
+ }
+ }
+
+ public function testCreateFromEdgeRcColons()
+ {
+ $file = __DIR__ . '/edgerc/.edgerc.invalid';
+ $authentication = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile(null, $file);
+
+ $this->assertInstanceOf(\Akamai\Open\EdgeGrid\Authentication::CLASS, $authentication);
+ $this->assertEquals(
+ [
+ 'client_token' => "akab-client-token-xxx-xxxxxxxxxxxxxxxx",
+ 'client_secret' => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
+ 'access_token' => "akab-access-token-xxx-xxxxxxxxxxxxxxxx"
+ ],
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'auth')
+ );
+ $this->assertEquals(
+ 'akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals(2048, \PHPUnit_Framework_Assert::readAttribute($authentication, 'max_body_size'));
+ }
+
+ public function testCreateFromEdgeRcColonsWithSpaces()
+ {
+ $file = __DIR__ . '/edgerc/.edgerc.invalid-spaces';
+ $authentication = \Akamai\Open\EdgeGrid\Authentication::createFromEdgeRcFile(null, $file);
+
+ $this->assertInstanceOf(\Akamai\Open\EdgeGrid\Authentication::CLASS, $authentication);
+ $this->assertEquals(
+ [
+ 'client_token' => "akab-client-token-xxx-xxxxxxxxxxxxxxxx",
+ 'client_secret' => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
+ 'access_token' => "akab-access-token-xxx-xxxxxxxxxxxxxxxx"
+ ],
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'auth')
+ );
+ $this->assertEquals(
+ 'akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net',
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'host')
+ );
+ $this->assertEquals(2048, \PHPUnit_Framework_Assert::readAttribute($authentication, 'max_body_size'));
+ }
+
+ public function testSetConfig()
+ {
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+
+ $config = ['test' => 'value'];
+ $authentication->setConfig($config);
+
+ $this->assertEquals($config, \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+
+ $authentication = new \Akamai\Open\EdgeGrid\Authentication();
+ $authentication->setQuery('query=string');
+ $authentication->setConfig($config);
+
+ $config['query'] = 'query=string';
+ $this->assertEquals($config, \PHPUnit_Framework_Assert::readAttribute($authentication, 'config'));
+ }
+
+ public function createFromEdgeRcProvider()
+ {
+ $clientTest = new \Akamai\Open\EdgeGrid\Tests\ClientTest();
+ return $clientTest->createFromEdgeRcProvider();
+ }
+
+ public function createAuthHeaderDataProvider()
+ {
+ $testdata = json_decode(file_get_contents(__DIR__ . '/testdata.json'), true);
+
+ $defaults = [
+ 'auth' => [
+ 'client_token' => $testdata['client_token'],
+ 'client_secret' => $testdata['client_secret'],
+ 'access_token' => $testdata['access_token'],
+ ],
+ 'host' => parse_url($testdata['base_url'], PHP_URL_HOST),
+ 'headersToSign' => $testdata['headers_to_sign'],
+ 'nonce' => $testdata['nonce'],
+ 'timestamp' => $testdata['timestamp'],
+ 'maxBody' => $testdata['max_body'],
+ ];
+
+ foreach ($testdata['tests'] as $test) {
+ $data = array_merge($defaults, [
+ 'method' => $test['request']['method'],
+ 'path' => $test['request']['path'],
+ 'expected' => $test['expectedAuthorization'],
+ 'query' => (isset($test['request']['query'])) ? $test['request']['query'] : null,
+ 'body' => (isset($test['request']['data'])) ? $test['request']['data'] : null,
+ 'name' => $test['testName'],
+ ]);
+
+ $data['headers'] = [];
+ if (isset($test['request']['headers'])) {
+ array_walk_recursive($test['request']['headers'], function ($value, $key) use (&$data) {
+ $data['headers'][$key] = $value;
+ });
+ }
+
+ ksort($data);
+
+ yield $data;
+ }
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/ClientTest.php b/akamai/vendor/akamai-open/edgegrid-client/tests/ClientTest.php
new file mode 100644
index 00000000..a58b1533
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/ClientTest.php
@@ -0,0 +1,657 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Akamai\Open\EdgeGrid\Tests;
+
+use Akamai\Open\EdgeGrid\Client;
+use GuzzleHttp\Handler\MockHandler;
+use GuzzleHttp\HandlerStack;
+use GuzzleHttp\Middleware;
+use GuzzleHttp\Psr7\Response;
+
+/**
+ * Test for Akamai\Open\EdgeGrid\Client
+ *
+ * @author Davey Shafik
+ * @since PHP 5.6
+ * @version 1.0
+ */
+class ClientTest extends \PHPUnit_Framework_TestCase
+{
+ public function setUp()
+ {
+ Client::setVerbose(false);
+ Client::setDebug(false);
+ }
+
+ /**
+ * @param $name
+ * @param $options
+ * @param $request
+ * @param $result
+ * @dataProvider makeAuthHeaderProvider
+ */
+ public function testMakeAuthHeader($name, $options, $request, $result)
+ {
+ //$this->setName($name);
+
+ // Mock the response, we don't care about it
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $timestamp = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Timestamp::CLASS);
+ $timestamp->__toString()->willReturn($options['timestamp']);
+ $timestamp->isValid()->willReturn(true);
+ $nonce = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Nonce::CLASS);
+ $nonce->__toString()->willReturn($options['nonce']);
+
+ $client = new Client(
+ array_merge($options, [
+ 'base_uri' => $options['base_url'],
+ 'handler' => $handler,
+ 'timestamp' => $timestamp->reveal(),
+ 'nonce' => $nonce->reveal()
+ ])
+ );
+
+ $client->setAuth($options['client_token'], $options['client_secret'], $options['access_token']);
+ $client->setMaxBodySize($options['max_body']);
+
+ if (isset($options['headers_to_sign'])) {
+ $client->setHeadersToSign($options['headers_to_sign']);
+ }
+
+ $headers = array();
+ if (isset($request['headers'])) {
+ array_walk_recursive($request['headers'], function ($value, $key) use (&$headers) {
+ $headers[$key] = $value;
+ });
+ }
+
+ $client->request(
+ $request['method'],
+ $request['path'],
+ [
+ 'headers' => $headers,
+ 'body' => $request['data'],
+ ]
+ );
+
+ $this->assertEquals(1, sizeof($container));
+ $request = $container[0]['request'];
+ $headers = $request->getHeaders();
+
+ $this->assertArrayHasKey('Authorization', $headers);
+ $this->assertEquals(1, sizeof($headers['Authorization']));
+ $this->assertEquals($result, $headers['Authorization'][0]);
+ }
+
+ /**
+ * @param $name
+ * @param $options
+ * @param $request
+ * @param $result
+ * @dataProvider makeAuthHeaderProvider
+ */
+ public function testMakeAuthHeaderPsr7($name, $options, $request, $result)
+ {
+ //$this->setName($name);
+
+ // Mock the response, we don't care about it
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $timestamp = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Timestamp::CLASS);
+ $timestamp->__toString()->willReturn($options['timestamp']);
+ $timestamp->isValid()->willReturn(true);
+ $nonce = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Nonce::CLASS);
+ $nonce->__toString()->willReturn($options['nonce']);
+
+ $client = new Client(
+ array_merge($options, [
+ 'base_uri' => $options['base_url'],
+ 'handler' => $handler,
+ 'timestamp' => $timestamp->reveal(),
+ 'nonce' => $nonce->reveal()
+ ])
+ );
+
+ $client->setAuth($options['client_token'], $options['client_secret'], $options['access_token']);
+ $client->setMaxBodySize($options['max_body']);
+
+ if (isset($options['headers_to_sign'])) {
+ $client->setHeadersToSign($options['headers_to_sign']);
+ }
+
+ $headers = array();
+ if (isset($request['headers'])) {
+ array_walk_recursive($request['headers'], function ($value, $key) use (&$headers) {
+ $headers[$key] = $value;
+ });
+ }
+
+ $request = new \GuzzleHttp\Psr7\Request(
+ $request['method'],
+ $request['path'],
+ $headers,
+ $request['data']
+ );
+
+ $client->send($request);
+
+ $this->assertEquals(1, sizeof($container));
+ $request = $container[0]['request'];
+ $headers = $request->getHeaders();
+
+ $this->assertArrayHasKey('Authorization', $headers);
+ $this->assertEquals(1, sizeof($headers['Authorization']));
+ $this->assertEquals($result, $headers['Authorization'][0]);
+ }
+
+ /**
+ * @dataProvider createFromEdgeRcProvider
+ */
+ public function testCreateFromEdgeRcDefault($section, $file)
+ {
+ $_SERVER['HOME'] = __DIR__ . '/edgerc';
+ $client = \Akamai\Open\EdgeGrid\Client::createFromEdgeRcFile($section, $file);
+ $authentication = \PHPUnit_Framework_Assert::readAttribute($client, 'authentication');
+
+ $this->assertInstanceOf(\Akamai\Open\EdgeGrid\Client::CLASS, $client);
+ $this->assertEquals(
+ [
+ 'client_token' => "akab-client-token-xxx-xxxxxxxxxxxxxxxx",
+ 'client_secret' => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
+ 'access_token' => "akab-access-token-xxx-xxxxxxxxxxxxxxxx"
+ ],
+ \PHPUnit_Framework_Assert::readAttribute($authentication, 'auth')
+ );
+ $this->assertEquals(
+ 'https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net',
+ $client->getConfig('base_uri')
+ );
+ $this->assertEquals(2048, \PHPUnit_Framework_Assert::readAttribute($authentication, 'max_body_size'));
+ }
+
+ public function testHostnameWithTrailingSlash()
+ {
+ $client = new \Akamai\Open\EdgeGrid\Client();
+ $client->setHost('akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/');
+
+ $this->assertEquals(
+ 'akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net',
+ $client->getConfig('headers')['Host']
+ );
+ }
+
+ public function testDefaultTimeout()
+ {
+ // Mock the response, we don't care about it
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $this->assertArrayHasKey('timeout', $client->getConfig());
+ $this->assertEquals(Client::DEFAULT_REQUEST_TIMEOUT, $client->getConfig('timeout'));
+
+ $client->setAuth('test', 'test', 'test');
+
+ $client->get('/test');
+ $this->assertEquals(Client::DEFAULT_REQUEST_TIMEOUT, $container[0]['options']['timeout']);
+ }
+
+ public function testTimeoutOption()
+ {
+ // Mock the response, we don't care about it
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200), new Response(200)], $container);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ 'timeout' => 2
+ ]
+ );
+
+ $this->assertArrayHasKey('timeout', $client->getConfig());
+ $this->assertEquals(2, $client->getConfig('timeout'));
+
+ $client->setAuth('test', 'test', 'test');
+
+ $client->get('/test');
+ $this->assertEquals(2, end($container)['options']['timeout']);
+
+ $client->get('/test', ['timeout' => 5]);
+ $this->assertEquals(5, end($container)['options']['timeout']);
+ }
+
+ public function testSetTimeout()
+ {
+ // Mock the response, we don't care about it
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200), new Response(200), new Response(200)], $container);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $this->assertArrayHasKey('timeout', $client->getConfig());
+ $this->assertEquals(Client::DEFAULT_REQUEST_TIMEOUT, $client->getConfig('timeout'));
+
+ $client->get('/test', ['timeout' => 2]);
+ $this->assertEquals(2, end($container)['options']['timeout']);
+ $this->assertEquals(Client::DEFAULT_REQUEST_TIMEOUT, $client->getConfig('timeout'));
+
+ $client->setTimeout(5);
+ $client->get('/test');
+
+ $this->assertEquals(5, $client->getConfig('timeout'));
+ $this->assertEquals(5, end($container)['options']['timeout']);
+ }
+
+ public function testStaticDebugSingle()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setDebug(true);
+
+ $client->get('/test');
+ $this->assertEquals(true, is_resource(end($container)['options']['debug']));
+ }
+
+ public function testInstanceDebugSingle()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $client->setInstanceDebug(true);
+ $client->get('/test');
+ $this->assertEquals(true, is_resource(end($container)['options']['debug']));
+ }
+
+ public function testDebugOverrideSingle()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200), new Response(200)], $container);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ Client::setDebug(true);
+ $client->setInstanceDebug(false);
+
+ $client->get('/test');
+ $this->assertEquals(false, is_resource(end($container)['options']['debug']));
+ }
+
+ public function testInstanceDebugOptionSingle()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200), new Response(200), new Response(200)], $container);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $client->get('/test', ['debug' => true]);
+ $this->assertEquals(true, is_resource(end($container)['options']['debug']));
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+ $client->setDebug(true);
+ $client->get('/test', ['debug' => false]);
+ $this->assertEquals(false, is_resource(end($container)['options']['debug']));
+ $this->assertFalse(end($container)['options']['debug']);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+ Client::setDebug(true);
+ $client->get('/test', ['debug' => false]);
+ $this->assertEquals(false, is_resource(end($container)['options']['debug']));
+ $this->assertFalse(end($container)['options']['debug']);
+ }
+
+ public function testNonApiCall()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200), new Response(200), new Response(200)], $container);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $response = $client->get('/test');
+ $this->assertInstanceOf(\GuzzleHttp\Psr7\Response::CLASS, $response);
+ $this->assertEquals('http', end($container)['request']->getUri()->getScheme());
+ $this->assertEquals('example.org', end($container)['request']->getUri()->getHost());
+ $this->assertArrayNotHasKey('Authentication', end($container)['request']->getHeaders());
+
+ $response = $client->get('http://example.com/test');
+ $this->assertInstanceOf(\GuzzleHttp\Psr7\Response::CLASS, $response);
+ $this->assertEquals('http', end($container)['request']->getUri()->getScheme());
+ $this->assertEquals('example.com', end($container)['request']->getUri()->getHost());
+ $this->assertArrayNotHasKey('Authentication', end($container)['request']->getHeaders());
+
+ $response = $client->get('https://example.net/test');
+ $this->assertInstanceOf(\GuzzleHttp\Psr7\Response::CLASS, $response);
+ $this->assertEquals('https', end($container)['request']->getUri()->getScheme());
+ $this->assertEquals('example.net', end($container)['request']->getUri()->getHost());
+ $this->assertArrayNotHasKey('Authentication', end($container)['request']->getHeaders());
+ }
+
+ public function testForceHttps()
+ {
+ $client = new Client(
+ [
+ 'base_uri' => 'example.org'
+ ]
+ );
+
+ $uri = $client->getConfig('base_uri');
+ $this->assertEquals('https', parse_url($uri, PHP_URL_SCHEME));
+ }
+
+ /**
+ * @param $response
+ * @param $path
+ * @param $expected
+ * @dataProvider loggingProvider
+ */
+ public function testLogging($method, $responses, $path, $expected)
+ {
+ $handler = $this->getMockHandler($responses);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $logHandler = $this->setLogger($client);
+
+ try {
+ $client->{$method}($path);
+ } catch (\Exception $e) {
+ }
+
+ $records = [];
+ foreach ($logHandler->getRecords() as $record) {
+ $records[] = $record['message'];
+ }
+ $this->assertEquals($expected, $records);
+ }
+
+ public function testLoggingRedirect()
+ {
+ $handler = $this->getMockHandler([
+ new Response(301, ['Location' => '/redirected']),
+ new Response(200, ['Content-Type' => 'application/json'])
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $logHandler = $this->setLogger($client);
+
+ try {
+ $client->get("/redirect");
+ } catch (\Exception $e) {
+ }
+
+ $records = [];
+ foreach ($logHandler->getRecords() as $record) {
+ $records[] = $record['message'];
+ }
+ $this->assertEquals(["GET /redirect 301 ", "GET /redirected 200 application/json"], $records);
+ }
+
+ public function testLoggingDefault()
+ {
+ $client = new Client();
+ $client->setLogger();
+
+ $logger = \PHPUnit_Framework_Assert::readAttribute($client, 'logger');
+ $this->assertInstanceOf(
+ \Closure::CLASS,
+ $logger
+ );
+
+ $reflection = new \ReflectionFunction($logger);
+ $args = $reflection->getParameters();
+ $this->assertTrue(array_shift($args)->isCallable());
+ }
+
+ public function testLoggingRequestHandler()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, ['Content-Type' => 'application/json'])
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ ]
+ );
+ $logHandler = $this->setLogger($client);
+
+ $client->get("/test", ['handler' => $handler]);
+ $records = [];
+ foreach ($logHandler->getRecords() as $record) {
+ $records[] = $record['message'];
+ }
+ $this->assertEquals(["GET /test 200 application/json"], $records);
+ }
+
+ public function testSetSimpleLog()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, ['Content-Type' => 'application/json'])
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen("php://memory", "w+");
+ $client->setSimpleLog($fp, "{method} {target} {code}");
+ $client->get("/test");
+
+ fseek($fp, 0);
+ $this->assertEquals("GET /test 200", fgets($fp));
+ }
+
+ public function makeAuthHeaderProvider()
+ {
+ $testdata = json_decode(file_get_contents(__DIR__ . '/testdata.json'), true);
+ $tests = $testdata['tests'];
+ unset($testdata['tests']);
+
+ foreach ($tests as $test) {
+ yield [
+ 'name' => $test['testName'],
+ 'options' => array_merge($testdata, $test['request']),
+ 'request' => array_merge(['data' => ""], $test['request']),
+ 'result' => $test['expectedAuthorization'],
+ ];
+ }
+ }
+
+ public function createFromEdgeRcProvider()
+ {
+ return [
+ [
+ 'section' => null,
+ 'file' => null,
+ ],
+ [
+ 'section' => 'default',
+ 'file' => null,
+ ],
+ [
+ 'section' => 'testing',
+ 'file' => __DIR__ . '/edgerc/.edgerc.testing',
+ ],
+ [
+ 'section' => 'testing',
+ 'file' => __DIR__ . '/edgerc/.edgerc.default-testing',
+ ]
+ ];
+ }
+
+ public function loggingProvider()
+ {
+ return [
+ [
+ 'get',
+ [new Response(200)],
+ '/test',
+ [
+ "GET /test 200 "
+ ]
+ ],
+ [
+ 'get',
+ [new Response(404)],
+ '/error',
+ [
+ "GET /error 404 "
+ ]
+ ],
+ [
+ 'post',
+ [new Response(500)],
+ '/error',
+ [
+ "POST /error 500 "
+ ]
+ ],
+ [
+ 'put',
+ [new Response(200, ['Content-Type' => 'application/json'])],
+ '/test',
+ [
+ "PUT /test 200 application/json"
+ ]
+ ],
+ [
+ 'options',
+ [new Response(405, ['Content-Type' => 'application/json'])],
+ '/error',
+ [
+ "OPTIONS /error 405 application/json"
+ ]
+ ],
+ [
+ 'get',
+ [new Response(503, ['Content-Type' => 'text/csv'])],
+ '/error',
+ [
+ "GET /error 503 text/csv"
+ ]
+ ],
+ [
+ 'get',
+ [
+ new Response(301, ['Location' => '/redirect']),
+ new Response(200)
+ ],
+ '/notthere',
+ [
+ "GET /notthere 301 ",
+ "GET /redirect 200 ",
+ ]
+ ]
+ ];
+ }
+
+ public function getMockHandler($requests, array &$container = null)
+ {
+ $mock = new MockHandler($requests);
+ $container = [];
+ $history = Middleware::history($container);
+
+ $handler = HandlerStack::create($mock);
+ $handler->push($history, 'history');
+
+ return $handler;
+ }
+
+ /**
+ * @return Client
+ */
+ protected function setLogger(Client $client)
+ {
+ $handler = new \Monolog\Handler\TestHandler();
+ $logger = new \Monolog\Logger("Test Logger", [$handler]);
+ $client->setLogger($logger, "{method} {target} {code} {res_header_content-type}");
+
+ return $handler;
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/AuthenticationTest.php b/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/AuthenticationTest.php
new file mode 100644
index 00000000..f6eb4bb5
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/AuthenticationTest.php
@@ -0,0 +1,179 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Akamai\Open\EdgeGrid\Tests\Handler;
+
+use GuzzleHttp\Psr7\Response;
+
+class AuthenticationTest extends \Akamai\Open\EdgeGrid\Tests\ClientTest
+{
+ /**
+ * @dataProvider createFromEdgeRcProvider
+ */
+ public function testCreateFromEdgeRc($section, $file)
+ {
+ $_SERVER['HOME'] = __DIR__ . '/../edgerc';
+
+ $guzzle = new \GuzzleHttp\Client();
+ $authentication = \Akamai\Open\EdgeGrid\Handler\Authentication::createFromEdgeRcFile($section, $file);
+ $this->assertInstanceOf(\Akamai\Open\EdgeGrid\Handler\Authentication::CLASS, $authentication);
+ }
+
+ /**
+ * @param $name
+ * @param $options
+ * @param $request
+ * @param $result
+ * @dataProvider makeAuthHeaderProvider
+ */
+ public function testMakeAuthHeader($name, $options, $request, $result)
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $timestamp = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Timestamp::CLASS);
+ $timestamp->__toString()->willReturn($options['timestamp']);
+ $timestamp->isValid()->willReturn(true);
+ $nonce = $this->prophesize(\Akamai\Open\EdgeGrid\Authentication\Nonce::CLASS);
+ $nonce->__toString()->willReturn($options['nonce']);
+
+ $auth = new \Akamai\Open\EdgeGrid\Handler\Authentication();
+ $auth->setSigner();
+ $auth->setAuth($options['client_token'], $options['client_secret'], $options['access_token']);
+ $auth->setMaxBodySize($options['max_body']);
+ $auth->setTimestamp($timestamp->reveal());
+ $auth->setNonce($nonce->reveal());
+
+ if (isset($options['headers_to_sign'])) {
+ $auth->setHeadersToSign($options['headers_to_sign']);
+ }
+
+ // Because of PSR-7 immutability the history handler has
+ // to be the last one, otherwise it doesn't get the latest
+ // instance of the Request.
+ $handler->before('history', $auth, "signer");
+
+ $client = new \GuzzleHttp\Client(
+ array_merge($options, [
+ 'base_uri' => $options['base_url'],
+ 'handler' => $handler,
+ ])
+ );
+
+ $headers = array();
+ if (isset($request['headers'])) {
+ array_walk_recursive($request['headers'], function ($value, $key) use (&$headers) {
+ $headers[$key] = $value;
+ });
+ }
+
+ $client->request(
+ $request['method'],
+ $request['path'],
+ [
+ 'headers' => $headers,
+ 'body' => $request['data'],
+ ]
+ );
+
+ $this->assertEquals(1, sizeof($container));
+ $request = $container[0]['request'];
+ $headers = $request->getHeaders();
+
+ $this->assertArrayHasKey('Authorization', $headers);
+ $this->assertEquals(1, sizeof($headers['Authorization']));
+ $this->assertEquals($result, $headers['Authorization'][0]);
+ }
+
+ public function testHandlerChainingNotAuthenticated()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $auth = new \Akamai\Open\EdgeGrid\Handler\Authentication();
+
+ // Because of PSR-7 immutability the history handler has
+ // to be the last one, otherwise it doesn't get the latest
+ // instance of the Request.
+ $handler->before('history', $auth, "signer");
+
+ $client = new \GuzzleHttp\Client([
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]);
+
+ $client->get('/test');
+
+ $this->assertEquals(1, sizeof($container));
+ $request = $container[0]['request'];
+ $this->assertInstanceOf(\Psr\Http\Message\RequestInterface::CLASS, $request);
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\HandlerException
+ * @expectedExceptionMessage Signer not set, make sure to call setSigner first
+ */
+ public function testRequireSetSignerCall()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $auth = new \Akamai\Open\EdgeGrid\Handler\Authentication();
+
+ // Because of PSR-7 immutability the history handler has
+ // to be the last one, otherwise it doesn't get the latest
+ // instance of the Request.
+ $handler->before('history', $auth, "signer");
+
+ $client = new \GuzzleHttp\Client(
+ [
+ 'handler' => $handler,
+ ]
+ );
+
+ $client->get("https://test-akamaiapis.net");
+ }
+
+ public function testProxyNonFluent()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $auth = new \Akamai\Open\EdgeGrid\Handler\Authentication();
+ $auth->setSigner(new \Akamai\Open\EdgeGrid\Authentication());
+ $auth->setHost('test.host');
+
+ $this->assertEquals('test.host', $auth->getHost());
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Signer not set, make sure to call setSigner first
+ */
+ public function testProxyNoSigner()
+ {
+ $container = [];
+ $handler = $this->getMockHandler([new Response(200)], $container);
+
+ $auth = new \Akamai\Open\EdgeGrid\Handler\Authentication();
+ $auth->setHost('test.host');
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/DebugTest.php b/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/DebugTest.php
new file mode 100644
index 00000000..9b19ca8a
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/DebugTest.php
@@ -0,0 +1,486 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Akamai\Open\EdgeGrid\Tests\Handler;
+
+use GuzzleHttp\Psr7\Response;
+use Akamai\Open\EdgeGrid\Client;
+
+class DebugTest extends \PHPUnit_Framework_TestCase
+{
+ public function teardown()
+ {
+ Client::setDebug(false);
+ }
+
+ public function testInstanceDebug()
+ {
+ $handler = $this->getMockHandler([new Response(400, [], json_encode(['detail' => 'error info']))]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $fp = fopen('php://memory', 'a+');
+ $client->setInstanceDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\Exception $e) {
+ }
+
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = << [ERROR] Call to /error failed with a 400 Bad Request result
+===> [ERROR] This indicates a problem with authentication or headers.
+===> [ERROR] Please ensure that the .edgerc file is formatted correctly.
+===> [ERROR] If you still have issues, please use gen_edgerc.php to generate the credentials
+===> [ERROR] Problem details:
+error info[39;49;00m
+
+EOF;
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testStaticDebug()
+ {
+ $handler = $this->getMockHandler([new Response(400, [], json_encode(['detail' => 'error info']))]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\Exception $e) {
+ }
+
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = << [ERROR] Call to /error failed with a 400 Bad Request result
+===> [ERROR] This indicates a problem with authentication or headers.
+===> [ERROR] Please ensure that the .edgerc file is formatted correctly.
+===> [ERROR] If you still have issues, please use gen_edgerc.php to generate the credentials
+===> [ERROR] Problem details:
+error info[39;49;00m
+
+EOF;
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testDebugOverride()
+ {
+ $handler = $this->getMockHandler([new Response(400, [], json_encode(['detail' => 'error string']))]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+ $client->setInstanceDebug(false);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\Exception $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = "";
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testInstanceOverrideStream()
+ {
+ $handler = $this->getMockHandler([new Response(400, [], json_encode(['detail' => 'error string']))]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+ $fp2 = fopen('php://memory', 'a+');
+ $client->setInstanceDebug($fp2);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\Exception $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = "";
+ $this->assertEquals($expectedOutput, $output);
+
+ $output = $this->readStreamData($fp2);
+
+ $expectedOutput = << [ERROR] Call to /error failed with a 400 Bad Request result
+===> [ERROR] This indicates a problem with authentication or headers.
+===> [ERROR] Please ensure that the .edgerc file is formatted correctly.
+===> [ERROR] If you still have issues, please use gen_edgerc.php to generate the credentials
+===> [ERROR] Problem details:
+error string[39;49;00m
+
+EOF;
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testDebugMessages()
+ {
+ $handler = $this->getMockHandler([
+ new Response(400, [], json_encode(['detail' => 'error message 1'])),
+ new Response(401, [], json_encode(['detail' => 'error message 2'])),
+ new Response(403, [], json_encode(['detail' => 'error message 3'])),
+ new Response(404, [], json_encode(['detail' => 'error message 4']))
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $fp = fopen('php://memory', 'a+');
+ $client->setInstanceDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/400');
+ } catch (\Exception $e) {
+ }
+ try {
+ $client->get('/401');
+ } catch (\Exception $e) {
+ }
+ try {
+ $client->get('/403');
+ } catch (\Exception $e) {
+ }
+ try {
+ $client->get('/404');
+ } catch (\Exception $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = << [ERROR] Call to /400 failed with a 400 Bad Request result
+===> [ERROR] This indicates a problem with authentication or headers.
+===> [ERROR] Please ensure that the .edgerc file is formatted correctly.
+===> [ERROR] If you still have issues, please use gen_edgerc.php to generate the credentials
+===> [ERROR] Problem details:
+error message 1[39;49;00m
+[31;01m===> [ERROR] Call to /401 failed with a 401 Unauthorized result
+===> [ERROR] This indicates a problem with authentication or headers.
+===> [ERROR] Please ensure that the .edgerc file is formatted correctly.
+===> [ERROR] If you still have issues, please use gen_edgerc.php to generate the credentials
+===> [ERROR] Problem details:
+error message 2[39;49;00m
+[31;01m===> [ERROR] Call to /403 failed with a 403 Forbidden result
+===> [ERROR] This indicates a problem with authorization.
+
+===> [ERROR] Please ensure that the credentials you created for this script
+
+===> [ERROR] have the necessary permissions in the Luna portal.
+
+===> [ERROR] Problem details:
+error message 3[39;49;00m
+[31;01m===> [ERROR] Call to /404 failed with a 404 Not Found result
+===> [ERROR] This means that the page does not exist as requested.
+
+===> [ERROR] Please ensure that the URL you're calling is correctly formatted
+
+===> [ERROR] or look at other examples to make sure yours matches.
+
+===> [ERROR] Problem details:
+error message 4[39;49;00m
+
+EOF;
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testResponseNoDetail()
+ {
+ $handler = $this->getMockHandler([new Response(500, [], json_encode(['nodetail' => 'error info']))]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\Exception $e) {
+ }
+
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = << [ERROR] Call to /error failed with a 500 Internal Server Error result
+===> [ERROR] Problem details:
+{
+ "nodetail": "error info"
+}[39;49;00m
+
+EOF;
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testResponseNoBody()
+ {
+ $handler = $this->getMockHandler([new Response(500, [])]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\Exception $e) {
+ }
+
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = << [ERROR] Call to /error failed with a 500 Internal Server Error result
+===> [ERROR] Problem details:
+No response body returned[39;49;00m
+
+EOF;
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testResponseNoJsonBody()
+ {
+ $handler = $this->getMockHandler([new Response(500, [], "error info")]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\Exception $e) {
+ }
+
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $expectedOutput = << [ERROR] Call to /error failed with a 500 Internal Server Error result
+===> [ERROR] Problem details:
+error info[39;49;00m
+
+EOF;
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testStringResource()
+ {
+ $handler = new \Akamai\Open\EdgeGrid\Handler\Debug('php://stdout');
+ $fp = \PHPUnit_Framework_Assert::readAttribute($handler, 'fp');
+ $this->assertEquals('php://stdout', stream_get_meta_data($fp)['uri']);
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\HandlerException\IOException
+ * @expectedExceptionMessage Unable to use resource: fake://stream
+ */
+ public function testInvalidStringResource()
+ {
+ $handler = new \Akamai\Open\EdgeGrid\Handler\Debug('fake://stream');
+ }
+
+ public function testDebugResponseExceptionNoCode()
+ {
+ $handler = $this->getMockHandler([
+ new \GuzzleHttp\Exception\RequestException("Error message", new \GuzzleHttp\Psr7\Request('GET', '/test'))
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\RequestException $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+ $this->assertEmpty($output);
+ }
+
+ public function testVerboseResponseExceptionWithCode()
+ {
+ $handler = $this->getMockHandler([
+ new \GuzzleHttp\Exception\RequestException(
+ "Error message",
+ new \GuzzleHttp\Psr7\Request('GET', '/test'),
+ new Response(500)
+ )
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen("php://memory", "a+");
+ Client::setDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\RequestException $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+ $this->assertEmpty($output);
+ }
+
+ public function testVerboseResponseExceptionWithBody()
+ {
+ $handler = $this->getMockHandler([
+ new \GuzzleHttp\Exception\RequestException(
+ "Error message",
+ new \GuzzleHttp\Psr7\Request('GET', '/test'),
+ new Response(500, [], json_encode(["errorString" => "An error"]))
+ )
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setDebug($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\RequestException $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ $output = $this->readStreamData($fp);
+
+ $this->assertEmpty($output);
+ }
+
+ public function getMockHandler($request, array &$container = null)
+ {
+ $client = new \Akamai\Open\EdgeGrid\Tests\ClientTest();
+ return $client->getMockHandler($request, $container);
+ }
+
+ protected function readStreamData($fp)
+ {
+ fseek($fp, 0);
+ $output = '';
+ while (!feof($fp)) {
+ $output .= fgets($fp);
+ }
+
+ return $output;
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/VerboseTest.php b/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/VerboseTest.php
new file mode 100644
index 00000000..1bd91b1b
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/Handler/VerboseTest.php
@@ -0,0 +1,626 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Akamai\Open\EdgeGrid\Tests\Handler;
+
+use GuzzleHttp\Psr7\Response;
+use Akamai\Open\EdgeGrid\Client;
+
+class VerboseTest extends \PHPUnit_Framework_TestCase
+{
+ public function teardown()
+ {
+ Client::setVerbose(false);
+ }
+
+ public function testInstanceVerboseSingle()
+ {
+ $handler = $this->getMockHandler([new Response(200, [], json_encode(['test' => 'data']))]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $client->setInstanceVerbose(true);
+
+ ob_start();
+ $client->get('/test');
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b3' .
+ '0316d7b0a202020202274657374223a202264617461220a7d1b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testInstanceVerboseMultiple()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, [], json_encode(['test' => 'data'])),
+ new Response(200, [], json_encode(['test' => 'data2', ["foo", "bar"], false, null, 123, 0.123]))
+ ]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+ $client->setAuth('test', 'test', 'test');
+
+ $client->setInstanceVerbose(true);
+
+ ob_start();
+ $client->get('/test1');
+ $client->get('/test2');
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b3' .
+ '0316d7b0a202020202274657374223a202264617461220a7d1b5b33393b34393b30306d0a1b' .
+ '5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333b3' .
+ '0316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b33' .
+ '363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b303' .
+ '16d7b0a202020202274657374223a20226461746132222c0a202020202230223a205b0a2020' .
+ '20202020202022666f6f222c0a202020202020202022626172220a202020205d2c0a2020202' .
+ '02231223a2066616c73652c0a202020202232223a206e756c6c2c0a202020202233223a2031' .
+ '32332c0a202020202234223a20302e3132330a7d1b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testStaticVerboseSingle()
+ {
+ $handler = $this->getMockHandler([new Response(200, [], json_encode(['test' => 'data']))]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ $client->get('/test');
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b3' .
+ '0316d7b0a202020202274657374223a202264617461220a7d1b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testStaticVerboseMultiple()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, [], json_encode(['test' => 'data'])),
+ new Response(200, [], json_encode(['test' => 'data2', ["foo", "bar"], false, null, 123, 0.123]))
+ ]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ $client->get('/test');
+ $client->get('/test2');
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b3' .
+ '0316d7b0a202020202274657374223a202264617461220a7d1b5b33393b34393b30306d0a1b' .
+ '5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333b3' .
+ '0316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b33' .
+ '363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b303' .
+ '16d7b0a202020202274657374223a20226461746132222c0a202020202230223a205b0a2020' .
+ '20202020202022666f6f222c0a202020202020202022626172220a202020205d2c0a2020202' .
+ '02231223a2066616c73652c0a202020202232223a206e756c6c2c0a202020202233223a2031' .
+ '32332c0a202020202234223a20302e3132330a7d1b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseOverrideSingle()
+ {
+ $handler = $this->getMockHandler([new Response(200, [], json_encode(['test' => 'data']))]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+ $client->setInstanceVerbose(false);
+
+ ob_start();
+ $client->get('/test');
+ $output = ob_get_clean();
+
+ $expectedOutput = "";
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseOverrideMultiple()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, [], json_encode(['test' => 'data'])),
+ new Response(200, [], json_encode(['test' => 'data2', ["foo", "bar"], false, null, 123, 0.123]))
+ ]);
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+ $client->setInstanceVerbose(false);
+
+ ob_start();
+ $client->get('/test');
+ $client->get('/test2');
+ $output = ob_get_clean();
+
+ $expectedOutput = "";
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseRedirect()
+ {
+ $handler = $this->getMockHandler([
+ new Response(301, ["Location" => "http://example.org/redirected"], json_encode(['test' => 'data'])),
+ new Response(200, [], json_encode(['test' => 'data2', ["foo", "bar"], false, null, 123, 0.123]))
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ $client->get('/redirect');
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526564697265637465643a20687474703' .
+ 'a2f2f6578616d706c652e6f72672f726564697265637465641b5b33393b34393b30306d0a1b' .
+ '5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333b3' .
+ '0316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b33' .
+ '363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b303' .
+ '16d7b0a202020202274657374223a20226461746132222c0a202020202230223a205b0a2020' .
+ '20202020202022666f6f222c0a202020202020202022626172220a202020205d2c0a2020202' .
+ '02231223a2066616c73652c0a202020202232223a206e756c6c2c0a202020202233223a2031' .
+ '32332c0a202020202234223a20302e3132330a7d1b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseNonJson()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, [], "String body")
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ }
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b3' .
+ '0316d537472696e6720626f64791b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseRequestHandler()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, [], "String body")
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ try {
+ $client->get('/error', ['handler' => $handler]);
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ }
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b3' .
+ '0316d537472696e6720626f64791b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseNoResponse()
+ {
+ $handler = $this->getMockHandler([
+ new Response(101)
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ }
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b3' .
+ '0316d4e6f20726573706f6e736520626f64792072657475726e65641b5b33393b34393b3030' .
+ '6d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseError()
+ {
+ $handler = $this->getMockHandler([
+ new Response(404, [], json_encode(['test' => 'data2', ["foo", "bar"], false, null, 123, 0.123]))
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setVerbose([$fp, $fp]);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ fseek($fp, 0);
+ $output = '';
+ do {
+ $output .= fgets($fp);
+ } while (!feof($fp));
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b33313b30316d3d3d3d3e205b4552524f525d20416e206572726f72206f636375727265643a200a1b5b33333b30316d7b0a202020202274657374223a20226461746132222c0a202020202230223a205b0a202020202020202022666f6f222c0a202020202020202022626172220a202020205d2c0a202020202231223a2066616c73652c0a202020202232223a206e756c6c2c0a202020202233223a203132332c0a202020202234223a20302e3132330a7d1b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseErrorNonJson()
+ {
+ $handler = $this->getMockHandler([
+ new Response(404, [], "String body")
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setVerbose($fp);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ }
+ $this->assertEmpty(ob_get_clean());
+
+ fseek($fp, 0);
+ $output = '';
+ do {
+ $output .= fgets($fp);
+ } while (!feof($fp));
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b33313b30316d3d3d3d3e205b4552524f525d20416e206572726f72206f636375727265643a200a1b5b33333b30316d537472696e6720626f64791b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseMixed()
+ {
+ $handler = $this->getMockHandler([
+ new Response(200, [], json_encode(['test' => 'data'])),
+ new Response(404, [], json_encode(['test' => 'data2', ["foo", "bar"], false, null, 123, 0.123]))
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ $fp = fopen('php://memory', 'a+');
+ Client::setVerbose(['php://output', $fp]);
+
+ ob_start();
+ try {
+ $client->get('/success');
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\ClientException $e) {
+ }
+
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b33363b30316d3d3d3d3e205b564552424f53455d20526573706f6e73653a200a1b5b33333b30316d7b0a202020202274657374223a202264617461220a7d1b5b33393b34393b30306d0a1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+
+ fseek($fp, 0);
+ $output = '';
+ do {
+ $output .= fgets($fp);
+ } while (!feof($fp));
+
+ $expectedError = hex2bin(
+ '1b5b33313b30316d3d3d3d3e205b4552524f525d20416e206572726f72206f6363757272656' .
+ '43a200a1b5b33333b30316d7b0a202020202274657374223a20226461746132222c0a202020' .
+ '202230223a205b0a202020202020202022666f6f222c0a202020202020202022626172220a2' .
+ '02020205d2c0a202020202231223a2066616c73652c0a202020202232223a206e756c6c2c0a' .
+ '202020202233223a203132332c0a202020202234223a20302e3132330a7d1b5b33393b34393' .
+ 'b30306d0a'
+ );
+
+ $this->assertEquals($expectedError, $output);
+ }
+
+ public function testVerboseResponseExceptionNoCode()
+ {
+ $handler = $this->getMockHandler([
+ new \GuzzleHttp\Exception\RequestException("Error message", new \GuzzleHttp\Psr7\Request('GET', '/test'))
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\RequestException $e) {
+ }
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33313b30316d3d3d3d3e205b4552524f525d20416e206572726f72206f636375727265643a2' .
+ '00a1b5b33333b30316d4572726f72206d6573736167651b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseResponseExceptionWithCode()
+ {
+ $handler = $this->getMockHandler([
+ new \GuzzleHttp\Exception\RequestException(
+ "Error message",
+ new \GuzzleHttp\Psr7\Request('GET', '/test'),
+ new Response(500)
+ )
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\RequestException $e) {
+ }
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33313b30316d3d3d3d3e205b4552524f525d20416e206572726f72206f636375727265643a2' .
+ '00a1b5b33333b30316d3530303a204572726f72206d6573736167651b5b33393b34393b3030' .
+ '6d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseResponseExceptionWithBody()
+ {
+ $handler = $this->getMockHandler([
+ new \GuzzleHttp\Exception\RequestException(
+ "Error message",
+ new \GuzzleHttp\Psr7\Request('GET', '/test'),
+ new Response(500, [], json_encode(["errorString" => "An error"]))
+ )
+ ]);
+
+ $client = new Client(
+ [
+ 'base_uri' => 'http://example.org',
+ 'handler' => $handler,
+ ]
+ );
+
+ Client::setVerbose(true);
+
+ ob_start();
+ try {
+ $client->get('/error');
+ } catch (\GuzzleHttp\Exception\RequestException $e) {
+ }
+ $output = ob_get_clean();
+
+ $expectedOutput = hex2bin(
+ '1b5b33363b30316d3d3d3d3e205b564552424f53455d20526571756573743a200a1b5b33333' .
+ 'b30316d4e6f207265717565737420626f64792073656e741b5b33393b34393b30306d0a1b5b' .
+ '33313b30316d3d3d3d3e205b4552524f525d20416e206572726f72206f636375727265643a2' .
+ '00a1b5b33333b30316d3530303a204572726f72206d6573736167650a1b5b33333b30316d7b' .
+ '226572726f72537472696e67223a22416e206572726f72227d1b5b33393b34393b30306d0a'
+ );
+
+ $this->assertEquals($expectedOutput, $output);
+ }
+
+ public function testVerboseSingleStreamString()
+ {
+ $verbose = new \Akamai\Open\EdgeGrid\Handler\Verbose('php://memory');
+
+ $fp = \PHPUnit_Framework_Assert::readAttribute($verbose, 'outputStream');
+ $fp2 = \PHPUnit_Framework_Assert::readAttribute($verbose, 'errorStream');
+
+ $this->assertSame($fp, $fp2);
+ $this->assertTrue(stream_get_meta_data($fp)['uri'] == 'php://memory');
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\HandlerException\IOException
+ * @expectedExceptionMessage Unable to use output stream: error://stream
+ */
+ public function testVerboseSingleStreamStringInvalid()
+ {
+ $verbose = new \Akamai\Open\EdgeGrid\Handler\Verbose('error://stream');
+ }
+
+ public function testVerboseDualStreamString()
+ {
+ $verbose = new \Akamai\Open\EdgeGrid\Handler\Verbose('php://memory', 'php://temp');
+
+ $fp = \PHPUnit_Framework_Assert::readAttribute($verbose, 'outputStream');
+ $fp2 = \PHPUnit_Framework_Assert::readAttribute($verbose, 'errorStream');
+
+ $this->assertNotSame($fp, $fp2);
+ $this->assertTrue(stream_get_meta_data($fp)['uri'] == 'php://memory');
+ $this->assertTrue(stream_get_meta_data($fp2)['uri'] == 'php://temp');
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\HandlerException\IOException
+ * @expectedExceptionMessage Unable to use error stream: error://stream
+ */
+ public function testVerboseDualStreamStringErrorInvalid()
+ {
+ $verbose = new \Akamai\Open\EdgeGrid\Handler\Verbose('php://input', 'error://stream');
+ }
+
+ /**
+ * @expectedException \Akamai\Open\EdgeGrid\Exception\HandlerException\IOException
+ * @expectedExceptionMessage Unable to use output stream: error://stream
+ */
+ public function testVerboseDualStreamStringInvalid()
+ {
+ $verbose = new \Akamai\Open\EdgeGrid\Handler\Verbose('error://stream', 'error://stream2');
+ }
+
+ public function getMockHandler($request, array &$container = null)
+ {
+ $client = new \Akamai\Open\EdgeGrid\Tests\ClientTest();
+ return $client->getMockHandler($request, $container);
+ }
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/bootstrap.php b/akamai/vendor/akamai-open/edgegrid-client/tests/bootstrap.php
new file mode 100644
index 00000000..f0eadc36
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/bootstrap.php
@@ -0,0 +1,22 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+require_once __DIR__ . '/../vendor/autoload.php';
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc
new file mode 100644
index 00000000..9053fe65
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc
@@ -0,0 +1,6 @@
+[default]
+host = akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/
+access_token = akab-access-token-xxx-xxxxxxxxxxxxxxxx
+client_token = akab-client-token-xxx-xxxxxxxxxxxxxxxx
+client_secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+max-size = 2048
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.default-testing b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.default-testing
new file mode 100644
index 00000000..622596e8
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.default-testing
@@ -0,0 +1,14 @@
+[default]
+host = bad.host.example.org
+access_token = bad
+client_token = token
+client_secret = and secret
+max-size = 2048
+
+[testing]
+host = akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net
+access_token = akab-access-token-xxx-xxxxxxxxxxxxxxxx
+client_token = akab-client-token-xxx-xxxxxxxxxxxxxxxx
+client_secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+max-size = 2048
+
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.invalid b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.invalid
new file mode 100644
index 00000000..7e27fd55
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.invalid
@@ -0,0 +1,6 @@
+[default]
+host:akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/
+access_token:akab-access-token-xxx-xxxxxxxxxxxxxxxx
+client_token:akab-client-token-xxx-xxxxxxxxxxxxxxxx
+client_secret:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+max-size:2048
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.invalid-spaces b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.invalid-spaces
new file mode 100644
index 00000000..0f6e8cb2
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.invalid-spaces
@@ -0,0 +1,6 @@
+[default]
+host: akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/
+access_token: akab-access-token-xxx-xxxxxxxxxxxxxxxx
+client_token: akab-client-token-xxx-xxxxxxxxxxxxxxxx
+client_secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+max-size: 2048
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.testing b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.testing
new file mode 100644
index 00000000..34a13ba5
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/edgerc/.edgerc.testing
@@ -0,0 +1,6 @@
+[testing]
+host = akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net
+access_token = akab-access-token-xxx-xxxxxxxxxxxxxxxx
+client_token = akab-client-token-xxx-xxxxxxxxxxxxxxxx
+client_secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
+max-size = 2048
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/random_bytes.php b/akamai/vendor/akamai-open/edgegrid-client/tests/random_bytes.php
new file mode 100644
index 00000000..4d91f340
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/random_bytes.php
@@ -0,0 +1,34 @@
+
+ *
+ * For more information visit https://developer.akamai.com
+ *
+ * Copyright 2014 Akamai Technologies, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * random_bytes stub
+ *
+ * @see Akamai\Open\EdgeGrid\Tests\Client\Authentication\NonceTest->testMakeNonceRandomBytes()
+ *
+ * @param $size
+ * @return string
+ */
+function random_bytes($size)
+{
+ return __FUNCTION__;
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tests/testdata.json b/akamai/vendor/akamai-open/edgegrid-client/tests/testdata.json
new file mode 100644
index 00000000..17f8e417
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tests/testdata.json
@@ -0,0 +1,179 @@
+{
+ "base_url": "https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net/",
+ "access_token": "akab-access-token-xxx-xxxxxxxxxxxxxxxx",
+ "client_token":"akab-client-token-xxx-xxxxxxxxxxxxxxxx",
+ "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
+ "max_body": 2048,
+ "headers_to_sign": [ "X-Test1", "X-Test2", "X-Test3" ],
+ "nonce": "nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
+ "timestamp": "20140321T19:34:21+0000",
+ "tests": [
+ {
+ "testName": "simple GET",
+ "request": {
+ "method": "GET",
+ "path": "/",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=tL+y4hxyHxgWVD30X3pWnGKHcPzmrIF+LThiAOhMxYU="
+ },
+ {
+ "testName": "GET with querystring",
+ "request": {
+ "method": "GET",
+ "path": "/testapi/v1/t1?p1=1&p2=2",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=hKDH1UlnQySSHjvIcZpDMbQHihTQ0XyVAKZaApabdeA="
+ },
+ {
+ "testName": "POST inside limit",
+ "request": {
+ "method": "POST",
+ "path": "/testapi/v1/t3",
+ "data": "datadatadatadatadatadatadatadata",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=hXm4iCxtpN22m4cbZb4lVLW5rhX8Ca82vCFqXzSTPe4="
+ },
+ {
+ "testName": "POST too large",
+ "request": {
+ "method": "POST",
+ "path": "/testapi/v1/t3",
+ "data": "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=6Q6PiTipLae6n4GsSIDTCJ54bEbHUBp+4MUXrbQCBoY="
+ },
+ {
+ "testName": "POST length equals max_body",
+ "request": {
+ "method": "POST",
+ "path": "/testapi/v1/t3",
+ "data": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=6Q6PiTipLae6n4GsSIDTCJ54bEbHUBp+4MUXrbQCBoY="
+ },
+ {
+ "testName": "POST empty body",
+ "request": {
+ "method": "POST",
+ "path": "/testapi/v1/t6",
+ "data": "",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=1gEDxeQGD5GovIkJJGcBaKnZ+VaPtrc4qBUHixjsPCQ="
+ },
+ {
+ "testName": "POST nil body",
+ "request": {
+ "method": "POST",
+ "path": "/testapi/v1/t6",
+ "data": null,
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=1gEDxeQGD5GovIkJJGcBaKnZ+VaPtrc4qBUHixjsPCQ="
+ },
+ {
+ "testName": "Simple header signing with GET",
+ "request": {
+ "method": "GET",
+ "path": "/testapi/v1/t4",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"},
+ {"X-Test1": "test-simple-header"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=8F9AybcRw+PLxnvT+H0JRkjROrrUgsxJTnRXMzqvcwY="
+ },
+ {
+ "testName": "Header containing spaces",
+ "request": {
+ "method": "GET",
+ "path": "/testapi/v1/t4",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"},
+ {"X-Test1": "\" test-header-with-spaces \""}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=ucq2AbjCNtobHfCTuS38fdkl5UDdWHZhQX46fYR8CqI="
+ },
+ {
+ "testName": "Header with leading and interior spaces",
+ "request": {
+ "method": "GET",
+ "path": "/testapi/v1/t4",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"},
+ {"X-Test1": " first-thing second-thing"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=WtnneL539UadAAOJwnsXvPqT4Kt6z7HMgBEwAFpt3+c="
+ },
+ {
+ "testName": "Headers out of order",
+ "request": {
+ "method": "GET",
+ "path": "/testapi/v1/t4",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"},
+ {"X-Test2": "t2"},
+ {"X-Test1": "t1"},
+ {"X-Test3": "t3"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=Wus73Nx8jOYM+kkBFF2q8D1EATRIMr0WLWwpLBgkBqY="
+ },
+ {
+ "testName": "Extra header",
+ "request": {
+ "method": "GET",
+ "path": "/testapi/v1/t5",
+ "headers": [
+ {"Host": "akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net"},
+ {"X-Test2": "t2"},
+ {"X-Test1": "t1"},
+ {"X-Test3": "t3"},
+ {"X-Extra": "this won't be included"}
+ ]
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=Knd/jc0A5Ghhizjayr0AUUvl2MZjBpS3FDSzvtq4Ixc="
+ },
+ {
+ "testName": "PUT test",
+ "request": {
+ "method": "PUT",
+ "path": "/testapi/v1/t6",
+ "data": "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=GNBWEYSEWOLtu+7dD52da2C39aX/Jchpon3K/AmBqBU="
+ },
+ {
+ "testName": "GET with query args as option",
+ "request": {
+ "method": "GET",
+ "path": "/testapi/v1/t6",
+ "query": {
+ "test": "arg"
+ }
+ },
+ "expectedAuthorization": "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=MlHog3cBr9VL+L+KUpVsdyAHmXaOunCdKplWy4UlohI="
+ }
+ ]
+}
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tools/build-docs.sh b/akamai/vendor/akamai-open/edgegrid-client/tools/build-docs.sh
new file mode 100644
index 00000000..85310899
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tools/build-docs.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+export PATH=vendor/bin:$PATH
+DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+cd $DIR && cd ../
+composer install
+phpunit
+phploc --log-xml=./build/phploc.xml --count-tests ./src ./tests
+phpcs --standard=PSR1,PSR2 --report=checkstyle --report-file=build/phpcs.xml ./src/
+phpdox
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tools/build-phar.sh b/akamai/vendor/akamai-open/edgegrid-client/tools/build-phar.sh
new file mode 100644
index 00000000..f156df34
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tools/build-phar.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+export PATH=vendor/bin:$PATH
+if [[ -z $1 ]]
+then
+ export VERSION=""
+else
+ export VERSION="-$1"
+fi
+
+DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+cd $DIR && cd ../
+if [[ ! -d "build/phar" ]]
+then
+ mkdir -p build/phar
+fi
+
+# Create the bootstrap file if necessary
+echo "run();
+ exit;
+}
+__HALT_COMPILER(); ?>
+EOF;
+
+file_put_contents('build/phar/stub.php', \$stub);" > build/phar/bootstrap.php
+
+php -dphar.readonly=0 ./vendor/bin/box build
+
+mv akamai-open-edgegrid-client.phar "akamai-open-edgegrid-client${VERSION}.phar"
\ No newline at end of file
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tools/fix-cs.sh b/akamai/vendor/akamai-open/edgegrid-client/tools/fix-cs.sh
new file mode 100644
index 00000000..3493b7c1
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tools/fix-cs.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+export PATH=vendor/bin:$PATH
+DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+if [[ $# -eq 1 ]]
+then
+ RUNDIR=$@
+else
+ RUNDIR=$(cd $DIR && cd ../ && pwd)/src
+fi
+RESULT=$(phpcs --colors --standard=PSR1,PSR2 $RUNDIR)
+echo "$RESULT"
+echo $RESULT | grep "PHPCBF CAN FIX" > /dev/null
+if [[ $? -eq 0 ]]
+then
+ printf "Would you like to fix errors? [Y/n] "
+ read answer
+ if [[ $answer != "n" ]]
+ then
+ echo "Running phpcbf: "
+ phpcbf --standard=PSR1,PSR2 $RUNDIR
+ echo "Running php-cs-fixer: "
+ php-cs-fixer fix ./src --level=psr2
+ fi
+ exit -1
+fi
diff --git a/akamai/vendor/akamai-open/edgegrid-client/tools/publish-docs.sh b/akamai/vendor/akamai-open/edgegrid-client/tools/publish-docs.sh
new file mode 100644
index 00000000..95e8536c
--- /dev/null
+++ b/akamai/vendor/akamai-open/edgegrid-client/tools/publish-docs.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+if [ $# -ne 1 ]; then
+ echo "usage: ./publish-docs.sh \"commit message\""
+ exit 1;
+fi
+
+mv docs docs-temp
+git stash
+git checkout gh-pages
+sleep 3
+
+cp -R docs-temp/* .
+
+git add *
+git commit -m "$1"
+git push origin gh-pages
+
+git checkout master
+rm -Rf docs
+mv docs-temp docs
+git stash apply
\ No newline at end of file
diff --git a/akamai/vendor/autoload.php b/akamai/vendor/autoload.php
new file mode 100644
index 00000000..0e2dae8e
--- /dev/null
+++ b/akamai/vendor/autoload.php
@@ -0,0 +1,7 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0 class loader
+ *
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
+ *
+ * $loader = new \Composer\Autoload\ClassLoader();
+ *
+ * // register classes with namespaces
+ * $loader->add('Symfony\Component', __DIR__.'/component');
+ * $loader->add('Symfony', __DIR__.'/framework');
+ *
+ * // activate the autoloader
+ * $loader->register();
+ *
+ * // to enable searching the include path (eg. for PEAR packages)
+ * $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier
+ * @author Jordi Boggiano
+ */
+class ClassLoader
+{
+ // PSR-4
+ private $prefixLengthsPsr4 = array();
+ private $prefixDirsPsr4 = array();
+ private $fallbackDirsPsr4 = array();
+
+ // PSR-0
+ private $prefixesPsr0 = array();
+ private $fallbackDirsPsr0 = array();
+
+ private $useIncludePath = false;
+ private $classMap = array();
+
+ private $classMapAuthoritative = false;
+
+ public function getPrefixes()
+ {
+ if (!empty($this->prefixesPsr0)) {
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
+ }
+
+ return array();
+ }
+
+ public function getPrefixesPsr4()
+ {
+ return $this->prefixDirsPsr4;
+ }
+
+ public function getFallbackDirs()
+ {
+ return $this->fallbackDirsPsr0;
+ }
+
+ public function getFallbackDirsPsr4()
+ {
+ return $this->fallbackDirsPsr4;
+ }
+
+ public function getClassMap()
+ {
+ return $this->classMap;
+ }
+
+ /**
+ * @param array $classMap Class to filename map
+ */
+ public function addClassMap(array $classMap)
+ {
+ if ($this->classMap) {
+ $this->classMap = array_merge($this->classMap, $classMap);
+ } else {
+ $this->classMap = $classMap;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix, either
+ * appending or prepending to the ones previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 root directories
+ * @param bool $prepend Whether to prepend the directories
+ */
+ public function add($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ if ($prepend) {
+ $this->fallbackDirsPsr0 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr0
+ );
+ } else {
+ $this->fallbackDirsPsr0 = array_merge(
+ $this->fallbackDirsPsr0,
+ (array) $paths
+ );
+ }
+
+ return;
+ }
+
+ $first = $prefix[0];
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
+
+ return;
+ }
+ if ($prepend) {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixesPsr0[$first][$prefix]
+ );
+ } else {
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
+ $this->prefixesPsr0[$first][$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace, either
+ * appending or prepending to the ones previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-0 base directories
+ * @param bool $prepend Whether to prepend the directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function addPsr4($prefix, $paths, $prepend = false)
+ {
+ if (!$prefix) {
+ // Register directories for the root namespace.
+ if ($prepend) {
+ $this->fallbackDirsPsr4 = array_merge(
+ (array) $paths,
+ $this->fallbackDirsPsr4
+ );
+ } else {
+ $this->fallbackDirsPsr4 = array_merge(
+ $this->fallbackDirsPsr4,
+ (array) $paths
+ );
+ }
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
+ // Register directories for a new namespace.
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ } elseif ($prepend) {
+ // Prepend directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ (array) $paths,
+ $this->prefixDirsPsr4[$prefix]
+ );
+ } else {
+ // Append directories for an already registered namespace.
+ $this->prefixDirsPsr4[$prefix] = array_merge(
+ $this->prefixDirsPsr4[$prefix],
+ (array) $paths
+ );
+ }
+ }
+
+ /**
+ * Registers a set of PSR-0 directories for a given prefix,
+ * replacing any others previously set for this prefix.
+ *
+ * @param string $prefix The prefix
+ * @param array|string $paths The PSR-0 base directories
+ */
+ public function set($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr0 = (array) $paths;
+ } else {
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Registers a set of PSR-4 directories for a given namespace,
+ * replacing any others previously set for this namespace.
+ *
+ * @param string $prefix The prefix/namespace, with trailing '\\'
+ * @param array|string $paths The PSR-4 base directories
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setPsr4($prefix, $paths)
+ {
+ if (!$prefix) {
+ $this->fallbackDirsPsr4 = (array) $paths;
+ } else {
+ $length = strlen($prefix);
+ if ('\\' !== $prefix[$length - 1]) {
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
+ }
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
+ }
+ }
+
+ /**
+ * Turns on searching the include path for class files.
+ *
+ * @param bool $useIncludePath
+ */
+ public function setUseIncludePath($useIncludePath)
+ {
+ $this->useIncludePath = $useIncludePath;
+ }
+
+ /**
+ * Can be used to check if the autoloader uses the include path to check
+ * for classes.
+ *
+ * @return bool
+ */
+ public function getUseIncludePath()
+ {
+ return $this->useIncludePath;
+ }
+
+ /**
+ * Turns off searching the prefix and fallback directories for classes
+ * that have not been registered with the class map.
+ *
+ * @param bool $classMapAuthoritative
+ */
+ public function setClassMapAuthoritative($classMapAuthoritative)
+ {
+ $this->classMapAuthoritative = $classMapAuthoritative;
+ }
+
+ /**
+ * Should class lookup fail if not found in the current class map?
+ *
+ * @return bool
+ */
+ public function isClassMapAuthoritative()
+ {
+ return $this->classMapAuthoritative;
+ }
+
+ /**
+ * Registers this instance as an autoloader.
+ *
+ * @param bool $prepend Whether to prepend the autoloader or not
+ */
+ public function register($prepend = false)
+ {
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+ }
+
+ /**
+ * Unregisters this instance as an autoloader.
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $class The name of the class
+ * @return bool|null True if loaded, null otherwise
+ */
+ public function loadClass($class)
+ {
+ if ($file = $this->findFile($class)) {
+ includeFile($file);
+
+ return true;
+ }
+ }
+
+ /**
+ * Finds the path to the file where the class is defined.
+ *
+ * @param string $class The name of the class
+ *
+ * @return string|false The path if found, false otherwise
+ */
+ public function findFile($class)
+ {
+ // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
+ if ('\\' == $class[0]) {
+ $class = substr($class, 1);
+ }
+
+ // class map lookup
+ if (isset($this->classMap[$class])) {
+ return $this->classMap[$class];
+ }
+ if ($this->classMapAuthoritative) {
+ return false;
+ }
+
+ $file = $this->findFileWithExtension($class, '.php');
+
+ // Search for Hack files if we are running on HHVM
+ if ($file === null && defined('HHVM_VERSION')) {
+ $file = $this->findFileWithExtension($class, '.hh');
+ }
+
+ if ($file === null) {
+ // Remember that this class does not exist.
+ return $this->classMap[$class] = false;
+ }
+
+ return $file;
+ }
+
+ private function findFileWithExtension($class, $ext)
+ {
+ // PSR-4 lookup
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
+
+ $first = $class[0];
+ if (isset($this->prefixLengthsPsr4[$first])) {
+ foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-4 fallback dirs
+ foreach ($this->fallbackDirsPsr4 as $dir) {
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 lookup
+ if (false !== $pos = strrpos($class, '\\')) {
+ // namespaced class name
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
+ } else {
+ // PEAR-like class name
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
+ }
+
+ if (isset($this->prefixesPsr0[$first])) {
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
+ if (0 === strpos($class, $prefix)) {
+ foreach ($dirs as $dir) {
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+ }
+ }
+ }
+
+ // PSR-0 fallback dirs
+ foreach ($this->fallbackDirsPsr0 as $dir) {
+ if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
+ return $file;
+ }
+ }
+
+ // PSR-0 include paths.
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
+ return $file;
+ }
+ }
+}
+
+/**
+ * Scope isolated include.
+ *
+ * Prevents access to $this/self from included files.
+ */
+function includeFile($file)
+{
+ include $file;
+}
diff --git a/akamai/vendor/composer/autoload_classmap.php b/akamai/vendor/composer/autoload_classmap.php
new file mode 100644
index 00000000..7a91153b
--- /dev/null
+++ b/akamai/vendor/composer/autoload_classmap.php
@@ -0,0 +1,9 @@
+ array($vendorDir . '/seld/cli-prompt/src'),
+ 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
+ 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
+ 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog', $vendorDir . '/akamai-open/edgegrid-client/src/Monolog'),
+ 'League\\CLImate\\' => array($vendorDir . '/league/climate/src'),
+ 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'),
+ 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'),
+ 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
+ 'Akamai\\Open\\EdgeGrid\\' => array($vendorDir . '/akamai-open/edgegrid-client/src'),
+);
diff --git a/akamai/vendor/composer/autoload_real.php b/akamai/vendor/composer/autoload_real.php
new file mode 100644
index 00000000..111b035d
--- /dev/null
+++ b/akamai/vendor/composer/autoload_real.php
@@ -0,0 +1,55 @@
+ $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+
+ $loader->register(true);
+
+ $includeFiles = require __DIR__ . '/autoload_files.php';
+ foreach ($includeFiles as $file) {
+ composerRequire8e38b71d451b561f618ae67af0263926($file);
+ }
+
+ return $loader;
+ }
+}
+
+function composerRequire8e38b71d451b561f618ae67af0263926($file)
+{
+ require $file;
+}
diff --git a/akamai/vendor/composer/installed.json b/akamai/vendor/composer/installed.json
new file mode 100644
index 00000000..0282b2f6
--- /dev/null
+++ b/akamai/vendor/composer/installed.json
@@ -0,0 +1,589 @@
+[
+ {
+ "name": "seld/cli-prompt",
+ "version": "1.0.3",
+ "version_normalized": "1.0.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/cli-prompt.git",
+ "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/a19a7376a4689d4d94cab66ab4f3c816019ba8dd",
+ "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "time": "2017-03-18 11:32:45",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Seld\\CliPrompt\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be"
+ }
+ ],
+ "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type",
+ "keywords": [
+ "cli",
+ "console",
+ "hidden",
+ "input",
+ "prompt"
+ ]
+ },
+ {
+ "name": "psr/log",
+ "version": "1.1.2",
+ "version_normalized": "1.1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "time": "2019-11-01 11:05:21",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ]
+ },
+ {
+ "name": "league/climate",
+ "version": "3.4.1",
+ "version_normalized": "3.4.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/climate.git",
+ "reference": "d657a19837c1f79a891381fb128b755aa3386381"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/climate/zipball/d657a19837c1f79a891381fb128b755aa3386381",
+ "reference": "d657a19837c1f79a891381fb128b755aa3386381",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^5.6|^7.0",
+ "psr/log": "^1.0",
+ "seld/cli-prompt": "^1.0"
+ },
+ "require-dev": {
+ "mikey179/vfsstream": "^1.4",
+ "mockery/mockery": "^1.0",
+ "phpunit/phpunit": "^5.7.16"
+ },
+ "suggest": {
+ "ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring"
+ },
+ "time": "2018-04-29 16:43:54",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "League\\CLImate\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Craig Duncan",
+ "email": "git@duncanc.co.uk",
+ "homepage": "https://github.com/duncan3dc",
+ "role": "Developer"
+ },
+ {
+ "name": "Joe Tannenbaum",
+ "email": "hey@joe.codes",
+ "homepage": "http://joe.codes/",
+ "role": "Developer"
+ }
+ ],
+ "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.",
+ "keywords": [
+ "cli",
+ "colors",
+ "command",
+ "php",
+ "terminal"
+ ]
+ },
+ {
+ "name": "monolog/monolog",
+ "version": "1.25.2",
+ "version_normalized": "1.25.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Seldaek/monolog.git",
+ "reference": "d5e2fb341cb44f7e2ab639d12a1e5901091ec287"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Seldaek/monolog/zipball/d5e2fb341cb44f7e2ab639d12a1e5901091ec287",
+ "reference": "d5e2fb341cb44f7e2ab639d12a1e5901091ec287",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
+ },
+ "provide": {
+ "psr/log-implementation": "1.0.0"
+ },
+ "require-dev": {
+ "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+ "doctrine/couchdb": "~1.0@dev",
+ "graylog2/gelf-php": "~1.0",
+ "jakub-onderka/php-parallel-lint": "0.9",
+ "php-amqplib/php-amqplib": "~2.4",
+ "php-console/php-console": "^3.1.3",
+ "phpunit/phpunit": "~4.5",
+ "phpunit/phpunit-mock-objects": "2.3.0",
+ "ruflin/elastica": ">=0.90 <3.0",
+ "sentry/sentry": "^0.13",
+ "swiftmailer/swiftmailer": "^5.3|^6.0"
+ },
+ "suggest": {
+ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
+ "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+ "php-console/php-console": "Allow sending log messages to Google Chrome",
+ "rollbar/rollbar": "Allow sending log messages to Rollbar",
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "sentry/sentry": "Allow sending log messages to a Sentry server"
+ },
+ "time": "2019-11-13 10:00:05",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Monolog\\": "src/Monolog"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "homepage": "http://github.com/Seldaek/monolog",
+ "keywords": [
+ "log",
+ "logging",
+ "psr-3"
+ ]
+ },
+ {
+ "name": "ralouphie/getallheaders",
+ "version": "3.0.3",
+ "version_normalized": "3.0.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ralouphie/getallheaders.git",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
+ },
+ "time": "2019-03-08 08:55:37",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "files": [
+ "src/getallheaders.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "description": "A polyfill for getallheaders."
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "version_normalized": "1.0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "time": "2016-08-06 14:39:51",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ]
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "1.6.1",
+ "version_normalized": "1.6.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "239400de7a173fe9901b9ac7c06497751f00727a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a",
+ "reference": "239400de7a173fe9901b9ac7c06497751f00727a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0",
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "ext-zlib": "*",
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
+ },
+ "suggest": {
+ "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "time": "2019-07-01 23:21:34",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Schultze",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": [
+ "http",
+ "message",
+ "psr-7",
+ "request",
+ "response",
+ "stream",
+ "uri",
+ "url"
+ ]
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "v1.3.1",
+ "version_normalized": "1.3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+ "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0"
+ },
+ "time": "2016-12-20 10:07:11",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ]
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "6.4.1",
+ "version_normalized": "6.4.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "0895c932405407fd3a7368b6910c09a24d26db11"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/0895c932405407fd3a7368b6910c09a24d26db11",
+ "reference": "0895c932405407fd3a7368b6910c09a24d26db11",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.6.1",
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+ "psr/log": "^1.1"
+ },
+ "suggest": {
+ "psr/log": "Required for using the Log middleware"
+ },
+ "time": "2019-10-23 15:58:00",
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.3-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "rest",
+ "web service"
+ ]
+ },
+ {
+ "name": "akamai-open/edgegrid-client",
+ "version": "0.4.6",
+ "version_normalized": "0.4.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/akamai/AkamaiOPEN-edgegrid-php-client.git",
+ "reference": "00bd7dbe59d52c19c9a465373cb58d2a65e46ec6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/akamai/AkamaiOPEN-edgegrid-php-client/zipball/00bd7dbe59d52c19c9a465373cb58d2a65e46ec6",
+ "reference": "00bd7dbe59d52c19c9a465373cb58d2a65e46ec6",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/guzzle": "~6.0",
+ "league/climate": "~3.2",
+ "monolog/monolog": "^1.15",
+ "php": ">=5.5",
+ "psr/log": "^1.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^1.9",
+ "kherge/box": "^2.5",
+ "phploc/phploc": "^2.1",
+ "phpunit/phpunit": "~4.7",
+ "squizlabs/php_codesniffer": "^2.3",
+ "theseer/phpdox": "~0.8"
+ },
+ "time": "2016-08-30 16:19:13",
+ "type": "library",
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "Akamai\\Open\\EdgeGrid\\": "src/",
+ "Monolog\\": "src/Monolog"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Davey Shafik",
+ "email": "dshafik@akamai.com"
+ }
+ ],
+ "description": "Implements the Akamai {OPEN} EdgeGrid Authentication specified by https://developer.akamai.com/introduction/Client_Auth.html",
+ "homepage": "https://github.com/akamai-open/edgegrid-auth-php",
+ "keywords": [
+ "akamai",
+ "edgegrid",
+ "open"
+ ]
+ }
+]
diff --git a/akamai/vendor/guzzlehttp/guzzle/.php_cs b/akamai/vendor/guzzlehttp/guzzle/.php_cs
new file mode 100644
index 00000000..a8ace8aa
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/.php_cs
@@ -0,0 +1,21 @@
+setRiskyAllowed(true)
+ ->setRules([
+ '@PSR2' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'declare_strict_types' => false,
+ 'concat_space' => ['spacing'=>'one'],
+ // 'ordered_imports' => true,
+ // 'phpdoc_align' => ['align'=>'vertical'],
+ // 'native_function_invocation' => true,
+ ])
+ ->setFinder(
+ PhpCsFixer\Finder::create()
+ ->in(__DIR__.'/src')
+ ->name('*.php')
+ )
+;
+
+return $config;
diff --git a/akamai/vendor/guzzlehttp/guzzle/CHANGELOG.md b/akamai/vendor/guzzlehttp/guzzle/CHANGELOG.md
new file mode 100644
index 00000000..65557498
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/CHANGELOG.md
@@ -0,0 +1,1304 @@
+# Change Log
+
+## 6.4.1 - 2019-10-23
+
+* 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
+
+* Improvement: Improved error messages when using curl < 7.21.2 [#2108](https://github.com/guzzle/guzzle/pull/2108)
+* Fix: Test if response is readable before returning a summary in `RequestException::getResponseBodySummary()` [#2081](https://github.com/guzzle/guzzle/pull/2081)
+* Fix: Add support for GUZZLE_CURL_SELECT_TIMEOUT environment variable [#2161](https://github.com/guzzle/guzzle/pull/2161)
+* Improvement: Added `GuzzleHttp\Exception\InvalidArgumentException` [#2163](https://github.com/guzzle/guzzle/pull/2163)
+* Improvement: Added `GuzzleHttp\_current_time()` to use `hrtime()` if that function exists. [#2242](https://github.com/guzzle/guzzle/pull/2242)
+* Improvement: Added curl's `appconnect_time` in `TransferStats` [#2284](https://github.com/guzzle/guzzle/pull/2284)
+* Improvement: Make GuzzleException extend Throwable wherever it's available [#2273](https://github.com/guzzle/guzzle/pull/2273)
+* Fix: Prevent concurrent writes to file when saving `CookieJar` [#2335](https://github.com/guzzle/guzzle/pull/2335)
+* Improvement: Update `MockHandler` so we can test transfer time [#2362](https://github.com/guzzle/guzzle/pull/2362)
+
+## 6.3.3 - 2018-04-22
+
+* Fix: Default headers when decode_content is specified
+
+
+## 6.3.2 - 2018-03-26
+
+* Fix: Release process
+
+
+## 6.3.1 - 2018-03-26
+
+* Bug fix: Parsing 0 epoch expiry times in cookies [#2014](https://github.com/guzzle/guzzle/pull/2014)
+* Improvement: Better ConnectException detection [#2012](https://github.com/guzzle/guzzle/pull/2012)
+* Bug fix: Malformed domain that contains a "/" [#1999](https://github.com/guzzle/guzzle/pull/1999)
+* Bug fix: Undefined offset when a cookie has no first key-value pair [#1998](https://github.com/guzzle/guzzle/pull/1998)
+* Improvement: Support PHPUnit 6 [#1953](https://github.com/guzzle/guzzle/pull/1953)
+* Bug fix: Support empty headers [#1915](https://github.com/guzzle/guzzle/pull/1915)
+* Bug fix: Ignore case during header modifications [#1916](https://github.com/guzzle/guzzle/pull/1916)
+
++ Minor code cleanups, documentation fixes and clarifications.
+
+
+## 6.3.0 - 2017-06-22
+
+* Feature: force IP resolution (ipv4 or ipv6) [#1608](https://github.com/guzzle/guzzle/pull/1608), [#1659](https://github.com/guzzle/guzzle/pull/1659)
+* Improvement: Don't include summary in exception message when body is empty [#1621](https://github.com/guzzle/guzzle/pull/1621)
+* Improvement: Handle `on_headers` option in MockHandler [#1580](https://github.com/guzzle/guzzle/pull/1580)
+* Improvement: Added SUSE Linux CA path [#1609](https://github.com/guzzle/guzzle/issues/1609)
+* Improvement: Use class reference for getting the name of the class instead of using hardcoded strings [#1641](https://github.com/guzzle/guzzle/pull/1641)
+* Feature: Added `read_timeout` option [#1611](https://github.com/guzzle/guzzle/pull/1611)
+* Bug fix: PHP 7.x fixes [#1685](https://github.com/guzzle/guzzle/pull/1685), [#1686](https://github.com/guzzle/guzzle/pull/1686), [#1811](https://github.com/guzzle/guzzle/pull/1811)
+* Deprecation: BadResponseException instantiation without a response [#1642](https://github.com/guzzle/guzzle/pull/1642)
+* Feature: Added NTLM auth [#1569](https://github.com/guzzle/guzzle/pull/1569)
+* Feature: Track redirect HTTP status codes [#1711](https://github.com/guzzle/guzzle/pull/1711)
+* Improvement: Check handler type during construction [#1745](https://github.com/guzzle/guzzle/pull/1745)
+* Improvement: Always include the Content-Length if there's a body [#1721](https://github.com/guzzle/guzzle/pull/1721)
+* Feature: Added convenience method to access a cookie by name [#1318](https://github.com/guzzle/guzzle/pull/1318)
+* Bug fix: Fill `CURLOPT_CAPATH` and `CURLOPT_CAINFO` properly [#1684](https://github.com/guzzle/guzzle/pull/1684)
+* Improvement: Use `\GuzzleHttp\Promise\rejection_for` function instead of object init [#1827](https://github.com/guzzle/guzzle/pull/1827)
+
+
++ Minor code cleanups, documentation fixes and clarifications.
+
+## 6.2.3 - 2017-02-28
+
+* Fix deprecations with guzzle/psr7 version 1.4
+
+## 6.2.2 - 2016-10-08
+
+* Allow to pass nullable Response to delay callable
+* Only add scheme when host is present
+* Fix drain case where content-length is the literal string zero
+* Obfuscate in-URL credentials in exceptions
+
+## 6.2.1 - 2016-07-18
+
+* Address HTTP_PROXY security vulnerability, CVE-2016-5385:
+ https://httpoxy.org/
+* Fixing timeout bug with StreamHandler:
+ https://github.com/guzzle/guzzle/pull/1488
+* Only read up to `Content-Length` in PHP StreamHandler to avoid timeouts when
+ a server does not honor `Connection: close`.
+* Ignore URI fragment when sending requests.
+
+## 6.2.0 - 2016-03-21
+
+* Feature: added `GuzzleHttp\json_encode` and `GuzzleHttp\json_decode`.
+ https://github.com/guzzle/guzzle/pull/1389
+* Bug fix: Fix sleep calculation when waiting for delayed requests.
+ https://github.com/guzzle/guzzle/pull/1324
+* Feature: More flexible history containers.
+ https://github.com/guzzle/guzzle/pull/1373
+* Bug fix: defer sink stream opening in StreamHandler.
+ https://github.com/guzzle/guzzle/pull/1377
+* Bug fix: do not attempt to escape cookie values.
+ https://github.com/guzzle/guzzle/pull/1406
+* Feature: report original content encoding and length on decoded responses.
+ https://github.com/guzzle/guzzle/pull/1409
+* Bug fix: rewind seekable request bodies before dispatching to cURL.
+ https://github.com/guzzle/guzzle/pull/1422
+* Bug fix: provide an empty string to `http_build_query` for HHVM workaround.
+ https://github.com/guzzle/guzzle/pull/1367
+
+## 6.1.1 - 2015-11-22
+
+* Bug fix: Proxy::wrapSync() now correctly proxies to the appropriate handler
+ https://github.com/guzzle/guzzle/commit/911bcbc8b434adce64e223a6d1d14e9a8f63e4e4
+* Feature: HandlerStack is now more generic.
+ https://github.com/guzzle/guzzle/commit/f2102941331cda544745eedd97fc8fd46e1ee33e
+* Bug fix: setting verify to false in the StreamHandler now disables peer
+ verification. https://github.com/guzzle/guzzle/issues/1256
+* Feature: Middleware now uses an exception factory, including more error
+ context. https://github.com/guzzle/guzzle/pull/1282
+* Feature: better support for disabled functions.
+ https://github.com/guzzle/guzzle/pull/1287
+* Bug fix: fixed regression where MockHandler was not using `sink`.
+ https://github.com/guzzle/guzzle/pull/1292
+
+## 6.1.0 - 2015-09-08
+
+* Feature: Added the `on_stats` request option to provide access to transfer
+ statistics for requests. https://github.com/guzzle/guzzle/pull/1202
+* Feature: Added the ability to persist session cookies in CookieJars.
+ https://github.com/guzzle/guzzle/pull/1195
+* Feature: Some compatibility updates for Google APP Engine
+ https://github.com/guzzle/guzzle/pull/1216
+* Feature: Added support for NO_PROXY to prevent the use of a proxy based on
+ a simple set of rules. https://github.com/guzzle/guzzle/pull/1197
+* Feature: Cookies can now contain square brackets.
+ https://github.com/guzzle/guzzle/pull/1237
+* Bug fix: Now correctly parsing `=` inside of quotes in Cookies.
+ https://github.com/guzzle/guzzle/pull/1232
+* Bug fix: Cusotm cURL options now correctly override curl options of the
+ same name. https://github.com/guzzle/guzzle/pull/1221
+* Bug fix: Content-Type header is now added when using an explicitly provided
+ multipart body. https://github.com/guzzle/guzzle/pull/1218
+* Bug fix: Now ignoring Set-Cookie headers that have no name.
+* Bug fix: Reason phrase is no longer cast to an int in some cases in the
+ cURL handler. https://github.com/guzzle/guzzle/pull/1187
+* Bug fix: Remove the Authorization header when redirecting if the Host
+ header changes. https://github.com/guzzle/guzzle/pull/1207
+* Bug fix: Cookie path matching fixes
+ https://github.com/guzzle/guzzle/issues/1129
+* Bug fix: Fixing the cURL `body_as_string` setting
+ https://github.com/guzzle/guzzle/pull/1201
+* Bug fix: quotes are no longer stripped when parsing cookies.
+ https://github.com/guzzle/guzzle/issues/1172
+* Bug fix: `form_params` and `query` now always uses the `&` separator.
+ https://github.com/guzzle/guzzle/pull/1163
+* Bug fix: Adding a Content-Length to PHP stream wrapper requests if not set.
+ https://github.com/guzzle/guzzle/pull/1189
+
+## 6.0.2 - 2015-07-04
+
+* Fixed a memory leak in the curl handlers in which references to callbacks
+ were not being removed by `curl_reset`.
+* Cookies are now extracted properly before redirects.
+* Cookies now allow more character ranges.
+* Decoded Content-Encoding responses are now modified to correctly reflect
+ their state if the encoding was automatically removed by a handler. This
+ means that the `Content-Encoding` header may be removed an the
+ `Content-Length` modified to reflect the message size after removing the
+ encoding.
+* Added a more explicit error message when trying to use `form_params` and
+ `multipart` in the same request.
+* Several fixes for HHVM support.
+* Functions are now conditionally required using an additional level of
+ indirection to help with global Composer installations.
+
+## 6.0.1 - 2015-05-27
+
+* Fixed a bug with serializing the `query` request option where the `&`
+ separator was missing.
+* Added a better error message for when `body` is provided as an array. Please
+ use `form_params` or `multipart` instead.
+* Various doc fixes.
+
+## 6.0.0 - 2015-05-26
+
+* See the UPGRADING.md document for more information.
+* Added `multipart` and `form_params` request options.
+* Added `synchronous` request option.
+* Added the `on_headers` request option.
+* Fixed `expect` handling.
+* No longer adding default middlewares in the client ctor. These need to be
+ present on the provided handler in order to work.
+* Requests are no longer initiated when sending async requests with the
+ CurlMultiHandler. This prevents unexpected recursion from requests completing
+ while ticking the cURL loop.
+* Removed the semantics of setting `default` to `true`. This is no longer
+ required now that the cURL loop is not ticked for async requests.
+* Added request and response logging middleware.
+* No longer allowing self signed certificates when using the StreamHandler.
+* Ensuring that `sink` is valid if saving to a file.
+* Request exceptions now include a "handler context" which provides handler
+ specific contextual information.
+* Added `GuzzleHttp\RequestOptions` to allow request options to be applied
+ using constants.
+* `$maxHandles` has been removed from CurlMultiHandler.
+* `MultipartPostBody` is now part of the `guzzlehttp/psr7` package.
+
+## 5.3.0 - 2015-05-19
+
+* Mock now supports `save_to`
+* Marked `AbstractRequestEvent::getTransaction()` as public.
+* Fixed a bug in which multiple headers using different casing would overwrite
+ previous headers in the associative array.
+* Added `Utils::getDefaultHandler()`
+* Marked `GuzzleHttp\Client::getDefaultUserAgent` as deprecated.
+* URL scheme is now always lowercased.
+
+## 6.0.0-beta.1
+
+* Requires PHP >= 5.5
+* Updated to use PSR-7
+ * Requires immutable messages, which basically means an event based system
+ owned by a request instance is no longer possible.
+ * Utilizing the [Guzzle PSR-7 package](https://github.com/guzzle/psr7).
+ * Removed the dependency on `guzzlehttp/streams`. These stream abstractions
+ are available in the `guzzlehttp/psr7` package under the `GuzzleHttp\Psr7`
+ namespace.
+* Added middleware and handler system
+ * Replaced the Guzzle event and subscriber system with a middleware system.
+ * No longer depends on RingPHP, but rather places the HTTP handlers directly
+ in Guzzle, operating on PSR-7 messages.
+ * Retry logic is now encapsulated in `GuzzleHttp\Middleware::retry`, which
+ means the `guzzlehttp/retry-subscriber` is now obsolete.
+ * Mocking responses is now handled using `GuzzleHttp\Handler\MockHandler`.
+* Asynchronous responses
+ * No longer supports the `future` request option to send an async request.
+ Instead, use one of the `*Async` methods of a client (e.g., `requestAsync`,
+ `getAsync`, etc.).
+ * Utilizing `GuzzleHttp\Promise` instead of React's promise library to avoid
+ recursion required by chaining and forwarding react promises. See
+ https://github.com/guzzle/promises
+ * Added `requestAsync` and `sendAsync` to send request asynchronously.
+ * Added magic methods for `getAsync()`, `postAsync()`, etc. to send requests
+ asynchronously.
+* Request options
+ * POST and form updates
+ * Added the `form_fields` and `form_files` request options.
+ * Removed the `GuzzleHttp\Post` namespace.
+ * The `body` request option no longer accepts an array for POST requests.
+ * The `exceptions` request option has been deprecated in favor of the
+ `http_errors` request options.
+ * The `save_to` request option has been deprecated in favor of `sink` request
+ option.
+* Clients no longer accept an array of URI template string and variables for
+ URI variables. You will need to expand URI templates before passing them
+ into a client constructor or request method.
+* Client methods `get()`, `post()`, `put()`, `patch()`, `options()`, etc. are
+ now magic methods that will send synchronous requests.
+* Replaced `Utils.php` with plain functions in `functions.php`.
+* Removed `GuzzleHttp\Collection`.
+* Removed `GuzzleHttp\BatchResults`. Batched pool results are now returned as
+ an array.
+* Removed `GuzzleHttp\Query`. Query string handling is now handled using an
+ associative array passed into the `query` request option. The query string
+ is serialized using PHP's `http_build_query`. If you need more control, you
+ can pass the query string in as a string.
+* `GuzzleHttp\QueryParser` has been replaced with the
+ `GuzzleHttp\Psr7\parse_query`.
+
+## 5.2.0 - 2015-01-27
+
+* Added `AppliesHeadersInterface` to make applying headers to a request based
+ on the body more generic and not specific to `PostBodyInterface`.
+* Reduced the number of stack frames needed to send requests.
+* Nested futures are now resolved in the client rather than the RequestFsm
+* Finishing state transitions is now handled in the RequestFsm rather than the
+ RingBridge.
+* Added a guard in the Pool class to not use recursion for request retries.
+
+## 5.1.0 - 2014-12-19
+
+* Pool class no longer uses recursion when a request is intercepted.
+* The size of a Pool can now be dynamically adjusted using a callback.
+ See https://github.com/guzzle/guzzle/pull/943.
+* Setting a request option to `null` when creating a request with a client will
+ ensure that the option is not set. This allows you to overwrite default
+ request options on a per-request basis.
+ See https://github.com/guzzle/guzzle/pull/937.
+* Added the ability to limit which protocols are allowed for redirects by
+ specifying a `protocols` array in the `allow_redirects` request option.
+* Nested futures due to retries are now resolved when waiting for synchronous
+ responses. See https://github.com/guzzle/guzzle/pull/947.
+* `"0"` is now an allowed URI path. See
+ https://github.com/guzzle/guzzle/pull/935.
+* `Query` no longer typehints on the `$query` argument in the constructor,
+ allowing for strings and arrays.
+* Exceptions thrown in the `end` event are now correctly wrapped with Guzzle
+ specific exceptions if necessary.
+
+## 5.0.3 - 2014-11-03
+
+This change updates query strings so that they are treated as un-encoded values
+by default where the value represents an un-encoded value to send over the
+wire. A Query object then encodes the value before sending over the wire. This
+means that even value query string values (e.g., ":") are url encoded. This
+makes the Query class match PHP's http_build_query function. However, if you
+want to send requests over the wire using valid query string characters that do
+not need to be encoded, then you can provide a string to Url::setQuery() and
+pass true as the second argument to specify that the query string is a raw
+string that should not be parsed or encoded (unless a call to getQuery() is
+subsequently made, forcing the query-string to be converted into a Query
+object).
+
+## 5.0.2 - 2014-10-30
+
+* Added a trailing `\r\n` to multipart/form-data payloads. See
+ https://github.com/guzzle/guzzle/pull/871
+* Added a `GuzzleHttp\Pool::send()` convenience method to match the docs.
+* Status codes are now returned as integers. See
+ https://github.com/guzzle/guzzle/issues/881
+* No longer overwriting an existing `application/x-www-form-urlencoded` header
+ when sending POST requests, allowing for customized headers. See
+ https://github.com/guzzle/guzzle/issues/877
+* Improved path URL serialization.
+
+ * No longer double percent-encoding characters in the path or query string if
+ they are already encoded.
+ * Now properly encoding the supplied path to a URL object, instead of only
+ encoding ' ' and '?'.
+ * 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
+
+## 5.0.1 - 2014-10-16
+
+Bugfix release.
+
+* Fixed an issue where connection errors still returned response object in
+ error and end events event though the response is unusable. This has been
+ corrected so that a response is not returned in the `getResponse` method of
+ these events if the response did not complete. https://github.com/guzzle/guzzle/issues/867
+* Fixed an issue where transfer statistics were not being populated in the
+ RingBridge. https://github.com/guzzle/guzzle/issues/866
+
+## 5.0.0 - 2014-10-12
+
+Adding support for non-blocking responses and some minor API cleanup.
+
+### New Features
+
+* Added support for non-blocking responses based on `guzzlehttp/guzzle-ring`.
+* Added a public API for creating a default HTTP adapter.
+* Updated the redirect plugin to be non-blocking so that redirects are sent
+ concurrently. Other plugins like this can now be updated to be non-blocking.
+* Added a "progress" event so that you can get upload and download progress
+ events.
+* Added `GuzzleHttp\Pool` which implements FutureInterface and transfers
+ requests concurrently using a capped pool size as efficiently as possible.
+* Added `hasListeners()` to EmitterInterface.
+* Removed `GuzzleHttp\ClientInterface::sendAll` and marked
+ `GuzzleHttp\Client::sendAll` as deprecated (it's still there, just not the
+ recommended way).
+
+### Breaking changes
+
+The breaking changes in this release are relatively minor. The biggest thing to
+look out for is that request and response objects no longer implement fluent
+interfaces.
+
+* Removed the fluent interfaces (i.e., `return $this`) from requests,
+ 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/.
+ 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
+ for the HTTP request functions from function.php, these functions are now
+ implemented in `GuzzleHttp\Utils` using camelCase. `GuzzleHttp\json_decode`
+ moved to `GuzzleHttp\Utils::jsonDecode`. `GuzzleHttp\get_path` moved to
+ `GuzzleHttp\Utils::getPath`. `GuzzleHttp\set_path` moved to
+ `GuzzleHttp\Utils::setPath`. `GuzzleHttp\batch` should now be
+ `GuzzleHttp\Pool::batch`, which returns an `objectStorage`. Using functions.php
+ caused problems for many users: they aren't PSR-4 compliant, require an
+ explicit include, and needed an if-guard to ensure that the functions are not
+ declared multiple times.
+* Rewrote adapter layer.
+ * Removing all classes from `GuzzleHttp\Adapter`, these are now
+ implemented as callables that are stored in `GuzzleHttp\Ring\Client`.
+ * Removed the concept of "parallel adapters". Sending requests serially or
+ concurrently is now handled using a single adapter.
+ * Moved `GuzzleHttp\Adapter\Transaction` to `GuzzleHttp\Transaction`. The
+ Transaction object now exposes the request, response, and client as public
+ properties. The getters and setters have been removed.
+* Removed the "headers" event. This event was only useful for changing the
+ body a response once the headers of the response were known. You can implement
+ a similar behavior in a number of ways. One example might be to use a
+ FnStream that has access to the transaction being sent. For example, when the
+ first byte is written, you could check if the response headers match your
+ expectations, and if so, change the actual stream body that is being
+ written to.
+* Removed the `asArray` parameter from
+ `GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
+ value as an array, then use the newly added `getHeaderAsArray()` method of
+ `MessageInterface`. This change makes the Guzzle interfaces compatible with
+ the PSR-7 interfaces.
+* `GuzzleHttp\Message\MessageFactory` no longer allows subclasses to add
+ custom request options using double-dispatch (this was an implementation
+ detail). Instead, you should now provide an associative array to the
+ constructor which is a mapping of the request option name mapping to a
+ function that applies the option value to a request.
+* Removed the concept of "throwImmediately" from exceptions and error events.
+ This control mechanism was used to stop a transfer of concurrent requests
+ from completing. This can now be handled by throwing the exception or by
+ cancelling a pool of requests or each outstanding future request individually.
+* Updated to "GuzzleHttp\Streams" 3.0.
+ * `GuzzleHttp\Stream\StreamInterface::getContents()` no longer accepts a
+ `maxLen` parameter. This update makes the Guzzle streams project
+ compatible with the current PSR-7 proposal.
+ * `GuzzleHttp\Stream\Stream::__construct`,
+ `GuzzleHttp\Stream\Stream::factory`, and
+ `GuzzleHttp\Stream\Utils::create` no longer accept a size in the second
+ argument. They now accept an associative array of options, including the
+ "size" key and "metadata" key which can be used to provide custom metadata.
+
+## 4.2.2 - 2014-09-08
+
+* Fixed a memory leak in the CurlAdapter when reusing cURL handles.
+* No longer using `request_fulluri` in stream adapter proxies.
+* Relative redirects are now based on the last response, not the first response.
+
+## 4.2.1 - 2014-08-19
+
+* Ensuring that the StreamAdapter does not always add a Content-Type header
+* Adding automated github releases with a phar and zip
+
+## 4.2.0 - 2014-08-17
+
+* Now merging in default options using a case-insensitive comparison.
+ Closes https://github.com/guzzle/guzzle/issues/767
+* Added the ability to automatically decode `Content-Encoding` response bodies
+ using the `decode_content` request option. This is set to `true` by default
+ to decode the response body if it comes over the wire with a
+ `Content-Encoding`. Set this value to `false` to disable decoding the
+ response content, and pass a string to provide a request `Accept-Encoding`
+ header and turn on automatic response decoding. This feature now allows you
+ to pass an `Accept-Encoding` header in the headers of a request but still
+ disable automatic response decoding.
+ Closes https://github.com/guzzle/guzzle/issues/764
+* Added the ability to throw an exception immediately when transferring
+ requests in parallel. Closes https://github.com/guzzle/guzzle/issues/760
+* Updating guzzlehttp/streams dependency to ~2.1
+* No longer utilizing the now deprecated namespaced methods from the stream
+ package.
+
+## 4.1.8 - 2014-08-14
+
+* Fixed an issue in the CurlFactory that caused setting the `stream=false`
+ request option to throw an exception.
+ See: https://github.com/guzzle/guzzle/issues/769
+* TransactionIterator now calls rewind on the inner iterator.
+ See: https://github.com/guzzle/guzzle/pull/765
+* You can now set the `Content-Type` header to `multipart/form-data`
+ when creating POST requests to force multipart bodies.
+ See https://github.com/guzzle/guzzle/issues/768
+
+## 4.1.7 - 2014-08-07
+
+* Fixed an error in the HistoryPlugin that caused the same request and response
+ to be logged multiple times when an HTTP protocol error occurs.
+* Ensuring that cURL does not add a default Content-Type when no Content-Type
+ has been supplied by the user. This prevents the adapter layer from modifying
+ the request that is sent over the wire after any listeners may have already
+ put the request in a desired state (e.g., signed the request).
+* Throwing an exception when you attempt to send requests that have the
+ "stream" set to true in parallel using the MultiAdapter.
+* Only calling curl_multi_select when there are active cURL handles. This was
+ previously changed and caused performance problems on some systems due to PHP
+ always selecting until the maximum select timeout.
+* Fixed a bug where multipart/form-data POST fields were not correctly
+ aggregated (e.g., values with "&").
+
+## 4.1.6 - 2014-08-03
+
+* Added helper methods to make it easier to represent messages as strings,
+ including getting the start line and getting headers as a string.
+
+## 4.1.5 - 2014-08-02
+
+* Automatically retrying cURL "Connection died, retrying a fresh connect"
+ errors when possible.
+* cURL implementation cleanup
+* Allowing multiple event subscriber listeners to be registered per event by
+ passing an array of arrays of listener configuration.
+
+## 4.1.4 - 2014-07-22
+
+* Fixed a bug that caused multi-part POST requests with more than one field to
+ serialize incorrectly.
+* Paths can now be set to "0"
+* `ResponseInterface::xml` now accepts a `libxml_options` option and added a
+ missing default argument that was required when parsing XML response bodies.
+* A `save_to` stream is now created lazily, which means that files are not
+ created on disk unless a request succeeds.
+
+## 4.1.3 - 2014-07-15
+
+* Various fixes to multipart/form-data POST uploads
+* Wrapping function.php in an if-statement to ensure Guzzle can be used
+ globally and in a Composer install
+* Fixed an issue with generating and merging in events to an event array
+* POST headers are only applied before sending a request to allow you to change
+ the query aggregator used before uploading
+* Added much more robust query string parsing
+* Fixed various parsing and normalization issues with URLs
+* Fixing an issue where multi-valued headers were not being utilized correctly
+ in the StreamAdapter
+
+## 4.1.2 - 2014-06-18
+
+* Added support for sending payloads with GET requests
+
+## 4.1.1 - 2014-06-08
+
+* Fixed an issue related to using custom message factory options in subclasses
+* Fixed an issue with nested form fields in a multi-part POST
+* Fixed an issue with using the `json` request option for POST requests
+* Added `ToArrayInterface` to `GuzzleHttp\Cookie\CookieJar`
+
+## 4.1.0 - 2014-05-27
+
+* Added a `json` request option to easily serialize JSON payloads.
+* Added a `GuzzleHttp\json_decode()` wrapper to safely parse JSON.
+* Added `setPort()` and `getPort()` to `GuzzleHttp\Message\RequestInterface`.
+* Added the ability to provide an emitter to a client in the client constructor.
+* Added the ability to persist a cookie session using $_SESSION.
+* Added a trait that can be used to add event listeners to an iterator.
+* Removed request method constants from RequestInterface.
+* Fixed warning when invalid request start-lines are received.
+* Updated MessageFactory to work with custom request option methods.
+* Updated cacert bundle to latest build.
+
+4.0.2 (2014-04-16)
+------------------
+
+* Proxy requests using the StreamAdapter now properly use request_fulluri (#632)
+* Added the ability to set scalars as POST fields (#628)
+
+## 4.0.1 - 2014-04-04
+
+* The HTTP status code of a response is now set as the exception code of
+ RequestException objects.
+* 303 redirects will now correctly switch from POST to GET requests.
+* The default parallel adapter of a client now correctly uses the MultiAdapter.
+* HasDataTrait now initializes the internal data array as an empty array so
+ that the toArray() method always returns an array.
+
+## 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
+ parallel without needing to write asynchronous code.
+* Restructured how events are added to `GuzzleHttp\ClientInterface::sendAll()`.
+ You can now pass a callable or an array of associative arrays where each
+ associative array contains the "fn", "priority", and "once" keys.
+
+## 4.0.0.rc-2 - 2014-03-25
+
+* Removed `getConfig()` and `setConfig()` from clients to avoid confusion
+ around whether things like base_url, message_factory, etc. should be able to
+ be retrieved or modified.
+* Added `getDefaultOption()` and `setDefaultOption()` to ClientInterface
+* functions.php functions were renamed using snake_case to match PHP idioms
+* Added support for `HTTP_PROXY`, `HTTPS_PROXY`, and
+ `GUZZLE_CURL_SELECT_TIMEOUT` environment variables
+* Added the ability to specify custom `sendAll()` event priorities
+* Added the ability to specify custom stream context options to the stream
+ adapter.
+* Added a functions.php function for `get_path()` and `set_path()`
+* CurlAdapter and MultiAdapter now use a callable to generate curl resources
+* MockAdapter now properly reads a body and emits a `headers` event
+* Updated Url class to check if a scheme and host are set before adding ":"
+ and "//". This allows empty Url (e.g., "") to be serialized as "".
+* Parsing invalid XML no longer emits warnings
+* Curl classes now properly throw AdapterExceptions
+* Various performance optimizations
+* Streams are created with the faster `Stream\create()` function
+* Marked deprecation_proxy() as internal
+* Test server is now a collection of static methods on a class
+
+## 4.0.0-rc.1 - 2014-03-15
+
+* See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40
+
+## 3.8.1 - 2014-01-28
+
+* Bug: Always using GET requests when redirecting from a 303 response
+* Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in
+ `Guzzle\Http\ClientInterface::setSslVerification()`
+* Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL
+* Bug: The body of a request can now be set to `"0"`
+* Sending PHP stream requests no longer forces `HTTP/1.0`
+* Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of
+ each sub-exception
+* Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than
+ clobbering everything).
+* Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators)
+* Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`.
+ For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`.
+* Now properly escaping the regular expression delimiter when matching Cookie domains.
+* Network access is now disabled when loading XML documents
+
+## 3.8.0 - 2013-12-05
+
+* Added the ability to define a POST name for a file
+* JSON response parsing now properly walks additionalProperties
+* cURL error code 18 is now retried automatically in the BackoffPlugin
+* Fixed a cURL error when URLs contain fragments
+* Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were
+ CurlExceptions
+* CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e)
+* Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS`
+* Fixed a bug that was encountered when parsing empty header parameters
+* UriTemplate now has a `setRegex()` method to match the docs
+* The `debug` request parameter now checks if it is truthy rather than if it exists
+* Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin
+* Added the ability to combine URLs using strict RFC 3986 compliance
+* Command objects can now return the validation errors encountered by the command
+* Various fixes to cache revalidation (#437 and 29797e5)
+* Various fixes to the AsyncPlugin
+* Cleaned up build scripts
+
+## 3.7.4 - 2013-10-02
+
+* Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430)
+* Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp
+ (see https://github.com/aws/aws-sdk-php/issues/147)
+* Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots
+* Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420)
+* Updated the bundled cacert.pem (#419)
+* OauthPlugin now supports adding authentication to headers or query string (#425)
+
+## 3.7.3 - 2013-09-08
+
+* Added the ability to get the exception associated with a request/command when using `MultiTransferException` and
+ `CommandTransferException`.
+* Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description
+* Schemas are only injected into response models when explicitly configured.
+* No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of
+ an EntityBody.
+* Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator.
+* Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`.
+* Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody()
+* Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin
+* Bug fix: Visiting XML attributes first before visiting XML children when serializing requests
+* Bug fix: Properly parsing headers that contain commas contained in quotes
+* Bug fix: mimetype guessing based on a filename is now case-insensitive
+
+## 3.7.2 - 2013-08-02
+
+* Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander
+ See https://github.com/guzzle/guzzle/issues/371
+* Bug fix: Cookie domains are now matched correctly according to RFC 6265
+ See https://github.com/guzzle/guzzle/issues/377
+* Bug fix: GET parameters are now used when calculating an OAuth signature
+* Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted
+* `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched
+* `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input.
+ See https://github.com/guzzle/guzzle/issues/379
+* Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See
+ https://github.com/guzzle/guzzle/pull/380
+* cURL multi cleanup and optimizations
+
+## 3.7.1 - 2013-07-05
+
+* Bug fix: Setting default options on a client now works
+* Bug fix: Setting options on HEAD requests now works. See #352
+* Bug fix: Moving stream factory before send event to before building the stream. See #353
+* Bug fix: Cookies no longer match on IP addresses per RFC 6265
+* Bug fix: Correctly parsing header parameters that are in `<>` and quotes
+* Added `cert` and `ssl_key` as request options
+* `Host` header can now diverge from the host part of a URL if the header is set manually
+* `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter
+* OAuth parameters are only added via the plugin if they aren't already set
+* Exceptions are now thrown when a URL cannot be parsed
+* Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails
+* Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin
+
+## 3.7.0 - 2013-06-10
+
+* See UPGRADING.md for more information on how to upgrade.
+* Requests now support the ability to specify an array of $options when creating a request to more easily modify a
+ request. You can pass a 'request.options' configuration setting to a client to apply default request options to
+ every request created by a client (e.g. default query string variables, headers, curl options, etc.).
+* Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`.
+ See `Guzzle\Http\StaticClient::mount`.
+* Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests
+ created by a command (e.g. custom headers, query string variables, timeout settings, etc.).
+* Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the
+ headers of a response
+* Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key
+ (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`)
+* ServiceBuilders now support storing and retrieving arbitrary data
+* CachePlugin can now purge all resources for a given URI
+* CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource
+* CachePlugin now uses the Vary header to determine if a resource is a cache hit
+* `Guzzle\Http\Message\Response` now implements `\Serializable`
+* Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters
+* `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable
+* Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()`
+* Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size
+* `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message
+* Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older
+ Symfony users can still use the old version of Monolog.
+* Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`.
+ Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`.
+* Several performance improvements to `Guzzle\Common\Collection`
+* Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
+ createRequest, head, delete, put, patch, post, options, prepareRequest
+* Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
+* Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
+* Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
+* Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
+ default `array()`
+* Added `Guzzle\Stream\StreamInterface::isRepeatable`
+* Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
+ $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
+ $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`.
+* Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`.
+* Removed `Guzzle\Http\ClientInterface::expandTemplate()`
+* Removed `Guzzle\Http\ClientInterface::setRequestFactory()`
+* Removed `Guzzle\Http\ClientInterface::getCurlMulti()`
+* Removed `Guzzle\Http\Message\RequestInterface::canCache`
+* Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`
+* Removed `Guzzle\Http\Message\RequestInterface::isRedirect`
+* Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
+* You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting
+ `Guzzle\Common\Version::$emitWarnings` to true.
+* Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use
+ `$request->getResponseBody()->isRepeatable()` instead.
+* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use
+ `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+* Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
+* Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
+* Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
+* Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand.
+ These will work through Guzzle 4.0
+* Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params].
+* Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
+* Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`.
+* Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`.
+* Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
+* Marked `Guzzle\Common\Collection::inject()` as deprecated.
+* Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');`
+* CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
+* Always setting X-cache headers on cached responses
+* Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
+* `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
+ $request, Response $response);`
+* `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
+* `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
+* Added `CacheStorageInterface::purge($url)`
+* `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
+ CanCacheStrategyInterface $canCache = null)`
+* Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
+
+## 3.6.0 - 2013-05-29
+
+* ServiceDescription now implements ToArrayInterface
+* Added command.hidden_params to blacklist certain headers from being treated as additionalParameters
+* Guzzle can now correctly parse incomplete URLs
+* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
+* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
+* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
+* Specific header implementations can be created for complex headers. When a message creates a header, it uses a
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
+ CacheControl header implementation.
+* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
+* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
+* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
+ Guzzle\Http\Curl\RequestMediator
+* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
+* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
+* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
+* Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
+* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
+* All response header helper functions return a string rather than mixing Header objects and strings inconsistently
+* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
+ directly via interfaces
+* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
+ but are a no-op until removed.
+* Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a
+ `Guzzle\Service\Command\ArrayCommandInterface`.
+* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
+ on a request while the request is still being transferred
+* The ability to case-insensitively search for header values
+* Guzzle\Http\Message\Header::hasExactHeader
+* Guzzle\Http\Message\Header::raw. Use getAll()
+* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
+ instead.
+* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
+* Added the ability to cast Model objects to a string to view debug information.
+
+## 3.5.0 - 2013-05-13
+
+* Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times
+* Bug: Better cleanup of one-time events across the board (when an event is meant to fire once, it will now remove
+ itself from the EventDispatcher)
+* Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values
+* Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too
+* Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a
+ non-existent key
+* Bug: All __call() method arguments are now required (helps with mocking frameworks)
+* Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference
+ to help with refcount based garbage collection of resources created by sending a request
+* Deprecating ZF1 cache and log adapters. These will be removed in the next major version.
+* Deprecating `Response::getPreviousResponse()` (method signature still exists, but it's deprecated). Use the
+ HistoryPlugin for a history.
+* Added a `responseBody` alias for the `response_body` location
+* Refactored internals to no longer rely on Response::getRequest()
+* HistoryPlugin can now be cast to a string
+* HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests
+ and responses that are sent over the wire
+* Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects
+
+## 3.4.3 - 2013-04-30
+
+* Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response
+* Added a check to re-extract the temp cacert bundle from the phar before sending each request
+
+## 3.4.2 - 2013-04-29
+
+* Bug fix: Stream objects now work correctly with "a" and "a+" modes
+* Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present
+* Bug fix: AsyncPlugin no longer forces HEAD requests
+* Bug fix: DateTime timezones are now properly handled when using the service description schema formatter
+* Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails
+* Setting a response on a request will write to the custom request body from the response body if one is specified
+* LogPlugin now writes to php://output when STDERR is undefined
+* Added the ability to set multiple POST files for the same key in a single call
+* application/x-www-form-urlencoded POSTs now use the utf-8 charset by default
+* Added the ability to queue CurlExceptions to the MockPlugin
+* Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send)
+* Configuration loading now allows remote files
+
+## 3.4.1 - 2013-04-16
+
+* Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti
+ handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost.
+* Exceptions are now properly grouped when sending requests in parallel
+* Redirects are now properly aggregated when a multi transaction fails
+* Redirects now set the response on the original object even in the event of a failure
+* Bug fix: Model names are now properly set even when using $refs
+* Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax
+* Added support for oauth_callback in OAuth signatures
+* Added support for oauth_verifier in OAuth signatures
+* Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection
+
+## 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: 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.
+* Bug fix: Added `number` type to service descriptions.
+* Bug fix: empty parameters are removed from an OAuth signature
+* Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header
+* Bug fix: Fixed "array to string" error when validating a union of types in a service description
+* Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream
+* Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin.
+* Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs.
+* The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections.
+* Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if
+ the Content-Type can be determined based on the entity body or the path of the request.
+* Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder.
+* Added support for a PSR-3 LogAdapter.
+* Added a `command.after_prepare` event
+* Added `oauth_callback` parameter to the OauthPlugin
+* Added the ability to create a custom stream class when using a stream factory
+* Added a CachingEntityBody decorator
+* Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized.
+* The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar.
+* You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies
+* POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This
+ means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use
+ POST fields or files (the latter is only used when emulating a form POST in the browser).
+* Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest
+
+## 3.3.1 - 2013-03-10
+
+* Added the ability to create PHP streaming responses from HTTP requests
+* Bug fix: Running any filters when parsing response headers with service descriptions
+* Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing
+* Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across
+ response location visitors.
+* Bug fix: Removed the possibility of creating configuration files with circular dependencies
+* RequestFactory::create() now uses the key of a POST file when setting the POST file name
+* Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set
+
+## 3.3.0 - 2013-03-03
+
+* A large number of performance optimizations have been made
+* Bug fix: Added 'wb' as a valid write mode for streams
+* Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned
+* Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()`
+* BC: Removed `Guzzle\Http\Utils` class
+* BC: Setting a service description on a client will no longer modify the client's command factories.
+* BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using
+ the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
+* BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to
+ lowercase
+* Operation parameter objects are now lazy loaded internally
+* Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses
+* Added support for instantiating responseType=class responseClass classes. Classes must implement
+ `Guzzle\Service\Command\ResponseClassInterface`
+* Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These
+ additional properties also support locations and can be used to parse JSON responses where the outermost part of the
+ JSON is an array
+* Added support for nested renaming of JSON models (rename sentAs to name)
+* CachePlugin
+ * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error
+ * Debug headers can now added to cached response in the CachePlugin
+
+## 3.2.0 - 2013-02-14
+
+* CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients.
+* URLs with no path no longer contain a "/" by default
+* Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url.
+* BadResponseException no longer includes the full request and response message
+* Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface
+* Adding getResponseBody() to Guzzle\Http\Message\RequestInterface
+* Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription
+* Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list
+* xmlEncoding can now be customized for the XML declaration of a XML service description operation
+* Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value
+ aggregation and no longer uses callbacks
+* The URL encoding implementation of Guzzle\Http\QueryString can now be customized
+* Bug fix: Filters were not always invoked for array service description parameters
+* Bug fix: Redirects now use a target response body rather than a temporary response body
+* Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded
+* Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives
+
+## 3.1.2 - 2013-01-27
+
+* Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the
+ response body. For example, the XmlVisitor now parses the XML response into an array in the before() method.
+* Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent
+* CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444)
+* Fixed a bug where redirect responses were not chained correctly using getPreviousResponse()
+* Setting default headers on a client after setting the user-agent will not erase the user-agent setting
+
+## 3.1.1 - 2013-01-20
+
+* Adding wildcard support to Guzzle\Common\Collection::getPath()
+* Adding alias support to ServiceBuilder configs
+* Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface
+
+## 3.1.0 - 2013-01-12
+
+* BC: CurlException now extends from RequestException rather than BadResponseException
+* BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse()
+* Added getData to ServiceDescriptionInterface
+* Added context array to RequestInterface::setState()
+* Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http
+* Bug: Adding required content-type when JSON request visitor adds JSON to a command
+* Bug: Fixing the serialization of a service description with custom data
+* Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing
+ an array of successful and failed responses
+* Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection
+* Added Guzzle\Http\IoEmittingEntityBody
+* Moved command filtration from validators to location visitors
+* Added `extends` attributes to service description parameters
+* Added getModels to ServiceDescriptionInterface
+
+## 3.0.7 - 2012-12-19
+
+* Fixing phar detection when forcing a cacert to system if null or true
+* Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()`
+* Cleaning up `Guzzle\Common\Collection::inject` method
+* Adding a response_body location to service descriptions
+
+## 3.0.6 - 2012-12-09
+
+* CurlMulti performance improvements
+* Adding setErrorResponses() to Operation
+* composer.json tweaks
+
+## 3.0.5 - 2012-11-18
+
+* Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin
+* Bug: Response body can now be a string containing "0"
+* Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert
+* Bug: QueryString::fromString now properly parses query string parameters that contain equal signs
+* Added support for XML attributes in service description responses
+* DefaultRequestSerializer now supports array URI parameter values for URI template expansion
+* Added better mimetype guessing to requests and post files
+
+## 3.0.4 - 2012-11-11
+
+* Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value
+* Bug: Cookies can now be added that have a name, domain, or value set to "0"
+* Bug: Using the system cacert bundle when using the Phar
+* Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures
+* Enhanced cookie jar de-duplication
+* Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added
+* Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies
+* Added the ability to create any sort of hash for a stream rather than just an MD5 hash
+
+## 3.0.3 - 2012-11-04
+
+* Implementing redirects in PHP rather than cURL
+* Added PECL URI template extension and using as default parser if available
+* Bug: Fixed Content-Length parsing of Response factory
+* Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams.
+* Adding ToArrayInterface throughout library
+* Fixing OauthPlugin to create unique nonce values per request
+
+## 3.0.2 - 2012-10-25
+
+* Magic methods are enabled by default on clients
+* Magic methods return the result of a command
+* Service clients no longer require a base_url option in the factory
+* Bug: Fixed an issue with URI templates where null template variables were being expanded
+
+## 3.0.1 - 2012-10-22
+
+* Models can now be used like regular collection objects by calling filter, map, etc.
+* Models no longer require a Parameter structure or initial data in the constructor
+* Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator`
+
+## 3.0.0 - 2012-10-15
+
+* Rewrote service description format to be based on Swagger
+ * Now based on JSON schema
+ * Added nested input structures and nested response models
+ * Support for JSON and XML input and output models
+ * Renamed `commands` to `operations`
+ * Removed dot class notation
+ * Removed custom types
+* Broke the project into smaller top-level namespaces to be more component friendly
+* Removed support for XML configs and descriptions. Use arrays or JSON files.
+* Removed the Validation component and Inspector
+* Moved all cookie code to Guzzle\Plugin\Cookie
+* Magic methods on a Guzzle\Service\Client now return the command un-executed.
+* Calling getResult() or getResponse() on a command will lazily execute the command if needed.
+* Now shipping with cURL's CA certs and using it by default
+* Added previousResponse() method to response objects
+* No longer sending Accept and Accept-Encoding headers on every request
+* Only sending an Expect header by default when a payload is greater than 1MB
+* Added/moved client options:
+ * curl.blacklist to curl.option.blacklist
+ * Added ssl.certificate_authority
+* Added a Guzzle\Iterator component
+* Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin
+* Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin)
+* Added a more robust caching plugin
+* Added setBody to response objects
+* Updating LogPlugin to use a more flexible MessageFormatter
+* Added a completely revamped build process
+* Cleaning up Collection class and removing default values from the get method
+* Fixed ZF2 cache adapters
+
+## 2.8.8 - 2012-10-15
+
+* Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did
+
+## 2.8.7 - 2012-09-30
+
+* Bug: Fixed config file aliases for JSON includes
+* Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests
+* Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload
+* Bug: Hardening request and response parsing to account for missing parts
+* Bug: Fixed PEAR packaging
+* Bug: Fixed Request::getInfo
+* Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail
+* Adding the ability for the namespace Iterator factory to look in multiple directories
+* Added more getters/setters/removers from service descriptions
+* Added the ability to remove POST fields from OAuth signatures
+* OAuth plugin now supports 2-legged OAuth
+
+## 2.8.6 - 2012-09-05
+
+* Added the ability to modify and build service descriptions
+* Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command
+* Added a `json` parameter location
+* Now allowing dot notation for classes in the CacheAdapterFactory
+* Using the union of two arrays rather than an array_merge when extending service builder services and service params
+* Ensuring that a service is a string before doing strpos() checks on it when substituting services for references
+ in service builder config files.
+* Services defined in two different config files that include one another will by default replace the previously
+ defined service, but you can now create services that extend themselves and merge their settings over the previous
+* The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like
+ '_default' with a default JSON configuration file.
+
+## 2.8.5 - 2012-08-29
+
+* Bug: Suppressed empty arrays from URI templates
+* Bug: Added the missing $options argument from ServiceDescription::factory to enable caching
+* Added support for HTTP responses that do not contain a reason phrase in the start-line
+* AbstractCommand commands are now invokable
+* Added a way to get the data used when signing an Oauth request before a request is sent
+
+## 2.8.4 - 2012-08-15
+
+* Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin
+* Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable.
+* Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream
+* Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream
+* Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5())
+* Added additional response status codes
+* Removed SSL information from the default User-Agent header
+* DELETE requests can now send an entity body
+* Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries
+* Added the ability of the MockPlugin to consume mocked request bodies
+* LogPlugin now exposes request and response objects in the extras array
+
+## 2.8.3 - 2012-07-30
+
+* Bug: Fixed a case where empty POST requests were sent as GET requests
+* Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body
+* Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new
+* Added multiple inheritance to service description commands
+* Added an ApiCommandInterface and added `getParamNames()` and `hasParam()`
+* Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything
+* Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles
+
+## 2.8.2 - 2012-07-24
+
+* Bug: Query string values set to 0 are no longer dropped from the query string
+* Bug: A Collection object is no longer created each time a call is made to `Guzzle\Service\Command\AbstractCommand::getRequestHeaders()`
+* Bug: `+` is now treated as an encoded space when parsing query strings
+* QueryString and Collection performance improvements
+* Allowing dot notation for class paths in filters attribute of a service descriptions
+
+## 2.8.1 - 2012-07-16
+
+* Loosening Event Dispatcher dependency
+* POST redirects can now be customized using CURLOPT_POSTREDIR
+
+## 2.8.0 - 2012-07-15
+
+* BC: Guzzle\Http\Query
+ * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl)
+ * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding()
+ * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool)
+ * Changed the aggregation functions of QueryString to be static methods
+ * Can now use fromString() with querystrings that have a leading ?
+* cURL configuration values can be specified in service descriptions using `curl.` prefixed parameters
+* Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body
+* Cookies are no longer URL decoded by default
+* Bug: URI template variables set to null are no longer expanded
+
+## 2.7.2 - 2012-07-02
+
+* BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser.
+* BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty()
+* CachePlugin now allows for a custom request parameter function to check if a request can be cached
+* Bug fix: CachePlugin now only caches GET and HEAD requests by default
+* Bug fix: Using header glue when transferring headers over the wire
+* Allowing deeply nested arrays for composite variables in URI templates
+* Batch divisors can now return iterators or arrays
+
+## 2.7.1 - 2012-06-26
+
+* Minor patch to update version number in UA string
+* Updating build process
+
+## 2.7.0 - 2012-06-25
+
+* BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes.
+* BC: Removed magic setX methods from commands
+* BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method
+* Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable.
+* Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity)
+* Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace
+* Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin
+* Added the ability to set POST fields and files in a service description
+* Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method
+* Adding a command.before_prepare event to clients
+* Added BatchClosureTransfer and BatchClosureDivisor
+* BatchTransferException now includes references to the batch divisor and transfer strategies
+* Fixed some tests so that they pass more reliably
+* Added Guzzle\Common\Log\ArrayLogAdapter
+
+## 2.6.6 - 2012-06-10
+
+* BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin
+* BC: Removing Guzzle\Service\Command\CommandSet
+* Adding generic batching system (replaces the batch queue plugin and command set)
+* Updating ZF cache and log adapters and now using ZF's composer repository
+* Bug: Setting the name of each ApiParam when creating through an ApiCommand
+* Adding result_type, result_doc, deprecated, and doc_url to service descriptions
+* Bug: Changed the default cookie header casing back to 'Cookie'
+
+## 2.6.5 - 2012-06-03
+
+* BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource()
+* BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from
+* BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data
+* BC: Renaming methods in the CookieJarInterface
+* Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations
+* Making the default glue for HTTP headers ';' instead of ','
+* Adding a removeValue to Guzzle\Http\Message\Header
+* Adding getCookies() to request interface.
+* Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber()
+
+## 2.6.4 - 2012-05-30
+
+* BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class.
+* BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand
+* Bug: Fixing magic method command calls on clients
+* Bug: Email constraint only validates strings
+* Bug: Aggregate POST fields when POST files are present in curl handle
+* Bug: Fixing default User-Agent header
+* Bug: Only appending or prepending parameters in commands if they are specified
+* Bug: Not requiring response reason phrases or status codes to match a predefined list of codes
+* Allowing the use of dot notation for class namespaces when using instance_of constraint
+* Added any_match validation constraint
+* Added an AsyncPlugin
+* Passing request object to the calculateWait method of the ExponentialBackoffPlugin
+* Allowing the result of a command object to be changed
+* Parsing location and type sub values when instantiating a service description rather than over and over at runtime
+
+## 2.6.3 - 2012-05-23
+
+* [BC] Guzzle\Common\FromConfigInterface no longer requires any config options.
+* [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields.
+* You can now use an array of data when creating PUT request bodies in the request factory.
+* Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable.
+* [Http] Adding support for Content-Type in multipart POST uploads per upload
+* [Http] Added support for uploading multiple files using the same name (foo[0], foo[1])
+* Adding more POST data operations for easier manipulation of POST data.
+* You can now set empty POST fields.
+* The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files.
+* Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate.
+* CS updates
+
+## 2.6.2 - 2012-05-19
+
+* [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method.
+
+## 2.6.1 - 2012-05-19
+
+* [BC] Removing 'path' support in service descriptions. Use 'uri'.
+* [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache.
+* [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it.
+* [BC] Removing Guzzle\Common\XmlElement.
+* All commands, both dynamic and concrete, have ApiCommand objects.
+* Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits.
+* Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored.
+* Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible.
+
+## 2.6.0 - 2012-05-15
+
+* [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder
+* [BC] Executing a Command returns the result of the command rather than the command
+* [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed.
+* [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args.
+* [BC] Moving ResourceIterator* to Guzzle\Service\Resource
+* [BC] Completely refactored ResourceIterators to iterate over a cloned command object
+* [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate
+* [BC] Guzzle\Guzzle is now deprecated
+* Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject
+* Adding Guzzle\Version class to give version information about Guzzle
+* Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate()
+* Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data
+* ServiceDescription and ServiceBuilder are now cacheable using similar configs
+* Changing the format of XML and JSON service builder configs. Backwards compatible.
+* Cleaned up Cookie parsing
+* Trimming the default Guzzle User-Agent header
+* Adding a setOnComplete() method to Commands that is called when a command completes
+* Keeping track of requests that were mocked in the MockPlugin
+* Fixed a caching bug in the CacheAdapterFactory
+* Inspector objects can be injected into a Command object
+* Refactoring a lot of code and tests to be case insensitive when dealing with headers
+* Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL
+* Adding the ability to set global option overrides to service builder configs
+* Adding the ability to include other service builder config files from within XML and JSON files
+* Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method.
+
+## 2.5.0 - 2012-05-08
+
+* Major performance improvements
+* [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated.
+* [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component.
+* [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}"
+* Added the ability to passed parameters to all requests created by a client
+* Added callback functionality to the ExponentialBackoffPlugin
+* Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies.
+* Rewinding request stream bodies when retrying requests
+* Exception is thrown when JSON response body cannot be decoded
+* Added configurable magic method calls to clients and commands. This is off by default.
+* Fixed a defect that added a hash to every parsed URL part
+* Fixed duplicate none generation for OauthPlugin.
+* Emitting an event each time a client is generated by a ServiceBuilder
+* Using an ApiParams object instead of a Collection for parameters of an ApiCommand
+* cache.* request parameters should be renamed to params.cache.*
+* Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc.). See CurlHandle.
+* Added the ability to disable type validation of service descriptions
+* ServiceDescriptions and ServiceBuilders are now Serializable
diff --git a/akamai/vendor/guzzlehttp/guzzle/Dockerfile b/akamai/vendor/guzzlehttp/guzzle/Dockerfile
new file mode 100644
index 00000000..f6a09523
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/Dockerfile
@@ -0,0 +1,18 @@
+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 " --no-interaction \
+ && composer require guzzlehttp/guzzle
+
+
+FROM php:7.3
+
+RUN mkdir /guzzle
+
+WORKDIR /guzzle
+
+COPY --from=setup /guzzle /guzzle
diff --git a/akamai/vendor/guzzlehttp/guzzle/LICENSE b/akamai/vendor/guzzlehttp/guzzle/LICENSE
new file mode 100644
index 00000000..50a177b0
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/akamai/vendor/guzzlehttp/guzzle/README.md b/akamai/vendor/guzzlehttp/guzzle/README.md
new file mode 100644
index 00000000..a5ef18ae
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/README.md
@@ -0,0 +1,90 @@
+Guzzle, PHP HTTP client
+=======================
+
+[](https://github.com/guzzle/guzzle/releases)
+[](https://travis-ci.org/guzzle/guzzle)
+[](https://packagist.org/packages/guzzlehttp/guzzle)
+
+Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
+trivial to integrate with web services.
+
+- Simple interface for building query strings, POST requests, streaming large
+ uploads, streaming large downloads, using HTTP cookies, uploading JSON data,
+ etc...
+- 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.
+- 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.
+- Middleware system allows you to augment and compose client behavior.
+
+```php
+$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", ...}'
+
+# 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();
+});
+
+$promise->wait();
+```
+
+## Help and docs
+
+- [Documentation](http://guzzlephp.org/)
+- [Stack Overflow](http://stackoverflow.com/questions/tagged/guzzle)
+- [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:
+
+```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
+
+| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
+|---------|------------|---------------------|--------------|---------------------|---------------------|-------|-------------|
+| 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 | Maintained | `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 |
+
+[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-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/
diff --git a/akamai/vendor/guzzlehttp/guzzle/UPGRADING.md b/akamai/vendor/guzzlehttp/guzzle/UPGRADING.md
new file mode 100644
index 00000000..91d1dcc9
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/UPGRADING.md
@@ -0,0 +1,1203 @@
+Guzzle Upgrade Guide
+====================
+
+5.0 to 6.0
+----------
+
+Guzzle now uses [PSR-7](http://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
+updated to work with the new immutable PSR-7 request and response objects. Any
+event listeners or subscribers need to be updated to become middleware
+functions that wrap handlers (or are injected into a
+`GuzzleHttp\HandlerStack`).
+
+- Removed `GuzzleHttp\BatchResults`
+- Removed `GuzzleHttp\Collection`
+- Removed `GuzzleHttp\HasDataTrait`
+- Removed `GuzzleHttp\ToArrayInterface`
+- The `guzzlehttp/streams` dependency has been removed. Stream functionality
+ is now present in the `GuzzleHttp\Psr7` namespace provided by the
+ `guzzlehttp/psr7` package.
+- Guzzle no longer uses ReactPHP promises and now uses the
+ `guzzlehttp/promises` library. We use a custom promise library for three
+ significant reasons:
+ 1. React promises (at the time of writing this) are recursive. Promise
+ chaining and promise resolution will eventually blow the stack. Guzzle
+ promises are not recursive as they use a sort of trampolining technique.
+ Note: there has been movement in the React project to modify promises to
+ no longer utilize recursion.
+ 2. Guzzle needs to have the ability to synchronously block on a promise to
+ wait for a result. Guzzle promises allows this functionality (and does
+ not require the use of recursion).
+ 3. Because we need to be able to wait on a result, doing so using React
+ promises requires wrapping react promises with RingPHP futures. This
+ overhead is no longer needed, reducing stack sizes, reducing complexity,
+ and improving performance.
+- `GuzzleHttp\Mimetypes` has been moved to a function in
+ `GuzzleHttp\Psr7\mimetype_from_extension` and
+ `GuzzleHttp\Psr7\mimetype_from_filename`.
+- `GuzzleHttp\Query` and `GuzzleHttp\QueryParser` have been removed. Query
+ strings must now be passed into request objects as strings, or provided to
+ the `query` request option when creating requests with clients. The `query`
+ option uses PHP's `http_build_query` to convert an array to a string. If you
+ need a different serialization technique, you will need to pass the query
+ string in as a string. There are a couple helper functions that will make
+ working with query strings easier: `GuzzleHttp\Psr7\parse_query` and
+ `GuzzleHttp\Psr7\build_query`.
+- Guzzle no longer has a dependency on RingPHP. Due to the use of a middleware
+ system based on PSR-7, using RingPHP and it's middleware system as well adds
+ more complexity than the benefits it provides. All HTTP handlers that were
+ present in RingPHP have been modified to work directly with PSR-7 messages
+ and placed in the `GuzzleHttp\Handler` namespace. This significantly reduces
+ complexity in Guzzle, removes a dependency, and improves performance. RingPHP
+ will be maintained for Guzzle 5 support, but will no longer be a part of
+ Guzzle 6.
+- As Guzzle now uses a middleware based systems the event system and RingPHP
+ integration has been removed. Note: while the event system has been removed,
+ it is possible to add your own type of event system that is powered by the
+ middleware system.
+ - Removed the `Event` namespace.
+ - Removed the `Subscriber` namespace.
+ - Removed `Transaction` class
+ - Removed `RequestFsm`
+ - Removed `RingBridge`
+ - `GuzzleHttp\Subscriber\Cookie` is now provided by
+ `GuzzleHttp\Middleware::cookies`
+ - `GuzzleHttp\Subscriber\HttpError` is now provided by
+ `GuzzleHttp\Middleware::httpError`
+ - `GuzzleHttp\Subscriber\History` is now provided by
+ `GuzzleHttp\Middleware::history`
+ - `GuzzleHttp\Subscriber\Mock` is now provided by
+ `GuzzleHttp\Handler\MockHandler`
+ - `GuzzleHttp\Subscriber\Prepare` is now provided by
+ `GuzzleHttp\PrepareBodyMiddleware`
+ - `GuzzleHttp\Subscriber\Redirect` is now provided by
+ `GuzzleHttp\RedirectMiddleware`
+- Guzzle now uses `Psr\Http\Message\UriInterface` (implements in
+ `GuzzleHttp\Psr7\Uri`) for URI support. `GuzzleHttp\Url` is now gone.
+- Static functions in `GuzzleHttp\Utils` have been moved to namespaced
+ functions under the `GuzzleHttp` namespace. This requires either a Composer
+ based autoloader or you to include functions.php.
+- `GuzzleHttp\ClientInterface::getDefaultOption` has been renamed to
+ `GuzzleHttp\ClientInterface::getConfig`.
+- `GuzzleHttp\ClientInterface::setDefaultOption` has been removed.
+- The `json` and `xml` methods of response objects has been removed. With the
+ migration to strictly adhering to PSR-7 as the interface for Guzzle messages,
+ adding methods to message interfaces would actually require Guzzle messages
+ to extend from PSR-7 messages rather then work with them directly.
+
+## Migrating to middleware
+
+The change to PSR-7 unfortunately required significant refactoring to Guzzle
+due to the fact that PSR-7 messages are immutable. Guzzle 5 relied on an event
+system from plugins. The event system relied on mutability of HTTP messages and
+side effects in order to work. With immutable messages, you have to change your
+workflow to become more about either returning a value (e.g., functional
+middlewares) or setting a value on an object. Guzzle v6 has chosen the
+functional middleware approach.
+
+Instead of using the event system to listen for things like the `before` event,
+you now create a stack based middleware function that intercepts a request on
+the way in and the promise of the response on the way out. This is a much
+simpler and more predictable approach than the event system and works nicely
+with PSR-7 middleware. Due to the use of promises, the middleware system is
+also asynchronous.
+
+v5:
+
+```php
+use GuzzleHttp\Event\BeforeEvent;
+$client = new GuzzleHttp\Client();
+// Get the emitter and listen to the before event.
+$client->getEmitter()->on('before', function (BeforeEvent $e) {
+ // Guzzle v5 events relied on mutation
+ $e->getRequest()->setHeader('X-Foo', 'Bar');
+});
+```
+
+v6:
+
+In v6, you can modify the request before it is sent using the `mapRequest`
+middleware. The idiomatic way in v6 to modify the request/response lifecycle is
+to setup a handler middleware stack up front and inject the handler into a
+client.
+
+```php
+use GuzzleHttp\Middleware;
+// Create a handler stack that has all of the default middlewares attached
+$handler = GuzzleHttp\HandlerStack::create();
+// Push the handler onto the handler stack
+$handler->push(Middleware::mapRequest(function (RequestInterface $request) {
+ // Notice that we have to return a request object
+ return $request->withHeader('X-Foo', 'Bar');
+}));
+// Inject the handler into the client
+$client = new GuzzleHttp\Client(['handler' => $handler]);
+```
+
+## POST Requests
+
+This version added the [`form_params`](http://guzzle.readthedocs.org/en/latest/request-options.html#form_params)
+and `multipart` request options. `form_params` is an associative array of
+strings or array of strings and is used to serialize an
+`application/x-www-form-urlencoded` POST request. The
+[`multipart`](http://guzzle.readthedocs.org/en/latest/request-options.html#multipart)
+option is now used to send a multipart/form-data POST request.
+
+`GuzzleHttp\Post\PostFile` has been removed. Use the `multipart` option to add
+POST files to a multipart/form-data request.
+
+The `body` option no longer accepts an array to send POST requests. Please use
+`multipart` or `form_params` instead.
+
+The `base_url` option has been renamed to `base_uri`.
+
+4.x to 5.0
+----------
+
+## Rewritten Adapter Layer
+
+Guzzle now uses [RingPHP](http://ringphp.readthedocs.org/en/latest) to send
+HTTP requests. The `adapter` option in a `GuzzleHttp\Client` constructor
+is still supported, but it has now been renamed to `handler`. Instead of
+passing a `GuzzleHttp\Adapter\AdapterInterface`, you must now pass a PHP
+`callable` that follows the RingPHP specification.
+
+## Removed Fluent Interfaces
+
+[Fluent interfaces were removed](http://ocramius.github.io/blog/fluent-interfaces-are-evil)
+from the following classes:
+
+- `GuzzleHttp\Collection`
+- `GuzzleHttp\Url`
+- `GuzzleHttp\Query`
+- `GuzzleHttp\Post\PostBody`
+- `GuzzleHttp\Cookie\SetCookie`
+
+## Removed functions.php
+
+Removed "functions.php", so that Guzzle is truly PSR-4 compliant. The following
+functions can be used as replacements.
+
+- `GuzzleHttp\json_decode` -> `GuzzleHttp\Utils::jsonDecode`
+- `GuzzleHttp\get_path` -> `GuzzleHttp\Utils::getPath`
+- `GuzzleHttp\Utils::setPath` -> `GuzzleHttp\set_path`
+- `GuzzleHttp\Pool::batch` -> `GuzzleHttp\batch`. This function is, however,
+ deprecated in favor of using `GuzzleHttp\Pool::batch()`.
+
+The "procedural" global client has been removed with no replacement (e.g.,
+`GuzzleHttp\get()`, `GuzzleHttp\post()`, etc.). Use a `GuzzleHttp\Client`
+object as a replacement.
+
+## `throwImmediately` has been removed
+
+The concept of "throwImmediately" has been removed from exceptions and error
+events. This control mechanism was used to stop a transfer of concurrent
+requests from completing. This can now be handled by throwing the exception or
+by cancelling a pool of requests or each outstanding future request
+individually.
+
+## headers event has been removed
+
+Removed the "headers" event. This event was only useful for changing the
+body a response once the headers of the response were known. You can implement
+a similar behavior in a number of ways. One example might be to use a
+FnStream that has access to the transaction being sent. For example, when the
+first byte is written, you could check if the response headers match your
+expectations, and if so, change the actual stream body that is being
+written to.
+
+## Updates to HTTP Messages
+
+Removed the `asArray` parameter from
+`GuzzleHttp\Message\MessageInterface::getHeader`. If you want to get a header
+value as an array, then use the newly added `getHeaderAsArray()` method of
+`MessageInterface`. This change makes the Guzzle interfaces compatible with
+the PSR-7 interfaces.
+
+3.x to 4.0
+----------
+
+## Overarching changes:
+
+- Now requires PHP 5.4 or greater.
+- No longer requires cURL to send requests.
+- Guzzle no longer wraps every exception it throws. Only exceptions that are
+ recoverable are now wrapped by Guzzle.
+- Various namespaces have been removed or renamed.
+- No longer requiring the Symfony EventDispatcher. A custom event dispatcher
+ based on the Symfony EventDispatcher is
+ now utilized in `GuzzleHttp\Event\EmitterInterface` (resulting in significant
+ speed and functionality improvements).
+
+Changes per Guzzle 3.x namespace are described below.
+
+## Batch
+
+The `Guzzle\Batch` namespace has been removed. This is best left to
+third-parties to implement on top of Guzzle's core HTTP library.
+
+## Cache
+
+The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement
+has been implemented yet, but hoping to utilize a PSR cache interface).
+
+## Common
+
+- Removed all of the wrapped exceptions. It's better to use the standard PHP
+ library for unrecoverable exceptions.
+- `FromConfigInterface` has been removed.
+- `Guzzle\Common\Version` has been removed. The VERSION constant can be found
+ at `GuzzleHttp\ClientInterface::VERSION`.
+
+### Collection
+
+- `getAll` has been removed. Use `toArray` to convert a collection to an array.
+- `inject` has been removed.
+- `keySearch` has been removed.
+- `getPath` no longer supports wildcard expressions. Use something better like
+ JMESPath for this.
+- `setPath` now supports appending to an existing array via the `[]` notation.
+
+### Events
+
+Guzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses
+`GuzzleHttp\Event\Emitter`.
+
+- `Symfony\Component\EventDispatcher\EventDispatcherInterface` is replaced by
+ `GuzzleHttp\Event\EmitterInterface`.
+- `Symfony\Component\EventDispatcher\EventDispatcher` is replaced by
+ `GuzzleHttp\Event\Emitter`.
+- `Symfony\Component\EventDispatcher\Event` is replaced by
+ `GuzzleHttp\Event\Event`, and Guzzle now has an EventInterface in
+ `GuzzleHttp\Event\EventInterface`.
+- `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and
+ `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the
+ event emitter of a request, client, etc. now uses the `getEmitter` method
+ rather than the `getDispatcher` method.
+
+#### Emitter
+
+- Use the `once()` method to add a listener that automatically removes itself
+ the first time it is invoked.
+- Use the `listeners()` method to retrieve a list of event listeners rather than
+ the `getListeners()` method.
+- Use `emit()` instead of `dispatch()` to emit an event from an emitter.
+- Use `attach()` instead of `addSubscriber()` and `detach()` instead of
+ `removeSubscriber()`.
+
+```php
+$mock = new Mock();
+// 3.x
+$request->getEventDispatcher()->addSubscriber($mock);
+$request->getEventDispatcher()->removeSubscriber($mock);
+// 4.x
+$request->getEmitter()->attach($mock);
+$request->getEmitter()->detach($mock);
+```
+
+Use the `on()` method to add a listener rather than the `addListener()` method.
+
+```php
+// 3.x
+$request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } );
+// 4.x
+$request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } );
+```
+
+## Http
+
+### General changes
+
+- The cacert.pem certificate has been moved to `src/cacert.pem`.
+- Added the concept of adapters that are used to transfer requests over the
+ wire.
+- Simplified the event system.
+- Sending requests in parallel is still possible, but batching is no longer a
+ concept of the HTTP layer. Instead, you must use the `complete` and `error`
+ events to asynchronously manage parallel request transfers.
+- `Guzzle\Http\Url` has moved to `GuzzleHttp\Url`.
+- `Guzzle\Http\QueryString` has moved to `GuzzleHttp\Query`.
+- QueryAggregators have been rewritten so that they are simply callable
+ functions.
+- `GuzzleHttp\StaticClient` has been removed. Use the functions provided in
+ `functions.php` for an easy to use static client instance.
+- Exceptions in `GuzzleHttp\Exception` have been updated to all extend from
+ `GuzzleHttp\Exception\TransferException`.
+
+### Client
+
+Calling methods like `get()`, `post()`, `head()`, etc. no longer create and
+return a request, but rather creates a request, sends the request, and returns
+the response.
+
+```php
+// 3.0
+$request = $client->get('/');
+$response = $request->send();
+
+// 4.0
+$response = $client->get('/');
+
+// or, to mirror the previous behavior
+$request = $client->createRequest('GET', '/');
+$response = $client->send($request);
+```
+
+`GuzzleHttp\ClientInterface` has changed.
+
+- The `send` method no longer accepts more than one request. Use `sendAll` to
+ send multiple requests in parallel.
+- `setUserAgent()` has been removed. Use a default request option instead. You
+ could, for example, do something like:
+ `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`.
+- `setSslVerification()` has been removed. Use default request options instead,
+ like `$client->setConfig('defaults/verify', true)`.
+
+`GuzzleHttp\Client` has changed.
+
+- The constructor now accepts only an associative array. You can include a
+ `base_url` string or array to use a URI template as the base URL of a client.
+ You can also specify a `defaults` key that is an associative array of default
+ request options. You can pass an `adapter` to use a custom adapter,
+ `batch_adapter` to use a custom adapter for sending requests in parallel, or
+ a `message_factory` to change the factory used to create HTTP requests and
+ responses.
+- The client no longer emits a `client.create_request` event.
+- Creating requests with a client no longer automatically utilize a URI
+ template. You must pass an array into a creational method (e.g.,
+ `createRequest`, `get`, `put`, etc.) in order to expand a URI template.
+
+### Messages
+
+Messages no longer have references to their counterparts (i.e., a request no
+longer has a reference to it's response, and a response no loger has a
+reference to its request). This association is now managed through a
+`GuzzleHttp\Adapter\TransactionInterface` object. You can get references to
+these transaction objects using request events that are emitted over the
+lifecycle of a request.
+
+#### Requests with a body
+
+- `GuzzleHttp\Message\EntityEnclosingRequest` and
+ `GuzzleHttp\Message\EntityEnclosingRequestInterface` have been removed. The
+ separation between requests that contain a body and requests that do not
+ contain a body has been removed, and now `GuzzleHttp\Message\RequestInterface`
+ handles both use cases.
+- Any method that previously accepts a `GuzzleHttp\Response` object now accept a
+ `GuzzleHttp\Message\ResponseInterface`.
+- `GuzzleHttp\Message\RequestFactoryInterface` has been renamed to
+ `GuzzleHttp\Message\MessageFactoryInterface`. This interface is used to create
+ both requests and responses and is implemented in
+ `GuzzleHttp\Message\MessageFactory`.
+- POST field and file methods have been removed from the request object. You
+ must now use the methods made available to `GuzzleHttp\Post\PostBodyInterface`
+ to control the format of a POST body. Requests that are created using a
+ standard `GuzzleHttp\Message\MessageFactoryInterface` will automatically use
+ a `GuzzleHttp\Post\PostBody` body if the body was passed as an array or if
+ the method is POST and no body is provided.
+
+```php
+$request = $client->createRequest('POST', '/');
+$request->getBody()->setField('foo', 'bar');
+$request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r')));
+```
+
+#### Headers
+
+- `GuzzleHttp\Message\Header` has been removed. Header values are now simply
+ represented by an array of values or as a string. Header values are returned
+ as a string by default when retrieving a header value from a message. You can
+ pass an optional argument of `true` to retrieve a header value as an array
+ of strings instead of a single concatenated string.
+- `GuzzleHttp\PostFile` and `GuzzleHttp\PostFileInterface` have been moved to
+ `GuzzleHttp\Post`. This interface has been simplified and now allows the
+ addition of arbitrary headers.
+- Custom headers like `GuzzleHttp\Message\Header\Link` have been removed. Most
+ of the custom headers are now handled separately in specific
+ subscribers/plugins, and `GuzzleHttp\Message\HeaderValues::parseParams()` has
+ been updated to properly handle headers that contain parameters (like the
+ `Link` header).
+
+#### Responses
+
+- `GuzzleHttp\Message\Response::getInfo()` and
+ `GuzzleHttp\Message\Response::setInfo()` have been removed. Use the event
+ system to retrieve this type of information.
+- `GuzzleHttp\Message\Response::getRawHeaders()` has been removed.
+- `GuzzleHttp\Message\Response::getMessage()` has been removed.
+- `GuzzleHttp\Message\Response::calculateAge()` and other cache specific
+ methods have moved to the CacheSubscriber.
+- Header specific helper functions like `getContentMd5()` have been removed.
+ Just use `getHeader('Content-MD5')` instead.
+- `GuzzleHttp\Message\Response::setRequest()` and
+ `GuzzleHttp\Message\Response::getRequest()` have been removed. Use the event
+ system to work with request and response objects as a transaction.
+- `GuzzleHttp\Message\Response::getRedirectCount()` has been removed. Use the
+ Redirect subscriber instead.
+- `GuzzleHttp\Message\Response::isSuccessful()` and other related methods have
+ been removed. Use `getStatusCode()` instead.
+
+#### Streaming responses
+
+Streaming requests can now be created by a client directly, returning a
+`GuzzleHttp\Message\ResponseInterface` object that contains a body stream
+referencing an open PHP HTTP stream.
+
+```php
+// 3.0
+use Guzzle\Stream\PhpStreamRequestFactory;
+$request = $client->get('/');
+$factory = new PhpStreamRequestFactory();
+$stream = $factory->fromRequest($request);
+$data = $stream->read(1024);
+
+// 4.0
+$response = $client->get('/', ['stream' => true]);
+// Read some data off of the stream in the response body
+$data = $response->getBody()->read(1024);
+```
+
+#### Redirects
+
+The `configureRedirects()` method has been removed in favor of a
+`allow_redirects` request option.
+
+```php
+// Standard redirects with a default of a max of 5 redirects
+$request = $client->createRequest('GET', '/', ['allow_redirects' => true]);
+
+// Strict redirects with a custom number of redirects
+$request = $client->createRequest('GET', '/', [
+ 'allow_redirects' => ['max' => 5, 'strict' => true]
+]);
+```
+
+#### EntityBody
+
+EntityBody interfaces and classes have been removed or moved to
+`GuzzleHttp\Stream`. All classes and interfaces that once required
+`GuzzleHttp\EntityBodyInterface` now require
+`GuzzleHttp\Stream\StreamInterface`. Creating a new body for a request no
+longer uses `GuzzleHttp\EntityBody::factory` but now uses
+`GuzzleHttp\Stream\Stream::factory` or even better:
+`GuzzleHttp\Stream\create()`.
+
+- `Guzzle\Http\EntityBodyInterface` is now `GuzzleHttp\Stream\StreamInterface`
+- `Guzzle\Http\EntityBody` is now `GuzzleHttp\Stream\Stream`
+- `Guzzle\Http\CachingEntityBody` is now `GuzzleHttp\Stream\CachingStream`
+- `Guzzle\Http\ReadLimitEntityBody` is now `GuzzleHttp\Stream\LimitStream`
+- `Guzzle\Http\IoEmittyinEntityBody` has been removed.
+
+#### Request lifecycle events
+
+Requests previously submitted a large number of requests. The number of events
+emitted over the lifecycle of a request has been significantly reduced to make
+it easier to understand how to extend the behavior of a request. All events
+emitted during the lifecycle of a request now emit a custom
+`GuzzleHttp\Event\EventInterface` object that contains context providing
+methods and a way in which to modify the transaction at that specific point in
+time (e.g., intercept the request and set a response on the transaction).
+
+- `request.before_send` has been renamed to `before` and now emits a
+ `GuzzleHttp\Event\BeforeEvent`
+- `request.complete` has been renamed to `complete` and now emits a
+ `GuzzleHttp\Event\CompleteEvent`.
+- `request.sent` has been removed. Use `complete`.
+- `request.success` has been removed. Use `complete`.
+- `error` is now an event that emits a `GuzzleHttp\Event\ErrorEvent`.
+- `request.exception` has been removed. Use `error`.
+- `request.receive.status_line` has been removed.
+- `curl.callback.progress` has been removed. Use a custom `StreamInterface` to
+ maintain a status update.
+- `curl.callback.write` has been removed. Use a custom `StreamInterface` to
+ intercept writes.
+- `curl.callback.read` has been removed. Use a custom `StreamInterface` to
+ intercept reads.
+
+`headers` is a new event that is emitted after the response headers of a
+request have been received before the body of the response is downloaded. This
+event emits a `GuzzleHttp\Event\HeadersEvent`.
+
+You can intercept a request and inject a response using the `intercept()` event
+of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and
+`GuzzleHttp\Event\ErrorEvent` event.
+
+See: http://docs.guzzlephp.org/en/latest/events.html
+
+## Inflection
+
+The `Guzzle\Inflection` namespace has been removed. This is not a core concern
+of Guzzle.
+
+## Iterator
+
+The `Guzzle\Iterator` namespace has been removed.
+
+- `Guzzle\Iterator\AppendIterator`, `Guzzle\Iterator\ChunkedIterator`, and
+ `Guzzle\Iterator\MethodProxyIterator` are nice, but not a core requirement of
+ Guzzle itself.
+- `Guzzle\Iterator\FilterIterator` is no longer needed because an equivalent
+ class is shipped with PHP 5.4.
+- `Guzzle\Iterator\MapIterator` is not really needed when using PHP 5.5 because
+ it's easier to just wrap an iterator in a generator that maps values.
+
+For a replacement of these iterators, see https://github.com/nikic/iter
+
+## Log
+
+The LogPlugin has moved to https://github.com/guzzle/log-subscriber. The
+`Guzzle\Log` namespace has been removed. Guzzle now relies on
+`Psr\Log\LoggerInterface` for all logging. The MessageFormatter class has been
+moved to `GuzzleHttp\Subscriber\Log\Formatter`.
+
+## Parser
+
+The `Guzzle\Parser` namespace has been removed. This was previously used to
+make it possible to plug in custom parsers for cookies, messages, URI
+templates, and URLs; however, this level of complexity is not needed in Guzzle
+so it has been removed.
+
+- Cookie: Cookie parsing logic has been moved to
+ `GuzzleHttp\Cookie\SetCookie::fromString`.
+- Message: Message parsing logic for both requests and responses has been moved
+ to `GuzzleHttp\Message\MessageFactory::fromMessage`. Message parsing is only
+ used in debugging or deserializing messages, so it doesn't make sense for
+ Guzzle as a library to add this level of complexity to parsing messages.
+- UriTemplate: URI template parsing has been moved to
+ `GuzzleHttp\UriTemplate`. The Guzzle library will automatically use the PECL
+ URI template library if it is installed.
+- Url: URL parsing is now performed in `GuzzleHttp\Url::fromString` (previously
+ it was `Guzzle\Http\Url::factory()`). If custom URL parsing is necessary,
+ then developers are free to subclass `GuzzleHttp\Url`.
+
+## Plugin
+
+The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`.
+Several plugins are shipping with the core Guzzle library under this namespace.
+
+- `GuzzleHttp\Subscriber\Cookie`: Replaces the old CookiePlugin. Cookie jar
+ code has moved to `GuzzleHttp\Cookie`.
+- `GuzzleHttp\Subscriber\History`: Replaces the old HistoryPlugin.
+- `GuzzleHttp\Subscriber\HttpError`: Throws errors when a bad HTTP response is
+ received.
+- `GuzzleHttp\Subscriber\Mock`: Replaces the old MockPlugin.
+- `GuzzleHttp\Subscriber\Prepare`: Prepares the body of a request just before
+ sending. This subscriber is attached to all requests by default.
+- `GuzzleHttp\Subscriber\Redirect`: Replaces the RedirectPlugin.
+
+The following plugins have been removed (third-parties are free to re-implement
+these if needed):
+
+- `GuzzleHttp\Plugin\Async` has been removed.
+- `GuzzleHttp\Plugin\CurlAuth` has been removed.
+- `GuzzleHttp\Plugin\ErrorResponse\ErrorResponsePlugin` has been removed. This
+ functionality should instead be implemented with event listeners that occur
+ after normal response parsing occurs in the guzzle/command package.
+
+The following plugins are not part of the core Guzzle package, but are provided
+in separate repositories:
+
+- `Guzzle\Http\Plugin\BackoffPlugin` has been rewritten to be much simpler
+ to build custom retry policies using simple functions rather than various
+ chained classes. See: https://github.com/guzzle/retry-subscriber
+- `Guzzle\Http\Plugin\Cache\CachePlugin` has moved to
+ https://github.com/guzzle/cache-subscriber
+- `Guzzle\Http\Plugin\Log\LogPlugin` has moved to
+ https://github.com/guzzle/log-subscriber
+- `Guzzle\Http\Plugin\Md5\Md5Plugin` has moved to
+ https://github.com/guzzle/message-integrity-subscriber
+- `Guzzle\Http\Plugin\Mock\MockPlugin` has moved to
+ `GuzzleHttp\Subscriber\MockSubscriber`.
+- `Guzzle\Http\Plugin\Oauth\OauthPlugin` has moved to
+ https://github.com/guzzle/oauth-subscriber
+
+## Service
+
+The service description layer of Guzzle has moved into two separate packages:
+
+- http://github.com/guzzle/command Provides a high level abstraction over web
+ services by representing web service operations using commands.
+- http://github.com/guzzle/guzzle-services Provides an implementation of
+ guzzle/command that provides request serialization and response parsing using
+ Guzzle service descriptions.
+
+## Stream
+
+Stream have moved to a separate package available at
+https://github.com/guzzle/streams.
+
+`Guzzle\Stream\StreamInterface` has been given a large update to cleanly take
+on the responsibilities of `Guzzle\Http\EntityBody` and
+`Guzzle\Http\EntityBodyInterface` now that they have been removed. The number
+of methods implemented by the `StreamInterface` has been drastically reduced to
+allow developers to more easily extend and decorate stream behavior.
+
+## Removed methods from StreamInterface
+
+- `getStream` and `setStream` have been removed to better encapsulate streams.
+- `getMetadata` and `setMetadata` have been removed in favor of
+ `GuzzleHttp\Stream\MetadataStreamInterface`.
+- `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been
+ removed. This data is accessible when
+ using streams that implement `GuzzleHttp\Stream\MetadataStreamInterface`.
+- `rewind` has been removed. Use `seek(0)` for a similar behavior.
+
+## Renamed methods
+
+- `detachStream` has been renamed to `detach`.
+- `feof` has been renamed to `eof`.
+- `ftell` has been renamed to `tell`.
+- `readLine` has moved from an instance method to a static class method of
+ `GuzzleHttp\Stream\Stream`.
+
+## Metadata streams
+
+`GuzzleHttp\Stream\MetadataStreamInterface` has been added to denote streams
+that contain additional metadata accessible via `getMetadata()`.
+`GuzzleHttp\Stream\StreamInterface::getMetadata` and
+`GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed.
+
+## StreamRequestFactory
+
+The entire concept of the StreamRequestFactory has been removed. The way this
+was used in Guzzle 3 broke the actual interface of sending streaming requests
+(instead of getting back a Response, you got a StreamInterface). Streaming
+PHP requests are now implemented through the `GuzzleHttp\Adapter\StreamAdapter`.
+
+3.6 to 3.7
+----------
+
+### Deprecations
+
+- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.:
+
+```php
+\Guzzle\Common\Version::$emitWarnings = true;
+```
+
+The following APIs and options have been marked as deprecated:
+
+- Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead.
+- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead.
+- Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead.
+- Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead.
+- Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated
+- Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client.
+- Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8.
+- Marked `Guzzle\Common\Collection::inject()` as deprecated.
+- Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use
+ `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or
+ `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));`
+
+3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational
+request methods. When paired with a client's configuration settings, these options allow you to specify default settings
+for various aspects of a request. Because these options make other previous configuration options redundant, several
+configuration options and methods of a client and AbstractCommand have been deprecated.
+
+- Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`.
+- Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`.
+- Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')`
+- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0
+
+ $command = $client->getCommand('foo', array(
+ 'command.headers' => array('Test' => '123'),
+ 'command.response_body' => '/path/to/file'
+ ));
+
+ // Should be changed to:
+
+ $command = $client->getCommand('foo', array(
+ 'command.request_options' => array(
+ 'headers' => array('Test' => '123'),
+ 'save_as' => '/path/to/file'
+ )
+ ));
+
+### Interface changes
+
+Additions and changes (you will need to update any implementations or subclasses you may have created):
+
+- Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`:
+ createRequest, head, delete, put, patch, post, options, prepareRequest
+- Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()`
+- Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface`
+- Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to
+ `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a
+ resource, string, or EntityBody into the $options parameter to specify the download location of the response.
+- Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a
+ default `array()`
+- Added `Guzzle\Stream\StreamInterface::isRepeatable`
+- Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods.
+
+The following methods were removed from interfaces. All of these methods are still available in the concrete classes
+that implement them, but you should update your code to use alternative methods:
+
+- Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use
+ `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or
+ `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or
+ `$client->setDefaultOption('headers/{header_name}', 'value')`. or
+ `$client->setDefaultOption('headers', array('header_name' => 'value'))`.
+- Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`.
+- Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail.
+- Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail.
+- Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail.
+- Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin.
+- Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin.
+- Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin.
+
+### Cache plugin breaking changes
+
+- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a
+ CacheStorageInterface. These two objects and interface will be removed in a future version.
+- Always setting X-cache headers on cached responses
+- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin
+- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface
+ $request, Response $response);`
+- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);`
+- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);`
+- Added `CacheStorageInterface::purge($url)`
+- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin
+ $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache,
+ CanCacheStrategyInterface $canCache = null)`
+- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)`
+
+3.5 to 3.6
+----------
+
+* Mixed casing of headers are now forced to be a single consistent casing across all values for that header.
+* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution
+* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader().
+ For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader().
+ Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request.
+* Specific header implementations can be created for complex headers. When a message creates a header, it uses a
+ HeaderFactory which can map specific headers to specific header classes. There is now a Link header and
+ CacheControl header implementation.
+* Moved getLinks() from Response to just be used on a Link header object.
+
+If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the
+HeaderInterface (e.g. toArray(), getAll(), etc.).
+
+### Interface changes
+
+* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate
+* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti()
+* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in
+ Guzzle\Http\Curl\RequestMediator
+* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string.
+* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface
+* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders()
+
+### Removed deprecated functions
+
+* Removed Guzzle\Parser\ParserRegister::get(). Use getParser()
+* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser().
+
+### Deprecations
+
+* The ability to case-insensitively search for header values
+* Guzzle\Http\Message\Header::hasExactHeader
+* Guzzle\Http\Message\Header::raw. Use getAll()
+* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object
+ instead.
+
+### Other changes
+
+* All response header helper functions return a string rather than mixing Header objects and strings inconsistently
+* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc. are managed by Guzzle
+ directly via interfaces
+* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist
+ but are a no-op until removed.
+* Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a
+ `Guzzle\Service\Command\ArrayCommandInterface`.
+* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response
+ on a request while the request is still being transferred
+* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess
+
+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.
+
+3.2 to 3.3
+----------
+
+### Response::getEtag() quote stripping removed
+
+`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header
+
+### Removed `Guzzle\Http\Utils`
+
+The `Guzzle\Http\Utils` class was removed. This class was only used for testing.
+
+### Stream wrapper and type
+
+`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getStreamType()` are no longer converted to lowercase.
+
+### curl.emit_io became emit_io
+
+Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the
+'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io'
+
+3.1 to 3.2
+----------
+
+### CurlMulti is no longer reused globally
+
+Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added
+to a single client can pollute requests dispatched from other clients.
+
+If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the
+ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is
+created.
+
+```php
+$multi = new Guzzle\Http\Curl\CurlMulti();
+$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json');
+$builder->addListener('service_builder.create_client', function ($event) use ($multi) {
+ $event['client']->setCurlMulti($multi);
+}
+});
+```
+
+### No default path
+
+URLs no longer have a default path value of '/' if no path was specified.
+
+Before:
+
+```php
+$request = $client->get('http://www.foo.com');
+echo $request->getUrl();
+// >> http://www.foo.com/
+```
+
+After:
+
+```php
+$request = $client->get('http://www.foo.com');
+echo $request->getUrl();
+// >> http://www.foo.com
+```
+
+### Less verbose BadResponseException
+
+The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and
+response information. You can, however, get access to the request and response object by calling `getRequest()` or
+`getResponse()` on the exception object.
+
+### Query parameter aggregation
+
+Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a
+setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is
+responsible for handling the aggregation of multi-valued query string variables into a flattened hash.
+
+2.8 to 3.x
+----------
+
+### Guzzle\Service\Inspector
+
+Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig`
+
+**Before**
+
+```php
+use Guzzle\Service\Inspector;
+
+class YourClient extends \Guzzle\Service\Client
+{
+ public static function factory($config = array())
+ {
+ $default = array();
+ $required = array('base_url', 'username', 'api_key');
+ $config = Inspector::fromConfig($config, $default, $required);
+
+ $client = new self(
+ $config->get('base_url'),
+ $config->get('username'),
+ $config->get('api_key')
+ );
+ $client->setConfig($config);
+
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
+
+ return $client;
+ }
+```
+
+**After**
+
+```php
+use Guzzle\Common\Collection;
+
+class YourClient extends \Guzzle\Service\Client
+{
+ public static function factory($config = array())
+ {
+ $default = array();
+ $required = array('base_url', 'username', 'api_key');
+ $config = Collection::fromConfig($config, $default, $required);
+
+ $client = new self(
+ $config->get('base_url'),
+ $config->get('username'),
+ $config->get('api_key')
+ );
+ $client->setConfig($config);
+
+ $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json'));
+
+ return $client;
+ }
+```
+
+### Convert XML Service Descriptions to JSON
+
+**Before**
+
+```xml
+
+
+
+
+
+ Get a list of groups
+
+
+ Uses a search query to get a list of groups
+
+
+
+ Create a group
+
+
+
+
+ Delete a group by ID
+
+
+
+
+
+
+ Update a group
+
+
+
+
+
+
+```
+
+**After**
+
+```json
+{
+ "name": "Zendesk REST API v2",
+ "apiVersion": "2012-12-31",
+ "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users",
+ "operations": {
+ "list_groups": {
+ "httpMethod":"GET",
+ "uri": "groups.json",
+ "summary": "Get a list of groups"
+ },
+ "search_groups":{
+ "httpMethod":"GET",
+ "uri": "search.json?query=\"{query} type:group\"",
+ "summary": "Uses a search query to get a list of groups",
+ "parameters":{
+ "query":{
+ "location": "uri",
+ "description":"Zendesk Search Query",
+ "type": "string",
+ "required": true
+ }
+ }
+ },
+ "create_group": {
+ "httpMethod":"POST",
+ "uri": "groups.json",
+ "summary": "Create a group",
+ "parameters":{
+ "data": {
+ "type": "array",
+ "location": "body",
+ "description":"Group JSON",
+ "filters": "json_encode",
+ "required": true
+ },
+ "Content-Type":{
+ "type": "string",
+ "location":"header",
+ "static": "application/json"
+ }
+ }
+ },
+ "delete_group": {
+ "httpMethod":"DELETE",
+ "uri": "groups/{id}.json",
+ "summary": "Delete a group",
+ "parameters":{
+ "id":{
+ "location": "uri",
+ "description":"Group to delete by ID",
+ "type": "integer",
+ "required": true
+ }
+ }
+ },
+ "get_group": {
+ "httpMethod":"GET",
+ "uri": "groups/{id}.json",
+ "summary": "Get a ticket",
+ "parameters":{
+ "id":{
+ "location": "uri",
+ "description":"Group to get by ID",
+ "type": "integer",
+ "required": true
+ }
+ }
+ },
+ "update_group": {
+ "httpMethod":"PUT",
+ "uri": "groups/{id}.json",
+ "summary": "Update a group",
+ "parameters":{
+ "id": {
+ "location": "uri",
+ "description":"Group to update by ID",
+ "type": "integer",
+ "required": true
+ },
+ "data": {
+ "type": "array",
+ "location": "body",
+ "description":"Group JSON",
+ "filters": "json_encode",
+ "required": true
+ },
+ "Content-Type":{
+ "type": "string",
+ "location":"header",
+ "static": "application/json"
+ }
+ }
+ }
+}
+```
+
+### Guzzle\Service\Description\ServiceDescription
+
+Commands are now called Operations
+
+**Before**
+
+```php
+use Guzzle\Service\Description\ServiceDescription;
+
+$sd = new ServiceDescription();
+$sd->getCommands(); // @returns ApiCommandInterface[]
+$sd->hasCommand($name);
+$sd->getCommand($name); // @returns ApiCommandInterface|null
+$sd->addCommand($command); // @param ApiCommandInterface $command
+```
+
+**After**
+
+```php
+use Guzzle\Service\Description\ServiceDescription;
+
+$sd = new ServiceDescription();
+$sd->getOperations(); // @returns OperationInterface[]
+$sd->hasOperation($name);
+$sd->getOperation($name); // @returns OperationInterface|null
+$sd->addOperation($operation); // @param OperationInterface $operation
+```
+
+### Guzzle\Common\Inflection\Inflector
+
+Namespace is now `Guzzle\Inflection\Inflector`
+
+### Guzzle\Http\Plugin
+
+Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below.
+
+### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log
+
+Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively.
+
+**Before**
+
+```php
+use Guzzle\Common\Log\ClosureLogAdapter;
+use Guzzle\Http\Plugin\LogPlugin;
+
+/** @var \Guzzle\Http\Client */
+$client;
+
+// $verbosity is an integer indicating desired message verbosity level
+$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE);
+```
+
+**After**
+
+```php
+use Guzzle\Log\ClosureLogAdapter;
+use Guzzle\Log\MessageFormatter;
+use Guzzle\Plugin\Log\LogPlugin;
+
+/** @var \Guzzle\Http\Client */
+$client;
+
+// $format is a string indicating desired message format -- @see MessageFormatter
+$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT);
+```
+
+### Guzzle\Http\Plugin\CurlAuthPlugin
+
+Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`.
+
+### Guzzle\Http\Plugin\ExponentialBackoffPlugin
+
+Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes.
+
+**Before**
+
+```php
+use Guzzle\Http\Plugin\ExponentialBackoffPlugin;
+
+$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge(
+ ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429)
+ ));
+
+$client->addSubscriber($backoffPlugin);
+```
+
+**After**
+
+```php
+use Guzzle\Plugin\Backoff\BackoffPlugin;
+use Guzzle\Plugin\Backoff\HttpBackoffStrategy;
+
+// Use convenient factory method instead -- see implementation for ideas of what
+// you can do with chaining backoff strategies
+$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge(
+ HttpBackoffStrategy::getDefaultFailureCodes(), array(429)
+ ));
+$client->addSubscriber($backoffPlugin);
+```
+
+### Known Issues
+
+#### [BUG] Accept-Encoding header behavior changed unintentionally.
+
+(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e)
+
+In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to
+properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen.
+See issue #217 for a workaround, or use a version containing the fix.
diff --git a/akamai/vendor/guzzlehttp/guzzle/composer.json b/akamai/vendor/guzzlehttp/guzzle/composer.json
new file mode 100644
index 00000000..c5532575
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/composer.json
@@ -0,0 +1,58 @@
+{
+ "name": "guzzlehttp/guzzle",
+ "type": "library",
+ "description": "Guzzle is a PHP HTTP client library",
+ "keywords": [
+ "framework",
+ "http",
+ "rest",
+ "web service",
+ "curl",
+ "client",
+ "HTTP client"
+ ],
+ "homepage": "http://guzzlephp.org/",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.5",
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.0",
+ "guzzlehttp/psr7": "^1.6.1"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
+ "psr/log": "^1.1"
+ },
+ "suggest": {
+ "psr/log": "Required for using the Log middleware"
+ },
+ "config": {
+ "sort-packages": true
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "6.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "GuzzleHttp\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/phpstan.neon.dist b/akamai/vendor/guzzlehttp/guzzle/phpstan.neon.dist
new file mode 100644
index 00000000..4ef4192d
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/phpstan.neon.dist
@@ -0,0 +1,9 @@
+parameters:
+ level: 1
+ paths:
+ - src
+
+ ignoreErrors:
+ -
+ message: '#Function uri_template not found#'
+ path: %currentWorkingDirectory%/src/functions.php
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Client.php b/akamai/vendor/guzzlehttp/guzzle/src/Client.php
new file mode 100644
index 00000000..0f43c71f
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Client.php
@@ -0,0 +1,422 @@
+ 'http://www.foo.com/1.0/',
+ * 'timeout' => 0,
+ * 'allow_redirects' => false,
+ * 'proxy' => '192.168.16.1:10'
+ * ]);
+ *
+ * Client configuration settings include the following options:
+ *
+ * - handler: (callable) Function that transfers HTTP requests over the
+ * 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
+ * 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
+ * into relative URIs. Can be a string or instance of UriInterface.
+ * - **: any request option
+ *
+ * @param array $config Client configuration settings.
+ *
+ * @see \GuzzleHttp\RequestOptions for a list of available request options.
+ */
+ public function __construct(array $config = [])
+ {
+ if (!isset($config['handler'])) {
+ $config['handler'] = HandlerStack::create();
+ } elseif (!is_callable($config['handler'])) {
+ throw new \InvalidArgumentException('handler must be a callable');
+ }
+
+ // Convert the base_uri to a UriInterface
+ if (isset($config['base_uri'])) {
+ $config['base_uri'] = Psr7\uri_for($config['base_uri']);
+ }
+
+ $this->configureDefaults($config);
+ }
+
+ public function __call($method, $args)
+ {
+ 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] : [];
+
+ return substr($method, -5) === 'Async'
+ ? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
+ : $this->request($method, $uri, $opts);
+ }
+
+ public function sendAsync(RequestInterface $request, array $options = [])
+ {
+ // Merge the base URI into the request URI if needed.
+ $options = $this->prepareDefaults($options);
+
+ return $this->transfer(
+ $request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
+ $options
+ );
+ }
+
+ public function send(RequestInterface $request, array $options = [])
+ {
+ $options[RequestOptions::SYNCHRONOUS] = true;
+ return $this->sendAsync($request, $options)->wait();
+ }
+
+ public function requestAsync($method, $uri = '', array $options = [])
+ {
+ $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';
+ // Merge the URI into the base URI.
+ $uri = $this->buildUri($uri, $options);
+ if (is_array($body)) {
+ $this->invalidBody();
+ }
+ $request = new Psr7\Request($method, $uri, $headers, $body, $version);
+ // Remove the option so that they are not doubly-applied.
+ unset($options['headers'], $options['body'], $options['version']);
+
+ return $this->transfer($request, $options);
+ }
+
+ public function request($method, $uri = '', array $options = [])
+ {
+ $options[RequestOptions::SYNCHRONOUS] = true;
+ return $this->requestAsync($method, $uri, $options)->wait();
+ }
+
+ public function getConfig($option = null)
+ {
+ return $option === null
+ ? $this->config
+ : (isset($this->config[$option]) ? $this->config[$option] : null);
+ }
+
+ private function buildUri($uri, array $config)
+ {
+ // 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);
+ }
+
+ return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
+ }
+
+ /**
+ * Configures the default options for a client.
+ *
+ * @param array $config
+ */
+ private function configureDefaults(array $config)
+ {
+ $defaults = [
+ 'allow_redirects' => RedirectMiddleware::$defaultSettings,
+ 'http_errors' => true,
+ 'decode_content' => true,
+ 'verify' => true,
+ 'cookies' => false
+ ];
+
+ // 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 ($proxy = getenv('HTTPS_PROXY')) {
+ $defaults['proxy']['https'] = $proxy;
+ }
+
+ if ($noProxy = getenv('NO_PROXY')) {
+ $cleanedNoProxy = str_replace(' ', '', $noProxy);
+ $defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
+ }
+
+ $this->config = $config + $defaults;
+
+ if (!empty($config['cookies']) && $config['cookies'] === true) {
+ $this->config['cookies'] = new CookieJar();
+ }
+
+ // Add the default user-agent header.
+ if (!isset($this->config['headers'])) {
+ $this->config['headers'] = ['User-Agent' => default_user_agent()];
+ } 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') {
+ return;
+ }
+ }
+ $this->config['headers']['User-Agent'] = default_user_agent();
+ }
+ }
+
+ /**
+ * Merges default options into the array.
+ *
+ * @param array $options Options to modify by reference
+ *
+ * @return array
+ */
+ private function prepareDefaults(array $options)
+ {
+ $defaults = $this->config;
+
+ if (!empty($defaults['headers'])) {
+ // Default headers are only added if they are not present.
+ $defaults['_conditional'] = $defaults['headers'];
+ unset($defaults['headers']);
+ }
+
+ // 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)) {
+ // Allows default headers to be unset.
+ if ($options['headers'] === null) {
+ $defaults['_conditional'] = null;
+ unset($options['headers']);
+ } elseif (!is_array($options['headers'])) {
+ throw new \InvalidArgumentException('headers must be an array');
+ }
+ }
+
+ // Shallow merge defaults underneath options.
+ $result = $options + $defaults;
+
+ // Remove null values.
+ foreach ($result as $k => $v) {
+ if ($v === null) {
+ unset($result[$k]);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Transfers the given request and applies request options.
+ *
+ * The URI of the request is not modified and the request options are used
+ * as-is without merging in default options.
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return Promise\PromiseInterface
+ */
+ private function transfer(RequestInterface $request, array $options)
+ {
+ // 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);
+ $handler = $options['handler'];
+
+ try {
+ return Promise\promise_for($handler($request, $options));
+ } catch (\Exception $e) {
+ return Promise\rejection_for($e);
+ }
+ }
+
+ /**
+ * Applies the array of request options to a request.
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return RequestInterface
+ */
+ private function applyOptions(RequestInterface $request, array &$options)
+ {
+ $modify = [
+ 'set_headers' => [],
+ ];
+
+ if (isset($options['headers'])) {
+ $modify['set_headers'] = $options['headers'];
+ unset($options['headers']);
+ }
+
+ if (isset($options['form_params'])) {
+ if (isset($options['multipart'])) {
+ 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'], '', '&');
+ 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']);
+ $options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
+ }
+
+ if (isset($options['multipart'])) {
+ $options['body'] = new Psr7\MultipartStream($options['multipart']);
+ unset($options['multipart']);
+ }
+
+ if (isset($options['json'])) {
+ $options['body'] = \GuzzleHttp\json_encode($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']);
+ $options['_conditional']['Content-Type'] = 'application/json';
+ }
+
+ if (!empty($options['decode_content'])
+ && $options['decode_content'] !== true
+ ) {
+ // Ensure that we don't have the header in different case and set the new value.
+ $options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
+ $modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
+ }
+
+ if (isset($options['body'])) {
+ if (is_array($options['body'])) {
+ $this->invalidBody();
+ }
+ $modify['body'] = Psr7\stream_for($options['body']);
+ unset($options['body']);
+ }
+
+ if (!empty($options['auth']) && is_array($options['auth'])) {
+ $value = $options['auth'];
+ $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]");
+ break;
+ case 'digest':
+ // @todo: Do not rely on curl
+ $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]";
+ break;
+ }
+ }
+
+ if (isset($options['query'])) {
+ $value = $options['query'];
+ if (is_array($value)) {
+ $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
+ }
+ if (!is_string($value)) {
+ throw new \InvalidArgumentException('query must be a string or array');
+ }
+ $modify['query'] = $value;
+ unset($options['query']);
+ }
+
+ // 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');
+ }
+ }
+
+ $request = Psr7\modify_request($request, $modify);
+ if ($request->getBody() instanceof Psr7\MultipartStream) {
+ // Use a multipart/form-data POST if a Content-Type is not set.
+ // 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']);
+ $options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
+ . $request->getBody()->getBoundary();
+ }
+
+ // Merge in conditional headers if they are not present.
+ if (isset($options['_conditional'])) {
+ // Build up the changes so it's in a single clone of the message.
+ $modify = [];
+ foreach ($options['_conditional'] as $k => $v) {
+ if (!$request->hasHeader($k)) {
+ $modify['set_headers'][$k] = $v;
+ }
+ }
+ $request = Psr7\modify_request($request, $modify);
+ // Don't pass this internal value along to middleware/handlers.
+ unset($options['_conditional']);
+ }
+
+ return $request;
+ }
+
+ private function invalidBody()
+ {
+ throw new \InvalidArgumentException('Passing in the "body" request '
+ . 'option as an array to send a POST request has been deprecated. '
+ . '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.');
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/ClientInterface.php b/akamai/vendor/guzzlehttp/guzzle/src/ClientInterface.php
new file mode 100644
index 00000000..5b370851
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/ClientInterface.php
@@ -0,0 +1,84 @@
+strictMode = $strictMode;
+
+ foreach ($cookieArray as $cookie) {
+ if (!($cookie instanceof SetCookie)) {
+ $cookie = new SetCookie($cookie);
+ }
+ $this->setCookie($cookie);
+ }
+ }
+
+ /**
+ * Create a new Cookie jar from an associative array and domain.
+ *
+ * @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)
+ {
+ $cookieJar = new self();
+ foreach ($cookies as $name => $value) {
+ $cookieJar->setCookie(new SetCookie([
+ 'Domain' => $domain,
+ 'Name' => $name,
+ 'Value' => $value,
+ 'Discard' => true
+ ]));
+ }
+
+ 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
+ */
+ public static function shouldPersist(
+ SetCookie $cookie,
+ $allowSessionCookies = false
+ ) {
+ if ($cookie->getExpires() || $allowSessionCookies) {
+ if (!$cookie->getDiscard()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * 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)
+ {
+ // don't allow a null name
+ if ($name === null) {
+ return null;
+ }
+ foreach ($this->cookies as $cookie) {
+ if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
+ return $cookie;
+ }
+ }
+ }
+
+ public function toArray()
+ {
+ return array_map(function (SetCookie $cookie) {
+ return $cookie->toArray();
+ }, $this->getIterator()->getArrayCopy());
+ }
+
+ public function clear($domain = null, $path = null, $name = null)
+ {
+ if (!$domain) {
+ $this->cookies = [];
+ return;
+ } elseif (!$path) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($domain) {
+ return !$cookie->matchesDomain($domain);
+ }
+ );
+ } elseif (!$name) {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain) {
+ return !($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ } else {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) use ($path, $domain, $name) {
+ return !($cookie->getName() == $name &&
+ $cookie->matchesPath($path) &&
+ $cookie->matchesDomain($domain));
+ }
+ );
+ }
+ }
+
+ public function clearSessionCookies()
+ {
+ $this->cookies = array_filter(
+ $this->cookies,
+ function (SetCookie $cookie) {
+ return !$cookie->getDiscard() && $cookie->getExpires();
+ }
+ );
+ }
+
+ public function setCookie(SetCookie $cookie)
+ {
+ // If the name string is empty (but not 0), ignore the set-cookie
+ // string entirely.
+ $name = $cookie->getName();
+ if (!$name && $name !== '0') {
+ return false;
+ }
+
+ // Only allow cookies with set and valid domain, name, value
+ $result = $cookie->validate();
+ if ($result !== true) {
+ if ($this->strictMode) {
+ throw new \RuntimeException('Invalid cookie: ' . $result);
+ } else {
+ $this->removeCookieIfEmpty($cookie);
+ return false;
+ }
+ }
+
+ // Resolve conflicts with previously set cookies
+ foreach ($this->cookies as $i => $c) {
+
+ // Two cookies are identical, when their path, and domain are
+ // identical.
+ if ($c->getPath() != $cookie->getPath() ||
+ $c->getDomain() != $cookie->getDomain() ||
+ $c->getName() != $cookie->getName()
+ ) {
+ continue;
+ }
+
+ // The previously set cookie is a discard cookie and this one is
+ // not so allow the new cookie to be set
+ if (!$cookie->getDiscard() && $c->getDiscard()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the new cookie's expiration is further into the future, then
+ // replace the old cookie
+ if ($cookie->getExpires() > $c->getExpires()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // If the value has changed, we better change it
+ if ($cookie->getValue() !== $c->getValue()) {
+ unset($this->cookies[$i]);
+ continue;
+ }
+
+ // The cookie exists, so no need to continue
+ return false;
+ }
+
+ $this->cookies[] = $cookie;
+
+ return true;
+ }
+
+ public function count()
+ {
+ return count($this->cookies);
+ }
+
+ public function getIterator()
+ {
+ return new \ArrayIterator(array_values($this->cookies));
+ }
+
+ public function extractCookies(
+ RequestInterface $request,
+ ResponseInterface $response
+ ) {
+ 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(), '/')) {
+ $sc->setPath($this->getCookiePathFromRequest($request));
+ }
+ $this->setCookie($sc);
+ }
+ }
+ }
+
+ /**
+ * 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)
+ {
+ $uriPath = $request->getUri()->getPath();
+ if ('' === $uriPath) {
+ return '/';
+ }
+ if (0 !== strpos($uriPath, '/')) {
+ return '/';
+ }
+ if ('/' === $uriPath) {
+ return '/';
+ }
+ if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
+ return '/';
+ }
+
+ return substr($uriPath, 0, $lastSlashPos);
+ }
+
+ public function withCookieHeader(RequestInterface $request)
+ {
+ $values = [];
+ $uri = $request->getUri();
+ $scheme = $uri->getScheme();
+ $host = $uri->getHost();
+ $path = $uri->getPath() ?: '/';
+
+ foreach ($this->cookies as $cookie) {
+ if ($cookie->matchesPath($path) &&
+ $cookie->matchesDomain($host) &&
+ !$cookie->isExpired() &&
+ (!$cookie->getSecure() || $scheme === 'https')
+ ) {
+ $values[] = $cookie->getName() . '='
+ . $cookie->getValue();
+ }
+ }
+
+ return $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)
+ {
+ $cookieValue = $cookie->getValue();
+ if ($cookieValue === null || $cookieValue === '') {
+ $this->clear(
+ $cookie->getDomain(),
+ $cookie->getPath(),
+ $cookie->getName()
+ );
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php b/akamai/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
new file mode 100644
index 00000000..2cf298a8
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
@@ -0,0 +1,84 @@
+filename = $cookieFile;
+ $this->storeSessionCookies = $storeSessionCookies;
+
+ if (file_exists($cookieFile)) {
+ $this->load($cookieFile);
+ }
+ }
+
+ /**
+ * Saves the file when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save($this->filename);
+ }
+
+ /**
+ * 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)
+ {
+ $json = [];
+ 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)) {
+ throw new \RuntimeException("Unable to save file {$filename}");
+ }
+ }
+
+ /**
+ * Load cookies from a JSON formatted file.
+ *
+ * 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)
+ {
+ $json = file_get_contents($filename);
+ if (false === $json) {
+ throw new \RuntimeException("Unable to load file {$filename}");
+ } elseif ($json === '') {
+ return;
+ }
+
+ $data = \GuzzleHttp\json_decode($json, true);
+ if (is_array($data)) {
+ foreach (json_decode($json, true) as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie file: {$filename}");
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/akamai/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
new file mode 100644
index 00000000..0224a244
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
@@ -0,0 +1,72 @@
+sessionKey = $sessionKey;
+ $this->storeSessionCookies = $storeSessionCookies;
+ $this->load();
+ }
+
+ /**
+ * Saves cookies to session when shutting down
+ */
+ public function __destruct()
+ {
+ $this->save();
+ }
+
+ /**
+ * Save cookies to the client session
+ */
+ public function save()
+ {
+ $json = [];
+ foreach ($this as $cookie) {
+ /** @var SetCookie $cookie */
+ if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
+ $json[] = $cookie->toArray();
+ }
+ }
+
+ $_SESSION[$this->sessionKey] = json_encode($json);
+ }
+
+ /**
+ * Load the contents of the client session into the data array
+ */
+ protected function load()
+ {
+ if (!isset($_SESSION[$this->sessionKey])) {
+ return;
+ }
+ $data = json_decode($_SESSION[$this->sessionKey], true);
+ if (is_array($data)) {
+ foreach ($data as $cookie) {
+ $this->setCookie(new SetCookie($cookie));
+ }
+ } elseif (strlen($data)) {
+ throw new \RuntimeException("Invalid cookie data");
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/akamai/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
new file mode 100644
index 00000000..3d776a70
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
@@ -0,0 +1,403 @@
+ null,
+ 'Value' => null,
+ 'Domain' => null,
+ 'Path' => '/',
+ 'Max-Age' => null,
+ 'Expires' => null,
+ 'Secure' => false,
+ 'Discard' => false,
+ 'HttpOnly' => false
+ ];
+
+ /** @var array Cookie data */
+ private $data;
+
+ /**
+ * Create a new SetCookie object from a string
+ *
+ * @param string $cookie Set-Cookie header string
+ *
+ * @return self
+ */
+ public static function fromString($cookie)
+ {
+ // 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)));
+ // The name of the cookie (first kvp) must exist and include an equal sign.
+ if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
+ 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]);
+ $value = isset($cookieParts[1])
+ ? trim($cookieParts[1], " \n\r\t\0\x0B")
+ : true;
+
+ // Only check for non-cookies when cookies have been found
+ if (empty($data['Name'])) {
+ $data['Name'] = $key;
+ $data['Value'] = $value;
+ } else {
+ foreach (array_keys(self::$defaults) as $search) {
+ if (!strcasecmp($search, $key)) {
+ $data[$search] = $value;
+ continue 2;
+ }
+ }
+ $data[$key] = $value;
+ }
+ }
+
+ return new self($data);
+ }
+
+ /**
+ * @param array $data Array of cookie data provided by a Cookie parser
+ */
+ public function __construct(array $data = [])
+ {
+ $this->data = array_replace(self::$defaults, $data);
+ // 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());
+ }
+ }
+
+ public function __toString()
+ {
+ $str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
+ 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) . '; ';
+ } else {
+ $str .= ($v === true ? $k : "{$k}={$v}") . '; ';
+ }
+ }
+ }
+
+ return rtrim($str, '; ');
+ }
+
+ public function toArray()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Get the cookie name
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->data['Name'];
+ }
+
+ /**
+ * Set the cookie name
+ *
+ * @param string $name Cookie name
+ */
+ public function setName($name)
+ {
+ $this->data['Name'] = $name;
+ }
+
+ /**
+ * Get the cookie value
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->data['Value'];
+ }
+
+ /**
+ * Set the cookie value
+ *
+ * @param string $value Cookie value
+ */
+ public function setValue($value)
+ {
+ $this->data['Value'] = $value;
+ }
+
+ /**
+ * Get the domain
+ *
+ * @return string|null
+ */
+ public function getDomain()
+ {
+ return $this->data['Domain'];
+ }
+
+ /**
+ * Set the domain of the cookie
+ *
+ * @param string $domain
+ */
+ public function setDomain($domain)
+ {
+ $this->data['Domain'] = $domain;
+ }
+
+ /**
+ * Get the path
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->data['Path'];
+ }
+
+ /**
+ * Set the path of the cookie
+ *
+ * @param string $path Path of the cookie
+ */
+ public function setPath($path)
+ {
+ $this->data['Path'] = $path;
+ }
+
+ /**
+ * Maximum lifetime of the cookie in seconds
+ *
+ * @return int|null
+ */
+ public function getMaxAge()
+ {
+ return $this->data['Max-Age'];
+ }
+
+ /**
+ * Set the max-age of the cookie
+ *
+ * @param int $maxAge Max age of the cookie in seconds
+ */
+ public function setMaxAge($maxAge)
+ {
+ $this->data['Max-Age'] = $maxAge;
+ }
+
+ /**
+ * The UNIX timestamp when the cookie Expires
+ *
+ * @return mixed
+ */
+ public function getExpires()
+ {
+ return $this->data['Expires'];
+ }
+
+ /**
+ * Set the unix timestamp for which the cookie will expire
+ *
+ * @param int $timestamp Unix timestamp
+ */
+ public function setExpires($timestamp)
+ {
+ $this->data['Expires'] = is_numeric($timestamp)
+ ? (int) $timestamp
+ : strtotime($timestamp);
+ }
+
+ /**
+ * Get whether or not this is a secure cookie
+ *
+ * @return bool|null
+ */
+ public function getSecure()
+ {
+ return $this->data['Secure'];
+ }
+
+ /**
+ * Set whether or not the cookie is secure
+ *
+ * @param bool $secure Set to true or false if secure
+ */
+ public function setSecure($secure)
+ {
+ $this->data['Secure'] = $secure;
+ }
+
+ /**
+ * Get whether or not this is a session cookie
+ *
+ * @return bool|null
+ */
+ public function getDiscard()
+ {
+ return $this->data['Discard'];
+ }
+
+ /**
+ * 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)
+ {
+ $this->data['Discard'] = $discard;
+ }
+
+ /**
+ * Get whether or not this is an HTTP only cookie
+ *
+ * @return bool
+ */
+ public function getHttpOnly()
+ {
+ return $this->data['HttpOnly'];
+ }
+
+ /**
+ * 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)
+ {
+ $this->data['HttpOnly'] = $httpOnly;
+ }
+
+ /**
+ * Check if the cookie matches a path value.
+ *
+ * A request-path path-matches a given cookie-path if at least one of
+ * the following conditions holds:
+ *
+ * - The cookie-path and the request-path are identical.
+ * - The cookie-path is a prefix of the request-path, and the last
+ * character of the cookie-path is %x2F ("/").
+ * - The cookie-path is a prefix of the request-path, and the first
+ * character of the request-path that is not included in the cookie-
+ * path is a %x2F ("/") character.
+ *
+ * @param string $requestPath Path to check against
+ *
+ * @return bool
+ */
+ public function matchesPath($requestPath)
+ {
+ $cookiePath = $this->getPath();
+
+ // Match on exact matches or when path is the default empty "/"
+ if ($cookiePath === '/' || $cookiePath == $requestPath) {
+ return true;
+ }
+
+ // Ensure that the cookie-path is a prefix of the request path.
+ if (0 !== strpos($requestPath, $cookiePath)) {
+ return false;
+ }
+
+ // Match if the last character of the cookie-path is "/"
+ if (substr($cookiePath, -1, 1) === '/') {
+ return true;
+ }
+
+ // Match if the first character not included in cookie path is "/"
+ return substr($requestPath, strlen($cookiePath), 1) === '/';
+ }
+
+ /**
+ * Check if the cookie matches a domain value
+ *
+ * @param string $domain Domain to check against
+ *
+ * @return bool
+ */
+ public function matchesDomain($domain)
+ {
+ // Remove the leading '.' as per spec in RFC 6265.
+ // http://tools.ietf.org/html/rfc6265#section-5.2.3
+ $cookieDomain = ltrim($this->getDomain(), '.');
+
+ // Domain not set or exact match.
+ 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)) {
+ return false;
+ }
+
+ return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
+ }
+
+ /**
+ * Check if the cookie is expired
+ *
+ * @return bool
+ */
+ public function isExpired()
+ {
+ return $this->getExpires() !== null && time() > $this->getExpires();
+ }
+
+ /**
+ * 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)) {
+ return 'The cookie name must not be empty';
+ }
+
+ // Check if any of the invalid characters are present in the cookie name
+ if (preg_match(
+ '/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
+ $name
+ )) {
+ return 'Cookie name must not contain invalid characters: ASCII '
+ . 'Control characters (0-31;127), space, tab and the '
+ . 'following characters: ()<>@,;:\"/?={}';
+ }
+
+ // Value must not be empty, but can be 0
+ $value = $this->getValue();
+ if (empty($value) && !is_numeric($value)) {
+ 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.
+ $domain = $this->getDomain();
+ if (empty($domain) && !is_numeric($domain)) {
+ return 'The cookie domain must not be empty';
+ }
+
+ return true;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php b/akamai/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
new file mode 100644
index 00000000..427d896f
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
@@ -0,0 +1,27 @@
+getStatusCode()
+ : 0;
+ parent::__construct($message, $code, $previous);
+ $this->request = $request;
+ $this->response = $response;
+ $this->handlerContext = $handlerContext;
+ }
+
+ /**
+ * Wrap non-RequestExceptions with a RequestException
+ *
+ * @param RequestInterface $request
+ * @param \Exception $e
+ *
+ * @return RequestException
+ */
+ public static function wrapException(RequestInterface $request, \Exception $e)
+ {
+ return $e instanceof RequestException
+ ? $e
+ : new RequestException($e->getMessage(), $request, null, $e);
+ }
+
+ /**
+ * Factory method to create a new exception with a normalized error message
+ *
+ * @param RequestInterface $request Request
+ * @param ResponseInterface $response Response received
+ * @param \Exception $previous Previous exception
+ * @param array $ctx Optional handler context.
+ *
+ * @return self
+ */
+ public static function create(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $previous = null,
+ array $ctx = []
+ ) {
+ if (!$response) {
+ return new self(
+ 'Error completing request',
+ $request,
+ null,
+ $previous,
+ $ctx
+ );
+ }
+
+ $level = (int) floor($response->getStatusCode() / 100);
+ if ($level === 4) {
+ $label = 'Client error';
+ $className = ClientException::class;
+ } elseif ($level === 5) {
+ $label = 'Server error';
+ $className = ServerException::class;
+ } else {
+ $label = 'Unsuccessful request';
+ $className = __CLASS__;
+ }
+
+ $uri = $request->getUri();
+ $uri = static::obfuscateUri($uri);
+
+ // Client Error: `GET /` resulted in a `404 Not Found` response:
+ // ... (truncated)
+ $message = sprintf(
+ '%s: `%s %s` resulted in a `%s %s` response',
+ $label,
+ $request->getMethod(),
+ $uri,
+ $response->getStatusCode(),
+ $response->getReasonPhrase()
+ );
+
+ $summary = static::getResponseBodySummary($response);
+
+ if ($summary !== null) {
+ $message .= ":\n{$summary}\n";
+ }
+
+ 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)
+ {
+ $body = $response->getBody();
+
+ if (!$body->isSeekable() || !$body->isReadable()) {
+ return null;
+ }
+
+ $size = $body->getSize();
+
+ if ($size === 0) {
+ return null;
+ }
+
+ $summary = $body->read(120);
+ $body->rewind();
+
+ if ($size > 120) {
+ $summary .= ' (truncated...)';
+ }
+
+ // Matches any printable character, including unicode characters:
+ // letters, marks, numbers, punctuation, spacing, and separators.
+ if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
+ return null;
+ }
+
+ return $summary;
+ }
+
+ /**
+ * Obfuscates URI if there is an username and a password present
+ *
+ * @param UriInterface $uri
+ *
+ * @return UriInterface
+ */
+ private static function obfuscateUri($uri)
+ {
+ $userInfo = $uri->getUserInfo();
+
+ if (false !== ($pos = strpos($userInfo, ':'))) {
+ return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Get the request that caused the exception
+ *
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Get the associated response
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Check if a response was received
+ *
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return $this->response !== null;
+ }
+
+ /**
+ * 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.
+ *
+ * @return array
+ */
+ public function getHandlerContext()
+ {
+ return $this->handlerContext;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php b/akamai/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
new file mode 100644
index 00000000..a77c2892
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
@@ -0,0 +1,27 @@
+stream = $stream;
+ $msg = $msg ?: 'Could not seek the stream to position ' . $pos;
+ parent::__construct($msg);
+ }
+
+ /**
+ * @return StreamInterface
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php b/akamai/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
new file mode 100644
index 00000000..127094c1
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
@@ -0,0 +1,9 @@
+maxHandles = $maxHandles;
+ }
+
+ public function create(RequestInterface $request, array $options)
+ {
+ if (isset($options['curl']['body_as_string'])) {
+ $options['_body_as_string'] = $options['curl']['body_as_string'];
+ unset($options['curl']['body_as_string']);
+ }
+
+ $easy = new EasyHandle;
+ $easy->request = $request;
+ $easy->options = $options;
+ $conf = $this->getDefaultConf($easy);
+ $this->applyMethod($easy, $conf);
+ $this->applyHandlerOptions($easy, $conf);
+ $this->applyHeaders($easy, $conf);
+ unset($conf['_headers']);
+
+ // Add handler options from the request configuration options
+ if (isset($options['curl'])) {
+ $conf = array_replace($conf, $options['curl']);
+ }
+
+ $conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
+ $easy->handle = $this->handles
+ ? array_pop($this->handles)
+ : curl_init();
+ curl_setopt_array($easy->handle, $conf);
+
+ return $easy;
+ }
+
+ public function release(EasyHandle $easy)
+ {
+ $resource = $easy->handle;
+ unset($easy->handle);
+
+ 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);
+ $this->handles[] = $resource;
+ }
+ }
+
+ /**
+ * 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
+ */
+ public static function finish(
+ callable $handler,
+ EasyHandle $easy,
+ CurlFactoryInterface $factory
+ ) {
+ if (isset($easy->options['on_stats'])) {
+ self::invokeStats($easy);
+ }
+
+ if (!$easy->response || $easy->errno) {
+ return self::finishError($handler, $easy, $factory);
+ }
+
+ // Return the response if it is present and there is no error.
+ $factory->release($easy);
+
+ // Rewind the body of the response if possible.
+ $body = $easy->response->getBody();
+ if ($body->isSeekable()) {
+ $body->rewind();
+ }
+
+ return new FulfilledPromise($easy->response);
+ }
+
+ private static function invokeStats(EasyHandle $easy)
+ {
+ $curlStats = curl_getinfo($easy->handle);
+ $curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);
+ $stats = new TransferStats(
+ $easy->request,
+ $easy->response,
+ $curlStats['total_time'],
+ $easy->errno,
+ $curlStats
+ );
+ call_user_func($easy->options['on_stats'], $stats);
+ }
+
+ private static function finishError(
+ callable $handler,
+ EasyHandle $easy,
+ CurlFactoryInterface $factory
+ ) {
+ // 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'];
+ $factory->release($easy);
+
+ // Retry when nothing is present or when curl failed to rewind.
+ if (empty($easy->options['_err_message'])
+ && (!$easy->errno || $easy->errno == 65)
+ ) {
+ return self::retryFailedRewind($handler, $easy, $ctx);
+ }
+
+ return self::createRejection($easy, $ctx);
+ }
+
+ private static function createRejection(EasyHandle $easy, array $ctx)
+ {
+ static $connectionErrors = [
+ 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
+ // return a rejected promise that wraps that exception.
+ if ($easy->onHeadersException) {
+ return \GuzzleHttp\Promise\rejection_for(
+ new RequestException(
+ 'An error was encountered during the on_headers event',
+ $easy->request,
+ $easy->response,
+ $easy->onHeadersException,
+ $ctx
+ )
+ );
+ }
+ 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()
+ );
+ }
+
+ // Create a connection exception if it was a specific error code.
+ $error = isset($connectionErrors[$easy->errno])
+ ? new ConnectException($message, $easy->request, null, $ctx)
+ : new RequestException($message, $easy->request, $easy->response, null, $ctx);
+
+ return \GuzzleHttp\Promise\rejection_for($error);
+ }
+
+ private function getDefaultConf(EasyHandle $easy)
+ {
+ $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,
+ ];
+
+ 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;
+ } elseif ($version == 2.0) {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
+ } else {
+ $conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
+ }
+
+ return $conf;
+ }
+
+ private function applyMethod(EasyHandle $easy, array &$conf)
+ {
+ $body = $easy->request->getBody();
+ $size = $body->getSize();
+
+ if ($size === null || $size > 0) {
+ $this->applyBody($easy->request, $easy->options, $conf);
+ return;
+ }
+
+ $method = $easy->request->getMethod();
+ if ($method === 'PUT' || $method === 'POST') {
+ // See http://tools.ietf.org/html/rfc7230#section-3.3.2
+ if (!$easy->request->hasHeader('Content-Length')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
+ }
+ } elseif ($method === 'HEAD') {
+ $conf[CURLOPT_NOBODY] = true;
+ unset(
+ $conf[CURLOPT_WRITEFUNCTION],
+ $conf[CURLOPT_READFUNCTION],
+ $conf[CURLOPT_FILE],
+ $conf[CURLOPT_INFILE]
+ );
+ }
+ }
+
+ private function applyBody(RequestInterface $request, array $options, array &$conf)
+ {
+ $size = $request->hasHeader('Content-Length')
+ ? (int) $request->getHeaderLine('Content-Length')
+ : null;
+
+ // Send the body as a string if the size is less than 1MB OR if the
+ // [curl][body_as_string] request value is set.
+ if (($size !== null && $size < 1000000) ||
+ !empty($options['_body_as_string'])
+ ) {
+ $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;
+ if ($size !== null) {
+ $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) {
+ return $body->read($length);
+ };
+ }
+
+ // If the Expect header is not present, prevent curl from adding it
+ if (!$request->hasHeader('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:';
+ }
+ }
+
+ private function applyHeaders(EasyHandle $easy, array &$conf)
+ {
+ foreach ($conf['_headers'] as $name => $values) {
+ foreach ($values as $value) {
+ $value = (string) $value;
+ 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;";
+ } else {
+ $conf[CURLOPT_HTTPHEADER][] = "$name: $value";
+ }
+ }
+ }
+
+ // Remove the Accept header if one was not set
+ if (!$easy->request->hasHeader('Accept')) {
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept:';
+ }
+ }
+
+ /**
+ * Remove a header from the options array.
+ *
+ * @param string $name Case-insensitive header to remove
+ * @param array $options Array of options to modify
+ */
+ private function removeHeader($name, array &$options)
+ {
+ foreach (array_keys($options['_headers']) as $key) {
+ if (!strcasecmp($key, $name)) {
+ unset($options['_headers'][$key]);
+ return;
+ }
+ }
+ }
+
+ private function applyHandlerOptions(EasyHandle $easy, array &$conf)
+ {
+ $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;
+ } else {
+ $conf[CURLOPT_SSL_VERIFYHOST] = 0;
+ $conf[CURLOPT_SSL_VERIFYPEER] = false;
+ 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'])) {
+ 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'];
+ } else {
+ $conf[CURLOPT_CAINFO] = $options['verify'];
+ }
+ }
+ }
+ }
+
+ if (!empty($options['decode_content'])) {
+ $accept = $easy->request->getHeaderLine('Accept-Encoding');
+ if ($accept) {
+ $conf[CURLOPT_ENCODING] = $accept;
+ } else {
+ $conf[CURLOPT_ENCODING] = '';
+ // Don't let curl send the header over the wire
+ $conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
+ }
+ }
+
+ if (isset($options['sink'])) {
+ $sink = $options['sink'];
+ if (!is_string($sink)) {
+ $sink = \GuzzleHttp\Psr7\stream_for($sink);
+ } elseif (!is_dir(dirname($sink))) {
+ // Ensure that the directory exists before failing in curl.
+ throw new \RuntimeException(sprintf(
+ 'Directory %s does not exist for sink value of %s',
+ dirname($sink),
+ $sink
+ ));
+ } else {
+ $sink = new LazyOpenStream($sink, 'w+');
+ }
+ $easy->sink = $sink;
+ $conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
+ 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;
+ }
+
+ // 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;
+ } elseif ('v6' === $options['force_ip_resolve']) {
+ $conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
+ }
+ }
+
+ if (isset($options['connect_timeout'])) {
+ $timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
+ $conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
+ }
+
+ 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'];
+ } 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'])
+ ) {
+ $conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
+ }
+ }
+ }
+ }
+
+ if (isset($options['cert'])) {
+ $cert = $options['cert'];
+ if (is_array($cert)) {
+ $conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
+ $cert = $cert[0];
+ }
+ if (!file_exists($cert)) {
+ throw new \InvalidArgumentException(
+ "SSL certificate not found: {$cert}"
+ );
+ }
+ $conf[CURLOPT_SSLCERT] = $cert;
+ }
+
+ if (isset($options['ssl_key'])) {
+ $sslKey = $options['ssl_key'];
+ if (is_array($sslKey)) {
+ $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
+ $sslKey = $sslKey[0];
+ }
+ if (!file_exists($sslKey)) {
+ throw new \InvalidArgumentException(
+ "SSL private key not found: {$sslKey}"
+ );
+ }
+ $conf[CURLOPT_SSLKEY] = $sslKey;
+ }
+
+ if (isset($options['progress'])) {
+ $progress = $options['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);
+ };
+ }
+
+ if (!empty($options['debug'])) {
+ $conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
+ $conf[CURLOPT_VERBOSE] = true;
+ }
+ }
+
+ /**
+ * This function ensures that a response was set on a transaction. If one
+ * was not set, then the request is retried if possible. This error
+ * typically means you are sending a payload, curl encountered a
+ * "Connection died, retrying a fresh connect" error, tried to rewind the
+ * 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.
+ */
+ private static function retryFailedRewind(
+ callable $handler,
+ EasyHandle $easy,
+ array $ctx
+ ) {
+ try {
+ // Only rewind if the body has been read from.
+ $body = $easy->request->getBody();
+ if ($body->tell() > 0) {
+ $body->rewind();
+ }
+ } catch (\RuntimeException $e) {
+ $ctx['error'] = 'The connection unexpectedly failed without '
+ . 'providing an error. The request would have been retried, '
+ . 'but attempting to rewind the request body failed. '
+ . 'Exception: ' . $e;
+ return self::createRejection($easy, $ctx);
+ }
+
+ // Retry no more than 3 times before giving up.
+ if (!isset($easy->options['_curl_retries'])) {
+ $easy->options['_curl_retries'] = 1;
+ } elseif ($easy->options['_curl_retries'] == 2) {
+ $ctx['error'] = 'The cURL request was retried 3 times '
+ . 'and did not succeed. The most likely reason for the failure '
+ . 'is that cURL was unable to rewind the body of the request '
+ . 'and subsequent retries resulted in the same error. Turn on '
+ . 'the debug option to see what went wrong. See '
+ . 'https://bugs.php.net/bug.php?id=47204 for more information.';
+ return self::createRejection($easy, $ctx);
+ } else {
+ $easy->options['_curl_retries']++;
+ }
+
+ return $handler($easy->request, $easy->options);
+ }
+
+ private function createHeaderFn(EasyHandle $easy)
+ {
+ if (isset($easy->options['on_headers'])) {
+ $onHeaders = $easy->options['on_headers'];
+
+ if (!is_callable($onHeaders)) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ }
+ } else {
+ $onHeaders = null;
+ }
+
+ return function ($ch, $h) use (
+ $onHeaders,
+ $easy,
+ &$startingResponse
+ ) {
+ $value = trim($h);
+ if ($value === '') {
+ $startingResponse = true;
+ $easy->createResponse();
+ if ($onHeaders !== null) {
+ try {
+ $onHeaders($easy->response);
+ } catch (\Exception $e) {
+ // Associate the exception with the handle and trigger
+ // a curl header write error by returning 0.
+ $easy->onHeadersException = $e;
+ return -1;
+ }
+ }
+ } elseif ($startingResponse) {
+ $startingResponse = false;
+ $easy->headers = [$value];
+ } else {
+ $easy->headers[] = $value;
+ }
+ return strlen($h);
+ };
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php b/akamai/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
new file mode 100644
index 00000000..b0fc2368
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
@@ -0,0 +1,27 @@
+factory = isset($options['handle_factory'])
+ ? $options['handle_factory']
+ : new CurlFactory(3);
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (isset($options['delay'])) {
+ usleep($options['delay'] * 1000);
+ }
+
+ $easy = $this->factory->create($request, $options);
+ curl_exec($easy->handle);
+ $easy->errno = curl_errno($easy->handle);
+
+ return CurlFactory::finish($this, $easy, $this->factory);
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/akamai/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
new file mode 100644
index 00000000..d8297623
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
@@ -0,0 +1,205 @@
+factory = isset($options['handle_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;
+ } else {
+ $this->selectTimeout = 1;
+ }
+ }
+
+ public function __get($name)
+ {
+ if ($name === '_mh') {
+ return $this->_mh = curl_multi_init();
+ }
+
+ throw new \BadMethodCallException();
+ }
+
+ public function __destruct()
+ {
+ if (isset($this->_mh)) {
+ curl_multi_close($this->_mh);
+ unset($this->_mh);
+ }
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $easy = $this->factory->create($request, $options);
+ $id = (int) $easy->handle;
+
+ $promise = new Promise(
+ [$this, 'execute'],
+ function () use ($id) {
+ return $this->cancel($id);
+ }
+ );
+
+ $this->addRequest(['easy' => $easy, 'deferred' => $promise]);
+
+ return $promise;
+ }
+
+ /**
+ * Ticks the curl event loop.
+ */
+ public function tick()
+ {
+ // Add any delayed handles if needed.
+ if ($this->delays) {
+ $currentTime = \GuzzleHttp\_current_time();
+ foreach ($this->delays as $id => $delay) {
+ if ($currentTime >= $delay) {
+ unset($this->delays[$id]);
+ curl_multi_add_handle(
+ $this->_mh,
+ $this->handles[$id]['easy']->handle
+ );
+ }
+ }
+ }
+
+ // Step through the task queue which may add additional requests.
+ P\queue()->run();
+
+ if ($this->active &&
+ 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);
+ }
+
+ while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
+
+ $this->processMessages();
+ }
+
+ /**
+ * Runs until all outstanding connections have completed.
+ */
+ public function execute()
+ {
+ $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());
+ }
+ $this->tick();
+ }
+ }
+
+ private function addRequest(array $entry)
+ {
+ $easy = $entry['easy'];
+ $id = (int) $easy->handle;
+ $this->handles[$id] = $entry;
+ if (empty($easy->options['delay'])) {
+ curl_multi_add_handle($this->_mh, $easy->handle);
+ } else {
+ $this->delays[$id] = \GuzzleHttp\_current_time() + ($easy->options['delay'] / 1000);
+ }
+ }
+
+ /**
+ * Cancels a handle from sending and removes references to it.
+ *
+ * @param int $id Handle ID to cancel and remove.
+ *
+ * @return bool True on success, false on failure.
+ */
+ private function cancel($id)
+ {
+ // Cannot cancel if it has been processed.
+ if (!isset($this->handles[$id])) {
+ return false;
+ }
+
+ $handle = $this->handles[$id]['easy']->handle;
+ unset($this->delays[$id], $this->handles[$id]);
+ curl_multi_remove_handle($this->_mh, $handle);
+ curl_close($handle);
+
+ return true;
+ }
+
+ private function processMessages()
+ {
+ while ($done = curl_multi_info_read($this->_mh)) {
+ $id = (int) $done['handle'];
+ curl_multi_remove_handle($this->_mh, $done['handle']);
+
+ if (!isset($this->handles[$id])) {
+ // Probably was cancelled.
+ continue;
+ }
+
+ $entry = $this->handles[$id];
+ unset($this->handles[$id], $this->delays[$id]);
+ $entry['easy']->errno = $done['result'];
+ $entry['deferred']->resolve(
+ CurlFactory::finish(
+ $this,
+ $entry['easy'],
+ $this->factory
+ )
+ );
+ }
+ }
+
+ private function timeToNext()
+ {
+ $currentTime = \GuzzleHttp\_current_time();
+ $nextTime = PHP_INT_MAX;
+ foreach ($this->delays as $time) {
+ if ($time < $nextTime) {
+ $nextTime = $time;
+ }
+ }
+
+ return max(0, $nextTime - $currentTime) * 1000000;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php b/akamai/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
new file mode 100644
index 00000000..7754e911
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
@@ -0,0 +1,92 @@
+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);
+
+ if (!empty($this->options['decode_content'])
+ && isset($normalizedKeys['content-encoding'])
+ ) {
+ $headers['x-encoded-content-encoding']
+ = $headers[$normalizedKeys['content-encoding']];
+ unset($headers[$normalizedKeys['content-encoding']]);
+ if (isset($normalizedKeys['content-length'])) {
+ $headers['x-encoded-content-length']
+ = $headers[$normalizedKeys['content-length']];
+
+ $bodyLength = (int) $this->sink->getSize();
+ if ($bodyLength) {
+ $headers[$normalizedKeys['content-length']] = $bodyLength;
+ } else {
+ unset($headers[$normalizedKeys['content-length']]);
+ }
+ }
+ }
+
+ // Attach a response to the easy handle with the parsed headers.
+ $this->response = new Response(
+ $startLine[1],
+ $headers,
+ $this->sink,
+ substr($startLine[0], 5),
+ isset($startLine[2]) ? (string) $startLine[2] : null
+ );
+ }
+
+ public function __get($name)
+ {
+ $msg = $name === 'handle'
+ ? 'The EasyHandle has been released'
+ : 'Invalid property: ' . $name;
+ throw new \BadMethodCallException($msg);
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php b/akamai/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
new file mode 100644
index 00000000..d5c449c1
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
@@ -0,0 +1,190 @@
+onFulfilled = $onFulfilled;
+ $this->onRejected = $onRejected;
+
+ if ($queue) {
+ call_user_func_array([$this, 'append'], $queue);
+ }
+ }
+
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (!$this->queue) {
+ throw new \OutOfBoundsException('Mock queue is empty');
+ }
+
+ if (isset($options['delay'])) {
+ usleep($options['delay'] * 1000);
+ }
+
+ $this->lastRequest = $request;
+ $this->lastOptions = $options;
+ $response = array_shift($this->queue);
+
+ if (isset($options['on_headers'])) {
+ if (!is_callable($options['on_headers'])) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ }
+ try {
+ $options['on_headers']($response);
+ } catch (\Exception $e) {
+ $msg = 'An error was encountered during the on_headers event';
+ $response = new RequestException($msg, $request, $response, $e);
+ }
+ }
+
+ if (is_callable($response)) {
+ $response = call_user_func($response, $request, $options);
+ }
+
+ $response = $response instanceof \Exception
+ ? \GuzzleHttp\Promise\rejection_for($response)
+ : \GuzzleHttp\Promise\promise_for($response);
+
+ return $response->then(
+ function ($value) use ($request, $options) {
+ $this->invokeStats($request, $options, $value);
+ if ($this->onFulfilled) {
+ call_user_func($this->onFulfilled, $value);
+ }
+ if (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) {
+ $sink->write($contents);
+ }
+ }
+
+ return $value;
+ },
+ function ($reason) use ($request, $options) {
+ $this->invokeStats($request, $options, null, $reason);
+ if ($this->onRejected) {
+ call_user_func($this->onRejected, $reason);
+ }
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ );
+ }
+
+ /**
+ * Adds one or more variadic requests, exceptions, callables, or promises
+ * to the queue.
+ */
+ public function append()
+ {
+ foreach (func_get_args() as $value) {
+ if ($value instanceof ResponseInterface
+ || $value instanceof \Exception
+ || $value instanceof PromiseInterface
+ || is_callable($value)
+ ) {
+ $this->queue[] = $value;
+ } else {
+ throw new \InvalidArgumentException('Expected a response or '
+ . 'exception. Found ' . \GuzzleHttp\describe_type($value));
+ }
+ }
+ }
+
+ /**
+ * Get the last received request.
+ *
+ * @return RequestInterface
+ */
+ public function getLastRequest()
+ {
+ return $this->lastRequest;
+ }
+
+ /**
+ * Get the last received request options.
+ *
+ * @return array
+ */
+ public function getLastOptions()
+ {
+ return $this->lastOptions;
+ }
+
+ /**
+ * Returns the number of remaining items in the queue.
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->queue);
+ }
+
+ private function invokeStats(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response = null,
+ $reason = null
+ ) {
+ if (isset($options['on_stats'])) {
+ $transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;
+ $stats = new TransferStats($request, $response, $transferTime, $reason);
+ call_user_func($options['on_stats'], $stats);
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php b/akamai/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
new file mode 100644
index 00000000..f8b00be0
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
@@ -0,0 +1,55 @@
+withoutHeader('Expect');
+
+ // Append a content-length header if body size is zero to match
+ // cURL's behavior.
+ if (0 === $request->getBody()->getSize()) {
+ $request = $request->withHeader('Content-Length', '0');
+ }
+
+ return $this->createResponse(
+ $request,
+ $options,
+ $this->createStream($request, $options),
+ $startTime
+ );
+ } catch (\InvalidArgumentException $e) {
+ throw $e;
+ } catch (\Exception $e) {
+ // 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")
+ ) {
+ $e = new ConnectException($e->getMessage(), $request, $e);
+ }
+ $e = RequestException::wrapException($request, $e);
+ $this->invokeStats($options, $request, $startTime, null, $e);
+
+ return \GuzzleHttp\Promise\rejection_for($e);
+ }
+ }
+
+ private function invokeStats(
+ array $options,
+ RequestInterface $request,
+ $startTime,
+ ResponseInterface $response = null,
+ $error = null
+ ) {
+ if (isset($options['on_stats'])) {
+ $stats = new TransferStats(
+ $request,
+ $response,
+ \GuzzleHttp\_current_time() - $startTime,
+ $error,
+ []
+ );
+ call_user_func($options['on_stats'], $stats);
+ }
+ }
+
+ private function createResponse(
+ RequestInterface $request,
+ array $options,
+ $stream,
+ $startTime
+ ) {
+ $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);
+ $stream = Psr7\stream_for($stream);
+ $sink = $stream;
+
+ if (strcasecmp('HEAD', $request->getMethod())) {
+ $sink = $this->createSink($stream, $options);
+ }
+
+ $response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
+
+ if (isset($options['on_headers'])) {
+ try {
+ $options['on_headers']($response);
+ } catch (\Exception $e) {
+ $msg = 'An error was encountered during the on_headers event';
+ $ex = new RequestException($msg, $request, $response, $e);
+ return \GuzzleHttp\Promise\rejection_for($ex);
+ }
+ }
+
+ // Do not drain when the request is a HEAD request because they have
+ // no body.
+ if ($sink !== $stream) {
+ $this->drain(
+ $stream,
+ $sink,
+ $response->getHeaderLine('Content-Length')
+ );
+ }
+
+ $this->invokeStats($options, $request, $startTime, $response, null);
+
+ return new FulfilledPromise($response);
+ }
+
+ private function createSink(StreamInterface $stream, array $options)
+ {
+ if (!empty($options['stream'])) {
+ return $stream;
+ }
+
+ $sink = isset($options['sink'])
+ ? $options['sink']
+ : fopen('php://temp', 'r+');
+
+ return is_string($sink)
+ ? new Psr7\LazyOpenStream($sink, 'w+')
+ : Psr7\stream_for($sink);
+ }
+
+ private function checkDecode(array $options, array $headers, $stream)
+ {
+ // Automatically decode responses when instructed.
+ if (!empty($options['decode_content'])) {
+ $normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
+ if (isset($normalizedKeys['content-encoding'])) {
+ $encoding = $headers[$normalizedKeys['content-encoding']];
+ if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
+ $stream = new Psr7\InflateStream(
+ Psr7\stream_for($stream)
+ );
+ $headers['x-encoded-content-encoding']
+ = $headers[$normalizedKeys['content-encoding']];
+ // Remove content-encoding header
+ unset($headers[$normalizedKeys['content-encoding']]);
+ // Fix content-length header
+ if (isset($normalizedKeys['content-length'])) {
+ $headers['x-encoded-content-length']
+ = $headers[$normalizedKeys['content-length']];
+
+ $length = (int) $stream->getSize();
+ if ($length === 0) {
+ unset($headers[$normalizedKeys['content-length']]);
+ } else {
+ $headers[$normalizedKeys['content-length']] = [$length];
+ }
+ }
+ }
+ }
+ }
+
+ return [$stream, $headers];
+ }
+
+ /**
+ * 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.
+ *
+ * @return StreamInterface
+ * @throws \RuntimeException when the sink option is invalid.
+ */
+ private function drain(
+ StreamInterface $source,
+ StreamInterface $sink,
+ $contentLength
+ ) {
+ // 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
+ // Connection: Close headers.
+ Psr7\copy_to_stream(
+ $source,
+ $sink,
+ (strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
+ );
+
+ $sink->seek(0);
+ $source->close();
+
+ return $sink;
+ }
+
+ /**
+ * Create a resource and check to ensure it was created successfully
+ *
+ * @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[] = [
+ 'message' => $msg,
+ 'file' => $file,
+ 'line' => $line
+ ];
+ return true;
+ });
+
+ $resource = $callback();
+ restore_error_handler();
+
+ if (!$resource) {
+ $message = 'Error creating resource: ';
+ foreach ($errors as $err) {
+ foreach ($err as $key => $value) {
+ $message .= "[$key] $value" . PHP_EOL;
+ }
+ }
+ throw new \RuntimeException(trim($message));
+ }
+
+ return $resource;
+ }
+
+ private function createStream(RequestInterface $request, array $options)
+ {
+ static $methods;
+ if (!$methods) {
+ $methods = array_flip(get_class_methods(__CLASS__));
+ }
+
+ // HTTP/1.1 streams using the PHP stream wrapper require a
+ // Connection: close header
+ if ($request->getProtocolVersion() == '1.1'
+ && !$request->hasHeader('Connection')
+ ) {
+ $request = $request->withHeader('Connection', 'close');
+ }
+
+ // Ensure SSL is verified by default
+ if (!isset($options['verify'])) {
+ $options['verify'] = true;
+ }
+
+ $params = [];
+ $context = $this->getDefaultContext($request);
+
+ if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
+ throw new \InvalidArgumentException('on_headers must be callable');
+ }
+
+ if (!empty($options)) {
+ foreach ($options as $key => $value) {
+ $method = "add_{$key}";
+ if (isset($methods[$method])) {
+ $this->{$method}($request, $context, $value, $params);
+ }
+ }
+ }
+
+ if (isset($options['stream_context'])) {
+ if (!is_array($options['stream_context'])) {
+ throw new \InvalidArgumentException('stream_context must be an array');
+ }
+ $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]
+ ) {
+ 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);
+ }
+ );
+
+ return $this->createResource(
+ function () use ($uri, &$http_response_header, $context, $options) {
+ $resource = fopen((string) $uri, 'r', null, $context);
+ $this->lastHeaders = $http_response_header;
+
+ if (isset($options['read_timeout'])) {
+ $readTimeout = $options['read_timeout'];
+ $sec = (int) $readTimeout;
+ $usec = ($readTimeout - $sec) * 100000;
+ stream_set_timeout($resource, $sec, $usec);
+ }
+
+ return $resource;
+ }
+ );
+ }
+
+ private function resolveHost(RequestInterface $request, array $options)
+ {
+ $uri = $request->getUri();
+
+ 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'])) {
+ throw new ConnectException(
+ 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'])) {
+ throw new ConnectException(
+ sprintf(
+ "Could not resolve IPv6 address for host '%s'",
+ $uri->getHost()
+ ),
+ $request
+ );
+ }
+ $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
+ }
+ }
+
+ return $uri;
+ }
+
+ private function getDefaultContext(RequestInterface $request)
+ {
+ $headers = '';
+ foreach ($request->getHeaders() as $name => $value) {
+ foreach ($value as $val) {
+ $headers .= "$name: $val\r\n";
+ }
+ }
+
+ $context = [
+ 'http' => [
+ 'method' => $request->getMethod(),
+ 'header' => $headers,
+ 'protocol_version' => $request->getProtocolVersion(),
+ 'ignore_errors' => true,
+ 'follow_location' => 0,
+ ],
+ ];
+
+ $body = (string) $request->getBody();
+
+ if (!empty($body)) {
+ $context['http']['content'] = $body;
+ // Prevent the HTTP handler from adding a Content-Type header.
+ if (!$request->hasHeader('Content-Type')) {
+ $context['http']['header'] .= "Content-Type:\r\n";
+ }
+ }
+
+ $context['http']['header'] = rtrim($context['http']['header']);
+
+ return $context;
+ }
+
+ private function add_proxy(RequestInterface $request, &$options, $value, &$params)
+ {
+ 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(
+ $request->getUri()->getHost(),
+ $value['no']
+ )
+ ) {
+ $options['http']['proxy'] = $value[$scheme];
+ }
+ }
+ }
+ }
+
+ private function add_timeout(RequestInterface $request, &$options, $value, &$params)
+ {
+ if ($value > 0) {
+ $options['http']['timeout'] = $value;
+ }
+ }
+
+ private function add_verify(RequestInterface $request, &$options, $value, &$params)
+ {
+ 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) {
+ $options['ssl']['verify_peer'] = false;
+ $options['ssl']['verify_peer_name'] = false;
+ return;
+ } else {
+ throw new \InvalidArgumentException('Invalid verify request option');
+ }
+
+ $options['ssl']['verify_peer'] = true;
+ $options['ssl']['verify_peer_name'] = true;
+ $options['ssl']['allow_self_signed'] = false;
+ }
+
+ private function add_cert(RequestInterface $request, &$options, $value, &$params)
+ {
+ if (is_array($value)) {
+ $options['ssl']['passphrase'] = $value[1];
+ $value = $value[0];
+ }
+
+ 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)
+ {
+ $this->addNotification(
+ $params,
+ 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)
+ {
+ 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',
+ ];
+ static $args = ['severity', 'message', 'message_code',
+ 'bytes_transferred', 'bytes_max'];
+
+ $value = \GuzzleHttp\debug_resource($value);
+ $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
+ $this->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 . '" ');
+ }
+ fwrite($value, "\n");
+ }
+ );
+ }
+
+ private function addNotification(array &$params, callable $notify)
+ {
+ // Wrap the existing function if needed.
+ if (!isset($params['notification'])) {
+ $params['notification'] = $notify;
+ } else {
+ $params['notification'] = $this->callArray([
+ $params['notification'],
+ $notify
+ ]);
+ }
+ }
+
+ private function callArray(array $functions)
+ {
+ return function () use ($functions) {
+ $args = func_get_args();
+ foreach ($functions as $fn) {
+ call_user_func_array($fn, $args);
+ }
+ };
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/HandlerStack.php b/akamai/vendor/guzzlehttp/guzzle/src/HandlerStack.php
new file mode 100644
index 00000000..f0016861
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/HandlerStack.php
@@ -0,0 +1,273 @@
+push(Middleware::httpErrors(), 'http_errors');
+ $stack->push(Middleware::redirect(), 'allow_redirects');
+ $stack->push(Middleware::cookies(), 'cookies');
+ $stack->push(Middleware::prepareBody(), 'prepare_body');
+
+ return $stack;
+ }
+
+ /**
+ * @param callable $handler Underlying HTTP handler.
+ */
+ public function __construct(callable $handler = null)
+ {
+ $this->handler = $handler;
+ }
+
+ /**
+ * Invokes the handler stack as a composed handler
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $handler = $this->resolve();
+
+ return $handler($request, $options);
+ }
+
+ /**
+ * Dumps a string representation of the stack.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ $depth = 0;
+ $stack = [];
+ if ($this->handler) {
+ $stack[] = "0) Handler: " . $this->debugCallable($this->handler);
+ }
+
+ $result = '';
+ foreach (array_reverse($this->stack) as $tuple) {
+ $depth++;
+ $str = "{$depth}) Name: '{$tuple[1]}', ";
+ $str .= "Function: " . $this->debugCallable($tuple[0]);
+ $result = "> {$str}\n{$result}";
+ $stack[] = $str;
+ }
+
+ foreach (array_keys($stack) as $k) {
+ $result .= "< {$stack[$k]}\n";
+ }
+
+ return $result;
+ }
+
+ /**
+ * Set the HTTP handler that actually returns a promise.
+ *
+ * @param callable $handler Accepts a request and array of options and
+ * returns a Promise.
+ */
+ public function setHandler(callable $handler)
+ {
+ $this->handler = $handler;
+ $this->cached = null;
+ }
+
+ /**
+ * Returns true if the builder has a handler.
+ *
+ * @return bool
+ */
+ public function hasHandler()
+ {
+ return (bool) $this->handler;
+ }
+
+ /**
+ * Unshift a middleware to the bottom of the stack.
+ *
+ * @param callable $middleware Middleware function
+ * @param string $name Name to register for this middleware.
+ */
+ public function unshift(callable $middleware, $name = null)
+ {
+ 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.
+ */
+ public function push(callable $middleware, $name = '')
+ {
+ $this->stack[] = [$middleware, $name];
+ $this->cached = null;
+ }
+
+ /**
+ * 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.
+ */
+ public function before($findName, callable $middleware, $withName = '')
+ {
+ $this->splice($findName, $withName, $middleware, true);
+ }
+
+ /**
+ * 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.
+ */
+ public function after($findName, callable $middleware, $withName = '')
+ {
+ $this->splice($findName, $withName, $middleware, false);
+ }
+
+ /**
+ * Remove a middleware by instance or name from the stack.
+ *
+ * @param callable|string $remove Middleware to remove by instance or name.
+ */
+ public function remove($remove)
+ {
+ $this->cached = null;
+ $idx = is_callable($remove) ? 0 : 1;
+ $this->stack = array_values(array_filter(
+ $this->stack,
+ function ($tuple) use ($idx, $remove) {
+ return $tuple[$idx] !== $remove;
+ }
+ ));
+ }
+
+ /**
+ * Compose the middleware and handler into a single callable function.
+ *
+ * @return callable
+ */
+ public function resolve()
+ {
+ if (!$this->cached) {
+ if (!($prev = $this->handler)) {
+ throw new \LogicException('No handler has been specified');
+ }
+
+ foreach (array_reverse($this->stack) as $fn) {
+ $prev = $fn[0]($prev);
+ }
+
+ $this->cached = $prev;
+ }
+
+ return $this->cached;
+ }
+
+ /**
+ * @param string $name
+ * @return int
+ */
+ private function findByName($name)
+ {
+ foreach ($this->stack as $k => $v) {
+ if ($v[1] === $name) {
+ return $k;
+ }
+ }
+
+ throw new \InvalidArgumentException("Middleware not found: $name");
+ }
+
+ /**
+ * 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)
+ {
+ $this->cached = null;
+ $idx = $this->findByName($findName);
+ $tuple = [$middleware, $withName];
+
+ if ($before) {
+ if ($idx === 0) {
+ array_unshift($this->stack, $tuple);
+ } else {
+ $replacement = [$tuple, $this->stack[$idx]];
+ array_splice($this->stack, $idx, 1, $replacement);
+ }
+ } elseif ($idx === count($this->stack) - 1) {
+ $this->stack[] = $tuple;
+ } else {
+ $replacement = [$this->stack[$idx], $tuple];
+ 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
+ */
+ private function debugCallable($fn)
+ {
+ if (is_string($fn)) {
+ return "callable({$fn})";
+ }
+
+ if (is_array($fn)) {
+ return is_string($fn[0])
+ ? "callable({$fn[0]}::{$fn[1]})"
+ : "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
+ }
+
+ return 'callable(' . spl_object_hash($fn) . ')';
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/MessageFormatter.php b/akamai/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
new file mode 100644
index 00000000..663ac739
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
@@ -0,0 +1,180 @@
+>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
+ const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
+
+ /** @var string Template used to format log messages */
+ private $template;
+
+ /**
+ * @param string $template Log message template
+ */
+ public function __construct($template = self::CLF)
+ {
+ $this->template = $template ?: self::CLF;
+ }
+
+ /**
+ * 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
+ */
+ public function format(
+ RequestInterface $request,
+ ResponseInterface $response = null,
+ \Exception $error = null
+ ) {
+ $cache = [];
+
+ return preg_replace_callback(
+ '/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
+ function (array $matches) use ($request, $response, $error, &$cache) {
+ if (isset($cache[$matches[1]])) {
+ return $cache[$matches[1]];
+ }
+
+ $result = '';
+ switch ($matches[1]) {
+ case 'request':
+ $result = Psr7\str($request);
+ break;
+ case 'response':
+ $result = $response ? Psr7\str($response) : '';
+ break;
+ case 'req_headers':
+ $result = trim($request->getMethod()
+ . ' ' . $request->getRequestTarget())
+ . ' HTTP/' . $request->getProtocolVersion() . "\r\n"
+ . $this->headers($request);
+ break;
+ case 'res_headers':
+ $result = $response ?
+ sprintf(
+ 'HTTP/%s %d %s',
+ $response->getProtocolVersion(),
+ $response->getStatusCode(),
+ $response->getReasonPhrase()
+ ) . "\r\n" . $this->headers($response)
+ : 'NULL';
+ break;
+ case 'req_body':
+ $result = $request->getBody();
+ break;
+ case 'res_body':
+ $result = $response ? $response->getBody() : 'NULL';
+ break;
+ case 'ts':
+ case 'date_iso_8601':
+ $result = gmdate('c');
+ break;
+ case 'date_common_log':
+ $result = date('d/M/Y:H:i:s O');
+ break;
+ case 'method':
+ $result = $request->getMethod();
+ break;
+ case 'version':
+ $result = $request->getProtocolVersion();
+ break;
+ case 'uri':
+ case 'url':
+ $result = $request->getUri();
+ break;
+ case 'target':
+ $result = $request->getRequestTarget();
+ break;
+ case 'req_version':
+ $result = $request->getProtocolVersion();
+ break;
+ case 'res_version':
+ $result = $response
+ ? $response->getProtocolVersion()
+ : 'NULL';
+ break;
+ case 'host':
+ $result = $request->getHeaderLine('Host');
+ break;
+ case 'hostname':
+ $result = gethostname();
+ break;
+ case 'code':
+ $result = $response ? $response->getStatusCode() : 'NULL';
+ break;
+ case 'phrase':
+ $result = $response ? $response->getReasonPhrase() : 'NULL';
+ break;
+ case 'error':
+ $result = $error ? $error->getMessage() : 'NULL';
+ 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) {
+ $result = $response
+ ? $response->getHeaderLine(substr($matches[1], 11))
+ : 'NULL';
+ }
+ }
+
+ $cache[$matches[1]] = $result;
+ return $result;
+ },
+ $this->template
+ );
+ }
+
+ private function headers(MessageInterface $message)
+ {
+ $result = '';
+ foreach ($message->getHeaders() as $name => $values) {
+ $result .= $name . ': ' . implode(', ', $values) . "\r\n";
+ }
+
+ return trim($result);
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Middleware.php b/akamai/vendor/guzzlehttp/guzzle/src/Middleware.php
new file mode 100644
index 00000000..bffc1974
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Middleware.php
@@ -0,0 +1,254 @@
+withCookieHeader($request);
+ return $handler($request, $options)
+ ->then(
+ function ($response) use ($cookieJar, $request) {
+ $cookieJar->extractCookies($request, $response);
+ return $response;
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * 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.
+ */
+ public static function httpErrors()
+ {
+ return function (callable $handler) {
+ return 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) {
+ $code = $response->getStatusCode();
+ if ($code < 400) {
+ return $response;
+ }
+ throw RequestException::create($request, $response);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that pushes history data to an ArrayAccess container.
+ *
+ * @param array|\ArrayAccess $container Container to hold the history (by reference).
+ *
+ * @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)
+ {
+ 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 $handler($request, $options)->then(
+ function ($value) use ($request, &$container, $options) {
+ $container[] = [
+ 'request' => $request,
+ 'response' => $value,
+ 'error' => null,
+ 'options' => $options
+ ];
+ return $value;
+ },
+ function ($reason) use ($request, &$container, $options) {
+ $container[] = [
+ 'request' => $request,
+ 'response' => null,
+ 'error' => $reason,
+ 'options' => $options
+ ];
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * Middleware that invokes a callback before and after sending a request.
+ *
+ * The provided listener cannot modify or alter the response. It simply
+ * "taps" into the chain to be notified before returning the promise. The
+ * before listener accepts a request and options array, and the after
+ * listener accepts a request, options array, and response promise.
+ *
+ * @param callable $before Function to invoke before forwarding the request.
+ * @param callable $after Function invoked after forwarding.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function tap(callable $before = null, callable $after = null)
+ {
+ return function (callable $handler) use ($before, $after) {
+ return function ($request, array $options) use ($handler, $before, $after) {
+ if ($before) {
+ $before($request, $options);
+ }
+ $response = $handler($request, $options);
+ if ($after) {
+ $after($request, $options, $response);
+ }
+ return $response;
+ };
+ };
+ }
+
+ /**
+ * Middleware that handles request redirects.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function redirect()
+ {
+ return function (callable $handler) {
+ return new RedirectMiddleware($handler);
+ };
+ }
+
+ /**
+ * Middleware that retries requests based on the boolean result of
+ * invoking the provided "decider" function.
+ *
+ * If no delay function is provided, a simple implementation of exponential
+ * backoff will be utilized.
+ *
+ * @param callable $decider Function that accepts the number of retries,
+ * a request, [response], and [exception] and
+ * returns true if the request is to be retried.
+ * @param callable $delay Function that accepts the number of retries and
+ * returns the number of milliseconds to delay.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function retry(callable $decider, callable $delay = null)
+ {
+ return function (callable $handler) use ($decider, $delay) {
+ return new RetryMiddleware($decider, $handler, $delay);
+ };
+ }
+
+ /**
+ * 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.
+ *
+ * @return callable Returns a function that accepts the next handler.
+ */
+ public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' /* \Psr\Log\LogLevel::INFO */)
+ {
+ return function (callable $handler) use ($logger, $formatter, $logLevel) {
+ return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
+ return $handler($request, $options)->then(
+ function ($response) use ($logger, $request, $formatter, $logLevel) {
+ $message = $formatter->format($request, $response);
+ $logger->log($logLevel, $message);
+ return $response;
+ },
+ function ($reason) use ($logger, $request, $formatter) {
+ $response = $reason instanceof RequestException
+ ? $reason->getResponse()
+ : null;
+ $message = $formatter->format($request, $response, $reason);
+ $logger->notice($message);
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ );
+ };
+ };
+ }
+
+ /**
+ * 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()
+ {
+ return function (callable $handler) {
+ return new PrepareBodyMiddleware($handler);
+ };
+ }
+
+ /**
+ * Middleware that applies a map function to the request before passing to
+ * the next handler.
+ *
+ * @param callable $fn Function that accepts a RequestInterface and returns
+ * a RequestInterface.
+ * @return callable
+ */
+ public static function mapRequest(callable $fn)
+ {
+ return function (callable $handler) use ($fn) {
+ return function ($request, array $options) use ($handler, $fn) {
+ return $handler($fn($request), $options);
+ };
+ };
+ }
+
+ /**
+ * Middleware that applies a map function to the resolved promise's
+ * response.
+ *
+ * @param callable $fn Function that accepts a ResponseInterface and
+ * returns a ResponseInterface.
+ * @return callable
+ */
+ public static function mapResponse(callable $fn)
+ {
+ return function (callable $handler) use ($fn) {
+ return function ($request, array $options) use ($handler, $fn) {
+ return $handler($request, $options)->then($fn);
+ };
+ };
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/Pool.php b/akamai/vendor/guzzlehttp/guzzle/src/Pool.php
new file mode 100644
index 00000000..05c854ae
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/Pool.php
@@ -0,0 +1,123 @@
+ $rfn) {
+ if ($rfn instanceof RequestInterface) {
+ yield $key => $client->sendAsync($rfn, $opts);
+ } elseif (is_callable($rfn)) {
+ yield $key => $rfn($opts);
+ } else {
+ throw new \InvalidArgumentException('Each value yielded by '
+ . 'the iterator must be a Psr7\Http\Message\RequestInterface '
+ . 'or a callable that returns a promise that fulfills '
+ . 'with a Psr7\Message\Http\ResponseInterface object.');
+ }
+ }
+ };
+
+ $this->each = new EachPromise($requests(), $config);
+ }
+
+ public function promise()
+ {
+ return $this->each->promise();
+ }
+
+ /**
+ * Sends multiple requests concurrently and returns an array of responses
+ * and exceptions that uses the same ordering as the provided requests.
+ *
+ * IMPORTANT: This method keeps every request and response in memory, and
+ * as such, is NOT recommended when sending a large number or an
+ * indeterminate number of requests concurrently.
+ *
+ * @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}
+ *
+ * @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 = []
+ ) {
+ $res = [];
+ self::cmpCallback($options, 'fulfilled', $res);
+ self::cmpCallback($options, 'rejected', $res);
+ $pool = new static($client, $requests, $options);
+ $pool->promise()->wait();
+ ksort($res);
+
+ return $res;
+ }
+
+ private static function cmpCallback(array &$options, $name, array &$results)
+ {
+ if (!isset($options[$name])) {
+ $options[$name] = function ($v, $k) use (&$results) {
+ $results[$k] = $v;
+ };
+ } else {
+ $currentFn = $options[$name];
+ $options[$name] = function ($v, $k) use (&$results, $currentFn) {
+ $currentFn($v, $k);
+ $results[$k] = $v;
+ };
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php b/akamai/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
new file mode 100644
index 00000000..2eb95f9b
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
@@ -0,0 +1,106 @@
+nextHandler = $nextHandler;
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ $fn = $this->nextHandler;
+
+ // Don't do anything if the request has no body.
+ if ($request->getBody()->getSize() === 0) {
+ return $fn($request, $options);
+ }
+
+ $modify = [];
+
+ // 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)) {
+ $modify['set_headers']['Content-Type'] = $type;
+ }
+ }
+ }
+
+ // Add a default content-length or transfer-encoding header.
+ if (!$request->hasHeader('Content-Length')
+ && !$request->hasHeader('Transfer-Encoding')
+ ) {
+ $size = $request->getBody()->getSize();
+ if ($size !== null) {
+ $modify['set_headers']['Content-Length'] = $size;
+ } else {
+ $modify['set_headers']['Transfer-Encoding'] = 'chunked';
+ }
+ }
+
+ // Add the expect header if needed.
+ $this->addExpectHeader($request, $options, $modify);
+
+ return $fn(Psr7\modify_request($request, $modify), $options);
+ }
+
+ private function addExpectHeader(
+ RequestInterface $request,
+ array $options,
+ array &$modify
+ ) {
+ // Determine if the Expect header should be used
+ if ($request->hasHeader('Expect')) {
+ return;
+ }
+
+ $expect = isset($options['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) {
+ return;
+ }
+
+ // The expect header is unconditionally enabled
+ if ($expect === true) {
+ $modify['set_headers']['Expect'] = '100-Continue';
+ return;
+ }
+
+ // By default, send the expect header when the payload is > 1mb
+ if ($expect === null) {
+ $expect = 1048576;
+ }
+
+ // Always add if the body cannot be rewound, the size cannot be
+ // determined, or the size is greater than the cutoff threshold
+ $body = $request->getBody();
+ $size = $body->getSize();
+
+ if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
+ $modify['set_headers']['Expect'] = '100-Continue';
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php b/akamai/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
new file mode 100644
index 00000000..bff4e4e8
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
@@ -0,0 +1,237 @@
+ 5,
+ 'protocols' => ['http', 'https'],
+ 'strict' => false,
+ 'referer' => false,
+ 'track_redirects' => false,
+ ];
+
+ /** @var callable */
+ private $nextHandler;
+
+ /**
+ * @param callable $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)
+ {
+ $fn = $this->nextHandler;
+
+ if (empty($options['allow_redirects'])) {
+ return $fn($request, $options);
+ }
+
+ if ($options['allow_redirects'] === true) {
+ $options['allow_redirects'] = self::$defaultSettings;
+ } 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
+ $options['allow_redirects'] += self::$defaultSettings;
+ }
+
+ if (empty($options['allow_redirects']['max'])) {
+ return $fn($request, $options);
+ }
+
+ return $fn($request, $options)
+ ->then(function (ResponseInterface $response) use ($request, $options) {
+ return $this->checkRedirect($request, $options, $response);
+ });
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ * @param ResponseInterface|PromiseInterface $response
+ *
+ * @return ResponseInterface|PromiseInterface
+ */
+ public function checkRedirect(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response
+ ) {
+ if (substr($response->getStatusCode(), 0, 1) != '3'
+ || !$response->hasHeader('Location')
+ ) {
+ return $response;
+ }
+
+ $this->guardMax($request, $options);
+ $nextRequest = $this->modifyRequest($request, $options, $response);
+
+ if (isset($options['allow_redirects']['on_redirect'])) {
+ call_user_func(
+ $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.
+ if (!empty($options['allow_redirects']['track_redirects'])) {
+ return $this->withTracking(
+ $promise,
+ (string) $nextRequest->getUri(),
+ $response->getStatusCode()
+ );
+ }
+
+ return $promise;
+ }
+
+ private function withTracking(PromiseInterface $promise, $uri, $statusCode)
+ {
+ return $promise->then(
+ 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);
+ return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
+ ->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
+ }
+ );
+ }
+
+ private function guardMax(RequestInterface $request, array &$options)
+ {
+ $current = isset($options['__redirect_count'])
+ ? $options['__redirect_count']
+ : 0;
+ $options['__redirect_count'] = $current + 1;
+ $max = $options['allow_redirects']['max'];
+
+ if ($options['__redirect_count'] > $max) {
+ throw new TooManyRedirectsException(
+ "Will not follow more than {$max} redirects",
+ $request
+ );
+ }
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ * @param ResponseInterface $response
+ *
+ * @return RequestInterface
+ */
+ public function modifyRequest(
+ RequestInterface $request,
+ array $options,
+ ResponseInterface $response
+ ) {
+ // Request modifications to apply.
+ $modify = [];
+ $protocols = $options['allow_redirects']['protocols'];
+
+ // Use a GET request if this is an entity enclosing request and we are
+ // not forcing RFC compliance, but rather emulating what all browsers
+ // would do.
+ $statusCode = $response->getStatusCode();
+ if ($statusCode == 303 ||
+ ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
+ ) {
+ $modify['method'] = 'GET';
+ $modify['body'] = '';
+ }
+
+ $modify['uri'] = $this->redirectUri($request, $response, $protocols);
+ Psr7\rewind_body($request);
+
+ // Add the Referer header if it is told to do so and only
+ // add the header if we are not redirecting from https to http.
+ if ($options['allow_redirects']['referer']
+ && $modify['uri']->getScheme() === $request->getUri()->getScheme()
+ ) {
+ $uri = $request->getUri()->withUserInfo('');
+ $modify['set_headers']['Referer'] = (string) $uri;
+ } else {
+ $modify['remove_headers'][] = 'Referer';
+ }
+
+ // Remove Authorization header if host is different.
+ if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
+ $modify['remove_headers'][] = 'Authorization';
+ }
+
+ return Psr7\modify_request($request, $modify);
+ }
+
+ /**
+ * 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
+ ) {
+ $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)) {
+ throw new BadResponseException(
+ sprintf(
+ 'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
+ $location,
+ implode(', ', $protocols)
+ ),
+ $request,
+ $response
+ );
+ }
+
+ return $location;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/RequestOptions.php b/akamai/vendor/guzzlehttp/guzzle/src/RequestOptions.php
new file mode 100644
index 00000000..5c0fd19d
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/RequestOptions.php
@@ -0,0 +1,255 @@
+decider = $decider;
+ $this->nextHandler = $nextHandler;
+ $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
+ }
+
+ /**
+ * Default exponential backoff delay function.
+ *
+ * @param int $retries
+ *
+ * @return int
+ */
+ public static function exponentialDelay($retries)
+ {
+ return (int) pow(2, $retries - 1);
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return PromiseInterface
+ */
+ public function __invoke(RequestInterface $request, array $options)
+ {
+ if (!isset($options['retries'])) {
+ $options['retries'] = 0;
+ }
+
+ $fn = $this->nextHandler;
+ return $fn($request, $options)
+ ->then(
+ $this->onFulfilled($request, $options),
+ $this->onRejected($request, $options)
+ );
+ }
+
+ private function onFulfilled(RequestInterface $req, array $options)
+ {
+ return function ($value) use ($req, $options) {
+ if (!call_user_func(
+ $this->decider,
+ $options['retries'],
+ $req,
+ $value,
+ null
+ )) {
+ return $value;
+ }
+ return $this->doRetry($req, $options, $value);
+ };
+ }
+
+ private function onRejected(RequestInterface $req, array $options)
+ {
+ return function ($reason) use ($req, $options) {
+ if (!call_user_func(
+ $this->decider,
+ $options['retries'],
+ $req,
+ null,
+ $reason
+ )) {
+ return \GuzzleHttp\Promise\rejection_for($reason);
+ }
+ return $this->doRetry($req, $options);
+ };
+ }
+
+ private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
+ {
+ $options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
+
+ return $this($request, $options);
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/TransferStats.php b/akamai/vendor/guzzlehttp/guzzle/src/TransferStats.php
new file mode 100644
index 00000000..23a22a33
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/TransferStats.php
@@ -0,0 +1,126 @@
+request = $request;
+ $this->response = $response;
+ $this->transferTime = $transferTime;
+ $this->handlerErrorData = $handlerErrorData;
+ $this->handlerStats = $handlerStats;
+ }
+
+ /**
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Returns the response that was received (if any).
+ *
+ * @return ResponseInterface|null
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Returns true if a response was received.
+ *
+ * @return bool
+ */
+ public function hasResponse()
+ {
+ return $this->response !== null;
+ }
+
+ /**
+ * Gets handler specific error data.
+ *
+ * This might be an exception, a integer representing an error code, or
+ * anything else. Relying on this value assumes that you know what handler
+ * you are using.
+ *
+ * @return mixed
+ */
+ public function getHandlerErrorData()
+ {
+ return $this->handlerErrorData;
+ }
+
+ /**
+ * Get the effective URI the request was sent to.
+ *
+ * @return UriInterface
+ */
+ public function getEffectiveUri()
+ {
+ return $this->request->getUri();
+ }
+
+ /**
+ * Get the estimated time the request was being transferred by the handler.
+ *
+ * @return float Time in seconds.
+ */
+ public function getTransferTime()
+ {
+ return $this->transferTime;
+ }
+
+ /**
+ * Gets an array of all of the handler specific transfer data.
+ *
+ * @return array
+ */
+ public function getHandlerStats()
+ {
+ return $this->handlerStats;
+ }
+
+ /**
+ * Get a specific handler statistic from the handler by name.
+ *
+ * @param string $stat Handler specific transfer stat to retrieve.
+ *
+ * @return mixed|null
+ */
+ public function getHandlerStat($stat)
+ {
+ return isset($this->handlerStats[$stat])
+ ? $this->handlerStats[$stat]
+ : null;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/UriTemplate.php b/akamai/vendor/guzzlehttp/guzzle/src/UriTemplate.php
new file mode 100644
index 00000000..96dcfd09
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/UriTemplate.php
@@ -0,0 +1,237 @@
+ ['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);
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/functions.php b/akamai/vendor/guzzlehttp/guzzle/src/functions.php
new file mode 100644
index 00000000..51d736d8
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/functions.php
@@ -0,0 +1,346 @@
+expand($template, $variables);
+}
+
+/**
+ * Debug function used to describe the provided value type and class.
+ *
+ * @param mixed $input
+ *
+ * @return string Returns a string containing the type of the variable and
+ * if a class is provided, the class name.
+ */
+function describe_type($input)
+{
+ switch (gettype($input)) {
+ case 'object':
+ return 'object(' . get_class($input) . ')';
+ case 'array':
+ return 'array(' . count($input) . ')';
+ default:
+ ob_start();
+ var_dump($input);
+ // normalize float vs double
+ return str_replace('double(', 'float(', rtrim(ob_get_clean()));
+ }
+}
+
+/**
+ * Parses an array of header lines into an associative array of headers.
+ *
+ * @param array $lines Header lines array of strings in the following
+ * format: "Name: Value"
+ * @return array
+ */
+function headers_from_lines($lines)
+{
+ $headers = [];
+
+ foreach ($lines as $line) {
+ $parts = explode(':', $line, 2);
+ $headers[trim($parts[0])][] = isset($parts[1])
+ ? trim($parts[1])
+ : null;
+ }
+
+ return $headers;
+}
+
+/**
+ * Returns a debug stream based on the provided variable.
+ *
+ * @param mixed $value Optional value
+ *
+ * @return resource
+ */
+function debug_resource($value = null)
+{
+ if (is_resource($value)) {
+ return $value;
+ } elseif (defined('STDOUT')) {
+ return STDOUT;
+ }
+
+ return fopen('php://output', 'w');
+}
+
+/**
+ * Chooses and creates a default handler to use based on the environment.
+ *
+ * The returned handler is not wrapped by any default middlewares.
+ *
+ * @throws \RuntimeException if no viable Handler is available.
+ * @return callable Returns the best handler for the given system.
+ */
+function choose_handler()
+{
+ $handler = null;
+ if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
+ $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
+ } elseif (function_exists('curl_exec')) {
+ $handler = new CurlHandler();
+ } elseif (function_exists('curl_multi_exec')) {
+ $handler = new CurlMultiHandler();
+ }
+
+ if (ini_get('allow_url_fopen')) {
+ $handler = $handler
+ ? Proxy::wrapStreaming($handler, new StreamHandler())
+ : new StreamHandler();
+ } elseif (!$handler) {
+ throw new \RuntimeException('GuzzleHttp requires cURL, the '
+ . 'allow_url_fopen ini setting, or a custom HTTP handler.');
+ }
+
+ return $handler;
+}
+
+/**
+ * Get the default User-Agent string to use with Guzzle
+ *
+ * @return string
+ */
+function default_user_agent()
+{
+ static $defaultAgent = '';
+
+ if (!$defaultAgent) {
+ $defaultAgent = 'GuzzleHttp/' . Client::VERSION;
+ if (extension_loaded('curl') && function_exists('curl_version')) {
+ $defaultAgent .= ' curl/' . \curl_version()['version'];
+ }
+ $defaultAgent .= ' PHP/' . PHP_VERSION;
+ }
+
+ return $defaultAgent;
+}
+
+/**
+ * Returns the default cacert bundle for the current system.
+ *
+ * First, the openssl.cafile and curl.cainfo php.ini settings are checked.
+ * If those settings are not configured, then the common locations for
+ * bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
+ * and Windows are checked. If any of these file locations are found on
+ * disk, they will be utilized.
+ *
+ * Note: the result of this function is cached for subsequent calls.
+ *
+ * @return string
+ * @throws \RuntimeException if no bundle can be found.
+ */
+function default_ca_bundle()
+{
+ static $cached = null;
+ static $cafiles = [
+ // Red Hat, CentOS, Fedora (provided by the ca-certificates package)
+ '/etc/pki/tls/certs/ca-bundle.crt',
+ // Ubuntu, Debian (provided by the ca-certificates package)
+ '/etc/ssl/certs/ca-certificates.crt',
+ // FreeBSD (provided by the ca_root_nss package)
+ '/usr/local/share/certs/ca-root-nss.crt',
+ // SLES 12 (provided by the ca-certificates package)
+ '/var/lib/ca-certificates/ca-bundle.pem',
+ // OS X provided by homebrew (using the default path)
+ '/usr/local/etc/openssl/cert.pem',
+ // Google app engine
+ '/etc/ca-certificates.crt',
+ // Windows?
+ 'C:\\windows\\system32\\curl-ca-bundle.crt',
+ 'C:\\windows\\curl-ca-bundle.crt',
+ ];
+
+ if ($cached) {
+ return $cached;
+ }
+
+ if ($ca = ini_get('openssl.cafile')) {
+ return $cached = $ca;
+ }
+
+ if ($ca = ini_get('curl.cainfo')) {
+ return $cached = $ca;
+ }
+
+ foreach ($cafiles as $filename) {
+ if (file_exists($filename)) {
+ return $cached = $filename;
+ }
+ }
+
+ throw new \RuntimeException(
+ <<< EOT
+No system CA bundle could be found in any of the the common system locations.
+PHP versions earlier than 5.6 are not properly configured to use the system's
+CA bundle by default. In order to verify peer certificates, you will need to
+supply the path on disk to a certificate bundle to the 'verify' request
+option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
+need a specific certificate bundle, then Mozilla provides a commonly used CA
+bundle which can be downloaded here (provided by the maintainer of cURL):
+https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
+you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
+ini setting to point to the path to the file, allowing you to omit the 'verify'
+request option. See http://curl.haxx.se/docs/sslcerts.html for more
+information.
+EOT
+ );
+}
+
+/**
+ * Creates an associative array of lowercase header names to the actual
+ * header casing.
+ *
+ * @param array $headers
+ *
+ * @return array
+ */
+function normalize_header_keys(array $headers)
+{
+ $result = [];
+ foreach (array_keys($headers) as $key) {
+ $result[strtolower($key)] = $key;
+ }
+
+ return $result;
+}
+
+/**
+ * Returns true if the provided host matches any of the no proxy areas.
+ *
+ * This method will strip a port from the host if it is present. Each pattern
+ * can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
+ * partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
+ * "baz.foo.com", but ".foo.com" != "foo.com").
+ *
+ * Areas are matched in the following cases:
+ * 1. "*" (without quotes) always matches any hosts.
+ * 2. An exact match.
+ * 3. The area starts with "." and the area is the last part of the host. e.g.
+ * '.mit.edu' will match any host that ends with '.mit.edu'.
+ *
+ * @param string $host Host to check against the patterns.
+ * @param array $noProxyArray An array of host patterns.
+ *
+ * @return bool
+ */
+function is_host_in_noproxy($host, array $noProxyArray)
+{
+ if (strlen($host) === 0) {
+ throw new \InvalidArgumentException('Empty host provided');
+ }
+
+ // Strip port if present.
+ if (strpos($host, ':')) {
+ $host = explode($host, ':', 2)[0];
+ }
+
+ foreach ($noProxyArray as $area) {
+ // Always match on wildcards.
+ if ($area === '*') {
+ return true;
+ } elseif (empty($area)) {
+ // Don't match on empty values.
+ continue;
+ } elseif ($area === $host) {
+ // Exact matches.
+ return true;
+ } else {
+ // Special match if the area when prefixed with ".". Remove any
+ // existing leading "." and add a new leading ".".
+ $area = '.' . ltrim($area, '.');
+ if (substr($host, -(strlen($area))) === $area) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Wrapper for json_decode that throws when an error occurs.
+ *
+ * @param string $json JSON data to parse
+ * @param bool $assoc When true, returned objects will be converted
+ * into associative arrays.
+ * @param int $depth User specified recursion depth.
+ * @param int $options Bitmask of JSON decode options.
+ *
+ * @return mixed
+ * @throws Exception\InvalidArgumentException if the JSON cannot be decoded.
+ * @link http://www.php.net/manual/en/function.json-decode.php
+ */
+function json_decode($json, $assoc = false, $depth = 512, $options = 0)
+{
+ $data = \json_decode($json, $assoc, $depth, $options);
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ throw new Exception\InvalidArgumentException(
+ 'json_decode error: ' . json_last_error_msg()
+ );
+ }
+
+ return $data;
+}
+
+/**
+ * Wrapper for JSON encoding that throws when an error occurs.
+ *
+ * @param mixed $value The value being encoded
+ * @param int $options JSON encode option bitmask
+ * @param int $depth Set the maximum depth. Must be greater than zero.
+ *
+ * @return string
+ * @throws Exception\InvalidArgumentException if the JSON cannot be encoded.
+ * @link http://www.php.net/manual/en/function.json-encode.php
+ */
+function json_encode($value, $options = 0, $depth = 512)
+{
+ $json = \json_encode($value, $options, $depth);
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ throw new Exception\InvalidArgumentException(
+ 'json_encode error: ' . json_last_error_msg()
+ );
+ }
+
+ return $json;
+}
+
+/**
+ * Wrapper for the hrtime() or microtime() functions
+ * (depending on the PHP version, one of the two is used)
+ *
+ * @return float|mixed UNIX timestamp
+ * @internal
+ */
+function _current_time()
+{
+ return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
+}
diff --git a/akamai/vendor/guzzlehttp/guzzle/src/functions_include.php b/akamai/vendor/guzzlehttp/guzzle/src/functions_include.php
new file mode 100644
index 00000000..a93393ac
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/guzzle/src/functions_include.php
@@ -0,0 +1,6 @@
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/akamai/vendor/guzzlehttp/promises/Makefile b/akamai/vendor/guzzlehttp/promises/Makefile
new file mode 100644
index 00000000..8d5b3ef9
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/Makefile
@@ -0,0 +1,13 @@
+all: clean test
+
+test:
+ vendor/bin/phpunit
+
+coverage:
+ vendor/bin/phpunit --coverage-html=artifacts/coverage
+
+view-coverage:
+ open artifacts/coverage/index.html
+
+clean:
+ rm -rf artifacts/*
diff --git a/akamai/vendor/guzzlehttp/promises/README.md b/akamai/vendor/guzzlehttp/promises/README.md
new file mode 100644
index 00000000..7b607e28
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/README.md
@@ -0,0 +1,504 @@
+# Guzzle Promises
+
+[Promises/A+](https://promisesaplus.com/) implementation that handles promise
+chaining and resolution iteratively, allowing for "infinite" promise chaining
+while keeping the stack size constant. Read [this blog post](https://blog.domenic.me/youre-missing-the-point-of-promises/)
+for a general introduction to promises.
+
+- [Features](#features)
+- [Quick start](#quick-start)
+- [Synchronous wait](#synchronous-wait)
+- [Cancellation](#cancellation)
+- [API](#api)
+ - [Promise](#promise)
+ - [FulfilledPromise](#fulfilledpromise)
+ - [RejectedPromise](#rejectedpromise)
+- [Promise interop](#promise-interop)
+- [Implementation notes](#implementation-notes)
+
+
+# Features
+
+- [Promises/A+](https://promisesaplus.com/) implementation.
+- Promise resolution and chaining is handled iteratively, allowing for
+ "infinite" promise chaining.
+- Promises have a synchronous `wait` method.
+- Promises can be cancelled.
+- Works with any object that has a `then` function.
+- C# style async/await coroutine promises using
+ `GuzzleHttp\Promise\coroutine()`.
+
+
+# Quick start
+
+A *promise* represents the eventual result of an asynchronous operation. The
+primary way of interacting with a promise is through its `then` method, which
+registers callbacks to receive either a promise's eventual value or the reason
+why the promise cannot be fulfilled.
+
+
+## Callbacks
+
+Callbacks are registered with the `then` method by providing an optional
+`$onFulfilled` followed by an optional `$onRejected` function.
+
+
+```php
+use GuzzleHttp\Promise\Promise;
+
+$promise = new Promise();
+$promise->then(
+ // $onFulfilled
+ function ($value) {
+ echo 'The promise was fulfilled.';
+ },
+ // $onRejected
+ function ($reason) {
+ echo 'The promise was rejected.';
+ }
+);
+```
+
+*Resolving* a promise means that you either fulfill a promise with a *value* or
+reject a promise with a *reason*. Resolving a promises triggers callbacks
+registered with the promises's `then` method. These callbacks are triggered
+only once and in the order in which they were added.
+
+
+## Resolving a promise
+
+Promises are fulfilled using the `resolve($value)` method. Resolving a promise
+with any value other than a `GuzzleHttp\Promise\RejectedPromise` will trigger
+all of the onFulfilled callbacks (resolving a promise with a rejected promise
+will reject the promise and trigger the `$onRejected` callbacks).
+
+```php
+use GuzzleHttp\Promise\Promise;
+
+$promise = new Promise();
+$promise
+ ->then(function ($value) {
+ // Return a value and don't break the chain
+ return "Hello, " . $value;
+ })
+ // This then is executed after the first then and receives the value
+ // returned from the first then.
+ ->then(function ($value) {
+ echo $value;
+ });
+
+// Resolving the promise triggers the $onFulfilled callbacks and outputs
+// "Hello, reader".
+$promise->resolve('reader.');
+```
+
+
+## Promise forwarding
+
+Promises can be chained one after the other. Each then in the chain is a new
+promise. The return value of a promise is what's forwarded to the next
+promise in the chain. Returning a promise in a `then` callback will cause the
+subsequent promises in the chain to only be fulfilled when the returned promise
+has been fulfilled. The next promise in the chain will be invoked with the
+resolved value of the promise.
+
+```php
+use GuzzleHttp\Promise\Promise;
+
+$promise = new Promise();
+$nextPromise = new Promise();
+
+$promise
+ ->then(function ($value) use ($nextPromise) {
+ echo $value;
+ return $nextPromise;
+ })
+ ->then(function ($value) {
+ echo $value;
+ });
+
+// Triggers the first callback and outputs "A"
+$promise->resolve('A');
+// Triggers the second callback and outputs "B"
+$nextPromise->resolve('B');
+```
+
+## Promise rejection
+
+When a promise is rejected, the `$onRejected` callbacks are invoked with the
+rejection reason.
+
+```php
+use GuzzleHttp\Promise\Promise;
+
+$promise = new Promise();
+$promise->then(null, function ($reason) {
+ echo $reason;
+});
+
+$promise->reject('Error!');
+// Outputs "Error!"
+```
+
+## Rejection forwarding
+
+If an exception is thrown in an `$onRejected` callback, subsequent
+`$onRejected` callbacks are invoked with the thrown exception as the reason.
+
+```php
+use GuzzleHttp\Promise\Promise;
+
+$promise = new Promise();
+$promise->then(null, function ($reason) {
+ throw new \Exception($reason);
+})->then(null, function ($reason) {
+ assert($reason->getMessage() === 'Error!');
+});
+
+$promise->reject('Error!');
+```
+
+You can also forward a rejection down the promise chain by returning a
+`GuzzleHttp\Promise\RejectedPromise` in either an `$onFulfilled` or
+`$onRejected` callback.
+
+```php
+use GuzzleHttp\Promise\Promise;
+use GuzzleHttp\Promise\RejectedPromise;
+
+$promise = new Promise();
+$promise->then(null, function ($reason) {
+ return new RejectedPromise($reason);
+})->then(null, function ($reason) {
+ assert($reason === 'Error!');
+});
+
+$promise->reject('Error!');
+```
+
+If an exception is not thrown in a `$onRejected` callback and the callback
+does not return a rejected promise, downstream `$onFulfilled` callbacks are
+invoked using the value returned from the `$onRejected` callback.
+
+```php
+use GuzzleHttp\Promise\Promise;
+use GuzzleHttp\Promise\RejectedPromise;
+
+$promise = new Promise();
+$promise
+ ->then(null, function ($reason) {
+ return "It's ok";
+ })
+ ->then(function ($value) {
+ assert($value === "It's ok");
+ });
+
+$promise->reject('Error!');
+```
+
+# Synchronous wait
+
+You can synchronously force promises to complete using a promise's `wait`
+method. When creating a promise, you can provide a wait function that is used
+to synchronously force a promise to complete. When a wait function is invoked
+it is expected to deliver a value to the promise or reject the promise. If the
+wait function does not deliver a value, then an exception is thrown. The wait
+function provided to a promise constructor is invoked when the `wait` function
+of the promise is called.
+
+```php
+$promise = new Promise(function () use (&$promise) {
+ $promise->resolve('foo');
+});
+
+// Calling wait will return the value of the promise.
+echo $promise->wait(); // outputs "foo"
+```
+
+If an exception is encountered while invoking the wait function of a promise,
+the promise is rejected with the exception and the exception is thrown.
+
+```php
+$promise = new Promise(function () use (&$promise) {
+ throw new \Exception('foo');
+});
+
+$promise->wait(); // throws the exception.
+```
+
+Calling `wait` on a promise that has been fulfilled will not trigger the wait
+function. It will simply return the previously resolved value.
+
+```php
+$promise = new Promise(function () { die('this is not called!'); });
+$promise->resolve('foo');
+echo $promise->wait(); // outputs "foo"
+```
+
+Calling `wait` on a promise that has been rejected will throw an exception. If
+the rejection reason is an instance of `\Exception` the reason is thrown.
+Otherwise, a `GuzzleHttp\Promise\RejectionException` is thrown and the reason
+can be obtained by calling the `getReason` method of the exception.
+
+```php
+$promise = new Promise();
+$promise->reject('foo');
+$promise->wait();
+```
+
+> PHP Fatal error: Uncaught exception 'GuzzleHttp\Promise\RejectionException' with message 'The promise was rejected with value: foo'
+
+
+## Unwrapping a promise
+
+When synchronously waiting on a promise, you are joining the state of the
+promise into the current state of execution (i.e., return the value of the
+promise if it was fulfilled or throw an exception if it was rejected). This is
+called "unwrapping" the promise. Waiting on a promise will by default unwrap
+the promise state.
+
+You can force a promise to resolve and *not* unwrap the state of the promise
+by passing `false` to the first argument of the `wait` function:
+
+```php
+$promise = new Promise();
+$promise->reject('foo');
+// This will not throw an exception. It simply ensures the promise has
+// been resolved.
+$promise->wait(false);
+```
+
+When unwrapping a promise, the resolved value of the promise will be waited
+upon until the unwrapped value is not a promise. This means that if you resolve
+promise A with a promise B and unwrap promise A, the value returned by the
+wait function will be the value delivered to promise B.
+
+**Note**: when you do not unwrap the promise, no value is returned.
+
+
+# Cancellation
+
+You can cancel a promise that has not yet been fulfilled using the `cancel()`
+method of a promise. When creating a promise you can provide an optional
+cancel function that when invoked cancels the action of computing a resolution
+of the promise.
+
+
+# API
+
+
+## Promise
+
+When creating a promise object, you can provide an optional `$waitFn` and
+`$cancelFn`. `$waitFn` is a function that is invoked with no arguments and is
+expected to resolve the promise. `$cancelFn` is a function with no arguments
+that is expected to cancel the computation of a promise. It is invoked when the
+`cancel()` method of a promise is called.
+
+```php
+use GuzzleHttp\Promise\Promise;
+
+$promise = new Promise(
+ function () use (&$promise) {
+ $promise->resolve('waited');
+ },
+ function () {
+ // do something that will cancel the promise computation (e.g., close
+ // a socket, cancel a database query, etc...)
+ }
+);
+
+assert('waited' === $promise->wait());
+```
+
+A promise has the following methods:
+
+- `then(callable $onFulfilled, callable $onRejected) : PromiseInterface`
+
+ Appends fulfillment and rejection handlers to the promise, and returns a new promise resolving to the return value of the called handler.
+
+- `otherwise(callable $onRejected) : PromiseInterface`
+
+ Appends a rejection handler callback to the promise, and returns a new promise resolving to the return value of the callback if it is called, or to its original fulfillment value if the promise is instead fulfilled.
+
+- `wait($unwrap = true) : mixed`
+
+ Synchronously waits on the promise to complete.
+
+ `$unwrap` controls whether or not the value of the promise is returned for a
+ fulfilled promise or if an exception is thrown if the promise is rejected.
+ This is set to `true` by default.
+
+- `cancel()`
+
+ Attempts to cancel the promise if possible. The promise being cancelled and
+ the parent most ancestor that has not yet been resolved will also be
+ cancelled. Any promises waiting on the cancelled promise to resolve will also
+ be cancelled.
+
+- `getState() : string`
+
+ Returns the state of the promise. One of `pending`, `fulfilled`, or
+ `rejected`.
+
+- `resolve($value)`
+
+ Fulfills the promise with the given `$value`.
+
+- `reject($reason)`
+
+ Rejects the promise with the given `$reason`.
+
+
+## FulfilledPromise
+
+A fulfilled promise can be created to represent a promise that has been
+fulfilled.
+
+```php
+use GuzzleHttp\Promise\FulfilledPromise;
+
+$promise = new FulfilledPromise('value');
+
+// Fulfilled callbacks are immediately invoked.
+$promise->then(function ($value) {
+ echo $value;
+});
+```
+
+
+## RejectedPromise
+
+A rejected promise can be created to represent a promise that has been
+rejected.
+
+```php
+use GuzzleHttp\Promise\RejectedPromise;
+
+$promise = new RejectedPromise('Error');
+
+// Rejected callbacks are immediately invoked.
+$promise->then(null, function ($reason) {
+ echo $reason;
+});
+```
+
+
+# Promise interop
+
+This library works with foreign promises that have a `then` method. This means
+you can use Guzzle promises with [React promises](https://github.com/reactphp/promise)
+for example. When a foreign promise is returned inside of a then method
+callback, promise resolution will occur recursively.
+
+```php
+// Create a React promise
+$deferred = new React\Promise\Deferred();
+$reactPromise = $deferred->promise();
+
+// Create a Guzzle promise that is fulfilled with a React promise.
+$guzzlePromise = new \GuzzleHttp\Promise\Promise();
+$guzzlePromise->then(function ($value) use ($reactPromise) {
+ // Do something something with the value...
+ // Return the React promise
+ return $reactPromise;
+});
+```
+
+Please note that wait and cancel chaining is no longer possible when forwarding
+a foreign promise. You will need to wrap a third-party promise with a Guzzle
+promise in order to utilize wait and cancel functions with foreign promises.
+
+
+## Event Loop Integration
+
+In order to keep the stack size constant, Guzzle promises are resolved
+asynchronously using a task queue. When waiting on promises synchronously, the
+task queue will be automatically run to ensure that the blocking promise and
+any forwarded promises are resolved. When using promises asynchronously in an
+event loop, you will need to run the task queue on each tick of the loop. If
+you do not run the task queue, then promises will not be resolved.
+
+You can run the task queue using the `run()` method of the global task queue
+instance.
+
+```php
+// Get the global task queue
+$queue = \GuzzleHttp\Promise\queue();
+$queue->run();
+```
+
+For example, you could use Guzzle promises with React using a periodic timer:
+
+```php
+$loop = React\EventLoop\Factory::create();
+$loop->addPeriodicTimer(0, [$queue, 'run']);
+```
+
+*TODO*: Perhaps adding a `futureTick()` on each tick would be faster?
+
+
+# Implementation notes
+
+
+## Promise resolution and chaining is handled iteratively
+
+By shuffling pending handlers from one owner to another, promises are
+resolved iteratively, allowing for "infinite" then chaining.
+
+```php
+then(function ($v) {
+ // The stack size remains constant (a good thing)
+ echo xdebug_get_stack_depth() . ', ';
+ return $v + 1;
+ });
+}
+
+$parent->resolve(0);
+var_dump($p->wait()); // int(1000)
+
+```
+
+When a promise is fulfilled or rejected with a non-promise value, the promise
+then takes ownership of the handlers of each child promise and delivers values
+down the chain without using recursion.
+
+When a promise is resolved with another promise, the original promise transfers
+all of its pending handlers to the new promise. When the new promise is
+eventually resolved, all of the pending handlers are delivered the forwarded
+value.
+
+
+## A promise is the deferred.
+
+Some promise libraries implement promises using a deferred object to represent
+a computation and a promise object to represent the delivery of the result of
+the computation. This is a nice separation of computation and delivery because
+consumers of the promise cannot modify the value that will be eventually
+delivered.
+
+One side effect of being able to implement promise resolution and chaining
+iteratively is that you need to be able for one promise to reach into the state
+of another promise to shuffle around ownership of handlers. In order to achieve
+this without making the handlers of a promise publicly mutable, a promise is
+also the deferred value, allowing promises of the same parent class to reach
+into and modify the private properties of promises of the same type. While this
+does allow consumers of the value to modify the resolution or rejection of the
+deferred, it is a small price to pay for keeping the stack size constant.
+
+```php
+$promise = new Promise();
+$promise->then(function ($value) { echo $value; });
+// The promise is the deferred value, so you can deliver a value to it.
+$promise->resolve('foo');
+// prints "foo"
+```
diff --git a/akamai/vendor/guzzlehttp/promises/composer.json b/akamai/vendor/guzzlehttp/promises/composer.json
new file mode 100644
index 00000000..ec41a61e
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "guzzlehttp/promises",
+ "description": "Guzzle promises library",
+ "keywords": ["promise"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "require": {
+ "php": ">=5.5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ },
+ "files": ["src/functions_include.php"]
+ },
+ "scripts": {
+ "test": "vendor/bin/phpunit",
+ "test-ci": "vendor/bin/phpunit --coverage-text"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/AggregateException.php b/akamai/vendor/guzzlehttp/promises/src/AggregateException.php
new file mode 100644
index 00000000..6a5690c3
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/AggregateException.php
@@ -0,0 +1,16 @@
+then(function ($v) { echo $v; });
+ *
+ * @param callable $generatorFn Generator function to wrap into a promise.
+ *
+ * @return Promise
+ * @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
+ */
+final class Coroutine implements PromiseInterface
+{
+ /**
+ * @var PromiseInterface|null
+ */
+ private $currentPromise;
+
+ /**
+ * @var Generator
+ */
+ private $generator;
+
+ /**
+ * @var Promise
+ */
+ private $result;
+
+ public function __construct(callable $generatorFn)
+ {
+ $this->generator = $generatorFn();
+ $this->result = new Promise(function () {
+ while (isset($this->currentPromise)) {
+ $this->currentPromise->wait();
+ }
+ });
+ $this->nextCoroutine($this->generator->current());
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ return $this->result->then($onFulfilled, $onRejected);
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->result->otherwise($onRejected);
+ }
+
+ public function wait($unwrap = true)
+ {
+ return $this->result->wait($unwrap);
+ }
+
+ public function getState()
+ {
+ return $this->result->getState();
+ }
+
+ public function resolve($value)
+ {
+ $this->result->resolve($value);
+ }
+
+ public function reject($reason)
+ {
+ $this->result->reject($reason);
+ }
+
+ public function cancel()
+ {
+ $this->currentPromise->cancel();
+ $this->result->cancel();
+ }
+
+ private function nextCoroutine($yielded)
+ {
+ $this->currentPromise = promise_for($yielded)
+ ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
+ }
+
+ /**
+ * @internal
+ */
+ public function _handleSuccess($value)
+ {
+ unset($this->currentPromise);
+ try {
+ $next = $this->generator->send($value);
+ if ($this->generator->valid()) {
+ $this->nextCoroutine($next);
+ } else {
+ $this->result->resolve($value);
+ }
+ } catch (Exception $exception) {
+ $this->result->reject($exception);
+ } catch (Throwable $throwable) {
+ $this->result->reject($throwable);
+ }
+ }
+
+ /**
+ * @internal
+ */
+ public function _handleFailure($reason)
+ {
+ unset($this->currentPromise);
+ try {
+ $nextYield = $this->generator->throw(exception_for($reason));
+ // The throw was caught, so keep iterating on the coroutine
+ $this->nextCoroutine($nextYield);
+ } catch (Exception $exception) {
+ $this->result->reject($exception);
+ } catch (Throwable $throwable) {
+ $this->result->reject($throwable);
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/EachPromise.php b/akamai/vendor/guzzlehttp/promises/src/EachPromise.php
new file mode 100644
index 00000000..d0ddf603
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/EachPromise.php
@@ -0,0 +1,229 @@
+iterable = iter_for($iterable);
+
+ if (isset($config['concurrency'])) {
+ $this->concurrency = $config['concurrency'];
+ }
+
+ if (isset($config['fulfilled'])) {
+ $this->onFulfilled = $config['fulfilled'];
+ }
+
+ if (isset($config['rejected'])) {
+ $this->onRejected = $config['rejected'];
+ }
+ }
+
+ public function promise()
+ {
+ if ($this->aggregate) {
+ return $this->aggregate;
+ }
+
+ try {
+ $this->createPromise();
+ $this->iterable->rewind();
+ $this->refillPending();
+ } catch (\Throwable $e) {
+ $this->aggregate->reject($e);
+ } catch (\Exception $e) {
+ $this->aggregate->reject($e);
+ }
+
+ return $this->aggregate;
+ }
+
+ private function createPromise()
+ {
+ $this->mutex = false;
+ $this->aggregate = new Promise(function () {
+ reset($this->pending);
+ if (empty($this->pending) && !$this->iterable->valid()) {
+ $this->aggregate->resolve(null);
+ return;
+ }
+
+ // Consume a potentially fluctuating list of promises while
+ // ensuring that indexes are maintained (precluding array_shift).
+ while ($promise = current($this->pending)) {
+ next($this->pending);
+ $promise->wait();
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
+ return;
+ }
+ }
+ });
+
+ // Clear the references when the promise is resolved.
+ $clearFn = function () {
+ $this->iterable = $this->concurrency = $this->pending = null;
+ $this->onFulfilled = $this->onRejected = null;
+ };
+
+ $this->aggregate->then($clearFn, $clearFn);
+ }
+
+ private function refillPending()
+ {
+ if (!$this->concurrency) {
+ // Add all pending promises.
+ while ($this->addPending() && $this->advanceIterator());
+ return;
+ }
+
+ // Add only up to N pending promises.
+ $concurrency = is_callable($this->concurrency)
+ ? call_user_func($this->concurrency, count($this->pending))
+ : $this->concurrency;
+ $concurrency = max($concurrency - count($this->pending), 0);
+ // Concurrency may be set to 0 to disallow new promises.
+ if (!$concurrency) {
+ return;
+ }
+ // Add the first pending promise.
+ $this->addPending();
+ // Note this is special handling for concurrency=1 so that we do
+ // not advance the iterator after adding the first promise. This
+ // helps work around issues with generators that might not have the
+ // next value to yield until promise callbacks are called.
+ while (--$concurrency
+ && $this->advanceIterator()
+ && $this->addPending());
+ }
+
+ private function addPending()
+ {
+ if (!$this->iterable || !$this->iterable->valid()) {
+ return false;
+ }
+
+ $promise = promise_for($this->iterable->current());
+ $idx = $this->iterable->key();
+
+ $this->pending[$idx] = $promise->then(
+ function ($value) use ($idx) {
+ if ($this->onFulfilled) {
+ call_user_func(
+ $this->onFulfilled, $value, $idx, $this->aggregate
+ );
+ }
+ $this->step($idx);
+ },
+ function ($reason) use ($idx) {
+ if ($this->onRejected) {
+ call_user_func(
+ $this->onRejected, $reason, $idx, $this->aggregate
+ );
+ }
+ $this->step($idx);
+ }
+ );
+
+ return true;
+ }
+
+ private function advanceIterator()
+ {
+ // Place a lock on the iterator so that we ensure to not recurse,
+ // preventing fatal generator errors.
+ if ($this->mutex) {
+ return false;
+ }
+
+ $this->mutex = true;
+
+ try {
+ $this->iterable->next();
+ $this->mutex = false;
+ return true;
+ } catch (\Throwable $e) {
+ $this->aggregate->reject($e);
+ $this->mutex = false;
+ return false;
+ } catch (\Exception $e) {
+ $this->aggregate->reject($e);
+ $this->mutex = false;
+ return false;
+ }
+ }
+
+ private function step($idx)
+ {
+ // If the promise was already resolved, then ignore this step.
+ if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
+ return;
+ }
+
+ unset($this->pending[$idx]);
+
+ // Only refill pending promises if we are not locked, preventing the
+ // EachPromise to recursively invoke the provided iterator, which
+ // cause a fatal error: "Cannot resume an already running generator"
+ if ($this->advanceIterator() && !$this->checkIfFinished()) {
+ // Add more pending promises if possible.
+ $this->refillPending();
+ }
+ }
+
+ private function checkIfFinished()
+ {
+ if (!$this->pending && !$this->iterable->valid()) {
+ // Resolve the promise if there's nothing left to do.
+ $this->aggregate->resolve(null);
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/FulfilledPromise.php b/akamai/vendor/guzzlehttp/promises/src/FulfilledPromise.php
new file mode 100644
index 00000000..dbbeeb9f
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/FulfilledPromise.php
@@ -0,0 +1,82 @@
+value = $value;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ // Return itself if there is no onFulfilled function.
+ if (!$onFulfilled) {
+ return $this;
+ }
+
+ $queue = queue();
+ $p = new Promise([$queue, 'run']);
+ $value = $this->value;
+ $queue->add(static function () use ($p, $value, $onFulfilled) {
+ if ($p->getState() === self::PENDING) {
+ try {
+ $p->resolve($onFulfilled($value));
+ } catch (\Throwable $e) {
+ $p->reject($e);
+ } catch (\Exception $e) {
+ $p->reject($e);
+ }
+ }
+ });
+
+ return $p;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true, $defaultDelivery = null)
+ {
+ return $unwrap ? $this->value : null;
+ }
+
+ public function getState()
+ {
+ return self::FULFILLED;
+ }
+
+ public function resolve($value)
+ {
+ if ($value !== $this->value) {
+ throw new \LogicException("Cannot resolve a fulfilled promise");
+ }
+ }
+
+ public function reject($reason)
+ {
+ throw new \LogicException("Cannot reject a fulfilled promise");
+ }
+
+ public function cancel()
+ {
+ // pass
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/Promise.php b/akamai/vendor/guzzlehttp/promises/src/Promise.php
new file mode 100644
index 00000000..844ada07
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/Promise.php
@@ -0,0 +1,280 @@
+waitFn = $waitFn;
+ $this->cancelFn = $cancelFn;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ if ($this->state === self::PENDING) {
+ $p = new Promise(null, [$this, 'cancel']);
+ $this->handlers[] = [$p, $onFulfilled, $onRejected];
+ $p->waitList = $this->waitList;
+ $p->waitList[] = $this;
+ return $p;
+ }
+
+ // Return a fulfilled promise and immediately invoke any callbacks.
+ if ($this->state === self::FULFILLED) {
+ return $onFulfilled
+ ? promise_for($this->result)->then($onFulfilled)
+ : promise_for($this->result);
+ }
+
+ // It's either cancelled or rejected, so return a rejected promise
+ // and immediately invoke any callbacks.
+ $rejection = rejection_for($this->result);
+ return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true)
+ {
+ $this->waitIfPending();
+
+ $inner = $this->result instanceof PromiseInterface
+ ? $this->result->wait($unwrap)
+ : $this->result;
+
+ if ($unwrap) {
+ if ($this->result instanceof PromiseInterface
+ || $this->state === self::FULFILLED
+ ) {
+ return $inner;
+ } else {
+ // It's rejected so "unwrap" and throw an exception.
+ throw exception_for($inner);
+ }
+ }
+ }
+
+ public function getState()
+ {
+ return $this->state;
+ }
+
+ public function cancel()
+ {
+ if ($this->state !== self::PENDING) {
+ return;
+ }
+
+ $this->waitFn = $this->waitList = null;
+
+ if ($this->cancelFn) {
+ $fn = $this->cancelFn;
+ $this->cancelFn = null;
+ try {
+ $fn();
+ } catch (\Throwable $e) {
+ $this->reject($e);
+ } catch (\Exception $e) {
+ $this->reject($e);
+ }
+ }
+
+ // Reject the promise only if it wasn't rejected in a then callback.
+ if ($this->state === self::PENDING) {
+ $this->reject(new CancellationException('Promise has been cancelled'));
+ }
+ }
+
+ public function resolve($value)
+ {
+ $this->settle(self::FULFILLED, $value);
+ }
+
+ public function reject($reason)
+ {
+ $this->settle(self::REJECTED, $reason);
+ }
+
+ private function settle($state, $value)
+ {
+ if ($this->state !== self::PENDING) {
+ // Ignore calls with the same resolution.
+ if ($state === $this->state && $value === $this->result) {
+ return;
+ }
+ throw $this->state === $state
+ ? new \LogicException("The promise is already {$state}.")
+ : new \LogicException("Cannot change a {$this->state} promise to {$state}");
+ }
+
+ if ($value === $this) {
+ throw new \LogicException('Cannot fulfill or reject a promise with itself');
+ }
+
+ // Clear out the state of the promise but stash the handlers.
+ $this->state = $state;
+ $this->result = $value;
+ $handlers = $this->handlers;
+ $this->handlers = null;
+ $this->waitList = $this->waitFn = null;
+ $this->cancelFn = null;
+
+ if (!$handlers) {
+ return;
+ }
+
+ // If the value was not a settled promise or a thenable, then resolve
+ // it in the task queue using the correct ID.
+ if (!method_exists($value, 'then')) {
+ $id = $state === self::FULFILLED ? 1 : 2;
+ // It's a success, so resolve the handlers in the queue.
+ queue()->add(static function () use ($id, $value, $handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler($id, $value, $handler);
+ }
+ });
+ } elseif ($value instanceof Promise
+ && $value->getState() === self::PENDING
+ ) {
+ // We can just merge our handlers onto the next promise.
+ $value->handlers = array_merge($value->handlers, $handlers);
+ } else {
+ // Resolve the handlers when the forwarded promise is resolved.
+ $value->then(
+ static function ($value) use ($handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler(1, $value, $handler);
+ }
+ },
+ static function ($reason) use ($handlers) {
+ foreach ($handlers as $handler) {
+ self::callHandler(2, $reason, $handler);
+ }
+ }
+ );
+ }
+ }
+
+ /**
+ * Call a stack of handlers using a specific callback index and value.
+ *
+ * @param int $index 1 (resolve) or 2 (reject).
+ * @param mixed $value Value to pass to the callback.
+ * @param array $handler Array of handler data (promise and callbacks).
+ *
+ * @return array Returns the next group to resolve.
+ */
+ private static function callHandler($index, $value, array $handler)
+ {
+ /** @var PromiseInterface $promise */
+ $promise = $handler[0];
+
+ // The promise may have been cancelled or resolved before placing
+ // this thunk in the queue.
+ if ($promise->getState() !== self::PENDING) {
+ return;
+ }
+
+ try {
+ if (isset($handler[$index])) {
+ $promise->resolve($handler[$index]($value));
+ } elseif ($index === 1) {
+ // Forward resolution values as-is.
+ $promise->resolve($value);
+ } else {
+ // Forward rejections down the chain.
+ $promise->reject($value);
+ }
+ } catch (\Throwable $reason) {
+ $promise->reject($reason);
+ } catch (\Exception $reason) {
+ $promise->reject($reason);
+ }
+ }
+
+ private function waitIfPending()
+ {
+ if ($this->state !== self::PENDING) {
+ return;
+ } elseif ($this->waitFn) {
+ $this->invokeWaitFn();
+ } elseif ($this->waitList) {
+ $this->invokeWaitList();
+ } else {
+ // If there's not wait function, then reject the promise.
+ $this->reject('Cannot wait on a promise that has '
+ . 'no internal wait function. You must provide a wait '
+ . 'function when constructing the promise to be able to '
+ . 'wait on a promise.');
+ }
+
+ queue()->run();
+
+ if ($this->state === self::PENDING) {
+ $this->reject('Invoking the wait callback did not resolve the promise');
+ }
+ }
+
+ private function invokeWaitFn()
+ {
+ try {
+ $wfn = $this->waitFn;
+ $this->waitFn = null;
+ $wfn(true);
+ } catch (\Exception $reason) {
+ if ($this->state === self::PENDING) {
+ // The promise has not been resolved yet, so reject the promise
+ // with the exception.
+ $this->reject($reason);
+ } else {
+ // The promise was already resolved, so there's a problem in
+ // the application.
+ throw $reason;
+ }
+ }
+ }
+
+ private function invokeWaitList()
+ {
+ $waitList = $this->waitList;
+ $this->waitList = null;
+
+ foreach ($waitList as $result) {
+ while (true) {
+ $result->waitIfPending();
+
+ if ($result->result instanceof Promise) {
+ $result = $result->result;
+ } else {
+ if ($result->result instanceof PromiseInterface) {
+ $result->result->wait(false);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/PromiseInterface.php b/akamai/vendor/guzzlehttp/promises/src/PromiseInterface.php
new file mode 100644
index 00000000..8f5f4b99
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/PromiseInterface.php
@@ -0,0 +1,93 @@
+reason = $reason;
+ }
+
+ public function then(
+ callable $onFulfilled = null,
+ callable $onRejected = null
+ ) {
+ // If there's no onRejected callback then just return self.
+ if (!$onRejected) {
+ return $this;
+ }
+
+ $queue = queue();
+ $reason = $this->reason;
+ $p = new Promise([$queue, 'run']);
+ $queue->add(static function () use ($p, $reason, $onRejected) {
+ if ($p->getState() === self::PENDING) {
+ try {
+ // Return a resolved promise if onRejected does not throw.
+ $p->resolve($onRejected($reason));
+ } catch (\Throwable $e) {
+ // onRejected threw, so return a rejected promise.
+ $p->reject($e);
+ } catch (\Exception $e) {
+ // onRejected threw, so return a rejected promise.
+ $p->reject($e);
+ }
+ }
+ });
+
+ return $p;
+ }
+
+ public function otherwise(callable $onRejected)
+ {
+ return $this->then(null, $onRejected);
+ }
+
+ public function wait($unwrap = true, $defaultDelivery = null)
+ {
+ if ($unwrap) {
+ throw exception_for($this->reason);
+ }
+ }
+
+ public function getState()
+ {
+ return self::REJECTED;
+ }
+
+ public function resolve($value)
+ {
+ throw new \LogicException("Cannot resolve a rejected promise");
+ }
+
+ public function reject($reason)
+ {
+ if ($reason !== $this->reason) {
+ throw new \LogicException("Cannot reject a rejected promise");
+ }
+ }
+
+ public function cancel()
+ {
+ // pass
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/RejectionException.php b/akamai/vendor/guzzlehttp/promises/src/RejectionException.php
new file mode 100644
index 00000000..07c1136d
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/RejectionException.php
@@ -0,0 +1,47 @@
+reason = $reason;
+
+ $message = 'The promise was rejected';
+
+ if ($description) {
+ $message .= ' with reason: ' . $description;
+ } elseif (is_string($reason)
+ || (is_object($reason) && method_exists($reason, '__toString'))
+ ) {
+ $message .= ' with reason: ' . $this->reason;
+ } elseif ($reason instanceof \JsonSerializable) {
+ $message .= ' with reason: '
+ . json_encode($this->reason, JSON_PRETTY_PRINT);
+ }
+
+ parent::__construct($message);
+ }
+
+ /**
+ * Returns the rejection reason.
+ *
+ * @return mixed
+ */
+ public function getReason()
+ {
+ return $this->reason;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/TaskQueue.php b/akamai/vendor/guzzlehttp/promises/src/TaskQueue.php
new file mode 100644
index 00000000..6e8a2a08
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/TaskQueue.php
@@ -0,0 +1,66 @@
+run();
+ */
+class TaskQueue implements TaskQueueInterface
+{
+ private $enableShutdown = true;
+ private $queue = [];
+
+ public function __construct($withShutdown = true)
+ {
+ if ($withShutdown) {
+ register_shutdown_function(function () {
+ if ($this->enableShutdown) {
+ // Only run the tasks if an E_ERROR didn't occur.
+ $err = error_get_last();
+ if (!$err || ($err['type'] ^ E_ERROR)) {
+ $this->run();
+ }
+ }
+ });
+ }
+ }
+
+ public function isEmpty()
+ {
+ return !$this->queue;
+ }
+
+ public function add(callable $task)
+ {
+ $this->queue[] = $task;
+ }
+
+ public function run()
+ {
+ /** @var callable $task */
+ while ($task = array_shift($this->queue)) {
+ $task();
+ }
+ }
+
+ /**
+ * The task queue will be run and exhausted by default when the process
+ * exits IFF the exit is not the result of a PHP E_ERROR error.
+ *
+ * You can disable running the automatic shutdown of the queue by calling
+ * this function. If you disable the task queue shutdown process, then you
+ * MUST either run the task queue (as a result of running your event loop
+ * or manually using the run() method) or wait on each outstanding promise.
+ *
+ * Note: This shutdown will occur before any destructors are triggered.
+ */
+ public function disableShutdown()
+ {
+ $this->enableShutdown = false;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/TaskQueueInterface.php b/akamai/vendor/guzzlehttp/promises/src/TaskQueueInterface.php
new file mode 100644
index 00000000..ac8306e1
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/TaskQueueInterface.php
@@ -0,0 +1,25 @@
+
+ * while ($eventLoop->isRunning()) {
+ * GuzzleHttp\Promise\queue()->run();
+ * }
+ *
+ *
+ * @param TaskQueueInterface $assign Optionally specify a new queue instance.
+ *
+ * @return TaskQueueInterface
+ */
+function queue(TaskQueueInterface $assign = null)
+{
+ static $queue;
+
+ if ($assign) {
+ $queue = $assign;
+ } elseif (!$queue) {
+ $queue = new TaskQueue();
+ }
+
+ return $queue;
+}
+
+/**
+ * Adds a function to run in the task queue when it is next `run()` and returns
+ * a promise that is fulfilled or rejected with the result.
+ *
+ * @param callable $task Task function to run.
+ *
+ * @return PromiseInterface
+ */
+function task(callable $task)
+{
+ $queue = queue();
+ $promise = new Promise([$queue, 'run']);
+ $queue->add(function () use ($task, $promise) {
+ try {
+ $promise->resolve($task());
+ } catch (\Throwable $e) {
+ $promise->reject($e);
+ } catch (\Exception $e) {
+ $promise->reject($e);
+ }
+ });
+
+ return $promise;
+}
+
+/**
+ * Creates a promise for a value if the value is not a promise.
+ *
+ * @param mixed $value Promise or value.
+ *
+ * @return PromiseInterface
+ */
+function promise_for($value)
+{
+ if ($value instanceof PromiseInterface) {
+ return $value;
+ }
+
+ // Return a Guzzle promise that shadows the given promise.
+ if (method_exists($value, 'then')) {
+ $wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
+ $cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
+ $promise = new Promise($wfn, $cfn);
+ $value->then([$promise, 'resolve'], [$promise, 'reject']);
+ return $promise;
+ }
+
+ return new FulfilledPromise($value);
+}
+
+/**
+ * Creates a rejected promise for a reason if the reason is not a promise. If
+ * the provided reason is a promise, then it is returned as-is.
+ *
+ * @param mixed $reason Promise or reason.
+ *
+ * @return PromiseInterface
+ */
+function rejection_for($reason)
+{
+ if ($reason instanceof PromiseInterface) {
+ return $reason;
+ }
+
+ return new RejectedPromise($reason);
+}
+
+/**
+ * Create an exception for a rejected promise value.
+ *
+ * @param mixed $reason
+ *
+ * @return \Exception|\Throwable
+ */
+function exception_for($reason)
+{
+ return $reason instanceof \Exception || $reason instanceof \Throwable
+ ? $reason
+ : new RejectionException($reason);
+}
+
+/**
+ * Returns an iterator for the given value.
+ *
+ * @param mixed $value
+ *
+ * @return \Iterator
+ */
+function iter_for($value)
+{
+ if ($value instanceof \Iterator) {
+ return $value;
+ } elseif (is_array($value)) {
+ return new \ArrayIterator($value);
+ } else {
+ return new \ArrayIterator([$value]);
+ }
+}
+
+/**
+ * Synchronously waits on a promise to resolve and returns an inspection state
+ * array.
+ *
+ * Returns a state associative array containing a "state" key mapping to a
+ * valid promise state. If the state of the promise is "fulfilled", the array
+ * will contain a "value" key mapping to the fulfilled value of the promise. If
+ * the promise is rejected, the array will contain a "reason" key mapping to
+ * the rejection reason of the promise.
+ *
+ * @param PromiseInterface $promise Promise or value.
+ *
+ * @return array
+ */
+function inspect(PromiseInterface $promise)
+{
+ try {
+ return [
+ 'state' => PromiseInterface::FULFILLED,
+ 'value' => $promise->wait()
+ ];
+ } catch (RejectionException $e) {
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
+ } catch (\Throwable $e) {
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
+ } catch (\Exception $e) {
+ return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
+ }
+}
+
+/**
+ * Waits on all of the provided promises, but does not unwrap rejected promises
+ * as thrown exception.
+ *
+ * Returns an array of inspection state arrays.
+ *
+ * @param PromiseInterface[] $promises Traversable of promises to wait upon.
+ *
+ * @return array
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
+ */
+function inspect_all($promises)
+{
+ $results = [];
+ foreach ($promises as $key => $promise) {
+ $results[$key] = inspect($promise);
+ }
+
+ return $results;
+}
+
+/**
+ * Waits on all of the provided promises and returns the fulfilled values.
+ *
+ * Returns an array that contains the value of each promise (in the same order
+ * the promises were provided). An exception is thrown if any of the promises
+ * are rejected.
+ *
+ * @param mixed $promises Iterable of PromiseInterface objects to wait on.
+ *
+ * @return array
+ * @throws \Exception on error
+ * @throws \Throwable on error in PHP >=7
+ */
+function unwrap($promises)
+{
+ $results = [];
+ foreach ($promises as $key => $promise) {
+ $results[$key] = $promise->wait();
+ }
+
+ return $results;
+}
+
+/**
+ * Given an array of promises, return a promise that is fulfilled when all the
+ * items in the array are fulfilled.
+ *
+ * The promise's fulfillment value is an array with fulfillment values at
+ * respective positions to the original array. If any promise in the array
+ * rejects, the returned promise is rejected with the rejection reason.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ */
+function all($promises)
+{
+ $results = [];
+ return each(
+ $promises,
+ function ($value, $idx) use (&$results) {
+ $results[$idx] = $value;
+ },
+ function ($reason, $idx, Promise $aggregate) {
+ $aggregate->reject($reason);
+ }
+ )->then(function () use (&$results) {
+ ksort($results);
+ return $results;
+ });
+}
+
+/**
+ * Initiate a competitive race between multiple promises or values (values will
+ * become immediately fulfilled promises).
+ *
+ * When count amount of promises have been fulfilled, the returned promise is
+ * fulfilled with an array that contains the fulfillment values of the winners
+ * in order of resolution.
+ *
+ * This prommise is rejected with a {@see GuzzleHttp\Promise\AggregateException}
+ * if the number of fulfilled promises is less than the desired $count.
+ *
+ * @param int $count Total number of promises.
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ */
+function some($count, $promises)
+{
+ $results = [];
+ $rejections = [];
+
+ return each(
+ $promises,
+ function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
+ if ($p->getState() !== PromiseInterface::PENDING) {
+ return;
+ }
+ $results[$idx] = $value;
+ if (count($results) >= $count) {
+ $p->resolve(null);
+ }
+ },
+ function ($reason) use (&$rejections) {
+ $rejections[] = $reason;
+ }
+ )->then(
+ function () use (&$results, &$rejections, $count) {
+ if (count($results) !== $count) {
+ throw new AggregateException(
+ 'Not enough promises to fulfill count',
+ $rejections
+ );
+ }
+ ksort($results);
+ return array_values($results);
+ }
+ );
+}
+
+/**
+ * Like some(), with 1 as count. However, if the promise fulfills, the
+ * fulfillment value is not an array of 1 but the value directly.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ */
+function any($promises)
+{
+ return some(1, $promises)->then(function ($values) { return $values[0]; });
+}
+
+/**
+ * Returns a promise that is fulfilled when all of the provided promises have
+ * been fulfilled or rejected.
+ *
+ * The returned promise is fulfilled with an array of inspection state arrays.
+ *
+ * @param mixed $promises Promises or values.
+ *
+ * @return PromiseInterface
+ * @see GuzzleHttp\Promise\inspect for the inspection state array format.
+ */
+function settle($promises)
+{
+ $results = [];
+
+ return each(
+ $promises,
+ function ($value, $idx) use (&$results) {
+ $results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
+ },
+ function ($reason, $idx) use (&$results) {
+ $results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
+ }
+ )->then(function () use (&$results) {
+ ksort($results);
+ return $results;
+ });
+}
+
+/**
+ * Given an iterator that yields promises or values, returns a promise that is
+ * fulfilled with a null value when the iterator has been consumed or the
+ * aggregate promise has been fulfilled or rejected.
+ *
+ * $onFulfilled is a function that accepts the fulfilled value, iterator
+ * index, and the aggregate promise. The callback can invoke any necessary side
+ * effects and choose to resolve or reject the aggregate promise if needed.
+ *
+ * $onRejected is a function that accepts the rejection reason, iterator
+ * index, and the aggregate promise. The callback can invoke any necessary side
+ * effects and choose to resolve or reject the aggregate promise if needed.
+ *
+ * @param mixed $iterable Iterator or array to iterate over.
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return PromiseInterface
+ */
+function each(
+ $iterable,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+) {
+ return (new EachPromise($iterable, [
+ 'fulfilled' => $onFulfilled,
+ 'rejected' => $onRejected
+ ]))->promise();
+}
+
+/**
+ * Like each, but only allows a certain number of outstanding promises at any
+ * given time.
+ *
+ * $concurrency may be an integer or a function that accepts the number of
+ * pending promises and returns a numeric concurrency limit value to allow for
+ * dynamic a concurrency size.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ * @param callable $onRejected
+ *
+ * @return PromiseInterface
+ */
+function each_limit(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null,
+ callable $onRejected = null
+) {
+ return (new EachPromise($iterable, [
+ 'fulfilled' => $onFulfilled,
+ 'rejected' => $onRejected,
+ 'concurrency' => $concurrency
+ ]))->promise();
+}
+
+/**
+ * Like each_limit, but ensures that no promise in the given $iterable argument
+ * is rejected. If any promise is rejected, then the aggregate promise is
+ * rejected with the encountered rejection.
+ *
+ * @param mixed $iterable
+ * @param int|callable $concurrency
+ * @param callable $onFulfilled
+ *
+ * @return PromiseInterface
+ */
+function each_limit_all(
+ $iterable,
+ $concurrency,
+ callable $onFulfilled = null
+) {
+ return each_limit(
+ $iterable,
+ $concurrency,
+ $onFulfilled,
+ function ($reason, $idx, PromiseInterface $aggregate) {
+ $aggregate->reject($reason);
+ }
+ );
+}
+
+/**
+ * Returns true if a promise is fulfilled.
+ *
+ * @param PromiseInterface $promise
+ *
+ * @return bool
+ */
+function is_fulfilled(PromiseInterface $promise)
+{
+ return $promise->getState() === PromiseInterface::FULFILLED;
+}
+
+/**
+ * Returns true if a promise is rejected.
+ *
+ * @param PromiseInterface $promise
+ *
+ * @return bool
+ */
+function is_rejected(PromiseInterface $promise)
+{
+ return $promise->getState() === PromiseInterface::REJECTED;
+}
+
+/**
+ * Returns true if a promise is fulfilled or rejected.
+ *
+ * @param PromiseInterface $promise
+ *
+ * @return bool
+ */
+function is_settled(PromiseInterface $promise)
+{
+ return $promise->getState() !== PromiseInterface::PENDING;
+}
+
+/**
+ * @see Coroutine
+ *
+ * @param callable $generatorFn
+ *
+ * @return PromiseInterface
+ */
+function coroutine(callable $generatorFn)
+{
+ return new Coroutine($generatorFn);
+}
diff --git a/akamai/vendor/guzzlehttp/promises/src/functions_include.php b/akamai/vendor/guzzlehttp/promises/src/functions_include.php
new file mode 100644
index 00000000..34cd1710
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/promises/src/functions_include.php
@@ -0,0 +1,6 @@
+withPath('foo')->withHost('example.com')` will throw an exception
+ because the path of a URI with an authority must start with a slash "/" or be empty
+ - `(new Uri())->withScheme('http')` will return `'http://localhost'`
+
+### Deprecated
+
+- `Uri::resolve` in favor of `UriResolver::resolve`
+- `Uri::removeDotSegments` in favor of `UriResolver::removeDotSegments`
+
+### Fixed
+
+- `Stream::read` when length parameter <= 0.
+- `copy_to_stream` reads bytes in chunks instead of `maxLen` into memory.
+- `ServerRequest::getUriFromGlobals` when `Host` header contains port.
+- Compatibility of URIs with `file` scheme and empty host.
+
+
+## [1.3.1] - 2016-06-25
+
+### Fixed
+
+- `Uri::__toString` for network path references, e.g. `//example.org`.
+- Missing lowercase normalization for host.
+- Handling of URI components in case they are `'0'` in a lot of places,
+ e.g. as a user info password.
+- `Uri::withAddedHeader` to correctly merge headers with different case.
+- Trimming of header values in `Uri::withAddedHeader`. Header values may
+ be surrounded by whitespace which should be ignored according to RFC 7230
+ Section 3.2.4. This does not apply to header names.
+- `Uri::withAddedHeader` with an array of header values.
+- `Uri::resolve` when base path has no slash and handling of fragment.
+- Handling of encoding in `Uri::with(out)QueryValue` so one can pass the
+ key/value both in encoded as well as decoded form to those methods. This is
+ consistent with withPath, withQuery etc.
+- `ServerRequest::withoutAttribute` when attribute value is null.
+
+
+## [1.3.0] - 2016-04-13
+
+### Added
+
+- Remaining interfaces needed for full PSR7 compatibility
+ (ServerRequestInterface, UploadedFileInterface, etc.).
+- Support for stream_for from scalars.
+
+### Changed
+
+- Can now extend Uri.
+
+### Fixed
+- A bug in validating request methods by making it more permissive.
+
+
+## [1.2.3] - 2016-02-18
+
+### Fixed
+
+- Support in `GuzzleHttp\Psr7\CachingStream` for seeking forward on remote
+ streams, which can sometimes return fewer bytes than requested with `fread`.
+- Handling of gzipped responses with FNAME headers.
+
+
+## [1.2.2] - 2016-01-22
+
+### Added
+
+- Support for URIs without any authority.
+- Support for HTTP 451 'Unavailable For Legal Reasons.'
+- Support for using '0' as a filename.
+- Support for including non-standard ports in Host headers.
+
+
+## [1.2.1] - 2015-11-02
+
+### Changes
+
+- Now supporting negative offsets when seeking to SEEK_END.
+
+
+## [1.2.0] - 2015-08-15
+
+### Changed
+
+- Body as `"0"` is now properly added to a response.
+- Now allowing forward seeking in CachingStream.
+- Now properly parsing HTTP requests that contain proxy targets in
+ `parse_request`.
+- functions.php is now conditionally required.
+- user-info is no longer dropped when resolving URIs.
+
+
+## [1.1.0] - 2015-06-24
+
+### Changed
+
+- URIs can now be relative.
+- `multipart/form-data` headers are now overridden case-insensitively.
+- URI paths no longer encode the following characters because they are allowed
+ in URIs: "(", ")", "*", "!", "'"
+- A port is no longer added to a URI when the scheme is missing and no port is
+ present.
+
+
+## 1.0.0 - 2015-05-19
+
+Initial release.
+
+Currently unsupported:
+
+- `Psr\Http\Message\ServerRequestInterface`
+- `Psr\Http\Message\UploadedFileInterface`
+
+
+
+[Unreleased]: https://github.com/guzzle/psr7/compare/1.6.0...HEAD
+[1.6.0]: https://github.com/guzzle/psr7/compare/1.5.2...1.6.0
+[1.5.2]: https://github.com/guzzle/psr7/compare/1.5.1...1.5.2
+[1.5.1]: https://github.com/guzzle/psr7/compare/1.5.0...1.5.1
+[1.5.0]: https://github.com/guzzle/psr7/compare/1.4.2...1.5.0
+[1.4.2]: https://github.com/guzzle/psr7/compare/1.4.1...1.4.2
+[1.4.1]: https://github.com/guzzle/psr7/compare/1.4.0...1.4.1
+[1.4.0]: https://github.com/guzzle/psr7/compare/1.3.1...1.4.0
+[1.3.1]: https://github.com/guzzle/psr7/compare/1.3.0...1.3.1
+[1.3.0]: https://github.com/guzzle/psr7/compare/1.2.3...1.3.0
+[1.2.3]: https://github.com/guzzle/psr7/compare/1.2.2...1.2.3
+[1.2.2]: https://github.com/guzzle/psr7/compare/1.2.1...1.2.2
+[1.2.1]: https://github.com/guzzle/psr7/compare/1.2.0...1.2.1
+[1.2.0]: https://github.com/guzzle/psr7/compare/1.1.0...1.2.0
+[1.1.0]: https://github.com/guzzle/psr7/compare/1.0.0...1.1.0
diff --git a/akamai/vendor/guzzlehttp/psr7/LICENSE b/akamai/vendor/guzzlehttp/psr7/LICENSE
new file mode 100644
index 00000000..581d95f9
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/akamai/vendor/guzzlehttp/psr7/README.md b/akamai/vendor/guzzlehttp/psr7/README.md
new file mode 100644
index 00000000..c60a6a38
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/README.md
@@ -0,0 +1,745 @@
+# PSR-7 Message Implementation
+
+This repository contains a full [PSR-7](http://www.php-fig.org/psr/psr-7/)
+message implementation, several stream decorators, and some helpful
+functionality like query string parsing.
+
+
+[](https://travis-ci.org/guzzle/psr7)
+
+
+# Stream implementation
+
+This package comes with a number of stream implementations and stream
+decorators.
+
+
+## AppendStream
+
+`GuzzleHttp\Psr7\AppendStream`
+
+Reads from multiple streams, one after the other.
+
+```php
+use GuzzleHttp\Psr7;
+
+$a = Psr7\stream_for('abc, ');
+$b = Psr7\stream_for('123.');
+$composed = new Psr7\AppendStream([$a, $b]);
+
+$composed->addStream(Psr7\stream_for(' Above all listen to me'));
+
+echo $composed; // abc, 123. Above all listen to me.
+```
+
+
+## BufferStream
+
+`GuzzleHttp\Psr7\BufferStream`
+
+Provides a buffer stream that can be written to fill a buffer, and read
+from to remove bytes from the buffer.
+
+This stream returns a "hwm" metadata value that tells upstream consumers
+what the configured high water mark of the stream is, or the maximum
+preferred size of the buffer.
+
+```php
+use GuzzleHttp\Psr7;
+
+// When more than 1024 bytes are in the buffer, it will begin returning
+// false to writes. This is an indication that writers should slow down.
+$buffer = new Psr7\BufferStream(1024);
+```
+
+
+## CachingStream
+
+The CachingStream is used to allow seeking over previously read bytes on
+non-seekable streams. This can be useful when transferring a non-seekable
+entity body fails due to needing to rewind the stream (for example, resulting
+from a redirect). Data that is read from the remote stream will be buffered in
+a PHP temp stream so that previously read bytes are cached first in memory,
+then on disk.
+
+```php
+use GuzzleHttp\Psr7;
+
+$original = Psr7\stream_for(fopen('http://www.google.com', 'r'));
+$stream = new Psr7\CachingStream($original);
+
+$stream->read(1024);
+echo $stream->tell();
+// 1024
+
+$stream->seek(0);
+echo $stream->tell();
+// 0
+```
+
+
+## DroppingStream
+
+`GuzzleHttp\Psr7\DroppingStream`
+
+Stream decorator that begins dropping data once the size of the underlying
+stream becomes too full.
+
+```php
+use GuzzleHttp\Psr7;
+
+// Create an empty stream
+$stream = Psr7\stream_for();
+
+// Start dropping data when the stream has more than 10 bytes
+$dropping = new Psr7\DroppingStream($stream, 10);
+
+$dropping->write('01234567890123456789');
+echo $stream; // 0123456789
+```
+
+
+## FnStream
+
+`GuzzleHttp\Psr7\FnStream`
+
+Compose stream implementations based on a hash of functions.
+
+Allows for easy testing and extension of a provided stream without needing
+to create a concrete class for a simple extension point.
+
+```php
+
+use GuzzleHttp\Psr7;
+
+$stream = Psr7\stream_for('hi');
+$fnStream = Psr7\FnStream::decorate($stream, [
+ 'rewind' => function () use ($stream) {
+ echo 'About to rewind - ';
+ $stream->rewind();
+ echo 'rewound!';
+ }
+]);
+
+$fnStream->rewind();
+// Outputs: About to rewind - rewound!
+```
+
+
+## InflateStream
+
+`GuzzleHttp\Psr7\InflateStream`
+
+Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
+
+This stream decorator skips the first 10 bytes of the given stream to remove
+the gzip header, converts the provided stream to a PHP stream resource,
+then appends the zlib.inflate filter. The stream is then converted back
+to a Guzzle stream resource to be used as a Guzzle stream.
+
+
+## LazyOpenStream
+
+`GuzzleHttp\Psr7\LazyOpenStream`
+
+Lazily reads or writes to a file that is opened only after an IO operation
+take place on the stream.
+
+```php
+use GuzzleHttp\Psr7;
+
+$stream = new Psr7\LazyOpenStream('/path/to/file', 'r');
+// The file has not yet been opened...
+
+echo $stream->read(10);
+// The file is opened and read from only when needed.
+```
+
+
+## LimitStream
+
+`GuzzleHttp\Psr7\LimitStream`
+
+LimitStream can be used to read a subset or slice of an existing stream object.
+This can be useful for breaking a large file into smaller pieces to be sent in
+chunks (e.g. Amazon S3's multipart upload API).
+
+```php
+use GuzzleHttp\Psr7;
+
+$original = Psr7\stream_for(fopen('/tmp/test.txt', 'r+'));
+echo $original->getSize();
+// >>> 1048576
+
+// Limit the size of the body to 1024 bytes and start reading from byte 2048
+$stream = new Psr7\LimitStream($original, 1024, 2048);
+echo $stream->getSize();
+// >>> 1024
+echo $stream->tell();
+// >>> 0
+```
+
+
+## MultipartStream
+
+`GuzzleHttp\Psr7\MultipartStream`
+
+Stream that when read returns bytes for a streaming multipart or
+multipart/form-data stream.
+
+
+## NoSeekStream
+
+`GuzzleHttp\Psr7\NoSeekStream`
+
+NoSeekStream wraps a stream and does not allow seeking.
+
+```php
+use GuzzleHttp\Psr7;
+
+$original = Psr7\stream_for('foo');
+$noSeek = new Psr7\NoSeekStream($original);
+
+echo $noSeek->read(3);
+// foo
+var_export($noSeek->isSeekable());
+// false
+$noSeek->seek(0);
+var_export($noSeek->read(3));
+// NULL
+```
+
+
+## PumpStream
+
+`GuzzleHttp\Psr7\PumpStream`
+
+Provides a read only stream that pumps data from a PHP callable.
+
+When invoking the provided callable, the PumpStream will pass the amount of
+data requested to read to the callable. The callable can choose to ignore
+this value and return fewer or more bytes than requested. Any extra data
+returned by the provided callable is buffered internally until drained using
+the read() function of the PumpStream. The provided callable MUST return
+false when there is no more data to read.
+
+
+## Implementing stream decorators
+
+Creating a stream decorator is very easy thanks to the
+`GuzzleHttp\Psr7\StreamDecoratorTrait`. This trait provides methods that
+implement `Psr\Http\Message\StreamInterface` by proxying to an underlying
+stream. Just `use` the `StreamDecoratorTrait` and implement your custom
+methods.
+
+For example, let's say we wanted to call a specific function each time the last
+byte is read from a stream. This could be implemented by overriding the
+`read()` method.
+
+```php
+use Psr\Http\Message\StreamInterface;
+use GuzzleHttp\Psr7\StreamDecoratorTrait;
+
+class EofCallbackStream implements StreamInterface
+{
+ use StreamDecoratorTrait;
+
+ private $callback;
+
+ public function __construct(StreamInterface $stream, callable $cb)
+ {
+ $this->stream = $stream;
+ $this->callback = $cb;
+ }
+
+ public function read($length)
+ {
+ $result = $this->stream->read($length);
+
+ // Invoke the callback when EOF is hit.
+ if ($this->eof()) {
+ call_user_func($this->callback);
+ }
+
+ return $result;
+ }
+}
+```
+
+This decorator could be added to any existing stream and used like so:
+
+```php
+use GuzzleHttp\Psr7;
+
+$original = Psr7\stream_for('foo');
+
+$eofStream = new EofCallbackStream($original, function () {
+ echo 'EOF!';
+});
+
+$eofStream->read(2);
+$eofStream->read(1);
+// echoes "EOF!"
+$eofStream->seek(0);
+$eofStream->read(3);
+// echoes "EOF!"
+```
+
+
+## PHP StreamWrapper
+
+You can use the `GuzzleHttp\Psr7\StreamWrapper` class if you need to use a
+PSR-7 stream as a PHP stream resource.
+
+Use the `GuzzleHttp\Psr7\StreamWrapper::getResource()` method to create a PHP
+stream from a PSR-7 stream.
+
+```php
+use GuzzleHttp\Psr7\StreamWrapper;
+
+$stream = GuzzleHttp\Psr7\stream_for('hello!');
+$resource = StreamWrapper::getResource($stream);
+echo fread($resource, 6); // outputs hello!
+```
+
+
+# Function API
+
+There are various functions available under the `GuzzleHttp\Psr7` namespace.
+
+
+## `function str`
+
+`function str(MessageInterface $message)`
+
+Returns the string representation of an HTTP message.
+
+```php
+$request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com');
+echo GuzzleHttp\Psr7\str($request);
+```
+
+
+## `function uri_for`
+
+`function uri_for($uri)`
+
+This function accepts a string or `Psr\Http\Message\UriInterface` and returns a
+UriInterface for the given value. If the value is already a `UriInterface`, it
+is returned as-is.
+
+```php
+$uri = GuzzleHttp\Psr7\uri_for('http://example.com');
+assert($uri === GuzzleHttp\Psr7\uri_for($uri));
+```
+
+
+## `function stream_for`
+
+`function stream_for($resource = '', array $options = [])`
+
+Create a new stream based on the input type.
+
+Options is an associative array that can contain the following keys:
+
+* - metadata: Array of custom metadata.
+* - size: Size of the stream.
+
+This method accepts the following `$resource` types:
+
+- `Psr\Http\Message\StreamInterface`: Returns the value as-is.
+- `string`: Creates a stream object that uses the given string as the contents.
+- `resource`: Creates a stream object that wraps the given PHP stream resource.
+- `Iterator`: If the provided value implements `Iterator`, then a read-only
+ stream object will be created that wraps the given iterable. Each time the
+ stream is read from, data from the iterator will fill a buffer and will be
+ continuously called until the buffer is equal to the requested read size.
+ Subsequent read calls will first read from the buffer and then call `next`
+ on the underlying iterator until it is exhausted.
+- `object` with `__toString()`: If the object has the `__toString()` method,
+ the object will be cast to a string and then a stream will be returned that
+ uses the string value.
+- `NULL`: When `null` is passed, an empty stream object is returned.
+- `callable` When a callable is passed, a read-only stream object will be
+ created that invokes the given callable. The callable is invoked with the
+ number of suggested bytes to read. The callable can return any number of
+ bytes, but MUST return `false` when there is no more data to return. The
+ stream object that wraps the callable will invoke the callable until the
+ number of requested bytes are available. Any additional bytes will be
+ buffered and used in subsequent reads.
+
+```php
+$stream = GuzzleHttp\Psr7\stream_for('foo');
+$stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r'));
+
+$generator = function ($bytes) {
+ for ($i = 0; $i < $bytes; $i++) {
+ yield ' ';
+ }
+}
+
+$stream = GuzzleHttp\Psr7\stream_for($generator(100));
+```
+
+
+## `function parse_header`
+
+`function parse_header($header)`
+
+Parse an array of header values containing ";" separated data into an array of
+associative arrays representing the header key value pair data of the header.
+When a parameter does not contain a value, but just contains a key, this
+function will inject a key with a '' string value.
+
+
+## `function normalize_header`
+
+`function normalize_header($header)`
+
+Converts an array of header values that may contain comma separated headers
+into an array of headers with no comma separated values.
+
+
+## `function modify_request`
+
+`function modify_request(RequestInterface $request, array $changes)`
+
+Clone and modify a request with the given changes. This method is useful for
+reducing the number of clones needed to mutate a message.
+
+The changes can be one of:
+
+- method: (string) Changes the HTTP method.
+- set_headers: (array) Sets the given headers.
+- remove_headers: (array) Remove the given headers.
+- body: (mixed) Sets the given body.
+- uri: (UriInterface) Set the URI.
+- query: (string) Set the query string value of the URI.
+- version: (string) Set the protocol version.
+
+
+## `function rewind_body`
+
+`function rewind_body(MessageInterface $message)`
+
+Attempts to rewind a message body and throws an exception on failure. The body
+of the message will only be rewound if a call to `tell()` returns a value other
+than `0`.
+
+
+## `function try_fopen`
+
+`function try_fopen($filename, $mode)`
+
+Safely opens a PHP stream resource using a filename.
+
+When fopen fails, PHP normally raises a warning. This function adds an error
+handler that checks for errors and throws an exception instead.
+
+
+## `function copy_to_string`
+
+`function copy_to_string(StreamInterface $stream, $maxLen = -1)`
+
+Copy the contents of a stream into a string until the given number of bytes
+have been read.
+
+
+## `function copy_to_stream`
+
+`function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)`
+
+Copy the contents of a stream into another stream until the given number of
+bytes have been read.
+
+
+## `function hash`
+
+`function hash(StreamInterface $stream, $algo, $rawOutput = false)`
+
+Calculate a hash of a Stream. This method reads the entire stream to calculate
+a rolling hash (based on PHP's hash_init functions).
+
+
+## `function readline`
+
+`function readline(StreamInterface $stream, $maxLength = null)`
+
+Read a line from the stream up to the maximum allowed buffer length.
+
+
+## `function parse_request`
+
+`function parse_request($message)`
+
+Parses a request message string into a request object.
+
+
+## `function parse_response`
+
+`function parse_response($message)`
+
+Parses a response message string into a response object.
+
+
+## `function parse_query`
+
+`function parse_query($str, $urlEncoding = true)`
+
+Parse a query string into an associative array.
+
+If multiple values are found for the same key, the value of that key value pair
+will become an array. This function does not parse nested PHP style arrays into
+an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed into
+`['foo[a]' => '1', 'foo[b]' => '2']`).
+
+
+## `function build_query`
+
+`function build_query(array $params, $encoding = PHP_QUERY_RFC3986)`
+
+Build a query string from an array of key value pairs.
+
+This function can use the return value of parse_query() to build a query string.
+This function does not modify the provided keys when an array is encountered
+(like http_build_query would).
+
+
+## `function mimetype_from_filename`
+
+`function mimetype_from_filename($filename)`
+
+Determines the mimetype of a file by looking at its extension.
+
+
+## `function mimetype_from_extension`
+
+`function mimetype_from_extension($extension)`
+
+Maps a file extensions to a mimetype.
+
+
+# Additional URI Methods
+
+Aside from the standard `Psr\Http\Message\UriInterface` implementation in form of the `GuzzleHttp\Psr7\Uri` class,
+this library also provides additional functionality when working with URIs as static methods.
+
+## URI Types
+
+An instance of `Psr\Http\Message\UriInterface` can either be an absolute URI or a relative reference.
+An absolute URI has a scheme. A relative reference is used to express a URI relative to another URI,
+the base URI. Relative references can be divided into several forms according to
+[RFC 3986 Section 4.2](https://tools.ietf.org/html/rfc3986#section-4.2):
+
+- network-path references, e.g. `//example.com/path`
+- absolute-path references, e.g. `/path`
+- relative-path references, e.g. `subpath`
+
+The following methods can be used to identify the type of the URI.
+
+### `GuzzleHttp\Psr7\Uri::isAbsolute`
+
+`public static function isAbsolute(UriInterface $uri): bool`
+
+Whether the URI is absolute, i.e. it has a scheme.
+
+### `GuzzleHttp\Psr7\Uri::isNetworkPathReference`
+
+`public static function isNetworkPathReference(UriInterface $uri): bool`
+
+Whether the URI is a network-path reference. A relative reference that begins with two slash characters is
+termed an network-path reference.
+
+### `GuzzleHttp\Psr7\Uri::isAbsolutePathReference`
+
+`public static function isAbsolutePathReference(UriInterface $uri): bool`
+
+Whether the URI is a absolute-path reference. A relative reference that begins with a single slash character is
+termed an absolute-path reference.
+
+### `GuzzleHttp\Psr7\Uri::isRelativePathReference`
+
+`public static function isRelativePathReference(UriInterface $uri): bool`
+
+Whether the URI is a relative-path reference. A relative reference that does not begin with a slash character is
+termed a relative-path reference.
+
+### `GuzzleHttp\Psr7\Uri::isSameDocumentReference`
+
+`public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool`
+
+Whether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its
+fragment component, identical to the base URI. When no base URI is given, only an empty URI reference
+(apart from its fragment) is considered a same-document reference.
+
+## URI Components
+
+Additional methods to work with URI components.
+
+### `GuzzleHttp\Psr7\Uri::isDefaultPort`
+
+`public static function isDefaultPort(UriInterface $uri): bool`
+
+Whether the URI has the default port of the current scheme. `Psr\Http\Message\UriInterface::getPort` may return null
+or the standard port. This method can be used independently of the implementation.
+
+### `GuzzleHttp\Psr7\Uri::composeComponents`
+
+`public static function composeComponents($scheme, $authority, $path, $query, $fragment): string`
+
+Composes a URI reference string from its various components according to
+[RFC 3986 Section 5.3](https://tools.ietf.org/html/rfc3986#section-5.3). Usually this method does not need to be called
+manually but instead is used indirectly via `Psr\Http\Message\UriInterface::__toString`.
+
+### `GuzzleHttp\Psr7\Uri::fromParts`
+
+`public static function fromParts(array $parts): UriInterface`
+
+Creates a URI from a hash of [`parse_url`](http://php.net/manual/en/function.parse-url.php) components.
+
+
+### `GuzzleHttp\Psr7\Uri::withQueryValue`
+
+`public static function withQueryValue(UriInterface $uri, $key, $value): UriInterface`
+
+Creates a new URI with a specific query string value. Any existing query string values that exactly match the
+provided key are removed and replaced with the given key value pair. A value of null will set the query string
+key without a value, e.g. "key" instead of "key=value".
+
+### `GuzzleHttp\Psr7\Uri::withQueryValues`
+
+`public static function withQueryValues(UriInterface $uri, array $keyValueArray): UriInterface`
+
+Creates a new URI with multiple query string values. It has the same behavior as `withQueryValue()` but for an
+associative array of key => value.
+
+### `GuzzleHttp\Psr7\Uri::withoutQueryValue`
+
+`public static function withoutQueryValue(UriInterface $uri, $key): UriInterface`
+
+Creates a new URI with a specific query string value removed. Any existing query string values that exactly match the
+provided key are removed.
+
+## Reference Resolution
+
+`GuzzleHttp\Psr7\UriResolver` provides methods to resolve a URI reference in the context of a base URI according
+to [RFC 3986 Section 5](https://tools.ietf.org/html/rfc3986#section-5). This is for example also what web browsers
+do when resolving a link in a website based on the current request URI.
+
+### `GuzzleHttp\Psr7\UriResolver::resolve`
+
+`public static function resolve(UriInterface $base, UriInterface $rel): UriInterface`
+
+Converts the relative URI into a new URI that is resolved against the base URI.
+
+### `GuzzleHttp\Psr7\UriResolver::removeDotSegments`
+
+`public static function removeDotSegments(string $path): string`
+
+Removes dot segments from a path and returns the new path according to
+[RFC 3986 Section 5.2.4](https://tools.ietf.org/html/rfc3986#section-5.2.4).
+
+### `GuzzleHttp\Psr7\UriResolver::relativize`
+
+`public static function relativize(UriInterface $base, UriInterface $target): UriInterface`
+
+Returns the target URI as a relative reference from the base URI. This method is the counterpart to resolve():
+
+```php
+(string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
+```
+
+One use-case is to use the current request URI as base URI and then generate relative links in your documents
+to reduce the document size or offer self-contained downloadable document archives.
+
+```php
+$base = new Uri('http://example.com/a/b/');
+echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
+echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
+echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
+echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
+```
+
+## Normalization and Comparison
+
+`GuzzleHttp\Psr7\UriNormalizer` provides methods to normalize and compare URIs according to
+[RFC 3986 Section 6](https://tools.ietf.org/html/rfc3986#section-6).
+
+### `GuzzleHttp\Psr7\UriNormalizer::normalize`
+
+`public static function normalize(UriInterface $uri, $flags = self::PRESERVING_NORMALIZATIONS): UriInterface`
+
+Returns a normalized URI. The scheme and host component are already normalized to lowercase per PSR-7 UriInterface.
+This methods adds additional normalizations that can be configured with the `$flags` parameter which is a bitmask
+of normalizations to apply. The following normalizations are available:
+
+- `UriNormalizer::PRESERVING_NORMALIZATIONS`
+
+ Default normalizations which only include the ones that preserve semantics.
+
+- `UriNormalizer::CAPITALIZE_PERCENT_ENCODING`
+
+ All letters within a percent-encoding triplet (e.g., "%3A") are case-insensitive, and should be capitalized.
+
+ Example: `http://example.org/a%c2%b1b` → `http://example.org/a%C2%B1b`
+
+- `UriNormalizer::DECODE_UNRESERVED_CHARACTERS`
+
+ Decodes percent-encoded octets of unreserved characters. For consistency, percent-encoded octets in the ranges of
+ ALPHA (%41–%5A and %61–%7A), DIGIT (%30–%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) should
+ not be created by URI producers and, when found in a URI, should be decoded to their corresponding unreserved
+ characters by URI normalizers.
+
+ Example: `http://example.org/%7Eusern%61me/` → `http://example.org/~username/`
+
+- `UriNormalizer::CONVERT_EMPTY_PATH`
+
+ Converts the empty path to "/" for http and https URIs.
+
+ Example: `http://example.org` → `http://example.org/`
+
+- `UriNormalizer::REMOVE_DEFAULT_HOST`
+
+ Removes the default host of the given URI scheme from the URI. Only the "file" scheme defines the default host
+ "localhost". All of `file:/myfile`, `file:///myfile`, and `file://localhost/myfile` are equivalent according to
+ RFC 3986.
+
+ Example: `file://localhost/myfile` → `file:///myfile`
+
+- `UriNormalizer::REMOVE_DEFAULT_PORT`
+
+ Removes the default port of the given URI scheme from the URI.
+
+ Example: `http://example.org:80/` → `http://example.org/`
+
+- `UriNormalizer::REMOVE_DOT_SEGMENTS`
+
+ Removes unnecessary dot-segments. Dot-segments in relative-path references are not removed as it would
+ change the semantics of the URI reference.
+
+ Example: `http://example.org/../a/b/../c/./d.html` → `http://example.org/a/c/d.html`
+
+- `UriNormalizer::REMOVE_DUPLICATE_SLASHES`
+
+ Paths which include two or more adjacent slashes are converted to one. Webservers usually ignore duplicate slashes
+ and treat those URIs equivalent. But in theory those URIs do not need to be equivalent. So this normalization
+ may change the semantics. Encoded slashes (%2F) are not removed.
+
+ Example: `http://example.org//foo///bar.html` → `http://example.org/foo/bar.html`
+
+- `UriNormalizer::SORT_QUERY_PARAMETERS`
+
+ Sort query parameters with their values in alphabetical order. However, the order of parameters in a URI may be
+ significant (this is not defined by the standard). So this normalization is not safe and may change the semantics
+ of the URI.
+
+ Example: `?lang=en&article=fred` → `?article=fred&lang=en`
+
+### `GuzzleHttp\Psr7\UriNormalizer::isEquivalent`
+
+`public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS): bool`
+
+Whether two URIs can be considered equivalent. Both URIs are normalized automatically before comparison with the given
+`$normalizations` bitmask. The method also accepts relative URI references and returns true when they are equivalent.
+This of course assumes they will be resolved against the same base URI. If this is not the case, determination of
+equivalence or difference of relative references does not mean anything.
diff --git a/akamai/vendor/guzzlehttp/psr7/composer.json b/akamai/vendor/guzzlehttp/psr7/composer.json
new file mode 100644
index 00000000..168a055b
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/composer.json
@@ -0,0 +1,49 @@
+{
+ "name": "guzzlehttp/psr7",
+ "type": "library",
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": ["request", "response", "message", "stream", "http", "uri", "url", "psr-7"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Schultze",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0",
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8",
+ "ext-zlib": "*"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "suggest": {
+ "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ },
+ "files": ["src/functions_include.php"]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "GuzzleHttp\\Tests\\Psr7\\": "tests/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6-dev"
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/AppendStream.php b/akamai/vendor/guzzlehttp/psr7/src/AppendStream.php
new file mode 100644
index 00000000..472a0d61
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/AppendStream.php
@@ -0,0 +1,241 @@
+addStream($stream);
+ }
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->rewind();
+ return $this->getContents();
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ /**
+ * Add a stream to the AppendStream
+ *
+ * @param StreamInterface $stream Stream to append. Must be readable.
+ *
+ * @throws \InvalidArgumentException if the stream is not readable
+ */
+ public function addStream(StreamInterface $stream)
+ {
+ if (!$stream->isReadable()) {
+ throw new \InvalidArgumentException('Each stream must be readable');
+ }
+
+ // The stream is only seekable if all streams are seekable
+ if (!$stream->isSeekable()) {
+ $this->seekable = false;
+ }
+
+ $this->streams[] = $stream;
+ }
+
+ public function getContents()
+ {
+ return copy_to_string($this);
+ }
+
+ /**
+ * Closes each attached stream.
+ *
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->pos = $this->current = 0;
+ $this->seekable = true;
+
+ foreach ($this->streams as $stream) {
+ $stream->close();
+ }
+
+ $this->streams = [];
+ }
+
+ /**
+ * Detaches each attached stream.
+ *
+ * Returns null as it's not clear which underlying stream resource to return.
+ *
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ $this->pos = $this->current = 0;
+ $this->seekable = true;
+
+ foreach ($this->streams as $stream) {
+ $stream->detach();
+ }
+
+ $this->streams = [];
+ }
+
+ public function tell()
+ {
+ return $this->pos;
+ }
+
+ /**
+ * Tries to calculate the size by adding the size of each stream.
+ *
+ * If any of the streams do not return a valid number, then the size of the
+ * append stream cannot be determined and null is returned.
+ *
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ $size = 0;
+
+ foreach ($this->streams as $stream) {
+ $s = $stream->getSize();
+ if ($s === null) {
+ return null;
+ }
+ $size += $s;
+ }
+
+ return $size;
+ }
+
+ public function eof()
+ {
+ return !$this->streams ||
+ ($this->current >= count($this->streams) - 1 &&
+ $this->streams[$this->current]->eof());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ /**
+ * Attempts to seek to the given position. Only supports SEEK_SET.
+ *
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (!$this->seekable) {
+ throw new \RuntimeException('This AppendStream is not seekable');
+ } elseif ($whence !== SEEK_SET) {
+ throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
+ }
+
+ $this->pos = $this->current = 0;
+
+ // Rewind each stream
+ foreach ($this->streams as $i => $stream) {
+ try {
+ $stream->rewind();
+ } catch (\Exception $e) {
+ throw new \RuntimeException('Unable to seek stream '
+ . $i . ' of the AppendStream', 0, $e);
+ }
+ }
+
+ // Seek to the actual position by reading from each stream
+ while ($this->pos < $offset && !$this->eof()) {
+ $result = $this->read(min(8096, $offset - $this->pos));
+ if ($result === '') {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Reads from all of the appended streams until the length is met or EOF.
+ *
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ $buffer = '';
+ $total = count($this->streams) - 1;
+ $remaining = $length;
+ $progressToNext = false;
+
+ while ($remaining > 0) {
+
+ // Progress to the next stream if needed.
+ if ($progressToNext || $this->streams[$this->current]->eof()) {
+ $progressToNext = false;
+ if ($this->current === $total) {
+ break;
+ }
+ $this->current++;
+ }
+
+ $result = $this->streams[$this->current]->read($remaining);
+
+ // Using a loose comparison here to match on '', false, and null
+ if ($result == null) {
+ $progressToNext = true;
+ continue;
+ }
+
+ $buffer .= $result;
+ $remaining = $length - strlen($buffer);
+ }
+
+ $this->pos += strlen($buffer);
+
+ return $buffer;
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to an AppendStream');
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $key ? null : [];
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/BufferStream.php b/akamai/vendor/guzzlehttp/psr7/src/BufferStream.php
new file mode 100644
index 00000000..af4d4c22
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/BufferStream.php
@@ -0,0 +1,137 @@
+hwm = $hwm;
+ }
+
+ public function __toString()
+ {
+ return $this->getContents();
+ }
+
+ public function getContents()
+ {
+ $buffer = $this->buffer;
+ $this->buffer = '';
+
+ return $buffer;
+ }
+
+ public function close()
+ {
+ $this->buffer = '';
+ }
+
+ public function detach()
+ {
+ $this->close();
+ }
+
+ public function getSize()
+ {
+ return strlen($this->buffer);
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function isWritable()
+ {
+ return true;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a BufferStream');
+ }
+
+ public function eof()
+ {
+ return strlen($this->buffer) === 0;
+ }
+
+ public function tell()
+ {
+ throw new \RuntimeException('Cannot determine the position of a BufferStream');
+ }
+
+ /**
+ * Reads data from the buffer.
+ */
+ public function read($length)
+ {
+ $currentLength = strlen($this->buffer);
+
+ if ($length >= $currentLength) {
+ // No need to slice the buffer because we don't have enough data.
+ $result = $this->buffer;
+ $this->buffer = '';
+ } else {
+ // Slice up the result to provide a subset of the buffer.
+ $result = substr($this->buffer, 0, $length);
+ $this->buffer = substr($this->buffer, $length);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Writes data to the buffer.
+ */
+ public function write($string)
+ {
+ $this->buffer .= $string;
+
+ // TODO: What should happen here?
+ if (strlen($this->buffer) >= $this->hwm) {
+ return false;
+ }
+
+ return strlen($string);
+ }
+
+ public function getMetadata($key = null)
+ {
+ if ($key == 'hwm') {
+ return $this->hwm;
+ }
+
+ return $key ? null : [];
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/CachingStream.php b/akamai/vendor/guzzlehttp/psr7/src/CachingStream.php
new file mode 100644
index 00000000..ed68f086
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/CachingStream.php
@@ -0,0 +1,138 @@
+remoteStream = $stream;
+ $this->stream = $target ?: new Stream(fopen('php://temp', 'r+'));
+ }
+
+ public function getSize()
+ {
+ return max($this->stream->getSize(), $this->remoteStream->getSize());
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence == SEEK_SET) {
+ $byte = $offset;
+ } elseif ($whence == SEEK_CUR) {
+ $byte = $offset + $this->tell();
+ } elseif ($whence == SEEK_END) {
+ $size = $this->remoteStream->getSize();
+ if ($size === null) {
+ $size = $this->cacheEntireStream();
+ }
+ $byte = $size + $offset;
+ } else {
+ throw new \InvalidArgumentException('Invalid whence');
+ }
+
+ $diff = $byte - $this->stream->getSize();
+
+ if ($diff > 0) {
+ // Read the remoteStream until we have read in at least the amount
+ // of bytes requested, or we reach the end of the file.
+ while ($diff > 0 && !$this->remoteStream->eof()) {
+ $this->read($diff);
+ $diff = $byte - $this->stream->getSize();
+ }
+ } else {
+ // We can just do a normal seek since we've already seen this byte.
+ $this->stream->seek($byte);
+ }
+ }
+
+ public function read($length)
+ {
+ // Perform a regular read on any previously read data from the buffer
+ $data = $this->stream->read($length);
+ $remaining = $length - strlen($data);
+
+ // More data was requested so read from the remote stream
+ if ($remaining) {
+ // If data was written to the buffer in a position that would have
+ // been filled from the remote stream, then we must skip bytes on
+ // the remote stream to emulate overwriting bytes from that
+ // position. This mimics the behavior of other PHP stream wrappers.
+ $remoteData = $this->remoteStream->read(
+ $remaining + $this->skipReadBytes
+ );
+
+ if ($this->skipReadBytes) {
+ $len = strlen($remoteData);
+ $remoteData = substr($remoteData, $this->skipReadBytes);
+ $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
+ }
+
+ $data .= $remoteData;
+ $this->stream->write($remoteData);
+ }
+
+ return $data;
+ }
+
+ public function write($string)
+ {
+ // When appending to the end of the currently read stream, you'll want
+ // to skip bytes from being read from the remote stream to emulate
+ // other stream wrappers. Basically replacing bytes of data of a fixed
+ // length.
+ $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
+ if ($overflow > 0) {
+ $this->skipReadBytes += $overflow;
+ }
+
+ return $this->stream->write($string);
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof() && $this->remoteStream->eof();
+ }
+
+ /**
+ * Close both the remote stream and buffer stream
+ */
+ public function close()
+ {
+ $this->remoteStream->close() && $this->stream->close();
+ }
+
+ private function cacheEntireStream()
+ {
+ $target = new FnStream(['write' => 'strlen']);
+ copy_to_stream($this, $target);
+
+ return $this->tell();
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/DroppingStream.php b/akamai/vendor/guzzlehttp/psr7/src/DroppingStream.php
new file mode 100644
index 00000000..8935c80d
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/DroppingStream.php
@@ -0,0 +1,42 @@
+stream = $stream;
+ $this->maxLength = $maxLength;
+ }
+
+ public function write($string)
+ {
+ $diff = $this->maxLength - $this->stream->getSize();
+
+ // Begin returning 0 when the underlying stream is too large.
+ if ($diff <= 0) {
+ return 0;
+ }
+
+ // Write the stream or a subset of the stream if needed.
+ if (strlen($string) < $diff) {
+ return $this->stream->write($string);
+ }
+
+ return $this->stream->write(substr($string, 0, $diff));
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/FnStream.php b/akamai/vendor/guzzlehttp/psr7/src/FnStream.php
new file mode 100644
index 00000000..73daea6f
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/FnStream.php
@@ -0,0 +1,158 @@
+methods = $methods;
+
+ // Create the functions on the class
+ foreach ($methods as $name => $fn) {
+ $this->{'_fn_' . $name} = $fn;
+ }
+ }
+
+ /**
+ * Lazily determine which methods are not implemented.
+ * @throws \BadMethodCallException
+ */
+ public function __get($name)
+ {
+ throw new \BadMethodCallException(str_replace('_fn_', '', $name)
+ . '() is not implemented in the FnStream');
+ }
+
+ /**
+ * The close method is called on the underlying stream only if possible.
+ */
+ public function __destruct()
+ {
+ if (isset($this->_fn_close)) {
+ call_user_func($this->_fn_close);
+ }
+ }
+
+ /**
+ * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
+ * @throws \LogicException
+ */
+ public function __wakeup()
+ {
+ throw new \LogicException('FnStream should never be unserialized');
+ }
+
+ /**
+ * Adds custom functionality to an underlying stream by intercepting
+ * specific method calls.
+ *
+ * @param StreamInterface $stream Stream to decorate
+ * @param array $methods Hash of method name to a closure
+ *
+ * @return FnStream
+ */
+ public static function decorate(StreamInterface $stream, array $methods)
+ {
+ // If any of the required methods were not provided, then simply
+ // proxy to the decorated stream.
+ foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
+ $methods[$diff] = [$stream, $diff];
+ }
+
+ return new self($methods);
+ }
+
+ public function __toString()
+ {
+ return call_user_func($this->_fn___toString);
+ }
+
+ public function close()
+ {
+ return call_user_func($this->_fn_close);
+ }
+
+ public function detach()
+ {
+ return call_user_func($this->_fn_detach);
+ }
+
+ public function getSize()
+ {
+ return call_user_func($this->_fn_getSize);
+ }
+
+ public function tell()
+ {
+ return call_user_func($this->_fn_tell);
+ }
+
+ public function eof()
+ {
+ return call_user_func($this->_fn_eof);
+ }
+
+ public function isSeekable()
+ {
+ return call_user_func($this->_fn_isSeekable);
+ }
+
+ public function rewind()
+ {
+ call_user_func($this->_fn_rewind);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ call_user_func($this->_fn_seek, $offset, $whence);
+ }
+
+ public function isWritable()
+ {
+ return call_user_func($this->_fn_isWritable);
+ }
+
+ public function write($string)
+ {
+ return call_user_func($this->_fn_write, $string);
+ }
+
+ public function isReadable()
+ {
+ return call_user_func($this->_fn_isReadable);
+ }
+
+ public function read($length)
+ {
+ return call_user_func($this->_fn_read, $length);
+ }
+
+ public function getContents()
+ {
+ return call_user_func($this->_fn_getContents);
+ }
+
+ public function getMetadata($key = null)
+ {
+ return call_user_func($this->_fn_getMetadata, $key);
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/InflateStream.php b/akamai/vendor/guzzlehttp/psr7/src/InflateStream.php
new file mode 100644
index 00000000..5e4f6028
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/InflateStream.php
@@ -0,0 +1,52 @@
+read(10);
+ $filenameHeaderLength = $this->getLengthOfPossibleFilenameHeader($stream, $header);
+ // Skip the header, that is 10 + length of filename + 1 (nil) bytes
+ $stream = new LimitStream($stream, -1, 10 + $filenameHeaderLength);
+ $resource = StreamWrapper::getResource($stream);
+ stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
+ $this->stream = $stream->isSeekable() ? new Stream($resource) : new NoSeekStream(new Stream($resource));
+ }
+
+ /**
+ * @param StreamInterface $stream
+ * @param $header
+ * @return int
+ */
+ private function getLengthOfPossibleFilenameHeader(StreamInterface $stream, $header)
+ {
+ $filename_header_length = 0;
+
+ if (substr(bin2hex($header), 6, 2) === '08') {
+ // we have a filename, read until nil
+ $filename_header_length = 1;
+ while ($stream->read(1) !== chr(0)) {
+ $filename_header_length++;
+ }
+ }
+
+ return $filename_header_length;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/LazyOpenStream.php b/akamai/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
new file mode 100644
index 00000000..02cec3af
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
@@ -0,0 +1,39 @@
+filename = $filename;
+ $this->mode = $mode;
+ }
+
+ /**
+ * Creates the underlying stream lazily when required.
+ *
+ * @return StreamInterface
+ */
+ protected function createStream()
+ {
+ return stream_for(try_fopen($this->filename, $this->mode));
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/LimitStream.php b/akamai/vendor/guzzlehttp/psr7/src/LimitStream.php
new file mode 100644
index 00000000..e4f239e3
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/LimitStream.php
@@ -0,0 +1,155 @@
+stream = $stream;
+ $this->setLimit($limit);
+ $this->setOffset($offset);
+ }
+
+ public function eof()
+ {
+ // Always return true if the underlying stream is EOF
+ if ($this->stream->eof()) {
+ return true;
+ }
+
+ // No limit and the underlying stream is not at EOF
+ if ($this->limit == -1) {
+ return false;
+ }
+
+ return $this->stream->tell() >= $this->offset + $this->limit;
+ }
+
+ /**
+ * Returns the size of the limited subset of data
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ if (null === ($length = $this->stream->getSize())) {
+ return null;
+ } elseif ($this->limit == -1) {
+ return $length - $this->offset;
+ } else {
+ return min($this->limit, $length - $this->offset);
+ }
+ }
+
+ /**
+ * Allow for a bounded seek on the read limited stream
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if ($whence !== SEEK_SET || $offset < 0) {
+ throw new \RuntimeException(sprintf(
+ 'Cannot seek to offset %s with whence %s',
+ $offset,
+ $whence
+ ));
+ }
+
+ $offset += $this->offset;
+
+ if ($this->limit !== -1) {
+ if ($offset > $this->offset + $this->limit) {
+ $offset = $this->offset + $this->limit;
+ }
+ }
+
+ $this->stream->seek($offset);
+ }
+
+ /**
+ * Give a relative tell()
+ * {@inheritdoc}
+ */
+ public function tell()
+ {
+ return $this->stream->tell() - $this->offset;
+ }
+
+ /**
+ * Set the offset to start limiting from
+ *
+ * @param int $offset Offset to seek to and begin byte limiting from
+ *
+ * @throws \RuntimeException if the stream cannot be seeked.
+ */
+ public function setOffset($offset)
+ {
+ $current = $this->stream->tell();
+
+ if ($current !== $offset) {
+ // If the stream cannot seek to the offset position, then read to it
+ if ($this->stream->isSeekable()) {
+ $this->stream->seek($offset);
+ } elseif ($current > $offset) {
+ throw new \RuntimeException("Could not seek to stream offset $offset");
+ } else {
+ $this->stream->read($offset - $current);
+ }
+ }
+
+ $this->offset = $offset;
+ }
+
+ /**
+ * Set the limit of bytes that the decorator allows to be read from the
+ * stream.
+ *
+ * @param int $limit Number of bytes to allow to be read from the stream.
+ * Use -1 for no limit.
+ */
+ public function setLimit($limit)
+ {
+ $this->limit = $limit;
+ }
+
+ public function read($length)
+ {
+ if ($this->limit == -1) {
+ return $this->stream->read($length);
+ }
+
+ // Check if the current position is less than the total allowed
+ // bytes + original offset
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
+ if ($remaining > 0) {
+ // Only return the amount of requested data, ensuring that the byte
+ // limit is not exceeded
+ return $this->stream->read(min($remaining, $length));
+ }
+
+ return '';
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/MessageTrait.php b/akamai/vendor/guzzlehttp/psr7/src/MessageTrait.php
new file mode 100644
index 00000000..a7966d10
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/MessageTrait.php
@@ -0,0 +1,213 @@
+ array of values */
+ private $headers = [];
+
+ /** @var array Map of lowercase header name => original name at registration */
+ private $headerNames = [];
+
+ /** @var string */
+ private $protocol = '1.1';
+
+ /** @var StreamInterface */
+ private $stream;
+
+ public function getProtocolVersion()
+ {
+ return $this->protocol;
+ }
+
+ public function withProtocolVersion($version)
+ {
+ if ($this->protocol === $version) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->protocol = $version;
+ return $new;
+ }
+
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ public function hasHeader($header)
+ {
+ return isset($this->headerNames[strtolower($header)]);
+ }
+
+ public function getHeader($header)
+ {
+ $header = strtolower($header);
+
+ if (!isset($this->headerNames[$header])) {
+ return [];
+ }
+
+ $header = $this->headerNames[$header];
+
+ return $this->headers[$header];
+ }
+
+ public function getHeaderLine($header)
+ {
+ return implode(', ', $this->getHeader($header));
+ }
+
+ public function withHeader($header, $value)
+ {
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
+ $normalized = strtolower($header);
+
+ $new = clone $this;
+ if (isset($new->headerNames[$normalized])) {
+ unset($new->headers[$new->headerNames[$normalized]]);
+ }
+ $new->headerNames[$normalized] = $header;
+ $new->headers[$header] = $value;
+
+ return $new;
+ }
+
+ public function withAddedHeader($header, $value)
+ {
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
+ $normalized = strtolower($header);
+
+ $new = clone $this;
+ if (isset($new->headerNames[$normalized])) {
+ $header = $this->headerNames[$normalized];
+ $new->headers[$header] = array_merge($this->headers[$header], $value);
+ } else {
+ $new->headerNames[$normalized] = $header;
+ $new->headers[$header] = $value;
+ }
+
+ return $new;
+ }
+
+ public function withoutHeader($header)
+ {
+ $normalized = strtolower($header);
+
+ if (!isset($this->headerNames[$normalized])) {
+ return $this;
+ }
+
+ $header = $this->headerNames[$normalized];
+
+ $new = clone $this;
+ unset($new->headers[$header], $new->headerNames[$normalized]);
+
+ return $new;
+ }
+
+ public function getBody()
+ {
+ if (!$this->stream) {
+ $this->stream = stream_for('');
+ }
+
+ return $this->stream;
+ }
+
+ public function withBody(StreamInterface $body)
+ {
+ if ($body === $this->stream) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->stream = $body;
+ return $new;
+ }
+
+ private function setHeaders(array $headers)
+ {
+ $this->headerNames = $this->headers = [];
+ foreach ($headers as $header => $value) {
+ if (is_int($header)) {
+ // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec
+ // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass.
+ $header = (string) $header;
+ }
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
+ $normalized = strtolower($header);
+ if (isset($this->headerNames[$normalized])) {
+ $header = $this->headerNames[$normalized];
+ $this->headers[$header] = array_merge($this->headers[$header], $value);
+ } else {
+ $this->headerNames[$normalized] = $header;
+ $this->headers[$header] = $value;
+ }
+ }
+ }
+
+ private function normalizeHeaderValue($value)
+ {
+ if (!is_array($value)) {
+ return $this->trimHeaderValues([$value]);
+ }
+
+ if (count($value) === 0) {
+ throw new \InvalidArgumentException('Header value can not be an empty array.');
+ }
+
+ return $this->trimHeaderValues($value);
+ }
+
+ /**
+ * Trims whitespace from the header values.
+ *
+ * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
+ *
+ * header-field = field-name ":" OWS field-value OWS
+ * OWS = *( SP / HTAB )
+ *
+ * @param string[] $values Header values
+ *
+ * @return string[] Trimmed header values
+ *
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
+ */
+ private function trimHeaderValues(array $values)
+ {
+ return array_map(function ($value) {
+ if (!is_scalar($value) && null !== $value) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Header value must be scalar or null but %s provided.',
+ is_object($value) ? get_class($value) : gettype($value)
+ ));
+ }
+
+ return trim((string) $value, " \t");
+ }, $values);
+ }
+
+ private function assertHeader($header)
+ {
+ if (!is_string($header)) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Header name must be a string but %s provided.',
+ is_object($header) ? get_class($header) : gettype($header)
+ ));
+ }
+
+ if ($header === '') {
+ throw new \InvalidArgumentException('Header name can not be empty.');
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/MultipartStream.php b/akamai/vendor/guzzlehttp/psr7/src/MultipartStream.php
new file mode 100644
index 00000000..c0fd584f
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/MultipartStream.php
@@ -0,0 +1,153 @@
+boundary = $boundary ?: sha1(uniqid('', true));
+ $this->stream = $this->createStream($elements);
+ }
+
+ /**
+ * Get the boundary
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ return $this->boundary;
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /**
+ * Get the headers needed before transferring the content of a POST file
+ */
+ private function getHeaders(array $headers)
+ {
+ $str = '';
+ foreach ($headers as $key => $value) {
+ $str .= "{$key}: {$value}\r\n";
+ }
+
+ return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
+ }
+
+ /**
+ * Create the aggregate stream that will be used to upload the POST data
+ */
+ protected function createStream(array $elements)
+ {
+ $stream = new AppendStream();
+
+ foreach ($elements as $element) {
+ $this->addElement($stream, $element);
+ }
+
+ // Add the trailing boundary with CRLF
+ $stream->addStream(stream_for("--{$this->boundary}--\r\n"));
+
+ return $stream;
+ }
+
+ private function addElement(AppendStream $stream, array $element)
+ {
+ foreach (['contents', 'name'] as $key) {
+ if (!array_key_exists($key, $element)) {
+ throw new \InvalidArgumentException("A '{$key}' key is required");
+ }
+ }
+
+ $element['contents'] = stream_for($element['contents']);
+
+ if (empty($element['filename'])) {
+ $uri = $element['contents']->getMetadata('uri');
+ if (substr($uri, 0, 6) !== 'php://') {
+ $element['filename'] = $uri;
+ }
+ }
+
+ list($body, $headers) = $this->createElement(
+ $element['name'],
+ $element['contents'],
+ isset($element['filename']) ? $element['filename'] : null,
+ isset($element['headers']) ? $element['headers'] : []
+ );
+
+ $stream->addStream(stream_for($this->getHeaders($headers)));
+ $stream->addStream($body);
+ $stream->addStream(stream_for("\r\n"));
+ }
+
+ /**
+ * @return array
+ */
+ private function createElement($name, StreamInterface $stream, $filename, array $headers)
+ {
+ // Set a default content-disposition header if one was no provided
+ $disposition = $this->getHeader($headers, 'content-disposition');
+ if (!$disposition) {
+ $headers['Content-Disposition'] = ($filename === '0' || $filename)
+ ? sprintf('form-data; name="%s"; filename="%s"',
+ $name,
+ basename($filename))
+ : "form-data; name=\"{$name}\"";
+ }
+
+ // Set a default content-length header if one was no provided
+ $length = $this->getHeader($headers, 'content-length');
+ if (!$length) {
+ if ($length = $stream->getSize()) {
+ $headers['Content-Length'] = (string) $length;
+ }
+ }
+
+ // Set a default Content-Type if one was not supplied
+ $type = $this->getHeader($headers, 'content-type');
+ if (!$type && ($filename === '0' || $filename)) {
+ if ($type = mimetype_from_filename($filename)) {
+ $headers['Content-Type'] = $type;
+ }
+ }
+
+ return [$stream, $headers];
+ }
+
+ private function getHeader(array $headers, $key)
+ {
+ $lowercaseHeader = strtolower($key);
+ foreach ($headers as $k => $v) {
+ if (strtolower($k) === $lowercaseHeader) {
+ return $v;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/NoSeekStream.php b/akamai/vendor/guzzlehttp/psr7/src/NoSeekStream.php
new file mode 100644
index 00000000..23322180
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/NoSeekStream.php
@@ -0,0 +1,22 @@
+source = $source;
+ $this->size = isset($options['size']) ? $options['size'] : null;
+ $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
+ $this->buffer = new BufferStream();
+ }
+
+ public function __toString()
+ {
+ try {
+ return copy_to_string($this);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function close()
+ {
+ $this->detach();
+ }
+
+ public function detach()
+ {
+ $this->tellPos = false;
+ $this->source = null;
+ }
+
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ public function tell()
+ {
+ return $this->tellPos;
+ }
+
+ public function eof()
+ {
+ return !$this->source;
+ }
+
+ public function isSeekable()
+ {
+ return false;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ throw new \RuntimeException('Cannot seek a PumpStream');
+ }
+
+ public function isWritable()
+ {
+ return false;
+ }
+
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write to a PumpStream');
+ }
+
+ public function isReadable()
+ {
+ return true;
+ }
+
+ public function read($length)
+ {
+ $data = $this->buffer->read($length);
+ $readLen = strlen($data);
+ $this->tellPos += $readLen;
+ $remaining = $length - $readLen;
+
+ if ($remaining) {
+ $this->pump($remaining);
+ $data .= $this->buffer->read($remaining);
+ $this->tellPos += strlen($data) - $readLen;
+ }
+
+ return $data;
+ }
+
+ public function getContents()
+ {
+ $result = '';
+ while (!$this->eof()) {
+ $result .= $this->read(1000000);
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!$key) {
+ return $this->metadata;
+ }
+
+ return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
+ }
+
+ private function pump($length)
+ {
+ if ($this->source) {
+ do {
+ $data = call_user_func($this->source, $length);
+ if ($data === false || $data === null) {
+ $this->source = null;
+ return;
+ }
+ $this->buffer->write($data);
+ $length -= strlen($data);
+ } while ($length > 0);
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/Request.php b/akamai/vendor/guzzlehttp/psr7/src/Request.php
new file mode 100644
index 00000000..59f337db
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/Request.php
@@ -0,0 +1,151 @@
+assertMethod($method);
+ if (!($uri instanceof UriInterface)) {
+ $uri = new Uri($uri);
+ }
+
+ $this->method = strtoupper($method);
+ $this->uri = $uri;
+ $this->setHeaders($headers);
+ $this->protocol = $version;
+
+ if (!isset($this->headerNames['host'])) {
+ $this->updateHostFromUri();
+ }
+
+ if ($body !== '' && $body !== null) {
+ $this->stream = stream_for($body);
+ }
+ }
+
+ public function getRequestTarget()
+ {
+ if ($this->requestTarget !== null) {
+ return $this->requestTarget;
+ }
+
+ $target = $this->uri->getPath();
+ if ($target == '') {
+ $target = '/';
+ }
+ if ($this->uri->getQuery() != '') {
+ $target .= '?' . $this->uri->getQuery();
+ }
+
+ return $target;
+ }
+
+ public function withRequestTarget($requestTarget)
+ {
+ if (preg_match('#\s#', $requestTarget)) {
+ throw new InvalidArgumentException(
+ 'Invalid request target provided; cannot contain whitespace'
+ );
+ }
+
+ $new = clone $this;
+ $new->requestTarget = $requestTarget;
+ return $new;
+ }
+
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+ public function withMethod($method)
+ {
+ $this->assertMethod($method);
+ $new = clone $this;
+ $new->method = strtoupper($method);
+ return $new;
+ }
+
+ public function getUri()
+ {
+ return $this->uri;
+ }
+
+ public function withUri(UriInterface $uri, $preserveHost = false)
+ {
+ if ($uri === $this->uri) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->uri = $uri;
+
+ if (!$preserveHost || !isset($this->headerNames['host'])) {
+ $new->updateHostFromUri();
+ }
+
+ return $new;
+ }
+
+ private function updateHostFromUri()
+ {
+ $host = $this->uri->getHost();
+
+ if ($host == '') {
+ return;
+ }
+
+ if (($port = $this->uri->getPort()) !== null) {
+ $host .= ':' . $port;
+ }
+
+ if (isset($this->headerNames['host'])) {
+ $header = $this->headerNames['host'];
+ } else {
+ $header = 'Host';
+ $this->headerNames['host'] = 'Host';
+ }
+ // Ensure Host is the first header.
+ // See: http://tools.ietf.org/html/rfc7230#section-5.4
+ $this->headers = [$header => [$host]] + $this->headers;
+ }
+
+ private function assertMethod($method)
+ {
+ if (!is_string($method) || $method === '') {
+ throw new \InvalidArgumentException('Method must be a non-empty string.');
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/Response.php b/akamai/vendor/guzzlehttp/psr7/src/Response.php
new file mode 100644
index 00000000..e7e04d86
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/Response.php
@@ -0,0 +1,154 @@
+ 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-status',
+ 208 => 'Already Reported',
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Switch Proxy',
+ 307 => 'Temporary Redirect',
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Time-out',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Large',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested range not satisfiable',
+ 417 => 'Expectation Failed',
+ 418 => 'I\'m a teapot',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 425 => 'Unordered Collection',
+ 426 => 'Upgrade Required',
+ 428 => 'Precondition Required',
+ 429 => 'Too Many Requests',
+ 431 => 'Request Header Fields Too Large',
+ 451 => 'Unavailable For Legal Reasons',
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Time-out',
+ 505 => 'HTTP Version not supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage',
+ 508 => 'Loop Detected',
+ 511 => 'Network Authentication Required',
+ ];
+
+ /** @var string */
+ private $reasonPhrase = '';
+
+ /** @var int */
+ private $statusCode = 200;
+
+ /**
+ * @param int $status Status code
+ * @param array $headers Response headers
+ * @param string|null|resource|StreamInterface $body Response body
+ * @param string $version Protocol version
+ * @param string|null $reason Reason phrase (when empty a default will be used based on the status code)
+ */
+ public function __construct(
+ $status = 200,
+ array $headers = [],
+ $body = null,
+ $version = '1.1',
+ $reason = null
+ ) {
+ $this->assertStatusCodeIsInteger($status);
+ $status = (int) $status;
+ $this->assertStatusCodeRange($status);
+
+ $this->statusCode = $status;
+
+ if ($body !== '' && $body !== null) {
+ $this->stream = stream_for($body);
+ }
+
+ $this->setHeaders($headers);
+ if ($reason == '' && isset(self::$phrases[$this->statusCode])) {
+ $this->reasonPhrase = self::$phrases[$this->statusCode];
+ } else {
+ $this->reasonPhrase = (string) $reason;
+ }
+
+ $this->protocol = $version;
+ }
+
+ public function getStatusCode()
+ {
+ return $this->statusCode;
+ }
+
+ public function getReasonPhrase()
+ {
+ return $this->reasonPhrase;
+ }
+
+ public function withStatus($code, $reasonPhrase = '')
+ {
+ $this->assertStatusCodeIsInteger($code);
+ $code = (int) $code;
+ $this->assertStatusCodeRange($code);
+
+ $new = clone $this;
+ $new->statusCode = $code;
+ if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {
+ $reasonPhrase = self::$phrases[$new->statusCode];
+ }
+ $new->reasonPhrase = $reasonPhrase;
+ return $new;
+ }
+
+ private function assertStatusCodeIsInteger($statusCode)
+ {
+ if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
+ throw new \InvalidArgumentException('Status code must be an integer value.');
+ }
+ }
+
+ private function assertStatusCodeRange($statusCode)
+ {
+ if ($statusCode < 100 || $statusCode >= 600) {
+ throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/Rfc7230.php b/akamai/vendor/guzzlehttp/psr7/src/Rfc7230.php
new file mode 100644
index 00000000..505e4742
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/Rfc7230.php
@@ -0,0 +1,18 @@
+@,;:\\\"/[\]?={}\x01-\x20\x7F]++):[ \t]*+((?:[ \t]*+[\x21-\x7E\x80-\xFF]++)*+)[ \t]*+\r?\n)m";
+ const HEADER_FOLD_REGEX = "(\r?\n[ \t]++)";
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/ServerRequest.php b/akamai/vendor/guzzlehttp/psr7/src/ServerRequest.php
new file mode 100644
index 00000000..1a09a6c8
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/ServerRequest.php
@@ -0,0 +1,376 @@
+serverParams = $serverParams;
+
+ parent::__construct($method, $uri, $headers, $body, $version);
+ }
+
+ /**
+ * Return an UploadedFile instance array.
+ *
+ * @param array $files A array which respect $_FILES structure
+ * @throws InvalidArgumentException for unrecognized values
+ * @return array
+ */
+ public static function normalizeFiles(array $files)
+ {
+ $normalized = [];
+
+ foreach ($files as $key => $value) {
+ if ($value instanceof UploadedFileInterface) {
+ $normalized[$key] = $value;
+ } elseif (is_array($value) && isset($value['tmp_name'])) {
+ $normalized[$key] = self::createUploadedFileFromSpec($value);
+ } elseif (is_array($value)) {
+ $normalized[$key] = self::normalizeFiles($value);
+ continue;
+ } else {
+ throw new InvalidArgumentException('Invalid value in files specification');
+ }
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * Create and return an UploadedFile instance from a $_FILES specification.
+ *
+ * If the specification represents an array of values, this method will
+ * delegate to normalizeNestedFileSpec() and return that return value.
+ *
+ * @param array $value $_FILES struct
+ * @return array|UploadedFileInterface
+ */
+ private static function createUploadedFileFromSpec(array $value)
+ {
+ if (is_array($value['tmp_name'])) {
+ return self::normalizeNestedFileSpec($value);
+ }
+
+ return new UploadedFile(
+ $value['tmp_name'],
+ (int) $value['size'],
+ (int) $value['error'],
+ $value['name'],
+ $value['type']
+ );
+ }
+
+ /**
+ * Normalize an array of file specifications.
+ *
+ * Loops through all nested files and returns a normalized array of
+ * UploadedFileInterface instances.
+ *
+ * @param array $files
+ * @return UploadedFileInterface[]
+ */
+ private static function normalizeNestedFileSpec(array $files = [])
+ {
+ $normalizedFiles = [];
+
+ foreach (array_keys($files['tmp_name']) as $key) {
+ $spec = [
+ 'tmp_name' => $files['tmp_name'][$key],
+ 'size' => $files['size'][$key],
+ 'error' => $files['error'][$key],
+ 'name' => $files['name'][$key],
+ 'type' => $files['type'][$key],
+ ];
+ $normalizedFiles[$key] = self::createUploadedFileFromSpec($spec);
+ }
+
+ return $normalizedFiles;
+ }
+
+ /**
+ * Return a ServerRequest populated with superglobals:
+ * $_GET
+ * $_POST
+ * $_COOKIE
+ * $_FILES
+ * $_SERVER
+ *
+ * @return ServerRequestInterface
+ */
+ public static function fromGlobals()
+ {
+ $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
+ $headers = getallheaders();
+ $uri = self::getUriFromGlobals();
+ $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
+ $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
+
+ $serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
+
+ return $serverRequest
+ ->withCookieParams($_COOKIE)
+ ->withQueryParams($_GET)
+ ->withParsedBody($_POST)
+ ->withUploadedFiles(self::normalizeFiles($_FILES));
+ }
+
+ private static function extractHostAndPortFromAuthority($authority)
+ {
+ $uri = 'http://'.$authority;
+ $parts = parse_url($uri);
+ if (false === $parts) {
+ return [null, null];
+ }
+
+ $host = isset($parts['host']) ? $parts['host'] : null;
+ $port = isset($parts['port']) ? $parts['port'] : null;
+
+ return [$host, $port];
+ }
+
+ /**
+ * Get a Uri populated with values from $_SERVER.
+ *
+ * @return UriInterface
+ */
+ public static function getUriFromGlobals()
+ {
+ $uri = new Uri('');
+
+ $uri = $uri->withScheme(!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ? 'https' : 'http');
+
+ $hasPort = false;
+ if (isset($_SERVER['HTTP_HOST'])) {
+ list($host, $port) = self::extractHostAndPortFromAuthority($_SERVER['HTTP_HOST']);
+ if ($host !== null) {
+ $uri = $uri->withHost($host);
+ }
+
+ if ($port !== null) {
+ $hasPort = true;
+ $uri = $uri->withPort($port);
+ }
+ } elseif (isset($_SERVER['SERVER_NAME'])) {
+ $uri = $uri->withHost($_SERVER['SERVER_NAME']);
+ } elseif (isset($_SERVER['SERVER_ADDR'])) {
+ $uri = $uri->withHost($_SERVER['SERVER_ADDR']);
+ }
+
+ if (!$hasPort && isset($_SERVER['SERVER_PORT'])) {
+ $uri = $uri->withPort($_SERVER['SERVER_PORT']);
+ }
+
+ $hasQuery = false;
+ if (isset($_SERVER['REQUEST_URI'])) {
+ $requestUriParts = explode('?', $_SERVER['REQUEST_URI'], 2);
+ $uri = $uri->withPath($requestUriParts[0]);
+ if (isset($requestUriParts[1])) {
+ $hasQuery = true;
+ $uri = $uri->withQuery($requestUriParts[1]);
+ }
+ }
+
+ if (!$hasQuery && isset($_SERVER['QUERY_STRING'])) {
+ $uri = $uri->withQuery($_SERVER['QUERY_STRING']);
+ }
+
+ return $uri;
+ }
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getServerParams()
+ {
+ return $this->serverParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUploadedFiles()
+ {
+ return $this->uploadedFiles;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withUploadedFiles(array $uploadedFiles)
+ {
+ $new = clone $this;
+ $new->uploadedFiles = $uploadedFiles;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCookieParams()
+ {
+ return $this->cookieParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withCookieParams(array $cookies)
+ {
+ $new = clone $this;
+ $new->cookieParams = $cookies;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getQueryParams()
+ {
+ return $this->queryParams;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withQueryParams(array $query)
+ {
+ $new = clone $this;
+ $new->queryParams = $query;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParsedBody()
+ {
+ return $this->parsedBody;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withParsedBody($data)
+ {
+ $new = clone $this;
+ $new->parsedBody = $data;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttributes()
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAttribute($attribute, $default = null)
+ {
+ if (false === array_key_exists($attribute, $this->attributes)) {
+ return $default;
+ }
+
+ return $this->attributes[$attribute];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withAttribute($attribute, $value)
+ {
+ $new = clone $this;
+ $new->attributes[$attribute] = $value;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withoutAttribute($attribute)
+ {
+ if (false === array_key_exists($attribute, $this->attributes)) {
+ return $this;
+ }
+
+ $new = clone $this;
+ unset($new->attributes[$attribute]);
+
+ return $new;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/Stream.php b/akamai/vendor/guzzlehttp/psr7/src/Stream.php
new file mode 100644
index 00000000..d9e7409c
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/Stream.php
@@ -0,0 +1,267 @@
+size = $options['size'];
+ }
+
+ $this->customMetadata = isset($options['metadata'])
+ ? $options['metadata']
+ : [];
+
+ $this->stream = $stream;
+ $meta = stream_get_meta_data($this->stream);
+ $this->seekable = $meta['seekable'];
+ $this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']);
+ $this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']);
+ $this->uri = $this->getMetadata('uri');
+ }
+
+ /**
+ * Closes the stream when the destructed
+ */
+ public function __destruct()
+ {
+ $this->close();
+ }
+
+ public function __toString()
+ {
+ try {
+ $this->seek(0);
+ return (string) stream_get_contents($this->stream);
+ } catch (\Exception $e) {
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+
+ $contents = stream_get_contents($this->stream);
+
+ if ($contents === false) {
+ throw new \RuntimeException('Unable to read stream contents');
+ }
+
+ return $contents;
+ }
+
+ public function close()
+ {
+ if (isset($this->stream)) {
+ if (is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->detach();
+ }
+ }
+
+ public function detach()
+ {
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ $result = $this->stream;
+ unset($this->stream);
+ $this->size = $this->uri = null;
+ $this->readable = $this->writable = $this->seekable = false;
+
+ return $result;
+ }
+
+ public function getSize()
+ {
+ if ($this->size !== null) {
+ return $this->size;
+ }
+
+ if (!isset($this->stream)) {
+ return null;
+ }
+
+ // Clear the stat cache if the stream has a URI
+ if ($this->uri) {
+ clearstatcache(true, $this->uri);
+ }
+
+ $stats = fstat($this->stream);
+ if (isset($stats['size'])) {
+ $this->size = $stats['size'];
+ return $this->size;
+ }
+
+ return null;
+ }
+
+ public function isReadable()
+ {
+ return $this->readable;
+ }
+
+ public function isWritable()
+ {
+ return $this->writable;
+ }
+
+ public function isSeekable()
+ {
+ return $this->seekable;
+ }
+
+ public function eof()
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+
+ return feof($this->stream);
+ }
+
+ public function tell()
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+
+ $result = ftell($this->stream);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to determine stream position');
+ }
+
+ return $result;
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $whence = (int) $whence;
+
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+ if (!$this->seekable) {
+ throw new \RuntimeException('Stream is not seekable');
+ }
+ if (fseek($this->stream, $offset, $whence) === -1) {
+ throw new \RuntimeException('Unable to seek to stream position '
+ . $offset . ' with whence ' . var_export($whence, true));
+ }
+ }
+
+ public function read($length)
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+ if (!$this->readable) {
+ throw new \RuntimeException('Cannot read from non-readable stream');
+ }
+ if ($length < 0) {
+ throw new \RuntimeException('Length parameter cannot be negative');
+ }
+
+ if (0 === $length) {
+ return '';
+ }
+
+ $string = fread($this->stream, $length);
+ if (false === $string) {
+ throw new \RuntimeException('Unable to read from stream');
+ }
+
+ return $string;
+ }
+
+ public function write($string)
+ {
+ if (!isset($this->stream)) {
+ throw new \RuntimeException('Stream is detached');
+ }
+ if (!$this->writable) {
+ throw new \RuntimeException('Cannot write to a non-writable stream');
+ }
+
+ // We can't know the size after writing anything
+ $this->size = null;
+ $result = fwrite($this->stream, $string);
+
+ if ($result === false) {
+ throw new \RuntimeException('Unable to write to stream');
+ }
+
+ return $result;
+ }
+
+ public function getMetadata($key = null)
+ {
+ if (!isset($this->stream)) {
+ return $key ? null : [];
+ } elseif (!$key) {
+ return $this->customMetadata + stream_get_meta_data($this->stream);
+ } elseif (isset($this->customMetadata[$key])) {
+ return $this->customMetadata[$key];
+ }
+
+ $meta = stream_get_meta_data($this->stream);
+
+ return isset($meta[$key]) ? $meta[$key] : null;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php b/akamai/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
new file mode 100644
index 00000000..daec6f52
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
@@ -0,0 +1,149 @@
+stream = $stream;
+ }
+
+ /**
+ * Magic method used to create a new stream if streams are not added in
+ * the constructor of a decorator (e.g., LazyOpenStream).
+ *
+ * @param string $name Name of the property (allows "stream" only).
+ *
+ * @return StreamInterface
+ */
+ public function __get($name)
+ {
+ if ($name == 'stream') {
+ $this->stream = $this->createStream();
+ return $this->stream;
+ }
+
+ throw new \UnexpectedValueException("$name not found on class");
+ }
+
+ public function __toString()
+ {
+ try {
+ if ($this->isSeekable()) {
+ $this->seek(0);
+ }
+ return $this->getContents();
+ } catch (\Exception $e) {
+ // Really, PHP? https://bugs.php.net/bug.php?id=53648
+ trigger_error('StreamDecorator::__toString exception: '
+ . (string) $e, E_USER_ERROR);
+ return '';
+ }
+ }
+
+ public function getContents()
+ {
+ return copy_to_string($this);
+ }
+
+ /**
+ * Allow decorators to implement custom methods
+ *
+ * @param string $method Missing method name
+ * @param array $args Method arguments
+ *
+ * @return mixed
+ */
+ public function __call($method, array $args)
+ {
+ $result = call_user_func_array([$this->stream, $method], $args);
+
+ // Always return the wrapped object if the result is a return $this
+ return $result === $this->stream ? $this : $result;
+ }
+
+ public function close()
+ {
+ $this->stream->close();
+ }
+
+ public function getMetadata($key = null)
+ {
+ return $this->stream->getMetadata($key);
+ }
+
+ public function detach()
+ {
+ return $this->stream->detach();
+ }
+
+ public function getSize()
+ {
+ return $this->stream->getSize();
+ }
+
+ public function eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function isReadable()
+ {
+ return $this->stream->isReadable();
+ }
+
+ public function isWritable()
+ {
+ return $this->stream->isWritable();
+ }
+
+ public function isSeekable()
+ {
+ return $this->stream->isSeekable();
+ }
+
+ public function rewind()
+ {
+ $this->seek(0);
+ }
+
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $this->stream->seek($offset, $whence);
+ }
+
+ public function read($length)
+ {
+ return $this->stream->read($length);
+ }
+
+ public function write($string)
+ {
+ return $this->stream->write($string);
+ }
+
+ /**
+ * Implement in subclasses to dynamically create streams when requested.
+ *
+ * @return StreamInterface
+ * @throws \BadMethodCallException
+ */
+ protected function createStream()
+ {
+ throw new \BadMethodCallException('Not implemented');
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/StreamWrapper.php b/akamai/vendor/guzzlehttp/psr7/src/StreamWrapper.php
new file mode 100644
index 00000000..0f3a2856
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/StreamWrapper.php
@@ -0,0 +1,161 @@
+isReadable()) {
+ $mode = $stream->isWritable() ? 'r+' : 'r';
+ } elseif ($stream->isWritable()) {
+ $mode = 'w';
+ } else {
+ throw new \InvalidArgumentException('The stream must be readable, '
+ . 'writable, or both.');
+ }
+
+ return fopen('guzzle://stream', $mode, null, self::createStreamContext($stream));
+ }
+
+ /**
+ * Creates a stream context that can be used to open a stream as a php stream resource.
+ *
+ * @param StreamInterface $stream
+ *
+ * @return resource
+ */
+ public static function createStreamContext(StreamInterface $stream)
+ {
+ return stream_context_create([
+ 'guzzle' => ['stream' => $stream]
+ ]);
+ }
+
+ /**
+ * Registers the stream wrapper if needed
+ */
+ public static function register()
+ {
+ if (!in_array('guzzle', stream_get_wrappers())) {
+ stream_wrapper_register('guzzle', __CLASS__);
+ }
+ }
+
+ public function stream_open($path, $mode, $options, &$opened_path)
+ {
+ $options = stream_context_get_options($this->context);
+
+ if (!isset($options['guzzle']['stream'])) {
+ return false;
+ }
+
+ $this->mode = $mode;
+ $this->stream = $options['guzzle']['stream'];
+
+ return true;
+ }
+
+ public function stream_read($count)
+ {
+ return $this->stream->read($count);
+ }
+
+ public function stream_write($data)
+ {
+ return (int) $this->stream->write($data);
+ }
+
+ public function stream_tell()
+ {
+ return $this->stream->tell();
+ }
+
+ public function stream_eof()
+ {
+ return $this->stream->eof();
+ }
+
+ public function stream_seek($offset, $whence)
+ {
+ $this->stream->seek($offset, $whence);
+
+ return true;
+ }
+
+ public function stream_cast($cast_as)
+ {
+ $stream = clone($this->stream);
+
+ return $stream->detach();
+ }
+
+ public function stream_stat()
+ {
+ static $modeMap = [
+ 'r' => 33060,
+ 'rb' => 33060,
+ 'r+' => 33206,
+ 'w' => 33188,
+ 'wb' => 33188
+ ];
+
+ return [
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => $modeMap[$this->mode],
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => $this->stream->getSize() ?: 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ ];
+ }
+
+ public function url_stat($path, $flags)
+ {
+ return [
+ 'dev' => 0,
+ 'ino' => 0,
+ 'mode' => 0,
+ 'nlink' => 0,
+ 'uid' => 0,
+ 'gid' => 0,
+ 'rdev' => 0,
+ 'size' => 0,
+ 'atime' => 0,
+ 'mtime' => 0,
+ 'ctime' => 0,
+ 'blksize' => 0,
+ 'blocks' => 0
+ ];
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/UploadedFile.php b/akamai/vendor/guzzlehttp/psr7/src/UploadedFile.php
new file mode 100644
index 00000000..e62bd5c8
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/UploadedFile.php
@@ -0,0 +1,316 @@
+setError($errorStatus);
+ $this->setSize($size);
+ $this->setClientFilename($clientFilename);
+ $this->setClientMediaType($clientMediaType);
+
+ if ($this->isOk()) {
+ $this->setStreamOrFile($streamOrFile);
+ }
+ }
+
+ /**
+ * Depending on the value set file or stream variable
+ *
+ * @param mixed $streamOrFile
+ * @throws InvalidArgumentException
+ */
+ private function setStreamOrFile($streamOrFile)
+ {
+ if (is_string($streamOrFile)) {
+ $this->file = $streamOrFile;
+ } elseif (is_resource($streamOrFile)) {
+ $this->stream = new Stream($streamOrFile);
+ } elseif ($streamOrFile instanceof StreamInterface) {
+ $this->stream = $streamOrFile;
+ } else {
+ throw new InvalidArgumentException(
+ 'Invalid stream or file provided for UploadedFile'
+ );
+ }
+ }
+
+ /**
+ * @param int $error
+ * @throws InvalidArgumentException
+ */
+ private function setError($error)
+ {
+ if (false === is_int($error)) {
+ throw new InvalidArgumentException(
+ 'Upload file error status must be an integer'
+ );
+ }
+
+ if (false === in_array($error, UploadedFile::$errors)) {
+ throw new InvalidArgumentException(
+ 'Invalid error status for UploadedFile'
+ );
+ }
+
+ $this->error = $error;
+ }
+
+ /**
+ * @param int $size
+ * @throws InvalidArgumentException
+ */
+ private function setSize($size)
+ {
+ if (false === is_int($size)) {
+ throw new InvalidArgumentException(
+ 'Upload file size must be an integer'
+ );
+ }
+
+ $this->size = $size;
+ }
+
+ /**
+ * @param mixed $param
+ * @return boolean
+ */
+ private function isStringOrNull($param)
+ {
+ return in_array(gettype($param), ['string', 'NULL']);
+ }
+
+ /**
+ * @param mixed $param
+ * @return boolean
+ */
+ private function isStringNotEmpty($param)
+ {
+ return is_string($param) && false === empty($param);
+ }
+
+ /**
+ * @param string|null $clientFilename
+ * @throws InvalidArgumentException
+ */
+ private function setClientFilename($clientFilename)
+ {
+ if (false === $this->isStringOrNull($clientFilename)) {
+ throw new InvalidArgumentException(
+ 'Upload file client filename must be a string or null'
+ );
+ }
+
+ $this->clientFilename = $clientFilename;
+ }
+
+ /**
+ * @param string|null $clientMediaType
+ * @throws InvalidArgumentException
+ */
+ private function setClientMediaType($clientMediaType)
+ {
+ if (false === $this->isStringOrNull($clientMediaType)) {
+ throw new InvalidArgumentException(
+ 'Upload file client media type must be a string or null'
+ );
+ }
+
+ $this->clientMediaType = $clientMediaType;
+ }
+
+ /**
+ * Return true if there is no upload error
+ *
+ * @return boolean
+ */
+ private function isOk()
+ {
+ return $this->error === UPLOAD_ERR_OK;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isMoved()
+ {
+ return $this->moved;
+ }
+
+ /**
+ * @throws RuntimeException if is moved or not ok
+ */
+ private function validateActive()
+ {
+ if (false === $this->isOk()) {
+ throw new RuntimeException('Cannot retrieve stream due to upload error');
+ }
+
+ if ($this->isMoved()) {
+ throw new RuntimeException('Cannot retrieve stream after it has already been moved');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws RuntimeException if the upload was not successful.
+ */
+ public function getStream()
+ {
+ $this->validateActive();
+
+ if ($this->stream instanceof StreamInterface) {
+ return $this->stream;
+ }
+
+ return new LazyOpenStream($this->file, 'r+');
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @see http://php.net/is_uploaded_file
+ * @see http://php.net/move_uploaded_file
+ * @param string $targetPath Path to which to move the uploaded file.
+ * @throws RuntimeException if the upload was not successful.
+ * @throws InvalidArgumentException if the $path specified is invalid.
+ * @throws RuntimeException on any error during the move operation, or on
+ * the second or subsequent call to the method.
+ */
+ public function moveTo($targetPath)
+ {
+ $this->validateActive();
+
+ if (false === $this->isStringNotEmpty($targetPath)) {
+ throw new InvalidArgumentException(
+ 'Invalid path provided for move operation; must be a non-empty string'
+ );
+ }
+
+ if ($this->file) {
+ $this->moved = php_sapi_name() == 'cli'
+ ? rename($this->file, $targetPath)
+ : move_uploaded_file($this->file, $targetPath);
+ } else {
+ copy_to_stream(
+ $this->getStream(),
+ new LazyOpenStream($targetPath, 'w')
+ );
+
+ $this->moved = true;
+ }
+
+ if (false === $this->moved) {
+ throw new RuntimeException(
+ sprintf('Uploaded file could not be moved to %s', $targetPath)
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return int|null The file size in bytes or null if unknown.
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @see http://php.net/manual/en/features.file-upload.errors.php
+ * @return int One of PHP's UPLOAD_ERR_XXX constants.
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return string|null The filename sent by the client or null if none
+ * was provided.
+ */
+ public function getClientFilename()
+ {
+ return $this->clientFilename;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getClientMediaType()
+ {
+ return $this->clientMediaType;
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/Uri.php b/akamai/vendor/guzzlehttp/psr7/src/Uri.php
new file mode 100644
index 00000000..825a25ee
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/Uri.php
@@ -0,0 +1,760 @@
+ 80,
+ 'https' => 443,
+ 'ftp' => 21,
+ 'gopher' => 70,
+ 'nntp' => 119,
+ 'news' => 119,
+ 'telnet' => 23,
+ 'tn3270' => 23,
+ 'imap' => 143,
+ 'pop' => 110,
+ 'ldap' => 389,
+ ];
+
+ private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
+ private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
+ private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
+
+ /** @var string Uri scheme. */
+ private $scheme = '';
+
+ /** @var string Uri user info. */
+ private $userInfo = '';
+
+ /** @var string Uri host. */
+ private $host = '';
+
+ /** @var int|null Uri port. */
+ private $port;
+
+ /** @var string Uri path. */
+ private $path = '';
+
+ /** @var string Uri query string. */
+ private $query = '';
+
+ /** @var string Uri fragment. */
+ private $fragment = '';
+
+ /**
+ * @param string $uri URI to parse
+ */
+ public function __construct($uri = '')
+ {
+ // weak type check to also accept null until we can add scalar type hints
+ if ($uri != '') {
+ $parts = parse_url($uri);
+ if ($parts === false) {
+ throw new \InvalidArgumentException("Unable to parse URI: $uri");
+ }
+ $this->applyParts($parts);
+ }
+ }
+
+ public function __toString()
+ {
+ return self::composeComponents(
+ $this->scheme,
+ $this->getAuthority(),
+ $this->path,
+ $this->query,
+ $this->fragment
+ );
+ }
+
+ /**
+ * Composes a URI reference string from its various components.
+ *
+ * Usually this method does not need to be called manually but instead is used indirectly via
+ * `Psr\Http\Message\UriInterface::__toString`.
+ *
+ * PSR-7 UriInterface treats an empty component the same as a missing component as
+ * getQuery(), getFragment() etc. always return a string. This explains the slight
+ * difference to RFC 3986 Section 5.3.
+ *
+ * Another adjustment is that the authority separator is added even when the authority is missing/empty
+ * for the "file" scheme. This is because PHP stream functions like `file_get_contents` only work with
+ * `file:///myfile` but not with `file:/myfile` although they are equivalent according to RFC 3986. But
+ * `file:///` is the more common syntax for the file scheme anyway (Chrome for example redirects to
+ * that format).
+ *
+ * @param string $scheme
+ * @param string $authority
+ * @param string $path
+ * @param string $query
+ * @param string $fragment
+ *
+ * @return string
+ *
+ * @link https://tools.ietf.org/html/rfc3986#section-5.3
+ */
+ public static function composeComponents($scheme, $authority, $path, $query, $fragment)
+ {
+ $uri = '';
+
+ // weak type checks to also accept null until we can add scalar type hints
+ if ($scheme != '') {
+ $uri .= $scheme . ':';
+ }
+
+ if ($authority != ''|| $scheme === 'file') {
+ $uri .= '//' . $authority;
+ }
+
+ $uri .= $path;
+
+ if ($query != '') {
+ $uri .= '?' . $query;
+ }
+
+ if ($fragment != '') {
+ $uri .= '#' . $fragment;
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Whether the URI has the default port of the current scheme.
+ *
+ * `Psr\Http\Message\UriInterface::getPort` may return null or the standard port. This method can be used
+ * independently of the implementation.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ */
+ public static function isDefaultPort(UriInterface $uri)
+ {
+ return $uri->getPort() === null
+ || (isset(self::$defaultPorts[$uri->getScheme()]) && $uri->getPort() === self::$defaultPorts[$uri->getScheme()]);
+ }
+
+ /**
+ * Whether the URI is absolute, i.e. it has a scheme.
+ *
+ * An instance of UriInterface can either be an absolute URI or a relative reference. This method returns true
+ * if it is the former. An absolute URI has a scheme. A relative reference is used to express a URI relative
+ * to another URI, the base URI. Relative references can be divided into several forms:
+ * - network-path references, e.g. '//example.com/path'
+ * - absolute-path references, e.g. '/path'
+ * - relative-path references, e.g. 'subpath'
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ * @see Uri::isNetworkPathReference
+ * @see Uri::isAbsolutePathReference
+ * @see Uri::isRelativePathReference
+ * @link https://tools.ietf.org/html/rfc3986#section-4
+ */
+ public static function isAbsolute(UriInterface $uri)
+ {
+ return $uri->getScheme() !== '';
+ }
+
+ /**
+ * Whether the URI is a network-path reference.
+ *
+ * A relative reference that begins with two slash characters is termed an network-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isNetworkPathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === '' && $uri->getAuthority() !== '';
+ }
+
+ /**
+ * Whether the URI is a absolute-path reference.
+ *
+ * A relative reference that begins with a single slash character is termed an absolute-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isAbsolutePathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === ''
+ && $uri->getAuthority() === ''
+ && isset($uri->getPath()[0])
+ && $uri->getPath()[0] === '/';
+ }
+
+ /**
+ * Whether the URI is a relative-path reference.
+ *
+ * A relative reference that does not begin with a slash character is termed a relative-path reference.
+ *
+ * @param UriInterface $uri
+ *
+ * @return bool
+ * @link https://tools.ietf.org/html/rfc3986#section-4.2
+ */
+ public static function isRelativePathReference(UriInterface $uri)
+ {
+ return $uri->getScheme() === ''
+ && $uri->getAuthority() === ''
+ && (!isset($uri->getPath()[0]) || $uri->getPath()[0] !== '/');
+ }
+
+ /**
+ * Whether the URI is a same-document reference.
+ *
+ * A same-document reference refers to a URI that is, aside from its fragment
+ * component, identical to the base URI. When no base URI is given, only an empty
+ * URI reference (apart from its fragment) is considered a same-document reference.
+ *
+ * @param UriInterface $uri The URI to check
+ * @param UriInterface|null $base An optional base URI to compare against
+ *
+ * @return bool
+ * @link https://tools.ietf.org/html/rfc3986#section-4.4
+ */
+ public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null)
+ {
+ if ($base !== null) {
+ $uri = UriResolver::resolve($base, $uri);
+
+ return ($uri->getScheme() === $base->getScheme())
+ && ($uri->getAuthority() === $base->getAuthority())
+ && ($uri->getPath() === $base->getPath())
+ && ($uri->getQuery() === $base->getQuery());
+ }
+
+ return $uri->getScheme() === '' && $uri->getAuthority() === '' && $uri->getPath() === '' && $uri->getQuery() === '';
+ }
+
+ /**
+ * Removes dot segments from a path and returns the new path.
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @deprecated since version 1.4. Use UriResolver::removeDotSegments instead.
+ * @see UriResolver::removeDotSegments
+ */
+ public static function removeDotSegments($path)
+ {
+ return UriResolver::removeDotSegments($path);
+ }
+
+ /**
+ * Converts the relative URI into a new URI that is resolved against the base URI.
+ *
+ * @param UriInterface $base Base URI
+ * @param string|UriInterface $rel Relative URI
+ *
+ * @return UriInterface
+ *
+ * @deprecated since version 1.4. Use UriResolver::resolve instead.
+ * @see UriResolver::resolve
+ */
+ public static function resolve(UriInterface $base, $rel)
+ {
+ if (!($rel instanceof UriInterface)) {
+ $rel = new self($rel);
+ }
+
+ return UriResolver::resolve($base, $rel);
+ }
+
+ /**
+ * Creates a new URI with a specific query string value removed.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed.
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Query string key to remove.
+ *
+ * @return UriInterface
+ */
+ public static function withoutQueryValue(UriInterface $uri, $key)
+ {
+ $result = self::getFilteredQueryString($uri, [$key]);
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a new URI with a specific query string value.
+ *
+ * Any existing query string values that exactly match the provided key are
+ * removed and replaced with the given key value pair.
+ *
+ * A value of null will set the query string key without a value, e.g. "key"
+ * instead of "key=value".
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param string $key Key to set.
+ * @param string|null $value Value to set
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValue(UriInterface $uri, $key, $value)
+ {
+ $result = self::getFilteredQueryString($uri, [$key]);
+
+ $result[] = self::generateQueryString($key, $value);
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a new URI with multiple specific query string values.
+ *
+ * It has the same behavior as withQueryValue() but for an associative array of key => value.
+ *
+ * @param UriInterface $uri URI to use as a base.
+ * @param array $keyValueArray Associative array of key and values
+ *
+ * @return UriInterface
+ */
+ public static function withQueryValues(UriInterface $uri, array $keyValueArray)
+ {
+ $result = self::getFilteredQueryString($uri, array_keys($keyValueArray));
+
+ foreach ($keyValueArray as $key => $value) {
+ $result[] = self::generateQueryString($key, $value);
+ }
+
+ return $uri->withQuery(implode('&', $result));
+ }
+
+ /**
+ * Creates a URI from a hash of `parse_url` components.
+ *
+ * @param array $parts
+ *
+ * @return UriInterface
+ * @link http://php.net/manual/en/function.parse-url.php
+ *
+ * @throws \InvalidArgumentException If the components do not form a valid URI.
+ */
+ public static function fromParts(array $parts)
+ {
+ $uri = new self();
+ $uri->applyParts($parts);
+ $uri->validateState();
+
+ return $uri;
+ }
+
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+ public function getAuthority()
+ {
+ $authority = $this->host;
+ if ($this->userInfo !== '') {
+ $authority = $this->userInfo . '@' . $authority;
+ }
+
+ if ($this->port !== null) {
+ $authority .= ':' . $this->port;
+ }
+
+ return $authority;
+ }
+
+ public function getUserInfo()
+ {
+ return $this->userInfo;
+ }
+
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+ public function withScheme($scheme)
+ {
+ $scheme = $this->filterScheme($scheme);
+
+ if ($this->scheme === $scheme) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->scheme = $scheme;
+ $new->removeDefaultPort();
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withUserInfo($user, $password = null)
+ {
+ $info = $this->filterUserInfoComponent($user);
+ if ($password !== null) {
+ $info .= ':' . $this->filterUserInfoComponent($password);
+ }
+
+ if ($this->userInfo === $info) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->userInfo = $info;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withHost($host)
+ {
+ $host = $this->filterHost($host);
+
+ if ($this->host === $host) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->host = $host;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withPort($port)
+ {
+ $port = $this->filterPort($port);
+
+ if ($this->port === $port) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->port = $port;
+ $new->removeDefaultPort();
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withPath($path)
+ {
+ $path = $this->filterPath($path);
+
+ if ($this->path === $path) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->path = $path;
+ $new->validateState();
+
+ return $new;
+ }
+
+ public function withQuery($query)
+ {
+ $query = $this->filterQueryAndFragment($query);
+
+ if ($this->query === $query) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->query = $query;
+
+ return $new;
+ }
+
+ public function withFragment($fragment)
+ {
+ $fragment = $this->filterQueryAndFragment($fragment);
+
+ if ($this->fragment === $fragment) {
+ return $this;
+ }
+
+ $new = clone $this;
+ $new->fragment = $fragment;
+
+ return $new;
+ }
+
+ /**
+ * Apply parse_url parts to a URI.
+ *
+ * @param array $parts Array of parse_url parts to apply.
+ */
+ private function applyParts(array $parts)
+ {
+ $this->scheme = isset($parts['scheme'])
+ ? $this->filterScheme($parts['scheme'])
+ : '';
+ $this->userInfo = isset($parts['user'])
+ ? $this->filterUserInfoComponent($parts['user'])
+ : '';
+ $this->host = isset($parts['host'])
+ ? $this->filterHost($parts['host'])
+ : '';
+ $this->port = isset($parts['port'])
+ ? $this->filterPort($parts['port'])
+ : null;
+ $this->path = isset($parts['path'])
+ ? $this->filterPath($parts['path'])
+ : '';
+ $this->query = isset($parts['query'])
+ ? $this->filterQueryAndFragment($parts['query'])
+ : '';
+ $this->fragment = isset($parts['fragment'])
+ ? $this->filterQueryAndFragment($parts['fragment'])
+ : '';
+ if (isset($parts['pass'])) {
+ $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
+ }
+
+ $this->removeDefaultPort();
+ }
+
+ /**
+ * @param string $scheme
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the scheme is invalid.
+ */
+ private function filterScheme($scheme)
+ {
+ if (!is_string($scheme)) {
+ throw new \InvalidArgumentException('Scheme must be a string');
+ }
+
+ return strtolower($scheme);
+ }
+
+ /**
+ * @param string $component
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the user info is invalid.
+ */
+ private function filterUserInfoComponent($component)
+ {
+ if (!is_string($component)) {
+ throw new \InvalidArgumentException('User info must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $component
+ );
+ }
+
+ /**
+ * @param string $host
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the host is invalid.
+ */
+ private function filterHost($host)
+ {
+ if (!is_string($host)) {
+ throw new \InvalidArgumentException('Host must be a string');
+ }
+
+ return strtolower($host);
+ }
+
+ /**
+ * @param int|null $port
+ *
+ * @return int|null
+ *
+ * @throws \InvalidArgumentException If the port is invalid.
+ */
+ private function filterPort($port)
+ {
+ if ($port === null) {
+ return null;
+ }
+
+ $port = (int) $port;
+ if (0 > $port || 0xffff < $port) {
+ throw new \InvalidArgumentException(
+ sprintf('Invalid port: %d. Must be between 0 and 65535', $port)
+ );
+ }
+
+ return $port;
+ }
+
+ /**
+ * @param UriInterface $uri
+ * @param array $keys
+ *
+ * @return array
+ */
+ private static function getFilteredQueryString(UriInterface $uri, array $keys)
+ {
+ $current = $uri->getQuery();
+
+ if ($current === '') {
+ return [];
+ }
+
+ $decodedKeys = array_map('rawurldecode', $keys);
+
+ return array_filter(explode('&', $current), function ($part) use ($decodedKeys) {
+ return !in_array(rawurldecode(explode('=', $part)[0]), $decodedKeys, true);
+ });
+ }
+
+ /**
+ * @param string $key
+ * @param string|null $value
+ *
+ * @return string
+ */
+ private static function generateQueryString($key, $value)
+ {
+ // Query string separators ("=", "&") within the key or value need to be encoded
+ // (while preventing double-encoding) before setting the query string. All other
+ // chars that need percent-encoding will be encoded by withQuery().
+ $queryString = strtr($key, self::$replaceQuery);
+
+ if ($value !== null) {
+ $queryString .= '=' . strtr($value, self::$replaceQuery);
+ }
+
+ return $queryString;
+ }
+
+ private function removeDefaultPort()
+ {
+ if ($this->port !== null && self::isDefaultPort($this)) {
+ $this->port = null;
+ }
+ }
+
+ /**
+ * Filters the path of a URI
+ *
+ * @param string $path
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the path is invalid.
+ */
+ private function filterPath($path)
+ {
+ if (!is_string($path)) {
+ throw new \InvalidArgumentException('Path must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/]++|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $path
+ );
+ }
+
+ /**
+ * Filters the query string or fragment of a URI.
+ *
+ * @param string $str
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the query or fragment is invalid.
+ */
+ private function filterQueryAndFragment($str)
+ {
+ if (!is_string($str)) {
+ throw new \InvalidArgumentException('Query and fragment must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]++|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $str
+ );
+ }
+
+ private function rawurlencodeMatchZero(array $match)
+ {
+ return rawurlencode($match[0]);
+ }
+
+ private function validateState()
+ {
+ if ($this->host === '' && ($this->scheme === 'http' || $this->scheme === 'https')) {
+ $this->host = self::HTTP_DEFAULT_HOST;
+ }
+
+ if ($this->getAuthority() === '') {
+ if (0 === strpos($this->path, '//')) {
+ throw new \InvalidArgumentException('The path of a URI without an authority must not start with two slashes "//"');
+ }
+ if ($this->scheme === '' && false !== strpos(explode('/', $this->path, 2)[0], ':')) {
+ throw new \InvalidArgumentException('A relative URI must not have a path beginning with a segment containing a colon');
+ }
+ } elseif (isset($this->path[0]) && $this->path[0] !== '/') {
+ @trigger_error(
+ 'The path of a URI with an authority must start with a slash "/" or be empty. Automagically fixing the URI ' .
+ 'by adding a leading slash to the path is deprecated since version 1.4 and will throw an exception instead.',
+ E_USER_DEPRECATED
+ );
+ $this->path = '/'. $this->path;
+ //throw new \InvalidArgumentException('The path of a URI with an authority must start with a slash "/" or be empty');
+ }
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/UriNormalizer.php b/akamai/vendor/guzzlehttp/psr7/src/UriNormalizer.php
new file mode 100644
index 00000000..384c29e5
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/UriNormalizer.php
@@ -0,0 +1,216 @@
+getPath() === '' &&
+ ($uri->getScheme() === 'http' || $uri->getScheme() === 'https')
+ ) {
+ $uri = $uri->withPath('/');
+ }
+
+ if ($flags & self::REMOVE_DEFAULT_HOST && $uri->getScheme() === 'file' && $uri->getHost() === 'localhost') {
+ $uri = $uri->withHost('');
+ }
+
+ if ($flags & self::REMOVE_DEFAULT_PORT && $uri->getPort() !== null && Uri::isDefaultPort($uri)) {
+ $uri = $uri->withPort(null);
+ }
+
+ if ($flags & self::REMOVE_DOT_SEGMENTS && !Uri::isRelativePathReference($uri)) {
+ $uri = $uri->withPath(UriResolver::removeDotSegments($uri->getPath()));
+ }
+
+ if ($flags & self::REMOVE_DUPLICATE_SLASHES) {
+ $uri = $uri->withPath(preg_replace('#//++#', '/', $uri->getPath()));
+ }
+
+ if ($flags & self::SORT_QUERY_PARAMETERS && $uri->getQuery() !== '') {
+ $queryKeyValues = explode('&', $uri->getQuery());
+ sort($queryKeyValues);
+ $uri = $uri->withQuery(implode('&', $queryKeyValues));
+ }
+
+ return $uri;
+ }
+
+ /**
+ * Whether two URIs can be considered equivalent.
+ *
+ * Both URIs are normalized automatically before comparison with the given $normalizations bitmask. The method also
+ * accepts relative URI references and returns true when they are equivalent. This of course assumes they will be
+ * resolved against the same base URI. If this is not the case, determination of equivalence or difference of
+ * relative references does not mean anything.
+ *
+ * @param UriInterface $uri1 An URI to compare
+ * @param UriInterface $uri2 An URI to compare
+ * @param int $normalizations A bitmask of normalizations to apply, see constants
+ *
+ * @return bool
+ * @link https://tools.ietf.org/html/rfc3986#section-6.1
+ */
+ public static function isEquivalent(UriInterface $uri1, UriInterface $uri2, $normalizations = self::PRESERVING_NORMALIZATIONS)
+ {
+ return (string) self::normalize($uri1, $normalizations) === (string) self::normalize($uri2, $normalizations);
+ }
+
+ private static function capitalizePercentEncoding(UriInterface $uri)
+ {
+ $regex = '/(?:%[A-Fa-f0-9]{2})++/';
+
+ $callback = function (array $match) {
+ return strtoupper($match[0]);
+ };
+
+ return
+ $uri->withPath(
+ preg_replace_callback($regex, $callback, $uri->getPath())
+ )->withQuery(
+ preg_replace_callback($regex, $callback, $uri->getQuery())
+ );
+ }
+
+ private static function decodeUnreservedCharacters(UriInterface $uri)
+ {
+ $regex = '/%(?:2D|2E|5F|7E|3[0-9]|[46][1-9A-F]|[57][0-9A])/i';
+
+ $callback = function (array $match) {
+ return rawurldecode($match[0]);
+ };
+
+ return
+ $uri->withPath(
+ preg_replace_callback($regex, $callback, $uri->getPath())
+ )->withQuery(
+ preg_replace_callback($regex, $callback, $uri->getQuery())
+ );
+ }
+
+ private function __construct()
+ {
+ // cannot be instantiated
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/UriResolver.php b/akamai/vendor/guzzlehttp/psr7/src/UriResolver.php
new file mode 100644
index 00000000..c1cb8a27
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/UriResolver.php
@@ -0,0 +1,219 @@
+getScheme() != '') {
+ return $rel->withPath(self::removeDotSegments($rel->getPath()));
+ }
+
+ if ($rel->getAuthority() != '') {
+ $targetAuthority = $rel->getAuthority();
+ $targetPath = self::removeDotSegments($rel->getPath());
+ $targetQuery = $rel->getQuery();
+ } else {
+ $targetAuthority = $base->getAuthority();
+ if ($rel->getPath() === '') {
+ $targetPath = $base->getPath();
+ $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
+ } else {
+ if ($rel->getPath()[0] === '/') {
+ $targetPath = $rel->getPath();
+ } else {
+ if ($targetAuthority != '' && $base->getPath() === '') {
+ $targetPath = '/' . $rel->getPath();
+ } else {
+ $lastSlashPos = strrpos($base->getPath(), '/');
+ if ($lastSlashPos === false) {
+ $targetPath = $rel->getPath();
+ } else {
+ $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
+ }
+ }
+ }
+ $targetPath = self::removeDotSegments($targetPath);
+ $targetQuery = $rel->getQuery();
+ }
+ }
+
+ return new Uri(Uri::composeComponents(
+ $base->getScheme(),
+ $targetAuthority,
+ $targetPath,
+ $targetQuery,
+ $rel->getFragment()
+ ));
+ }
+
+ /**
+ * Returns the target URI as a relative reference from the base URI.
+ *
+ * This method is the counterpart to resolve():
+ *
+ * (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
+ *
+ * One use-case is to use the current request URI as base URI and then generate relative links in your documents
+ * to reduce the document size or offer self-contained downloadable document archives.
+ *
+ * $base = new Uri('http://example.com/a/b/');
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c')); // prints 'c'.
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y')); // prints '../x/y'.
+ * echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
+ * echo UriResolver::relativize($base, new Uri('http://example.org/a/b/')); // prints '//example.org/a/b/'.
+ *
+ * This method also accepts a target that is already relative and will try to relativize it further. Only a
+ * relative-path reference will be returned as-is.
+ *
+ * echo UriResolver::relativize($base, new Uri('/a/b/c')); // prints 'c' as well
+ *
+ * @param UriInterface $base Base URI
+ * @param UriInterface $target Target URI
+ *
+ * @return UriInterface The relative URI reference
+ */
+ public static function relativize(UriInterface $base, UriInterface $target)
+ {
+ if ($target->getScheme() !== '' &&
+ ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
+ ) {
+ return $target;
+ }
+
+ if (Uri::isRelativePathReference($target)) {
+ // As the target is already highly relative we return it as-is. It would be possible to resolve
+ // the target with `$target = self::resolve($base, $target);` and then try make it more relative
+ // by removing a duplicate query. But let's not do that automatically.
+ return $target;
+ }
+
+ if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
+ return $target->withScheme('');
+ }
+
+ // We must remove the path before removing the authority because if the path starts with two slashes, the URI
+ // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
+ // invalid.
+ $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
+
+ if ($base->getPath() !== $target->getPath()) {
+ return $emptyPathUri->withPath(self::getRelativePath($base, $target));
+ }
+
+ if ($base->getQuery() === $target->getQuery()) {
+ // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
+ return $emptyPathUri->withQuery('');
+ }
+
+ // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
+ // inherit the base query component when resolving.
+ if ($target->getQuery() === '') {
+ $segments = explode('/', $target->getPath());
+ $lastSegment = end($segments);
+
+ return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
+ }
+
+ return $emptyPathUri;
+ }
+
+ private static function getRelativePath(UriInterface $base, UriInterface $target)
+ {
+ $sourceSegments = explode('/', $base->getPath());
+ $targetSegments = explode('/', $target->getPath());
+ array_pop($sourceSegments);
+ $targetLastSegment = array_pop($targetSegments);
+ foreach ($sourceSegments as $i => $segment) {
+ if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
+ unset($sourceSegments[$i], $targetSegments[$i]);
+ } else {
+ break;
+ }
+ }
+ $targetSegments[] = $targetLastSegment;
+ $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);
+
+ // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
+ // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
+ // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
+ if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
+ $relativePath = "./$relativePath";
+ } elseif ('/' === $relativePath[0]) {
+ if ($base->getAuthority() != '' && $base->getPath() === '') {
+ // In this case an extra slash is added by resolve() automatically. So we must not add one here.
+ $relativePath = ".$relativePath";
+ } else {
+ $relativePath = "./$relativePath";
+ }
+ }
+
+ return $relativePath;
+ }
+
+ private function __construct()
+ {
+ // cannot be instantiated
+ }
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/functions.php b/akamai/vendor/guzzlehttp/psr7/src/functions.php
new file mode 100644
index 00000000..8e6dafe6
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/functions.php
@@ -0,0 +1,899 @@
+getMethod() . ' '
+ . $message->getRequestTarget())
+ . ' HTTP/' . $message->getProtocolVersion();
+ if (!$message->hasHeader('host')) {
+ $msg .= "\r\nHost: " . $message->getUri()->getHost();
+ }
+ } elseif ($message instanceof ResponseInterface) {
+ $msg = 'HTTP/' . $message->getProtocolVersion() . ' '
+ . $message->getStatusCode() . ' '
+ . $message->getReasonPhrase();
+ } else {
+ throw new \InvalidArgumentException('Unknown message type');
+ }
+
+ foreach ($message->getHeaders() as $name => $values) {
+ $msg .= "\r\n{$name}: " . implode(', ', $values);
+ }
+
+ return "{$msg}\r\n\r\n" . $message->getBody();
+}
+
+/**
+ * Returns a UriInterface for the given value.
+ *
+ * This function accepts a string or {@see Psr\Http\Message\UriInterface} and
+ * returns a UriInterface for the given value. If the value is already a
+ * `UriInterface`, it is returned as-is.
+ *
+ * @param string|UriInterface $uri
+ *
+ * @return UriInterface
+ * @throws \InvalidArgumentException
+ */
+function uri_for($uri)
+{
+ if ($uri instanceof UriInterface) {
+ return $uri;
+ } elseif (is_string($uri)) {
+ return new Uri($uri);
+ }
+
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
+}
+
+/**
+ * Create a new stream based on the input type.
+ *
+ * Options is an associative array that can contain the following keys:
+ * - metadata: Array of custom metadata.
+ * - size: Size of the stream.
+ *
+ * @param resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource Entity body data
+ * @param array $options Additional options
+ *
+ * @return StreamInterface
+ * @throws \InvalidArgumentException if the $resource arg is not valid.
+ */
+function stream_for($resource = '', array $options = [])
+{
+ if (is_scalar($resource)) {
+ $stream = fopen('php://temp', 'r+');
+ if ($resource !== '') {
+ fwrite($stream, $resource);
+ fseek($stream, 0);
+ }
+ return new Stream($stream, $options);
+ }
+
+ switch (gettype($resource)) {
+ case 'resource':
+ return new Stream($resource, $options);
+ case 'object':
+ if ($resource instanceof StreamInterface) {
+ return $resource;
+ } elseif ($resource instanceof \Iterator) {
+ return new PumpStream(function () use ($resource) {
+ if (!$resource->valid()) {
+ return false;
+ }
+ $result = $resource->current();
+ $resource->next();
+ return $result;
+ }, $options);
+ } elseif (method_exists($resource, '__toString')) {
+ return stream_for((string) $resource, $options);
+ }
+ break;
+ case 'NULL':
+ return new Stream(fopen('php://temp', 'r+'), $options);
+ }
+
+ if (is_callable($resource)) {
+ return new PumpStream($resource, $options);
+ }
+
+ throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
+}
+
+/**
+ * Parse an array of header values containing ";" separated data into an
+ * array of associative arrays representing the header key value pair
+ * data of the header. When a parameter does not contain a value, but just
+ * contains a key, this function will inject a key with a '' string value.
+ *
+ * @param string|array $header Header to parse into components.
+ *
+ * @return array Returns the parsed header values.
+ */
+function parse_header($header)
+{
+ static $trimmed = "\"' \n\t\r";
+ $params = $matches = [];
+
+ foreach (normalize_header($header) as $val) {
+ $part = [];
+ foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
+ if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
+ $m = $matches[0];
+ if (isset($m[1])) {
+ $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
+ } else {
+ $part[] = trim($m[0], $trimmed);
+ }
+ }
+ }
+ if ($part) {
+ $params[] = $part;
+ }
+ }
+
+ return $params;
+}
+
+/**
+ * Converts an array of header values that may contain comma separated
+ * headers into an array of headers with no comma separated values.
+ *
+ * @param string|array $header Header to normalize.
+ *
+ * @return array Returns the normalized header field values.
+ */
+function normalize_header($header)
+{
+ if (!is_array($header)) {
+ return array_map('trim', explode(',', $header));
+ }
+
+ $result = [];
+ foreach ($header as $value) {
+ foreach ((array) $value as $v) {
+ if (strpos($v, ',') === false) {
+ $result[] = $v;
+ continue;
+ }
+ foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
+ $result[] = trim($vv);
+ }
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Clone and modify a request with the given changes.
+ *
+ * The changes can be one of:
+ * - method: (string) Changes the HTTP method.
+ * - set_headers: (array) Sets the given headers.
+ * - remove_headers: (array) Remove the given headers.
+ * - body: (mixed) Sets the given body.
+ * - uri: (UriInterface) Set the URI.
+ * - query: (string) Set the query string value of the URI.
+ * - version: (string) Set the protocol version.
+ *
+ * @param RequestInterface $request Request to clone and modify.
+ * @param array $changes Changes to apply.
+ *
+ * @return RequestInterface
+ */
+function modify_request(RequestInterface $request, array $changes)
+{
+ if (!$changes) {
+ return $request;
+ }
+
+ $headers = $request->getHeaders();
+
+ if (!isset($changes['uri'])) {
+ $uri = $request->getUri();
+ } else {
+ // Remove the host header if one is on the URI
+ if ($host = $changes['uri']->getHost()) {
+ $changes['set_headers']['Host'] = $host;
+
+ if ($port = $changes['uri']->getPort()) {
+ $standardPorts = ['http' => 80, 'https' => 443];
+ $scheme = $changes['uri']->getScheme();
+ if (isset($standardPorts[$scheme]) && $port != $standardPorts[$scheme]) {
+ $changes['set_headers']['Host'] .= ':'.$port;
+ }
+ }
+ }
+ $uri = $changes['uri'];
+ }
+
+ if (!empty($changes['remove_headers'])) {
+ $headers = _caseless_remove($changes['remove_headers'], $headers);
+ }
+
+ if (!empty($changes['set_headers'])) {
+ $headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
+ $headers = $changes['set_headers'] + $headers;
+ }
+
+ if (isset($changes['query'])) {
+ $uri = $uri->withQuery($changes['query']);
+ }
+
+ if ($request instanceof ServerRequestInterface) {
+ return (new ServerRequest(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion(),
+ $request->getServerParams()
+ ))
+ ->withParsedBody($request->getParsedBody())
+ ->withQueryParams($request->getQueryParams())
+ ->withCookieParams($request->getCookieParams())
+ ->withUploadedFiles($request->getUploadedFiles());
+ }
+
+ return new Request(
+ isset($changes['method']) ? $changes['method'] : $request->getMethod(),
+ $uri,
+ $headers,
+ isset($changes['body']) ? $changes['body'] : $request->getBody(),
+ isset($changes['version'])
+ ? $changes['version']
+ : $request->getProtocolVersion()
+ );
+}
+
+/**
+ * Attempts to rewind a message body and throws an exception on failure.
+ *
+ * The body of the message will only be rewound if a call to `tell()` returns a
+ * value other than `0`.
+ *
+ * @param MessageInterface $message Message to rewind
+ *
+ * @throws \RuntimeException
+ */
+function rewind_body(MessageInterface $message)
+{
+ $body = $message->getBody();
+
+ if ($body->tell()) {
+ $body->rewind();
+ }
+}
+
+/**
+ * Safely opens a PHP stream resource using a filename.
+ *
+ * When fopen fails, PHP normally raises a warning. This function adds an
+ * error handler that checks for errors and throws an exception instead.
+ *
+ * @param string $filename File to open
+ * @param string $mode Mode used to open the file
+ *
+ * @return resource
+ * @throws \RuntimeException if the file cannot be opened
+ */
+function try_fopen($filename, $mode)
+{
+ $ex = null;
+ set_error_handler(function () use ($filename, $mode, &$ex) {
+ $ex = new \RuntimeException(sprintf(
+ 'Unable to open %s using mode %s: %s',
+ $filename,
+ $mode,
+ func_get_args()[1]
+ ));
+ });
+
+ $handle = fopen($filename, $mode);
+ restore_error_handler();
+
+ if ($ex) {
+ /** @var $ex \RuntimeException */
+ throw $ex;
+ }
+
+ return $handle;
+}
+
+/**
+ * Copy the contents of a stream into a string until the given number of
+ * bytes have been read.
+ *
+ * @param StreamInterface $stream Stream to read
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ * @return string
+ * @throws \RuntimeException on error.
+ */
+function copy_to_string(StreamInterface $stream, $maxLen = -1)
+{
+ $buffer = '';
+
+ if ($maxLen === -1) {
+ while (!$stream->eof()) {
+ $buf = $stream->read(1048576);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ }
+ return $buffer;
+ }
+
+ $len = 0;
+ while (!$stream->eof() && $len < $maxLen) {
+ $buf = $stream->read($maxLen - $len);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+ $buffer .= $buf;
+ $len = strlen($buffer);
+ }
+
+ return $buffer;
+}
+
+/**
+ * Copy the contents of a stream into another stream until the given number
+ * of bytes have been read.
+ *
+ * @param StreamInterface $source Stream to read from
+ * @param StreamInterface $dest Stream to write to
+ * @param int $maxLen Maximum number of bytes to read. Pass -1
+ * to read the entire stream.
+ *
+ * @throws \RuntimeException on error.
+ */
+function copy_to_stream(
+ StreamInterface $source,
+ StreamInterface $dest,
+ $maxLen = -1
+) {
+ $bufferSize = 8192;
+
+ if ($maxLen === -1) {
+ while (!$source->eof()) {
+ if (!$dest->write($source->read($bufferSize))) {
+ break;
+ }
+ }
+ } else {
+ $remaining = $maxLen;
+ while ($remaining > 0 && !$source->eof()) {
+ $buf = $source->read(min($bufferSize, $remaining));
+ $len = strlen($buf);
+ if (!$len) {
+ break;
+ }
+ $remaining -= $len;
+ $dest->write($buf);
+ }
+ }
+}
+
+/**
+ * Calculate a hash of a Stream
+ *
+ * @param StreamInterface $stream Stream to calculate the hash for
+ * @param string $algo Hash algorithm (e.g. md5, crc32, etc)
+ * @param bool $rawOutput Whether or not to use raw output
+ *
+ * @return string Returns the hash of the stream
+ * @throws \RuntimeException on error.
+ */
+function hash(
+ StreamInterface $stream,
+ $algo,
+ $rawOutput = false
+) {
+ $pos = $stream->tell();
+
+ if ($pos > 0) {
+ $stream->rewind();
+ }
+
+ $ctx = hash_init($algo);
+ while (!$stream->eof()) {
+ hash_update($ctx, $stream->read(1048576));
+ }
+
+ $out = hash_final($ctx, (bool) $rawOutput);
+ $stream->seek($pos);
+
+ return $out;
+}
+
+/**
+ * Read a line from the stream up to the maximum allowed buffer length
+ *
+ * @param StreamInterface $stream Stream to read from
+ * @param int $maxLength Maximum buffer length
+ *
+ * @return string
+ */
+function readline(StreamInterface $stream, $maxLength = null)
+{
+ $buffer = '';
+ $size = 0;
+
+ while (!$stream->eof()) {
+ // Using a loose equality here to match on '' and false.
+ if (null == ($byte = $stream->read(1))) {
+ return $buffer;
+ }
+ $buffer .= $byte;
+ // Break when a new line is found or the max length - 1 is reached
+ if ($byte === "\n" || ++$size === $maxLength - 1) {
+ break;
+ }
+ }
+
+ return $buffer;
+}
+
+/**
+ * Parses a request message string into a request object.
+ *
+ * @param string $message Request message string.
+ *
+ * @return Request
+ */
+function parse_request($message)
+{
+ $data = _parse_message($message);
+ $matches = [];
+ if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
+ throw new \InvalidArgumentException('Invalid request string');
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+ $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
+
+ $request = new Request(
+ $parts[0],
+ $matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1],
+ $data['headers'],
+ $data['body'],
+ $version
+ );
+
+ return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
+}
+
+/**
+ * Parses a response message string into a response object.
+ *
+ * @param string $message Response message string.
+ *
+ * @return Response
+ */
+function parse_response($message)
+{
+ $data = _parse_message($message);
+ // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space
+ // between status-code and reason-phrase is required. But browsers accept
+ // responses without space and reason as well.
+ if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
+ throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']);
+ }
+ $parts = explode(' ', $data['start-line'], 3);
+
+ return new Response(
+ $parts[1],
+ $data['headers'],
+ $data['body'],
+ explode('/', $parts[0])[1],
+ isset($parts[2]) ? $parts[2] : null
+ );
+}
+
+/**
+ * Parse a query string into an associative array.
+ *
+ * If multiple values are found for the same key, the value of that key
+ * value pair will become an array. This function does not parse nested
+ * PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
+ * be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
+ *
+ * @param string $str Query string to parse
+ * @param int|bool $urlEncoding How the query string is encoded
+ *
+ * @return array
+ */
+function parse_query($str, $urlEncoding = true)
+{
+ $result = [];
+
+ if ($str === '') {
+ return $result;
+ }
+
+ if ($urlEncoding === true) {
+ $decoder = function ($value) {
+ return rawurldecode(str_replace('+', ' ', $value));
+ };
+ } elseif ($urlEncoding === PHP_QUERY_RFC3986) {
+ $decoder = 'rawurldecode';
+ } elseif ($urlEncoding === PHP_QUERY_RFC1738) {
+ $decoder = 'urldecode';
+ } else {
+ $decoder = function ($str) { return $str; };
+ }
+
+ foreach (explode('&', $str) as $kvp) {
+ $parts = explode('=', $kvp, 2);
+ $key = $decoder($parts[0]);
+ $value = isset($parts[1]) ? $decoder($parts[1]) : null;
+ if (!isset($result[$key])) {
+ $result[$key] = $value;
+ } else {
+ if (!is_array($result[$key])) {
+ $result[$key] = [$result[$key]];
+ }
+ $result[$key][] = $value;
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * Build a query string from an array of key value pairs.
+ *
+ * This function can use the return value of parse_query() to build a query
+ * string. This function does not modify the provided keys when an array is
+ * encountered (like http_build_query would).
+ *
+ * @param array $params Query string parameters.
+ * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
+ * to encode using RFC3986, or PHP_QUERY_RFC1738
+ * to encode using RFC1738.
+ * @return string
+ */
+function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
+{
+ if (!$params) {
+ return '';
+ }
+
+ if ($encoding === false) {
+ $encoder = function ($str) { return $str; };
+ } elseif ($encoding === PHP_QUERY_RFC3986) {
+ $encoder = 'rawurlencode';
+ } elseif ($encoding === PHP_QUERY_RFC1738) {
+ $encoder = 'urlencode';
+ } else {
+ throw new \InvalidArgumentException('Invalid type');
+ }
+
+ $qs = '';
+ foreach ($params as $k => $v) {
+ $k = $encoder($k);
+ if (!is_array($v)) {
+ $qs .= $k;
+ if ($v !== null) {
+ $qs .= '=' . $encoder($v);
+ }
+ $qs .= '&';
+ } else {
+ foreach ($v as $vv) {
+ $qs .= $k;
+ if ($vv !== null) {
+ $qs .= '=' . $encoder($vv);
+ }
+ $qs .= '&';
+ }
+ }
+ }
+
+ return $qs ? (string) substr($qs, 0, -1) : '';
+}
+
+/**
+ * Determines the mimetype of a file by looking at its extension.
+ *
+ * @param $filename
+ *
+ * @return null|string
+ */
+function mimetype_from_filename($filename)
+{
+ return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
+}
+
+/**
+ * Maps a file extensions to a mimetype.
+ *
+ * @param $extension string The file extension.
+ *
+ * @return string|null
+ * @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
+ */
+function mimetype_from_extension($extension)
+{
+ static $mimetypes = [
+ '3gp' => 'video/3gpp',
+ '7z' => 'application/x-7z-compressed',
+ 'aac' => 'audio/x-aac',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'asc' => 'text/plain',
+ 'asf' => 'video/x-ms-asf',
+ 'atom' => 'application/atom+xml',
+ 'avi' => 'video/x-msvideo',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bzip2',
+ 'cer' => 'application/pkix-cert',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'css' => 'text/css',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'deb' => 'application/x-debian-package',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dvi' => 'application/x-dvi',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'etx' => 'text/x-setext',
+ 'flac' => 'audio/flac',
+ 'flv' => 'video/x-flv',
+ 'gif' => 'image/gif',
+ 'gz' => 'application/gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ini' => 'text/plain',
+ 'iso' => 'application/x-iso9660-image',
+ 'jar' => 'application/java-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'js' => 'text/javascript',
+ 'json' => 'application/json',
+ 'latex' => 'application/x-latex',
+ 'log' => 'text/plain',
+ 'm4a' => 'audio/mp4',
+ 'm4v' => 'video/mp4',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mkv' => 'video/x-matroska',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pdf' => 'application/pdf',
+ 'pgm' => 'image/x-portable-graymap',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'ps' => 'application/postscript',
+ 'qt' => 'video/quicktime',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'svg' => 'image/svg+xml',
+ 'swf' => 'application/x-shockwave-flash',
+ 'tar' => 'application/x-tar',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'torrent' => 'application/x-bittorrent',
+ 'ttf' => 'application/x-font-ttf',
+ 'txt' => 'text/plain',
+ 'wav' => 'audio/x-wav',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmv' => 'video/x-ms-wmv',
+ 'woff' => 'application/x-font-woff',
+ 'wsdl' => 'application/wsdl+xml',
+ 'xbm' => 'image/x-xbitmap',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xml' => 'application/xml',
+ 'xpm' => 'image/x-xpixmap',
+ 'xwd' => 'image/x-xwindowdump',
+ 'yaml' => 'text/yaml',
+ 'yml' => 'text/yaml',
+ 'zip' => 'application/zip',
+ ];
+
+ $extension = strtolower($extension);
+
+ return isset($mimetypes[$extension])
+ ? $mimetypes[$extension]
+ : null;
+}
+
+/**
+ * Parses an HTTP message into an associative array.
+ *
+ * The array contains the "start-line" key containing the start line of
+ * the message, "headers" key containing an associative array of header
+ * array values, and a "body" key containing the body of the message.
+ *
+ * @param string $message HTTP request or response to parse.
+ *
+ * @return array
+ * @internal
+ */
+function _parse_message($message)
+{
+ if (!$message) {
+ throw new \InvalidArgumentException('Invalid message');
+ }
+
+ $message = ltrim($message, "\r\n");
+
+ $messageParts = preg_split("/\r?\n\r?\n/", $message, 2);
+
+ if ($messageParts === false || count($messageParts) !== 2) {
+ throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
+ }
+
+ list($rawHeaders, $body) = $messageParts;
+ $rawHeaders .= "\r\n"; // Put back the delimiter we split previously
+ $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);
+
+ if ($headerParts === false || count($headerParts) !== 2) {
+ throw new \InvalidArgumentException('Invalid message: Missing status line');
+ }
+
+ list($startLine, $rawHeaders) = $headerParts;
+
+ if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
+ // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
+ $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
+ }
+
+ /** @var array[] $headerLines */
+ $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);
+
+ // If these aren't the same, then one line didn't match and there's an invalid header.
+ if ($count !== substr_count($rawHeaders, "\n")) {
+ // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4
+ if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
+ throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
+ }
+
+ throw new \InvalidArgumentException('Invalid header syntax');
+ }
+
+ $headers = [];
+
+ foreach ($headerLines as $headerLine) {
+ $headers[$headerLine[1]][] = $headerLine[2];
+ }
+
+ return [
+ 'start-line' => $startLine,
+ 'headers' => $headers,
+ 'body' => $body,
+ ];
+}
+
+/**
+ * Constructs a URI for an HTTP request message.
+ *
+ * @param string $path Path from the start-line
+ * @param array $headers Array of headers (each value an array).
+ *
+ * @return string
+ * @internal
+ */
+function _parse_request_uri($path, array $headers)
+{
+ $hostKey = array_filter(array_keys($headers), function ($k) {
+ return strtolower($k) === 'host';
+ });
+
+ // If no host is found, then a full URI cannot be constructed.
+ if (!$hostKey) {
+ return $path;
+ }
+
+ $host = $headers[reset($hostKey)][0];
+ $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
+
+ return $scheme . '://' . $host . '/' . ltrim($path, '/');
+}
+
+/**
+ * Get a short summary of the message body
+ *
+ * Will return `null` if the response is not printable.
+ *
+ * @param MessageInterface $message The message to get the body summary
+ * @param int $truncateAt The maximum allowed size of the summary
+ *
+ * @return null|string
+ */
+function get_message_body_summary(MessageInterface $message, $truncateAt = 120)
+{
+ $body = $message->getBody();
+
+ if (!$body->isSeekable() || !$body->isReadable()) {
+ return null;
+ }
+
+ $size = $body->getSize();
+
+ if ($size === 0) {
+ return null;
+ }
+
+ $summary = $body->read($truncateAt);
+ $body->rewind();
+
+ if ($size > $truncateAt) {
+ $summary .= ' (truncated...)';
+ }
+
+ // Matches any printable character, including unicode characters:
+ // letters, marks, numbers, punctuation, spacing, and separators.
+ if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
+ return null;
+ }
+
+ return $summary;
+}
+
+/** @internal */
+function _caseless_remove($keys, array $data)
+{
+ $result = [];
+
+ foreach ($keys as &$key) {
+ $key = strtolower($key);
+ }
+
+ foreach ($data as $k => $v) {
+ if (!in_array(strtolower($k), $keys)) {
+ $result[$k] = $v;
+ }
+ }
+
+ return $result;
+}
diff --git a/akamai/vendor/guzzlehttp/psr7/src/functions_include.php b/akamai/vendor/guzzlehttp/psr7/src/functions_include.php
new file mode 100644
index 00000000..96a4a83a
--- /dev/null
+++ b/akamai/vendor/guzzlehttp/psr7/src/functions_include.php
@@ -0,0 +1,6 @@
+
+
+[](https://github.com/thephpleague/climate/tags)
+[](LICENSE.md)
+[](https://travis-ci.org/thephpleague/climate)
+[](https://scrutinizer-ci.com/g/thephpleague/climate/code-structure)
+[](https://scrutinizer-ci.com/g/thephpleague/climate)
+[](https://packagist.org/packages/league/climate)
+
+Running PHP from the command line? CLImate is your new best bud.
+
+CLImate allows you to easily output colored text, special formats, and more.
+
+
+## Installation
+Using [composer](https://packagist.org/packages/league/climate):
+```bash
+$ composer require league/climate
+```
+
+
+## Quick Example
+```php
+require_once __DIR__ . "vendor/autoload.php";
+
+$climate = new \League\CLImate\CLImate;
+
+$climate->red('Whoa now this text is red.');
+$climate->blue('Blue? Wow!');
+```
+
+_Read more at https://climate.thephpleague.com/_
+
+
+## Credits
+
+This library was created by [Joe Tannenbaum](https://joe.codes/).
+Much love to [Damian Makki](https://dribbble.com/damianmakki) for the logo.
diff --git a/akamai/vendor/league/climate/composer.json b/akamai/vendor/league/climate/composer.json
new file mode 100644
index 00000000..3f455396
--- /dev/null
+++ b/akamai/vendor/league/climate/composer.json
@@ -0,0 +1,45 @@
+{
+ "name": "league/climate",
+ "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.",
+ "keywords": ["cli","php", "terminal", "command", "colors"],
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Joe Tannenbaum",
+ "email": "hey@joe.codes",
+ "homepage": "http://joe.codes/",
+ "role": "Developer"
+ }, {
+ "name": "Craig Duncan",
+ "email": "git@duncanc.co.uk",
+ "homepage": "https://github.com/duncan3dc",
+ "role": "Developer"
+ }
+ ],
+ "require": {
+ "psr/log": "^1.0",
+ "php": "^5.6|^7.0",
+ "seld/cli-prompt": "^1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7.16",
+ "mockery/mockery": "^1.0",
+ "mikey179/vfsStream": "^1.4"
+ },
+ "suggest": {
+ "ext-mbstring": "If ext-mbstring is not available you MUST install symfony/polyfill-mbstring"
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\CLImate\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "League\\CLImate\\Tests\\": "tests/"
+ }
+ },
+ "scripts": {
+ "test": "phpunit"
+ }
+}
diff --git a/akamai/vendor/league/climate/src/ASCII/404.txt b/akamai/vendor/league/climate/src/ASCII/404.txt
new file mode 100644
index 00000000..25cd0672
--- /dev/null
+++ b/akamai/vendor/league/climate/src/ASCII/404.txt
@@ -0,0 +1,6 @@
+ _ _ ___ _ _
+ | || | / _ \| || |
+ | || |_| | | | || |_
+ |__ _| | | |__ _|
+ | | | |_| | | |
+ |_| \___/ |_|
\ No newline at end of file
diff --git a/akamai/vendor/league/climate/src/ASCII/bender.txt b/akamai/vendor/league/climate/src/ASCII/bender.txt
new file mode 100644
index 00000000..760c3e32
--- /dev/null
+++ b/akamai/vendor/league/climate/src/ASCII/bender.txt
@@ -0,0 +1,17 @@
+ ( )
+ H
+ H
+ _H_
+ .-'-.-'-.
+ / \
+| |
+| .-------'._
+| / / '.' '. \
+| \ \ @ @ / /
+| '---------'
+| _______|
+| .'-+-+-+|
+| '.-+-+-+|
+| """""" |
+'-.__ __.-'
+ """
\ No newline at end of file
diff --git a/akamai/vendor/league/climate/src/ASCII/failed.txt b/akamai/vendor/league/climate/src/ASCII/failed.txt
new file mode 100644
index 00000000..19187b60
--- /dev/null
+++ b/akamai/vendor/league/climate/src/ASCII/failed.txt
@@ -0,0 +1,6 @@
+ ______ _____ _ ______ _____
+ | ____/\ |_ _| | | ____| __ \
+ | |__ / \ | | | | | |__ | | | |
+ | __/ /\ \ | | | | | __| | | | |
+ | | / ____ \ _| |_| |____| |____| |__| |
+ |_|/_/ \_\_____|______|______|_____/
\ No newline at end of file
diff --git a/akamai/vendor/league/climate/src/ASCII/fancy-bender.txt b/akamai/vendor/league/climate/src/ASCII/fancy-bender.txt
new file mode 100644
index 00000000..b8e7f8aa
--- /dev/null
+++ b/akamai/vendor/league/climate/src/ASCII/fancy-bender.txt
@@ -0,0 +1,17 @@
+ ( )
+ H
+ H
+ _H_
+ .-'-.-'-.
+ / \
+| |
+| .-------'._
+| // '.' '. \
+| \\ / /
+| '---------'
+| _______|
+| .'-+-+-+|
+| '.-+-+-+|
+| """""" |
+'-.__ __.-'
+ """
\ No newline at end of file
diff --git a/akamai/vendor/league/climate/src/ASCII/passed.txt b/akamai/vendor/league/climate/src/ASCII/passed.txt
new file mode 100644
index 00000000..0cbc03be
--- /dev/null
+++ b/akamai/vendor/league/climate/src/ASCII/passed.txt
@@ -0,0 +1,6 @@
+ _____ _____ _____ ______ _____
+ | __ \ /\ / ____/ ____| ____| __ \
+ | |__) / \ | (___| (___ | |__ | | | |
+ | ___/ /\ \ \___ \\___ \| __| | | | |
+ | | / ____ \ ____) |___) | |____| |__| |
+ |_| /_/ \_\_____/_____/|______|_____/
\ No newline at end of file
diff --git a/akamai/vendor/league/climate/src/Argument/Argument.php b/akamai/vendor/league/climate/src/Argument/Argument.php
new file mode 100644
index 00000000..fd34ad20
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Argument/Argument.php
@@ -0,0 +1,384 @@
+setName($name);
+ }
+
+ /**
+ * Build a new command argument from an array.
+ *
+ * @param string $name
+ * @param array $params
+ *
+ * @return Argument
+ */
+ public static function createFromArray($name, array $params)
+ {
+ $argument = new Argument($name);
+ $params = self::getSettableArgumentParams($params);
+
+ foreach ($params as $key => $value) {
+ $method = 'set' . ucwords($key);
+ $argument->{$method}($value);
+ }
+
+ if ($argument->defaultValue()) {
+ $argument->setValue($argument->defaultValue());
+ }
+
+ return $argument;
+ }
+
+ /**
+ * Get argument params based on settable properties
+ *
+ * @param array $params
+ *
+ * @return array
+ */
+ protected static function getSettableArgumentParams(array $params)
+ {
+ $allowed = [
+ 'prefix',
+ 'longPrefix',
+ 'description',
+ 'required',
+ 'noValue',
+ 'castTo',
+ 'defaultValue',
+ ];
+
+ return array_intersect_key($params, array_flip($allowed));
+ }
+
+ /**
+ * Retrieve an argument's name.
+ *
+ * Use this name when internally referring to the argument.
+ *
+ * @return string
+ */
+ public function name()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Set an argument's name.
+ *
+ * Use this name when internally referring to the argument.
+ *
+ * @param string $name
+ */
+ protected function setName($name)
+ {
+ $this->name = trim($name);
+ }
+
+ /**
+ * Retrieve an argument's short form.
+ *
+ * @return string
+ */
+ public function prefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * Set an argument's short form.
+ *
+ * @param string $prefix
+ */
+ protected function setPrefix($prefix)
+ {
+ $this->prefix = trim($prefix);
+ }
+
+ /**
+ * Retrieve an argument's long form.
+ *
+ * @return string
+ */
+ public function longPrefix()
+ {
+ return $this->longPrefix;
+ }
+
+ /**
+ * Set an argument's short form.
+ *
+ * @param string $longPrefix
+ */
+ protected function setLongPrefix($longPrefix)
+ {
+ $this->longPrefix = trim($longPrefix);
+ }
+
+ /**
+ * Determine if an argument has a prefix.
+ *
+ * @return bool
+ */
+ public function hasPrefix()
+ {
+ return $this->prefix() || $this->longPrefix();
+ }
+
+ /**
+ * Retrieve an argument's description.
+ *
+ * @return string
+ */
+ public function description()
+ {
+ return $this->description;
+ }
+
+ /**
+ * Set an argument's description.
+ *
+ * @param string $description
+ */
+ protected function setDescription($description)
+ {
+ $this->description = trim($description);
+ }
+
+ /**
+ * Determine whether or not an argument is required.
+ *
+ * @return bool
+ */
+ public function isRequired()
+ {
+ return $this->required;
+ }
+
+ /**
+ * Set whether an argument is required or not.
+ *
+ * @param bool $required
+ */
+ protected function setRequired($required)
+ {
+ $this->required = (bool) $required;
+ }
+
+ /**
+ * Determine whether or not an argument only needs to be defined to have a
+ * value.
+ *
+ * @return bool
+ */
+ public function noValue()
+ {
+ return $this->noValue;
+ }
+
+ /**
+ * Set whether or not an argument only needs to be defined to have a value.
+ *
+ * @param bool $noValue
+ */
+ protected function setNoValue($noValue)
+ {
+ $this->setCastTo('bool');
+ $this->noValue = (bool) $noValue;
+ }
+
+ /**
+ * Retrieve the data type to cast an argument's value to.
+ *
+ * @return string
+ */
+ public function castTo()
+ {
+ return $this->castTo;
+ }
+
+ /**
+ * Set the data type to cast an argument's value to.
+ *
+ * Valid data types are "string", "int", "float", and "bool".
+ *
+ * @throws \Exception if $castTo is not a valid data type.
+ * @param string $castTo
+ */
+ protected function setCastTo($castTo)
+ {
+ if (!in_array($castTo, ['string', 'int', 'float', 'bool'])) {
+ throw new \Exception(
+ "An argument may only be cast to the data type "
+ . "'string', 'int', 'float', or 'bool'."
+ );
+ }
+
+ $this->castTo = $this->noValue() ? 'bool' : $castTo;
+ }
+
+ /**
+ * Retrieve an argument's default value.
+ *
+ * @return string
+ */
+ public function defaultValue()
+ {
+ return $this->defaultValue;
+ }
+
+ /**
+ * Set an argument's default value.
+ *
+ * @param string $defaultValue
+ */
+ public function setDefaultValue($defaultValue)
+ {
+ $this->defaultValue = $defaultValue;
+ }
+
+ /**
+ * Retrieve an argument's value.
+ *
+ * Argument values are type cast based on the value of $castTo.
+ *
+ * @return string|int|float|bool
+ */
+ public function value()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Set an argument's value based on its command line entry.
+ *
+ * Argument values are type cast based on the value of $castTo.
+ *
+ * @param string|bool $value
+ */
+ public function setValue($value)
+ {
+ $cast_method = 'castTo' . ucwords($this->castTo);
+ $this->value = $this->{$cast_method}($value);
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return string
+ */
+ protected function castToString($value)
+ {
+ return (string) $value;
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return int
+ */
+ protected function castToInt($value)
+ {
+ return (int) $value;
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return float
+ */
+ protected function castToFloat($value)
+ {
+ return (float) $value;
+ }
+
+ /**
+ * @param string $value
+ *
+ * @return bool
+ */
+ protected function castToBool($value)
+ {
+ return (bool) $value;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Argument/Filter.php b/akamai/vendor/league/climate/src/Argument/Filter.php
new file mode 100644
index 00000000..9b10e98f
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Argument/Filter.php
@@ -0,0 +1,183 @@
+arguments = $arguments;
+ }
+
+ /**
+ * Retrieve optional arguments
+ *
+ * @return Argument[]
+ */
+ public function optional()
+ {
+ return $this->filterArguments(['isOptional']);
+ }
+
+ /**
+ * Retrieve required arguments
+ *
+ * @return Argument[]
+ */
+ public function required()
+ {
+ return $this->filterArguments(['isRequired']);
+ }
+
+ /**
+ * Retrieve arguments with prefix
+ *
+ * @return Argument[]
+ */
+ public function withPrefix()
+ {
+ return $this->filterArguments(['hasPrefix']);
+ }
+
+ /**
+ * Retrieve arguments without prefix
+ *
+ * @return Argument[]
+ */
+ public function withoutPrefix()
+ {
+ return $this->filterArguments(['noPrefix']);
+ }
+
+ /**
+ * Find all required arguments that don't have values after parsing.
+ *
+ * These arguments weren't defined on the command line.
+ *
+ * @return Argument[]
+ */
+ public function missing()
+ {
+ return $this->filterArguments(['isRequired', 'noValue']);
+ }
+
+ /**
+ * Filter defined arguments as to whether they are required or not
+ *
+ * @param string[] $filters
+ *
+ * @return Argument[]
+ */
+ protected function filterArguments($filters = [])
+ {
+ $arguments = $this->arguments;
+
+ foreach ($filters as $filter) {
+ $arguments = array_filter($arguments, [$this, $filter]);
+ }
+
+ if (in_array('hasPrefix', $filters)) {
+ usort($arguments, [$this, 'compareByPrefix']);
+ }
+
+ return array_values($arguments);
+ }
+
+ /**
+ * Determine whether an argument as a prefix
+ *
+ * @param Argument $argument
+ *
+ * @return bool
+ */
+ protected function noPrefix($argument)
+ {
+ return !$argument->hasPrefix();
+ }
+
+ /**
+ * Determine whether an argument as a prefix
+ *
+ * @param Argument $argument
+ *
+ * @return bool
+ */
+ protected function hasPrefix($argument)
+ {
+ return $argument->hasPrefix();
+ }
+
+ /**
+ * Determine whether an argument is required
+ *
+ * @param Argument $argument
+ *
+ * @return bool
+ */
+ protected function isRequired($argument)
+ {
+ return $argument->isRequired();
+ }
+
+ /**
+ * Determine whether an argument is optional
+ *
+ * @param Argument $argument
+ *
+ * @return bool
+ */
+ protected function isOptional($argument)
+ {
+ return !$argument->isRequired();
+ }
+
+ /**
+ * Determine whether an argument is optional
+ *
+ * @param Argument $argument
+ *
+ * @return bool
+ */
+ protected function noValue($argument)
+ {
+ return is_null($argument->value());
+ }
+
+ /**
+ * Compare two arguments by their short and long prefixes.
+ *
+ * @see usort()
+ *
+ * @param Argument $a
+ * @param Argument $b
+ *
+ * @return int
+ */
+ public function compareByPrefix(Argument $a, Argument $b)
+ {
+ if ($this->prefixCompareString($a) < $this->prefixCompareString($b)) {
+ return -1;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Prep the prefix string for comparison
+ *
+ * @param Argument $argument
+ *
+ * @return string
+ */
+ protected function prefixCompareString(Argument $argument)
+ {
+ return mb_strtolower($argument->longPrefix() ?: $argument->prefix() ?: '');
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Argument/Manager.php b/akamai/vendor/league/climate/src/Argument/Manager.php
new file mode 100644
index 00000000..c6f354d9
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Argument/Manager.php
@@ -0,0 +1,238 @@
+filter = new Filter();
+ $this->summary = new Summary();
+ $this->parser = new Parser();
+ }
+
+ /**
+ * Add an argument.
+ *
+ * @throws \Exception if $argument isn't an array or Argument object.
+ * @param Argument|string|array $argument
+ * @param $options
+ */
+ public function add($argument, array $options = [])
+ {
+ if (is_array($argument)) {
+ $this->addMany($argument);
+ return;
+ }
+
+ if (is_string($argument)) {
+ $argument = Argument::createFromArray($argument, $options);
+ }
+
+ if (!($argument instanceof Argument)) {
+ throw new \Exception('Please provide an argument name or object.');
+ }
+
+ $this->arguments[$argument->name()] = $argument;
+ }
+
+ /**
+ * Add multiple arguments to a CLImate script.
+ *
+ * @param array $arguments
+ */
+ protected function addMany(array $arguments = [])
+ {
+ foreach ($arguments as $name => $options) {
+ $this->add($name, $options);
+ }
+ }
+
+ /**
+ * Determine if an argument exists.
+ *
+ * @param string $name
+ * @return bool
+ */
+ public function exists($name)
+ {
+ return isset($this->arguments[$name]);
+ }
+
+ /**
+ * Retrieve an argument's value.
+ *
+ * @param string $name
+ * @return string|int|float|bool|null
+ */
+ public function get($name)
+ {
+ return isset($this->arguments[$name]) ? $this->arguments[$name]->value() : null;
+ }
+
+ /**
+ * Retrieve all arguments.
+ *
+ * @return Argument[]
+ */
+ public function all()
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * Determine if an argument has been defined on the command line.
+ *
+ * This can be useful for making sure an argument is present on the command
+ * line before parse()'ing them into argument objects.
+ *
+ * @param string $name
+ * @param array $argv
+ *
+ * @return bool
+ */
+ public function defined($name, array $argv = null)
+ {
+ // The argument isn't defined if it's not defined by the calling code.
+ if (!$this->exists($name)) {
+ return false;
+ }
+
+ $argument = $this->arguments[$name];
+ $command_arguments = $this->parser->arguments($argv);
+
+ foreach ($command_arguments as $command_argument) {
+ if ($this->isArgument($argument, $command_argument)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if the defined argument matches the command argument.
+ *
+ * @param Argument $argument
+ * @param string $command_argument
+ *
+ * @return bool
+ */
+ protected function isArgument($argument, $command_argument)
+ {
+ $possibilities = [
+ $argument->prefix() => "-{$argument->prefix()}",
+ $argument->longPrefix() => "--{$argument->longPrefix()}",
+ ];
+
+ foreach ($possibilities as $key => $search) {
+ if ($key && strpos($command_argument, $search) === 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Retrieve all arguments as key/value pairs.
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $return = [];
+
+ foreach ($this->all() as $name => $argument) {
+ $return[$name] = $argument->value();
+ }
+
+ return $return;
+ }
+
+ /**
+ * Set a program's description.
+ *
+ * @param string $description
+ */
+ public function description($description)
+ {
+ $this->description = trim($description);
+ }
+
+ /**
+ * Output a script's usage statement.
+ *
+ * @param CLImate $climate
+ * @param array $argv
+ */
+ public function usage(CLImate $climate, array $argv = null)
+ {
+ $this->summary
+ ->setClimate($climate)
+ ->setDescription($this->description)
+ ->setCommand($this->parser->command($argv))
+ ->setFilter($this->filter, $this->all())
+ ->output();
+ }
+
+ /**
+ * Parse command line arguments into CLImate arguments.
+ *
+ * @throws \Exception if required arguments aren't defined.
+ * @param array $argv
+ */
+ public function parse(array $argv = null)
+ {
+ $this->parser->setFilter($this->filter, $this->all());
+
+ $this->parser->parse($argv);
+ }
+
+ /**
+ * Get the trailing arguments
+ *
+ * @return string|null
+ */
+ public function trailing()
+ {
+ return $this->parser->trailing();
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Argument/Parser.php b/akamai/vendor/league/climate/src/Argument/Parser.php
new file mode 100644
index 00000000..d522d4b9
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Argument/Parser.php
@@ -0,0 +1,278 @@
+summary = new Summary();
+ }
+
+ /**
+ * @param Filter $filter
+ * @param Argument[] $arguments
+ *
+ * @return \League\CLImate\Argument\Parser
+ */
+ public function setFilter($filter, $arguments)
+ {
+ $this->filter = $filter;
+ $this->filter->setArguments($arguments);
+
+ return $this;
+ }
+
+ /**
+ * Parse command line arguments into CLImate arguments.
+ *
+ * @throws \Exception if required arguments aren't defined.
+ * @param array $argv
+ */
+ public function parse(array $argv = null)
+ {
+ $cliArguments = $this->arguments($argv);
+
+ if (in_array('--', $cliArguments)) {
+ $cliArguments = $this->removeTrailingArguments($cliArguments);
+ }
+
+ $unParsedArguments = $this->prefixedArguments($cliArguments);
+
+ $this->nonPrefixedArguments($unParsedArguments);
+
+ // After parsing find out which arguments were required but not
+ // defined on the command line.
+ $missingArguments = $this->filter->missing();
+
+ if (count($missingArguments) > 0) {
+ throw new \Exception(
+ 'The following arguments are required: '
+ . $this->summary->short($missingArguments) . '.'
+ );
+ }
+ }
+
+ /**
+ * Get the command name.
+ *
+ * @param array $argv
+ *
+ * @return string
+ */
+ public function command(array $argv = null)
+ {
+ return $this->getCommandAndArguments($argv)['command'];
+ }
+
+ /**
+ * Get the passed arguments.
+ *
+ * @param array $argv
+ *
+ * @return array
+ */
+ public function arguments(array $argv = null)
+ {
+ return $this->getCommandAndArguments($argv)['arguments'];
+ }
+
+ /**
+ * Get the trailing arguments
+ *
+ * @return string|null
+ */
+ public function trailing()
+ {
+ return $this->trailing;
+ }
+
+ /**
+ * Remove the trailing arguments from the parser and set them aside
+ *
+ * @param array $arguments
+ *
+ * @return array
+ */
+ protected function removeTrailingArguments(array $arguments)
+ {
+ $trailing = array_splice($arguments, array_search('--', $arguments));
+ array_shift($trailing);
+ $this->trailing = implode(' ', $trailing);
+
+ return $arguments;
+ }
+
+ /**
+ * Parse command line options into prefixed CLImate arguments.
+ *
+ * Prefixed arguments are arguments with a prefix (-) or a long prefix (--)
+ * on the command line.
+ *
+ * Return the arguments passed on the command line that didn't match up with
+ * prefixed arguments so they can be assigned to non-prefixed arguments.
+ *
+ * @param array $argv
+ * @return array
+ */
+ protected function prefixedArguments(array $argv = [])
+ {
+ foreach ($argv as $key => $passed_argument) {
+ $argv = $this->trySettingArgumentValue($argv, $key, $passed_argument);
+ }
+
+ // Send un-parsed arguments back upstream.
+ return array_values($argv);
+ }
+
+ /**
+ * Parse unset command line options into non-prefixed CLImate arguments.
+ *
+ * Non-prefixed arguments are parsed after the prefixed arguments on the
+ * command line, in the order that they're defined in the script.
+ *
+ * @param array $unParsedArguments
+ */
+ protected function nonPrefixedArguments(array $unParsedArguments = [])
+ {
+ foreach ($this->filter->withoutPrefix() as $key => $argument) {
+ if (isset($unParsedArguments[$key])) {
+ $argument->setValue($unParsedArguments[$key]);
+ }
+ }
+ }
+
+ /**
+ * Parse the name and value of the argument passed in
+ *
+ * @param string $cliArgument
+ * @return string[] [$name, $value]
+ */
+ protected function getNameAndValue($cliArgument)
+ {
+ // Look for arguments defined in the "key=value" format.
+ if (strpos($cliArgument, '=') !== false) {
+ return explode('=', $cliArgument, 2);
+ }
+
+ // If the argument isn't in "key=value" format then assume it's in
+ // "key value" format and define the value after we've found the
+ // matching CLImate argument.
+ return [$cliArgument, null];
+ }
+
+ /**
+ * Attempt to set the an argument's value and remove applicable
+ * arguments from array
+ *
+ * @param array $argv
+ * @param int $key
+ * @param string $passed_argument
+ *
+ * @return array The new $argv
+ */
+ protected function trySettingArgumentValue($argv, $key, $passed_argument)
+ {
+ list($name, $value) = $this->getNameAndValue($passed_argument);
+
+ // Look for the argument in our defined $arguments
+ // and assign their value.
+ if (!($argument = $this->findPrefixedArgument($name))) {
+ return $argv;
+ }
+
+ // We found an argument key, so take it out of the array.
+ unset($argv[$key]);
+
+ return $this->setArgumentValue($argv, $argument, $key, $value);
+ }
+
+ /**
+ * Set the argument's value
+ *
+ * @param array $argv
+ * @param Argument $argument
+ * @param int $key
+ * @param string|null $value
+ *
+ * @return array The new $argv
+ */
+ protected function setArgumentValue($argv, $argument, $key, $value)
+ {
+ // Arguments are given the value true if they only need to
+ // be defined on the command line to be set.
+ if ($argument->noValue()) {
+ $argument->setValue(true);
+ return $argv;
+ }
+
+ if (is_null($value)) {
+ if (count($argv) === 0) {
+ return $argv;
+ }
+
+ // If the value wasn't previously defined in "key=value"
+ // format then define it from the next command argument.
+ $argument->setValue($argv[++$key]);
+ unset($argv[$key]);
+ return $argv;
+ }
+
+ $argument->setValue($value);
+
+ return $argv;
+ }
+
+ /**
+ * Search for argument in defined prefix arguments
+ *
+ * @param string $name
+ *
+ * @return Argument|false
+ */
+ protected function findPrefixedArgument($name)
+ {
+ foreach ($this->filter->withPrefix() as $argument) {
+ if (in_array($name, ["-{$argument->prefix()}", "--{$argument->longPrefix()}"])) {
+ return $argument;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Pull a command name and arguments from $argv.
+ *
+ * @param array $argv
+ * @return array
+ */
+ protected function getCommandAndArguments(array $argv = null)
+ {
+ // If no $argv is provided then use the global PHP defined $argv.
+ if (is_null($argv)) {
+ global $argv;
+ }
+
+ $arguments = $argv;
+ $command = array_shift($arguments);
+
+ return compact('arguments', 'command');
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Argument/Summary.php b/akamai/vendor/league/climate/src/Argument/Summary.php
new file mode 100644
index 00000000..dad871f5
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Argument/Summary.php
@@ -0,0 +1,211 @@
+climate = $climate;
+
+ return $this;
+ }
+
+ /**
+ * @param string $description
+ *
+ * @return \League\CLImate\Argument\Summary
+ */
+ public function setDescription($description)
+ {
+ $this->description = $description;
+
+ return $this;
+ }
+
+ /**
+ * @param string $command
+ *
+ * @return \League\CLImate\Argument\Summary
+ */
+ public function setCommand($command)
+ {
+ $this->command = $command;
+
+ return $this;
+ }
+
+ /**
+ * @param Filter $filter
+ * @param Argument[] $arguments
+ *
+ * @return \League\CLImate\Argument\Summary
+ */
+ public function setFilter($filter, $arguments)
+ {
+ $this->filter = $filter;
+ $this->filter->setArguments($arguments);
+
+ return $this;
+ }
+
+ /**
+ * Output the full summary for the program
+ */
+ public function output()
+ {
+ // Print the description if it's defined.
+ if ($this->description) {
+ $this->climate->out($this->description)->br();
+ }
+
+ // Print the usage statement with the arguments without a prefix at the end.
+ $this->climate->out("Usage: {$this->command} "
+ . $this->short($this->getOrderedArguments()));
+
+ // Print argument details.
+ foreach (['required', 'optional'] as $type) {
+ $this->outputArguments($this->filter->{$type}(), $type);
+ }
+ }
+
+ /**
+ * Build a short summary of a list of arguments.
+ *
+ * @param Argument[] $arguments
+ *
+ * @return string
+ */
+ public function short($arguments)
+ {
+ return implode(' ', array_map([$this, 'argumentBracketed'], $arguments));
+ }
+
+ /**
+ * Build an argument's summary for use in a usage statement.
+ *
+ * For example, "-u username, --user username", "--force", or
+ * "-c count (default: 7)".
+ *
+ * @param Argument $argument
+ *
+ * @return string
+ */
+ public function argument(Argument $argument)
+ {
+ $summary = $this->prefixedArguments($argument);
+ $printedName = mb_strstr($summary, ' ' . $argument->name());
+
+ // Print the argument name if it's not printed yet.
+ if (!$printedName && !$argument->noValue()) {
+ $summary .= $argument->name();
+ }
+
+ if ($argument->defaultValue()) {
+ $summary .= " (default: {$argument->defaultValue()})";
+ }
+
+ return $summary;
+ }
+
+ /**
+ * Build argument summary surrounded by brackets
+ *
+ * @param Argument $argument
+ *
+ * @return string
+ */
+ protected function argumentBracketed(Argument $argument)
+ {
+ return '[' . $this->argument($argument) . ']';
+ }
+
+ /**
+ * Get the arguments ordered by whether or not they have a prefix
+ *
+ * @return Argument[]
+ */
+ protected function getOrderedArguments()
+ {
+ return array_merge($this->filter->withPrefix(), $this->filter->withoutPrefix());
+ }
+
+ /**
+ * Print out the argument list
+ *
+ * @param array $arguments
+ * @param string $type
+ */
+ protected function outputArguments($arguments, $type)
+ {
+ if (count($arguments) == 0) {
+ return;
+ }
+
+ $this->climate->br()->out(mb_convert_case($type, MB_CASE_TITLE) . ' Arguments:');
+
+ foreach ($arguments as $argument) {
+ $this->climate->tab()->out($this->argument($argument));
+
+ if ($argument->description()) {
+ $this->climate->tab(2)->out($argument->description());
+ }
+ }
+ }
+
+ /**
+ * Builds the summary for any prefixed arguments
+ *
+ * @param Argument $argument
+ *
+ * @return string
+ */
+ protected function prefixedArguments(Argument $argument)
+ {
+ $prefixes = [$argument->prefix(), $argument->longPrefix()];
+ $summary = [];
+
+ foreach ($prefixes as $key => $prefix) {
+ if (!$prefix) {
+ continue;
+ }
+
+ $sub = str_repeat('-', $key + 1) . $prefix;
+
+ if (!$argument->noValue()) {
+ $sub .= " {$argument->name()}";
+ }
+
+ $summary[] = $sub;
+ }
+
+ return implode(', ', $summary);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/CLImate.php b/akamai/vendor/league/climate/src/CLImate.php
new file mode 100644
index 00000000..295a02f0
--- /dev/null
+++ b/akamai/vendor/league/climate/src/CLImate.php
@@ -0,0 +1,442 @@
+setStyle(new Style());
+ $this->setRouter(new Router());
+ $this->setSettingsManager(new SettingsManager());
+ $this->setOutput(new Output());
+ $this->setUtil(new UtilFactory());
+ $this->setArgumentManager(new ArgumentManager());
+ }
+
+ /**
+ * Set the style property
+ *
+ * @param \League\CLImate\Decorator\Style $style
+ */
+ public function setStyle(Style $style)
+ {
+ $this->style = $style;
+ }
+
+ /**
+ * Set the router property
+ *
+ * @param \League\CLImate\TerminalObject\Router\Router $router
+ */
+ public function setRouter(Router $router)
+ {
+ $this->router = $router;
+ }
+
+ /**
+ * Set the settings property
+ *
+ * @param \League\CLImate\Settings\Manager $manager
+ */
+ public function setSettingsManager(SettingsManager $manager)
+ {
+ $this->settings = $manager;
+ }
+
+ /**
+ * Set the arguments property
+ *
+ * @param \League\CLImate\Argument\Manager $manager
+ */
+ public function setArgumentManager(ArgumentManager $manager)
+ {
+ $this->arguments = $manager;
+ }
+
+ /**
+ * Set the output property
+ *
+ * @param \League\CLImate\Util\Output $output
+ */
+ public function setOutput(Output $output)
+ {
+ $this->output = $output;
+ }
+
+ /**
+ * Set the util property
+ *
+ * @param \League\CLImate\Util\UtilFactory $util
+ */
+ public function setUtil(UtilFactory $util)
+ {
+ $this->util = $util;
+ }
+
+ /**
+ * Extend CLImate with custom methods
+ *
+ * @param string|object|array $class
+ * @param string $key Optional custom key instead of class name
+ *
+ * @return \League\CLImate\CLImate
+ */
+ public function extend($class, $key = null)
+ {
+ $this->router->addExtension($key, $class);
+
+ return $this;
+ }
+
+ /**
+ * Force ansi support on
+ *
+ * @return \League\CLImate\CLImate
+ */
+ public function forceAnsiOn()
+ {
+ $this->util->system->forceAnsi();
+
+ return $this;
+ }
+
+ /**
+ * Force ansi support off
+ *
+ * @return \League\CLImate\CLImate
+ */
+ public function forceAnsiOff()
+ {
+ $this->util->system->forceAnsi(false);
+
+ return $this;
+ }
+
+ /**
+ * Write line to writer once
+ *
+ * @param string|array $writer
+ *
+ * @return \League\CLImate\CLImate
+ */
+ public function to($writer)
+ {
+ $this->output->once($writer);
+
+ return $this;
+ }
+
+ /**
+ * Output the program's usage statement
+ *
+ * @param array $argv
+ */
+ public function usage(array $argv = null)
+ {
+ return $this->arguments->usage($this, $argv);
+ }
+
+ /**
+ * Set the program's description
+ *
+ * @param string $description
+ *
+ * @return \League\CLImate\CLImate
+ */
+ public function description($description)
+ {
+ $this->arguments->description($description);
+
+ return $this;
+ }
+
+ /**
+ * Check if we have valid output
+ *
+ * @param mixed $output
+ *
+ * @return boolean
+ */
+ protected function hasOutput($output)
+ {
+ if (!empty($output)) {
+ return true;
+ }
+
+ // Check for type first to avoid errors with objects/arrays/etc
+ return ((is_string($output) || is_numeric($output)) && strlen($output) > 0);
+ }
+
+ /**
+ * Search for the method within the string
+ * and route it if we find one.
+ *
+ * @param string $method
+ * @param string $name
+ *
+ * @return string The new string without the executed method.
+ */
+ protected function parseStyleMethod($method, $name)
+ {
+ // If the name starts with this method string...
+ if (substr($name, 0, strlen($method)) == $method) {
+ // ...remove the method name from the beginning of the string...
+ $name = substr($name, strlen($method));
+
+ // ...and trim off any of those underscores hanging around
+ $name = ltrim($name, '_');
+
+ $this->style->set($method);
+ }
+
+ return $name;
+ }
+
+ /**
+ * Search for any style methods within the name and apply them
+ *
+ * @param string $name
+ * @param array $method_search
+ *
+ * @return string Anything left over after applying styles
+ */
+ protected function applyStyleMethods($name, $method_search = null)
+ {
+ // Get all of the possible style attributes
+ $method_search = $method_search ?: array_keys($this->style->all());
+
+ $new_name = $this->searchForStyleMethods($name, $method_search);
+
+ // While we still have a name left and we keep finding methods,
+ // loop through the possibilities
+ if (strlen($new_name) > 0 && $new_name != $name) {
+ return $this->applyStyleMethods($new_name, $method_search);
+ }
+
+ return $new_name;
+ }
+
+ /**
+ * Search for style methods in the current name
+ *
+ * @param string $name
+ * @param array $search
+ * @return string
+ */
+ protected function searchForStyleMethods($name, $search)
+ {
+ // Loop through the possible methods
+ foreach ($search as $method) {
+ // See if we found a valid method
+ $name = $this->parseStyleMethod($method, $name);
+ }
+
+ return $name;
+ }
+
+ /**
+ * Build up the terminal object and return it
+ *
+ * @param string $name
+ * @param array $arguments
+ *
+ * @return object|null
+ */
+ protected function buildTerminalObject($name, $arguments)
+ {
+ // Retrieve the parser for the current set of styles
+ $parser = $this->style->parser($this->util->system);
+
+ // Reset the styles
+ $this->style->reset();
+
+ // Execute the terminal object
+ $this->router->settings($this->settings);
+ $this->router->parser($parser);
+ $this->router->output($this->output);
+ $this->router->util($this->util);
+
+ return $this->router->execute($name, $arguments);
+ }
+
+ /**
+ * Route anything leftover after styles were applied
+ *
+ * @param string $name
+ * @param array $arguments
+ *
+ * @return object|null
+ */
+ protected function routeRemainingMethod($name, array $arguments)
+ {
+ // If we still have something left, let's figure out what it is
+ if ($this->router->exists($name)) {
+ $obj = $this->buildTerminalObject($name, $arguments);
+
+ // If something was returned, return it
+ if (is_object($obj)) {
+ return $obj;
+ }
+ } elseif ($this->settings->exists($name)) {
+ $this->settings->add($name, reset($arguments));
+ // Handle passthroughs to the arguments manager.
+ } else {
+ // If we can't find it at this point, let's fail gracefully
+ $this->out(reset($arguments));
+ }
+ }
+
+ /**
+ * Magic method for anything called that doesn't exist
+ *
+ * @param string $requested_method
+ * @param array $arguments
+ *
+ * @return \League\CLImate\CLImate|\League\CLImate\TerminalObject\Dynamic\DynamicTerminalObject
+ *
+ * List of many of the possible method being called here
+ * documented at the top of this class.
+ */
+ public function __call($requested_method, $arguments)
+ {
+ // Apply any style methods that we can find first
+ $name = $this->applyStyleMethods(Helper::snakeCase($requested_method));
+
+ // The first argument is the string|array|object we want to echo out
+ $output = reset($arguments);
+
+ if (strlen($name)) {
+ // If we have something left, let's try and route it to the appropriate place
+ if ($result = $this->routeRemainingMethod($name, $arguments)) {
+ return $result;
+ }
+ } elseif ($this->hasOutput($output)) {
+ // If we have fulfilled all of the requested methods and we have output, output it
+ $this->out($output);
+ }
+
+ return $this;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Component/BackgroundColor.php b/akamai/vendor/league/climate/src/Decorator/Component/BackgroundColor.php
new file mode 100644
index 00000000..70f5d9f6
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Component/BackgroundColor.php
@@ -0,0 +1,72 @@
+strip($val));
+
+ if ($color) {
+ $color += self::ADD;
+ }
+
+ return $color;
+ }
+
+ /**
+ * Set the current background color
+ *
+ * @param mixed $val
+ *
+ * @return boolean
+ */
+ public function set($val)
+ {
+ return parent::set($this->strip($val));
+ }
+
+ /**
+ * Get all of the available background colors
+ *
+ * @return array
+ */
+ public function all()
+ {
+ $colors = [];
+
+ foreach ($this->colors as $color => $code) {
+ $colors['background_' . $color] = $code + self::ADD;
+ }
+
+ return $colors;
+ }
+
+ /**
+ * Strip the color of any prefixes
+ *
+ * @param string $val
+ *
+ * @return string
+ */
+ protected function strip($val)
+ {
+ return str_replace('background_', '', $val);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Component/BaseDecorator.php b/akamai/vendor/league/climate/src/Decorator/Component/BaseDecorator.php
new file mode 100644
index 00000000..40f0329b
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Component/BaseDecorator.php
@@ -0,0 +1,53 @@
+defaults();
+ }
+
+ /**
+ * Load up the defaults for this decorator
+ */
+ public function defaults()
+ {
+ foreach ($this->defaults as $name => $code) {
+ $this->add($name, $code);
+ }
+ }
+
+ /**
+ * Reset the currently set decorator
+ */
+ public function reset()
+ {
+ $this->current = [];
+ }
+
+ /**
+ * Retrieve the currently set codes for the decorator
+ *
+ * @return array
+ */
+ public function current()
+ {
+ return $this->current;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Component/Color.php b/akamai/vendor/league/climate/src/Decorator/Component/Color.php
new file mode 100644
index 00000000..7b176dc2
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Component/Color.php
@@ -0,0 +1,100 @@
+ 39,
+ 'black' => 30,
+ 'red' => 31,
+ 'green' => 32,
+ 'yellow' => 33,
+ 'blue' => 34,
+ 'magenta' => 35,
+ 'cyan' => 36,
+ 'light_gray' => 37,
+ 'dark_gray' => 90,
+ 'light_red' => 91,
+ 'light_green' => 92,
+ 'light_yellow' => 93,
+ 'light_blue' => 94,
+ 'light_magenta' => 95,
+ 'light_cyan' => 96,
+ 'white' => 97,
+ ];
+
+ /**
+ * Add a color into the mix
+ *
+ * @param string $key
+ * @param integer $value
+ */
+ public function add($key, $value)
+ {
+ $this->colors[$key] = (int) $value;
+ }
+
+ /**
+ * Retrieve all of available colors
+ *
+ * @return array
+ */
+ public function all()
+ {
+ return $this->colors;
+ }
+
+ /**
+ * Get the code for the color
+ *
+ * @param string $val
+ *
+ * @return string
+ */
+ public function get($val)
+ {
+ // If we already have the code, just return that
+ if (is_numeric($val)) {
+ return $val;
+ }
+
+ if (array_key_exists($val, $this->colors)) {
+ return $this->colors[$val];
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the current color
+ *
+ * @param string $val
+ *
+ * @return boolean
+ */
+ public function set($val)
+ {
+ $code = $this->get($val);
+
+ if ($code) {
+ $this->current = [$code];
+
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Component/Command.php b/akamai/vendor/league/climate/src/Decorator/Component/Command.php
new file mode 100644
index 00000000..343ac154
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Component/Command.php
@@ -0,0 +1,77 @@
+ 'green',
+ 'comment' => 'yellow',
+ 'whisper' => 'light_gray',
+ 'shout' => 'red',
+ 'error' => 'light_red',
+ ];
+
+ /**
+ * Add a command into the mix
+ *
+ * @param string $key
+ * @param mixed $value
+ */
+ public function add($key, $value)
+ {
+ $this->commands[$key] = $value;
+ }
+
+ /**
+ * Retrieve all of the available commands
+ *
+ * @return array
+ */
+ public function all()
+ {
+ return $this->commands;
+ }
+
+ /**
+ * Get the style that corresponds to the command
+ *
+ * @param string $val
+ *
+ * @return string
+ */
+ public function get($val)
+ {
+ if (array_key_exists($val, $this->commands)) {
+ return $this->commands[$val];
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the currently used command
+ *
+ * @param string $val
+ *
+ * @return string|false
+ */
+ public function set($val)
+ {
+ // Return the code because it is a string corresponding
+ // to a property in another class
+ return ($code = $this->get($val)) ? $code : false;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Component/DecoratorInterface.php b/akamai/vendor/league/climate/src/Decorator/Component/DecoratorInterface.php
new file mode 100644
index 00000000..b48e41a0
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Component/DecoratorInterface.php
@@ -0,0 +1,28 @@
+ 1,
+ 'dim' => 2,
+ 'underline' => 4,
+ 'blink' => 5,
+ 'invert' => 7,
+ 'hidden' => 8,
+ ];
+
+ /**
+ * Add a format into the mix
+ *
+ * @param string $key
+ * @param mixed $value
+ */
+ public function add($key, $value)
+ {
+ $this->formats[$key] = (int) $value;
+ }
+
+ /**
+ * Retrieve all of the available formats
+ *
+ * @return array
+ */
+ public function all()
+ {
+ return $this->formats;
+ }
+
+ /**
+ * Get the code for the format
+ *
+ * @param string $val
+ *
+ * @return string
+ */
+ public function get($val)
+ {
+ // If we already have the code, just return that
+ if (is_numeric($val)) {
+ return $val;
+ }
+
+ if (array_key_exists($val, $this->formats)) {
+ return $this->formats[$val];
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the current format
+ *
+ * @param string $val
+ *
+ * @return boolean
+ */
+ public function set($val)
+ {
+ $code = $this->get($val);
+
+ if ($code) {
+ $this->current[] = $code;
+
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Parser/Ansi.php b/akamai/vendor/league/climate/src/Decorator/Parser/Ansi.php
new file mode 100644
index 00000000..d4d86c52
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Parser/Ansi.php
@@ -0,0 +1,174 @@
+start() . $this->parse($str) . $this->end();
+ }
+
+ /**
+ * Get the string that begins the style
+ *
+ * @param string $codes
+ * @return string
+ */
+ protected function start($codes = null)
+ {
+ $codes = $codes ?: $this->currentCode();
+ $codes = $this->codeStr($codes);
+
+ return $this->wrapCodes($codes);
+ }
+
+ /**
+ * Get the string that ends the style
+ *
+ * @param string|array $codes
+ * @return string
+ */
+ protected function end($codes = null)
+ {
+ if (empty($codes)) {
+ $codes = [0];
+ } else {
+ $codes = Helper::toArray($codes);
+
+ // Reset everything back to normal up front
+ array_unshift($codes, 0);
+ }
+
+ return $this->wrapCodes($this->codeStr($codes));
+ }
+
+ /**
+ * Wrap the code string in the full escaped sequence
+ *
+ * @param string $codes
+ *
+ * @return string
+ */
+
+ protected function wrapCodes($codes)
+ {
+ return "\e[{$codes}m";
+ }
+
+ /**
+ * Parse the string for tags and replace them with their codes
+ *
+ * @param string $str
+ *
+ * @return string
+ */
+
+ protected function parse($str)
+ {
+ $count = preg_match_all($this->tags->regex(), $str, $matches);
+
+ // If we didn't find anything, return the string right back
+ if (!$count || !is_array($matches)) {
+ return $str;
+ }
+
+ // All we want is the array of actual strings matched
+ $matches = reset($matches);
+
+ return $this->parseTags($str, $matches);
+ }
+
+ /**
+ * Parse the given string for the tags and replace them with the appropriate codes
+ *
+ * @param string $str
+ * @param array $tags
+ *
+ * @return string
+ */
+
+ protected function parseTags($str, $tags)
+ {
+ // Let's keep a history of styles applied
+ $history = ($this->currentCode()) ? [$this->currentCode()] : [];
+
+ foreach ($tags as $tag) {
+ $str = $this->replaceTag($str, $tag, $history);
+ }
+
+ return $str;
+ }
+
+ /**
+ * Replace the tag in the str
+ *
+ * @param string $str
+ * @param string $tag
+ * @param array $history
+ *
+ * @return string
+ */
+
+ protected function replaceTag($str, $tag, &$history)
+ {
+ // We will be replacing tags one at a time, can't pass this by reference
+ $replace_count = 1;
+
+ if (strpos($tag, '/')) {
+ // We are closing out the tag, pop off the last element and get the codes that are left
+ array_pop($history);
+ $replace = $this->end($history);
+ } else {
+ // We are starting a new tag, add it onto the history and replace with correct color code
+ $history[] = $this->tags->value($tag);
+ $replace = $this->start($this->tags->value($tag));
+ }
+
+ return str_replace($tag, $replace, $str, $replace_count);
+ }
+
+ /**
+ * Stringify the codes
+ *
+ * @param mixed $codes
+ *
+ * @return string
+ */
+
+ protected function codeStr($codes)
+ {
+ // If we get something that is already a code string, just pass it back
+ if (!is_array($codes) && strpos($codes, ';')) {
+ return $codes;
+ }
+
+ $codes = Helper::toArray($codes);
+
+ // Sort for the sake of consistency and testability
+ sort($codes);
+
+ return implode(';', $codes);
+ }
+
+ /**
+ * Retrieve the current style code
+ *
+ * @return string
+ */
+
+ protected function currentCode()
+ {
+ return $this->codeStr($this->current);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Parser/NonAnsi.php b/akamai/vendor/league/climate/src/Decorator/Parser/NonAnsi.php
new file mode 100644
index 00000000..6c5fef69
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Parser/NonAnsi.php
@@ -0,0 +1,19 @@
+tags->regex(), '', $str);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Parser/Parser.php b/akamai/vendor/league/climate/src/Decorator/Parser/Parser.php
new file mode 100644
index 00000000..43e09101
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Parser/Parser.php
@@ -0,0 +1,38 @@
+current = $current;
+ $this->tags = $tags;
+ }
+
+ /**
+ * Wrap the string in the current style
+ *
+ * @param string $str
+ *
+ * @return string
+ */
+ abstract public function apply($str);
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Parser/ParserFactory.php b/akamai/vendor/league/climate/src/Decorator/Parser/ParserFactory.php
new file mode 100644
index 00000000..5383f5a4
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Parser/ParserFactory.php
@@ -0,0 +1,26 @@
+hasAnsiSupport()) {
+ return new Ansi($current, $tags);
+ }
+
+ return new NonAnsi($current, $tags);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Parser/ParserImporter.php b/akamai/vendor/league/climate/src/Decorator/Parser/ParserImporter.php
new file mode 100644
index 00000000..823c041c
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Parser/ParserImporter.php
@@ -0,0 +1,23 @@
+parser = $parser;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Style.php b/akamai/vendor/league/climate/src/Decorator/Style.php
new file mode 100644
index 00000000..fb526692
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Style.php
@@ -0,0 +1,295 @@
+ 'Format',
+ 'color' => 'Color',
+ 'background' => 'BackgroundColor',
+ 'command' => 'Command',
+ ];
+
+ protected $parser;
+
+ /**
+ * An array of the current styles applied
+ *
+ * @var array $current
+ */
+ protected $current = [];
+
+ public function __construct()
+ {
+ foreach ($this->available as $key => $class) {
+ $class = 'League\CLImate\Decorator\Component\\' . $class;
+ $this->style[$key] = new $class();
+ }
+ }
+
+ /**
+ * Get all of the styles available
+ *
+ * @return array
+ */
+ public function all()
+ {
+ $all = [];
+
+ foreach ($this->style as $style) {
+ $all = array_merge($all, $this->convertToCodes($style->all()));
+ }
+
+ return $all;
+ }
+
+ /**
+ * Attempt to get the corresponding code for the style
+ *
+ * @param mixed $key
+ *
+ * @return mixed
+ */
+ public function get($key)
+ {
+ foreach ($this->style as $style) {
+ if ($code = $style->get($key)) {
+ return $code;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Attempt to set some aspect of the styling,
+ * return true if attempt was successful
+ *
+ * @param string $key
+ *
+ * @return boolean
+ */
+ public function set($key)
+ {
+ foreach ($this->style as $style) {
+ if ($code = $style->set($key)) {
+ return $this->validateCode($code);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Reset the current styles applied
+ *
+ */
+ public function reset()
+ {
+ foreach ($this->style as $style) {
+ $style->reset();
+ }
+ }
+
+ /**
+ * Get a new instance of the Parser class based on the current settings
+ *
+ * @param \League\CLImate\Util\System\System $system
+ *
+ * @return \League\CLImate\Decorator\Parser\Parser
+ */
+ public function parser(System $system)
+ {
+ return ParserFactory::getInstance($system, $this->current(), new Tags($this->all()));
+ }
+
+ /**
+ * Compile an array of the current codes
+ *
+ * @return array
+ */
+ public function current()
+ {
+ $full_current = [];
+
+ foreach ($this->style as $style) {
+ $full_current = array_merge($full_current, Helper::toArray($style->current()));
+ }
+
+ $full_current = array_filter($full_current);
+
+ return array_values($full_current);
+ }
+
+ /**
+ * Make sure that the code is an integer, if not let's try and get it there
+ *
+ * @param mixed $code
+ *
+ * @return boolean
+ */
+ protected function validateCode($code)
+ {
+ if (is_integer($code)) {
+ return true;
+ }
+
+ // Plug it back in and see what we get
+ if (is_string($code)) {
+ return $this->set($code);
+ }
+
+ if (is_array($code)) {
+ return $this->validateCodeArray($code);
+ }
+
+ return false;
+ }
+
+ /**
+ * Validate an array of codes
+ *
+ * @param array $codes
+ *
+ * @return boolean
+ */
+ protected function validateCodeArray(array $codes)
+ {
+ // Loop through it and add each of the properties
+ $adds = [];
+
+ foreach ($codes as $code) {
+ $adds[] = $this->set($code);
+ }
+
+ // If any of them came back true, we're good to go
+ return in_array(true, $adds);
+ }
+
+ /**
+ * Convert the array of codes to integers
+ *
+ * @param array $codes
+ * @return array
+ */
+ protected function convertToCodes(array $codes)
+ {
+ foreach ($codes as $key => $code) {
+ if (is_int($code)) {
+ continue;
+ }
+
+ $codes[$key] = $this->getCode($code);
+ }
+
+ return $codes;
+ }
+
+ /**
+ * Retrieve the integers from the mixed code input
+ *
+ * @param string|array $code
+ *
+ * @return integer|array
+ */
+ protected function getCode($code)
+ {
+ if (is_array($code)) {
+ return $this->getCodeArray($code);
+ }
+
+ return $this->get($code);
+ }
+
+ /**
+ * Retrieve an array of integers from the array of codes
+ *
+ * @param array $codes
+ *
+ * @return array
+ */
+ protected function getCodeArray(array $codes)
+ {
+ foreach ($codes as $key => $code) {
+ $codes[$key] = $this->get($code);
+ }
+
+ return $codes;
+ }
+
+ /**
+ * Parse the add method for the style they are trying to add
+ *
+ * @param string $method
+ *
+ * @return string
+ */
+ protected function parseAddMethod($method)
+ {
+ return strtolower(substr($method, 3, strlen($method)));
+ }
+
+ /**
+ * Add a custom style
+ *
+ * @param string $style
+ * @param string $key
+ * @param string $value
+ */
+ protected function add($style, $key, $value)
+ {
+ $this->style[$style]->add($key, $value);
+
+ // If we are adding a color, make sure it gets added
+ // as a background color too
+ if ($style == 'color') {
+ $this->style['background']->add($key, $value);
+ }
+ }
+
+ /**
+ * Magic Methods
+ *
+ * List of possible magic methods are at the top of this class
+ *
+ * @param string $requested_method
+ * @param array $arguments
+ */
+ public function __call($requested_method, $arguments)
+ {
+ // The only methods we are concerned about are 'add' methods
+ if (substr($requested_method, 0, 3) != 'add') {
+ return false;
+ }
+
+ $style = $this->parseAddMethod($requested_method);
+
+ if (array_key_exists($style, $this->style)) {
+ list($key, $value) = $arguments;
+ $this->add($style, $key, $value);
+ }
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Decorator/Tags.php b/akamai/vendor/league/climate/src/Decorator/Tags.php
new file mode 100644
index 00000000..ab15a41f
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Decorator/Tags.php
@@ -0,0 +1,76 @@
+keys = $keys;
+ $this->build();
+ }
+
+ /**
+ * Get all available tags
+ *
+ * @return array
+ */
+
+ public function all()
+ {
+ return $this->tags;
+ }
+
+ /**
+ * Get the value of the requested tag
+ *
+ * @param string $key
+ *
+ * @return string|null
+ */
+
+ public function value($key)
+ {
+ return (array_key_exists($key, $this->tags)) ? $this->tags[$key] : null;
+ }
+
+ /**
+ * Get the regular expression that can be used to parse the string for tags
+ *
+ * @return string
+ */
+
+ public function regex()
+ {
+ return '(<(?:(?:(?:\\\)*\/)*(?:' . implode('|', array_keys($this->keys)) . '))>)';
+ }
+
+ /**
+ * Build the search and replace for all of the various style tags
+ */
+
+ protected function build()
+ {
+ foreach ($this->keys as $tag => $code) {
+ $this->tags["<{$tag}>"] = $code;
+ $this->tags["{$tag}>"] = $code;
+ $this->tags["<\\/{$tag}>"] = $code;
+ }
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Logger.php b/akamai/vendor/league/climate/src/Logger.php
new file mode 100644
index 00000000..e9ce9b8e
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Logger.php
@@ -0,0 +1,174 @@
+ 1,
+ LogLevel::ALERT => 2,
+ LogLevel::CRITICAL => 3,
+ LogLevel::ERROR => 4,
+ LogLevel::WARNING => 5,
+ LogLevel::NOTICE => 6,
+ LogLevel::INFO => 7,
+ LogLevel::DEBUG => 8,
+ ];
+
+ /**
+ * @var int $level Ignore logging attempts at a level less than this.
+ */
+ private $level;
+
+ /**
+ * @var CLImate $climate The underlying climate instance we are using for output.
+ */
+ private $climate;
+
+ /**
+ * Create a new Logger instance.
+ *
+ * @param string $level One of the LogLevel constants
+ * @param CLImate $climate An existing CLImate instance to use for output
+ */
+ public function __construct($level = LogLevel::INFO, CLImate $climate = null)
+ {
+ $this->level = $this->convertLevel($level);
+
+ if ($climate === null) {
+ $climate = new CLImate;
+ }
+ $this->climate = $climate;
+
+ # Define some default styles to use for the output
+ $commands = [
+ "emergency" => ["white", "bold", "background_red"],
+ "alert" => ["white", "background_yellow"],
+ "critical" => ["red", "bold"],
+ "error" => ["red"],
+ "warning" => "yellow",
+ "notice" => "light_cyan",
+ "info" => "green",
+ "debug" => "dark_gray",
+ ];
+
+ # If any of the required styles are not defined then define them now
+ foreach ($commands as $command => $style) {
+ if (!$this->climate->style->get($command)) {
+ $this->climate->style->addCommand($command, $style);
+ }
+ }
+ }
+
+
+ /**
+ * Get a numeric log level for the passed parameter.
+ *
+ * @param string $level One of the LogLevel constants
+ *
+ * @return int
+ */
+ private function convertLevel($level)
+ {
+ # If this is one of the defined string log levels then return it's numeric value
+ if (!array_key_exists($level, $this->levels)) {
+ throw new InvalidArgumentException("Unknown log level: {$level}");
+ }
+
+ return $this->levels[$level];
+ }
+
+
+ /**
+ * Get a new instance logging at a different level
+ *
+ * @param string $level One of the LogLevel constants
+ *
+ * @return Logger
+ */
+ public function withLogLevel($level)
+ {
+ $logger = clone $this;
+ $logger->level = $this->convertLevel($level);
+ return $logger;
+ }
+
+
+ /**
+ * Log messages to a CLImate instance.
+ *
+ * @param string $level One of the LogLevel constants
+ * @param string|object $message If an object is passed it must implement __toString()
+ * @param array $context Placeholders to be substituted in the message
+ *
+ * @return void
+ */
+ public function log($level, $message, array $context = [])
+ {
+ if ($this->convertLevel($level) > $this->level) {
+ return;
+ }
+
+ # Handle objects implementing __toString
+ $message = (string)$message;
+
+ # Handle any placeholders in the $context array
+ foreach ($context as $key => $val) {
+ $placeholder = "{" . $key . "}";
+
+ # If this context key is used as a placeholder, then replace it, and remove it from the $context array
+ if (strpos($message, $placeholder) !== false) {
+ $val = (string)$val;
+ $message = str_replace($placeholder, $val, $message);
+ unset($context[$key]);
+ }
+ }
+
+ # Send the message to the climate instance
+ $this->climate->{$level}($message);
+
+ # Append any context information not used as placeholders
+ $this->outputRecursiveContext($level, $context, 1);
+ }
+
+
+ /**
+ * Handle recursive arrays in the logging context.
+ *
+ * @param string $level One of the LogLevel constants
+ * @param array $context The array of context to output
+ * @param int $indent The current level of indentation to be used
+ *
+ * @return void
+ */
+ private function outputRecursiveContext($level, array $context, $indent)
+ {
+ foreach ($context as $key => $val) {
+ $this->climate->tab($indent);
+
+ $this->climate->{$level}()->inline("{$key}: ");
+
+ if (is_array($val)) {
+ $this->climate->{$level}("[");
+ $this->outputRecursiveContext($level, $val, $indent + 1);
+ $this->climate->tab($indent)->{$level}("]");
+ } else {
+ $this->climate->{$level}((string)$val);
+ }
+ }
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Settings/Art.php b/akamai/vendor/league/climate/src/Settings/Art.php
new file mode 100644
index 00000000..cf69ab99
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Settings/Art.php
@@ -0,0 +1,22 @@
+dirs = array_merge($this->dirs, func_get_args());
+ $this->dirs = array_filter($this->dirs);
+ $this->dirs = array_values($this->dirs);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Settings/Manager.php b/akamai/vendor/league/climate/src/Settings/Manager.php
new file mode 100644
index 00000000..ccd5a320
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Settings/Manager.php
@@ -0,0 +1,84 @@
+getPath($name));
+ }
+
+ /**
+ * Add a setting
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ public function add($name, $value)
+ {
+ $setting = $this->getPath($name);
+ $key = $this->getClassName($name);
+
+ // If the current key doesn't exist in the settings array, set it up
+ if (!array_key_exists($name, $this->settings)) {
+ $this->settings[$key] = new $setting();
+ }
+
+ $this->settings[$key]->add($value);
+ }
+
+ /**
+ * Get the value of the requested setting if it exists
+ *
+ * @param string $key
+ *
+ * @return mixed
+ */
+ public function get($key)
+ {
+ if (array_key_exists($key, $this->settings)) {
+ return $this->settings[$key];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the short name for the requested settings class
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ protected function getPath($name)
+ {
+ return 'League\CLImate\Settings\\' . $this->getClassName($name);
+ }
+
+ /**
+ * Get the short class name for the setting
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ protected function getClassName($name)
+ {
+ return ucwords(str_replace('add_', '', $name));
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Settings/SettingsImporter.php b/akamai/vendor/league/climate/src/Settings/SettingsImporter.php
new file mode 100644
index 00000000..72420cbc
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Settings/SettingsImporter.php
@@ -0,0 +1,32 @@
+$method($setting);
+ }
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Settings/SettingsInterface.php b/akamai/vendor/league/climate/src/Settings/SettingsInterface.php
new file mode 100644
index 00000000..180bd676
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Settings/SettingsInterface.php
@@ -0,0 +1,11 @@
+$key = $value;
+ }
+ }
+
+ /**
+ * Get the parser for the current object
+ *
+ * @return \League\CLImate\Decorator\Parser\Parser
+ */
+ public function getParser()
+ {
+ return $this->parser;
+ }
+
+ /**
+ * Check if this object requires a new line to be added after the output
+ *
+ * @return boolean
+ */
+ public function sameLine()
+ {
+ return false;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/BasicTerminalObjectInterface.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/BasicTerminalObjectInterface.php
new file mode 100644
index 00000000..863abb58
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/BasicTerminalObjectInterface.php
@@ -0,0 +1,34 @@
+char($char)->length($length);
+ }
+
+ /**
+ * Set the character to repeat for the border
+ *
+ * @param string $char
+ *
+ * @return Border
+ */
+ public function char($char)
+ {
+ $this->set('char', $char);
+
+ return $this;
+ }
+
+ /**
+ * Set the length of the border
+ *
+ * @param integer $length
+ *
+ * @return Border
+ */
+ public function length($length)
+ {
+ $this->set('length', $length);
+
+ return $this;
+ }
+
+ /**
+ * Return the border
+ *
+ * @return string
+ */
+ public function result()
+ {
+ $length = $this->length ?: $this->util->width() ?: 100;
+ $str = str_repeat($this->char, $length);
+ $str = substr($str, 0, $length);
+
+ return $str;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Br.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Br.php
new file mode 100644
index 00000000..8c697974
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Br.php
@@ -0,0 +1,16 @@
+count, '');
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Clear.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Clear.php
new file mode 100644
index 00000000..23f27666
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Clear.php
@@ -0,0 +1,21 @@
+data = $data;
+ $this->column_count = $column_count;
+ }
+
+ /**
+ * Calculate the number of columns organize data
+ *
+ * @return array
+ */
+ public function result()
+ {
+ $keys = array_keys($this->data);
+ $first_key = reset($keys);
+
+ return (!is_int($first_key)) ? $this->associativeColumns() : $this->columns();
+ }
+
+ /**
+ * Get columns for a regular array
+ *
+ * @return array
+ */
+ protected function columns()
+ {
+ $this->data = $this->setData();
+ $column_widths = $this->getColumnWidths();
+ $output = [];
+ $count = count(reset($this->data));
+
+ for ($i = 0; $i < $count; $i++) {
+ $output[] = $this->getRow($i, $column_widths);
+ }
+
+ return $output;
+ }
+
+ /**
+ * Re-configure the data into it's final form
+ */
+ protected function setData()
+ {
+ // If it's already an array of arrays, we're good to go
+ if (is_array(reset($this->data))) {
+ return $this->setArrayOfArraysData();
+ }
+
+ $column_width = $this->getColumnWidth($this->data);
+ $row_count = $this->getMaxRows($column_width);
+
+ return array_chunk($this->data, $row_count);
+ }
+
+ /**
+ * Re-configure an array of arrays into column arrays
+ */
+ protected function setArrayOfArraysData()
+ {
+ $this->setColumnCountViaArray($this->data);
+
+ $new_data = array_fill(0, $this->column_count, []);
+
+ foreach ($this->data as $items) {
+ for ($i = 0; $i < $this->column_count; $i++) {
+ $new_data[$i][] = (array_key_exists($i, $items)) ? $items[$i] : null;
+ }
+ }
+
+ return $new_data;
+ }
+
+ /**
+ * Get columns for an associative array
+ *
+ * @return array
+ */
+ protected function associativeColumns()
+ {
+ $column_width = $this->getColumnWidth(array_keys($this->data));
+ $output = [];
+
+ foreach ($this->data as $key => $value) {
+ $output[] = $this->pad($key, $column_width) . $value;
+ }
+
+ return $output;
+ }
+
+ /**
+ * Get the row of data
+ *
+ * @param integer $key
+ * @param array $column_widths
+ *
+ * @return string
+ */
+ protected function getRow($key, $column_widths)
+ {
+ $row = [];
+
+ for ($j = 0; $j < $this->column_count; $j++) {
+ if (isset($this->data[$j]) && array_key_exists($key, $this->data[$j])) {
+ $row[] = $this->pad($this->data[$j][$key], $column_widths[$j]);
+ }
+ }
+
+ return trim(implode('', $row));
+ }
+
+ /**
+ * Get the standard column width
+ *
+ * @param array $data
+ *
+ * @return integer
+ */
+ protected function getColumnWidth($data)
+ {
+ // Return the maximum width plus a buffer
+ return $this->maxStrLen($data) + 5;
+ }
+
+ /**
+ * Get an array of each column's width
+ *
+ * @return array
+ */
+ protected function getColumnWidths()
+ {
+ $column_widths = [];
+
+ for ($i = 0; $i < $this->column_count; $i++) {
+ if (!isset($this->data[$i])) {
+ $column_widths[] = 0;
+ continue;
+ }
+ $column_widths[] = $this->getColumnWidth($this->data[$i]);
+ }
+
+ return $column_widths;
+ }
+
+ /**
+ * Set the count property
+ *
+ * @param integer $column_width
+ */
+ protected function setColumnCount($column_width)
+ {
+ $this->column_count = (int) floor($this->util->width() / $column_width);
+ }
+
+ /**
+ * Set the count property via an array
+ *
+ * @param array $items
+ */
+ protected function setColumnCountViaArray($items)
+ {
+ $counts = array_map(function ($arr) {
+ return count($arr);
+ }, $items);
+
+ $this->column_count = max($counts);
+ }
+
+ /**
+ * Get the number of rows per column
+ *
+ * @param integer $column_width
+ *
+ * @return integer
+ */
+ protected function getMaxRows($column_width)
+ {
+ if (!$this->column_count) {
+ $this->setColumnCount($column_width);
+ }
+
+ return ceil(count($this->data) / $this->column_count);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Draw.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Draw.php
new file mode 100644
index 00000000..0f124786
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Draw.php
@@ -0,0 +1,30 @@
+addDir(__DIR__ . '/../../ASCII');
+
+ $this->art = $art;
+ }
+
+ /**
+ * Return the art
+ *
+ * @return array
+ */
+ public function result()
+ {
+ $file = $this->artFile($this->art);
+
+ return $this->parse($file);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Dump.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Dump.php
new file mode 100644
index 00000000..4412f03a
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Dump.php
@@ -0,0 +1,36 @@
+data = $data;
+ }
+
+ /**
+ * Return the data as JSON
+ *
+ * @return string
+ */
+ public function result()
+ {
+ ob_start();
+
+ var_dump($this->data);
+
+ $result = ob_get_contents();
+
+ ob_end_clean();
+
+ return $result;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Flank.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Flank.php
new file mode 100644
index 00000000..046bcaf8
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Flank.php
@@ -0,0 +1,74 @@
+str = $str;
+
+ $this->char($char)->repeat($repeat);
+ }
+
+ /**
+ * Set the character(s) to repeat on either side
+ *
+ * @param string $char
+ *
+ * @return Flank
+ */
+ public function char($char)
+ {
+ $this->set('char', $char);
+
+ return $this;
+ }
+
+ /**
+ * Set the repeat of the flank character(s)
+ *
+ * @param integer $repeat
+ *
+ * @return Flank
+ */
+ public function repeat($repeat)
+ {
+ $this->set('repeat', $repeat);
+
+ return $this;
+ }
+
+ /**
+ * Return the flanked string
+ *
+ * @return string
+ */
+ public function result()
+ {
+ $flank = str_repeat($this->char, $this->repeat);
+
+ return "{$flank} {$this->str} {$flank}";
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Inline.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Inline.php
new file mode 100644
index 00000000..9cd8dc5b
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Inline.php
@@ -0,0 +1,16 @@
+data = $data;
+ }
+
+ /**
+ * Return the data as JSON
+ *
+ * @return string
+ */
+ public function result()
+ {
+ return json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Out.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Out.php
new file mode 100644
index 00000000..550b6c45
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Out.php
@@ -0,0 +1,28 @@
+content = $content;
+ }
+
+ /**
+ * Return the content to output
+ *
+ * @return string
+ */
+ public function result()
+ {
+ return $this->content;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Repeatable.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Repeatable.php
new file mode 100644
index 00000000..7d8dacd1
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Repeatable.php
@@ -0,0 +1,18 @@
+count = (int) round(max((int) $count, 1));
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Tab.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Tab.php
new file mode 100644
index 00000000..1eae6cf8
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Tab.php
@@ -0,0 +1,29 @@
+count);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Basic/Table.php b/akamai/vendor/league/climate/src/TerminalObject/Basic/Table.php
new file mode 100644
index 00000000..508b605f
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Basic/Table.php
@@ -0,0 +1,243 @@
+data = $data;
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * Return the built rows
+ *
+ * @return array
+ */
+ public function result()
+ {
+ $this->column_widths = $this->getColumnWidths();
+ $this->table_width = $this->getWidth();
+ $this->border = $this->getBorder();
+
+ $this->buildHeaderRow();
+
+ foreach ($this->data as $key => $columns) {
+ $this->addLine($this->buildRow($columns));
+ $this->addLine($this->border);
+ }
+
+ return $this->rows;
+ }
+
+ /**
+ * Append a line to the output.
+ *
+ * @param string $line The line to output
+ *
+ * @return void
+ */
+ private function addLine($line)
+ {
+ $this->rows[] = $this->prefix . $line;
+ }
+
+
+ /**
+ * Determine the width of the table
+ *
+ * @return integer
+ */
+ protected function getWidth()
+ {
+ $first_row = reset($this->data);
+ $first_row = $this->buildRow($first_row);
+
+ return $this->lengthWithoutTags($first_row);
+ }
+
+ /**
+ * Get the border for each row based on the table width
+ */
+ protected function getBorder()
+ {
+ return (new Border())->length($this->table_width)->result();
+ }
+
+ /**
+ * Check for a header row (if it's an array of associative arrays or objects),
+ * if there is one, tack it onto the front of the rows array
+ */
+ protected function buildHeaderRow()
+ {
+ $this->addLine($this->border);
+
+ $header_row = $this->getHeaderRow();
+ if ($header_row) {
+ $this->addLine($this->buildRow($header_row));
+ $this->addLine((new Border)->char('=')->length($this->table_width)->result());
+ }
+ }
+
+ /**
+ * Get table row
+ *
+ * @param mixed $columns
+ *
+ * @return string
+ */
+ protected function buildRow($columns)
+ {
+ $row = [];
+
+ foreach ($columns as $key => $column) {
+ $row[] = $this->buildCell($key, $column);
+ }
+
+ $row = implode($this->column_divider, $row);
+
+ return trim($this->column_divider . $row . $this->column_divider);
+ }
+
+ /**
+ * Build the string for this particular table cell
+ *
+ * @param mixed $key
+ * @param string $column
+ *
+ * @return string
+ */
+ protected function buildCell($key, $column)
+ {
+ return $this->pad($column, $this->column_widths[$key]);
+ }
+
+ /**
+ * Get the header row for the table if it's an associative array or object
+ *
+ * @return mixed
+ */
+ protected function getHeaderRow()
+ {
+ $first_item = reset($this->data);
+
+ if (is_object($first_item)) {
+ $first_item = get_object_vars($first_item);
+ }
+
+ $keys = array_keys($first_item);
+ $first_key = reset($keys);
+
+ // We have an associative array (probably), let's have a header row
+ if (!is_int($first_key)) {
+ return array_combine($keys, $keys);
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine the width of each column
+ *
+ * @return array
+ */
+ protected function getColumnWidths()
+ {
+ $first_row = reset($this->data);
+
+ if (is_object($first_row)) {
+ $first_row = get_object_vars($first_row);
+ }
+
+ // Create an array with the columns as keys and values of zero
+ $column_widths = $this->getDefaultColumnWidths($first_row);
+
+ foreach ($this->data as $columns) {
+ foreach ($columns as $key => $column) {
+ $column_widths[$key] = $this->getCellWidth($column_widths[$key], $column);
+ }
+ }
+
+ return $column_widths;
+ }
+
+ /**
+ * Set up an array of default column widths
+ *
+ * @param array $columns
+ *
+ * @return array
+ */
+ protected function getDefaultColumnWidths(array $columns)
+ {
+ $widths = $this->arrayOfStrLens(array_keys($columns));
+
+ return array_combine(array_keys($columns), $widths);
+ }
+
+ /**
+ * Determine the width of the columns without tags
+ *
+ * @param array $current_width
+ * @param string $str
+ *
+ * @return integer
+ */
+ protected function getCellWidth($current_width, $str)
+ {
+ return max($current_width, $this->lengthWithoutTags($str));
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Animation.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Animation.php
new file mode 100644
index 00000000..8ab7a092
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Animation.php
@@ -0,0 +1,213 @@
+addDir(__DIR__ . '/../../ASCII');
+
+ $this->setSleeper($sleeper);
+ $this->setKeyFrames($keyframes);
+
+ $this->art = $art;
+ }
+
+ /**
+ * Run a basic animation
+ */
+ public function run()
+ {
+ $files = $this->artDir($this->art);
+ $animation = [];
+
+ foreach ($files as $file) {
+ $animation[] = $this->parse($file);
+ }
+
+ $this->animate($animation);
+ }
+
+ /**
+ * Set the speed of the animation based on a percentage
+ * (50% slower, 200% faster, etc)
+ *
+ * @param int|float $percentage
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Animation
+ */
+ public function speed($percentage)
+ {
+ $this->sleeper->speed($percentage);
+
+ return $this;
+ }
+
+ /**
+ * Scroll the art
+ *
+ * @param string $direction
+ * @return bool
+ */
+ public function scroll($direction = 'right')
+ {
+ $this->setupKeyframes();
+
+ $mapping = $this->getScrollDirectionMapping();
+
+ if (!array_key_exists($direction, $mapping)) {
+ return false;
+ }
+
+ $lines = $this->getLines();
+ $enter_from = $mapping[$direction];
+ $exit_to = $mapping[$enter_from];
+
+ $this->animate($this->keyframes->scroll($lines, $enter_from, $exit_to));
+ }
+
+ /**
+ * Animate the art exiting the screen
+ *
+ * @param string $direction top|bottom|right|left
+ */
+ public function exitTo($direction)
+ {
+ $this->setupKeyframes();
+
+ $this->animate($this->keyframes->exitTo($this->getLines(), $direction));
+ }
+
+ /**
+ * Animate the art entering the screen
+ *
+ * @param string $direction top|bottom|right|left
+ */
+ public function enterFrom($direction)
+ {
+ $this->setupKeyframes();
+
+ $this->animate($this->keyframes->enterFrom($this->getLines(), $direction));
+ }
+
+ protected function getScrollDirectionMapping()
+ {
+ return [
+ 'left' => 'right',
+ 'right' => 'left',
+ 'top' => 'bottom',
+ 'bottom' => 'top',
+ 'up' => 'bottom',
+ 'down' => 'top',
+ ];
+ }
+
+ protected function getLines()
+ {
+ return $this->parse($this->artFile($this->art));
+ }
+
+ /**
+ * @param \League\CLImate\TerminalObject\Helper\Sleeper $sleeper
+ */
+ protected function setSleeper($sleeper = null)
+ {
+ $this->sleeper = $sleeper ?: new Sleeper();
+ }
+
+ /**
+ * @param League\CLImate\TerminalObject\Dynamic\Animation\Keyframe $keyframes
+ */
+ protected function setKeyFrames($keyframes)
+ {
+ $this->keyframes = $keyframes ?: new Keyframe;
+ }
+
+ /**
+ * Set up the necessary properties on the Keyframe class
+ */
+ protected function setupKeyframes()
+ {
+ $this->keyframes->parser($this->parser);
+ $this->keyframes->util($this->util);
+ }
+
+ /**
+ * Animate the given keyframes
+ *
+ * @param array $keyframes Array of arrays
+ */
+ protected function animate(array $keyframes)
+ {
+ $count = 0;
+
+ foreach ($keyframes as $lines) {
+ $this->writeKeyFrame($lines, $count);
+ $this->sleeper->sleep();
+ $count = count($lines);
+ }
+ }
+
+ /**
+ * Write the current keyframe to the terminal, line by line
+ *
+ * @param array $lines
+ * @param integer $count
+ */
+ protected function writeKeyFrame(array $lines, $count)
+ {
+ foreach ($lines as $key => $line) {
+ $content = $this->getLineFormatted($line, $key, $count);
+ $this->output->write($this->parser->apply($content));
+ }
+ }
+
+ /**
+ * Format the line to re-write previous lines, if necessary
+ *
+ * @param string $line
+ * @param integer $key
+ * @param integer $last_frame_count
+ *
+ * @return string
+ */
+ protected function getLineFormatted($line, $key, $last_frame_count)
+ {
+ // If this is the first thing we're writing, just return the line
+ if ($last_frame_count == 0) {
+ return $line;
+ }
+
+ $content = '';
+
+ // If this is the first line of the frame,
+ // move the cursor up the total number of previous lines from the previous frame
+ if ($key == 0) {
+ $content .= $this->util->cursor->up($last_frame_count);
+ }
+
+ $content .= $this->util->cursor->startOfCurrentLine();
+ $content .= $this->util->cursor->deleteCurrentLine();
+ $content .= $line;
+
+ return $content;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Animation/Keyframe.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Animation/Keyframe.php
new file mode 100644
index 00000000..cb9fe398
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Animation/Keyframe.php
@@ -0,0 +1,265 @@
+exitTo($lines, $direction));
+ }
+
+ /**
+ * Get the exit keyframes for the desired direction
+ *
+ * @param array $lines
+ * @param string $direction
+ *
+ * @return array
+ */
+ public function exitTo($lines, $direction)
+ {
+ $lines = $this->adjustLines($lines, $direction);
+ $line_method = $this->getLineMethod($direction);
+
+ $direction_keyframes = $this->getDirectionFrames($direction, $lines, $line_method);
+
+ $keyframes = array_fill(0, 4, $lines);
+ $keyframes = array_merge($keyframes, $direction_keyframes);
+ $keyframes[] = array_fill(0, count($lines), '');
+
+ return $keyframes;
+ }
+
+ /**
+ * Get scroll keyframes
+ *
+ * @param array $lines
+ * @param string $enter_from
+ * @param string $exit_to
+ *
+ * @return array
+ */
+ public function scroll($lines, $enter_from, $exit_to)
+ {
+ $keyframes = $this->enterFrom($lines, $enter_from);
+ $keyframes = array_merge($keyframes, $this->exitTo($lines, $exit_to));
+ $keyframes = array_unique($keyframes, SORT_REGULAR);
+ $keyframes[] = reset($keyframes);
+
+ return $keyframes;
+ }
+
+ /**
+ * Get the line parser for the direction
+ *
+ * @param string $direction
+ * @return string
+ */
+ protected function getLineMethod($direction)
+ {
+ return 'current' . ucwords(strtolower($direction)) . 'Line';
+ }
+
+ /**
+ * Adjust the array of lines if necessary
+ *
+ * @param array $lines
+ * @param string $direction
+ *
+ * @return array
+ */
+ protected function adjustLines(array $lines, $direction)
+ {
+ $adjust_method = 'adjust' . ucwords(strtolower($direction)) . 'Lines';
+
+ if (method_exists($this, $adjust_method)) {
+ return $this->$adjust_method($lines);
+ }
+
+ return $lines;
+ }
+
+ /**
+ * Pad the array of lines for "right" animation
+ *
+ * @param array $lines
+ * @return array
+ */
+ protected function adjustRightLines(array $lines)
+ {
+ return $this->padArray($lines, $this->util->width());
+ }
+
+ /**
+ * Pad the array of lines for "left" animation
+ *
+ * @param array $lines
+ * @return array
+ */
+ protected function adjustLeftLines(array $lines)
+ {
+ return $this->padArray($lines, $this->maxStrLen($lines));
+ }
+
+ /**
+ * Get the keyframes appropriate for the animation direction
+ *
+ * @param string $direction
+ * @param array $lines
+ * @param string $line_method
+ *
+ * @return array
+ */
+ protected function getDirectionFrames($direction, array $lines, $line_method)
+ {
+ $mapping = [
+ 'exitHorizontalFrames' => ['left', 'right'],
+ 'exitVerticalFrames' => ['top', 'bottom'],
+ ];
+
+ foreach ($mapping as $method => $directions) {
+ if (in_array($direction, $directions)) {
+ return $this->$method($lines, $line_method);
+ }
+ }
+
+ // Fail gracefully, simply return an array
+ return [];
+ }
+
+ /**
+ * Create horizontal exit animation keyframes for the art
+ *
+ * @param array $lines
+ * @param string $line_method
+ *
+ * @return array
+ */
+ protected function exitHorizontalFrames(array $lines, $line_method)
+ {
+ $keyframes = [];
+ $length = mb_strlen($lines[0]);
+
+ for ($i = $length; $i > 0; $i--) {
+ $keyframes[] = $this->getHorizontalKeyframe($lines, $i, $line_method, $length);
+ }
+
+ return $keyframes;
+ }
+
+ /**
+ * Get the keyframe for a horizontal animation
+ *
+ * @param array $lines
+ * @param int $frame_number
+ * @param string $line_method
+ * @param int $length
+ *
+ * @return array
+ */
+ protected function getHorizontalKeyframe(array $lines, $frame_number, $line_method, $length)
+ {
+ $keyframe = [];
+
+ foreach ($lines as $line) {
+ $keyframe[] = $this->$line_method($line, $frame_number, $length);
+ }
+
+ return $keyframe;
+ }
+
+ /**
+ * Create vertical exit animation keyframes for the art
+ *
+ * @param array $lines
+ * @param string $line_method
+ *
+ * @return array
+ */
+ protected function exitVerticalFrames(array $lines, $line_method)
+ {
+ $keyframes = [];
+ $line_count = count($lines);
+
+ for ($i = $line_count - 1; $i >= 0; $i--) {
+ $keyframes[] = $this->$line_method($lines, $line_count, $i);
+ }
+
+ return $keyframes;
+ }
+
+ /**
+ * Get the current line as it is exiting left
+ *
+ * @param string $line
+ * @param int $frame_number
+ *
+ * @return string
+ */
+ protected function currentLeftLine($line, $frame_number)
+ {
+ return mb_substr($line, -$frame_number);
+ }
+
+
+ /**
+ * Get the current line as it is exiting right
+ *
+ * @param string $line
+ * @param int $frame_number
+ * @param int $length
+ *
+ * @return string
+ */
+ protected function currentRightLine($line, $frame_number, $length)
+ {
+ return str_repeat(' ', $length - $frame_number) . mb_substr($line, 0, $frame_number);
+ }
+
+ /**
+ * Slice off X number of lines from the bottom and fill the rest with empty strings
+ *
+ * @param array $lines
+ * @param integer $total_lines
+ * @param integer $current
+ *
+ * @return array
+ */
+ protected function currentTopLine($lines, $total_lines, $current)
+ {
+ $keyframe = array_slice($lines, -$current, $current);
+
+ return array_merge($keyframe, array_fill(0, $total_lines - $current, ''));
+ }
+
+ /**
+ * Slice off X number of lines from the top and fill the rest with empty strings
+ *
+ * @param array $lines
+ * @param integer $total_lines
+ * @param integer $current
+ *
+ * @return array
+ */
+ protected function currentBottomLine($lines, $total_lines, $current)
+ {
+ $keyframe = array_fill(0, $total_lines - $current, '');
+
+ return array_merge($keyframe, array_slice($lines, 0, $current));
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/Checkbox.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/Checkbox.php
new file mode 100644
index 00000000..e26101da
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/Checkbox.php
@@ -0,0 +1,219 @@
+value = (!is_int($value)) ? $value : $label;
+ $this->label = $label;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isCurrent()
+ {
+ return $this->current;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isChecked()
+ {
+ return $this->checked;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isFirst()
+ {
+ return $this->first;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isLast()
+ {
+ return $this->last;
+ }
+
+ /**
+ * Set whether the pointer is currently pointing at this checkbox
+ *
+ * @param bool $current
+ *
+ * @return Checkbox
+ */
+ public function setCurrent($current = true)
+ {
+ $this->current = $current;
+
+ return $this;
+ }
+
+ /**
+ * Set whether the checkbox is currently checked
+ *
+ * @param bool $checked
+ *
+ * @return Checkbox
+ */
+ public function setChecked($checked = true)
+ {
+ $this->checked = $checked;
+
+ return $this;
+ }
+
+ /**
+ * @return Checkbox
+ */
+ public function setFirst()
+ {
+ $this->first = true;
+
+ return $this;
+ }
+
+ /**
+ * @return Checkbox
+ */
+ public function setLast()
+ {
+ $this->last = true;
+
+ return $this;
+ }
+
+ /**
+ * @return string|int|bool
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Build out basic checkbox string based on current options
+ *
+ * @return string
+ */
+ protected function buildCheckboxString()
+ {
+ $parts = [
+ ($this->isCurrent()) ? $this->pointer() : ' ',
+ $this->checkbox($this->isChecked()),
+ $this->label,
+ ];
+
+ $line = implode(' ', $parts);
+
+ return $line . $this->getPaddingString($line);
+ }
+
+ /**
+ * Get the padding string based on the length of the terminal/line
+ *
+ * @param string $line
+ *
+ * @return string
+ */
+ protected function getPaddingString($line)
+ {
+ $length = $this->util->system->width() - $this->lengthWithoutTags($line);
+
+ return str_repeat(' ', $length);
+ }
+
+ /**
+ * Get the checkbox symbol
+ *
+ * @param bool $checked
+ *
+ * @return string
+ */
+ protected function checkbox($checked)
+ {
+ if ($checked) {
+ return html_entity_decode("●");
+ }
+
+ return html_entity_decode("○");
+ }
+
+ /**
+ * Get the pointer symbol
+ *
+ * @return string
+ */
+ protected function pointer()
+ {
+ return html_entity_decode("❯");
+ }
+
+ public function __toString()
+ {
+ if ($this->isFirst()) {
+ return $this->buildCheckboxString();
+ }
+
+ if ($this->isLast()) {
+ return $this->buildCheckboxString() . $this->util->cursor->left(10) . '';
+ }
+
+ return $this->buildCheckboxString();
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/CheckboxGroup.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/CheckboxGroup.php
new file mode 100644
index 00000000..3a09d684
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/CheckboxGroup.php
@@ -0,0 +1,191 @@
+ $option) {
+ $this->checkboxes[] = new Checkbox($option, $key);
+ }
+
+ $this->count = count($this->checkboxes);
+
+ $this->checkboxes[0]->setFirst()->setCurrent();
+ $this->checkboxes[$this->count - 1]->setLast();
+ }
+
+ public function write()
+ {
+ array_map([$this, 'writeCheckbox'], $this->checkboxes);
+ }
+
+ /**
+ * Retrieve the checked option values
+ *
+ * @return array
+ */
+ public function getCheckedValues()
+ {
+ return array_values(array_map([$this, 'getValue'], $this->getChecked()));
+ }
+
+ /**
+ * Set the newly selected option based on the direction
+ *
+ * @param string $direction 'previous' or 'next'
+ */
+ public function setCurrent($direction)
+ {
+ list($option, $key) = $this->getCurrent();
+
+ $option->setCurrent(false);
+
+ $new_key = $this->getCurrentKey($direction, $option, $key);
+
+ $this->checkboxes[$new_key]->setCurrent();
+ }
+
+ /**
+ * Toggle the current option's checked status
+ */
+ public function toggleCurrent()
+ {
+ list($option) = $this->getCurrent();
+
+ $option->setChecked(!$option->isChecked());
+ }
+
+ /**
+ * Get the number of checkboxes
+ *
+ * @return int
+ */
+ public function count()
+ {
+ return $this->count;
+ }
+
+ /**
+ * Retrieve the checked options
+ *
+ * @return array
+ */
+ protected function getChecked()
+ {
+ return array_filter($this->checkboxes, [$this, 'isChecked']);
+ }
+
+ /**
+ * Determine whether the option is checked
+ *
+ * @param Checkbox $option
+ *
+ * @return bool
+ */
+ protected function isChecked($option)
+ {
+ return $option->isChecked();
+ }
+
+ /**
+ * Retrieve the option's value
+ *
+ * @param Checkbox $option
+ *
+ * @return mixed
+ */
+ protected function getValue($option)
+ {
+ return $option->getValue();
+ }
+
+ /**
+ * Get the currently selected option
+ *
+ * @return array
+ */
+ protected function getCurrent()
+ {
+ foreach ($this->checkboxes as $key => $option) {
+ if ($option->isCurrent()) {
+ return [$option, $key];
+ }
+ }
+ }
+
+ /**
+ * Retrieve the correct current key
+ *
+ * @param string $direction 'previous' or 'next'
+ * @param Checkbox $option
+ * @param int $key
+ *
+ * @return int
+ */
+ protected function getCurrentKey($direction, $option, $key)
+ {
+ $method = 'get' . ucwords($direction). 'Key';
+
+ return $this->{$method}($option, $key);
+ }
+
+ /**
+ * @param Checkbox $option
+ * @param int $key
+ *
+ * @return int
+ */
+ protected function getPreviousKey($option, $key)
+ {
+ if ($option->isFirst()) {
+ return count($this->checkboxes) - 1;
+ }
+
+ return --$key;
+ }
+
+ /**
+ * @param Checkbox $option
+ * @param int $key
+ *
+ * @return int
+ */
+ protected function getNextKey($option, $key)
+ {
+ if ($option->isLast()) {
+ return 0;
+ }
+
+ return ++$key;
+ }
+
+ /**
+ * @param Checkbox $checkbox
+ */
+ protected function writeCheckbox($checkbox)
+ {
+ $checkbox->util($this->util);
+ $checkbox->parser($this->parser);
+
+ $parsed = $this->parser->apply((string) $checkbox);
+
+ if ($checkbox->isLast()) {
+ $this->output->sameLine()->write($parsed);
+ return;
+ }
+
+ $this->output->write($parsed);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/RadioGroup.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/RadioGroup.php
new file mode 100644
index 00000000..bf086119
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkbox/RadioGroup.php
@@ -0,0 +1,38 @@
+getCurrent();
+
+ $checkbox->setChecked(!$checkbox->isChecked());
+
+ foreach ($this->checkboxes as $key => $checkbox) {
+ if ($key == $checkbox_key) {
+ continue;
+ }
+
+ $checkbox->setChecked(false);
+ }
+ }
+
+ /**
+ * Get the checked option
+ *
+ * @return string|bool|int
+ */
+ public function getCheckedValues()
+ {
+ if ($checked = $this->getChecked()) {
+ return reset($checked)->getValue();
+ }
+
+ return null;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkboxes.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkboxes.php
new file mode 100644
index 00000000..89c3bfe2
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Checkboxes.php
@@ -0,0 +1,159 @@
+prompt = $prompt;
+ $this->reader = $reader ?: new Stdin();
+
+ $this->checkboxes = $this->buildCheckboxes($options);
+ }
+
+ /**
+ * Do it! Prompt the user for information!
+ *
+ * @return string
+ */
+ public function prompt()
+ {
+ $this->output->write($this->parser->apply($this->promptFormatted()));
+
+ $this->writeCheckboxes();
+
+ $this->util->system->exec('stty sane');
+
+ return $this->checkboxes->getCheckedValues();
+ }
+
+ /**
+ * Build out the checkboxes
+ *
+ * @param array $options
+ *
+ * @return Checkbox\CheckboxGroup
+ */
+ protected function buildCheckboxes(array $options)
+ {
+ return new Checkbox\CheckboxGroup($options);
+ }
+
+ /**
+ * Format the prompt string
+ *
+ * @return string
+ */
+ protected function promptFormatted()
+ {
+ return $this->prompt . ' (use to select)';
+ }
+
+ /**
+ * Output the checkboxes and listen for any keystrokes
+ */
+ protected function writeCheckboxes()
+ {
+ $this->updateCheckboxView();
+
+ $this->util->system->exec('stty -icanon');
+ $this->output->sameLine()->write($this->util->cursor->hide());
+
+ $this->listenForInput();
+ }
+
+ /**
+ * Listen for input and act on it
+ */
+ protected function listenForInput()
+ {
+ while ($char = $this->reader->char(1)) {
+ if ($this->handleCharacter($char)) {
+ break;
+ }
+
+ $this->moveCursorToTop();
+ $this->updateCheckboxView();
+ }
+ }
+
+ /**
+ * Take the appropriate action based on the input character,
+ * returns whether to stop listening or not
+ *
+ * @param string $char
+ *
+ * @return bool
+ */
+ protected function handleCharacter($char)
+ {
+ switch ($char) {
+ case "\n":
+ $this->output->sameLine()->write($this->util->cursor->defaultStyle());
+ $this->output->sameLine()->write("\e[0m");
+ return true; // Break the while loop as well
+
+ case "\e":
+ $this->handleAnsi();
+ break;
+
+ case ' ':
+ $this->checkboxes->toggleCurrent();
+ break;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move the cursor to the top of the option list
+ */
+ protected function moveCursorToTop()
+ {
+ $output = $this->util->cursor->up($this->checkboxes->count() - 1);
+ $output .= $this->util->cursor->startOfCurrentLine();
+
+ $this->output->sameLine()->write($output);
+ }
+
+ /**
+ * Handle any ANSI characters
+ */
+ protected function handleAnsi()
+ {
+ switch ($this->reader->char(2)) {
+ // Up arrow
+ case '[A':
+ $this->checkboxes->setCurrent('previous');
+ break;
+
+ // Down arrow
+ case '[B':
+ $this->checkboxes->setCurrent('next');
+ break;
+ }
+ }
+
+ /**
+ * Re-write the checkboxes based on the current objects
+ */
+ protected function updateCheckboxView()
+ {
+ $this->checkboxes->util($this->util);
+ $this->checkboxes->output($this->output);
+ $this->checkboxes->parser($this->parser);
+
+ $this->checkboxes->write();
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Confirm.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Confirm.php
new file mode 100644
index 00000000..61ad0aa8
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Confirm.php
@@ -0,0 +1,19 @@
+accept(['y', 'n'], true);
+ $this->strict();
+
+ return ($this->prompt() == 'y');
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/DynamicTerminalObject.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/DynamicTerminalObject.php
new file mode 100644
index 00000000..c8f8751d
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/DynamicTerminalObject.php
@@ -0,0 +1,18 @@
+prompt = $prompt;
+ $this->reader = $reader ?: new Stdin();
+ }
+
+ /**
+ * Do it! Prompt the user for information!
+ *
+ * @return string
+ */
+ public function prompt()
+ {
+ $this->writePrompt();
+
+ $response = $this->valueOrDefault($this->getUserInput());
+
+ if ($this->isValidResponse($response)) {
+ return $response;
+ }
+
+ return $this->prompt();
+ }
+
+ /**
+ * Define the acceptable responses and whether or not to
+ * display them to the user
+ *
+ * @param array|object $acceptable
+ * @param boolean $show
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Input
+ */
+ public function accept($acceptable, $show = false)
+ {
+ $this->acceptable = $acceptable;
+ $this->show_acceptable = $show;
+
+ return $this;
+ }
+
+ /**
+ * Define whether we should be strict about exact responses
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Input
+ */
+ public function strict()
+ {
+ $this->strict = true;
+
+ return $this;
+ }
+
+ /**
+ * Set a default response
+ *
+ * @param string $default
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Input
+ */
+ public function defaultTo($default)
+ {
+ $this->default = $default;
+
+ return $this;
+ }
+
+ /**
+ * Set multiline input to true
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Input
+ */
+ public function multiLine()
+ {
+ $this->multiLine = true;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ protected function getUserInput()
+ {
+ if ($this->multiLine) {
+ return $this->reader->multiLine();
+ }
+
+ return $this->reader->line();
+ }
+
+ /**
+ * Write out the formatted prompt
+ */
+ protected function writePrompt()
+ {
+ $prompt = $this->parser->apply($this->promptFormatted());
+
+ $this->output->sameLine()->write($prompt);
+ }
+
+ /**
+ * If no response was given and there is a default, return it,
+ * otherwise return response
+ *
+ * @param string $response
+ *
+ * @return string
+ */
+ protected function valueOrDefault($response)
+ {
+ if (strlen($response) == 0 && strlen($this->default)) {
+ return $this->default;
+ }
+
+ return $response;
+ }
+
+ /**
+ * Format the acceptable responses as options
+ *
+ * @return string
+ */
+ protected function acceptableFormatted()
+ {
+ if (!is_array($this->acceptable)) {
+ return '';
+ }
+
+ $acceptable = array_map([$this, 'acceptableItemFormatted'], $this->acceptable);
+
+ return '[' . implode('/', $acceptable) . ']';
+ }
+
+ /**
+ * Format the acceptable item depending on whether it is the default or not
+ *
+ * @param string $item
+ *
+ * @return string
+ */
+ protected function acceptableItemFormatted($item)
+ {
+ if ($item == $this->default) {
+ return '' . $item . '';
+ }
+
+ return $item;
+ }
+
+ /**
+ * Format the prompt incorporating spacing and any acceptable options
+ *
+ * @return string
+ */
+ protected function promptFormatted()
+ {
+ $prompt = $this->prompt . ' ';
+
+ if ($this->show_acceptable) {
+ $prompt .= $this->acceptableFormatted() . ' ';
+ }
+
+ return $prompt;
+ }
+
+ /**
+ * Apply some string manipulation functions for normalization
+ *
+ * @param string|array $var
+ * @return array
+ */
+ protected function levelPlayingField($var)
+ {
+ $levelers = ['trim', 'mb_strtolower'];
+
+ foreach ($levelers as $leveler) {
+ if (is_array($var)) {
+ $var = array_map($leveler, $var);
+ } else {
+ $var = $leveler($var);
+ }
+ }
+
+ return $var;
+ }
+
+ /**
+ * Determine whether or not the acceptable property is of type closure
+ *
+ * @return boolean
+ */
+ protected function acceptableIsClosure()
+ {
+ return (is_object($this->acceptable) && $this->acceptable instanceof \Closure);
+ }
+
+ /**
+ * Determine if the user's response is in the acceptable responses array
+ *
+ * @param string $response
+ *
+ * @return boolean $response
+ */
+ protected function isAcceptableResponse($response)
+ {
+ if ($this->strict) {
+ return in_array($response, $this->acceptable);
+ }
+
+ $acceptable = $this->levelPlayingField($this->acceptable);
+ $response = $this->levelPlayingField($response);
+
+ return in_array($response, $acceptable);
+ }
+
+ /**
+ * Determine if the user's response is valid based on the current settings
+ *
+ * @param string $response
+ *
+ * @return boolean $response
+ */
+ protected function isValidResponse($response)
+ {
+ if (empty($this->acceptable)) {
+ return true;
+ }
+
+ if ($this->acceptableIsClosure()) {
+ return call_user_func($this->acceptable, $response);
+ }
+
+ return $this->isAcceptableResponse($response);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/InputAbstract.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/InputAbstract.php
new file mode 100644
index 00000000..230ed61e
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/InputAbstract.php
@@ -0,0 +1,37 @@
+length($length);
+ }
+
+ if (is_string($char)) {
+ $this->char($char);
+ }
+ }
+
+ /**
+ * Set the character(s) that should be used to pad
+ *
+ * @param string $char
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Padding
+ */
+ public function char($char)
+ {
+ $this->char = $char;
+
+ return $this;
+ }
+
+ /**
+ * Set the length of the line that should be generated
+ *
+ * @param integer $length
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Padding
+ */
+ public function length($length)
+ {
+ $this->length = $length;
+
+ return $this;
+ }
+
+ /**
+ * Get the length of the line based on the width of the terminal window
+ *
+ * @return integer
+ */
+ protected function getLength()
+ {
+ if (!$this->length) {
+ $this->length = $this->util->width();
+ }
+
+ return $this->length;
+ }
+
+ /**
+ * Pad the content with the characters
+ *
+ * @param string $content
+ *
+ * @return string
+ */
+ protected function padContent($content)
+ {
+ if (strlen($this->char) > 0) {
+ $length = $this->getLength();
+ $padding_length = ceil($length / mb_strlen($this->char));
+
+ $padding = str_repeat($this->char, $padding_length);
+ $content .= mb_substr($padding, 0, $length - mb_strlen($content));
+ }
+
+ return $content;
+ }
+
+ /**
+ * Output the content and pad to the previously defined length
+ *
+ * @param string $content
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\Padding
+ */
+ public function label($content)
+ {
+ // Handle long labels by splitting them across several lines
+ $lines = [];
+ $stop = mb_strlen($content);
+ $width = $this->util->width();
+ for ($i = 0; $i < $stop; $i += $width) {
+ $lines[] = mb_substr($content, $i, $width);
+ }
+ $content = array_pop($lines);
+
+ foreach ($lines as $line) {
+ $this->output->write($this->parser->apply($line));
+ }
+
+ $content = $this->padContent($content);
+ $content = $this->parser->apply($content);
+
+ $this->output->sameLine();
+ $this->output->write($content);
+
+ return $this;
+ }
+
+ /**
+ * Output result
+ *
+ * @param string $content
+ */
+ public function result($content)
+ {
+ $this->output->write($this->parser->apply(' ' . $content));
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Password.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Password.php
new file mode 100644
index 00000000..a8d714cc
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Password.php
@@ -0,0 +1,13 @@
+writePrompt();
+
+ return $this->reader->hidden();
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Progress.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Progress.php
new file mode 100644
index 00000000..a6a6a705
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Progress.php
@@ -0,0 +1,311 @@
+total($total);
+ }
+ }
+
+ /**
+ * Set the total property
+ *
+ * @param integer $total
+ *
+ * @return Progress
+ */
+ public function total($total)
+ {
+ $this->total = $total;
+
+ return $this;
+ }
+
+ /**
+ * Determines the current percentage we are at and re-writes the progress bar
+ *
+ * @param integer $current
+ * @param mixed $label
+ * @throws \Exception
+ */
+ public function current($current, $label = null)
+ {
+ if ($this->total == 0) {
+ // Avoid dividing by 0
+ throw new \Exception('The progress total must be greater than zero.');
+ }
+
+ if ($current > $this->total) {
+ throw new \Exception('The current is greater than the total.');
+ }
+
+ $this->drawProgressBar($current, $label);
+
+ $this->current = $current;
+ $this->label = $label;
+ }
+
+ /**
+ * Increments the current position we are at and re-writes the progress bar
+ *
+ * @param integer $increment The number of items to increment by
+ * @param string $label
+ */
+ public function advance($increment = 1, $label = null)
+ {
+ $this->current($this->current + $increment, $label);
+ }
+
+ /**
+ * Force the progress bar to redraw every time regardless of whether it has changed or not
+ *
+ * @param boolean $force
+ * @return Progress
+ */
+ public function forceRedraw($force = true)
+ {
+ $this->force_redraw = !!$force;
+
+ return $this;
+ }
+
+
+ /**
+ * Update a progress bar using an iterable.
+ *
+ * @param iterable $items Array or any other iterable object
+ * @param callable $callback A handler to run on each item
+ */
+ public function each($items, callable $callback = null)
+ {
+ if ($items instanceof \Traversable) {
+ $items = iterator_to_array($items);
+ }
+
+ $total = count($items);
+ if (!$total) {
+ return;
+ }
+ $this->total($total);
+
+ foreach ($items as $key => $item) {
+ if ($callback) {
+ $label = $callback($item, $key);
+ } else {
+ $label = null;
+ }
+
+ $this->advance(1, $label);
+ }
+ }
+
+
+ /**
+ * Draw the progress bar, if necessary
+ *
+ * @param string $current
+ * @param string $label
+ */
+ protected function drawProgressBar($current, $label)
+ {
+ $percentage = $this->percentageFormatted($current / $this->total);
+
+ if ($this->shouldRedraw($percentage, $label)) {
+ $progress_bar = $this->getProgressBar($current, $label);
+ $this->output->write($this->parser->apply($progress_bar));
+ }
+
+ $this->current_percentage = $percentage;
+ }
+
+ /**
+ * Build the progress bar str and return it
+ *
+ * @param integer $current
+ * @param string $label
+ *
+ * @return string
+ */
+ protected function getProgressBar($current, $label)
+ {
+ if ($this->first_line) {
+ // Drop down a line, we are about to
+ // re-write this line for the progress bar
+ $this->output->write('');
+ $this->first_line = false;
+ }
+
+ // Move the cursor up and clear it to the end
+ $line_count = $this->has_label_line ? 2 : 1;
+
+ $progress_bar = $this->util->cursor->up($line_count);
+ $progress_bar .= $this->util->cursor->startOfCurrentLine();
+ $progress_bar .= $this->util->cursor->deleteCurrentLine();
+ $progress_bar .= $this->getProgressBarStr($current, $label);
+
+ // If this line has a label then set that this progress bar has a label line
+ if (strlen($label) > 0) {
+ $this->has_label_line = true;
+ }
+
+ return $progress_bar;
+ }
+
+ /**
+ * Get the progress bar string, basically:
+ * =============> 50% label
+ *
+ * @param integer $current
+ * @param string $label
+ *
+ * @return string
+ */
+ protected function getProgressBarStr($current, $label)
+ {
+ $percentage = $current / $this->total;
+ $bar_length = round($this->getBarStrLen() * $percentage);
+
+ $bar = $this->getBar($bar_length);
+ $number = $this->percentageFormatted($percentage);
+
+ if ($label) {
+ $label = $this->labelFormatted($label);
+ // If this line doesn't have a label, but we've had one before,
+ // then ensure the label line is cleared
+ } elseif ($this->has_label_line) {
+ $label = $this->labelFormatted('');
+ }
+
+ return trim("{$bar} {$number}{$label}");
+ }
+
+ /**
+ * Get the string for the actual bar based on the current length
+ *
+ * @param integer $length
+ *
+ * @return string
+ */
+ protected function getBar($length)
+ {
+ $bar = str_repeat('=', $length);
+ $padding = str_repeat(' ', $this->getBarStrLen() - $length);
+
+ return "{$bar}>{$padding}";
+ }
+
+ /**
+ * Get the length of the bar string based on the width of the terminal window
+ *
+ * @return integer
+ */
+ protected function getBarStrLen()
+ {
+ if (!$this->bar_str_len) {
+ // Subtract 10 because of the '> 100%' plus some padding, max 100
+ $this->bar_str_len = min($this->util->width() - 10, 100);
+ }
+
+ return $this->bar_str_len;
+ }
+
+ /**
+ * Format the percentage so it looks pretty
+ *
+ * @param integer $percentage
+ * @return float
+ */
+ protected function percentageFormatted($percentage)
+ {
+ return round($percentage * 100) . '%';
+ }
+
+ /**
+ * Format the label so it is positioned correctly
+ *
+ * @param string $label
+ * @return string
+ */
+ protected function labelFormatted($label)
+ {
+ return "\n" . $this->util->cursor->startOfCurrentLine() . $this->util->cursor->deleteCurrentLine() . $label;
+ }
+
+ /**
+ * Determine whether the progress bar has changed and we need to redrew
+ *
+ * @param string $percentage
+ * @param string $label
+ *
+ * @return boolean
+ */
+ protected function shouldRedraw($percentage, $label)
+ {
+ return ($this->force_redraw || $percentage != $this->current_percentage || $label != $this->label);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Radio.php b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Radio.php
new file mode 100644
index 00000000..097be145
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Dynamic/Radio.php
@@ -0,0 +1,18 @@
+dirs as $dir) {
+ $this->addDir($dir);
+ }
+ }
+
+ /**
+ * Add a directory to search for art in
+ *
+ * @param string $dir
+ */
+ protected function addDir($dir)
+ {
+ // Add any additional directories to the top of the array
+ // so that the user can override art
+ array_unshift($this->art_dirs, rtrim($dir, '/'));
+
+ // Keep the array clean
+ $this->art_dirs = array_unique($this->art_dirs);
+ $this->art_dirs = array_filter($this->art_dirs);
+ $this->art_dirs = array_values($this->art_dirs);
+ }
+
+ /**
+ * Find a valid art path
+ *
+ * @param string $art
+ *
+ * @return array
+ */
+ protected function artDir($art)
+ {
+ return $this->fileSearch($art, '/*.*');
+ }
+
+ /**
+ * Find a valid art path
+ *
+ * @param string $art
+ *
+ * @return string
+ */
+ protected function artFile($art)
+ {
+ $files = $this->fileSearch($art, '.*');
+
+ if (count($files) === 0) {
+ $this->addDir(__DIR__ . '/../../ASCII');
+ $files = $this->fileSearch($this->default_art, '.*');
+ }
+
+ if (count($files) === 0) {
+ throw new \UnexpectedValueException("Unable to find an art file with the name '{$art}'");
+ }
+
+ return reset($files);
+ }
+
+ /**
+ * Find a set of files in the current art directories
+ * based on a pattern
+ *
+ * @param string $art
+ * @param string $pattern
+ *
+ * @return array
+ */
+ protected function fileSearch($art, $pattern)
+ {
+ foreach ($this->art_dirs as $dir) {
+ $directory_iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir));
+
+ $paths = [];
+ $regex = '~' . preg_quote($art) . $pattern . '~';
+
+ foreach ($directory_iterator as $file) {
+ if ($file->isDir()) {
+ continue;
+ }
+
+ // Look for anything that has the $art filename
+ if (preg_match($regex, $file)) {
+ $paths[] = $file->getPathname();
+ }
+ }
+
+ asort($paths);
+
+ // If we've got one, no need to look any further
+ if (!empty($paths)) {
+ return $paths;
+ }
+ }
+
+ return [];
+ }
+
+ /**
+ * Parse the contents of the file and return each line
+ *
+ * @param string $path
+ *
+ * @return array
+ */
+ protected function parse($path)
+ {
+ $output = file_get_contents($path);
+ $output = explode("\n", $output);
+ $output = array_map('rtrim', $output);
+
+ return $output;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Helper/Sleeper.php b/akamai/vendor/league/climate/src/TerminalObject/Helper/Sleeper.php
new file mode 100644
index 00000000..b0ae6398
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Helper/Sleeper.php
@@ -0,0 +1,37 @@
+ 0) {
+ $this->speed *= (100 / $percentage);
+ }
+
+ return $this->speed;
+ }
+
+ /**
+ * Sleep for the specified amount of time
+ */
+ public function sleep()
+ {
+ usleep($this->speed);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Helper/SleeperInterface.php b/akamai/vendor/league/climate/src/TerminalObject/Helper/SleeperInterface.php
new file mode 100644
index 00000000..b18135ab
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Helper/SleeperInterface.php
@@ -0,0 +1,13 @@
+ignore_tags)) {
+ $this->ignore_tags = array_keys($this->parser->tags->all());
+ }
+ }
+
+ /**
+ * Determine the length of the string without any tags
+ *
+ * @param string $str
+ *
+ * @return integer
+ */
+ protected function lengthWithoutTags($str)
+ {
+ $this->setIgnoreTags();
+
+ return mb_strwidth($this->withoutTags($str), 'UTF-8');
+ }
+
+ /**
+ * Get the string without the tags that are to be ignored
+ *
+ * @param string $str
+ *
+ * @return string
+ */
+ protected function withoutTags($str)
+ {
+ $this->setIgnoreTags();
+
+ return str_replace($this->ignore_tags, '', $str);
+ }
+
+ /**
+ * Apply padding to a string
+ *
+ * @param string $str
+ * @param string $final_length
+ * @param string $padding_side
+ *
+ * @return string
+ */
+ protected function pad($str, $final_length, $padding_side = 'right')
+ {
+ $padding = $final_length - $this->lengthWithoutTags($str);
+
+ if ($padding_side == 'left') {
+ return str_repeat(' ', $padding) . $str;
+ }
+
+ return $str . str_repeat(' ', $padding);
+ }
+
+ /**
+ * Apply padding to an array of strings
+ *
+ * @param array $arr
+ * @param integer $final_length
+ * @param string $padding_side
+ *
+ * @return array
+ */
+ protected function padArray($arr, $final_length, $padding_side = 'right')
+ {
+ foreach ($arr as $key => $value) {
+ $arr[$key] = $this->pad($value, $final_length, $padding_side);
+ }
+
+ return $arr;
+ }
+
+ /**
+ * Find the max string length in an array
+ *
+ * @param array $arr
+ * @return int
+ */
+ protected function maxStrLen(array $arr)
+ {
+ return max($this->arrayOfStrLens($arr));
+ }
+
+ /**
+ * Get an array of the string lengths from an array of strings
+ *
+ * @param array $arr
+ * @return array
+ */
+ protected function arrayOfStrLens(array $arr)
+ {
+ return array_map([$this, 'lengthWithoutTags'], $arr);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Router/BaseRouter.php b/akamai/vendor/league/climate/src/TerminalObject/Router/BaseRouter.php
new file mode 100644
index 00000000..cabbc7b7
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Router/BaseRouter.php
@@ -0,0 +1,89 @@
+extensions[$key] = $class;
+ }
+
+ /**
+ * Get the full path for the class based on the key
+ *
+ * @param string $class
+ *
+ * @return string
+ */
+ public function path($class)
+ {
+ return $this->getExtension($class) ?: $this->getPath($this->shortName($class));
+ }
+
+ /**
+ * Determines if the requested class is a
+ * valid terminal object class
+ *
+ * @param string $class
+ *
+ * @return boolean
+ */
+ public function exists($class)
+ {
+ $class = $this->path($class);
+
+ return (is_object($class) || class_exists($class));
+ }
+
+ /**
+ * Get the full path for the terminal object class
+ *
+ * @param string $class
+ *
+ * @return string
+ */
+ protected function getPath($class)
+ {
+ return 'League\CLImate\TerminalObject\\' . $this->pathPrefix() . '\\' . $class;
+ }
+
+ /**
+ * Get an extension by its key
+ *
+ * @param string $key
+ *
+ * @return string|false Full class path to extension
+ */
+ protected function getExtension($key)
+ {
+ if (array_key_exists($key, $this->extensions)) {
+ return $this->extensions[$key];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the class short name
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ protected function shortName($name)
+ {
+ $name = str_replace('_', ' ', $name);
+ $name = ucwords($name);
+
+ return str_replace(' ', '', $name);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Router/BasicRouter.php b/akamai/vendor/league/climate/src/TerminalObject/Router/BasicRouter.php
new file mode 100644
index 00000000..a30b9c97
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Router/BasicRouter.php
@@ -0,0 +1,42 @@
+result());
+
+ $this->output->persist();
+
+ foreach ($results as $result) {
+ if ($obj->sameLine()) {
+ $this->output->sameLine();
+ }
+
+ $this->output->write($obj->getParser()->apply($result));
+ }
+
+ $this->output->persist(false);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Router/DynamicRouter.php b/akamai/vendor/league/climate/src/TerminalObject/Router/DynamicRouter.php
new file mode 100644
index 00000000..8456fb7d
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Router/DynamicRouter.php
@@ -0,0 +1,32 @@
+output($this->output);
+
+ return $obj;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Router/ExtensionCollection.php b/akamai/vendor/league/climate/src/TerminalObject/Router/ExtensionCollection.php
new file mode 100644
index 00000000..52b59bec
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Router/ExtensionCollection.php
@@ -0,0 +1,145 @@
+ [], 'dynamic' => []];
+
+ /**
+ * @var string $basic_interface
+ */
+ protected $basic_interface = 'League\CLImate\TerminalObject\Basic\BasicTerminalObjectInterface';
+
+ /**
+ * @var string $dynamic_interface
+ */
+ protected $dynamic_interface = 'League\CLImate\TerminalObject\Dynamic\DynamicTerminalObjectInterface';
+
+ public function __construct($key, $class)
+ {
+ $this->createCollection($key, $class);
+ }
+
+ public function collection()
+ {
+ return $this->collection;
+ }
+
+ /**
+ * Create the collection from the key/class
+ *
+ * @param string $original_key
+ * @param string|object|array $original_class
+ *
+ * @return type
+ */
+ protected function createCollection($original_key, $original_class)
+ {
+ $collection = $this->convertToArray($original_key, $original_class);
+
+ foreach ($collection as $key => $class) {
+ $this->validateExtension($class);
+ $this->collection[$this->getType($class)][$this->getKey($key, $class)] = $class;
+ }
+ }
+
+ /**
+ * Convert the given class and key to an array of classes
+ *
+ * @param string|object|array $class
+ * @param string $key Optional custom key instead of class name
+ *
+ * @return array
+ */
+ protected function convertToArray($key, $class)
+ {
+ if (is_array($class)) {
+ return $class;
+ }
+
+ return [$this->getKey($key, $class) => $class];
+ }
+
+ /**
+ * Ensure that the extension is valid
+ *
+ * @param string|object|array $class
+ */
+ protected function validateExtension($class)
+ {
+ $this->validateClassExists($class);
+ $this->validateClassImplementation($class);
+ }
+
+ /**
+ * @param string|object $class
+ *
+ * @throws \Exception if extension class does not exist
+ */
+ protected function validateClassExists($class)
+ {
+ if (is_string($class) && !class_exists($class)) {
+ throw new \Exception('Class does not exist: ' . $class);
+ }
+ }
+
+ /**
+ * @param string|object $class
+ *
+ * @throws \Exception if extension class does not implement either Dynamic or Basic interface
+ */
+ protected function validateClassImplementation($class)
+ {
+ $str_class = is_string($class);
+
+ $valid_implementation = (is_a($class, $this->basic_interface, $str_class)
+ || is_a($class, $this->dynamic_interface, $str_class));
+
+ if (!$valid_implementation) {
+ throw new \Exception('Class must implement either '
+ . $this->basic_interface . ' or ' . $this->dynamic_interface);
+ }
+ }
+
+ /**
+ * Determine the extension key based on the class
+ *
+ * @param string|null $key
+ * @param string|object $class
+ *
+ * @return string
+ */
+ protected function getKey($key, $class)
+ {
+ if ($key === null || !is_string($key)) {
+ $class_path = (is_string($class)) ? $class : get_class($class);
+
+ $key = explode('\\', $class_path);
+ $key = end($key);
+ }
+
+ return Helper::snakeCase($key);
+ }
+
+ /**
+ * Get the type of class the extension implements
+ *
+ * @param string|object $class
+ *
+ * @return string 'basic' or 'dynamic'
+ */
+ protected function getType($class)
+ {
+ if (is_a($class, $this->basic_interface, is_string($class))) {
+ return 'basic';
+ }
+
+ return 'dynamic';
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Router/Router.php b/akamai/vendor/league/climate/src/TerminalObject/Router/Router.php
new file mode 100644
index 00000000..0edc6409
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Router/Router.php
@@ -0,0 +1,157 @@
+dynamic = $dynamic ?: new DynamicRouter();
+ $this->basic = $basic ?: new BasicRouter();
+ }
+
+ /**
+ * Register a custom class with the router
+ *
+ * @param string $key
+ * @param string $class
+ */
+ public function addExtension($key, $class)
+ {
+ $extension = new ExtensionCollection($key, $class);
+
+ foreach ($extension->collection() as $obj_type => $collection) {
+ foreach ($collection as $obj_key => $obj_class) {
+ $this->{$obj_type}->addExtension($obj_key, $obj_class);
+ }
+ }
+ }
+
+ /**
+ * Check if the name matches an existing terminal object
+ *
+ * @param string $name
+ *
+ * @return boolean
+ */
+ public function exists($name)
+ {
+ return ($this->basic->exists($name) || $this->dynamic->exists($name));
+ }
+
+ /**
+ * Execute a terminal object using given arguments
+ *
+ * @param string $name
+ * @param mixed $arguments
+ *
+ * @return null|\League\CLImate\TerminalObject\Basic\BasicTerminalObjectInterface
+ */
+ public function execute($name, $arguments)
+ {
+ $router = $this->getRouter($name);
+
+ $router->output($this->output);
+
+ $obj = $this->getObject($router, $name, $arguments);
+
+ $obj->parser($this->parser);
+ $obj->util($this->util);
+
+ // If the object needs any settings, import them
+ foreach ($obj->settings() as $obj_setting) {
+ $setting = $this->settings->get($obj_setting);
+
+ if ($setting) {
+ $obj->importSetting($setting);
+ }
+ }
+
+ return $router->execute($obj);
+ }
+
+ /**
+ * Get the object whether it's a string or already instantiated
+ *
+ * @param \League\CLImate\TerminalObject\Router\RouterInterface $router
+ * @param string $name
+ * @param array $arguments
+ *
+ * @return \League\CLImate\TerminalObject\Dynamic\DynamicTerminalObjectInterface|\League\CLImate\TerminalObject\Basic\BasicTerminalObjectInterface
+ */
+ protected function getObject($router, $name, $arguments)
+ {
+ $obj = $router->path($name);
+
+ if (is_string($obj)) {
+ $obj = (new \ReflectionClass($obj))->newInstanceArgs($arguments);
+ }
+
+ if (method_exists($obj, 'arguments')) {
+ call_user_func_array([$obj, 'arguments'], $arguments);
+ }
+
+ return $obj;
+ }
+
+ /**
+ * Determine which type of router we are using and return it
+ *
+ * @param string $name
+ *
+ * @return \League\CLImate\TerminalObject\Router\RouterInterface|null
+ */
+ protected function getRouter($name)
+ {
+ if ($this->basic->exists($name)) {
+ return $this->basic;
+ }
+
+ if ($this->dynamic->exists($name)) {
+ return $this->dynamic;
+ }
+ }
+
+ /**
+ * Set the settings property
+ *
+ * @param \League\CLImate\Settings\Manager $settings
+ *
+ * @return Router
+ */
+ public function settings(Manager $settings)
+ {
+ $this->settings = $settings;
+
+ return $this;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/TerminalObject/Router/RouterInterface.php b/akamai/vendor/league/climate/src/TerminalObject/Router/RouterInterface.php
new file mode 100644
index 00000000..218f8ae0
--- /dev/null
+++ b/akamai/vendor/league/climate/src/TerminalObject/Router/RouterInterface.php
@@ -0,0 +1,29 @@
+add('out', new Writer\StdOut);
+ $this->add('error', new Writer\StdErr);
+ $this->add('buffer', new Writer\Buffer);
+
+ $this->defaultTo('out');
+ }
+
+ /**
+ * Dictate that a new line should not be added after the output
+ */
+ public function sameLine()
+ {
+ $this->new_line = false;
+
+ return $this;
+ }
+
+ /**
+ * Add a writer to the available writers
+ *
+ * @param string $key
+ * @param WriterInterface|array $writer
+ *
+ * @return \League\CLImate\Util\Output
+ */
+ public function add($key, $writer)
+ {
+ $this->writers[$key] = $this->resolve(Helper::toArray($writer));
+
+ return $this;
+ }
+
+ /**
+ * Set the default writer
+ *
+ * @param string|array $keys
+ */
+ public function defaultTo($keys)
+ {
+ $this->default = $this->getWriters($keys);
+ }
+
+ /**
+ * Add a default writer
+ *
+ * @param string|array $keys
+ */
+ public function addDefault($keys)
+ {
+ $this->default = array_merge($this->default, $this->getWriters($keys));
+ }
+
+ /**
+ * Register a writer to be used just once
+ *
+ * @param string|array $keys
+ *
+ * @return \League\CLImate\Util\Output
+ */
+ public function once($keys)
+ {
+ $this->once = $this->getWriters($keys);
+
+ return $this;
+ }
+
+ /**
+ * Persist or un-persist one time writers (for multi-line output)
+ *
+ * @param bool $persist
+ *
+ * @return \League\CLImate\Util\Output
+ */
+ public function persist($persist = true)
+ {
+ $this->persist = (bool) $persist;
+
+ if (!$this->persist) {
+ $this->resetOneTimers();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get a specific writer
+ *
+ * @throws \Exception if writer key doesn't exist
+ * @param string $writer
+ *
+ * @return WriterInterface|array
+ */
+ public function get($writer)
+ {
+ if (!array_key_exists($writer, $this->writers)) {
+ throw new \Exception('Unknown writer [' . $writer . ']');
+ }
+
+ if (count($this->writers[$writer]) == 1) {
+ return reset($this->writers[$writer]);
+ }
+
+ return $this->writers[$writer];
+ }
+
+ /**
+ * Get the currently available writers
+ *
+ * @return array
+ */
+ public function getAvailable()
+ {
+ $writers = [];
+
+ foreach ($this->writers as $key => $writer) {
+ $writers[$key] = $this->getReadable($writer);
+ }
+
+ return $writers;
+ }
+
+ /**
+ * Write the content using the provided writer
+ *
+ * @param string $content
+ */
+ public function write($content)
+ {
+ if ($this->new_line) {
+ $content .= PHP_EOL;
+ }
+
+ foreach ($this->getCurrentWriters() as $writer) {
+ $writer->write($content);
+ }
+
+ $this->resetOneTimers();
+ }
+
+ /**
+ * Resolve the writer(s) down to an array of WriterInterface classes
+ *
+ * @param WriterInterface|array|string $writer
+ *
+ * @return array
+ */
+ protected function resolve($writer)
+ {
+ $resolver = 'resolve' . ucwords(gettype($writer)) . 'Writer';
+
+ if (method_exists($this, $resolver) && $resolved = $this->{$resolver}($writer)) {
+ return $resolved;
+ }
+
+ $this->handleUnknownWriter($writer);
+ }
+
+ /**
+ * @param array $writer
+ *
+ * @return array
+ */
+ protected function resolveArrayWriter($writer)
+ {
+ return Helper::flatten(array_map([$this, 'resolve'], $writer));
+ }
+
+ /**
+ * @param object $writer
+ *
+ * @return WriterInterface|false
+ */
+ protected function resolveObjectWriter($writer)
+ {
+ if ($writer instanceof WriterInterface) {
+ return $writer;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string $writer
+ *
+ * @return array|false
+ */
+ protected function resolveStringWriter($writer)
+ {
+ if (is_string($writer) && array_key_exists($writer, $this->writers)) {
+ return $this->writers[$writer];
+ }
+
+ return false;
+ }
+
+ /**
+ * @param mixed $writer
+ * @throws \Exception For non-valid writer
+ */
+ protected function handleUnknownWriter($writer)
+ {
+ // If we've gotten this far and don't know what it is,
+ // let's at least try and give a helpful error message
+ if (is_object($writer)) {
+ throw new \Exception('Class [' . get_class($writer) . '] must implement '
+ . 'League\CLImate\Util\Writer\WriterInterface.');
+ }
+
+ // No idea, just tell them we can't resolve it
+ throw new \Exception('Unable to resolve writer [' . $writer . ']');
+ }
+
+ /**
+ * Get the readable version of the writer(s)
+ *
+ * @param array $writer
+ *
+ * @return string|array
+ */
+ protected function getReadable(array $writer)
+ {
+ $classes = array_map('get_class', $writer);
+
+ if (count($classes) == 1) {
+ return reset($classes);
+ }
+
+ return $classes;
+ }
+
+ /**
+ * Get the writers based on their keys
+ *
+ * @param string|array $keys
+ *
+ * @return array
+ */
+ protected function getWriters($keys)
+ {
+ $writers = array_flip(Helper::toArray($keys));
+
+ return Helper::flatten(array_intersect_key($this->writers, $writers));
+ }
+
+ /**
+ * @return WriterInterface[]
+ */
+ protected function getCurrentWriters()
+ {
+ return $this->once ?: $this->default;
+ }
+
+ /**
+ * Reset anything only used for the current content being written
+ */
+ protected function resetOneTimers()
+ {
+ // Reset new line flag for next time
+ $this->new_line = true;
+
+ if (!$this->persist) {
+ // Reset once since we only want to use it... once.
+ $this->once = null;
+ }
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/OutputImporter.php b/akamai/vendor/league/climate/src/Util/OutputImporter.php
new file mode 100644
index 00000000..e508f16d
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/OutputImporter.php
@@ -0,0 +1,23 @@
+output = $output;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/Reader/ReaderInterface.php b/akamai/vendor/league/climate/src/Util/Reader/ReaderInterface.php
new file mode 100644
index 00000000..6ef947fb
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/Reader/ReaderInterface.php
@@ -0,0 +1,16 @@
+getStdIn(), 1024));
+ }
+
+ /**
+ * Read from STDIN until EOF (^D) is reached
+ *
+ * @return string
+ */
+ public function multiLine()
+ {
+ return trim(stream_get_contents($this->getStdIn()));
+ }
+
+ /**
+ * Read one character
+ *
+ * @param int $count
+ *
+ * @return string
+ */
+ public function char($count = 1)
+ {
+ return fread($this->getStdIn(), $count);
+ }
+
+ /**
+ * Read the line, but hide what the user is typing
+ *
+ * @return string
+ */
+ public function hidden()
+ {
+ return CliPrompt::hiddenPrompt();
+ }
+
+ /**
+ * Return a valid STDIN, even if it previously EOF'ed
+ *
+ * Lazily re-opens STDIN after hitting an EOF
+ *
+ * @return resource
+ * @throws \Exception
+ */
+ protected function getStdIn()
+ {
+ if ($this->stdIn && !feof($this->stdIn)) {
+ return $this->stdIn;
+ }
+
+ try {
+ $this->setStdIn();
+ } catch (\Error $e) {
+ throw new \Exception('Unable to read from STDIN', 0, $e);
+ }
+
+ return $this->stdIn;
+ }
+
+ /**
+ * Attempt to set the stdin property
+ *
+ * @throws \Exception
+ */
+ protected function setStdIn()
+ {
+ if ($this->stdIn !== false) {
+ fclose($this->stdIn);
+ }
+
+ $this->stdIn = fopen('php://stdin', 'r');
+
+ if (!$this->stdIn) {
+ throw new \Exception('Unable to read from STDIN');
+ }
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/System/Linux.php b/akamai/vendor/league/climate/src/Util/System/Linux.php
new file mode 100644
index 00000000..463b53f4
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/System/Linux.php
@@ -0,0 +1,74 @@
+getDimension($this->exec('tput cols'));
+ }
+
+ /**
+ * Get the height of the terminal
+ *
+ * @return integer|null
+ */
+ public function height()
+ {
+ return $this->getDimension($this->exec('tput lines'));
+ }
+
+ /**
+ * Determine if system has access to bash commands
+ *
+ * @return bool
+ */
+ public function canAccessBash()
+ {
+ return (rtrim($this->exec("/usr/bin/env bash -c 'echo OK'")) === 'OK');
+ }
+
+ /**
+ * Display a hidden response prompt and return the response
+ *
+ * @param string $prompt
+ *
+ * @return string
+ */
+ public function hiddenResponsePrompt($prompt)
+ {
+ $bash_command = 'read -s -p "' . $prompt . '" response && echo $response';
+
+ return rtrim($this->exec("/usr/bin/env bash -c '{$bash_command}'"));
+ }
+
+ /**
+ * Determine if dimension is numeric and return it
+ *
+ * @param integer|string|null $dimension
+ *
+ * @return integer|null
+ */
+ protected function getDimension($dimension)
+ {
+ return (is_numeric($dimension)) ? $dimension : null;
+ }
+
+ /**
+ * Check if the stream supports ansi escape characters.
+ *
+ * Based on https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Console/Output/StreamOutput.php
+ *
+ * @return bool
+ */
+ protected function systemHasAnsiSupport()
+ {
+ return (function_exists('posix_isatty') && @posix_isatty(STDOUT));
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/System/System.php b/akamai/vendor/league/climate/src/Util/System/System.php
new file mode 100644
index 00000000..1eaaf116
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/System/System.php
@@ -0,0 +1,68 @@
+force_ansi = $force;
+ }
+
+ /**
+ * @return integer|null
+ */
+ abstract public function width();
+
+ /**
+ * @return integer|null
+ */
+ abstract public function height();
+
+ /**
+ * Check if the stream supports ansi escape characters.
+ *
+ * @return bool
+ */
+ abstract protected function systemHasAnsiSupport();
+
+ /**
+ * Check if we are forcing ansi, fallback to system support
+ *
+ * @return bool
+ */
+ public function hasAnsiSupport()
+ {
+ if (is_bool($this->force_ansi)) {
+ return $this->force_ansi;
+ }
+
+ return $this->systemHasAnsiSupport();
+ }
+
+ /**
+ * Wraps exec function, allowing the dimension methods to decouple
+ *
+ * @param string $command
+ * @param boolean $full
+ *
+ * @return string|array
+ */
+ public function exec($command, $full = false)
+ {
+ if ($full) {
+ exec($command, $output);
+
+ return $output;
+ }
+
+ return exec($command);
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/System/SystemFactory.php b/akamai/vendor/league/climate/src/Util/System/SystemFactory.php
new file mode 100644
index 00000000..b6137b3d
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/System/SystemFactory.php
@@ -0,0 +1,44 @@
+getDimension('width');
+ }
+
+ /**
+ * Get the height of the terminal
+ *
+ * @return integer|null
+ */
+ public function height()
+ {
+ return $this->getDimension('height');
+ }
+
+ /**
+ * Get specified terminal dimension
+ *
+ * @param string $key
+ *
+ * @return integer|null
+ */
+
+ protected function getDimension($key)
+ {
+ $index = array_search($key, ['height', 'width']);
+ $dimensions = $this->getDimensions();
+
+ return (!empty($dimensions[$index])) ? $dimensions[$index] : null;
+ }
+
+ /**
+ * Get information about the dimensions of the terminal
+ *
+ * @return array
+ */
+ protected function getDimensions()
+ {
+ $output = $this->exec('mode CON', true);
+
+ if (!is_array($output)) {
+ return [];
+ }
+
+ $output = implode("\n", $output);
+
+ preg_match_all('/.*:\s*(\d+)/', $output, $matches);
+
+ return (!empty($matches[1])) ? $matches[1] : [];
+ }
+
+ /**
+ * Check if the stream supports ansi escape characters.
+ *
+ * Based on https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Console/Output/StreamOutput.php
+ *
+ * @return bool
+ */
+ protected function systemHasAnsiSupport()
+ {
+ return (getenv('ANSICON') === true || getenv('ConEmuANSI') === 'ON');
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/UtilFactory.php b/akamai/vendor/league/climate/src/Util/UtilFactory.php
new file mode 100644
index 00000000..3584a6b4
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/UtilFactory.php
@@ -0,0 +1,66 @@
+system = $system ?: SystemFactory::getInstance();
+ $this->cursor = $cursor ?: new Cursor();
+ }
+
+ /**
+ * Get the width of the terminal
+ *
+ * @return integer
+ */
+
+ public function width()
+ {
+ return (int) $this->getDimension($this->system->width(), 80);
+ }
+
+ /**
+ * Get the height of the terminal
+ *
+ * @return integer
+ */
+
+ public function height()
+ {
+ return (int) $this->getDimension($this->system->height(), 25);
+ }
+
+ /**
+ * Determine if the value is numeric, fallback to a default if not
+ *
+ * @param integer|null $dimension
+ * @param integer $default
+ *
+ * @return integer
+ */
+
+ protected function getDimension($dimension, $default)
+ {
+ return (is_numeric($dimension)) ? $dimension : $default;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/UtilImporter.php b/akamai/vendor/league/climate/src/Util/UtilImporter.php
new file mode 100644
index 00000000..88debfc4
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/UtilImporter.php
@@ -0,0 +1,23 @@
+util = $util;
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/Writer/Buffer.php b/akamai/vendor/league/climate/src/Util/Writer/Buffer.php
new file mode 100644
index 00000000..58f1051f
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/Writer/Buffer.php
@@ -0,0 +1,44 @@
+contents .= $content;
+ }
+
+
+ /**
+ * Get the buffered data.
+ *
+ * @return string
+ */
+ public function get()
+ {
+ return $this->contents;
+ }
+
+ /**
+ * Clean the buffer and throw away any data.
+ *
+ * @return void
+ */
+ public function clean()
+ {
+ $this->contents = "";
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/Writer/File.php b/akamai/vendor/league/climate/src/Util/Writer/File.php
new file mode 100644
index 00000000..c323472a
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/Writer/File.php
@@ -0,0 +1,99 @@
+resource = $resource;
+ $this->use_locking = $use_locking;
+ $this->gzip_file = $gzip_file;
+ }
+
+ public function lock()
+ {
+ $this->use_locking = true;
+
+ return $this;
+ }
+
+ public function gzipped()
+ {
+ $this->gzip_file = true;
+
+ return $this;
+ }
+
+ /**
+ * Write the content to the stream
+ *
+ * @param string $content
+ */
+ public function write($content)
+ {
+ $resource = $this->getResource();
+
+ if ($this->use_locking) {
+ flock($resource, LOCK_EX);
+ }
+
+ gzwrite($resource, $content);
+
+ if ($this->use_locking) {
+ flock($resource, LOCK_UN);
+ }
+ }
+
+ protected function getResource()
+ {
+ if (is_resource($this->resource)) {
+ return $this->resource;
+ }
+
+ $this->close_locally = true;
+
+ if (!is_writable($this->resource)) {
+ throw new \Exception("The resource [{$this->resource}] is not writable");
+ }
+
+ if (!($this->resource = $this->openResource())) {
+ throw new \Exception("The resource could not be opened");
+ }
+
+ return $this->resource;
+ }
+
+ protected function openResource()
+ {
+ if ($this->gzip_file) {
+ return gzopen($this->resource, 'a');
+ }
+
+ return fopen($this->resource, 'a');
+ }
+
+ public function _destruct()
+ {
+ if ($this->close_locally) {
+ gzclose($this->getResource());
+ }
+ }
+}
diff --git a/akamai/vendor/league/climate/src/Util/Writer/StdErr.php b/akamai/vendor/league/climate/src/Util/Writer/StdErr.php
new file mode 100644
index 00000000..4e778a6f
--- /dev/null
+++ b/akamai/vendor/league/climate/src/Util/Writer/StdErr.php
@@ -0,0 +1,16 @@
+useMicrosecondTimestamps(false)`, disabling it gets you a bit of performance boost but reduces the precision to the second instead of microsecond
+ * Added possibility to skip some extra stack frames in IntrospectionProcessor if you have some library wrapping Monolog that is always adding frames
+ * Added `Logger->withName` to clone a logger (keeping all handlers) with a new name
+ * Added FluentdFormatter for the Fluentd unix socket protocol
+ * Added HandlerWrapper base class to ease the creation of handler wrappers, just extend it and override as needed
+ * Added support for replacing context sub-keys using `%context.*%` in LineFormatter
+ * Added support for `payload` context value in RollbarHandler
+ * Added setRelease to RavenHandler to describe the application version, sent with every log
+ * Added support for `fingerprint` context value in RavenHandler
+ * Fixed JSON encoding errors that would gobble up the whole log record, we now handle those more gracefully by dropping chars as needed
+ * Fixed write timeouts in SocketHandler and derivatives, set to 10sec by default, lower it with `setWritingTimeout()`
+ * Fixed PHP7 compatibility with regard to Exception/Throwable handling in a few places
+
+### 1.17.2 (2015-10-14)
+
+ * Fixed ErrorHandler compatibility with non-Monolog PSR-3 loggers
+ * Fixed SlackHandler handling to use slack functionalities better
+ * Fixed SwiftMailerHandler bug when sending multiple emails they all had the same id
+ * Fixed 5.3 compatibility regression
+
+### 1.17.1 (2015-08-31)
+
+ * Fixed RollbarHandler triggering PHP notices
+
+### 1.17.0 (2015-08-30)
+
+ * Added support for `checksum` and `release` context/extra values in RavenHandler
+ * Added better support for exceptions in RollbarHandler
+ * Added UidProcessor::getUid
+ * Added support for showing the resource type in NormalizedFormatter
+ * Fixed IntrospectionProcessor triggering PHP notices
+
+### 1.16.0 (2015-08-09)
+
+ * Added IFTTTHandler to notify ifttt.com triggers
+ * Added Logger::setHandlers() to allow setting/replacing all handlers
+ * Added $capSize in RedisHandler to cap the log size
+ * Fixed StreamHandler creation of directory to only trigger when the first log write happens
+ * Fixed bug in the handling of curl failures
+ * Fixed duplicate logging of fatal errors when both error and fatal error handlers are registered in monolog's ErrorHandler
+ * Fixed missing fatal errors records with handlers that need to be closed to flush log records
+ * Fixed TagProcessor::addTags support for associative arrays
+
+### 1.15.0 (2015-07-12)
+
+ * Added addTags and setTags methods to change a TagProcessor
+ * Added automatic creation of directories if they are missing for a StreamHandler to open a log file
+ * Added retry functionality to Loggly, Cube and Mandrill handlers so they retry up to 5 times in case of network failure
+ * Fixed process exit code being incorrectly reset to 0 if ErrorHandler::registerExceptionHandler was used
+ * Fixed HTML/JS escaping in BrowserConsoleHandler
+ * Fixed JSON encoding errors being silently suppressed (PHP 5.5+ only)
+
+### 1.14.0 (2015-06-19)
+
+ * Added PHPConsoleHandler to send record to Chrome's PHP Console extension and library
+ * Added support for objects implementing __toString in the NormalizerFormatter
+ * Added support for HipChat's v2 API in HipChatHandler
+ * Added Logger::setTimezone() to initialize the timezone monolog should use in case date.timezone isn't correct for your app
+ * Added an option to send formatted message instead of the raw record on PushoverHandler via ->useFormattedMessage(true)
+ * Fixed curl errors being silently suppressed
+
+### 1.13.1 (2015-03-09)
+
+ * Fixed regression in HipChat requiring a new token to be created
+
+### 1.13.0 (2015-03-05)
+
+ * Added Registry::hasLogger to check for the presence of a logger instance
+ * Added context.user support to RavenHandler
+ * Added HipChat API v2 support in the HipChatHandler
+ * Added NativeMailerHandler::addParameter to pass params to the mail() process
+ * Added context data to SlackHandler when $includeContextAndExtra is true
+ * Added ability to customize the Swift_Message per-email in SwiftMailerHandler
+ * Fixed SwiftMailerHandler to lazily create message instances if a callback is provided
+ * Fixed serialization of INF and NaN values in Normalizer and LineFormatter
+
+### 1.12.0 (2014-12-29)
+
+ * Break: HandlerInterface::isHandling now receives a partial record containing only a level key. This was always the intent and does not break any Monolog handler but is strictly speaking a BC break and you should check if you relied on any other field in your own handlers.
+ * Added PsrHandler to forward records to another PSR-3 logger
+ * Added SamplingHandler to wrap around a handler and include only every Nth record
+ * Added MongoDBFormatter to support better storage with MongoDBHandler (it must be enabled manually for now)
+ * Added exception codes in the output of most formatters
+ * Added LineFormatter::includeStacktraces to enable exception stack traces in logs (uses more than one line)
+ * Added $useShortAttachment to SlackHandler to minify attachment size and $includeExtra to append extra data
+ * Added $host to HipChatHandler for users of private instances
+ * Added $transactionName to NewRelicHandler and support for a transaction_name context value
+ * Fixed MandrillHandler to avoid outputing API call responses
+ * Fixed some non-standard behaviors in SyslogUdpHandler
+
+### 1.11.0 (2014-09-30)
+
+ * Break: The NewRelicHandler extra and context data are now prefixed with extra_ and context_ to avoid clashes. Watch out if you have scripts reading those from the API and rely on names
+ * Added WhatFailureGroupHandler to suppress any exception coming from the wrapped handlers and avoid chain failures if a logging service fails
+ * Added MandrillHandler to send emails via the Mandrillapp.com API
+ * Added SlackHandler to log records to a Slack.com account
+ * Added FleepHookHandler to log records to a Fleep.io account
+ * Added LogglyHandler::addTag to allow adding tags to an existing handler
+ * Added $ignoreEmptyContextAndExtra to LineFormatter to avoid empty [] at the end
+ * Added $useLocking to StreamHandler and RotatingFileHandler to enable flock() while writing
+ * Added support for PhpAmqpLib in the AmqpHandler
+ * Added FingersCrossedHandler::clear and BufferHandler::clear to reset them between batches in long running jobs
+ * Added support for adding extra fields from $_SERVER in the WebProcessor
+ * Fixed support for non-string values in PrsLogMessageProcessor
+ * Fixed SwiftMailer messages being sent with the wrong date in long running scripts
+ * Fixed minor PHP 5.6 compatibility issues
+ * Fixed BufferHandler::close being called twice
+
+### 1.10.0 (2014-06-04)
+
+ * Added Logger::getHandlers() and Logger::getProcessors() methods
+ * Added $passthruLevel argument to FingersCrossedHandler to let it always pass some records through even if the trigger level is not reached
+ * Added support for extra data in NewRelicHandler
+ * Added $expandNewlines flag to the ErrorLogHandler to create multiple log entries when a message has multiple lines
+
+### 1.9.1 (2014-04-24)
+
+ * Fixed regression in RotatingFileHandler file permissions
+ * Fixed initialization of the BufferHandler to make sure it gets flushed after receiving records
+ * Fixed ChromePHPHandler and FirePHPHandler's activation strategies to be more conservative
+
+### 1.9.0 (2014-04-20)
+
+ * Added LogEntriesHandler to send logs to a LogEntries account
+ * Added $filePermissions to tweak file mode on StreamHandler and RotatingFileHandler
+ * Added $useFormatting flag to MemoryProcessor to make it send raw data in bytes
+ * Added support for table formatting in FirePHPHandler via the table context key
+ * Added a TagProcessor to add tags to records, and support for tags in RavenHandler
+ * Added $appendNewline flag to the JsonFormatter to enable using it when logging to files
+ * Added sound support to the PushoverHandler
+ * Fixed multi-threading support in StreamHandler
+ * Fixed empty headers issue when ChromePHPHandler received no records
+ * Fixed default format of the ErrorLogHandler
+
+### 1.8.0 (2014-03-23)
+
+ * Break: the LineFormatter now strips newlines by default because this was a bug, set $allowInlineLineBreaks to true if you need them
+ * Added BrowserConsoleHandler to send logs to any browser's console via console.log() injection in the output
+ * Added FilterHandler to filter records and only allow those of a given list of levels through to the wrapped handler
+ * Added FlowdockHandler to send logs to a Flowdock account
+ * Added RollbarHandler to send logs to a Rollbar account
+ * Added HtmlFormatter to send prettier log emails with colors for each log level
+ * Added GitProcessor to add the current branch/commit to extra record data
+ * Added a Monolog\Registry class to allow easier global access to pre-configured loggers
+ * Added support for the new official graylog2/gelf-php lib for GelfHandler, upgrade if you can by replacing the mlehner/gelf-php requirement
+ * Added support for HHVM
+ * Added support for Loggly batch uploads
+ * Added support for tweaking the content type and encoding in NativeMailerHandler
+ * Added $skipClassesPartials to tweak the ignored classes in the IntrospectionProcessor
+ * Fixed batch request support in GelfHandler
+
+### 1.7.0 (2013-11-14)
+
+ * Added ElasticSearchHandler to send logs to an Elastic Search server
+ * Added DynamoDbHandler and ScalarFormatter to send logs to Amazon's Dynamo DB
+ * Added SyslogUdpHandler to send logs to a remote syslogd server
+ * Added LogglyHandler to send logs to a Loggly account
+ * Added $level to IntrospectionProcessor so it only adds backtraces when needed
+ * Added $version to LogstashFormatter to allow using the new v1 Logstash format
+ * Added $appName to NewRelicHandler
+ * Added configuration of Pushover notification retries/expiry
+ * Added $maxColumnWidth to NativeMailerHandler to change the 70 chars default
+ * Added chainability to most setters for all handlers
+ * Fixed RavenHandler batch processing so it takes the message from the record with highest priority
+ * Fixed HipChatHandler batch processing so it sends all messages at once
+ * Fixed issues with eAccelerator
+ * Fixed and improved many small things
+
+### 1.6.0 (2013-07-29)
+
+ * Added HipChatHandler to send logs to a HipChat chat room
+ * Added ErrorLogHandler to send logs to PHP's error_log function
+ * Added NewRelicHandler to send logs to NewRelic's service
+ * Added Monolog\ErrorHandler helper class to register a Logger as exception/error/fatal handler
+ * Added ChannelLevelActivationStrategy for the FingersCrossedHandler to customize levels by channel
+ * Added stack traces output when normalizing exceptions (json output & co)
+ * Added Monolog\Logger::API constant (currently 1)
+ * Added support for ChromePHP's v4.0 extension
+ * Added support for message priorities in PushoverHandler, see $highPriorityLevel and $emergencyLevel
+ * Added support for sending messages to multiple users at once with the PushoverHandler
+ * Fixed RavenHandler's support for batch sending of messages (when behind a Buffer or FingersCrossedHandler)
+ * Fixed normalization of Traversables with very large data sets, only the first 1000 items are shown now
+ * Fixed issue in RotatingFileHandler when an open_basedir restriction is active
+ * Fixed minor issues in RavenHandler and bumped the API to Raven 0.5.0
+ * Fixed SyslogHandler issue when many were used concurrently with different facilities
+
+### 1.5.0 (2013-04-23)
+
+ * Added ProcessIdProcessor to inject the PID in log records
+ * Added UidProcessor to inject a unique identifier to all log records of one request/run
+ * Added support for previous exceptions in the LineFormatter exception serialization
+ * Added Monolog\Logger::getLevels() to get all available levels
+ * Fixed ChromePHPHandler so it avoids sending headers larger than Chrome can handle
+
+### 1.4.1 (2013-04-01)
+
+ * Fixed exception formatting in the LineFormatter to be more minimalistic
+ * Fixed RavenHandler's handling of context/extra data, requires Raven client >0.1.0
+ * Fixed log rotation in RotatingFileHandler to work with long running scripts spanning multiple days
+ * Fixed WebProcessor array access so it checks for data presence
+ * Fixed Buffer, Group and FingersCrossed handlers to make use of their processors
+
+### 1.4.0 (2013-02-13)
+
+ * Added RedisHandler to log to Redis via the Predis library or the phpredis extension
+ * Added ZendMonitorHandler to log to the Zend Server monitor
+ * Added the possibility to pass arrays of handlers and processors directly in the Logger constructor
+ * Added `$useSSL` option to the PushoverHandler which is enabled by default
+ * Fixed ChromePHPHandler and FirePHPHandler issue when multiple instances are used simultaneously
+ * Fixed header injection capability in the NativeMailHandler
+
+### 1.3.1 (2013-01-11)
+
+ * Fixed LogstashFormatter to be usable with stream handlers
+ * Fixed GelfMessageFormatter levels on Windows
+
+### 1.3.0 (2013-01-08)
+
+ * Added PSR-3 compliance, the `Monolog\Logger` class is now an instance of `Psr\Log\LoggerInterface`
+ * Added PsrLogMessageProcessor that you can selectively enable for full PSR-3 compliance
+ * Added LogstashFormatter (combine with SocketHandler or StreamHandler to send logs to Logstash)
+ * Added PushoverHandler to send mobile notifications
+ * Added CouchDBHandler and DoctrineCouchDBHandler
+ * Added RavenHandler to send data to Sentry servers
+ * Added support for the new MongoClient class in MongoDBHandler
+ * Added microsecond precision to log records' timestamps
+ * Added `$flushOnOverflow` param to BufferHandler to flush by batches instead of losing
+ the oldest entries
+ * Fixed normalization of objects with cyclic references
+
+### 1.2.1 (2012-08-29)
+
+ * Added new $logopts arg to SyslogHandler to provide custom openlog options
+ * Fixed fatal error in SyslogHandler
+
+### 1.2.0 (2012-08-18)
+
+ * Added AmqpHandler (for use with AMQP servers)
+ * Added CubeHandler
+ * Added NativeMailerHandler::addHeader() to send custom headers in mails
+ * Added the possibility to specify more than one recipient in NativeMailerHandler
+ * Added the possibility to specify float timeouts in SocketHandler
+ * Added NOTICE and EMERGENCY levels to conform with RFC 5424
+ * Fixed the log records to use the php default timezone instead of UTC
+ * Fixed BufferHandler not being flushed properly on PHP fatal errors
+ * Fixed normalization of exotic resource types
+ * Fixed the default format of the SyslogHandler to avoid duplicating datetimes in syslog
+
+### 1.1.0 (2012-04-23)
+
+ * Added Monolog\Logger::isHandling() to check if a handler will
+ handle the given log level
+ * Added ChromePHPHandler
+ * Added MongoDBHandler
+ * Added GelfHandler (for use with Graylog2 servers)
+ * Added SocketHandler (for use with syslog-ng for example)
+ * Added NormalizerFormatter
+ * Added the possibility to change the activation strategy of the FingersCrossedHandler
+ * Added possibility to show microseconds in logs
+ * Added `server` and `referer` to WebProcessor output
+
+### 1.0.2 (2011-10-24)
+
+ * Fixed bug in IE with large response headers and FirePHPHandler
+
+### 1.0.1 (2011-08-25)
+
+ * Added MemoryPeakUsageProcessor and MemoryUsageProcessor
+ * Added Monolog\Logger::getName() to get a logger's channel name
+
+### 1.0.0 (2011-07-06)
+
+ * Added IntrospectionProcessor to get info from where the logger was called
+ * Fixed WebProcessor in CLI
+
+### 1.0.0-RC1 (2011-07-01)
+
+ * Initial release
diff --git a/akamai/vendor/monolog/monolog/LICENSE b/akamai/vendor/monolog/monolog/LICENSE
new file mode 100644
index 00000000..16473219
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2011-2016 Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/akamai/vendor/monolog/monolog/README.md b/akamai/vendor/monolog/monolog/README.md
new file mode 100644
index 00000000..a578eb22
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/README.md
@@ -0,0 +1,94 @@
+# Monolog - Logging for PHP [](https://travis-ci.org/Seldaek/monolog)
+
+[](https://packagist.org/packages/monolog/monolog)
+[](https://packagist.org/packages/monolog/monolog)
+
+
+Monolog sends your logs to files, sockets, inboxes, databases and various
+web services. See the complete list of handlers below. Special handlers
+allow you to build advanced logging strategies.
+
+This library implements the [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+interface that you can type-hint against in your own libraries to keep
+a maximum of interoperability. You can also use it in your applications to
+make sure you can always use another compatible logger at a later time.
+As of 1.11.0 Monolog public APIs will also accept PSR-3 log levels.
+Internally Monolog still uses its own level scheme since it predates PSR-3.
+
+## Installation
+
+Install the latest version with
+
+```bash
+$ composer require monolog/monolog
+```
+
+## Basic Usage
+
+```php
+pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
+
+// add records to the log
+$log->addWarning('Foo');
+$log->addError('Bar');
+```
+
+## Documentation
+
+- [Usage Instructions](doc/01-usage.md)
+- [Handlers, Formatters and Processors](doc/02-handlers-formatters-processors.md)
+- [Utility classes](doc/03-utilities.md)
+- [Extending Monolog](doc/04-extending.md)
+
+## Third Party Packages
+
+Third party handlers, formatters and processors are
+[listed in the wiki](https://github.com/Seldaek/monolog/wiki/Third-Party-Packages). You
+can also add your own there if you publish one.
+
+## About
+
+### Requirements
+
+- Monolog works with PHP 5.3 or above, and is also tested to work with HHVM.
+
+### Submitting bugs and feature requests
+
+Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/monolog/issues)
+
+### Framework Integrations
+
+- Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+ can be used very easily with Monolog since it implements the interface.
+- [Symfony2](http://symfony.com) comes out of the box with Monolog.
+- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog.
+- [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog.
+- [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog.
+- [PPI](http://www.ppi.io/) comes out of the box with Monolog.
+- [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin.
+- [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer.
+- [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog.
+- [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) comes out of the box with Monolog.
+- [Nette Framework](http://nette.org/en/) can be used with Monolog via [Kdyby/Monolog](https://github.com/Kdyby/Monolog) extension.
+- [Proton Micro Framework](https://github.com/alexbilbie/Proton) comes out of the box with Monolog.
+
+### Author
+
+Jordi Boggiano - -
+See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project.
+
+### License
+
+Monolog is licensed under the MIT License - see the `LICENSE` file for details
+
+### Acknowledgements
+
+This library is heavily inspired by Python's [Logbook](https://logbook.readthedocs.io/en/stable/)
+library, although most concepts have been adjusted to fit to the PHP world.
diff --git a/akamai/vendor/monolog/monolog/composer.json b/akamai/vendor/monolog/monolog/composer.json
new file mode 100644
index 00000000..097df878
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/composer.json
@@ -0,0 +1,66 @@
+{
+ "name": "monolog/monolog",
+ "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+ "keywords": ["log", "logging", "psr-3"],
+ "homepage": "http://github.com/Seldaek/monolog",
+ "type": "library",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "psr/log": "~1.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.5",
+ "graylog2/gelf-php": "~1.0",
+ "sentry/sentry": "^0.13",
+ "ruflin/elastica": ">=0.90 <3.0",
+ "doctrine/couchdb": "~1.0@dev",
+ "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+ "php-amqplib/php-amqplib": "~2.4",
+ "swiftmailer/swiftmailer": "^5.3|^6.0",
+ "php-console/php-console": "^3.1.3",
+ "phpunit/phpunit-mock-objects": "2.3.0",
+ "jakub-onderka/php-parallel-lint": "0.9"
+ },
+ "_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223 - needs hhvm 3.8+ on travis",
+ "suggest": {
+ "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+ "sentry/sentry": "Allow sending log messages to a Sentry server",
+ "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+ "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
+ "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+ "ext-mongo": "Allow sending log messages to a MongoDB server",
+ "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
+ "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+ "rollbar/rollbar": "Allow sending log messages to Rollbar",
+ "php-console/php-console": "Allow sending log messages to Google Chrome"
+ },
+ "autoload": {
+ "psr-4": {"Monolog\\": "src/Monolog"}
+ },
+ "autoload-dev": {
+ "psr-4": {"Monolog\\": "tests/Monolog"}
+ },
+ "provide": {
+ "psr/log-implementation": "1.0.0"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "scripts": {
+ "test": [
+ "parallel-lint . --exclude vendor --exclude src/Monolog/Handler/FormattableHandlerInterface.php --exclude src/Monolog/Handler/FormattableHandlerTrait.php --exclude src/Monolog/Handler/ProcessableHandlerInterface.php --exclude src/Monolog/Handler/ProcessableHandlerTrait.php",
+ "phpunit"
+ ]
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/ErrorHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/ErrorHandler.php
new file mode 100644
index 00000000..adc55bdf
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/ErrorHandler.php
@@ -0,0 +1,239 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+use Monolog\Handler\AbstractHandler;
+use Monolog\Registry;
+
+/**
+ * Monolog error handler
+ *
+ * A facility to enable logging of runtime errors, exceptions and fatal errors.
+ *
+ * Quick setup: ErrorHandler::register($logger);
+ *
+ * @author Jordi Boggiano
+ */
+class ErrorHandler
+{
+ private $logger;
+
+ private $previousExceptionHandler;
+ private $uncaughtExceptionLevel;
+
+ private $previousErrorHandler;
+ private $errorLevelMap;
+ private $handleOnlyReportedErrors;
+
+ private $hasFatalErrorHandler;
+ private $fatalLevel;
+ private $reservedMemory;
+ private $lastFatalTrace;
+ private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR);
+
+ public function __construct(LoggerInterface $logger)
+ {
+ $this->logger = $logger;
+ }
+
+ /**
+ * Registers a new ErrorHandler for a given Logger
+ *
+ * By default it will handle errors, exceptions and fatal errors
+ *
+ * @param LoggerInterface $logger
+ * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
+ * @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling
+ * @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling
+ * @return ErrorHandler
+ */
+ public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null)
+ {
+ //Forces the autoloader to run for LogLevel. Fixes an autoload issue at compile-time on PHP5.3. See https://github.com/Seldaek/monolog/pull/929
+ class_exists('\\Psr\\Log\\LogLevel', true);
+
+ $handler = new static($logger);
+ if ($errorLevelMap !== false) {
+ $handler->registerErrorHandler($errorLevelMap);
+ }
+ if ($exceptionLevel !== false) {
+ $handler->registerExceptionHandler($exceptionLevel);
+ }
+ if ($fatalLevel !== false) {
+ $handler->registerFatalHandler($fatalLevel);
+ }
+
+ return $handler;
+ }
+
+ public function registerExceptionHandler($level = null, $callPrevious = true)
+ {
+ $prev = set_exception_handler(array($this, 'handleException'));
+ $this->uncaughtExceptionLevel = $level;
+ if ($callPrevious && $prev) {
+ $this->previousExceptionHandler = $prev;
+ }
+ }
+
+ public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1, $handleOnlyReportedErrors = true)
+ {
+ $prev = set_error_handler(array($this, 'handleError'), $errorTypes);
+ $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
+ if ($callPrevious) {
+ $this->previousErrorHandler = $prev ?: true;
+ }
+
+ $this->handleOnlyReportedErrors = $handleOnlyReportedErrors;
+ }
+
+ public function registerFatalHandler($level = null, $reservedMemorySize = 20)
+ {
+ register_shutdown_function(array($this, 'handleFatalError'));
+
+ $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
+ $this->fatalLevel = $level;
+ $this->hasFatalErrorHandler = true;
+ }
+
+ protected function defaultErrorLevelMap()
+ {
+ return array(
+ E_ERROR => LogLevel::CRITICAL,
+ E_WARNING => LogLevel::WARNING,
+ E_PARSE => LogLevel::ALERT,
+ E_NOTICE => LogLevel::NOTICE,
+ E_CORE_ERROR => LogLevel::CRITICAL,
+ E_CORE_WARNING => LogLevel::WARNING,
+ E_COMPILE_ERROR => LogLevel::ALERT,
+ E_COMPILE_WARNING => LogLevel::WARNING,
+ E_USER_ERROR => LogLevel::ERROR,
+ E_USER_WARNING => LogLevel::WARNING,
+ E_USER_NOTICE => LogLevel::NOTICE,
+ E_STRICT => LogLevel::NOTICE,
+ E_RECOVERABLE_ERROR => LogLevel::ERROR,
+ E_DEPRECATED => LogLevel::NOTICE,
+ E_USER_DEPRECATED => LogLevel::NOTICE,
+ );
+ }
+
+ /**
+ * @private
+ */
+ public function handleException($e)
+ {
+ $this->logger->log(
+ $this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel,
+ sprintf('Uncaught Exception %s: "%s" at %s line %s', Utils::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()),
+ array('exception' => $e)
+ );
+
+ if ($this->previousExceptionHandler) {
+ call_user_func($this->previousExceptionHandler, $e);
+ }
+
+ exit(255);
+ }
+
+ /**
+ * @private
+ */
+ public function handleError($code, $message, $file = '', $line = 0, $context = array())
+ {
+ if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) {
+ return;
+ }
+
+ // fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries
+ if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) {
+ $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL;
+ $this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line));
+ } else {
+ // http://php.net/manual/en/function.debug-backtrace.php
+ // As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added.
+ // Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'.
+ $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS);
+ array_shift($trace); // Exclude handleError from trace
+ $this->lastFatalTrace = $trace;
+ }
+
+ if ($this->previousErrorHandler === true) {
+ return false;
+ } elseif ($this->previousErrorHandler) {
+ return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context);
+ }
+ }
+
+ /**
+ * @private
+ */
+ public function handleFatalError()
+ {
+ $this->reservedMemory = null;
+
+ $lastError = error_get_last();
+ if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) {
+ $this->logger->log(
+ $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel,
+ 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
+ array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace)
+ );
+
+ if ($this->logger instanceof Logger) {
+ foreach ($this->logger->getHandlers() as $handler) {
+ if ($handler instanceof AbstractHandler) {
+ $handler->close();
+ }
+ }
+ }
+ }
+ }
+
+ private static function codeToString($code)
+ {
+ switch ($code) {
+ case E_ERROR:
+ return 'E_ERROR';
+ case E_WARNING:
+ return 'E_WARNING';
+ case E_PARSE:
+ return 'E_PARSE';
+ case E_NOTICE:
+ return 'E_NOTICE';
+ case E_CORE_ERROR:
+ return 'E_CORE_ERROR';
+ case E_CORE_WARNING:
+ return 'E_CORE_WARNING';
+ case E_COMPILE_ERROR:
+ return 'E_COMPILE_ERROR';
+ case E_COMPILE_WARNING:
+ return 'E_COMPILE_WARNING';
+ case E_USER_ERROR:
+ return 'E_USER_ERROR';
+ case E_USER_WARNING:
+ return 'E_USER_WARNING';
+ case E_USER_NOTICE:
+ return 'E_USER_NOTICE';
+ case E_STRICT:
+ return 'E_STRICT';
+ case E_RECOVERABLE_ERROR:
+ return 'E_RECOVERABLE_ERROR';
+ case E_DEPRECATED:
+ return 'E_DEPRECATED';
+ case E_USER_DEPRECATED:
+ return 'E_USER_DEPRECATED';
+ }
+
+ return 'Unknown PHP error';
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php
new file mode 100644
index 00000000..9beda1e7
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * Formats a log message according to the ChromePHP array format
+ *
+ * @author Christophe Coevoet
+ */
+class ChromePHPFormatter implements FormatterInterface
+{
+ /**
+ * Translates Monolog log levels to Wildfire levels.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => 'log',
+ Logger::INFO => 'info',
+ Logger::NOTICE => 'info',
+ Logger::WARNING => 'warn',
+ Logger::ERROR => 'error',
+ Logger::CRITICAL => 'error',
+ Logger::ALERT => 'error',
+ Logger::EMERGENCY => 'error',
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ // Retrieve the line and file if set and remove them from the formatted extra
+ $backtrace = 'unknown';
+ if (isset($record['extra']['file'], $record['extra']['line'])) {
+ $backtrace = $record['extra']['file'].' : '.$record['extra']['line'];
+ unset($record['extra']['file'], $record['extra']['line']);
+ }
+
+ $message = array('message' => $record['message']);
+ if ($record['context']) {
+ $message['context'] = $record['context'];
+ }
+ if ($record['extra']) {
+ $message['extra'] = $record['extra'];
+ }
+ if (count($message) === 1) {
+ $message = reset($message);
+ }
+
+ return array(
+ $record['channel'],
+ $message,
+ $backtrace,
+ $this->logLevels[$record['level']],
+ );
+ }
+
+ public function formatBatch(array $records)
+ {
+ $formatted = array();
+
+ foreach ($records as $record) {
+ $formatted[] = $this->format($record);
+ }
+
+ return $formatted;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php
new file mode 100644
index 00000000..4c556cf1
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php
@@ -0,0 +1,89 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Elastica\Document;
+
+/**
+ * Format a log message into an Elastica Document
+ *
+ * @author Jelle Vink
+ */
+class ElasticaFormatter extends NormalizerFormatter
+{
+ /**
+ * @var string Elastic search index name
+ */
+ protected $index;
+
+ /**
+ * @var string Elastic search document type
+ */
+ protected $type;
+
+ /**
+ * @param string $index Elastic Search index name
+ * @param string $type Elastic Search document type
+ */
+ public function __construct($index, $type)
+ {
+ // elasticsearch requires a ISO 8601 format date with optional millisecond precision.
+ parent::__construct('Y-m-d\TH:i:s.uP');
+
+ $this->index = $index;
+ $this->type = $type;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $record = parent::format($record);
+
+ return $this->getDocument($record);
+ }
+
+ /**
+ * Getter index
+ * @return string
+ */
+ public function getIndex()
+ {
+ return $this->index;
+ }
+
+ /**
+ * Getter type
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Convert a log message into an Elastica Document
+ *
+ * @param array $record Log message
+ * @return Document
+ */
+ protected function getDocument($record)
+ {
+ $document = new Document();
+ $document->setData($record);
+ $document->setType($this->type);
+ $document->setIndex($this->index);
+
+ return $document;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php
new file mode 100644
index 00000000..5094af3c
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php
@@ -0,0 +1,116 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * formats the record to be used in the FlowdockHandler
+ *
+ * @author Dominik Liebler
+ */
+class FlowdockFormatter implements FormatterInterface
+{
+ /**
+ * @var string
+ */
+ private $source;
+
+ /**
+ * @var string
+ */
+ private $sourceEmail;
+
+ /**
+ * @param string $source
+ * @param string $sourceEmail
+ */
+ public function __construct($source, $sourceEmail)
+ {
+ $this->source = $source;
+ $this->sourceEmail = $sourceEmail;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $tags = array(
+ '#logs',
+ '#' . strtolower($record['level_name']),
+ '#' . $record['channel'],
+ );
+
+ foreach ($record['extra'] as $value) {
+ $tags[] = '#' . $value;
+ }
+
+ $subject = sprintf(
+ 'in %s: %s - %s',
+ $this->source,
+ $record['level_name'],
+ $this->getShortMessage($record['message'])
+ );
+
+ $record['flowdock'] = array(
+ 'source' => $this->source,
+ 'from_address' => $this->sourceEmail,
+ 'subject' => $subject,
+ 'content' => $record['message'],
+ 'tags' => $tags,
+ 'project' => $this->source,
+ );
+
+ return $record;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatBatch(array $records)
+ {
+ $formatted = array();
+
+ foreach ($records as $record) {
+ $formatted[] = $this->format($record);
+ }
+
+ return $formatted;
+ }
+
+ /**
+ * @param string $message
+ *
+ * @return string
+ */
+ public function getShortMessage($message)
+ {
+ static $hasMbString;
+
+ if (null === $hasMbString) {
+ $hasMbString = function_exists('mb_strlen');
+ }
+
+ $maxLength = 45;
+
+ if ($hasMbString) {
+ if (mb_strlen($message, 'UTF-8') > $maxLength) {
+ $message = mb_substr($message, 0, $maxLength - 4, 'UTF-8') . ' ...';
+ }
+ } else {
+ if (strlen($message) > $maxLength) {
+ $message = substr($message, 0, $maxLength - 4) . ' ...';
+ }
+ }
+
+ return $message;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php
new file mode 100644
index 00000000..f8ead475
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php
@@ -0,0 +1,88 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Utils;
+
+/**
+ * Class FluentdFormatter
+ *
+ * Serializes a log message to Fluentd unix socket protocol
+ *
+ * Fluentd config:
+ *
+ *
+ * type unix
+ * path /var/run/td-agent/td-agent.sock
+ *
+ *
+ * Monolog setup:
+ *
+ * $logger = new Monolog\Logger('fluent.tag');
+ * $fluentHandler = new Monolog\Handler\SocketHandler('unix:///var/run/td-agent/td-agent.sock');
+ * $fluentHandler->setFormatter(new Monolog\Formatter\FluentdFormatter());
+ * $logger->pushHandler($fluentHandler);
+ *
+ * @author Andrius Putna
+ */
+class FluentdFormatter implements FormatterInterface
+{
+ /**
+ * @var bool $levelTag should message level be a part of the fluentd tag
+ */
+ protected $levelTag = false;
+
+ public function __construct($levelTag = false)
+ {
+ if (!function_exists('json_encode')) {
+ throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s FluentdUnixFormatter');
+ }
+
+ $this->levelTag = (bool) $levelTag;
+ }
+
+ public function isUsingLevelsInTag()
+ {
+ return $this->levelTag;
+ }
+
+ public function format(array $record)
+ {
+ $tag = $record['channel'];
+ if ($this->levelTag) {
+ $tag .= '.' . strtolower($record['level_name']);
+ }
+
+ $message = array(
+ 'message' => $record['message'],
+ 'context' => $record['context'],
+ 'extra' => $record['extra'],
+ );
+
+ if (!$this->levelTag) {
+ $message['level'] = $record['level'];
+ $message['level_name'] = $record['level_name'];
+ }
+
+ return Utils::jsonEncode(array($tag, $record['datetime']->getTimestamp(), $message));
+ }
+
+ public function formatBatch(array $records)
+ {
+ $message = '';
+ foreach ($records as $record) {
+ $message .= $this->format($record);
+ }
+
+ return $message;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php
new file mode 100644
index 00000000..b5de7511
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Interface for formatters
+ *
+ * @author Jordi Boggiano
+ */
+interface FormatterInterface
+{
+ /**
+ * Formats a log record.
+ *
+ * @param array $record A record to format
+ * @return mixed The formatted record
+ */
+ public function format(array $record);
+
+ /**
+ * Formats a set of log records.
+ *
+ * @param array $records A set of records to format
+ * @return mixed The formatted set of records
+ */
+ public function formatBatch(array $records);
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php
new file mode 100644
index 00000000..2c1b0e86
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php
@@ -0,0 +1,138 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+use Gelf\Message;
+
+/**
+ * Serializes a log message to GELF
+ * @see http://www.graylog2.org/about/gelf
+ *
+ * @author Matt Lehner
+ */
+class GelfMessageFormatter extends NormalizerFormatter
+{
+ const DEFAULT_MAX_LENGTH = 32766;
+
+ /**
+ * @var string the name of the system for the Gelf log message
+ */
+ protected $systemName;
+
+ /**
+ * @var string a prefix for 'extra' fields from the Monolog record (optional)
+ */
+ protected $extraPrefix;
+
+ /**
+ * @var string a prefix for 'context' fields from the Monolog record (optional)
+ */
+ protected $contextPrefix;
+
+ /**
+ * @var int max length per field
+ */
+ protected $maxLength;
+
+ /**
+ * Translates Monolog log levels to Graylog2 log priorities.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => 7,
+ Logger::INFO => 6,
+ Logger::NOTICE => 5,
+ Logger::WARNING => 4,
+ Logger::ERROR => 3,
+ Logger::CRITICAL => 2,
+ Logger::ALERT => 1,
+ Logger::EMERGENCY => 0,
+ );
+
+ public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $maxLength = null)
+ {
+ parent::__construct('U.u');
+
+ $this->systemName = $systemName ?: gethostname();
+
+ $this->extraPrefix = $extraPrefix;
+ $this->contextPrefix = $contextPrefix;
+ $this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $record = parent::format($record);
+
+ if (!isset($record['datetime'], $record['message'], $record['level'])) {
+ throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, '.var_export($record, true).' given');
+ }
+
+ $message = new Message();
+ $message
+ ->setTimestamp($record['datetime'])
+ ->setShortMessage((string) $record['message'])
+ ->setHost($this->systemName)
+ ->setLevel($this->logLevels[$record['level']]);
+
+ // message length + system name length + 200 for padding / metadata
+ $len = 200 + strlen((string) $record['message']) + strlen($this->systemName);
+
+ if ($len > $this->maxLength) {
+ $message->setShortMessage(substr($record['message'], 0, $this->maxLength));
+ }
+
+ if (isset($record['channel'])) {
+ $message->setFacility($record['channel']);
+ }
+ if (isset($record['extra']['line'])) {
+ $message->setLine($record['extra']['line']);
+ unset($record['extra']['line']);
+ }
+ if (isset($record['extra']['file'])) {
+ $message->setFile($record['extra']['file']);
+ unset($record['extra']['file']);
+ }
+
+ foreach ($record['extra'] as $key => $val) {
+ $val = is_scalar($val) || null === $val ? $val : $this->toJson($val);
+ $len = strlen($this->extraPrefix . $key . $val);
+ if ($len > $this->maxLength) {
+ $message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength));
+ break;
+ }
+ $message->setAdditional($this->extraPrefix . $key, $val);
+ }
+
+ foreach ($record['context'] as $key => $val) {
+ $val = is_scalar($val) || null === $val ? $val : $this->toJson($val);
+ $len = strlen($this->contextPrefix . $key . $val);
+ if ($len > $this->maxLength) {
+ $message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength));
+ break;
+ }
+ $message->setAdditional($this->contextPrefix . $key, $val);
+ }
+
+ if (null === $message->getFile() && isset($record['context']['exception']['file'])) {
+ if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) {
+ $message->setFile($matches[1]);
+ $message->setLine($matches[2]);
+ }
+ }
+
+ return $message;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php
new file mode 100644
index 00000000..9e8d2d01
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php
@@ -0,0 +1,142 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Formats incoming records into an HTML table
+ *
+ * This is especially useful for html email logging
+ *
+ * @author Tiago Brito
+ */
+class HtmlFormatter extends NormalizerFormatter
+{
+ /**
+ * Translates Monolog log levels to html color priorities.
+ */
+ protected $logLevels = array(
+ Logger::DEBUG => '#cccccc',
+ Logger::INFO => '#468847',
+ Logger::NOTICE => '#3a87ad',
+ Logger::WARNING => '#c09853',
+ Logger::ERROR => '#f0ad4e',
+ Logger::CRITICAL => '#FF7708',
+ Logger::ALERT => '#C12A19',
+ Logger::EMERGENCY => '#000000',
+ );
+
+ /**
+ * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+ */
+ public function __construct($dateFormat = null)
+ {
+ parent::__construct($dateFormat);
+ }
+
+ /**
+ * Creates an HTML table row
+ *
+ * @param string $th Row header content
+ * @param string $td Row standard cell content
+ * @param bool $escapeTd false if td content must not be html escaped
+ * @return string
+ */
+ protected function addRow($th, $td = ' ', $escapeTd = true)
+ {
+ $th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8');
+ if ($escapeTd) {
+ $td = '
'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'
';
+ }
+
+ return "
\n
$th:
\n
".$td."
\n
";
+ }
+
+ /**
+ * Create a HTML h1 tag
+ *
+ * @param string $title Text to be in the h1
+ * @param int $level Error level
+ * @return string
+ */
+ protected function addTitle($title, $level)
+ {
+ $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8');
+
+ return '
'.$title.'
';
+ }
+
+ /**
+ * Formats a log record.
+ *
+ * @param array $record A record to format
+ * @return mixed The formatted record
+ */
+ public function format(array $record)
+ {
+ $output = $this->addTitle($record['level_name'], $record['level']);
+ $output .= '
';
+ }
+
+ /**
+ * Formats a set of log records.
+ *
+ * @param array $records A set of records to format
+ * @return mixed The formatted set of records
+ */
+ public function formatBatch(array $records)
+ {
+ $message = '';
+ foreach ($records as $record) {
+ $message .= $this->format($record);
+ }
+
+ return $message;
+ }
+
+ protected function convertToString($data)
+ {
+ if (null === $data || is_scalar($data)) {
+ return (string) $data;
+ }
+
+ $data = $this->normalize($data);
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ return Utils::jsonEncode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, true);
+ }
+
+ return str_replace('\\/', '/', Utils::jsonEncode($data, null, true));
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php
new file mode 100644
index 00000000..96a05917
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php
@@ -0,0 +1,208 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Exception;
+use Monolog\Utils;
+use Throwable;
+
+/**
+ * Encodes whatever record data is passed to it as json
+ *
+ * This can be useful to log to databases or remote APIs
+ *
+ * @author Jordi Boggiano
+ */
+class JsonFormatter extends NormalizerFormatter
+{
+ const BATCH_MODE_JSON = 1;
+ const BATCH_MODE_NEWLINES = 2;
+
+ protected $batchMode;
+ protected $appendNewline;
+
+ /**
+ * @var bool
+ */
+ protected $includeStacktraces = false;
+
+ /**
+ * @param int $batchMode
+ * @param bool $appendNewline
+ */
+ public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
+ {
+ $this->batchMode = $batchMode;
+ $this->appendNewline = $appendNewline;
+ }
+
+ /**
+ * The batch mode option configures the formatting style for
+ * multiple records. By default, multiple records will be
+ * formatted as a JSON-encoded array. However, for
+ * compatibility with some API endpoints, alternative styles
+ * are available.
+ *
+ * @return int
+ */
+ public function getBatchMode()
+ {
+ return $this->batchMode;
+ }
+
+ /**
+ * True if newlines are appended to every formatted record
+ *
+ * @return bool
+ */
+ public function isAppendingNewlines()
+ {
+ return $this->appendNewline;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatBatch(array $records)
+ {
+ switch ($this->batchMode) {
+ case static::BATCH_MODE_NEWLINES:
+ return $this->formatBatchNewlines($records);
+
+ case static::BATCH_MODE_JSON:
+ default:
+ return $this->formatBatchJson($records);
+ }
+ }
+
+ /**
+ * @param bool $include
+ */
+ public function includeStacktraces($include = true)
+ {
+ $this->includeStacktraces = $include;
+ }
+
+ /**
+ * Return a JSON-encoded array of records.
+ *
+ * @param array $records
+ * @return string
+ */
+ protected function formatBatchJson(array $records)
+ {
+ return $this->toJson($this->normalize($records), true);
+ }
+
+ /**
+ * Use new lines to separate records instead of a
+ * JSON-encoded array.
+ *
+ * @param array $records
+ * @return string
+ */
+ protected function formatBatchNewlines(array $records)
+ {
+ $instance = $this;
+
+ $oldNewline = $this->appendNewline;
+ $this->appendNewline = false;
+ array_walk($records, function (&$value, $key) use ($instance) {
+ $value = $instance->format($value);
+ });
+ $this->appendNewline = $oldNewline;
+
+ return implode("\n", $records);
+ }
+
+ /**
+ * Normalizes given $data.
+ *
+ * @param mixed $data
+ *
+ * @return mixed
+ */
+ protected function normalize($data, $depth = 0)
+ {
+ if ($depth > 9) {
+ return 'Over 9 levels deep, aborting normalization';
+ }
+
+ if (is_array($data)) {
+ $normalized = array();
+
+ $count = 1;
+ foreach ($data as $key => $value) {
+ if ($count++ > 1000) {
+ $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization';
+ break;
+ }
+
+ $normalized[$key] = $this->normalize($value, $depth+1);
+ }
+
+ return $normalized;
+ }
+
+ if ($data instanceof Exception || $data instanceof Throwable) {
+ return $this->normalizeException($data);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Normalizes given exception with or without its own stack trace based on
+ * `includeStacktraces` property.
+ *
+ * @param Exception|Throwable $e
+ *
+ * @return array
+ */
+ protected function normalizeException($e)
+ {
+ // TODO 2.0 only check for Throwable
+ if (!$e instanceof Exception && !$e instanceof Throwable) {
+ throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
+ }
+
+ $data = array(
+ 'class' => Utils::getClass($e),
+ 'message' => $e->getMessage(),
+ 'code' => (int) $e->getCode(),
+ 'file' => $e->getFile().':'.$e->getLine(),
+ );
+
+ if ($this->includeStacktraces) {
+ $trace = $e->getTrace();
+ foreach ($trace as $frame) {
+ if (isset($frame['file'])) {
+ $data['trace'][] = $frame['file'].':'.$frame['line'];
+ }
+ }
+ }
+
+ if ($previous = $e->getPrevious()) {
+ $data['previous'] = $this->normalizeException($previous);
+ }
+
+ return $data;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
new file mode 100644
index 00000000..acc1fd38
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php
@@ -0,0 +1,181 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Utils;
+
+/**
+ * Formats incoming records into a one-line string
+ *
+ * This is especially useful for logging to files
+ *
+ * @author Jordi Boggiano
+ * @author Christophe Coevoet
+ */
+class LineFormatter extends NormalizerFormatter
+{
+ const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
+
+ protected $format;
+ protected $allowInlineLineBreaks;
+ protected $ignoreEmptyContextAndExtra;
+ protected $includeStacktraces;
+
+ /**
+ * @param string $format The format of the message
+ * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+ * @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries
+ * @param bool $ignoreEmptyContextAndExtra
+ */
+ public function __construct($format = null, $dateFormat = null, $allowInlineLineBreaks = false, $ignoreEmptyContextAndExtra = false)
+ {
+ $this->format = $format ?: static::SIMPLE_FORMAT;
+ $this->allowInlineLineBreaks = $allowInlineLineBreaks;
+ $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra;
+ parent::__construct($dateFormat);
+ }
+
+ public function includeStacktraces($include = true)
+ {
+ $this->includeStacktraces = $include;
+ if ($this->includeStacktraces) {
+ $this->allowInlineLineBreaks = true;
+ }
+ }
+
+ public function allowInlineLineBreaks($allow = true)
+ {
+ $this->allowInlineLineBreaks = $allow;
+ }
+
+ public function ignoreEmptyContextAndExtra($ignore = true)
+ {
+ $this->ignoreEmptyContextAndExtra = $ignore;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $vars = parent::format($record);
+
+ $output = $this->format;
+
+ foreach ($vars['extra'] as $var => $val) {
+ if (false !== strpos($output, '%extra.'.$var.'%')) {
+ $output = str_replace('%extra.'.$var.'%', $this->stringify($val), $output);
+ unset($vars['extra'][$var]);
+ }
+ }
+
+
+ foreach ($vars['context'] as $var => $val) {
+ if (false !== strpos($output, '%context.'.$var.'%')) {
+ $output = str_replace('%context.'.$var.'%', $this->stringify($val), $output);
+ unset($vars['context'][$var]);
+ }
+ }
+
+ if ($this->ignoreEmptyContextAndExtra) {
+ if (empty($vars['context'])) {
+ unset($vars['context']);
+ $output = str_replace('%context%', '', $output);
+ }
+
+ if (empty($vars['extra'])) {
+ unset($vars['extra']);
+ $output = str_replace('%extra%', '', $output);
+ }
+ }
+
+ foreach ($vars as $var => $val) {
+ if (false !== strpos($output, '%'.$var.'%')) {
+ $output = str_replace('%'.$var.'%', $this->stringify($val), $output);
+ }
+ }
+
+ // remove leftover %extra.xxx% and %context.xxx% if any
+ if (false !== strpos($output, '%')) {
+ $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output);
+ }
+
+ return $output;
+ }
+
+ public function formatBatch(array $records)
+ {
+ $message = '';
+ foreach ($records as $record) {
+ $message .= $this->format($record);
+ }
+
+ return $message;
+ }
+
+ public function stringify($value)
+ {
+ return $this->replaceNewlines($this->convertToString($value));
+ }
+
+ protected function normalizeException($e)
+ {
+ // TODO 2.0 only check for Throwable
+ if (!$e instanceof \Exception && !$e instanceof \Throwable) {
+ throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
+ }
+
+ $previousText = '';
+ if ($previous = $e->getPrevious()) {
+ do {
+ $previousText .= ', '.Utils::getClass($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
+ } while ($previous = $previous->getPrevious());
+ }
+
+ $str = '[object] ('.Utils::getClass($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')';
+ if ($this->includeStacktraces) {
+ $str .= "\n[stacktrace]\n".$e->getTraceAsString()."\n";
+ }
+
+ return $str;
+ }
+
+ protected function convertToString($data)
+ {
+ if (null === $data || is_bool($data)) {
+ return var_export($data, true);
+ }
+
+ if (is_scalar($data)) {
+ return (string) $data;
+ }
+
+ if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ return $this->toJson($data, true);
+ }
+
+ return str_replace('\\/', '/', $this->toJson($data, true));
+ }
+
+ protected function replaceNewlines($str)
+ {
+ if ($this->allowInlineLineBreaks) {
+ if (0 === strpos($str, '{')) {
+ return str_replace(array('\r', '\n'), array("\r", "\n"), $str);
+ }
+
+ return $str;
+ }
+
+ return str_replace(array("\r\n", "\r", "\n"), ' ', $str);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php
new file mode 100644
index 00000000..401859bb
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php
@@ -0,0 +1,47 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Encodes message information into JSON in a format compatible with Loggly.
+ *
+ * @author Adam Pancutt
+ */
+class LogglyFormatter extends JsonFormatter
+{
+ /**
+ * Overrides the default batch mode to new lines for compatibility with the
+ * Loggly bulk API.
+ *
+ * @param int $batchMode
+ */
+ public function __construct($batchMode = self::BATCH_MODE_NEWLINES, $appendNewline = false)
+ {
+ parent::__construct($batchMode, $appendNewline);
+ }
+
+ /**
+ * Appends the 'timestamp' parameter for indexing by Loggly.
+ *
+ * @see https://www.loggly.com/docs/automated-parsing/#json
+ * @see \Monolog\Formatter\JsonFormatter::format()
+ */
+ public function format(array $record)
+ {
+ if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTime)) {
+ $record["timestamp"] = $record["datetime"]->format("Y-m-d\TH:i:s.uO");
+ // TODO 2.0 unset the 'datetime' parameter, retained for BC
+ }
+
+ return parent::format($record);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php
new file mode 100644
index 00000000..8f83bec0
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php
@@ -0,0 +1,166 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Serializes a log message to Logstash Event Format
+ *
+ * @see http://logstash.net/
+ * @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb
+ *
+ * @author Tim Mower
+ */
+class LogstashFormatter extends NormalizerFormatter
+{
+ const V0 = 0;
+ const V1 = 1;
+
+ /**
+ * @var string the name of the system for the Logstash log message, used to fill the @source field
+ */
+ protected $systemName;
+
+ /**
+ * @var string an application name for the Logstash log message, used to fill the @type field
+ */
+ protected $applicationName;
+
+ /**
+ * @var string a prefix for 'extra' fields from the Monolog record (optional)
+ */
+ protected $extraPrefix;
+
+ /**
+ * @var string a prefix for 'context' fields from the Monolog record (optional)
+ */
+ protected $contextPrefix;
+
+ /**
+ * @var int logstash format version to use
+ */
+ protected $version;
+
+ /**
+ * @param string $applicationName the application that sends the data, used as the "type" field of logstash
+ * @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine
+ * @param string $extraPrefix prefix for extra keys inside logstash "fields"
+ * @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_
+ * @param int $version the logstash format version to use, defaults to 0
+ */
+ public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0)
+ {
+ // logstash requires a ISO 8601 format date with optional millisecond precision.
+ parent::__construct('Y-m-d\TH:i:s.uP');
+
+ $this->systemName = $systemName ?: gethostname();
+ $this->applicationName = $applicationName;
+ $this->extraPrefix = $extraPrefix;
+ $this->contextPrefix = $contextPrefix;
+ $this->version = $version;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ $record = parent::format($record);
+
+ if ($this->version === self::V1) {
+ $message = $this->formatV1($record);
+ } else {
+ $message = $this->formatV0($record);
+ }
+
+ return $this->toJson($message) . "\n";
+ }
+
+ protected function formatV0(array $record)
+ {
+ if (empty($record['datetime'])) {
+ $record['datetime'] = gmdate('c');
+ }
+ $message = array(
+ '@timestamp' => $record['datetime'],
+ '@source' => $this->systemName,
+ '@fields' => array(),
+ );
+ if (isset($record['message'])) {
+ $message['@message'] = $record['message'];
+ }
+ if (isset($record['channel'])) {
+ $message['@tags'] = array($record['channel']);
+ $message['@fields']['channel'] = $record['channel'];
+ }
+ if (isset($record['level'])) {
+ $message['@fields']['level'] = $record['level'];
+ }
+ if ($this->applicationName) {
+ $message['@type'] = $this->applicationName;
+ }
+ if (isset($record['extra']['server'])) {
+ $message['@source_host'] = $record['extra']['server'];
+ }
+ if (isset($record['extra']['url'])) {
+ $message['@source_path'] = $record['extra']['url'];
+ }
+ if (!empty($record['extra'])) {
+ foreach ($record['extra'] as $key => $val) {
+ $message['@fields'][$this->extraPrefix . $key] = $val;
+ }
+ }
+ if (!empty($record['context'])) {
+ foreach ($record['context'] as $key => $val) {
+ $message['@fields'][$this->contextPrefix . $key] = $val;
+ }
+ }
+
+ return $message;
+ }
+
+ protected function formatV1(array $record)
+ {
+ if (empty($record['datetime'])) {
+ $record['datetime'] = gmdate('c');
+ }
+ $message = array(
+ '@timestamp' => $record['datetime'],
+ '@version' => 1,
+ 'host' => $this->systemName,
+ );
+ if (isset($record['message'])) {
+ $message['message'] = $record['message'];
+ }
+ if (isset($record['channel'])) {
+ $message['type'] = $record['channel'];
+ $message['channel'] = $record['channel'];
+ }
+ if (isset($record['level_name'])) {
+ $message['level'] = $record['level_name'];
+ }
+ if ($this->applicationName) {
+ $message['type'] = $this->applicationName;
+ }
+ if (!empty($record['extra'])) {
+ foreach ($record['extra'] as $key => $val) {
+ $message[$this->extraPrefix . $key] = $val;
+ }
+ }
+ if (!empty($record['context'])) {
+ foreach ($record['context'] as $key => $val) {
+ $message[$this->contextPrefix . $key] = $val;
+ }
+ }
+
+ return $message;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php
new file mode 100644
index 00000000..bd9e4c02
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Utils;
+
+/**
+ * Formats a record for use with the MongoDBHandler.
+ *
+ * @author Florian Plattner
+ */
+class MongoDBFormatter implements FormatterInterface
+{
+ private $exceptionTraceAsString;
+ private $maxNestingLevel;
+
+ /**
+ * @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record['context'] is 2
+ * @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings
+ */
+ public function __construct($maxNestingLevel = 3, $exceptionTraceAsString = true)
+ {
+ $this->maxNestingLevel = max($maxNestingLevel, 0);
+ $this->exceptionTraceAsString = (bool) $exceptionTraceAsString;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function format(array $record)
+ {
+ return $this->formatArray($record);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function formatBatch(array $records)
+ {
+ foreach ($records as $key => $record) {
+ $records[$key] = $this->format($record);
+ }
+
+ return $records;
+ }
+
+ protected function formatArray(array $record, $nestingLevel = 0)
+ {
+ if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) {
+ foreach ($record as $name => $value) {
+ if ($value instanceof \DateTime) {
+ $record[$name] = $this->formatDate($value, $nestingLevel + 1);
+ } elseif ($value instanceof \Exception) {
+ $record[$name] = $this->formatException($value, $nestingLevel + 1);
+ } elseif (is_array($value)) {
+ $record[$name] = $this->formatArray($value, $nestingLevel + 1);
+ } elseif (is_object($value)) {
+ $record[$name] = $this->formatObject($value, $nestingLevel + 1);
+ }
+ }
+ } else {
+ $record = '[...]';
+ }
+
+ return $record;
+ }
+
+ protected function formatObject($value, $nestingLevel)
+ {
+ $objectVars = get_object_vars($value);
+ $objectVars['class'] = Utils::getClass($value);
+
+ return $this->formatArray($objectVars, $nestingLevel);
+ }
+
+ protected function formatException(\Exception $exception, $nestingLevel)
+ {
+ $formattedException = array(
+ 'class' => Utils::getClass($exception),
+ 'message' => $exception->getMessage(),
+ 'code' => (int) $exception->getCode(),
+ 'file' => $exception->getFile() . ':' . $exception->getLine(),
+ );
+
+ if ($this->exceptionTraceAsString === true) {
+ $formattedException['trace'] = $exception->getTraceAsString();
+ } else {
+ $formattedException['trace'] = $exception->getTrace();
+ }
+
+ return $this->formatArray($formattedException, $nestingLevel);
+ }
+
+ protected function formatDate(\DateTime $value, $nestingLevel)
+ {
+ return new \MongoDate($value->getTimestamp());
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php
new file mode 100644
index 00000000..61861c86
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php
@@ -0,0 +1,176 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Exception;
+use Monolog\Utils;
+
+/**
+ * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets
+ *
+ * @author Jordi Boggiano
+ */
+class NormalizerFormatter implements FormatterInterface
+{
+ const SIMPLE_DATE = "Y-m-d H:i:s";
+
+ protected $dateFormat;
+
+ /**
+ * @param string $dateFormat The format of the timestamp: one supported by DateTime::format
+ */
+ public function __construct($dateFormat = null)
+ {
+ $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
+ if (!function_exists('json_encode')) {
+ throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ return $this->normalize($record);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatBatch(array $records)
+ {
+ foreach ($records as $key => $record) {
+ $records[$key] = $this->format($record);
+ }
+
+ return $records;
+ }
+
+ protected function normalize($data, $depth = 0)
+ {
+ if ($depth > 9) {
+ return 'Over 9 levels deep, aborting normalization';
+ }
+
+ if (null === $data || is_scalar($data)) {
+ if (is_float($data)) {
+ if (is_infinite($data)) {
+ return ($data > 0 ? '' : '-') . 'INF';
+ }
+ if (is_nan($data)) {
+ return 'NaN';
+ }
+ }
+
+ return $data;
+ }
+
+ if (is_array($data)) {
+ $normalized = array();
+
+ $count = 1;
+ foreach ($data as $key => $value) {
+ if ($count++ > 1000) {
+ $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization';
+ break;
+ }
+
+ $normalized[$key] = $this->normalize($value, $depth+1);
+ }
+
+ return $normalized;
+ }
+
+ if ($data instanceof \DateTime) {
+ return $data->format($this->dateFormat);
+ }
+
+ if (is_object($data)) {
+ // TODO 2.0 only check for Throwable
+ if ($data instanceof Exception || (PHP_VERSION_ID > 70000 && $data instanceof \Throwable)) {
+ return $this->normalizeException($data);
+ }
+
+ // non-serializable objects that implement __toString stringified
+ if (method_exists($data, '__toString') && !$data instanceof \JsonSerializable) {
+ $value = $data->__toString();
+ } else {
+ // the rest is json-serialized in some way
+ $value = $this->toJson($data, true);
+ }
+
+ return sprintf("[object] (%s: %s)", Utils::getClass($data), $value);
+ }
+
+ if (is_resource($data)) {
+ return sprintf('[resource] (%s)', get_resource_type($data));
+ }
+
+ return '[unknown('.gettype($data).')]';
+ }
+
+ protected function normalizeException($e)
+ {
+ // TODO 2.0 only check for Throwable
+ if (!$e instanceof Exception && !$e instanceof \Throwable) {
+ throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e));
+ }
+
+ $data = array(
+ 'class' => Utils::getClass($e),
+ 'message' => $e->getMessage(),
+ 'code' => (int) $e->getCode(),
+ 'file' => $e->getFile().':'.$e->getLine(),
+ );
+
+ if ($e instanceof \SoapFault) {
+ if (isset($e->faultcode)) {
+ $data['faultcode'] = $e->faultcode;
+ }
+
+ if (isset($e->faultactor)) {
+ $data['faultactor'] = $e->faultactor;
+ }
+
+ if (isset($e->detail) && (is_string($e->detail) || is_object($e->detail) || is_array($e->detail))) {
+ $data['detail'] = is_string($e->detail) ? $e->detail : reset($e->detail);
+ }
+ }
+
+ $trace = $e->getTrace();
+ foreach ($trace as $frame) {
+ if (isset($frame['file'])) {
+ $data['trace'][] = $frame['file'].':'.$frame['line'];
+ }
+ }
+
+ if ($previous = $e->getPrevious()) {
+ $data['previous'] = $this->normalizeException($previous);
+ }
+
+ return $data;
+ }
+
+ /**
+ * Return the JSON representation of a value
+ *
+ * @param mixed $data
+ * @param bool $ignoreErrors
+ * @throws \RuntimeException if encoding fails and errors are not ignored
+ * @return string
+ */
+ protected function toJson($data, $ignoreErrors = false)
+ {
+ return Utils::jsonEncode($data, null, $ignoreErrors);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php
new file mode 100644
index 00000000..5d345d53
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+/**
+ * Formats data into an associative array of scalar values.
+ * Objects and arrays will be JSON encoded.
+ *
+ * @author Andrew Lawson
+ */
+class ScalarFormatter extends NormalizerFormatter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ foreach ($record as $key => $value) {
+ $record[$key] = $this->normalizeValue($value);
+ }
+
+ return $record;
+ }
+
+ /**
+ * @param mixed $value
+ * @return mixed
+ */
+ protected function normalizeValue($value)
+ {
+ $normalized = $this->normalize($value);
+
+ if (is_array($normalized) || is_object($normalized)) {
+ return $this->toJson($normalized, true);
+ }
+
+ return $normalized;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php
new file mode 100644
index 00000000..65dba99c
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php
@@ -0,0 +1,113 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Formatter;
+
+use Monolog\Logger;
+
+/**
+ * Serializes a log message according to Wildfire's header requirements
+ *
+ * @author Eric Clemmons (@ericclemmons)
+ * @author Christophe Coevoet
+ * @author Kirill chEbba Chebunin
+ */
+class WildfireFormatter extends NormalizerFormatter
+{
+ const TABLE = 'table';
+
+ /**
+ * Translates Monolog log levels to Wildfire levels.
+ */
+ private $logLevels = array(
+ Logger::DEBUG => 'LOG',
+ Logger::INFO => 'INFO',
+ Logger::NOTICE => 'INFO',
+ Logger::WARNING => 'WARN',
+ Logger::ERROR => 'ERROR',
+ Logger::CRITICAL => 'ERROR',
+ Logger::ALERT => 'ERROR',
+ Logger::EMERGENCY => 'ERROR',
+ );
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(array $record)
+ {
+ // Retrieve the line and file if set and remove them from the formatted extra
+ $file = $line = '';
+ if (isset($record['extra']['file'])) {
+ $file = $record['extra']['file'];
+ unset($record['extra']['file']);
+ }
+ if (isset($record['extra']['line'])) {
+ $line = $record['extra']['line'];
+ unset($record['extra']['line']);
+ }
+
+ $record = $this->normalize($record);
+ $message = array('message' => $record['message']);
+ $handleError = false;
+ if ($record['context']) {
+ $message['context'] = $record['context'];
+ $handleError = true;
+ }
+ if ($record['extra']) {
+ $message['extra'] = $record['extra'];
+ $handleError = true;
+ }
+ if (count($message) === 1) {
+ $message = reset($message);
+ }
+
+ if (isset($record['context'][self::TABLE])) {
+ $type = 'TABLE';
+ $label = $record['channel'] .': '. $record['message'];
+ $message = $record['context'][self::TABLE];
+ } else {
+ $type = $this->logLevels[$record['level']];
+ $label = $record['channel'];
+ }
+
+ // Create JSON object describing the appearance of the message in the console
+ $json = $this->toJson(array(
+ array(
+ 'Type' => $type,
+ 'File' => $file,
+ 'Line' => $line,
+ 'Label' => $label,
+ ),
+ $message,
+ ), $handleError);
+
+ // The message itself is a serialization of the above JSON object + it's length
+ return sprintf(
+ '%s|%s|',
+ strlen($json),
+ $json
+ );
+ }
+
+ public function formatBatch(array $records)
+ {
+ throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter');
+ }
+
+ protected function normalize($data, $depth = 0)
+ {
+ if (is_object($data) && !$data instanceof \DateTime) {
+ return $data;
+ }
+
+ return parent::normalize($data, $depth);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php
new file mode 100644
index 00000000..92b9d458
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php
@@ -0,0 +1,196 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+use Monolog\ResettableInterface;
+
+/**
+ * Base Handler class providing the Handler structure
+ *
+ * @author Jordi Boggiano
+ */
+abstract class AbstractHandler implements HandlerInterface, ResettableInterface
+{
+ protected $level = Logger::DEBUG;
+ protected $bubble = true;
+
+ /**
+ * @var FormatterInterface
+ */
+ protected $formatter;
+ protected $processors = array();
+
+ /**
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($level = Logger::DEBUG, $bubble = true)
+ {
+ $this->setLevel($level);
+ $this->bubble = $bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return $record['level'] >= $this->level;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ foreach ($records as $record) {
+ $this->handle($record);
+ }
+ }
+
+ /**
+ * Closes the handler.
+ *
+ * This will be called automatically when the object is destroyed
+ */
+ public function close()
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pushProcessor($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
+ }
+ array_unshift($this->processors, $callback);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function popProcessor()
+ {
+ if (!$this->processors) {
+ throw new \LogicException('You tried to pop from an empty processor stack.');
+ }
+
+ return array_shift($this->processors);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->formatter = $formatter;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter()
+ {
+ if (!$this->formatter) {
+ $this->formatter = $this->getDefaultFormatter();
+ }
+
+ return $this->formatter;
+ }
+
+ /**
+ * Sets minimum logging level at which this handler will be triggered.
+ *
+ * @param int|string $level Level or level name
+ * @return self
+ */
+ public function setLevel($level)
+ {
+ $this->level = Logger::toMonologLevel($level);
+
+ return $this;
+ }
+
+ /**
+ * Gets minimum logging level at which this handler will be triggered.
+ *
+ * @return int
+ */
+ public function getLevel()
+ {
+ return $this->level;
+ }
+
+ /**
+ * Sets the bubbling behavior.
+ *
+ * @param bool $bubble true means that this handler allows bubbling.
+ * false means that bubbling is not permitted.
+ * @return self
+ */
+ public function setBubble($bubble)
+ {
+ $this->bubble = $bubble;
+
+ return $this;
+ }
+
+ /**
+ * Gets the bubbling behavior.
+ *
+ * @return bool true means that this handler allows bubbling.
+ * false means that bubbling is not permitted.
+ */
+ public function getBubble()
+ {
+ return $this->bubble;
+ }
+
+ public function __destruct()
+ {
+ try {
+ $this->close();
+ } catch (\Exception $e) {
+ // do nothing
+ } catch (\Throwable $e) {
+ // do nothing
+ }
+ }
+
+ public function reset()
+ {
+ foreach ($this->processors as $processor) {
+ if ($processor instanceof ResettableInterface) {
+ $processor->reset();
+ }
+ }
+ }
+
+ /**
+ * Gets the default formatter.
+ *
+ * @return FormatterInterface
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php
new file mode 100644
index 00000000..e1e89530
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\ResettableInterface;
+
+/**
+ * Base Handler class providing the Handler structure
+ *
+ * Classes extending it should (in most cases) only implement write($record)
+ *
+ * @author Jordi Boggiano
+ * @author Christophe Coevoet
+ */
+abstract class AbstractProcessingHandler extends AbstractHandler
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if (!$this->isHandling($record)) {
+ return false;
+ }
+
+ $record = $this->processRecord($record);
+
+ $record['formatted'] = $this->getFormatter()->format($record);
+
+ $this->write($record);
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * Writes the record down to the log of the implementing handler
+ *
+ * @param array $record
+ * @return void
+ */
+ abstract protected function write(array $record);
+
+ /**
+ * Processes a record.
+ *
+ * @param array $record
+ * @return array
+ */
+ protected function processRecord(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ return $record;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php
new file mode 100644
index 00000000..8c76aca0
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php
@@ -0,0 +1,101 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Common syslog functionality
+ */
+abstract class AbstractSyslogHandler extends AbstractProcessingHandler
+{
+ protected $facility;
+
+ /**
+ * Translates Monolog log levels to syslog log priorities.
+ */
+ protected $logLevels = array(
+ Logger::DEBUG => LOG_DEBUG,
+ Logger::INFO => LOG_INFO,
+ Logger::NOTICE => LOG_NOTICE,
+ Logger::WARNING => LOG_WARNING,
+ Logger::ERROR => LOG_ERR,
+ Logger::CRITICAL => LOG_CRIT,
+ Logger::ALERT => LOG_ALERT,
+ Logger::EMERGENCY => LOG_EMERG,
+ );
+
+ /**
+ * List of valid log facility names.
+ */
+ protected $facilities = array(
+ 'auth' => LOG_AUTH,
+ 'authpriv' => LOG_AUTHPRIV,
+ 'cron' => LOG_CRON,
+ 'daemon' => LOG_DAEMON,
+ 'kern' => LOG_KERN,
+ 'lpr' => LOG_LPR,
+ 'mail' => LOG_MAIL,
+ 'news' => LOG_NEWS,
+ 'syslog' => LOG_SYSLOG,
+ 'user' => LOG_USER,
+ 'uucp' => LOG_UUCP,
+ );
+
+ /**
+ * @param mixed $facility
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
+ $this->facilities['local0'] = LOG_LOCAL0;
+ $this->facilities['local1'] = LOG_LOCAL1;
+ $this->facilities['local2'] = LOG_LOCAL2;
+ $this->facilities['local3'] = LOG_LOCAL3;
+ $this->facilities['local4'] = LOG_LOCAL4;
+ $this->facilities['local5'] = LOG_LOCAL5;
+ $this->facilities['local6'] = LOG_LOCAL6;
+ $this->facilities['local7'] = LOG_LOCAL7;
+ } else {
+ $this->facilities['local0'] = 128; // LOG_LOCAL0
+ $this->facilities['local1'] = 136; // LOG_LOCAL1
+ $this->facilities['local2'] = 144; // LOG_LOCAL2
+ $this->facilities['local3'] = 152; // LOG_LOCAL3
+ $this->facilities['local4'] = 160; // LOG_LOCAL4
+ $this->facilities['local5'] = 168; // LOG_LOCAL5
+ $this->facilities['local6'] = 176; // LOG_LOCAL6
+ $this->facilities['local7'] = 184; // LOG_LOCAL7
+ }
+
+ // convert textual description of facility to syslog constant
+ if (array_key_exists(strtolower($facility), $this->facilities)) {
+ $facility = $this->facilities[strtolower($facility)];
+ } elseif (!in_array($facility, array_values($this->facilities), true)) {
+ throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given');
+ }
+
+ $this->facility = $facility;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%');
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php
new file mode 100644
index 00000000..e5a46bc0
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php
@@ -0,0 +1,148 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\JsonFormatter;
+use PhpAmqpLib\Message\AMQPMessage;
+use PhpAmqpLib\Channel\AMQPChannel;
+use AMQPExchange;
+
+class AmqpHandler extends AbstractProcessingHandler
+{
+ /**
+ * @var AMQPExchange|AMQPChannel $exchange
+ */
+ protected $exchange;
+
+ /**
+ * @var string
+ */
+ protected $exchangeName;
+
+ /**
+ * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use
+ * @param string $exchangeName
+ * @param int $level
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true)
+ {
+ if ($exchange instanceof AMQPExchange) {
+ $exchange->setName($exchangeName);
+ } elseif ($exchange instanceof AMQPChannel) {
+ $this->exchangeName = $exchangeName;
+ } else {
+ throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required');
+ }
+ $this->exchange = $exchange;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $data = $record["formatted"];
+ $routingKey = $this->getRoutingKey($record);
+
+ if ($this->exchange instanceof AMQPExchange) {
+ $this->exchange->publish(
+ $data,
+ $routingKey,
+ 0,
+ array(
+ 'delivery_mode' => 2,
+ 'content_type' => 'application/json',
+ )
+ );
+ } else {
+ $this->exchange->basic_publish(
+ $this->createAmqpMessage($data),
+ $this->exchangeName,
+ $routingKey
+ );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function handleBatch(array $records)
+ {
+ if ($this->exchange instanceof AMQPExchange) {
+ parent::handleBatch($records);
+
+ return;
+ }
+
+ foreach ($records as $record) {
+ if (!$this->isHandling($record)) {
+ continue;
+ }
+
+ $record = $this->processRecord($record);
+ $data = $this->getFormatter()->format($record);
+
+ $this->exchange->batch_basic_publish(
+ $this->createAmqpMessage($data),
+ $this->exchangeName,
+ $this->getRoutingKey($record)
+ );
+ }
+
+ $this->exchange->publish_batch();
+ }
+
+ /**
+ * Gets the routing key for the AMQP exchange
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function getRoutingKey(array $record)
+ {
+ $routingKey = sprintf(
+ '%s.%s',
+ // TODO 2.0 remove substr call
+ substr($record['level_name'], 0, 4),
+ $record['channel']
+ );
+
+ return strtolower($routingKey);
+ }
+
+ /**
+ * @param string $data
+ * @return AMQPMessage
+ */
+ private function createAmqpMessage($data)
+ {
+ return new AMQPMessage(
+ (string) $data,
+ array(
+ 'delivery_mode' => 2,
+ 'content_type' => 'application/json',
+ )
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php
new file mode 100644
index 00000000..68feb480
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php
@@ -0,0 +1,241 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Handler sending logs to browser's javascript console with no browser extension required
+ *
+ * @author Olivier Poitrey
+ */
+class BrowserConsoleHandler extends AbstractProcessingHandler
+{
+ protected static $initialized = false;
+ protected static $records = array();
+
+ /**
+ * {@inheritDoc}
+ *
+ * Formatted output may contain some formatting markers to be transferred to `console.log` using the %c format.
+ *
+ * Example of formatted string:
+ *
+ * You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ // Accumulate records
+ static::$records[] = $record;
+
+ // Register shutdown handler if not already done
+ if (!static::$initialized) {
+ static::$initialized = true;
+ $this->registerShutdownFunction();
+ }
+ }
+
+ /**
+ * Convert records to javascript console commands and send it to the browser.
+ * This method is automatically called on PHP shutdown if output is HTML or Javascript.
+ */
+ public static function send()
+ {
+ $format = static::getResponseFormat();
+ if ($format === 'unknown') {
+ return;
+ }
+
+ if (count(static::$records)) {
+ if ($format === 'html') {
+ static::writeOutput('');
+ } elseif ($format === 'js') {
+ static::writeOutput(static::generateScript());
+ }
+ static::resetStatic();
+ }
+ }
+
+ public function close()
+ {
+ self::resetStatic();
+ }
+
+ public function reset()
+ {
+ self::resetStatic();
+ }
+
+ /**
+ * Forget all logged records
+ */
+ public static function resetStatic()
+ {
+ static::$records = array();
+ }
+
+ /**
+ * Wrapper for register_shutdown_function to allow overriding
+ */
+ protected function registerShutdownFunction()
+ {
+ if (PHP_SAPI !== 'cli') {
+ register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
+ }
+ }
+
+ /**
+ * Wrapper for echo to allow overriding
+ *
+ * @param string $str
+ */
+ protected static function writeOutput($str)
+ {
+ echo $str;
+ }
+
+ /**
+ * Checks the format of the response
+ *
+ * If Content-Type is set to application/javascript or text/javascript -> js
+ * If Content-Type is set to text/html, or is unset -> html
+ * If Content-Type is anything else -> unknown
+ *
+ * @return string One of 'js', 'html' or 'unknown'
+ */
+ protected static function getResponseFormat()
+ {
+ // Check content type
+ foreach (headers_list() as $header) {
+ if (stripos($header, 'content-type:') === 0) {
+ // This handler only works with HTML and javascript outputs
+ // text/javascript is obsolete in favour of application/javascript, but still used
+ if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
+ return 'js';
+ }
+ if (stripos($header, 'text/html') === false) {
+ return 'unknown';
+ }
+ break;
+ }
+ }
+
+ return 'html';
+ }
+
+ private static function generateScript()
+ {
+ $script = array();
+ foreach (static::$records as $record) {
+ $context = static::dump('Context', $record['context']);
+ $extra = static::dump('Extra', $record['extra']);
+
+ if (empty($context) && empty($extra)) {
+ $script[] = static::call_array('log', static::handleStyles($record['formatted']));
+ } else {
+ $script = array_merge($script,
+ array(static::call_array('groupCollapsed', static::handleStyles($record['formatted']))),
+ $context,
+ $extra,
+ array(static::call('groupEnd'))
+ );
+ }
+ }
+
+ return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
+ }
+
+ private static function handleStyles($formatted)
+ {
+ $args = array();
+ $format = '%c' . $formatted;
+ preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
+
+ foreach (array_reverse($matches) as $match) {
+ $args[] = '"font-weight: normal"';
+ $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
+
+ $pos = $match[0][1];
+ $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
+ }
+
+ $args[] = static::quote('font-weight: normal');
+ $args[] = static::quote($format);
+
+ return array_reverse($args);
+ }
+
+ private static function handleCustomStyles($style, $string)
+ {
+ static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey');
+ static $labels = array();
+
+ return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) {
+ if (trim($m[1]) === 'autolabel') {
+ // Format the string as a label with consistent auto assigned background color
+ if (!isset($labels[$string])) {
+ $labels[$string] = $colors[count($labels) % count($colors)];
+ }
+ $color = $labels[$string];
+
+ return "background-color: $color; color: white; border-radius: 3px; padding: 0 2px 0 2px";
+ }
+
+ return $m[1];
+ }, $style);
+ }
+
+ private static function dump($title, array $dict)
+ {
+ $script = array();
+ $dict = array_filter($dict);
+ if (empty($dict)) {
+ return $script;
+ }
+ $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title));
+ foreach ($dict as $key => $value) {
+ $value = json_encode($value);
+ if (empty($value)) {
+ $value = static::quote('');
+ }
+ $script[] = static::call('log', static::quote('%s: %o'), static::quote($key), $value);
+ }
+
+ return $script;
+ }
+
+ private static function quote($arg)
+ {
+ return '"' . addcslashes($arg, "\"\n\\") . '"';
+ }
+
+ private static function call()
+ {
+ $args = func_get_args();
+ $method = array_shift($args);
+
+ return static::call_array($method, $args);
+ }
+
+ private static function call_array($method, array $args)
+ {
+ return 'c.' . $method . '(' . implode(', ', $args) . ');';
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php
new file mode 100644
index 00000000..0957e558
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php
@@ -0,0 +1,148 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\ResettableInterface;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Buffers all records until closing the handler and then pass them as batch.
+ *
+ * This is useful for a MailHandler to send only one mail per request instead of
+ * sending one per log message.
+ *
+ * @author Christophe Coevoet
+ */
+class BufferHandler extends AbstractHandler
+{
+ protected $handler;
+ protected $bufferSize = 0;
+ protected $bufferLimit;
+ protected $flushOnOverflow;
+ protected $buffer = array();
+ protected $initialized = false;
+
+ /**
+ * @param HandlerInterface $handler Handler.
+ * @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
+ */
+ public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
+ {
+ parent::__construct($level, $bubble);
+ $this->handler = $handler;
+ $this->bufferLimit = (int) $bufferLimit;
+ $this->flushOnOverflow = $flushOnOverflow;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($record['level'] < $this->level) {
+ return false;
+ }
+
+ if (!$this->initialized) {
+ // __destructor() doesn't get called on Fatal errors
+ register_shutdown_function(array($this, 'close'));
+ $this->initialized = true;
+ }
+
+ if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
+ if ($this->flushOnOverflow) {
+ $this->flush();
+ } else {
+ array_shift($this->buffer);
+ $this->bufferSize--;
+ }
+ }
+
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ $this->buffer[] = $record;
+ $this->bufferSize++;
+
+ return false === $this->bubble;
+ }
+
+ public function flush()
+ {
+ if ($this->bufferSize === 0) {
+ return;
+ }
+
+ $this->handler->handleBatch($this->buffer);
+ $this->clear();
+ }
+
+ public function __destruct()
+ {
+ // suppress the parent behavior since we already have register_shutdown_function()
+ // to call close(), and the reference contained there will prevent this from being
+ // GC'd until the end of the request
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->flush();
+ }
+
+ /**
+ * Clears the buffer without flushing any messages down to the wrapped handler.
+ */
+ public function clear()
+ {
+ $this->bufferSize = 0;
+ $this->buffer = array();
+ }
+
+ public function reset()
+ {
+ $this->flush();
+
+ parent::reset();
+
+ if ($this->handler instanceof ResettableInterface) {
+ $this->handler->reset();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->handler->setFormatter($formatter);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter()
+ {
+ return $this->handler->getFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php
new file mode 100644
index 00000000..47120e54
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php
@@ -0,0 +1,212 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\ChromePHPFormatter;
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
+ *
+ * This also works out of the box with Firefox 43+
+ *
+ * @author Christophe Coevoet
+ */
+class ChromePHPHandler extends AbstractProcessingHandler
+{
+ /**
+ * Version of the extension
+ */
+ const VERSION = '4.0';
+
+ /**
+ * Header name
+ */
+ const HEADER_NAME = 'X-ChromeLogger-Data';
+
+ /**
+ * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+)
+ */
+ const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}';
+
+ protected static $initialized = false;
+
+ /**
+ * Tracks whether we sent too much data
+ *
+ * Chrome limits the headers to 4KB, so when we sent 3KB we stop sending
+ *
+ * @var bool
+ */
+ protected static $overflowed = false;
+
+ protected static $json = array(
+ 'version' => self::VERSION,
+ 'columns' => array('label', 'log', 'backtrace', 'type'),
+ 'rows' => array(),
+ );
+
+ protected static $sendHeaders = true;
+
+ /**
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+ if (!function_exists('json_encode')) {
+ throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s ChromePHPHandler');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $messages = array();
+
+ foreach ($records as $record) {
+ if ($record['level'] < $this->level) {
+ continue;
+ }
+ $messages[] = $this->processRecord($record);
+ }
+
+ if (!empty($messages)) {
+ $messages = $this->getFormatter()->formatBatch($messages);
+ self::$json['rows'] = array_merge(self::$json['rows'], $messages);
+ $this->send();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new ChromePHPFormatter();
+ }
+
+ /**
+ * Creates & sends header for a record
+ *
+ * @see sendHeader()
+ * @see send()
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ self::$json['rows'][] = $record['formatted'];
+
+ $this->send();
+ }
+
+ /**
+ * Sends the log header
+ *
+ * @see sendHeader()
+ */
+ protected function send()
+ {
+ if (self::$overflowed || !self::$sendHeaders) {
+ return;
+ }
+
+ if (!self::$initialized) {
+ self::$initialized = true;
+
+ self::$sendHeaders = $this->headersAccepted();
+ if (!self::$sendHeaders) {
+ return;
+ }
+
+ self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
+ }
+
+ $json = Utils::jsonEncode(self::$json, null, true);
+ $data = base64_encode(utf8_encode($json));
+ if (strlen($data) > 3 * 1024) {
+ self::$overflowed = true;
+
+ $record = array(
+ 'message' => 'Incomplete logs, chrome header size limit reached',
+ 'context' => array(),
+ 'level' => Logger::WARNING,
+ 'level_name' => Logger::getLevelName(Logger::WARNING),
+ 'channel' => 'monolog',
+ 'datetime' => new \DateTime(),
+ 'extra' => array(),
+ );
+ self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
+ $json = Utils::jsonEncode(self::$json, null, true);
+ $data = base64_encode(utf8_encode($json));
+ }
+
+ if (trim($data) !== '') {
+ $this->sendHeader(self::HEADER_NAME, $data);
+ }
+ }
+
+ /**
+ * Send header string to the client
+ *
+ * @param string $header
+ * @param string $content
+ */
+ protected function sendHeader($header, $content)
+ {
+ if (!headers_sent() && self::$sendHeaders) {
+ header(sprintf('%s: %s', $header, $content));
+ }
+ }
+
+ /**
+ * Verifies if the headers are accepted by the current user agent
+ *
+ * @return bool
+ */
+ protected function headersAccepted()
+ {
+ if (empty($_SERVER['HTTP_USER_AGENT'])) {
+ return false;
+ }
+
+ return preg_match(self::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']);
+ }
+
+ /**
+ * BC getter for the sendHeaders property that has been made static
+ */
+ public function __get($property)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ return static::$sendHeaders;
+ }
+
+ /**
+ * BC setter for the sendHeaders property that has been made static
+ */
+ public function __set($property, $value)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ static::$sendHeaders = $value;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php
new file mode 100644
index 00000000..cc986971
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\JsonFormatter;
+use Monolog\Logger;
+
+/**
+ * CouchDB handler
+ *
+ * @author Markus Bachmann
+ */
+class CouchDBHandler extends AbstractProcessingHandler
+{
+ private $options;
+
+ public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true)
+ {
+ $this->options = array_merge(array(
+ 'host' => 'localhost',
+ 'port' => 5984,
+ 'dbname' => 'logger',
+ 'username' => null,
+ 'password' => null,
+ ), $options);
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $basicAuth = null;
+ if ($this->options['username']) {
+ $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']);
+ }
+
+ $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname'];
+ $context = stream_context_create(array(
+ 'http' => array(
+ 'method' => 'POST',
+ 'content' => $record['formatted'],
+ 'ignore_errors' => true,
+ 'max_redirects' => 0,
+ 'header' => 'Content-type: application/json',
+ ),
+ ));
+
+ if (false === @file_get_contents($url, null, $context)) {
+ throw new \RuntimeException(sprintf('Could not connect to %s', $url));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php
new file mode 100644
index 00000000..44928efb
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php
@@ -0,0 +1,152 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * Logs to Cube.
+ *
+ * @link http://square.github.com/cube/
+ * @author Wan Chen
+ */
+class CubeHandler extends AbstractProcessingHandler
+{
+ private $udpConnection;
+ private $httpConnection;
+ private $scheme;
+ private $host;
+ private $port;
+ private $acceptedSchemes = array('http', 'udp');
+
+ /**
+ * Create a Cube handler
+ *
+ * @throws \UnexpectedValueException when given url is not a valid url.
+ * A valid url must consist of three parts : protocol://host:port
+ * Only valid protocols used by Cube are http and udp
+ */
+ public function __construct($url, $level = Logger::DEBUG, $bubble = true)
+ {
+ $urlInfo = parse_url($url);
+
+ if (!isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) {
+ throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
+ }
+
+ if (!in_array($urlInfo['scheme'], $this->acceptedSchemes)) {
+ throw new \UnexpectedValueException(
+ 'Invalid protocol (' . $urlInfo['scheme'] . ').'
+ . ' Valid options are ' . implode(', ', $this->acceptedSchemes));
+ }
+
+ $this->scheme = $urlInfo['scheme'];
+ $this->host = $urlInfo['host'];
+ $this->port = $urlInfo['port'];
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * Establish a connection to an UDP socket
+ *
+ * @throws \LogicException when unable to connect to the socket
+ * @throws MissingExtensionException when there is no socket extension
+ */
+ protected function connectUdp()
+ {
+ if (!extension_loaded('sockets')) {
+ throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler');
+ }
+
+ $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0);
+ if (!$this->udpConnection) {
+ throw new \LogicException('Unable to create a socket');
+ }
+
+ if (!socket_connect($this->udpConnection, $this->host, $this->port)) {
+ throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port);
+ }
+ }
+
+ /**
+ * Establish a connection to a http server
+ * @throws \LogicException when no curl extension
+ */
+ protected function connectHttp()
+ {
+ if (!extension_loaded('curl')) {
+ throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler');
+ }
+
+ $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put');
+
+ if (!$this->httpConnection) {
+ throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port);
+ }
+
+ curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST");
+ curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $date = $record['datetime'];
+
+ $data = array('time' => $date->format('Y-m-d\TH:i:s.uO'));
+ unset($record['datetime']);
+
+ if (isset($record['context']['type'])) {
+ $data['type'] = $record['context']['type'];
+ unset($record['context']['type']);
+ } else {
+ $data['type'] = $record['channel'];
+ }
+
+ $data['data'] = $record['context'];
+ $data['data']['level'] = $record['level'];
+
+ if ($this->scheme === 'http') {
+ $this->writeHttp(Utils::jsonEncode($data));
+ } else {
+ $this->writeUdp(Utils::jsonEncode($data));
+ }
+ }
+
+ private function writeUdp($data)
+ {
+ if (!$this->udpConnection) {
+ $this->connectUdp();
+ }
+
+ socket_send($this->udpConnection, $data, strlen($data), 0);
+ }
+
+ private function writeHttp($data)
+ {
+ if (!$this->httpConnection) {
+ $this->connectHttp();
+ }
+
+ curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
+ curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array(
+ 'Content-Type: application/json',
+ 'Content-Length: ' . strlen('['.$data.']'),
+ ));
+
+ Curl\Util::execute($this->httpConnection, 5, false);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php
new file mode 100644
index 00000000..48d30b35
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\Curl;
+
+class Util
+{
+ private static $retriableErrorCodes = array(
+ CURLE_COULDNT_RESOLVE_HOST,
+ CURLE_COULDNT_CONNECT,
+ CURLE_HTTP_NOT_FOUND,
+ CURLE_READ_ERROR,
+ CURLE_OPERATION_TIMEOUTED,
+ CURLE_HTTP_POST_ERROR,
+ CURLE_SSL_CONNECT_ERROR,
+ );
+
+ /**
+ * Executes a CURL request with optional retries and exception on failure
+ *
+ * @param resource $ch curl handler
+ * @throws \RuntimeException
+ */
+ public static function execute($ch, $retries = 5, $closeAfterDone = true)
+ {
+ while ($retries--) {
+ if (curl_exec($ch) === false) {
+ $curlErrno = curl_errno($ch);
+
+ if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) {
+ $curlError = curl_error($ch);
+
+ if ($closeAfterDone) {
+ curl_close($ch);
+ }
+
+ throw new \RuntimeException(sprintf('Curl error (code %s): %s', $curlErrno, $curlError));
+ }
+
+ continue;
+ }
+
+ if ($closeAfterDone) {
+ curl_close($ch);
+ }
+ break;
+ }
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php
new file mode 100644
index 00000000..35b55cb4
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php
@@ -0,0 +1,169 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Simple handler wrapper that deduplicates log records across multiple requests
+ *
+ * It also includes the BufferHandler functionality and will buffer
+ * all messages until the end of the request or flush() is called.
+ *
+ * This works by storing all log records' messages above $deduplicationLevel
+ * to the file specified by $deduplicationStore. When further logs come in at the end of the
+ * request (or when flush() is called), all those above $deduplicationLevel are checked
+ * against the existing stored logs. If they match and the timestamps in the stored log is
+ * not older than $time seconds, the new log record is discarded. If no log record is new, the
+ * whole data set is discarded.
+ *
+ * This is mainly useful in combination with Mail handlers or things like Slack or HipChat handlers
+ * that send messages to people, to avoid spamming with the same message over and over in case of
+ * a major component failure like a database server being down which makes all requests fail in the
+ * same way.
+ *
+ * @author Jordi Boggiano
+ */
+class DeduplicationHandler extends BufferHandler
+{
+ /**
+ * @var string
+ */
+ protected $deduplicationStore;
+
+ /**
+ * @var int
+ */
+ protected $deduplicationLevel;
+
+ /**
+ * @var int
+ */
+ protected $time;
+
+ /**
+ * @var bool
+ */
+ private $gc = false;
+
+ /**
+ * @param HandlerInterface $handler Handler.
+ * @param string $deduplicationStore The file/path where the deduplication log should be kept
+ * @param int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes
+ * @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true)
+ {
+ parent::__construct($handler, 0, Logger::DEBUG, $bubble, false);
+
+ $this->deduplicationStore = $deduplicationStore === null ? sys_get_temp_dir() . '/monolog-dedup-' . substr(md5(__FILE__), 0, 20) .'.log' : $deduplicationStore;
+ $this->deduplicationLevel = Logger::toMonologLevel($deduplicationLevel);
+ $this->time = $time;
+ }
+
+ public function flush()
+ {
+ if ($this->bufferSize === 0) {
+ return;
+ }
+
+ $passthru = null;
+
+ foreach ($this->buffer as $record) {
+ if ($record['level'] >= $this->deduplicationLevel) {
+
+ $passthru = $passthru || !$this->isDuplicate($record);
+ if ($passthru) {
+ $this->appendRecord($record);
+ }
+ }
+ }
+
+ // default of null is valid as well as if no record matches duplicationLevel we just pass through
+ if ($passthru === true || $passthru === null) {
+ $this->handler->handleBatch($this->buffer);
+ }
+
+ $this->clear();
+
+ if ($this->gc) {
+ $this->collectLogs();
+ }
+ }
+
+ private function isDuplicate(array $record)
+ {
+ if (!file_exists($this->deduplicationStore)) {
+ return false;
+ }
+
+ $store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+ if (!is_array($store)) {
+ return false;
+ }
+
+ $yesterday = time() - 86400;
+ $timestampValidity = $record['datetime']->getTimestamp() - $this->time;
+ $expectedMessage = preg_replace('{[\r\n].*}', '', $record['message']);
+
+ for ($i = count($store) - 1; $i >= 0; $i--) {
+ list($timestamp, $level, $message) = explode(':', $store[$i], 3);
+
+ if ($level === $record['level_name'] && $message === $expectedMessage && $timestamp > $timestampValidity) {
+ return true;
+ }
+
+ if ($timestamp < $yesterday) {
+ $this->gc = true;
+ }
+ }
+
+ return false;
+ }
+
+ private function collectLogs()
+ {
+ if (!file_exists($this->deduplicationStore)) {
+ return false;
+ }
+
+ $handle = fopen($this->deduplicationStore, 'rw+');
+ flock($handle, LOCK_EX);
+ $validLogs = array();
+
+ $timestampValidity = time() - $this->time;
+
+ while (!feof($handle)) {
+ $log = fgets($handle);
+ if (substr($log, 0, 10) >= $timestampValidity) {
+ $validLogs[] = $log;
+ }
+ }
+
+ ftruncate($handle, 0);
+ rewind($handle);
+ foreach ($validLogs as $log) {
+ fwrite($handle, $log);
+ }
+
+ flock($handle, LOCK_UN);
+ fclose($handle);
+
+ $this->gc = false;
+ }
+
+ private function appendRecord(array $record)
+ {
+ file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php
new file mode 100644
index 00000000..b91ffec9
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\NormalizerFormatter;
+use Doctrine\CouchDB\CouchDBClient;
+
+/**
+ * CouchDB handler for Doctrine CouchDB ODM
+ *
+ * @author Markus Bachmann
+ */
+class DoctrineCouchDBHandler extends AbstractProcessingHandler
+{
+ private $client;
+
+ public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true)
+ {
+ $this->client = $client;
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $this->client->postDocument($record['formatted']);
+ }
+
+ protected function getDefaultFormatter()
+ {
+ return new NormalizerFormatter;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php
new file mode 100644
index 00000000..237b71f6
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Aws\Sdk;
+use Aws\DynamoDb\DynamoDbClient;
+use Aws\DynamoDb\Marshaler;
+use Monolog\Formatter\ScalarFormatter;
+use Monolog\Logger;
+
+/**
+ * Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/)
+ *
+ * @link https://github.com/aws/aws-sdk-php/
+ * @author Andrew Lawson
+ */
+class DynamoDbHandler extends AbstractProcessingHandler
+{
+ const DATE_FORMAT = 'Y-m-d\TH:i:s.uO';
+
+ /**
+ * @var DynamoDbClient
+ */
+ protected $client;
+
+ /**
+ * @var string
+ */
+ protected $table;
+
+ /**
+ * @var int
+ */
+ protected $version;
+
+ /**
+ * @var Marshaler
+ */
+ protected $marshaler;
+
+ /**
+ * @param DynamoDbClient $client
+ * @param string $table
+ * @param int $level
+ * @param bool $bubble
+ */
+ public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (defined('Aws\Sdk::VERSION') && version_compare(Sdk::VERSION, '3.0', '>=')) {
+ $this->version = 3;
+ $this->marshaler = new Marshaler;
+ } else {
+ $this->version = 2;
+ }
+
+ $this->client = $client;
+ $this->table = $table;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $filtered = $this->filterEmptyFields($record['formatted']);
+ if ($this->version === 3) {
+ $formatted = $this->marshaler->marshalItem($filtered);
+ } else {
+ $formatted = $this->client->formatAttributes($filtered);
+ }
+
+ $this->client->putItem(array(
+ 'TableName' => $this->table,
+ 'Item' => $formatted,
+ ));
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ protected function filterEmptyFields(array $record)
+ {
+ return array_filter($record, function ($value) {
+ return !empty($value) || false === $value || 0 === $value;
+ });
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new ScalarFormatter(self::DATE_FORMAT);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php
new file mode 100644
index 00000000..bb0f83eb
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php
@@ -0,0 +1,128 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\ElasticaFormatter;
+use Monolog\Logger;
+use Elastica\Client;
+use Elastica\Exception\ExceptionInterface;
+
+/**
+ * Elastic Search handler
+ *
+ * Usage example:
+ *
+ * $client = new \Elastica\Client();
+ * $options = array(
+ * 'index' => 'elastic_index_name',
+ * 'type' => 'elastic_doc_type',
+ * );
+ * $handler = new ElasticSearchHandler($client, $options);
+ * $log = new Logger('application');
+ * $log->pushHandler($handler);
+ *
+ * @author Jelle Vink
+ */
+class ElasticSearchHandler extends AbstractProcessingHandler
+{
+ /**
+ * @var Client
+ */
+ protected $client;
+
+ /**
+ * @var array Handler config options
+ */
+ protected $options = array();
+
+ /**
+ * @param Client $client Elastica Client object
+ * @param array $options Handler configuration
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+ $this->client = $client;
+ $this->options = array_merge(
+ array(
+ 'index' => 'monolog', // Elastic index name
+ 'type' => 'record', // Elastic document type
+ 'ignore_error' => false, // Suppress Elastica exceptions
+ ),
+ $options
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ $this->bulkSend(array($record['formatted']));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ if ($formatter instanceof ElasticaFormatter) {
+ return parent::setFormatter($formatter);
+ }
+ throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter');
+ }
+
+ /**
+ * Getter options
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new ElasticaFormatter($this->options['index'], $this->options['type']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $documents = $this->getFormatter()->formatBatch($records);
+ $this->bulkSend($documents);
+ }
+
+ /**
+ * Use Elasticsearch bulk API to send list of documents
+ * @param array $documents
+ * @throws \RuntimeException
+ */
+ protected function bulkSend(array $documents)
+ {
+ try {
+ $this->client->addDocuments($documents);
+ } catch (ExceptionInterface $e) {
+ if (!$this->options['ignore_error']) {
+ throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e);
+ }
+ }
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php
new file mode 100644
index 00000000..b2986b0f
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Stores to PHP error_log() handler.
+ *
+ * @author Elan Ruusamäe
+ */
+class ErrorLogHandler extends AbstractProcessingHandler
+{
+ const OPERATING_SYSTEM = 0;
+ const SAPI = 4;
+
+ protected $messageType;
+ protected $expandNewlines;
+
+ /**
+ * @param int $messageType Says where the error should go.
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries
+ */
+ public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false)
+ {
+ parent::__construct($level, $bubble);
+
+ if (false === in_array($messageType, self::getAvailableTypes())) {
+ $message = sprintf('The given message type "%s" is not supported', print_r($messageType, true));
+ throw new \InvalidArgumentException($message);
+ }
+
+ $this->messageType = $messageType;
+ $this->expandNewlines = $expandNewlines;
+ }
+
+ /**
+ * @return array With all available types
+ */
+ public static function getAvailableTypes()
+ {
+ return array(
+ self::OPERATING_SYSTEM,
+ self::SAPI,
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('[%datetime%] %channel%.%level_name%: %message% %context% %extra%');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if ($this->expandNewlines) {
+ $lines = preg_split('{[\r\n]+}', (string) $record['formatted']);
+ foreach ($lines as $line) {
+ error_log($line, $this->messageType);
+ }
+ } else {
+ error_log((string) $record['formatted'], $this->messageType);
+ }
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php
new file mode 100644
index 00000000..11ede52e
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php
@@ -0,0 +1,170 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Simple handler wrapper that filters records based on a list of levels
+ *
+ * It can be configured with an exact list of levels to allow, or a min/max level.
+ *
+ * @author Hennadiy Verkh
+ * @author Jordi Boggiano
+ */
+class FilterHandler extends AbstractHandler
+{
+ /**
+ * Handler or factory callable($record, $this)
+ *
+ * @var callable|\Monolog\Handler\HandlerInterface
+ */
+ protected $handler;
+
+ /**
+ * Minimum level for logs that are passed to handler
+ *
+ * @var int[]
+ */
+ protected $acceptedLevels;
+
+ /**
+ * Whether the messages that are handled can bubble up the stack or not
+ *
+ * @var bool
+ */
+ protected $bubble;
+
+ /**
+ * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler).
+ * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
+ * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true)
+ {
+ $this->handler = $handler;
+ $this->bubble = $bubble;
+ $this->setAcceptedLevels($minLevelOrList, $maxLevel);
+
+ if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+ throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function getAcceptedLevels()
+ {
+ return array_flip($this->acceptedLevels);
+ }
+
+ /**
+ * @param int|string|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided
+ * @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array
+ */
+ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY)
+ {
+ if (is_array($minLevelOrList)) {
+ $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList);
+ } else {
+ $minLevelOrList = Logger::toMonologLevel($minLevelOrList);
+ $maxLevel = Logger::toMonologLevel($maxLevel);
+ $acceptedLevels = array_values(array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) {
+ return $level >= $minLevelOrList && $level <= $maxLevel;
+ }));
+ }
+ $this->acceptedLevels = array_flip($acceptedLevels);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return isset($this->acceptedLevels[$record['level']]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if (!$this->isHandling($record)) {
+ return false;
+ }
+
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ $this->getHandler($record)->handle($record);
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $filtered = array();
+ foreach ($records as $record) {
+ if ($this->isHandling($record)) {
+ $filtered[] = $record;
+ }
+ }
+
+ $this->getHandler($filtered[count($filtered) - 1])->handleBatch($filtered);
+ }
+
+ /**
+ * Return the nested handler
+ *
+ * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+ *
+ * @return HandlerInterface
+ */
+ public function getHandler(array $record = null)
+ {
+ if (!$this->handler instanceof HandlerInterface) {
+ $this->handler = call_user_func($this->handler, $record, $this);
+ if (!$this->handler instanceof HandlerInterface) {
+ throw new \RuntimeException("The factory callable should return a HandlerInterface");
+ }
+ }
+
+ return $this->handler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->getHandler()->setFormatter($formatter);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter()
+ {
+ return $this->getHandler()->getFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php
new file mode 100644
index 00000000..aaca12cc
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+/**
+ * Interface for activation strategies for the FingersCrossedHandler.
+ *
+ * @author Johannes M. Schmitt
+ */
+interface ActivationStrategyInterface
+{
+ /**
+ * Returns whether the given record activates the handler.
+ *
+ * @param array $record
+ * @return bool
+ */
+ public function isHandlerActivated(array $record);
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php
new file mode 100644
index 00000000..2a2a64d9
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php
@@ -0,0 +1,59 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+use Monolog\Logger;
+
+/**
+ * Channel and Error level based monolog activation strategy. Allows to trigger activation
+ * based on level per channel. e.g. trigger activation on level 'ERROR' by default, except
+ * for records of the 'sql' channel; those should trigger activation on level 'WARN'.
+ *
+ * Example:
+ *
+ *
+ * $activationStrategy = new ChannelLevelActivationStrategy(
+ * Logger::CRITICAL,
+ * array(
+ * 'request' => Logger::ALERT,
+ * 'sensitive' => Logger::ERROR,
+ * )
+ * );
+ * $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy);
+ *
+ *
+ * @author Mike Meessen
+ */
+class ChannelLevelActivationStrategy implements ActivationStrategyInterface
+{
+ private $defaultActionLevel;
+ private $channelToActionLevel;
+
+ /**
+ * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any
+ * @param array $channelToActionLevel An array that maps channel names to action levels.
+ */
+ public function __construct($defaultActionLevel, $channelToActionLevel = array())
+ {
+ $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel);
+ $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel);
+ }
+
+ public function isHandlerActivated(array $record)
+ {
+ if (isset($this->channelToActionLevel[$record['channel']])) {
+ return $record['level'] >= $this->channelToActionLevel[$record['channel']];
+ }
+
+ return $record['level'] >= $this->defaultActionLevel;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php
new file mode 100644
index 00000000..6e630852
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\FingersCrossed;
+
+use Monolog\Logger;
+
+/**
+ * Error level based activation strategy.
+ *
+ * @author Johannes M. Schmitt
+ */
+class ErrorLevelActivationStrategy implements ActivationStrategyInterface
+{
+ private $actionLevel;
+
+ public function __construct($actionLevel)
+ {
+ $this->actionLevel = Logger::toMonologLevel($actionLevel);
+ }
+
+ public function isHandlerActivated(array $record)
+ {
+ return $record['level'] >= $this->actionLevel;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php
new file mode 100644
index 00000000..cdabc445
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php
@@ -0,0 +1,207 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
+use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
+use Monolog\Logger;
+use Monolog\ResettableInterface;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Buffers all records until a certain level is reached
+ *
+ * The advantage of this approach is that you don't get any clutter in your log files.
+ * Only requests which actually trigger an error (or whatever your actionLevel is) will be
+ * in the logs, but they will contain all records, not only those above the level threshold.
+ *
+ * You can find the various activation strategies in the
+ * Monolog\Handler\FingersCrossed\ namespace.
+ *
+ * @author Jordi Boggiano
+ */
+class FingersCrossedHandler extends AbstractHandler
+{
+ protected $handler;
+ protected $activationStrategy;
+ protected $buffering = true;
+ protected $bufferSize;
+ protected $buffer = array();
+ protected $stopBuffering;
+ protected $passthruLevel;
+
+ /**
+ * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler).
+ * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
+ * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true)
+ * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered
+ */
+ public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null)
+ {
+ if (null === $activationStrategy) {
+ $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
+ }
+
+ // convert simple int activationStrategy to an object
+ if (!$activationStrategy instanceof ActivationStrategyInterface) {
+ $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
+ }
+
+ $this->handler = $handler;
+ $this->activationStrategy = $activationStrategy;
+ $this->bufferSize = $bufferSize;
+ $this->bubble = $bubble;
+ $this->stopBuffering = $stopBuffering;
+
+ if ($passthruLevel !== null) {
+ $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
+ }
+
+ if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+ throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return true;
+ }
+
+ /**
+ * Manually activate this logger regardless of the activation strategy
+ */
+ public function activate()
+ {
+ if ($this->stopBuffering) {
+ $this->buffering = false;
+ }
+ $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
+ $this->buffer = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ if ($this->buffering) {
+ $this->buffer[] = $record;
+ if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
+ array_shift($this->buffer);
+ }
+ if ($this->activationStrategy->isHandlerActivated($record)) {
+ $this->activate();
+ }
+ } else {
+ $this->getHandler($record)->handle($record);
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->flushBuffer();
+ }
+
+ public function reset()
+ {
+ $this->flushBuffer();
+
+ parent::reset();
+
+ if ($this->getHandler() instanceof ResettableInterface) {
+ $this->getHandler()->reset();
+ }
+ }
+
+ /**
+ * Clears the buffer without flushing any messages down to the wrapped handler.
+ *
+ * It also resets the handler to its initial buffering state.
+ */
+ public function clear()
+ {
+ $this->buffer = array();
+ $this->reset();
+ }
+
+ /**
+ * Resets the state of the handler. Stops forwarding records to the wrapped handler.
+ */
+ private function flushBuffer()
+ {
+ if (null !== $this->passthruLevel) {
+ $level = $this->passthruLevel;
+ $this->buffer = array_filter($this->buffer, function ($record) use ($level) {
+ return $record['level'] >= $level;
+ });
+ if (count($this->buffer) > 0) {
+ $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
+ }
+ }
+
+ $this->buffer = array();
+ $this->buffering = true;
+ }
+
+ /**
+ * Return the nested handler
+ *
+ * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+ *
+ * @return HandlerInterface
+ */
+ public function getHandler(array $record = null)
+ {
+ if (!$this->handler instanceof HandlerInterface) {
+ $this->handler = call_user_func($this->handler, $record, $this);
+ if (!$this->handler instanceof HandlerInterface) {
+ throw new \RuntimeException("The factory callable should return a HandlerInterface");
+ }
+ }
+
+ return $this->handler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->getHandler()->setFormatter($formatter);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter()
+ {
+ return $this->getHandler()->getFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php
new file mode 100644
index 00000000..c30b1843
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php
@@ -0,0 +1,195 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\WildfireFormatter;
+
+/**
+ * Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
+ *
+ * @author Eric Clemmons (@ericclemmons)
+ */
+class FirePHPHandler extends AbstractProcessingHandler
+{
+ /**
+ * WildFire JSON header message format
+ */
+ const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
+
+ /**
+ * FirePHP structure for parsing messages & their presentation
+ */
+ const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
+
+ /**
+ * Must reference a "known" plugin, otherwise headers won't display in FirePHP
+ */
+ const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3';
+
+ /**
+ * Header prefix for Wildfire to recognize & parse headers
+ */
+ const HEADER_PREFIX = 'X-Wf';
+
+ /**
+ * Whether or not Wildfire vendor-specific headers have been generated & sent yet
+ */
+ protected static $initialized = false;
+
+ /**
+ * Shared static message index between potentially multiple handlers
+ * @var int
+ */
+ protected static $messageIndex = 1;
+
+ protected static $sendHeaders = true;
+
+ /**
+ * Base header creation function used by init headers & record headers
+ *
+ * @param array $meta Wildfire Plugin, Protocol & Structure Indexes
+ * @param string $message Log message
+ * @return array Complete header string ready for the client as key and message as value
+ */
+ protected function createHeader(array $meta, $message)
+ {
+ $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta));
+
+ return array($header => $message);
+ }
+
+ /**
+ * Creates message header from record
+ *
+ * @see createHeader()
+ * @param array $record
+ * @return string
+ */
+ protected function createRecordHeader(array $record)
+ {
+ // Wildfire is extensible to support multiple protocols & plugins in a single request,
+ // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
+ return $this->createHeader(
+ array(1, 1, 1, self::$messageIndex++),
+ $record['formatted']
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new WildfireFormatter();
+ }
+
+ /**
+ * Wildfire initialization headers to enable message parsing
+ *
+ * @see createHeader()
+ * @see sendHeader()
+ * @return array
+ */
+ protected function getInitHeaders()
+ {
+ // Initial payload consists of required headers for Wildfire
+ return array_merge(
+ $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI),
+ $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI),
+ $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI)
+ );
+ }
+
+ /**
+ * Send header string to the client
+ *
+ * @param string $header
+ * @param string $content
+ */
+ protected function sendHeader($header, $content)
+ {
+ if (!headers_sent() && self::$sendHeaders) {
+ header(sprintf('%s: %s', $header, $content));
+ }
+ }
+
+ /**
+ * Creates & sends header for a record, ensuring init headers have been sent prior
+ *
+ * @see sendHeader()
+ * @see sendInitHeaders()
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ if (!self::$sendHeaders) {
+ return;
+ }
+
+ // WildFire-specific headers must be sent prior to any messages
+ if (!self::$initialized) {
+ self::$initialized = true;
+
+ self::$sendHeaders = $this->headersAccepted();
+ if (!self::$sendHeaders) {
+ return;
+ }
+
+ foreach ($this->getInitHeaders() as $header => $content) {
+ $this->sendHeader($header, $content);
+ }
+ }
+
+ $header = $this->createRecordHeader($record);
+ if (trim(current($header)) !== '') {
+ $this->sendHeader(key($header), current($header));
+ }
+ }
+
+ /**
+ * Verifies if the headers are accepted by the current user agent
+ *
+ * @return bool
+ */
+ protected function headersAccepted()
+ {
+ if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) {
+ return true;
+ }
+
+ return isset($_SERVER['HTTP_X_FIREPHP_VERSION']);
+ }
+
+ /**
+ * BC getter for the sendHeaders property that has been made static
+ */
+ public function __get($property)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ return static::$sendHeaders;
+ }
+
+ /**
+ * BC setter for the sendHeaders property that has been made static
+ */
+ public function __set($property, $value)
+ {
+ if ('sendHeaders' !== $property) {
+ throw new \InvalidArgumentException('Undefined property '.$property);
+ }
+
+ static::$sendHeaders = $value;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php
new file mode 100644
index 00000000..c43c0134
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php
@@ -0,0 +1,126 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Sends logs to Fleep.io using Webhook integrations
+ *
+ * You'll need a Fleep.io account to use this handler.
+ *
+ * @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation
+ * @author Ando Roots
+ */
+class FleepHookHandler extends SocketHandler
+{
+ const FLEEP_HOST = 'fleep.io';
+
+ const FLEEP_HOOK_URI = '/hook/';
+
+ /**
+ * @var string Webhook token (specifies the conversation where logs are sent)
+ */
+ protected $token;
+
+ /**
+ * Construct a new Fleep.io Handler.
+ *
+ * For instructions on how to create a new web hook in your conversations
+ * see https://fleep.io/integrations/webhooks/
+ *
+ * @param string $token Webhook token
+ * @param bool|int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @throws MissingExtensionException
+ */
+ public function __construct($token, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler');
+ }
+
+ $this->token = $token;
+
+ $connectionString = 'ssl://' . self::FLEEP_HOST . ':443';
+ parent::__construct($connectionString, $level, $bubble);
+ }
+
+ /**
+ * Returns the default formatter to use with this handler
+ *
+ * Overloaded to remove empty context and extra arrays from the end of the log message.
+ *
+ * @return LineFormatter
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter(null, null, true, true);
+ }
+
+ /**
+ * Handles a log record
+ *
+ * @param array $record
+ */
+ public function write(array $record)
+ {
+ parent::write($record);
+ $this->closeSocket();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ $header = "POST " . self::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n";
+ $header .= "Host: " . self::FLEEP_HOST . "\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ $dataArray = array(
+ 'message' => $record['formatted'],
+ );
+
+ return http_build_query($dataArray);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php
new file mode 100644
index 00000000..f0f010cb
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php
@@ -0,0 +1,128 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Formatter\FlowdockFormatter;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Sends notifications through the Flowdock push API
+ *
+ * This must be configured with a FlowdockFormatter instance via setFormatter()
+ *
+ * Notes:
+ * API token - Flowdock API token
+ *
+ * @author Dominik Liebler
+ * @see https://www.flowdock.com/api/push
+ */
+class FlowdockHandler extends SocketHandler
+{
+ /**
+ * @var string
+ */
+ protected $apiToken;
+
+ /**
+ * @param string $apiToken
+ * @param bool|int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ *
+ * @throws MissingExtensionException if OpenSSL is missing
+ */
+ public function __construct($apiToken, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler');
+ }
+
+ parent::__construct('ssl://api.flowdock.com:443', $level, $bubble);
+ $this->apiToken = $apiToken;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ if (!$formatter instanceof FlowdockFormatter) {
+ throw new \InvalidArgumentException('The FlowdockHandler requires an instance of Monolog\Formatter\FlowdockFormatter to function correctly');
+ }
+
+ return parent::setFormatter($formatter);
+ }
+
+ /**
+ * Gets the default formatter.
+ *
+ * @return FormatterInterface
+ */
+ protected function getDefaultFormatter()
+ {
+ throw new \InvalidArgumentException('The FlowdockHandler must be configured (via setFormatter) with an instance of Monolog\Formatter\FlowdockFormatter to function correctly');
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ parent::write($record);
+
+ $this->closeSocket();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ return Utils::jsonEncode($record['formatted']['flowdock']);
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n";
+ $header .= "Host: api.flowdock.com\r\n";
+ $header .= "Content-Type: application/json\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php
new file mode 100644
index 00000000..3e2f1b28
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php
@@ -0,0 +1,39 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Interface to describe loggers that have a formatter
+ *
+ * This interface is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano
+ */
+interface FormattableHandlerInterface
+{
+ /**
+ * Sets the formatter.
+ *
+ * @param FormatterInterface $formatter
+ * @return HandlerInterface self
+ */
+ public function setFormatter(FormatterInterface $formatter): HandlerInterface;
+
+ /**
+ * Gets the formatter.
+ *
+ * @return FormatterInterface
+ */
+ public function getFormatter(): FormatterInterface;
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php
new file mode 100644
index 00000000..e9ec5e77
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * Helper trait for implementing FormattableInterface
+ *
+ * This trait is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano
+ */
+trait FormattableHandlerTrait
+{
+ /**
+ * @var FormatterInterface
+ */
+ protected $formatter;
+
+ /**
+ * {@inheritdoc}
+ * @suppress PhanTypeMismatchReturn
+ */
+ public function setFormatter(FormatterInterface $formatter): HandlerInterface
+ {
+ $this->formatter = $formatter;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter(): FormatterInterface
+ {
+ if (!$this->formatter) {
+ $this->formatter = $this->getDefaultFormatter();
+ }
+
+ return $this->formatter;
+ }
+
+ /**
+ * Gets the default formatter.
+ *
+ * Overwrite this if the LineFormatter is not a good default for your handler.
+ */
+ protected function getDefaultFormatter(): FormatterInterface
+ {
+ return new LineFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php
new file mode 100644
index 00000000..71e46693
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php
@@ -0,0 +1,65 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Gelf\IMessagePublisher;
+use Gelf\PublisherInterface;
+use Gelf\Publisher;
+use InvalidArgumentException;
+use Monolog\Logger;
+use Monolog\Formatter\GelfMessageFormatter;
+
+/**
+ * Handler to send messages to a Graylog2 (http://www.graylog2.org) server
+ *
+ * @author Matt Lehner
+ * @author Benjamin Zikarsky
+ */
+class GelfHandler extends AbstractProcessingHandler
+{
+ /**
+ * @var Publisher the publisher object that sends the message to the server
+ */
+ protected $publisher;
+
+ /**
+ * @param PublisherInterface|IMessagePublisher|Publisher $publisher a publisher object
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($publisher, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ if (!$publisher instanceof Publisher && !$publisher instanceof IMessagePublisher && !$publisher instanceof PublisherInterface) {
+ throw new InvalidArgumentException('Invalid publisher, expected a Gelf\Publisher, Gelf\IMessagePublisher or Gelf\PublisherInterface instance');
+ }
+
+ $this->publisher = $publisher;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->publisher->publish($record['formatted']);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new GelfMessageFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php
new file mode 100644
index 00000000..0d461f9c
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php
@@ -0,0 +1,117 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\ResettableInterface;
+
+/**
+ * Forwards records to multiple handlers
+ *
+ * @author Lenar Lõhmus
+ */
+class GroupHandler extends AbstractHandler
+{
+ protected $handlers;
+
+ /**
+ * @param array $handlers Array of Handlers.
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(array $handlers, $bubble = true)
+ {
+ foreach ($handlers as $handler) {
+ if (!$handler instanceof HandlerInterface) {
+ throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.');
+ }
+ }
+
+ $this->handlers = $handlers;
+ $this->bubble = $bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ foreach ($this->handlers as $handler) {
+ if ($handler->isHandling($record)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ foreach ($this->handlers as $handler) {
+ $handler->handle($record);
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ if ($this->processors) {
+ $processed = array();
+ foreach ($records as $record) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ $processed[] = $record;
+ }
+ $records = $processed;
+ }
+
+ foreach ($this->handlers as $handler) {
+ $handler->handleBatch($records);
+ }
+ }
+
+ public function reset()
+ {
+ parent::reset();
+
+ foreach ($this->handlers as $handler) {
+ if ($handler instanceof ResettableInterface) {
+ $handler->reset();
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ foreach ($this->handlers as $handler) {
+ $handler->setFormatter($formatter);
+ }
+
+ return $this;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php
new file mode 100644
index 00000000..8d5a4a09
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php
@@ -0,0 +1,90 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Interface that all Monolog Handlers must implement
+ *
+ * @author Jordi Boggiano
+ */
+interface HandlerInterface
+{
+ /**
+ * Checks whether the given record will be handled by this handler.
+ *
+ * This is mostly done for performance reasons, to avoid calling processors for nothing.
+ *
+ * Handlers should still check the record levels within handle(), returning false in isHandling()
+ * is no guarantee that handle() will not be called, and isHandling() might not be called
+ * for a given record.
+ *
+ * @param array $record Partial log record containing only a level key
+ *
+ * @return bool
+ */
+ public function isHandling(array $record);
+
+ /**
+ * Handles a record.
+ *
+ * All records may be passed to this method, and the handler should discard
+ * those that it does not want to handle.
+ *
+ * The return value of this function controls the bubbling process of the handler stack.
+ * Unless the bubbling is interrupted (by returning true), the Logger class will keep on
+ * calling further handlers in the stack with a given log record.
+ *
+ * @param array $record The record to handle
+ * @return bool true means that this handler handled the record, and that bubbling is not permitted.
+ * false means the record was either not processed or that this handler allows bubbling.
+ */
+ public function handle(array $record);
+
+ /**
+ * Handles a set of records at once.
+ *
+ * @param array $records The records to handle (an array of record arrays)
+ */
+ public function handleBatch(array $records);
+
+ /**
+ * Adds a processor in the stack.
+ *
+ * @param callable $callback
+ * @return self
+ */
+ public function pushProcessor($callback);
+
+ /**
+ * Removes the processor on top of the stack and returns it.
+ *
+ * @return callable
+ */
+ public function popProcessor();
+
+ /**
+ * Sets the formatter.
+ *
+ * @param FormatterInterface $formatter
+ * @return self
+ */
+ public function setFormatter(FormatterInterface $formatter);
+
+ /**
+ * Gets the formatter.
+ *
+ * @return FormatterInterface
+ */
+ public function getFormatter();
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php
new file mode 100644
index 00000000..55e64986
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php
@@ -0,0 +1,116 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\ResettableInterface;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * This simple wrapper class can be used to extend handlers functionality.
+ *
+ * Example: A custom filtering that can be applied to any handler.
+ *
+ * Inherit from this class and override handle() like this:
+ *
+ * public function handle(array $record)
+ * {
+ * if ($record meets certain conditions) {
+ * return false;
+ * }
+ * return $this->handler->handle($record);
+ * }
+ *
+ * @author Alexey Karapetov
+ */
+class HandlerWrapper implements HandlerInterface, ResettableInterface
+{
+ /**
+ * @var HandlerInterface
+ */
+ protected $handler;
+
+ /**
+ * HandlerWrapper constructor.
+ * @param HandlerInterface $handler
+ */
+ public function __construct(HandlerInterface $handler)
+ {
+ $this->handler = $handler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isHandling(array $record)
+ {
+ return $this->handler->isHandling($record);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ return $this->handler->handle($record);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ return $this->handler->handleBatch($records);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function pushProcessor($callback)
+ {
+ $this->handler->pushProcessor($callback);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function popProcessor()
+ {
+ return $this->handler->popProcessor();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->handler->setFormatter($formatter);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter()
+ {
+ return $this->handler->getFormatter();
+ }
+
+ public function reset()
+ {
+ if ($this->handler instanceof ResettableInterface) {
+ return $this->handler->reset();
+ }
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php
new file mode 100644
index 00000000..179d6268
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php
@@ -0,0 +1,367 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the hipchat api to a hipchat room
+ *
+ * Notes:
+ * API token - HipChat API token
+ * Room - HipChat Room Id or name, where messages are sent
+ * Name - Name used to send the message (from)
+ * notify - Should the message trigger a notification in the clients
+ * version - The API version to use (HipChatHandler::API_V1 | HipChatHandler::API_V2)
+ *
+ * @author Rafael Dohms
+ * @see https://www.hipchat.com/docs/api
+ */
+class HipChatHandler extends SocketHandler
+{
+ /**
+ * Use API version 1
+ */
+ const API_V1 = 'v1';
+
+ /**
+ * Use API version v2
+ */
+ const API_V2 = 'v2';
+
+ /**
+ * The maximum allowed length for the name used in the "from" field.
+ */
+ const MAXIMUM_NAME_LENGTH = 15;
+
+ /**
+ * The maximum allowed length for the message.
+ */
+ const MAXIMUM_MESSAGE_LENGTH = 9500;
+
+ /**
+ * @var string
+ */
+ private $token;
+
+ /**
+ * @var string
+ */
+ private $room;
+
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var bool
+ */
+ private $notify;
+
+ /**
+ * @var string
+ */
+ private $format;
+
+ /**
+ * @var string
+ */
+ private $host;
+
+ /**
+ * @var string
+ */
+ private $version;
+
+ /**
+ * @param string $token HipChat API Token
+ * @param string $room The room that should be alerted of the message (Id or Name)
+ * @param string $name Name used in the "from" field.
+ * @param bool $notify Trigger a notification in clients or not
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $useSSL Whether to connect via SSL.
+ * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages)
+ * @param string $host The HipChat server hostname.
+ * @param string $version The HipChat API version (default HipChatHandler::API_V1)
+ */
+ public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1)
+ {
+ @trigger_error('The Monolog\Handler\HipChatHandler class is deprecated. You should migrate to Slack and the SlackWebhookHandler / SlackbotHandler, see https://www.atlassian.com/partnerships/slack', E_USER_DEPRECATED);
+
+ if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) {
+ throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.');
+ }
+
+ $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80';
+ parent::__construct($connectionString, $level, $bubble);
+
+ $this->token = $token;
+ $this->name = $name;
+ $this->notify = $notify;
+ $this->room = $room;
+ $this->format = $format;
+ $this->host = $host;
+ $this->version = $version;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ $dataArray = array(
+ 'notify' => $this->version == self::API_V1 ?
+ ($this->notify ? 1 : 0) :
+ ($this->notify ? 'true' : 'false'),
+ 'message' => $record['formatted'],
+ 'message_format' => $this->format,
+ 'color' => $this->getAlertColor($record['level']),
+ );
+
+ if (!$this->validateStringLength($dataArray['message'], static::MAXIMUM_MESSAGE_LENGTH)) {
+ if (function_exists('mb_substr')) {
+ $dataArray['message'] = mb_substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]';
+ } else {
+ $dataArray['message'] = substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]';
+ }
+ }
+
+ // if we are using the legacy API then we need to send some additional information
+ if ($this->version == self::API_V1) {
+ $dataArray['room_id'] = $this->room;
+ }
+
+ // append the sender name if it is set
+ // always append it if we use the v1 api (it is required in v1)
+ if ($this->version == self::API_V1 || $this->name !== null) {
+ $dataArray['from'] = (string) $this->name;
+ }
+
+ return http_build_query($dataArray);
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ if ($this->version == self::API_V1) {
+ $header = "POST /v1/rooms/message?format=json&auth_token={$this->token} HTTP/1.1\r\n";
+ } else {
+ // needed for rooms with special (spaces, etc) characters in the name
+ $room = rawurlencode($this->room);
+ $header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n";
+ }
+
+ $header .= "Host: {$this->host}\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ /**
+ * Assigns a color to each level of log records.
+ *
+ * @param int $level
+ * @return string
+ */
+ protected function getAlertColor($level)
+ {
+ switch (true) {
+ case $level >= Logger::ERROR:
+ return 'red';
+ case $level >= Logger::WARNING:
+ return 'yellow';
+ case $level >= Logger::INFO:
+ return 'green';
+ case $level == Logger::DEBUG:
+ return 'gray';
+ default:
+ return 'yellow';
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ parent::write($record);
+ $this->finalizeWrite();
+ }
+
+ /**
+ * Finalizes the request by reading some bytes and then closing the socket
+ *
+ * If we do not read some but close the socket too early, hipchat sometimes
+ * drops the request entirely.
+ */
+ protected function finalizeWrite()
+ {
+ $res = $this->getResource();
+ if (is_resource($res)) {
+ @fread($res, 2048);
+ }
+ $this->closeSocket();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ if (count($records) == 0) {
+ return true;
+ }
+
+ $batchRecords = $this->combineRecords($records);
+
+ $handled = false;
+ foreach ($batchRecords as $batchRecord) {
+ if ($this->isHandling($batchRecord)) {
+ $this->write($batchRecord);
+ $handled = true;
+ }
+ }
+
+ if (!$handled) {
+ return false;
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * Combines multiple records into one. Error level of the combined record
+ * will be the highest level from the given records. Datetime will be taken
+ * from the first record.
+ *
+ * @param $records
+ * @return array
+ */
+ private function combineRecords($records)
+ {
+ $batchRecord = null;
+ $batchRecords = array();
+ $messages = array();
+ $formattedMessages = array();
+ $level = 0;
+ $levelName = null;
+ $datetime = null;
+
+ foreach ($records as $record) {
+ $record = $this->processRecord($record);
+
+ if ($record['level'] > $level) {
+ $level = $record['level'];
+ $levelName = $record['level_name'];
+ }
+
+ if (null === $datetime) {
+ $datetime = $record['datetime'];
+ }
+
+ $messages[] = $record['message'];
+ $messageStr = implode(PHP_EOL, $messages);
+ $formattedMessages[] = $this->getFormatter()->format($record);
+ $formattedMessageStr = implode('', $formattedMessages);
+
+ $batchRecord = array(
+ 'message' => $messageStr,
+ 'formatted' => $formattedMessageStr,
+ 'context' => array(),
+ 'extra' => array(),
+ );
+
+ if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) {
+ // Pop the last message and implode the remaining messages
+ $lastMessage = array_pop($messages);
+ $lastFormattedMessage = array_pop($formattedMessages);
+ $batchRecord['message'] = implode(PHP_EOL, $messages);
+ $batchRecord['formatted'] = implode('', $formattedMessages);
+
+ $batchRecords[] = $batchRecord;
+ $messages = array($lastMessage);
+ $formattedMessages = array($lastFormattedMessage);
+
+ $batchRecord = null;
+ }
+ }
+
+ if (null !== $batchRecord) {
+ $batchRecords[] = $batchRecord;
+ }
+
+ // Set the max level and datetime for all records
+ foreach ($batchRecords as &$batchRecord) {
+ $batchRecord = array_merge(
+ $batchRecord,
+ array(
+ 'level' => $level,
+ 'level_name' => $levelName,
+ 'datetime' => $datetime,
+ )
+ );
+ }
+
+ return $batchRecords;
+ }
+
+ /**
+ * Validates the length of a string.
+ *
+ * If the `mb_strlen()` function is available, it will use that, as HipChat
+ * allows UTF-8 characters. Otherwise, it will fall back to `strlen()`.
+ *
+ * Note that this might cause false failures in the specific case of using
+ * a valid name with less than 16 characters, but 16 or more bytes, on a
+ * system where `mb_strlen()` is unavailable.
+ *
+ * @param string $str
+ * @param int $length
+ *
+ * @return bool
+ */
+ private function validateStringLength($str, $length)
+ {
+ if (function_exists('mb_strlen')) {
+ return (mb_strlen($str) <= $length);
+ }
+
+ return (strlen($str) <= $length);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php
new file mode 100644
index 00000000..f4d3b97e
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+
+/**
+ * IFTTTHandler uses cURL to trigger IFTTT Maker actions
+ *
+ * Register a secret key and trigger/event name at https://ifttt.com/maker
+ *
+ * value1 will be the channel from monolog's Logger constructor,
+ * value2 will be the level name (ERROR, WARNING, ..)
+ * value3 will be the log record's message
+ *
+ * @author Nehal Patel
+ */
+class IFTTTHandler extends AbstractProcessingHandler
+{
+ private $eventName;
+ private $secretKey;
+
+ /**
+ * @param string $eventName The name of the IFTTT Maker event that should be triggered
+ * @param string $secretKey A valid IFTTT secret key
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bubble = true)
+ {
+ $this->eventName = $eventName;
+ $this->secretKey = $secretKey;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write(array $record)
+ {
+ $postData = array(
+ "value1" => $record["channel"],
+ "value2" => $record["level_name"],
+ "value3" => $record["message"],
+ );
+ $postString = Utils::jsonEncode($postData);
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array(
+ "Content-Type: application/json",
+ ));
+
+ Curl\Util::execute($ch);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php
new file mode 100644
index 00000000..8f683dce
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php
@@ -0,0 +1,62 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+ namespace Monolog\Handler;
+
+ use Monolog\Logger;
+
+/**
+ * Inspired on LogEntriesHandler.
+ *
+ * @author Robert Kaufmann III
+ * @author Gabriel Machado
+ */
+class InsightOpsHandler extends SocketHandler
+{
+ /**
+ * @var string
+ */
+ protected $logToken;
+
+ /**
+ * @param string $token Log token supplied by InsightOps
+ * @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'.
+ * @param bool $useSSL Whether or not SSL encryption should be used
+ * @param int $level The minimum logging level to trigger this handler
+ * @param bool $bubble Whether or not messages that are handled should bubble up the stack.
+ *
+ * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
+ */
+ public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, $bubble = true)
+ {
+ if ($useSSL && !extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for InsightOpsHandler');
+ }
+
+ $endpoint = $useSSL
+ ? 'ssl://' . $region . '.data.logs.insight.rapid7.com:443'
+ : $region . '.data.logs.insight.rapid7.com:80';
+
+ parent::__construct($endpoint, $level, $bubble);
+ $this->logToken = $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ return $this->logToken . ' ' . $record['formatted'];
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php
new file mode 100644
index 00000000..ea89fb3e
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * @author Robert Kaufmann III
+ */
+class LogEntriesHandler extends SocketHandler
+{
+ /**
+ * @var string
+ */
+ protected $logToken;
+
+ /**
+ * @param string $token Log token supplied by LogEntries
+ * @param bool $useSSL Whether or not SSL encryption should be used.
+ * @param int $level The minimum logging level to trigger this handler
+ * @param bool $bubble Whether or not messages that are handled should bubble up the stack.
+ *
+ * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
+ */
+ public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true, $host = 'data.logentries.com')
+ {
+ if ($useSSL && !extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler');
+ }
+
+ $endpoint = $useSSL ? 'ssl://' . $host . ':443' : $host . ':80';
+ parent::__construct($endpoint, $level, $bubble);
+ $this->logToken = $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ return $this->logToken . ' ' . $record['formatted'];
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php
new file mode 100644
index 00000000..bcd62e1c
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php
@@ -0,0 +1,102 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LogglyFormatter;
+
+/**
+ * Sends errors to Loggly.
+ *
+ * @author Przemek Sobstel
+ * @author Adam Pancutt
+ * @author Gregory Barchard
+ */
+class LogglyHandler extends AbstractProcessingHandler
+{
+ const HOST = 'logs-01.loggly.com';
+ const ENDPOINT_SINGLE = 'inputs';
+ const ENDPOINT_BATCH = 'bulk';
+
+ protected $token;
+
+ protected $tag = array();
+
+ public function __construct($token, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!extension_loaded('curl')) {
+ throw new \LogicException('The curl extension is needed to use the LogglyHandler');
+ }
+
+ $this->token = $token;
+
+ parent::__construct($level, $bubble);
+ }
+
+ public function setTag($tag)
+ {
+ $tag = !empty($tag) ? $tag : array();
+ $this->tag = is_array($tag) ? $tag : array($tag);
+ }
+
+ public function addTag($tag)
+ {
+ if (!empty($tag)) {
+ $tag = is_array($tag) ? $tag : array($tag);
+ $this->tag = array_unique(array_merge($this->tag, $tag));
+ }
+ }
+
+ protected function write(array $record)
+ {
+ $this->send($record["formatted"], self::ENDPOINT_SINGLE);
+ }
+
+ public function handleBatch(array $records)
+ {
+ $level = $this->level;
+
+ $records = array_filter($records, function ($record) use ($level) {
+ return ($record['level'] >= $level);
+ });
+
+ if ($records) {
+ $this->send($this->getFormatter()->formatBatch($records), self::ENDPOINT_BATCH);
+ }
+ }
+
+ protected function send($data, $endpoint)
+ {
+ $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token);
+
+ $headers = array('Content-Type: application/json');
+
+ if (!empty($this->tag)) {
+ $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag);
+ }
+
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+
+ Curl\Util::execute($ch);
+ }
+
+ protected function getDefaultFormatter()
+ {
+ return new LogglyFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php
new file mode 100644
index 00000000..9e232838
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Base class for all mail handlers
+ *
+ * @author Gyula Sallai
+ */
+abstract class MailHandler extends AbstractProcessingHandler
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $messages = array();
+
+ foreach ($records as $record) {
+ if ($record['level'] < $this->level) {
+ continue;
+ }
+ $messages[] = $this->processRecord($record);
+ }
+
+ if (!empty($messages)) {
+ $this->send((string) $this->getFormatter()->formatBatch($messages), $messages);
+ }
+ }
+
+ /**
+ * Send a mail with the given content
+ *
+ * @param string $content formatted email body to be sent
+ * @param array $records the array of log records that formed this content
+ */
+ abstract protected function send($content, array $records);
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->send((string) $record['formatted'], array($record));
+ }
+
+ protected function getHighestRecord(array $records)
+ {
+ $highestRecord = null;
+ foreach ($records as $record) {
+ if ($highestRecord === null || $highestRecord['level'] < $record['level']) {
+ $highestRecord = $record;
+ }
+ }
+
+ return $highestRecord;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php
new file mode 100644
index 00000000..3f0956a9
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php
@@ -0,0 +1,68 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * MandrillHandler uses cURL to send the emails to the Mandrill API
+ *
+ * @author Adam Nicholson
+ */
+class MandrillHandler extends MailHandler
+{
+ protected $message;
+ protected $apiKey;
+
+ /**
+ * @param string $apiKey A valid Mandrill API key
+ * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ if (!$message instanceof \Swift_Message && is_callable($message)) {
+ $message = call_user_func($message);
+ }
+ if (!$message instanceof \Swift_Message) {
+ throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it');
+ }
+ $this->message = $message;
+ $this->apiKey = $apiKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function send($content, array $records)
+ {
+ $message = clone $this->message;
+ $message->setBody($content);
+ $message->setDate(time());
+
+ $ch = curl_init();
+
+ curl_setopt($ch, CURLOPT_URL, 'https://mandrillapp.com/api/1.0/messages/send-raw.json');
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
+ 'key' => $this->apiKey,
+ 'raw_message' => (string) $message,
+ 'async' => false,
+ )));
+
+ Curl\Util::execute($ch);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php
new file mode 100644
index 00000000..4724a7e2
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Exception can be thrown if an extension for an handler is missing
+ *
+ * @author Christian Bergau
+ */
+class MissingExtensionException extends \Exception
+{
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php
new file mode 100644
index 00000000..56fe755b
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php
@@ -0,0 +1,59 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\NormalizerFormatter;
+
+/**
+ * Logs to a MongoDB database.
+ *
+ * usage example:
+ *
+ * $log = new Logger('application');
+ * $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod");
+ * $log->pushHandler($mongodb);
+ *
+ * @author Thomas Tourlourat
+ */
+class MongoDBHandler extends AbstractProcessingHandler
+{
+ protected $mongoCollection;
+
+ public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo || $mongo instanceof \MongoDB\Client)) {
+ throw new \InvalidArgumentException('MongoClient, Mongo or MongoDB\Client instance required');
+ }
+
+ $this->mongoCollection = $mongo->selectCollection($database, $collection);
+
+ parent::__construct($level, $bubble);
+ }
+
+ protected function write(array $record)
+ {
+ if ($this->mongoCollection instanceof \MongoDB\Collection) {
+ $this->mongoCollection->insertOne($record["formatted"]);
+ } else {
+ $this->mongoCollection->save($record["formatted"]);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new NormalizerFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php
new file mode 100644
index 00000000..d7807fd1
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php
@@ -0,0 +1,185 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+/**
+ * NativeMailerHandler uses the mail() function to send the emails
+ *
+ * @author Christophe Coevoet
+ * @author Mark Garrett
+ */
+class NativeMailerHandler extends MailHandler
+{
+ /**
+ * The email addresses to which the message will be sent
+ * @var array
+ */
+ protected $to;
+
+ /**
+ * The subject of the email
+ * @var string
+ */
+ protected $subject;
+
+ /**
+ * Optional headers for the message
+ * @var array
+ */
+ protected $headers = array();
+
+ /**
+ * Optional parameters for the message
+ * @var array
+ */
+ protected $parameters = array();
+
+ /**
+ * The wordwrap length for the message
+ * @var int
+ */
+ protected $maxColumnWidth;
+
+ /**
+ * The Content-type for the message
+ * @var string
+ */
+ protected $contentType = 'text/plain';
+
+ /**
+ * The encoding for the message
+ * @var string
+ */
+ protected $encoding = 'utf-8';
+
+ /**
+ * @param string|array $to The receiver of the mail
+ * @param string $subject The subject of the mail
+ * @param string $from The sender of the mail
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int $maxColumnWidth The maximum column width that the message lines will have
+ */
+ public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70)
+ {
+ parent::__construct($level, $bubble);
+ $this->to = is_array($to) ? $to : array($to);
+ $this->subject = $subject;
+ $this->addHeader(sprintf('From: %s', $from));
+ $this->maxColumnWidth = $maxColumnWidth;
+ }
+
+ /**
+ * Add headers to the message
+ *
+ * @param string|array $headers Custom added headers
+ * @return self
+ */
+ public function addHeader($headers)
+ {
+ foreach ((array) $headers as $header) {
+ if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) {
+ throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons');
+ }
+ $this->headers[] = $header;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add parameters to the message
+ *
+ * @param string|array $parameters Custom added parameters
+ * @return self
+ */
+ public function addParameter($parameters)
+ {
+ $this->parameters = array_merge($this->parameters, (array) $parameters);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function send($content, array $records)
+ {
+ $content = wordwrap($content, $this->maxColumnWidth);
+ $headers = ltrim(implode("\r\n", $this->headers) . "\r\n", "\r\n");
+ $headers .= 'Content-type: ' . $this->getContentType() . '; charset=' . $this->getEncoding() . "\r\n";
+ if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) {
+ $headers .= 'MIME-Version: 1.0' . "\r\n";
+ }
+
+ $subject = $this->subject;
+ if ($records) {
+ $subjectFormatter = new LineFormatter($this->subject);
+ $subject = $subjectFormatter->format($this->getHighestRecord($records));
+ }
+
+ $parameters = implode(' ', $this->parameters);
+ foreach ($this->to as $to) {
+ mail($to, $subject, $content, $headers, $parameters);
+ }
+ }
+
+ /**
+ * @return string $contentType
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+ /**
+ * @return string $encoding
+ */
+ public function getEncoding()
+ {
+ return $this->encoding;
+ }
+
+ /**
+ * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML
+ * messages.
+ * @return self
+ */
+ public function setContentType($contentType)
+ {
+ if (strpos($contentType, "\n") !== false || strpos($contentType, "\r") !== false) {
+ throw new \InvalidArgumentException('The content type can not contain newline characters to prevent email header injection');
+ }
+
+ $this->contentType = $contentType;
+
+ return $this;
+ }
+
+ /**
+ * @param string $encoding
+ * @return self
+ */
+ public function setEncoding($encoding)
+ {
+ if (strpos($encoding, "\n") !== false || strpos($encoding, "\r") !== false) {
+ throw new \InvalidArgumentException('The encoding can not contain newline characters to prevent email header injection');
+ }
+
+ $this->encoding = $encoding;
+
+ return $this;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php
new file mode 100644
index 00000000..64dc1381
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php
@@ -0,0 +1,205 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Formatter\NormalizerFormatter;
+
+/**
+ * Class to record a log on a NewRelic application.
+ * Enabling New Relic High Security mode may prevent capture of useful information.
+ *
+ * This handler requires a NormalizerFormatter to function and expects an array in $record['formatted']
+ *
+ * @see https://docs.newrelic.com/docs/agents/php-agent
+ * @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security
+ */
+class NewRelicHandler extends AbstractProcessingHandler
+{
+ /**
+ * Name of the New Relic application that will receive logs from this handler.
+ *
+ * @var string
+ */
+ protected $appName;
+
+ /**
+ * Name of the current transaction
+ *
+ * @var string
+ */
+ protected $transactionName;
+
+ /**
+ * Some context and extra data is passed into the handler as arrays of values. Do we send them as is
+ * (useful if we are using the API), or explode them for display on the NewRelic RPM website?
+ *
+ * @var bool
+ */
+ protected $explodeArrays;
+
+ /**
+ * {@inheritDoc}
+ *
+ * @param string $appName
+ * @param bool $explodeArrays
+ * @param string $transactionName
+ */
+ public function __construct(
+ $level = Logger::ERROR,
+ $bubble = true,
+ $appName = null,
+ $explodeArrays = false,
+ $transactionName = null
+ ) {
+ parent::__construct($level, $bubble);
+
+ $this->appName = $appName;
+ $this->explodeArrays = $explodeArrays;
+ $this->transactionName = $transactionName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ if (!$this->isNewRelicEnabled()) {
+ throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
+ }
+
+ if ($appName = $this->getAppName($record['context'])) {
+ $this->setNewRelicAppName($appName);
+ }
+
+ if ($transactionName = $this->getTransactionName($record['context'])) {
+ $this->setNewRelicTransactionName($transactionName);
+ unset($record['formatted']['context']['transaction_name']);
+ }
+
+ if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) {
+ newrelic_notice_error($record['message'], $record['context']['exception']);
+ unset($record['formatted']['context']['exception']);
+ } else {
+ newrelic_notice_error($record['message']);
+ }
+
+ if (isset($record['formatted']['context']) && is_array($record['formatted']['context'])) {
+ foreach ($record['formatted']['context'] as $key => $parameter) {
+ if (is_array($parameter) && $this->explodeArrays) {
+ foreach ($parameter as $paramKey => $paramValue) {
+ $this->setNewRelicParameter('context_' . $key . '_' . $paramKey, $paramValue);
+ }
+ } else {
+ $this->setNewRelicParameter('context_' . $key, $parameter);
+ }
+ }
+ }
+
+ if (isset($record['formatted']['extra']) && is_array($record['formatted']['extra'])) {
+ foreach ($record['formatted']['extra'] as $key => $parameter) {
+ if (is_array($parameter) && $this->explodeArrays) {
+ foreach ($parameter as $paramKey => $paramValue) {
+ $this->setNewRelicParameter('extra_' . $key . '_' . $paramKey, $paramValue);
+ }
+ } else {
+ $this->setNewRelicParameter('extra_' . $key, $parameter);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks whether the NewRelic extension is enabled in the system.
+ *
+ * @return bool
+ */
+ protected function isNewRelicEnabled()
+ {
+ return extension_loaded('newrelic');
+ }
+
+ /**
+ * Returns the appname where this log should be sent. Each log can override the default appname, set in this
+ * handler's constructor, by providing the appname in it's context.
+ *
+ * @param array $context
+ * @return null|string
+ */
+ protected function getAppName(array $context)
+ {
+ if (isset($context['appname'])) {
+ return $context['appname'];
+ }
+
+ return $this->appName;
+ }
+
+ /**
+ * Returns the name of the current transaction. Each log can override the default transaction name, set in this
+ * handler's constructor, by providing the transaction_name in it's context
+ *
+ * @param array $context
+ *
+ * @return null|string
+ */
+ protected function getTransactionName(array $context)
+ {
+ if (isset($context['transaction_name'])) {
+ return $context['transaction_name'];
+ }
+
+ return $this->transactionName;
+ }
+
+ /**
+ * Sets the NewRelic application that should receive this log.
+ *
+ * @param string $appName
+ */
+ protected function setNewRelicAppName($appName)
+ {
+ newrelic_set_appname($appName);
+ }
+
+ /**
+ * Overwrites the name of the current transaction
+ *
+ * @param string $transactionName
+ */
+ protected function setNewRelicTransactionName($transactionName)
+ {
+ newrelic_name_transaction($transactionName);
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ protected function setNewRelicParameter($key, $value)
+ {
+ if (null === $value || is_scalar($value)) {
+ newrelic_add_custom_parameter($key, $value);
+ } else {
+ newrelic_add_custom_parameter($key, Utils::jsonEncode($value, null, true));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new NormalizerFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php
new file mode 100644
index 00000000..4b845883
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Blackhole
+ *
+ * Any record it can handle will be thrown away. This can be used
+ * to put on top of an existing stack to override it temporarily.
+ *
+ * @author Jordi Boggiano
+ */
+class NullHandler extends AbstractHandler
+{
+ /**
+ * @param int $level The minimum logging level at which this handler will be triggered
+ */
+ public function __construct($level = Logger::DEBUG)
+ {
+ parent::__construct($level, false);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($record['level'] < $this->level) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php
new file mode 100644
index 00000000..d0a8b43e
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php
@@ -0,0 +1,243 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Exception;
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+use Monolog\Utils;
+use PhpConsole\Connector;
+use PhpConsole\Handler;
+use PhpConsole\Helper;
+
+/**
+ * Monolog handler for Google Chrome extension "PHP Console"
+ *
+ * Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely
+ *
+ * Usage:
+ * 1. Install Google Chrome extension https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef
+ * 2. See overview https://github.com/barbushin/php-console#overview
+ * 3. Install PHP Console library https://github.com/barbushin/php-console#installation
+ * 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png)
+ *
+ * $logger = new \Monolog\Logger('all', array(new \Monolog\Handler\PHPConsoleHandler()));
+ * \Monolog\ErrorHandler::register($logger);
+ * echo $undefinedVar;
+ * $logger->addDebug('SELECT * FROM users', array('db', 'time' => 0.012));
+ * PC::debug($_SERVER); // PHP Console debugger for any type of vars
+ *
+ * @author Sergey Barbushin https://www.linkedin.com/in/barbushin
+ */
+class PHPConsoleHandler extends AbstractProcessingHandler
+{
+ private $options = array(
+ 'enabled' => true, // bool Is PHP Console server enabled
+ 'classesPartialsTraceIgnore' => array('Monolog\\'), // array Hide calls of classes started with...
+ 'debugTagsKeysInContext' => array(0, 'tag'), // bool Is PHP Console server enabled
+ 'useOwnErrorsHandler' => false, // bool Enable errors handling
+ 'useOwnExceptionsHandler' => false, // bool Enable exceptions handling
+ 'sourcesBasePath' => null, // string Base path of all project sources to strip in errors source paths
+ 'registerHelper' => true, // bool Register PhpConsole\Helper that allows short debug calls like PC::debug($var, 'ta.g.s')
+ 'serverEncoding' => null, // string|null Server internal encoding
+ 'headersLimit' => null, // int|null Set headers size limit for your web-server
+ 'password' => null, // string|null Protect PHP Console connection by password
+ 'enableSslOnlyMode' => false, // bool Force connection by SSL for clients with PHP Console installed
+ 'ipMasks' => array(), // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1')
+ 'enableEvalListener' => false, // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required)
+ 'dumperDetectCallbacks' => false, // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings
+ 'dumperLevelLimit' => 5, // int Maximum dumped vars array or object nested dump level
+ 'dumperItemsCountLimit' => 100, // int Maximum dumped var same level array items or object properties number
+ 'dumperItemSizeLimit' => 5000, // int Maximum length of any string or dumped array item
+ 'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON
+ 'detectDumpTraceAndSource' => false, // bool Autodetect and append trace data to debug
+ 'dataStorage' => null, // PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ)
+ );
+
+ /** @var Connector */
+ private $connector;
+
+ /**
+ * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details
+ * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional)
+ * @param int $level
+ * @param bool $bubble
+ * @throws Exception
+ */
+ public function __construct(array $options = array(), Connector $connector = null, $level = Logger::DEBUG, $bubble = true)
+ {
+ if (!class_exists('PhpConsole\Connector')) {
+ throw new Exception('PHP Console library not found. See https://github.com/barbushin/php-console#installation');
+ }
+ parent::__construct($level, $bubble);
+ $this->options = $this->initOptions($options);
+ $this->connector = $this->initConnector($connector);
+ }
+
+ private function initOptions(array $options)
+ {
+ $wrongOptions = array_diff(array_keys($options), array_keys($this->options));
+ if ($wrongOptions) {
+ throw new Exception('Unknown options: ' . implode(', ', $wrongOptions));
+ }
+
+ return array_replace($this->options, $options);
+ }
+
+ private function initConnector(Connector $connector = null)
+ {
+ if (!$connector) {
+ if ($this->options['dataStorage']) {
+ Connector::setPostponeStorage($this->options['dataStorage']);
+ }
+ $connector = Connector::getInstance();
+ }
+
+ if ($this->options['registerHelper'] && !Helper::isRegistered()) {
+ Helper::register();
+ }
+
+ if ($this->options['enabled'] && $connector->isActiveClient()) {
+ if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) {
+ $handler = Handler::getInstance();
+ $handler->setHandleErrors($this->options['useOwnErrorsHandler']);
+ $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']);
+ $handler->start();
+ }
+ if ($this->options['sourcesBasePath']) {
+ $connector->setSourcesBasePath($this->options['sourcesBasePath']);
+ }
+ if ($this->options['serverEncoding']) {
+ $connector->setServerEncoding($this->options['serverEncoding']);
+ }
+ if ($this->options['password']) {
+ $connector->setPassword($this->options['password']);
+ }
+ if ($this->options['enableSslOnlyMode']) {
+ $connector->enableSslOnlyMode();
+ }
+ if ($this->options['ipMasks']) {
+ $connector->setAllowedIpMasks($this->options['ipMasks']);
+ }
+ if ($this->options['headersLimit']) {
+ $connector->setHeadersLimit($this->options['headersLimit']);
+ }
+ if ($this->options['detectDumpTraceAndSource']) {
+ $connector->getDebugDispatcher()->detectTraceAndSource = true;
+ }
+ $dumper = $connector->getDumper();
+ $dumper->levelLimit = $this->options['dumperLevelLimit'];
+ $dumper->itemsCountLimit = $this->options['dumperItemsCountLimit'];
+ $dumper->itemSizeLimit = $this->options['dumperItemSizeLimit'];
+ $dumper->dumpSizeLimit = $this->options['dumperDumpSizeLimit'];
+ $dumper->detectCallbacks = $this->options['dumperDetectCallbacks'];
+ if ($this->options['enableEvalListener']) {
+ $connector->startEvalRequestsListener();
+ }
+ }
+
+ return $connector;
+ }
+
+ public function getConnector()
+ {
+ return $this->connector;
+ }
+
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ public function handle(array $record)
+ {
+ if ($this->options['enabled'] && $this->connector->isActiveClient()) {
+ return parent::handle($record);
+ }
+
+ return !$this->bubble;
+ }
+
+ /**
+ * Writes the record down to the log of the implementing handler
+ *
+ * @param array $record
+ * @return void
+ */
+ protected function write(array $record)
+ {
+ if ($record['level'] < Logger::NOTICE) {
+ $this->handleDebugRecord($record);
+ } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) {
+ $this->handleExceptionRecord($record);
+ } else {
+ $this->handleErrorRecord($record);
+ }
+ }
+
+ private function handleDebugRecord(array $record)
+ {
+ $tags = $this->getRecordTags($record);
+ $message = $record['message'];
+ if ($record['context']) {
+ $message .= ' ' . Utils::jsonEncode($this->connector->getDumper()->dump(array_filter($record['context'])), null, true);
+ }
+ $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']);
+ }
+
+ private function handleExceptionRecord(array $record)
+ {
+ $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']);
+ }
+
+ private function handleErrorRecord(array $record)
+ {
+ $context = $record['context'];
+
+ $this->connector->getErrorsDispatcher()->dispatchError(
+ isset($context['code']) ? $context['code'] : null,
+ isset($context['message']) ? $context['message'] : $record['message'],
+ isset($context['file']) ? $context['file'] : null,
+ isset($context['line']) ? $context['line'] : null,
+ $this->options['classesPartialsTraceIgnore']
+ );
+ }
+
+ private function getRecordTags(array &$record)
+ {
+ $tags = null;
+ if (!empty($record['context'])) {
+ $context = & $record['context'];
+ foreach ($this->options['debugTagsKeysInContext'] as $key) {
+ if (!empty($context[$key])) {
+ $tags = $context[$key];
+ if ($key === 0) {
+ array_shift($context);
+ } else {
+ unset($context[$key]);
+ }
+ break;
+ }
+ }
+ }
+
+ return $tags ?: strtolower($record['level_name']);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('%message%');
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php
new file mode 100644
index 00000000..66a3d83a
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php
@@ -0,0 +1,40 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Processor\ProcessorInterface;
+
+/**
+ * Interface to describe loggers that have processors
+ *
+ * This interface is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano
+ */
+interface ProcessableHandlerInterface
+{
+ /**
+ * Adds a processor in the stack.
+ *
+ * @param ProcessorInterface|callable $callback
+ * @return HandlerInterface self
+ */
+ public function pushProcessor($callback): HandlerInterface;
+
+ /**
+ * Removes the processor on top of the stack and returns it.
+ *
+ * @throws \LogicException In case the processor stack is empty
+ * @return callable
+ */
+ public function popProcessor(): callable;
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php
new file mode 100644
index 00000000..09f32a12
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\ResettableInterface;
+
+/**
+ * Helper trait for implementing ProcessableInterface
+ *
+ * This trait is present in monolog 1.x to ease forward compatibility.
+ *
+ * @author Jordi Boggiano
+ */
+trait ProcessableHandlerTrait
+{
+ /**
+ * @var callable[]
+ */
+ protected $processors = [];
+
+ /**
+ * {@inheritdoc}
+ * @suppress PhanTypeMismatchReturn
+ */
+ public function pushProcessor($callback): HandlerInterface
+ {
+ array_unshift($this->processors, $callback);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function popProcessor(): callable
+ {
+ if (!$this->processors) {
+ throw new \LogicException('You tried to pop from an empty processor stack.');
+ }
+
+ return array_shift($this->processors);
+ }
+
+ /**
+ * Processes a record.
+ */
+ protected function processRecord(array $record): array
+ {
+ foreach ($this->processors as $processor) {
+ $record = $processor($record);
+ }
+
+ return $record;
+ }
+
+ protected function resetProcessors(): void
+ {
+ foreach ($this->processors as $processor) {
+ if ($processor instanceof ResettableInterface) {
+ $processor->reset();
+ }
+ }
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php
new file mode 100644
index 00000000..a99e6ab7
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Proxies log messages to an existing PSR-3 compliant logger.
+ *
+ * @author Michael Moussa
+ */
+class PsrHandler extends AbstractHandler
+{
+ /**
+ * PSR-3 compliant logger
+ *
+ * @var LoggerInterface
+ */
+ protected $logger;
+
+ /**
+ * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ $this->logger = $logger;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function handle(array $record)
+ {
+ if (!$this->isHandling($record)) {
+ return false;
+ }
+
+ $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']);
+
+ return false === $this->bubble;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php
new file mode 100644
index 00000000..f27bb3da
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php
@@ -0,0 +1,185 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through the pushover api to mobile phones
+ *
+ * @author Sebastian Göttschkes
+ * @see https://www.pushover.net/api
+ */
+class PushoverHandler extends SocketHandler
+{
+ private $token;
+ private $users;
+ private $title;
+ private $user;
+ private $retry;
+ private $expire;
+
+ private $highPriorityLevel;
+ private $emergencyLevel;
+ private $useFormattedMessage = false;
+
+ /**
+ * All parameters that can be sent to Pushover
+ * @see https://pushover.net/api
+ * @var array
+ */
+ private $parameterNames = array(
+ 'token' => true,
+ 'user' => true,
+ 'message' => true,
+ 'device' => true,
+ 'title' => true,
+ 'url' => true,
+ 'url_title' => true,
+ 'priority' => true,
+ 'timestamp' => true,
+ 'sound' => true,
+ 'retry' => true,
+ 'expire' => true,
+ 'callback' => true,
+ );
+
+ /**
+ * Sounds the api supports by default
+ * @see https://pushover.net/api#sounds
+ * @var array
+ */
+ private $sounds = array(
+ 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming',
+ 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb',
+ 'persistent', 'echo', 'updown', 'none',
+ );
+
+ /**
+ * @param string $token Pushover api token
+ * @param string|array $users Pushover user id or array of ids the message will be sent to
+ * @param string $title Title sent to the Pushover API
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
+ * the pushover.net app owner. OpenSSL is required for this option.
+ * @param int $highPriorityLevel The minimum logging level at which this handler will start
+ * sending "high priority" requests to the Pushover API
+ * @param int $emergencyLevel The minimum logging level at which this handler will start
+ * sending "emergency" requests to the Pushover API
+ * @param int $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user.
+ * @param int $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds).
+ */
+ public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200)
+ {
+ $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80';
+ parent::__construct($connectionString, $level, $bubble);
+
+ $this->token = $token;
+ $this->users = (array) $users;
+ $this->title = $title ?: gethostname();
+ $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel);
+ $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel);
+ $this->retry = $retry;
+ $this->expire = $expire;
+ }
+
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ private function buildContent($record)
+ {
+ // Pushover has a limit of 512 characters on title and message combined.
+ $maxMessageLength = 512 - strlen($this->title);
+
+ $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message'];
+ $message = substr($message, 0, $maxMessageLength);
+
+ $timestamp = $record['datetime']->getTimestamp();
+
+ $dataArray = array(
+ 'token' => $this->token,
+ 'user' => $this->user,
+ 'message' => $message,
+ 'title' => $this->title,
+ 'timestamp' => $timestamp,
+ );
+
+ if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) {
+ $dataArray['priority'] = 2;
+ $dataArray['retry'] = $this->retry;
+ $dataArray['expire'] = $this->expire;
+ } elseif (isset($record['level']) && $record['level'] >= $this->highPriorityLevel) {
+ $dataArray['priority'] = 1;
+ }
+
+ // First determine the available parameters
+ $context = array_intersect_key($record['context'], $this->parameterNames);
+ $extra = array_intersect_key($record['extra'], $this->parameterNames);
+
+ // Least important info should be merged with subsequent info
+ $dataArray = array_merge($extra, $context, $dataArray);
+
+ // Only pass sounds that are supported by the API
+ if (isset($dataArray['sound']) && !in_array($dataArray['sound'], $this->sounds)) {
+ unset($dataArray['sound']);
+ }
+
+ return http_build_query($dataArray);
+ }
+
+ private function buildHeader($content)
+ {
+ $header = "POST /1/messages.json HTTP/1.1\r\n";
+ $header .= "Host: api.pushover.net\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ protected function write(array $record)
+ {
+ foreach ($this->users as $user) {
+ $this->user = $user;
+
+ parent::write($record);
+ $this->closeSocket();
+ }
+
+ $this->user = null;
+ }
+
+ public function setHighPriorityLevel($value)
+ {
+ $this->highPriorityLevel = $value;
+ }
+
+ public function setEmergencyLevel($value)
+ {
+ $this->emergencyLevel = $value;
+ }
+
+ /**
+ * Use the formatted message?
+ * @param bool $value
+ */
+ public function useFormattedMessage($value)
+ {
+ $this->useFormattedMessage = (bool) $value;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php
new file mode 100644
index 00000000..1929f25f
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php
@@ -0,0 +1,234 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+use Raven_Client;
+
+/**
+ * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server
+ * using sentry-php (https://github.com/getsentry/sentry-php)
+ *
+ * @author Marc Abramowitz
+ */
+class RavenHandler extends AbstractProcessingHandler
+{
+ /**
+ * Translates Monolog log levels to Raven log levels.
+ */
+ protected $logLevels = array(
+ Logger::DEBUG => Raven_Client::DEBUG,
+ Logger::INFO => Raven_Client::INFO,
+ Logger::NOTICE => Raven_Client::INFO,
+ Logger::WARNING => Raven_Client::WARNING,
+ Logger::ERROR => Raven_Client::ERROR,
+ Logger::CRITICAL => Raven_Client::FATAL,
+ Logger::ALERT => Raven_Client::FATAL,
+ Logger::EMERGENCY => Raven_Client::FATAL,
+ );
+
+ /**
+ * @var string should represent the current version of the calling
+ * software. Can be any string (git commit, version number)
+ */
+ protected $release;
+
+ /**
+ * @var Raven_Client the client object that sends the message to the server
+ */
+ protected $ravenClient;
+
+ /**
+ * @var LineFormatter The formatter to use for the logs generated via handleBatch()
+ */
+ protected $batchFormatter;
+
+ /**
+ * @param Raven_Client $ravenClient
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
+ {
+ @trigger_error('The Monolog\Handler\RavenHandler class is deprecated. You should rather upgrade to the sentry/sentry 2.x and use Sentry\Monolog\Handler, see https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php', E_USER_DEPRECATED);
+
+ parent::__construct($level, $bubble);
+
+ $this->ravenClient = $ravenClient;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ $level = $this->level;
+
+ // filter records based on their level
+ $records = array_filter($records, function ($record) use ($level) {
+ return $record['level'] >= $level;
+ });
+
+ if (!$records) {
+ return;
+ }
+
+ // the record with the highest severity is the "main" one
+ $record = array_reduce($records, function ($highest, $record) {
+ if ($record['level'] > $highest['level']) {
+ return $record;
+ }
+
+ return $highest;
+ });
+
+ // the other ones are added as a context item
+ $logs = array();
+ foreach ($records as $r) {
+ $logs[] = $this->processRecord($r);
+ }
+
+ if ($logs) {
+ $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs);
+ }
+
+ $this->handle($record);
+ }
+
+ /**
+ * Sets the formatter for the logs generated by handleBatch().
+ *
+ * @param FormatterInterface $formatter
+ */
+ public function setBatchFormatter(FormatterInterface $formatter)
+ {
+ $this->batchFormatter = $formatter;
+ }
+
+ /**
+ * Gets the formatter for the logs generated by handleBatch().
+ *
+ * @return FormatterInterface
+ */
+ public function getBatchFormatter()
+ {
+ if (!$this->batchFormatter) {
+ $this->batchFormatter = $this->getDefaultBatchFormatter();
+ }
+
+ return $this->batchFormatter;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $previousUserContext = false;
+ $options = array();
+ $options['level'] = $this->logLevels[$record['level']];
+ $options['tags'] = array();
+ if (!empty($record['extra']['tags'])) {
+ $options['tags'] = array_merge($options['tags'], $record['extra']['tags']);
+ unset($record['extra']['tags']);
+ }
+ if (!empty($record['context']['tags'])) {
+ $options['tags'] = array_merge($options['tags'], $record['context']['tags']);
+ unset($record['context']['tags']);
+ }
+ if (!empty($record['context']['fingerprint'])) {
+ $options['fingerprint'] = $record['context']['fingerprint'];
+ unset($record['context']['fingerprint']);
+ }
+ if (!empty($record['context']['logger'])) {
+ $options['logger'] = $record['context']['logger'];
+ unset($record['context']['logger']);
+ } else {
+ $options['logger'] = $record['channel'];
+ }
+ foreach ($this->getExtraParameters() as $key) {
+ foreach (array('extra', 'context') as $source) {
+ if (!empty($record[$source][$key])) {
+ $options[$key] = $record[$source][$key];
+ unset($record[$source][$key]);
+ }
+ }
+ }
+ if (!empty($record['context'])) {
+ $options['extra']['context'] = $record['context'];
+ if (!empty($record['context']['user'])) {
+ $previousUserContext = $this->ravenClient->context->user;
+ $this->ravenClient->user_context($record['context']['user']);
+ unset($options['extra']['context']['user']);
+ }
+ }
+ if (!empty($record['extra'])) {
+ $options['extra']['extra'] = $record['extra'];
+ }
+
+ if (!empty($this->release) && !isset($options['release'])) {
+ $options['release'] = $this->release;
+ }
+
+ if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) {
+ $options['message'] = $record['formatted'];
+ $this->ravenClient->captureException($record['context']['exception'], $options);
+ } else {
+ $this->ravenClient->captureMessage($record['formatted'], array(), $options);
+ }
+
+ if ($previousUserContext !== false) {
+ $this->ravenClient->user_context($previousUserContext);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter('[%channel%] %message%');
+ }
+
+ /**
+ * Gets the default formatter for the logs generated by handleBatch().
+ *
+ * @return FormatterInterface
+ */
+ protected function getDefaultBatchFormatter()
+ {
+ return new LineFormatter();
+ }
+
+ /**
+ * Gets extra parameters supported by Raven that can be found in "extra" and "context"
+ *
+ * @return array
+ */
+ protected function getExtraParameters()
+ {
+ return array('contexts', 'checksum', 'release', 'event_id');
+ }
+
+ /**
+ * @param string $value
+ * @return self
+ */
+ public function setRelease($value)
+ {
+ $this->release = $value;
+
+ return $this;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php
new file mode 100644
index 00000000..590f9965
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Logger;
+
+/**
+ * Logs to a Redis key using rpush
+ *
+ * usage example:
+ *
+ * $log = new Logger('application');
+ * $redis = new RedisHandler(new Predis\Client("tcp://localhost:6379"), "logs", "prod");
+ * $log->pushHandler($redis);
+ *
+ * @author Thomas Tourlourat
+ */
+class RedisHandler extends AbstractProcessingHandler
+{
+ private $redisClient;
+ private $redisKey;
+ protected $capSize;
+
+ /**
+ * @param \Predis\Client|\Redis $redis The redis instance
+ * @param string $key The key name to push records to
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int $capSize Number of entries to limit list size to
+ */
+ public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false)
+ {
+ if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
+ throw new \InvalidArgumentException('Predis\Client or Redis instance required');
+ }
+
+ $this->redisClient = $redis;
+ $this->redisKey = $key;
+ $this->capSize = $capSize;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function write(array $record)
+ {
+ if ($this->capSize) {
+ $this->writeCapped($record);
+ } else {
+ $this->redisClient->rpush($this->redisKey, $record["formatted"]);
+ }
+ }
+
+ /**
+ * Write and cap the collection
+ * Writes the record to the redis list and caps its
+ *
+ * @param array $record associative record array
+ * @return void
+ */
+ protected function writeCapped(array $record)
+ {
+ if ($this->redisClient instanceof \Redis) {
+ $this->redisClient->multi()
+ ->rpush($this->redisKey, $record["formatted"])
+ ->ltrim($this->redisKey, -$this->capSize, -1)
+ ->exec();
+ } else {
+ $redisKey = $this->redisKey;
+ $capSize = $this->capSize;
+ $this->redisClient->transaction(function ($tx) use ($record, $redisKey, $capSize) {
+ $tx->rpush($redisKey, $record["formatted"]);
+ $tx->ltrim($redisKey, -$capSize, -1);
+ });
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultFormatter()
+ {
+ return new LineFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php
new file mode 100644
index 00000000..65073ffe
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php
@@ -0,0 +1,144 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use RollbarNotifier;
+use Exception;
+use Monolog\Logger;
+
+/**
+ * Sends errors to Rollbar
+ *
+ * If the context data contains a `payload` key, that is used as an array
+ * of payload options to RollbarNotifier's report_message/report_exception methods.
+ *
+ * Rollbar's context info will contain the context + extra keys from the log record
+ * merged, and then on top of that a few keys:
+ *
+ * - level (rollbar level name)
+ * - monolog_level (monolog level name, raw level, as rollbar only has 5 but monolog 8)
+ * - channel
+ * - datetime (unix timestamp)
+ *
+ * @author Paul Statezny
+ */
+class RollbarHandler extends AbstractProcessingHandler
+{
+ /**
+ * Rollbar notifier
+ *
+ * @var RollbarNotifier
+ */
+ protected $rollbarNotifier;
+
+ protected $levelMap = array(
+ Logger::DEBUG => 'debug',
+ Logger::INFO => 'info',
+ Logger::NOTICE => 'info',
+ Logger::WARNING => 'warning',
+ Logger::ERROR => 'error',
+ Logger::CRITICAL => 'critical',
+ Logger::ALERT => 'critical',
+ Logger::EMERGENCY => 'critical',
+ );
+
+ /**
+ * Records whether any log records have been added since the last flush of the rollbar notifier
+ *
+ * @var bool
+ */
+ private $hasRecords = false;
+
+ protected $initialized = false;
+
+ /**
+ * @param RollbarNotifier $rollbarNotifier RollbarNotifier object constructed with valid token
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(RollbarNotifier $rollbarNotifier, $level = Logger::ERROR, $bubble = true)
+ {
+ $this->rollbarNotifier = $rollbarNotifier;
+
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if (!$this->initialized) {
+ // __destructor() doesn't get called on Fatal errors
+ register_shutdown_function(array($this, 'close'));
+ $this->initialized = true;
+ }
+
+ $context = $record['context'];
+ $payload = array();
+ if (isset($context['payload'])) {
+ $payload = $context['payload'];
+ unset($context['payload']);
+ }
+ $context = array_merge($context, $record['extra'], array(
+ 'level' => $this->levelMap[$record['level']],
+ 'monolog_level' => $record['level_name'],
+ 'channel' => $record['channel'],
+ 'datetime' => $record['datetime']->format('U'),
+ ));
+
+ if (isset($context['exception']) && $context['exception'] instanceof Exception) {
+ $payload['level'] = $context['level'];
+ $exception = $context['exception'];
+ unset($context['exception']);
+
+ $this->rollbarNotifier->report_exception($exception, $context, $payload);
+ } else {
+ $this->rollbarNotifier->report_message(
+ $record['message'],
+ $context['level'],
+ $context,
+ $payload
+ );
+ }
+
+ $this->hasRecords = true;
+ }
+
+ public function flush()
+ {
+ if ($this->hasRecords) {
+ $this->rollbarNotifier->flush();
+ $this->hasRecords = false;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->flush();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ $this->flush();
+
+ parent::reset();
+ }
+
+
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php
new file mode 100644
index 00000000..ae2309f8
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php
@@ -0,0 +1,190 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Stores logs to files that are rotated every day and a limited number of files are kept.
+ *
+ * This rotation is only intended to be used as a workaround. Using logrotate to
+ * handle the rotation is strongly encouraged when you can use it.
+ *
+ * @author Christophe Coevoet
+ * @author Jordi Boggiano
+ */
+class RotatingFileHandler extends StreamHandler
+{
+ const FILE_PER_DAY = 'Y-m-d';
+ const FILE_PER_MONTH = 'Y-m';
+ const FILE_PER_YEAR = 'Y';
+
+ protected $filename;
+ protected $maxFiles;
+ protected $mustRotate;
+ protected $nextRotation;
+ protected $filenameFormat;
+ protected $dateFormat;
+
+ /**
+ * @param string $filename
+ * @param int $maxFiles The maximal amount of files to keep (0 means unlimited)
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
+ * @param bool $useLocking Try to lock log file before doing any writes
+ */
+ public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
+ {
+ $this->filename = $filename;
+ $this->maxFiles = (int) $maxFiles;
+ $this->nextRotation = new \DateTime('tomorrow');
+ $this->filenameFormat = '{filename}-{date}';
+ $this->dateFormat = 'Y-m-d';
+
+ parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ parent::close();
+
+ if (true === $this->mustRotate) {
+ $this->rotate();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function reset()
+ {
+ parent::reset();
+
+ if (true === $this->mustRotate) {
+ $this->rotate();
+ }
+ }
+
+ public function setFilenameFormat($filenameFormat, $dateFormat)
+ {
+ if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) {
+ trigger_error(
+ 'Invalid date format - format must be one of '.
+ 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '.
+ 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '.
+ 'date formats using slashes, underscores and/or dots instead of dashes.',
+ E_USER_DEPRECATED
+ );
+ }
+ if (substr_count($filenameFormat, '{date}') === 0) {
+ trigger_error(
+ 'Invalid filename format - format should contain at least `{date}`, because otherwise rotating is impossible.',
+ E_USER_DEPRECATED
+ );
+ }
+ $this->filenameFormat = $filenameFormat;
+ $this->dateFormat = $dateFormat;
+ $this->url = $this->getTimedFilename();
+ $this->close();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ // on the first record written, if the log is new, we should rotate (once per day)
+ if (null === $this->mustRotate) {
+ $this->mustRotate = !file_exists($this->url);
+ }
+
+ if ($this->nextRotation < $record['datetime']) {
+ $this->mustRotate = true;
+ $this->close();
+ }
+
+ parent::write($record);
+ }
+
+ /**
+ * Rotates the files.
+ */
+ protected function rotate()
+ {
+ // update filename
+ $this->url = $this->getTimedFilename();
+ $this->nextRotation = new \DateTime('tomorrow');
+
+ // skip GC of old logs if files are unlimited
+ if (0 === $this->maxFiles) {
+ return;
+ }
+
+ $logFiles = glob($this->getGlobPattern());
+ if ($this->maxFiles >= count($logFiles)) {
+ // no files to remove
+ return;
+ }
+
+ // Sorting the files by name to remove the older ones
+ usort($logFiles, function ($a, $b) {
+ return strcmp($b, $a);
+ });
+
+ foreach (array_slice($logFiles, $this->maxFiles) as $file) {
+ if (is_writable($file)) {
+ // suppress errors here as unlink() might fail if two processes
+ // are cleaning up/rotating at the same time
+ set_error_handler(function ($errno, $errstr, $errfile, $errline) {});
+ unlink($file);
+ restore_error_handler();
+ }
+ }
+
+ $this->mustRotate = false;
+ }
+
+ protected function getTimedFilename()
+ {
+ $fileInfo = pathinfo($this->filename);
+ $timedFilename = str_replace(
+ array('{filename}', '{date}'),
+ array($fileInfo['filename'], date($this->dateFormat)),
+ $fileInfo['dirname'] . '/' . $this->filenameFormat
+ );
+
+ if (!empty($fileInfo['extension'])) {
+ $timedFilename .= '.'.$fileInfo['extension'];
+ }
+
+ return $timedFilename;
+ }
+
+ protected function getGlobPattern()
+ {
+ $fileInfo = pathinfo($this->filename);
+ $glob = str_replace(
+ array('{filename}', '{date}'),
+ array($fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'),
+ $fileInfo['dirname'] . '/' . $this->filenameFormat
+ );
+ if (!empty($fileInfo['extension'])) {
+ $glob .= '.'.$fileInfo['extension'];
+ }
+
+ return $glob;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php
new file mode 100644
index 00000000..b547ed7d
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php
@@ -0,0 +1,113 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Sampling handler
+ *
+ * A sampled event stream can be useful for logging high frequency events in
+ * a production environment where you only need an idea of what is happening
+ * and are not concerned with capturing every occurrence. Since the decision to
+ * handle or not handle a particular event is determined randomly, the
+ * resulting sampled log is not guaranteed to contain 1/N of the events that
+ * occurred in the application, but based on the Law of large numbers, it will
+ * tend to be close to this ratio with a large number of attempts.
+ *
+ * @author Bryan Davis
+ * @author Kunal Mehta
+ */
+class SamplingHandler extends AbstractHandler
+{
+ /**
+ * @var callable|HandlerInterface $handler
+ */
+ protected $handler;
+
+ /**
+ * @var int $factor
+ */
+ protected $factor;
+
+ /**
+ * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler).
+ * @param int $factor Sample factor
+ */
+ public function __construct($handler, $factor)
+ {
+ parent::__construct();
+ $this->handler = $handler;
+ $this->factor = $factor;
+
+ if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
+ throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
+ }
+ }
+
+ public function isHandling(array $record)
+ {
+ return $this->getHandler($record)->isHandling($record);
+ }
+
+ public function handle(array $record)
+ {
+ if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ $this->getHandler($record)->handle($record);
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * Return the nested handler
+ *
+ * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
+ *
+ * @return HandlerInterface
+ */
+ public function getHandler(array $record = null)
+ {
+ if (!$this->handler instanceof HandlerInterface) {
+ $this->handler = call_user_func($this->handler, $record, $this);
+ if (!$this->handler instanceof HandlerInterface) {
+ throw new \RuntimeException("The factory callable should return a HandlerInterface");
+ }
+ }
+
+ return $this->handler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->getHandler()->setFormatter($formatter);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormatter()
+ {
+ return $this->getHandler()->getFormatter();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php
new file mode 100644
index 00000000..39455501
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php
@@ -0,0 +1,299 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\Slack;
+
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Formatter\NormalizerFormatter;
+use Monolog\Formatter\FormatterInterface;
+
+/**
+ * Slack record utility helping to log to Slack webhooks or API.
+ *
+ * @author Greg Kedzierski
+ * @author Haralan Dobrev
+ * @see https://api.slack.com/incoming-webhooks
+ * @see https://api.slack.com/docs/message-attachments
+ */
+class SlackRecord
+{
+ const COLOR_DANGER = 'danger';
+
+ const COLOR_WARNING = 'warning';
+
+ const COLOR_GOOD = 'good';
+
+ const COLOR_DEFAULT = '#e3e4e6';
+
+ /**
+ * Slack channel (encoded ID or name)
+ * @var string|null
+ */
+ private $channel;
+
+ /**
+ * Name of a bot
+ * @var string|null
+ */
+ private $username;
+
+ /**
+ * User icon e.g. 'ghost', 'http://example.com/user.png'
+ * @var string
+ */
+ private $userIcon;
+
+ /**
+ * Whether the message should be added to Slack as attachment (plain text otherwise)
+ * @var bool
+ */
+ private $useAttachment;
+
+ /**
+ * Whether the the context/extra messages added to Slack as attachments are in a short style
+ * @var bool
+ */
+ private $useShortAttachment;
+
+ /**
+ * Whether the attachment should include context and extra data
+ * @var bool
+ */
+ private $includeContextAndExtra;
+
+ /**
+ * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2']
+ * @var array
+ */
+ private $excludeFields;
+
+ /**
+ * @var FormatterInterface
+ */
+ private $formatter;
+
+ /**
+ * @var NormalizerFormatter
+ */
+ private $normalizerFormatter;
+
+ public function __construct($channel = null, $username = null, $useAttachment = true, $userIcon = null, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null)
+ {
+ $this->channel = $channel;
+ $this->username = $username;
+ $this->userIcon = trim($userIcon, ':');
+ $this->useAttachment = $useAttachment;
+ $this->useShortAttachment = $useShortAttachment;
+ $this->includeContextAndExtra = $includeContextAndExtra;
+ $this->excludeFields = $excludeFields;
+ $this->formatter = $formatter;
+
+ if ($this->includeContextAndExtra) {
+ $this->normalizerFormatter = new NormalizerFormatter();
+ }
+ }
+
+ public function getSlackData(array $record)
+ {
+ $dataArray = array();
+ $record = $this->excludeFields($record);
+
+ if ($this->username) {
+ $dataArray['username'] = $this->username;
+ }
+
+ if ($this->channel) {
+ $dataArray['channel'] = $this->channel;
+ }
+
+ if ($this->formatter && !$this->useAttachment) {
+ $message = $this->formatter->format($record);
+ } else {
+ $message = $record['message'];
+ }
+
+ if ($this->useAttachment) {
+ $attachment = array(
+ 'fallback' => $message,
+ 'text' => $message,
+ 'color' => $this->getAttachmentColor($record['level']),
+ 'fields' => array(),
+ 'mrkdwn_in' => array('fields'),
+ 'ts' => $record['datetime']->getTimestamp()
+ );
+
+ if ($this->useShortAttachment) {
+ $attachment['title'] = $record['level_name'];
+ } else {
+ $attachment['title'] = 'Message';
+ $attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name']);
+ }
+
+
+ if ($this->includeContextAndExtra) {
+ foreach (array('extra', 'context') as $key) {
+ if (empty($record[$key])) {
+ continue;
+ }
+
+ if ($this->useShortAttachment) {
+ $attachment['fields'][] = $this->generateAttachmentField(
+ $key,
+ $record[$key]
+ );
+ } else {
+ // Add all extra fields as individual fields in attachment
+ $attachment['fields'] = array_merge(
+ $attachment['fields'],
+ $this->generateAttachmentFields($record[$key])
+ );
+ }
+ }
+ }
+
+ $dataArray['attachments'] = array($attachment);
+ } else {
+ $dataArray['text'] = $message;
+ }
+
+ if ($this->userIcon) {
+ if (filter_var($this->userIcon, FILTER_VALIDATE_URL)) {
+ $dataArray['icon_url'] = $this->userIcon;
+ } else {
+ $dataArray['icon_emoji'] = ":{$this->userIcon}:";
+ }
+ }
+
+ return $dataArray;
+ }
+
+ /**
+ * Returned a Slack message attachment color associated with
+ * provided level.
+ *
+ * @param int $level
+ * @return string
+ */
+ public function getAttachmentColor($level)
+ {
+ switch (true) {
+ case $level >= Logger::ERROR:
+ return self::COLOR_DANGER;
+ case $level >= Logger::WARNING:
+ return self::COLOR_WARNING;
+ case $level >= Logger::INFO:
+ return self::COLOR_GOOD;
+ default:
+ return self::COLOR_DEFAULT;
+ }
+ }
+
+ /**
+ * Stringifies an array of key/value pairs to be used in attachment fields
+ *
+ * @param array $fields
+ *
+ * @return string
+ */
+ public function stringify($fields)
+ {
+ $normalized = $this->normalizerFormatter->format($fields);
+ $prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128;
+ $flags = 0;
+ if (PHP_VERSION_ID >= 50400) {
+ $flags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
+ }
+
+ $hasSecondDimension = count(array_filter($normalized, 'is_array'));
+ $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric'));
+
+ return $hasSecondDimension || $hasNonNumericKeys
+ ? Utils::jsonEncode($normalized, $prettyPrintFlag | $flags)
+ : Utils::jsonEncode($normalized, $flags);
+ }
+
+ /**
+ * Sets the formatter
+ *
+ * @param FormatterInterface $formatter
+ */
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ $this->formatter = $formatter;
+ }
+
+ /**
+ * Generates attachment field
+ *
+ * @param string $title
+ * @param string|array $value
+ *
+ * @return array
+ */
+ private function generateAttachmentField($title, $value)
+ {
+ $value = is_array($value)
+ ? sprintf('```%s```', $this->stringify($value))
+ : $value;
+
+ return array(
+ 'title' => ucfirst($title),
+ 'value' => $value,
+ 'short' => false
+ );
+ }
+
+ /**
+ * Generates a collection of attachment fields from array
+ *
+ * @param array $data
+ *
+ * @return array
+ */
+ private function generateAttachmentFields(array $data)
+ {
+ $fields = array();
+ foreach ($this->normalizerFormatter->format($data) as $key => $value) {
+ $fields[] = $this->generateAttachmentField($key, $value);
+ }
+
+ return $fields;
+ }
+
+ /**
+ * Get a copy of record with fields excluded according to $this->excludeFields
+ *
+ * @param array $record
+ *
+ * @return array
+ */
+ private function excludeFields(array $record)
+ {
+ foreach ($this->excludeFields as $field) {
+ $keys = explode('.', $field);
+ $node = &$record;
+ $lastKey = end($keys);
+ foreach ($keys as $key) {
+ if (!isset($node[$key])) {
+ break;
+ }
+ if ($lastKey === $key) {
+ unset($node[$key]);
+ break;
+ }
+ $node = &$node[$key];
+ }
+ }
+
+ return $record;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php
new file mode 100644
index 00000000..88c4c4d0
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php
@@ -0,0 +1,221 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Handler\Slack\SlackRecord;
+
+/**
+ * Sends notifications through Slack API
+ *
+ * @author Greg Kedzierski
+ * @see https://api.slack.com/
+ */
+class SlackHandler extends SocketHandler
+{
+ /**
+ * Slack API token
+ * @var string
+ */
+ private $token;
+
+ /**
+ * Instance of the SlackRecord util class preparing data for Slack API.
+ * @var SlackRecord
+ */
+ private $slackRecord;
+
+ /**
+ * @param string $token Slack API token
+ * @param string $channel Slack channel (encoded ID or name)
+ * @param string|null $username Name of a bot
+ * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise)
+ * @param string|null $iconEmoji The emoji name to use (or null)
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style
+ * @param bool $includeContextAndExtra Whether the attachment should include context and extra data
+ * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2']
+ * @throws MissingExtensionException If no OpenSSL PHP extension configured
+ */
+ public function __construct($token, $channel, $username = null, $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array())
+ {
+ if (!extension_loaded('openssl')) {
+ throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler');
+ }
+
+ parent::__construct('ssl://slack.com:443', $level, $bubble);
+
+ $this->slackRecord = new SlackRecord(
+ $channel,
+ $username,
+ $useAttachment,
+ $iconEmoji,
+ $useShortAttachment,
+ $includeContextAndExtra,
+ $excludeFields,
+ $this->formatter
+ );
+
+ $this->token = $token;
+ }
+
+ public function getSlackRecord()
+ {
+ return $this->slackRecord;
+ }
+
+ public function getToken()
+ {
+ return $this->token;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ * @return string
+ */
+ protected function generateDataStream($record)
+ {
+ $content = $this->buildContent($record);
+
+ return $this->buildHeader($content) . $content;
+ }
+
+ /**
+ * Builds the body of API call
+ *
+ * @param array $record
+ * @return string
+ */
+ private function buildContent($record)
+ {
+ $dataArray = $this->prepareContentData($record);
+
+ return http_build_query($dataArray);
+ }
+
+ /**
+ * Prepares content data
+ *
+ * @param array $record
+ * @return array
+ */
+ protected function prepareContentData($record)
+ {
+ $dataArray = $this->slackRecord->getSlackData($record);
+ $dataArray['token'] = $this->token;
+
+ if (!empty($dataArray['attachments'])) {
+ $dataArray['attachments'] = Utils::jsonEncode($dataArray['attachments']);
+ }
+
+ return $dataArray;
+ }
+
+ /**
+ * Builds the header of the API Call
+ *
+ * @param string $content
+ * @return string
+ */
+ private function buildHeader($content)
+ {
+ $header = "POST /api/chat.postMessage HTTP/1.1\r\n";
+ $header .= "Host: slack.com\r\n";
+ $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
+ $header .= "Content-Length: " . strlen($content) . "\r\n";
+ $header .= "\r\n";
+
+ return $header;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ parent::write($record);
+ $this->finalizeWrite();
+ }
+
+ /**
+ * Finalizes the request by reading some bytes and then closing the socket
+ *
+ * If we do not read some but close the socket too early, slack sometimes
+ * drops the request entirely.
+ */
+ protected function finalizeWrite()
+ {
+ $res = $this->getResource();
+ if (is_resource($res)) {
+ @fread($res, 2048);
+ }
+ $this->closeSocket();
+ }
+
+ /**
+ * Returned a Slack message attachment color associated with
+ * provided level.
+ *
+ * @param int $level
+ * @return string
+ * @deprecated Use underlying SlackRecord instead
+ */
+ protected function getAttachmentColor($level)
+ {
+ trigger_error(
+ 'SlackHandler::getAttachmentColor() is deprecated. Use underlying SlackRecord instead.',
+ E_USER_DEPRECATED
+ );
+
+ return $this->slackRecord->getAttachmentColor($level);
+ }
+
+ /**
+ * Stringifies an array of key/value pairs to be used in attachment fields
+ *
+ * @param array $fields
+ * @return string
+ * @deprecated Use underlying SlackRecord instead
+ */
+ protected function stringify($fields)
+ {
+ trigger_error(
+ 'SlackHandler::stringify() is deprecated. Use underlying SlackRecord instead.',
+ E_USER_DEPRECATED
+ );
+
+ return $this->slackRecord->stringify($fields);
+ }
+
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ parent::setFormatter($formatter);
+ $this->slackRecord->setFormatter($formatter);
+
+ return $this;
+ }
+
+ public function getFormatter()
+ {
+ $formatter = parent::getFormatter();
+ $this->slackRecord->setFormatter($formatter);
+
+ return $formatter;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php
new file mode 100644
index 00000000..b87be99a
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php
@@ -0,0 +1,121 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+use Monolog\Utils;
+use Monolog\Handler\Slack\SlackRecord;
+
+/**
+ * Sends notifications through Slack Webhooks
+ *
+ * @author Haralan Dobrev
+ * @see https://api.slack.com/incoming-webhooks
+ */
+class SlackWebhookHandler extends AbstractProcessingHandler
+{
+ /**
+ * Slack Webhook token
+ * @var string
+ */
+ private $webhookUrl;
+
+ /**
+ * Instance of the SlackRecord util class preparing data for Slack API.
+ * @var SlackRecord
+ */
+ private $slackRecord;
+
+ /**
+ * @param string $webhookUrl Slack Webhook URL
+ * @param string|null $channel Slack channel (encoded ID or name)
+ * @param string|null $username Name of a bot
+ * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise)
+ * @param string|null $iconEmoji The emoji name to use (or null)
+ * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style
+ * @param bool $includeContextAndExtra Whether the attachment should include context and extra data
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2']
+ */
+ public function __construct($webhookUrl, $channel = null, $username = null, $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeContextAndExtra = false, $level = Logger::CRITICAL, $bubble = true, array $excludeFields = array())
+ {
+ parent::__construct($level, $bubble);
+
+ $this->webhookUrl = $webhookUrl;
+
+ $this->slackRecord = new SlackRecord(
+ $channel,
+ $username,
+ $useAttachment,
+ $iconEmoji,
+ $useShortAttachment,
+ $includeContextAndExtra,
+ $excludeFields,
+ $this->formatter
+ );
+ }
+
+ public function getSlackRecord()
+ {
+ return $this->slackRecord;
+ }
+
+ public function getWebhookUrl()
+ {
+ return $this->webhookUrl;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ $postData = $this->slackRecord->getSlackData($record);
+ $postString = Utils::jsonEncode($postData);
+
+ $ch = curl_init();
+ $options = array(
+ CURLOPT_URL => $this->webhookUrl,
+ CURLOPT_POST => true,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => array('Content-type: application/json'),
+ CURLOPT_POSTFIELDS => $postString
+ );
+ if (defined('CURLOPT_SAFE_UPLOAD')) {
+ $options[CURLOPT_SAFE_UPLOAD] = true;
+ }
+
+ curl_setopt_array($ch, $options);
+
+ Curl\Util::execute($ch);
+ }
+
+ public function setFormatter(FormatterInterface $formatter)
+ {
+ parent::setFormatter($formatter);
+ $this->slackRecord->setFormatter($formatter);
+
+ return $this;
+ }
+
+ public function getFormatter()
+ {
+ $formatter = parent::getFormatter();
+ $this->slackRecord->setFormatter($formatter);
+
+ return $formatter;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php
new file mode 100644
index 00000000..d3352ea0
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php
@@ -0,0 +1,84 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Sends notifications through Slack's Slackbot
+ *
+ * @author Haralan Dobrev
+ * @see https://slack.com/apps/A0F81R8ET-slackbot
+ * @deprecated According to Slack the API used on this handler it is deprecated.
+ * Therefore this handler will be removed on 2.x
+ * Slack suggests to use webhooks instead. Please contact slack for more information.
+ */
+class SlackbotHandler extends AbstractProcessingHandler
+{
+ /**
+ * The slug of the Slack team
+ * @var string
+ */
+ private $slackTeam;
+
+ /**
+ * Slackbot token
+ * @var string
+ */
+ private $token;
+
+ /**
+ * Slack channel name
+ * @var string
+ */
+ private $channel;
+
+ /**
+ * @param string $slackTeam Slack team slug
+ * @param string $token Slackbot token
+ * @param string $channel Slack channel (encoded ID or name)
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true)
+ {
+ @trigger_error('SlackbotHandler is deprecated and will be removed on 2.x', E_USER_DEPRECATED);
+ parent::__construct($level, $bubble);
+
+ $this->slackTeam = $slackTeam;
+ $this->token = $token;
+ $this->channel = $channel;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @param array $record
+ */
+ protected function write(array $record)
+ {
+ $slackbotUrl = sprintf(
+ 'https://%s.slack.com/services/hooks/slackbot?token=%s&channel=%s',
+ $this->slackTeam,
+ $this->token,
+ $this->channel
+ );
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $slackbotUrl);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $record['message']);
+
+ Curl\Util::execute($ch);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php
new file mode 100644
index 00000000..db50d97f
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php
@@ -0,0 +1,385 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Stores to any socket - uses fsockopen() or pfsockopen().
+ *
+ * @author Pablo de Leon Belloc
+ * @see http://php.net/manual/en/function.fsockopen.php
+ */
+class SocketHandler extends AbstractProcessingHandler
+{
+ private $connectionString;
+ private $connectionTimeout;
+ private $resource;
+ private $timeout = 0;
+ private $writingTimeout = 10;
+ private $lastSentBytes = null;
+ private $chunkSize = null;
+ private $persistent = false;
+ private $errno;
+ private $errstr;
+ private $lastWritingAt;
+
+ /**
+ * @param string $connectionString Socket connection string
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+ $this->connectionString = $connectionString;
+ $this->connectionTimeout = (float) ini_get('default_socket_timeout');
+ }
+
+ /**
+ * Connect (if necessary) and write to the socket
+ *
+ * @param array $record
+ *
+ * @throws \UnexpectedValueException
+ * @throws \RuntimeException
+ */
+ protected function write(array $record)
+ {
+ $this->connectIfNotConnected();
+ $data = $this->generateDataStream($record);
+ $this->writeToSocket($data);
+ }
+
+ /**
+ * We will not close a PersistentSocket instance so it can be reused in other requests.
+ */
+ public function close()
+ {
+ if (!$this->isPersistent()) {
+ $this->closeSocket();
+ }
+ }
+
+ /**
+ * Close socket, if open
+ */
+ public function closeSocket()
+ {
+ if (is_resource($this->resource)) {
+ fclose($this->resource);
+ $this->resource = null;
+ }
+ }
+
+ /**
+ * Set socket connection to nbe persistent. It only has effect before the connection is initiated.
+ *
+ * @param bool $persistent
+ */
+ public function setPersistent($persistent)
+ {
+ $this->persistent = (bool) $persistent;
+ }
+
+ /**
+ * Set connection timeout. Only has effect before we connect.
+ *
+ * @param float $seconds
+ *
+ * @see http://php.net/manual/en/function.fsockopen.php
+ */
+ public function setConnectionTimeout($seconds)
+ {
+ $this->validateTimeout($seconds);
+ $this->connectionTimeout = (float) $seconds;
+ }
+
+ /**
+ * Set write timeout. Only has effect before we connect.
+ *
+ * @param float $seconds
+ *
+ * @see http://php.net/manual/en/function.stream-set-timeout.php
+ */
+ public function setTimeout($seconds)
+ {
+ $this->validateTimeout($seconds);
+ $this->timeout = (float) $seconds;
+ }
+
+ /**
+ * Set writing timeout. Only has effect during connection in the writing cycle.
+ *
+ * @param float $seconds 0 for no timeout
+ */
+ public function setWritingTimeout($seconds)
+ {
+ $this->validateTimeout($seconds);
+ $this->writingTimeout = (float) $seconds;
+ }
+
+ /**
+ * Set chunk size. Only has effect during connection in the writing cycle.
+ *
+ * @param float $bytes
+ */
+ public function setChunkSize($bytes)
+ {
+ $this->chunkSize = $bytes;
+ }
+
+ /**
+ * Get current connection string
+ *
+ * @return string
+ */
+ public function getConnectionString()
+ {
+ return $this->connectionString;
+ }
+
+ /**
+ * Get persistent setting
+ *
+ * @return bool
+ */
+ public function isPersistent()
+ {
+ return $this->persistent;
+ }
+
+ /**
+ * Get current connection timeout setting
+ *
+ * @return float
+ */
+ public function getConnectionTimeout()
+ {
+ return $this->connectionTimeout;
+ }
+
+ /**
+ * Get current in-transfer timeout
+ *
+ * @return float
+ */
+ public function getTimeout()
+ {
+ return $this->timeout;
+ }
+
+ /**
+ * Get current local writing timeout
+ *
+ * @return float
+ */
+ public function getWritingTimeout()
+ {
+ return $this->writingTimeout;
+ }
+
+ /**
+ * Get current chunk size
+ *
+ * @return float
+ */
+ public function getChunkSize()
+ {
+ return $this->chunkSize;
+ }
+
+ /**
+ * Check to see if the socket is currently available.
+ *
+ * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details.
+ *
+ * @return bool
+ */
+ public function isConnected()
+ {
+ return is_resource($this->resource)
+ && !feof($this->resource); // on TCP - other party can close connection.
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function pfsockopen()
+ {
+ return @pfsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function fsockopen()
+ {
+ return @fsockopen($this->connectionString, -1, $this->errno, $this->errstr, $this->connectionTimeout);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ *
+ * @see http://php.net/manual/en/function.stream-set-timeout.php
+ */
+ protected function streamSetTimeout()
+ {
+ $seconds = floor($this->timeout);
+ $microseconds = round(($this->timeout - $seconds) * 1e6);
+
+ return stream_set_timeout($this->resource, $seconds, $microseconds);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ *
+ * @see http://php.net/manual/en/function.stream-set-chunk-size.php
+ */
+ protected function streamSetChunkSize()
+ {
+ return stream_set_chunk_size($this->resource, $this->chunkSize);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function fwrite($data)
+ {
+ return @fwrite($this->resource, $data);
+ }
+
+ /**
+ * Wrapper to allow mocking
+ */
+ protected function streamGetMetadata()
+ {
+ return stream_get_meta_data($this->resource);
+ }
+
+ private function validateTimeout($value)
+ {
+ $ok = filter_var($value, FILTER_VALIDATE_FLOAT);
+ if ($ok === false || $value < 0) {
+ throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)");
+ }
+ }
+
+ private function connectIfNotConnected()
+ {
+ if ($this->isConnected()) {
+ return;
+ }
+ $this->connect();
+ }
+
+ protected function generateDataStream($record)
+ {
+ return (string) $record['formatted'];
+ }
+
+ /**
+ * @return resource|null
+ */
+ protected function getResource()
+ {
+ return $this->resource;
+ }
+
+ private function connect()
+ {
+ $this->createSocketResource();
+ $this->setSocketTimeout();
+ $this->setStreamChunkSize();
+ }
+
+ private function createSocketResource()
+ {
+ if ($this->isPersistent()) {
+ $resource = $this->pfsockopen();
+ } else {
+ $resource = $this->fsockopen();
+ }
+ if (!$resource) {
+ throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)");
+ }
+ $this->resource = $resource;
+ }
+
+ private function setSocketTimeout()
+ {
+ if (!$this->streamSetTimeout()) {
+ throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()");
+ }
+ }
+
+ private function setStreamChunkSize()
+ {
+ if ($this->chunkSize && !$this->streamSetChunkSize()) {
+ throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()");
+ }
+ }
+
+ private function writeToSocket($data)
+ {
+ $length = strlen($data);
+ $sent = 0;
+ $this->lastSentBytes = $sent;
+ while ($this->isConnected() && $sent < $length) {
+ if (0 == $sent) {
+ $chunk = $this->fwrite($data);
+ } else {
+ $chunk = $this->fwrite(substr($data, $sent));
+ }
+ if ($chunk === false) {
+ throw new \RuntimeException("Could not write to socket");
+ }
+ $sent += $chunk;
+ $socketInfo = $this->streamGetMetadata();
+ if ($socketInfo['timed_out']) {
+ throw new \RuntimeException("Write timed-out");
+ }
+
+ if ($this->writingIsTimedOut($sent)) {
+ throw new \RuntimeException("Write timed-out, no data sent for `{$this->writingTimeout}` seconds, probably we got disconnected (sent $sent of $length)");
+ }
+ }
+ if (!$this->isConnected() && $sent < $length) {
+ throw new \RuntimeException("End-of-file reached, probably we got disconnected (sent $sent of $length)");
+ }
+ }
+
+ private function writingIsTimedOut($sent)
+ {
+ $writingTimeout = (int) floor($this->writingTimeout);
+ if (0 === $writingTimeout) {
+ return false;
+ }
+
+ if ($sent !== $this->lastSentBytes) {
+ $this->lastWritingAt = time();
+ $this->lastSentBytes = $sent;
+
+ return false;
+ } else {
+ usleep(100);
+ }
+
+ if ((time() - $this->lastWritingAt) >= $writingTimeout) {
+ $this->closeSocket();
+
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php
new file mode 100644
index 00000000..27d90e06
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php
@@ -0,0 +1,177 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Stores to any stream resource
+ *
+ * Can be used to store into php://stderr, remote and local files, etc.
+ *
+ * @author Jordi Boggiano
+ */
+class StreamHandler extends AbstractProcessingHandler
+{
+ protected $stream;
+ protected $url;
+ private $errorMessage;
+ protected $filePermission;
+ protected $useLocking;
+ private $dirCreated;
+
+ /**
+ * @param resource|string $stream
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
+ * @param bool $useLocking Try to lock log file before doing any writes
+ *
+ * @throws \Exception If a missing directory is not buildable
+ * @throws \InvalidArgumentException If stream is not a resource or string
+ */
+ public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
+ {
+ parent::__construct($level, $bubble);
+ if (is_resource($stream)) {
+ $this->stream = $stream;
+ } elseif (is_string($stream)) {
+ $this->url = $stream;
+ } else {
+ throw new \InvalidArgumentException('A stream must either be a resource or a string.');
+ }
+
+ $this->filePermission = $filePermission;
+ $this->useLocking = $useLocking;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ if ($this->url && is_resource($this->stream)) {
+ fclose($this->stream);
+ }
+ $this->stream = null;
+ $this->dirCreated = null;
+ }
+
+ /**
+ * Return the currently active stream if it is open
+ *
+ * @return resource|null
+ */
+ public function getStream()
+ {
+ return $this->stream;
+ }
+
+ /**
+ * Return the stream URL if it was configured with a URL and not an active resource
+ *
+ * @return string|null
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if (!is_resource($this->stream)) {
+ if (null === $this->url || '' === $this->url) {
+ throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
+ }
+ $this->createDir();
+ $this->errorMessage = null;
+ set_error_handler(array($this, 'customErrorHandler'));
+ $this->stream = fopen($this->url, 'a');
+ if ($this->filePermission !== null) {
+ @chmod($this->url, $this->filePermission);
+ }
+ restore_error_handler();
+ if (!is_resource($this->stream)) {
+ $this->stream = null;
+ throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: '.$this->errorMessage, $this->url));
+ }
+ }
+
+ if ($this->useLocking) {
+ // ignoring errors here, there's not much we can do about them
+ flock($this->stream, LOCK_EX);
+ }
+
+ $this->streamWrite($this->stream, $record);
+
+ if ($this->useLocking) {
+ flock($this->stream, LOCK_UN);
+ }
+ }
+
+ /**
+ * Write to stream
+ * @param resource $stream
+ * @param array $record
+ */
+ protected function streamWrite($stream, array $record)
+ {
+ fwrite($stream, (string) $record['formatted']);
+ }
+
+ private function customErrorHandler($code, $msg)
+ {
+ $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
+ }
+
+ /**
+ * @param string $stream
+ *
+ * @return null|string
+ */
+ private function getDirFromStream($stream)
+ {
+ $pos = strpos($stream, '://');
+ if ($pos === false) {
+ return dirname($stream);
+ }
+
+ if ('file://' === substr($stream, 0, 7)) {
+ return dirname(substr($stream, 7));
+ }
+
+ return;
+ }
+
+ private function createDir()
+ {
+ // Do not try to create dir if it has already been tried.
+ if ($this->dirCreated) {
+ return;
+ }
+
+ $dir = $this->getDirFromStream($this->url);
+ if (null !== $dir && !is_dir($dir)) {
+ $this->errorMessage = null;
+ set_error_handler(array($this, 'customErrorHandler'));
+ $status = mkdir($dir, 0777, true);
+ restore_error_handler();
+ if (false === $status && !is_dir($dir)) {
+ throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir));
+ }
+ }
+ $this->dirCreated = true;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php
new file mode 100644
index 00000000..ac7b16ff
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php
@@ -0,0 +1,111 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Formatter\LineFormatter;
+use Swift;
+
+/**
+ * SwiftMailerHandler uses Swift_Mailer to send the emails
+ *
+ * @author Gyula Sallai
+ */
+class SwiftMailerHandler extends MailHandler
+{
+ protected $mailer;
+ private $messageTemplate;
+
+ /**
+ * @param \Swift_Mailer $mailer The mailer to use
+ * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ */
+ public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true)
+ {
+ parent::__construct($level, $bubble);
+
+ $this->mailer = $mailer;
+ $this->messageTemplate = $message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function send($content, array $records)
+ {
+ $this->mailer->send($this->buildMessage($content, $records));
+ }
+
+ /**
+ * Gets the formatter for the Swift_Message subject.
+ *
+ * @param string $format The format of the subject
+ * @return FormatterInterface
+ */
+ protected function getSubjectFormatter($format)
+ {
+ return new LineFormatter($format);
+ }
+
+ /**
+ * Creates instance of Swift_Message to be sent
+ *
+ * @param string $content formatted email body to be sent
+ * @param array $records Log records that formed the content
+ * @return \Swift_Message
+ */
+ protected function buildMessage($content, array $records)
+ {
+ $message = null;
+ if ($this->messageTemplate instanceof \Swift_Message) {
+ $message = clone $this->messageTemplate;
+ $message->generateId();
+ } elseif (is_callable($this->messageTemplate)) {
+ $message = call_user_func($this->messageTemplate, $content, $records);
+ }
+
+ if (!$message instanceof \Swift_Message) {
+ throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it');
+ }
+
+ if ($records) {
+ $subjectFormatter = $this->getSubjectFormatter($message->getSubject());
+ $message->setSubject($subjectFormatter->format($this->getHighestRecord($records)));
+ }
+
+ $message->setBody($content);
+ if (version_compare(Swift::VERSION, '6.0.0', '>=')) {
+ $message->setDate(new \DateTimeImmutable());
+ } else {
+ $message->setDate(time());
+ }
+
+ return $message;
+ }
+
+ /**
+ * BC getter, to be removed in 2.0
+ */
+ public function __get($name)
+ {
+ if ($name === 'message') {
+ trigger_error('SwiftMailerHandler->message is deprecated, use ->buildMessage() instead to retrieve the message', E_USER_DEPRECATED);
+
+ return $this->buildMessage(null, array());
+ }
+
+ throw new \InvalidArgumentException('Invalid property '.$name);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php
new file mode 100644
index 00000000..f770c802
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+
+/**
+ * Logs to syslog service.
+ *
+ * usage example:
+ *
+ * $log = new Logger('application');
+ * $syslog = new SyslogHandler('myfacility', 'local6');
+ * $formatter = new LineFormatter("%channel%.%level_name%: %message% %extra%");
+ * $syslog->setFormatter($formatter);
+ * $log->pushHandler($syslog);
+ *
+ * @author Sven Paulus
+ */
+class SyslogHandler extends AbstractSyslogHandler
+{
+ protected $ident;
+ protected $logopts;
+
+ /**
+ * @param string $ident
+ * @param mixed $facility
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID
+ */
+ public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID)
+ {
+ parent::__construct($facility, $level, $bubble);
+
+ $this->ident = $ident;
+ $this->logopts = $logopts;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ closelog();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ if (!openlog($this->ident, $this->logopts, $this->facility)) {
+ throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"');
+ }
+ syslog($this->logLevels[$record['level']], (string) $record['formatted']);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php
new file mode 100644
index 00000000..3bff085b
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler\SyslogUdp;
+
+class UdpSocket
+{
+ const DATAGRAM_MAX_LENGTH = 65023;
+
+ protected $ip;
+ protected $port;
+ protected $socket;
+
+ public function __construct($ip, $port = 514)
+ {
+ $this->ip = $ip;
+ $this->port = $port;
+ $this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+ }
+
+ public function write($line, $header = "")
+ {
+ $this->send($this->assembleMessage($line, $header));
+ }
+
+ public function close()
+ {
+ if (is_resource($this->socket)) {
+ socket_close($this->socket);
+ $this->socket = null;
+ }
+ }
+
+ protected function send($chunk)
+ {
+ if (!is_resource($this->socket)) {
+ throw new \LogicException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore');
+ }
+ socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port);
+ }
+
+ protected function assembleMessage($line, $header)
+ {
+ $chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header);
+
+ return $header . substr($line, 0, $chunkSize);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php
new file mode 100644
index 00000000..4dfd5f5e
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php
@@ -0,0 +1,124 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Logger;
+use Monolog\Handler\SyslogUdp\UdpSocket;
+
+/**
+ * A Handler for logging to a remote syslogd server.
+ *
+ * @author Jesper Skovgaard Nielsen
+ * @author Dominik Kukacka
+ */
+class SyslogUdpHandler extends AbstractSyslogHandler
+{
+ const RFC3164 = 0;
+ const RFC5424 = 1;
+
+ private $dateFormats = array(
+ self::RFC3164 => 'M d H:i:s',
+ self::RFC5424 => \DateTime::RFC3339,
+ );
+
+ protected $socket;
+ protected $ident;
+ protected $rfc;
+
+ /**
+ * @param string $host
+ * @param int $port
+ * @param mixed $facility
+ * @param int $level The minimum logging level at which this handler will be triggered
+ * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
+ * @param string $ident Program name or tag for each log message.
+ * @param int $rfc RFC to format the message for.
+ */
+ public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php', $rfc = self::RFC5424)
+ {
+ parent::__construct($facility, $level, $bubble);
+
+ $this->ident = $ident;
+ $this->rfc = $rfc;
+
+ $this->socket = new UdpSocket($host, $port ?: 514);
+ }
+
+ protected function write(array $record)
+ {
+ $lines = $this->splitMessageIntoLines($record['formatted']);
+
+ $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']]);
+
+ foreach ($lines as $line) {
+ $this->socket->write($line, $header);
+ }
+ }
+
+ public function close()
+ {
+ $this->socket->close();
+ }
+
+ private function splitMessageIntoLines($message)
+ {
+ if (is_array($message)) {
+ $message = implode("\n", $message);
+ }
+
+ return preg_split('/$\R?^/m', $message, -1, PREG_SPLIT_NO_EMPTY);
+ }
+
+ /**
+ * Make common syslog header (see rfc5424 or rfc3164)
+ */
+ protected function makeCommonSyslogHeader($severity)
+ {
+ $priority = $severity + $this->facility;
+
+ if (!$pid = getmypid()) {
+ $pid = '-';
+ }
+
+ if (!$hostname = gethostname()) {
+ $hostname = '-';
+ }
+
+ $date = $this->getDateTime();
+
+ if ($this->rfc === self::RFC3164) {
+ return "<$priority>" .
+ $date . " " .
+ $hostname . " " .
+ $this->ident . "[" . $pid . "]: ";
+ } else {
+ return "<$priority>1 " .
+ $date . " " .
+ $hostname . " " .
+ $this->ident . " " .
+ $pid . " - - ";
+ }
+ }
+
+ protected function getDateTime()
+ {
+ return date($this->dateFormats[$this->rfc]);
+ }
+
+ /**
+ * Inject your own socket, mainly used for testing
+ */
+ public function setSocket($socket)
+ {
+ $this->socket = $socket;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php
new file mode 100644
index 00000000..478db0ac
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php
@@ -0,0 +1,177 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Used for testing purposes.
+ *
+ * It records all records and gives you access to them for verification.
+ *
+ * @author Jordi Boggiano
+ *
+ * @method bool hasEmergency($record)
+ * @method bool hasAlert($record)
+ * @method bool hasCritical($record)
+ * @method bool hasError($record)
+ * @method bool hasWarning($record)
+ * @method bool hasNotice($record)
+ * @method bool hasInfo($record)
+ * @method bool hasDebug($record)
+ *
+ * @method bool hasEmergencyRecords()
+ * @method bool hasAlertRecords()
+ * @method bool hasCriticalRecords()
+ * @method bool hasErrorRecords()
+ * @method bool hasWarningRecords()
+ * @method bool hasNoticeRecords()
+ * @method bool hasInfoRecords()
+ * @method bool hasDebugRecords()
+ *
+ * @method bool hasEmergencyThatContains($message)
+ * @method bool hasAlertThatContains($message)
+ * @method bool hasCriticalThatContains($message)
+ * @method bool hasErrorThatContains($message)
+ * @method bool hasWarningThatContains($message)
+ * @method bool hasNoticeThatContains($message)
+ * @method bool hasInfoThatContains($message)
+ * @method bool hasDebugThatContains($message)
+ *
+ * @method bool hasEmergencyThatMatches($message)
+ * @method bool hasAlertThatMatches($message)
+ * @method bool hasCriticalThatMatches($message)
+ * @method bool hasErrorThatMatches($message)
+ * @method bool hasWarningThatMatches($message)
+ * @method bool hasNoticeThatMatches($message)
+ * @method bool hasInfoThatMatches($message)
+ * @method bool hasDebugThatMatches($message)
+ *
+ * @method bool hasEmergencyThatPasses($message)
+ * @method bool hasAlertThatPasses($message)
+ * @method bool hasCriticalThatPasses($message)
+ * @method bool hasErrorThatPasses($message)
+ * @method bool hasWarningThatPasses($message)
+ * @method bool hasNoticeThatPasses($message)
+ * @method bool hasInfoThatPasses($message)
+ * @method bool hasDebugThatPasses($message)
+ */
+class TestHandler extends AbstractProcessingHandler
+{
+ protected $records = array();
+ protected $recordsByLevel = array();
+ private $skipReset = false;
+
+ public function getRecords()
+ {
+ return $this->records;
+ }
+
+ public function clear()
+ {
+ $this->records = array();
+ $this->recordsByLevel = array();
+ }
+
+ public function reset()
+ {
+ if (!$this->skipReset) {
+ $this->clear();
+ }
+ }
+
+ public function setSkipReset($skipReset)
+ {
+ $this->skipReset = $skipReset;
+ }
+
+ public function hasRecords($level)
+ {
+ return isset($this->recordsByLevel[$level]);
+ }
+
+ /**
+ * @param string|array $record Either a message string or an array containing message and optionally context keys that will be checked against all records
+ * @param int $level Logger::LEVEL constant value
+ */
+ public function hasRecord($record, $level)
+ {
+ if (is_string($record)) {
+ $record = array('message' => $record);
+ }
+
+ return $this->hasRecordThatPasses(function ($rec) use ($record) {
+ if ($rec['message'] !== $record['message']) {
+ return false;
+ }
+ if (isset($record['context']) && $rec['context'] !== $record['context']) {
+ return false;
+ }
+ return true;
+ }, $level);
+ }
+
+ public function hasRecordThatContains($message, $level)
+ {
+ return $this->hasRecordThatPasses(function ($rec) use ($message) {
+ return strpos($rec['message'], $message) !== false;
+ }, $level);
+ }
+
+ public function hasRecordThatMatches($regex, $level)
+ {
+ return $this->hasRecordThatPasses(function ($rec) use ($regex) {
+ return preg_match($regex, $rec['message']) > 0;
+ }, $level);
+ }
+
+ public function hasRecordThatPasses($predicate, $level)
+ {
+ if (!is_callable($predicate)) {
+ throw new \InvalidArgumentException("Expected a callable for hasRecordThatSucceeds");
+ }
+
+ if (!isset($this->recordsByLevel[$level])) {
+ return false;
+ }
+
+ foreach ($this->recordsByLevel[$level] as $i => $rec) {
+ if (call_user_func($predicate, $rec, $i)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->recordsByLevel[$record['level']][] = $record;
+ $this->records[] = $record;
+ }
+
+ public function __call($method, $args)
+ {
+ if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
+ $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
+ $level = constant('Monolog\Logger::' . strtoupper($matches[2]));
+ if (method_exists($this, $genericMethod)) {
+ $args[] = $level;
+
+ return call_user_func_array(array($this, $genericMethod), $args);
+ }
+ }
+
+ throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php
new file mode 100644
index 00000000..7d7622a3
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+/**
+ * Forwards records to multiple handlers suppressing failures of each handler
+ * and continuing through to give every handler a chance to succeed.
+ *
+ * @author Craig D'Amelio
+ */
+class WhatFailureGroupHandler extends GroupHandler
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function handle(array $record)
+ {
+ if ($this->processors) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ }
+
+ foreach ($this->handlers as $handler) {
+ try {
+ $handler->handle($record);
+ } catch (\Exception $e) {
+ // What failure?
+ } catch (\Throwable $e) {
+ // What failure?
+ }
+ }
+
+ return false === $this->bubble;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleBatch(array $records)
+ {
+ if ($this->processors) {
+ $processed = array();
+ foreach ($records as $record) {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+ $processed[] = $record;
+ }
+ $records = $processed;
+ }
+
+ foreach ($this->handlers as $handler) {
+ try {
+ $handler->handleBatch($records);
+ } catch (\Exception $e) {
+ // What failure?
+ } catch (\Throwable $e) {
+ // What failure?
+ }
+ }
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php
new file mode 100644
index 00000000..a20aeae0
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php
@@ -0,0 +1,101 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Handler;
+
+use Monolog\Formatter\NormalizerFormatter;
+use Monolog\Logger;
+
+/**
+ * Handler sending logs to Zend Monitor
+ *
+ * @author Christian Bergau
+ * @author Jason Davis
+ */
+class ZendMonitorHandler extends AbstractProcessingHandler
+{
+ /**
+ * Monolog level / ZendMonitor Custom Event priority map
+ *
+ * @var array
+ */
+ protected $levelMap = array();
+
+ /**
+ * Construct
+ *
+ * @param int $level
+ * @param bool $bubble
+ * @throws MissingExtensionException
+ */
+ public function __construct($level = Logger::DEBUG, $bubble = true)
+ {
+ if (!function_exists('zend_monitor_custom_event')) {
+ throw new MissingExtensionException(
+ 'You must have Zend Server installed with Zend Monitor enabled in order to use this handler'
+ );
+ }
+ //zend monitor constants are not defined if zend monitor is not enabled.
+ $this->levelMap = array(
+ Logger::DEBUG => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+ Logger::INFO => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+ Logger::NOTICE => \ZEND_MONITOR_EVENT_SEVERITY_INFO,
+ Logger::WARNING => \ZEND_MONITOR_EVENT_SEVERITY_WARNING,
+ Logger::ERROR => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+ Logger::CRITICAL => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+ Logger::ALERT => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+ Logger::EMERGENCY => \ZEND_MONITOR_EVENT_SEVERITY_ERROR,
+ );
+ parent::__construct($level, $bubble);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function write(array $record)
+ {
+ $this->writeZendMonitorCustomEvent(
+ Logger::getLevelName($record['level']),
+ $record['message'],
+ $record['formatted'],
+ $this->levelMap[$record['level']]
+ );
+ }
+
+ /**
+ * Write to Zend Monitor Events
+ * @param string $type Text displayed in "Class Name (custom)" field
+ * @param string $message Text displayed in "Error String"
+ * @param mixed $formatted Displayed in Custom Variables tab
+ * @param int $severity Set the event severity level (-1,0,1)
+ */
+ protected function writeZendMonitorCustomEvent($type, $message, $formatted, $severity)
+ {
+ zend_monitor_custom_event($type, $message, $formatted, $severity);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefaultFormatter()
+ {
+ return new NormalizerFormatter();
+ }
+
+ /**
+ * Get the level map
+ *
+ * @return array
+ */
+ public function getLevelMap()
+ {
+ return $this->levelMap;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Logger.php b/akamai/vendor/monolog/monolog/src/Monolog/Logger.php
new file mode 100644
index 00000000..05dfc817
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Logger.php
@@ -0,0 +1,791 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Monolog\Handler\HandlerInterface;
+use Monolog\Handler\StreamHandler;
+use Psr\Log\LoggerInterface;
+use Psr\Log\InvalidArgumentException;
+use Exception;
+
+/**
+ * Monolog log channel
+ *
+ * It contains a stack of Handlers and a stack of Processors,
+ * and uses them to store records that are added to it.
+ *
+ * @author Jordi Boggiano
+ */
+class Logger implements LoggerInterface, ResettableInterface
+{
+ /**
+ * Detailed debug information
+ */
+ const DEBUG = 100;
+
+ /**
+ * Interesting events
+ *
+ * Examples: User logs in, SQL logs.
+ */
+ const INFO = 200;
+
+ /**
+ * Uncommon events
+ */
+ const NOTICE = 250;
+
+ /**
+ * Exceptional occurrences that are not errors
+ *
+ * Examples: Use of deprecated APIs, poor use of an API,
+ * undesirable things that are not necessarily wrong.
+ */
+ const WARNING = 300;
+
+ /**
+ * Runtime errors
+ */
+ const ERROR = 400;
+
+ /**
+ * Critical conditions
+ *
+ * Example: Application component unavailable, unexpected exception.
+ */
+ const CRITICAL = 500;
+
+ /**
+ * Action must be taken immediately
+ *
+ * Example: Entire website down, database unavailable, etc.
+ * This should trigger the SMS alerts and wake you up.
+ */
+ const ALERT = 550;
+
+ /**
+ * Urgent alert.
+ */
+ const EMERGENCY = 600;
+
+ /**
+ * Monolog API version
+ *
+ * This is only bumped when API breaks are done and should
+ * follow the major version of the library
+ *
+ * @var int
+ */
+ const API = 1;
+
+ /**
+ * Logging levels from syslog protocol defined in RFC 5424
+ *
+ * @var array $levels Logging levels
+ */
+ protected static $levels = array(
+ self::DEBUG => 'DEBUG',
+ self::INFO => 'INFO',
+ self::NOTICE => 'NOTICE',
+ self::WARNING => 'WARNING',
+ self::ERROR => 'ERROR',
+ self::CRITICAL => 'CRITICAL',
+ self::ALERT => 'ALERT',
+ self::EMERGENCY => 'EMERGENCY',
+ );
+
+ /**
+ * @var \DateTimeZone
+ */
+ protected static $timezone;
+
+ /**
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * The handler stack
+ *
+ * @var HandlerInterface[]
+ */
+ protected $handlers;
+
+ /**
+ * Processors that will process all log records
+ *
+ * To process records of a single handler instead, add the processor on that specific handler
+ *
+ * @var callable[]
+ */
+ protected $processors;
+
+ /**
+ * @var bool
+ */
+ protected $microsecondTimestamps = true;
+
+ /**
+ * @var callable
+ */
+ protected $exceptionHandler;
+
+ /**
+ * @param string $name The logging channel
+ * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
+ * @param callable[] $processors Optional array of processors
+ */
+ public function __construct($name, array $handlers = array(), array $processors = array())
+ {
+ $this->name = $name;
+ $this->setHandlers($handlers);
+ $this->processors = $processors;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Return a new cloned instance with the name changed
+ *
+ * @return static
+ */
+ public function withName($name)
+ {
+ $new = clone $this;
+ $new->name = $name;
+
+ return $new;
+ }
+
+ /**
+ * Pushes a handler on to the stack.
+ *
+ * @param HandlerInterface $handler
+ * @return $this
+ */
+ public function pushHandler(HandlerInterface $handler)
+ {
+ array_unshift($this->handlers, $handler);
+
+ return $this;
+ }
+
+ /**
+ * Pops a handler from the stack
+ *
+ * @return HandlerInterface
+ */
+ public function popHandler()
+ {
+ if (!$this->handlers) {
+ throw new \LogicException('You tried to pop from an empty handler stack.');
+ }
+
+ return array_shift($this->handlers);
+ }
+
+ /**
+ * Set handlers, replacing all existing ones.
+ *
+ * If a map is passed, keys will be ignored.
+ *
+ * @param HandlerInterface[] $handlers
+ * @return $this
+ */
+ public function setHandlers(array $handlers)
+ {
+ $this->handlers = array();
+ foreach (array_reverse($handlers) as $handler) {
+ $this->pushHandler($handler);
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return HandlerInterface[]
+ */
+ public function getHandlers()
+ {
+ return $this->handlers;
+ }
+
+ /**
+ * Adds a processor on to the stack.
+ *
+ * @param callable $callback
+ * @return $this
+ */
+ public function pushProcessor($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
+ }
+ array_unshift($this->processors, $callback);
+
+ return $this;
+ }
+
+ /**
+ * Removes the processor on top of the stack and returns it.
+ *
+ * @return callable
+ */
+ public function popProcessor()
+ {
+ if (!$this->processors) {
+ throw new \LogicException('You tried to pop from an empty processor stack.');
+ }
+
+ return array_shift($this->processors);
+ }
+
+ /**
+ * @return callable[]
+ */
+ public function getProcessors()
+ {
+ return $this->processors;
+ }
+
+ /**
+ * Control the use of microsecond resolution timestamps in the 'datetime'
+ * member of new records.
+ *
+ * Generating microsecond resolution timestamps by calling
+ * microtime(true), formatting the result via sprintf() and then parsing
+ * the resulting string via \DateTime::createFromFormat() can incur
+ * a measurable runtime overhead vs simple usage of DateTime to capture
+ * a second resolution timestamp in systems which generate a large number
+ * of log events.
+ *
+ * @param bool $micro True to use microtime() to create timestamps
+ */
+ public function useMicrosecondTimestamps($micro)
+ {
+ $this->microsecondTimestamps = (bool) $micro;
+ }
+
+ /**
+ * Adds a log record.
+ *
+ * @param int $level The logging level
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addRecord($level, $message, array $context = array())
+ {
+ if (!$this->handlers) {
+ $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG));
+ }
+
+ $levelName = static::getLevelName($level);
+
+ // check if any handler will handle this message so we can return early and save cycles
+ $handlerKey = null;
+ reset($this->handlers);
+ while ($handler = current($this->handlers)) {
+ if ($handler->isHandling(array('level' => $level))) {
+ $handlerKey = key($this->handlers);
+ break;
+ }
+
+ next($this->handlers);
+ }
+
+ if (null === $handlerKey) {
+ return false;
+ }
+
+ if (!static::$timezone) {
+ static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC');
+ }
+
+ // php7.1+ always has microseconds enabled, so we do not need this hack
+ if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) {
+ $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
+ } else {
+ $ts = new \DateTime(null, static::$timezone);
+ }
+ $ts->setTimezone(static::$timezone);
+
+ $record = array(
+ 'message' => (string) $message,
+ 'context' => $context,
+ 'level' => $level,
+ 'level_name' => $levelName,
+ 'channel' => $this->name,
+ 'datetime' => $ts,
+ 'extra' => array(),
+ );
+
+ try {
+ foreach ($this->processors as $processor) {
+ $record = call_user_func($processor, $record);
+ }
+
+ while ($handler = current($this->handlers)) {
+ if (true === $handler->handle($record)) {
+ break;
+ }
+
+ next($this->handlers);
+ }
+ } catch (Exception $e) {
+ $this->handleException($e, $record);
+ }
+
+ return true;
+ }
+
+ /**
+ * Ends a log cycle and frees all resources used by handlers.
+ *
+ * Closing a Handler means flushing all buffers and freeing any open resources/handles.
+ * Handlers that have been closed should be able to accept log records again and re-open
+ * themselves on demand, but this may not always be possible depending on implementation.
+ *
+ * This is useful at the end of a request and will be called automatically on every handler
+ * when they get destructed.
+ */
+ public function close()
+ {
+ foreach ($this->handlers as $handler) {
+ if (method_exists($handler, 'close')) {
+ $handler->close();
+ }
+ }
+ }
+
+ /**
+ * Ends a log cycle and resets all handlers and processors to their initial state.
+ *
+ * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal
+ * state, and getting it back to a state in which it can receive log records again.
+ *
+ * This is useful in case you want to avoid logs leaking between two requests or jobs when you
+ * have a long running process like a worker or an application server serving multiple requests
+ * in one process.
+ */
+ public function reset()
+ {
+ foreach ($this->handlers as $handler) {
+ if ($handler instanceof ResettableInterface) {
+ $handler->reset();
+ }
+ }
+
+ foreach ($this->processors as $processor) {
+ if ($processor instanceof ResettableInterface) {
+ $processor->reset();
+ }
+ }
+ }
+
+ /**
+ * Adds a log record at the DEBUG level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addDebug($message, array $context = array())
+ {
+ return $this->addRecord(static::DEBUG, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the INFO level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addInfo($message, array $context = array())
+ {
+ return $this->addRecord(static::INFO, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the NOTICE level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addNotice($message, array $context = array())
+ {
+ return $this->addRecord(static::NOTICE, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the WARNING level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addWarning($message, array $context = array())
+ {
+ return $this->addRecord(static::WARNING, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ERROR level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addError($message, array $context = array())
+ {
+ return $this->addRecord(static::ERROR, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the CRITICAL level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addCritical($message, array $context = array())
+ {
+ return $this->addRecord(static::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ALERT level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addAlert($message, array $context = array())
+ {
+ return $this->addRecord(static::ALERT, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the EMERGENCY level.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function addEmergency($message, array $context = array())
+ {
+ return $this->addRecord(static::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Gets all supported logging levels.
+ *
+ * @return array Assoc array with human-readable level names => level codes.
+ */
+ public static function getLevels()
+ {
+ return array_flip(static::$levels);
+ }
+
+ /**
+ * Gets the name of the logging level.
+ *
+ * @param int $level
+ * @return string
+ */
+ public static function getLevelName($level)
+ {
+ if (!isset(static::$levels[$level])) {
+ throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels)));
+ }
+
+ return static::$levels[$level];
+ }
+
+ /**
+ * Converts PSR-3 levels to Monolog ones if necessary
+ *
+ * @param string|int Level number (monolog) or name (PSR-3)
+ * @return int
+ */
+ public static function toMonologLevel($level)
+ {
+ if (is_string($level) && defined(__CLASS__.'::'.strtoupper($level))) {
+ return constant(__CLASS__.'::'.strtoupper($level));
+ }
+
+ return $level;
+ }
+
+ /**
+ * Checks whether the Logger has a handler that listens on the given level
+ *
+ * @param int $level
+ * @return bool
+ */
+ public function isHandling($level)
+ {
+ $record = array(
+ 'level' => $level,
+ );
+
+ foreach ($this->handlers as $handler) {
+ if ($handler->isHandling($record)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Set a custom exception handler
+ *
+ * @param callable $callback
+ * @return $this
+ */
+ public function setExceptionHandler($callback)
+ {
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException('Exception handler must be valid callable (callback or object with an __invoke method), '.var_export($callback, true).' given');
+ }
+ $this->exceptionHandler = $callback;
+
+ return $this;
+ }
+
+ /**
+ * @return callable
+ */
+ public function getExceptionHandler()
+ {
+ return $this->exceptionHandler;
+ }
+
+ /**
+ * Delegates exception management to the custom exception handler,
+ * or throws the exception if no custom handler is set.
+ */
+ protected function handleException(Exception $e, array $record)
+ {
+ if (!$this->exceptionHandler) {
+ throw $e;
+ }
+
+ call_user_func($this->exceptionHandler, $e, $record);
+ }
+
+ /**
+ * Adds a log record at an arbitrary level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param mixed $level The log level
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function log($level, $message, array $context = array())
+ {
+ $level = static::toMonologLevel($level);
+
+ return $this->addRecord($level, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the DEBUG level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function debug($message, array $context = array())
+ {
+ return $this->addRecord(static::DEBUG, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the INFO level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function info($message, array $context = array())
+ {
+ return $this->addRecord(static::INFO, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the NOTICE level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function notice($message, array $context = array())
+ {
+ return $this->addRecord(static::NOTICE, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the WARNING level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function warn($message, array $context = array())
+ {
+ return $this->addRecord(static::WARNING, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the WARNING level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function warning($message, array $context = array())
+ {
+ return $this->addRecord(static::WARNING, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ERROR level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function err($message, array $context = array())
+ {
+ return $this->addRecord(static::ERROR, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ERROR level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function error($message, array $context = array())
+ {
+ return $this->addRecord(static::ERROR, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the CRITICAL level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function crit($message, array $context = array())
+ {
+ return $this->addRecord(static::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the CRITICAL level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function critical($message, array $context = array())
+ {
+ return $this->addRecord(static::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the ALERT level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function alert($message, array $context = array())
+ {
+ return $this->addRecord(static::ALERT, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the EMERGENCY level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function emerg($message, array $context = array())
+ {
+ return $this->addRecord(static::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Adds a log record at the EMERGENCY level.
+ *
+ * This method allows for compatibility with common interfaces.
+ *
+ * @param string $message The log message
+ * @param array $context The log context
+ * @return bool Whether the record has been processed
+ */
+ public function emergency($message, array $context = array())
+ {
+ return $this->addRecord(static::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Set the timezone to be used for the timestamp of log records.
+ *
+ * This is stored globally for all Logger instances
+ *
+ * @param \DateTimeZone $tz Timezone object
+ */
+ public static function setTimezone(\DateTimeZone $tz)
+ {
+ self::$timezone = $tz;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php
new file mode 100644
index 00000000..9fc3f50f
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects Git branch and Git commit SHA in all records
+ *
+ * @author Nick Otter
+ * @author Jordi Boggiano
+ */
+class GitProcessor implements ProcessorInterface
+{
+ private $level;
+ private static $cache;
+
+ public function __construct($level = Logger::DEBUG)
+ {
+ $this->level = Logger::toMonologLevel($level);
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // return if the level is not high enough
+ if ($record['level'] < $this->level) {
+ return $record;
+ }
+
+ $record['extra']['git'] = self::getGitInfo();
+
+ return $record;
+ }
+
+ private static function getGitInfo()
+ {
+ if (self::$cache) {
+ return self::$cache;
+ }
+
+ $branches = `git branch -v --no-abbrev`;
+ if (preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) {
+ return self::$cache = array(
+ 'branch' => $matches[1],
+ 'commit' => $matches[2],
+ );
+ }
+
+ return self::$cache = array();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php
new file mode 100644
index 00000000..6ae192a2
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php
@@ -0,0 +1,112 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects line/file:class/function where the log message came from
+ *
+ * Warning: This only works if the handler processes the logs directly.
+ * If you put the processor on a handler that is behind a FingersCrossedHandler
+ * for example, the processor will only be called once the trigger level is reached,
+ * and all the log records will have the same file/line/.. data from the call that
+ * triggered the FingersCrossedHandler.
+ *
+ * @author Jordi Boggiano
+ */
+class IntrospectionProcessor implements ProcessorInterface
+{
+ private $level;
+
+ private $skipClassesPartials;
+
+ private $skipStackFramesCount;
+
+ private $skipFunctions = array(
+ 'call_user_func',
+ 'call_user_func_array',
+ );
+
+ public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array(), $skipStackFramesCount = 0)
+ {
+ $this->level = Logger::toMonologLevel($level);
+ $this->skipClassesPartials = array_merge(array('Monolog\\'), $skipClassesPartials);
+ $this->skipStackFramesCount = $skipStackFramesCount;
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // return if the level is not high enough
+ if ($record['level'] < $this->level) {
+ return $record;
+ }
+
+ /*
+ * http://php.net/manual/en/function.debug-backtrace.php
+ * As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added.
+ * Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'.
+ */
+ $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS);
+
+ // skip first since it's always the current method
+ array_shift($trace);
+ // the call_user_func call is also skipped
+ array_shift($trace);
+
+ $i = 0;
+
+ while ($this->isTraceClassOrSkippedFunction($trace, $i)) {
+ if (isset($trace[$i]['class'])) {
+ foreach ($this->skipClassesPartials as $part) {
+ if (strpos($trace[$i]['class'], $part) !== false) {
+ $i++;
+ continue 2;
+ }
+ }
+ } elseif (in_array($trace[$i]['function'], $this->skipFunctions)) {
+ $i++;
+ continue;
+ }
+
+ break;
+ }
+
+ $i += $this->skipStackFramesCount;
+
+ // we should have the call source now
+ $record['extra'] = array_merge(
+ $record['extra'],
+ array(
+ 'file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null,
+ 'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
+ 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null,
+ 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
+ )
+ );
+
+ return $record;
+ }
+
+ private function isTraceClassOrSkippedFunction(array $trace, $index)
+ {
+ if (!isset($trace[$index])) {
+ return false;
+ }
+
+ return isset($trace[$index]['class']) || in_array($trace[$index]['function'], $this->skipFunctions);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php
new file mode 100644
index 00000000..0543e929
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects memory_get_peak_usage in all records
+ *
+ * @see Monolog\Processor\MemoryProcessor::__construct() for options
+ * @author Rob Jensen
+ */
+class MemoryPeakUsageProcessor extends MemoryProcessor
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ $bytes = memory_get_peak_usage($this->realUsage);
+ $formatted = $this->formatBytes($bytes);
+
+ $record['extra']['memory_peak_usage'] = $formatted;
+
+ return $record;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php
new file mode 100644
index 00000000..2a379a30
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Some methods that are common for all memory processors
+ *
+ * @author Rob Jensen
+ */
+abstract class MemoryProcessor implements ProcessorInterface
+{
+ /**
+ * @var bool If true, get the real size of memory allocated from system. Else, only the memory used by emalloc() is reported.
+ */
+ protected $realUsage;
+
+ /**
+ * @var bool If true, then format memory size to human readable string (MB, KB, B depending on size)
+ */
+ protected $useFormatting;
+
+ /**
+ * @param bool $realUsage Set this to true to get the real size of memory allocated from system.
+ * @param bool $useFormatting If true, then format memory size to human readable string (MB, KB, B depending on size)
+ */
+ public function __construct($realUsage = true, $useFormatting = true)
+ {
+ $this->realUsage = (bool) $realUsage;
+ $this->useFormatting = (bool) $useFormatting;
+ }
+
+ /**
+ * Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is
+ *
+ * @param int $bytes
+ * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as is
+ */
+ protected function formatBytes($bytes)
+ {
+ $bytes = (int) $bytes;
+
+ if (!$this->useFormatting) {
+ return $bytes;
+ }
+
+ if ($bytes > 1024 * 1024) {
+ return round($bytes / 1024 / 1024, 2).' MB';
+ } elseif ($bytes > 1024) {
+ return round($bytes / 1024, 2).' KB';
+ }
+
+ return $bytes . ' B';
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php
new file mode 100644
index 00000000..2783d656
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php
@@ -0,0 +1,35 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects memory_get_usage in all records
+ *
+ * @see Monolog\Processor\MemoryProcessor::__construct() for options
+ * @author Rob Jensen
+ */
+class MemoryUsageProcessor extends MemoryProcessor
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ $bytes = memory_get_usage($this->realUsage);
+ $formatted = $this->formatBytes($bytes);
+
+ $record['extra']['memory_usage'] = $formatted;
+
+ return $record;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php
new file mode 100644
index 00000000..2f5b3265
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Logger;
+
+/**
+ * Injects Hg branch and Hg revision number in all records
+ *
+ * @author Jonathan A. Schweder
+ */
+class MercurialProcessor implements ProcessorInterface
+{
+ private $level;
+ private static $cache;
+
+ public function __construct($level = Logger::DEBUG)
+ {
+ $this->level = Logger::toMonologLevel($level);
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // return if the level is not high enough
+ if ($record['level'] < $this->level) {
+ return $record;
+ }
+
+ $record['extra']['hg'] = self::getMercurialInfo();
+
+ return $record;
+ }
+
+ private static function getMercurialInfo()
+ {
+ if (self::$cache) {
+ return self::$cache;
+ }
+
+ $result = explode(' ', trim(`hg id -nb`));
+ if (count($result) >= 3) {
+ return self::$cache = array(
+ 'branch' => $result[1],
+ 'revision' => $result[2],
+ );
+ }
+
+ return self::$cache = array();
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php
new file mode 100644
index 00000000..66b80fbb
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Adds value of getmypid into records
+ *
+ * @author Andreas Hörnicke
+ */
+class ProcessIdProcessor implements ProcessorInterface
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ $record['extra']['process_id'] = getmypid();
+
+ return $record;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php
new file mode 100644
index 00000000..7e64d4df
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * An optional interface to allow labelling Monolog processors.
+ *
+ * @author Nicolas Grekas
+ */
+interface ProcessorInterface
+{
+ /**
+ * @return array The processed records
+ */
+ public function __invoke(array $records);
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php
new file mode 100644
index 00000000..00885054
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\Utils;
+
+/**
+ * Processes a record's message according to PSR-3 rules
+ *
+ * It replaces {foo} with the value from $context['foo']
+ *
+ * @author Jordi Boggiano
+ */
+class PsrLogMessageProcessor implements ProcessorInterface
+{
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ if (false === strpos($record['message'], '{')) {
+ return $record;
+ }
+
+ $replacements = array();
+ foreach ($record['context'] as $key => $val) {
+ if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) {
+ $replacements['{'.$key.'}'] = $val;
+ } elseif (is_object($val)) {
+ $replacements['{'.$key.'}'] = '[object '.Utils::getClass($val).']';
+ } else {
+ $replacements['{'.$key.'}'] = '['.gettype($val).']';
+ }
+ }
+
+ $record['message'] = strtr($record['message'], $replacements);
+
+ return $record;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php
new file mode 100644
index 00000000..615a4d99
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php
@@ -0,0 +1,44 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Adds a tags array into record
+ *
+ * @author Martijn Riemers
+ */
+class TagProcessor implements ProcessorInterface
+{
+ private $tags;
+
+ public function __construct(array $tags = array())
+ {
+ $this->setTags($tags);
+ }
+
+ public function addTags(array $tags = array())
+ {
+ $this->tags = array_merge($this->tags, $tags);
+ }
+
+ public function setTags(array $tags = array())
+ {
+ $this->tags = $tags;
+ }
+
+ public function __invoke(array $record)
+ {
+ $record['extra']['tags'] = $this->tags;
+
+ return $record;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php
new file mode 100644
index 00000000..d1f708cf
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php
@@ -0,0 +1,59 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+use Monolog\ResettableInterface;
+
+/**
+ * Adds a unique identifier into records
+ *
+ * @author Simon Mönch
+ */
+class UidProcessor implements ProcessorInterface, ResettableInterface
+{
+ private $uid;
+
+ public function __construct($length = 7)
+ {
+ if (!is_int($length) || $length > 32 || $length < 1) {
+ throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32');
+ }
+
+
+ $this->uid = $this->generateUid($length);
+ }
+
+ public function __invoke(array $record)
+ {
+ $record['extra']['uid'] = $this->uid;
+
+ return $record;
+ }
+
+ /**
+ * @return string
+ */
+ public function getUid()
+ {
+ return $this->uid;
+ }
+
+ public function reset()
+ {
+ $this->uid = $this->generateUid(strlen($this->uid));
+ }
+
+ private function generateUid($length)
+ {
+ return substr(hash('md5', uniqid('', true)), 0, $length);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php b/akamai/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php
new file mode 100644
index 00000000..684188f6
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php
@@ -0,0 +1,113 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog\Processor;
+
+/**
+ * Injects url/method and remote IP of the current web request in all records
+ *
+ * @author Jordi Boggiano
+ */
+class WebProcessor implements ProcessorInterface
+{
+ /**
+ * @var array|\ArrayAccess
+ */
+ protected $serverData;
+
+ /**
+ * Default fields
+ *
+ * Array is structured as [key in record.extra => key in $serverData]
+ *
+ * @var array
+ */
+ protected $extraFields = array(
+ 'url' => 'REQUEST_URI',
+ 'ip' => 'REMOTE_ADDR',
+ 'http_method' => 'REQUEST_METHOD',
+ 'server' => 'SERVER_NAME',
+ 'referrer' => 'HTTP_REFERER',
+ );
+
+ /**
+ * @param array|\ArrayAccess $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data
+ * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer
+ */
+ public function __construct($serverData = null, array $extraFields = null)
+ {
+ if (null === $serverData) {
+ $this->serverData = &$_SERVER;
+ } elseif (is_array($serverData) || $serverData instanceof \ArrayAccess) {
+ $this->serverData = $serverData;
+ } else {
+ throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.');
+ }
+
+ if (null !== $extraFields) {
+ if (isset($extraFields[0])) {
+ foreach (array_keys($this->extraFields) as $fieldName) {
+ if (!in_array($fieldName, $extraFields)) {
+ unset($this->extraFields[$fieldName]);
+ }
+ }
+ } else {
+ $this->extraFields = $extraFields;
+ }
+ }
+ }
+
+ /**
+ * @param array $record
+ * @return array
+ */
+ public function __invoke(array $record)
+ {
+ // skip processing if for some reason request data
+ // is not present (CLI or wonky SAPIs)
+ if (!isset($this->serverData['REQUEST_URI'])) {
+ return $record;
+ }
+
+ $record['extra'] = $this->appendExtraFields($record['extra']);
+
+ return $record;
+ }
+
+ /**
+ * @param string $extraName
+ * @param string $serverName
+ * @return $this
+ */
+ public function addExtraField($extraName, $serverName)
+ {
+ $this->extraFields[$extraName] = $serverName;
+
+ return $this;
+ }
+
+ /**
+ * @param array $extra
+ * @return array
+ */
+ private function appendExtraFields(array $extra)
+ {
+ foreach ($this->extraFields as $extraName => $serverName) {
+ $extra[$extraName] = isset($this->serverData[$serverName]) ? $this->serverData[$serverName] : null;
+ }
+
+ if (isset($this->serverData['UNIQUE_ID'])) {
+ $extra['unique_id'] = $this->serverData['UNIQUE_ID'];
+ }
+
+ return $extra;
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Registry.php b/akamai/vendor/monolog/monolog/src/Monolog/Registry.php
new file mode 100644
index 00000000..159b751c
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Registry.php
@@ -0,0 +1,134 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use InvalidArgumentException;
+
+/**
+ * Monolog log registry
+ *
+ * Allows to get `Logger` instances in the global scope
+ * via static method calls on this class.
+ *
+ *
+ * $application = new Monolog\Logger('application');
+ * $api = new Monolog\Logger('api');
+ *
+ * Monolog\Registry::addLogger($application);
+ * Monolog\Registry::addLogger($api);
+ *
+ * function testLogger()
+ * {
+ * Monolog\Registry::api()->addError('Sent to $api Logger instance');
+ * Monolog\Registry::application()->addError('Sent to $application Logger instance');
+ * }
+ *
+ *
+ * @author Tomas Tatarko
+ */
+class Registry
+{
+ /**
+ * List of all loggers in the registry (by named indexes)
+ *
+ * @var Logger[]
+ */
+ private static $loggers = array();
+
+ /**
+ * Adds new logging channel to the registry
+ *
+ * @param Logger $logger Instance of the logging channel
+ * @param string|null $name Name of the logging channel ($logger->getName() by default)
+ * @param bool $overwrite Overwrite instance in the registry if the given name already exists?
+ * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists
+ */
+ public static function addLogger(Logger $logger, $name = null, $overwrite = false)
+ {
+ $name = $name ?: $logger->getName();
+
+ if (isset(self::$loggers[$name]) && !$overwrite) {
+ throw new InvalidArgumentException('Logger with the given name already exists');
+ }
+
+ self::$loggers[$name] = $logger;
+ }
+
+ /**
+ * Checks if such logging channel exists by name or instance
+ *
+ * @param string|Logger $logger Name or logger instance
+ */
+ public static function hasLogger($logger)
+ {
+ if ($logger instanceof Logger) {
+ $index = array_search($logger, self::$loggers, true);
+
+ return false !== $index;
+ } else {
+ return isset(self::$loggers[$logger]);
+ }
+ }
+
+ /**
+ * Removes instance from registry by name or instance
+ *
+ * @param string|Logger $logger Name or logger instance
+ */
+ public static function removeLogger($logger)
+ {
+ if ($logger instanceof Logger) {
+ if (false !== ($idx = array_search($logger, self::$loggers, true))) {
+ unset(self::$loggers[$idx]);
+ }
+ } else {
+ unset(self::$loggers[$logger]);
+ }
+ }
+
+ /**
+ * Clears the registry
+ */
+ public static function clear()
+ {
+ self::$loggers = array();
+ }
+
+ /**
+ * Gets Logger instance from the registry
+ *
+ * @param string $name Name of the requested Logger instance
+ * @throws \InvalidArgumentException If named Logger instance is not in the registry
+ * @return Logger Requested instance of Logger
+ */
+ public static function getInstance($name)
+ {
+ if (!isset(self::$loggers[$name])) {
+ throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name));
+ }
+
+ return self::$loggers[$name];
+ }
+
+ /**
+ * Gets Logger instance from the registry via static method call
+ *
+ * @param string $name Name of the requested Logger instance
+ * @param array $arguments Arguments passed to static method call
+ * @throws \InvalidArgumentException If named Logger instance is not in the registry
+ * @return Logger Requested instance of Logger
+ */
+ public static function __callStatic($name, $arguments)
+ {
+ return self::getInstance($name);
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/ResettableInterface.php b/akamai/vendor/monolog/monolog/src/Monolog/ResettableInterface.php
new file mode 100644
index 00000000..635bc77d
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/ResettableInterface.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+/**
+ * Handler or Processor implementing this interface will be reset when Logger::reset() is called.
+ *
+ * Resetting ends a log cycle gets them back to their initial state.
+ *
+ * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal
+ * state, and getting it back to a state in which it can receive log records again.
+ *
+ * This is useful in case you want to avoid logs leaking between two requests or jobs when you
+ * have a long running process like a worker or an application server serving multiple requests
+ * in one process.
+ *
+ * @author Grégoire Pineau
+ */
+interface ResettableInterface
+{
+ public function reset();
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/SignalHandler.php b/akamai/vendor/monolog/monolog/src/Monolog/SignalHandler.php
new file mode 100644
index 00000000..d87018fe
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/SignalHandler.php
@@ -0,0 +1,115 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+use ReflectionExtension;
+
+/**
+ * Monolog POSIX signal handler
+ *
+ * @author Robert Gust-Bardon
+ */
+class SignalHandler
+{
+ private $logger;
+
+ private $previousSignalHandler = array();
+ private $signalLevelMap = array();
+ private $signalRestartSyscalls = array();
+
+ public function __construct(LoggerInterface $logger)
+ {
+ $this->logger = $logger;
+ }
+
+ public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true)
+ {
+ if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) {
+ return $this;
+ }
+
+ if ($callPrevious) {
+ if (function_exists('pcntl_signal_get_handler')) {
+ $handler = pcntl_signal_get_handler($signo);
+ if ($handler === false) {
+ return $this;
+ }
+ $this->previousSignalHandler[$signo] = $handler;
+ } else {
+ $this->previousSignalHandler[$signo] = true;
+ }
+ } else {
+ unset($this->previousSignalHandler[$signo]);
+ }
+ $this->signalLevelMap[$signo] = $level;
+ $this->signalRestartSyscalls[$signo] = $restartSyscalls;
+
+ if (function_exists('pcntl_async_signals') && $async !== null) {
+ pcntl_async_signals($async);
+ }
+
+ pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls);
+
+ return $this;
+ }
+
+ public function handleSignal($signo, array $siginfo = null)
+ {
+ static $signals = array();
+
+ if (!$signals && extension_loaded('pcntl')) {
+ $pcntl = new ReflectionExtension('pcntl');
+ $constants = $pcntl->getConstants();
+ if (!$constants) {
+ // HHVM 3.24.2 returns an empty array.
+ $constants = get_defined_constants(true);
+ $constants = $constants['Core'];
+ }
+ foreach ($constants as $name => $value) {
+ if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) {
+ $signals[$value] = $name;
+ }
+ }
+ unset($constants);
+ }
+
+ $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL;
+ $signal = isset($signals[$signo]) ? $signals[$signo] : $signo;
+ $context = isset($siginfo) ? $siginfo : array();
+ $this->logger->log($level, sprintf('Program received signal %s', $signal), $context);
+
+ if (!isset($this->previousSignalHandler[$signo])) {
+ return;
+ }
+
+ if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) {
+ if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch')
+ && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) {
+ $restartSyscalls = isset($this->signalRestartSyscalls[$signo]) ? $this->signalRestartSyscalls[$signo] : true;
+ pcntl_signal($signo, SIG_DFL, $restartSyscalls);
+ pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset);
+ posix_kill(posix_getpid(), $signo);
+ pcntl_signal_dispatch();
+ pcntl_sigprocmask(SIG_SETMASK, $oldset);
+ pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls);
+ }
+ } elseif (is_callable($this->previousSignalHandler[$signo])) {
+ if (PHP_VERSION_ID >= 70100) {
+ $this->previousSignalHandler[$signo]($signo, $siginfo);
+ } else {
+ $this->previousSignalHandler[$signo]($signo);
+ }
+ }
+ }
+}
diff --git a/akamai/vendor/monolog/monolog/src/Monolog/Utils.php b/akamai/vendor/monolog/monolog/src/Monolog/Utils.php
new file mode 100644
index 00000000..180a159d
--- /dev/null
+++ b/akamai/vendor/monolog/monolog/src/Monolog/Utils.php
@@ -0,0 +1,159 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Monolog;
+
+class Utils
+{
+ /**
+ * @internal
+ */
+ public static function getClass($object)
+ {
+ $class = \get_class($object);
+
+ return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
+ }
+
+ /**
+ * Return the JSON representation of a value
+ *
+ * @param mixed $data
+ * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
+ * @param bool $ignoreErrors whether to ignore encoding errors or to throw on error, when ignored and the encoding fails, "null" is returned which is valid json for null
+ * @throws \RuntimeException if encoding fails and errors are not ignored
+ * @return string
+ */
+ public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = false)
+ {
+ if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
+ }
+
+ if ($ignoreErrors) {
+ $json = @json_encode($data, $encodeFlags);
+ if (false === $json) {
+ return 'null';
+ }
+
+ return $json;
+ }
+
+ $json = json_encode($data, $encodeFlags);
+ if (false === $json) {
+ $json = self::handleJsonError(json_last_error(), $data);
+ }
+
+ return $json;
+ }
+
+ /**
+ * Handle a json_encode failure.
+ *
+ * If the failure is due to invalid string encoding, try to clean the
+ * input and encode again. If the second encoding attempt fails, the
+ * inital error is not encoding related or the input can't be cleaned then
+ * raise a descriptive exception.
+ *
+ * @param int $code return code of json_last_error function
+ * @param mixed $data data that was meant to be encoded
+ * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
+ * @throws \RuntimeException if failure can't be corrected
+ * @return string JSON encoded data after error correction
+ */
+ public static function handleJsonError($code, $data, $encodeFlags = null)
+ {
+ if ($code !== JSON_ERROR_UTF8) {
+ self::throwEncodeError($code, $data);
+ }
+
+ if (is_string($data)) {
+ self::detectAndCleanUtf8($data);
+ } elseif (is_array($data)) {
+ array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8'));
+ } else {
+ self::throwEncodeError($code, $data);
+ }
+
+ if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) {
+ $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
+ }
+
+ $json = json_encode($data, $encodeFlags);
+
+ if ($json === false) {
+ self::throwEncodeError(json_last_error(), $data);
+ }
+
+ return $json;
+ }
+
+ /**
+ * Throws an exception according to a given code with a customized message
+ *
+ * @param int $code return code of json_last_error function
+ * @param mixed $data data that was meant to be encoded
+ * @throws \RuntimeException
+ */
+ private static function throwEncodeError($code, $data)
+ {
+ switch ($code) {
+ case JSON_ERROR_DEPTH:
+ $msg = 'Maximum stack depth exceeded';
+ break;
+ case JSON_ERROR_STATE_MISMATCH:
+ $msg = 'Underflow or the modes mismatch';
+ break;
+ case JSON_ERROR_CTRL_CHAR:
+ $msg = 'Unexpected control character found';
+ break;
+ case JSON_ERROR_UTF8:
+ $msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ break;
+ default:
+ $msg = 'Unknown error';
+ }
+
+ throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
+ }
+
+ /**
+ * Detect invalid UTF-8 string characters and convert to valid UTF-8.
+ *
+ * Valid UTF-8 input will be left unmodified, but strings containing
+ * invalid UTF-8 codepoints will be reencoded as UTF-8 with an assumed
+ * original encoding of ISO-8859-15. This conversion may result in
+ * incorrect output if the actual encoding was not ISO-8859-15, but it
+ * will be clean UTF-8 output and will not rely on expensive and fragile
+ * detection algorithms.
+ *
+ * Function converts the input in place in the passed variable so that it
+ * can be used as a callback for array_walk_recursive.
+ *
+ * @param mixed &$data Input to check and convert if needed
+ * @private
+ */
+ public static function detectAndCleanUtf8(&$data)
+ {
+ if (is_string($data) && !preg_match('//u', $data)) {
+ $data = preg_replace_callback(
+ '/[\x80-\xFF]+/',
+ function ($m) { return utf8_encode($m[0]); },
+ $data
+ );
+ $data = str_replace(
+ array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'),
+ array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'),
+ $data
+ );
+ }
+ }
+}
diff --git a/akamai/vendor/psr/http-message/CHANGELOG.md b/akamai/vendor/psr/http-message/CHANGELOG.md
new file mode 100644
index 00000000..74b1ef92
--- /dev/null
+++ b/akamai/vendor/psr/http-message/CHANGELOG.md
@@ -0,0 +1,36 @@
+# Changelog
+
+All notable changes to this project will be documented in this file, in reverse chronological order by release.
+
+## 1.0.1 - 2016-08-06
+
+### Added
+
+- Nothing.
+
+### Deprecated
+
+- Nothing.
+
+### Removed
+
+- Nothing.
+
+### Fixed
+
+- Updated all `@return self` annotation references in interfaces to use
+ `@return static`, which more closelly follows the semantics of the
+ specification.
+- Updated the `MessageInterface::getHeaders()` return annotation to use the
+ value `string[][]`, indicating the format is a nested array of strings.
+- Updated the `@link` annotation for `RequestInterface::withRequestTarget()`
+ to point to the correct section of RFC 7230.
+- Updated the `ServerRequestInterface::withUploadedFiles()` parameter annotation
+ to add the parameter name (`$uploadedFiles`).
+- Updated a `@throws` annotation for the `UploadedFileInterface::moveTo()`
+ method to correctly reference the method parameter (it was referencing an
+ incorrect parameter name previously).
+
+## 1.0.0 - 2016-05-18
+
+Initial stable release; reflects accepted PSR-7 specification.
diff --git a/akamai/vendor/psr/http-message/LICENSE b/akamai/vendor/psr/http-message/LICENSE
new file mode 100644
index 00000000..c2d8e452
--- /dev/null
+++ b/akamai/vendor/psr/http-message/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 PHP Framework Interoperability Group
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/akamai/vendor/psr/http-message/README.md b/akamai/vendor/psr/http-message/README.md
new file mode 100644
index 00000000..28185338
--- /dev/null
+++ b/akamai/vendor/psr/http-message/README.md
@@ -0,0 +1,13 @@
+PSR Http Message
+================
+
+This repository holds all interfaces/classes/traits related to
+[PSR-7](http://www.php-fig.org/psr/psr-7/).
+
+Note that this is not a HTTP message implementation of its own. It is merely an
+interface that describes a HTTP message. See the specification for more details.
+
+Usage
+-----
+
+We'll certainly need some stuff in here.
\ No newline at end of file
diff --git a/akamai/vendor/psr/http-message/composer.json b/akamai/vendor/psr/http-message/composer.json
new file mode 100644
index 00000000..b0d2937a
--- /dev/null
+++ b/akamai/vendor/psr/http-message/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "psr/http-message",
+ "description": "Common interface for HTTP messages",
+ "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"],
+ "homepage": "https://github.com/php-fig/http-message",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ }
+}
diff --git a/akamai/vendor/psr/http-message/src/MessageInterface.php b/akamai/vendor/psr/http-message/src/MessageInterface.php
new file mode 100644
index 00000000..dd46e5ec
--- /dev/null
+++ b/akamai/vendor/psr/http-message/src/MessageInterface.php
@@ -0,0 +1,187 @@
+getHeaders() as $name => $values) {
+ * echo $name . ": " . implode(", ", $values);
+ * }
+ *
+ * // Emit headers iteratively:
+ * foreach ($message->getHeaders() as $name => $values) {
+ * foreach ($values as $value) {
+ * header(sprintf('%s: %s', $name, $value), false);
+ * }
+ * }
+ *
+ * While header names are not case-sensitive, getHeaders() will preserve the
+ * exact case in which headers were originally specified.
+ *
+ * @return string[][] Returns an associative array of the message's headers. Each
+ * key MUST be a header name, and each value MUST be an array of strings
+ * for that header.
+ */
+ public function getHeaders();
+
+ /**
+ * Checks if a header exists by the given case-insensitive name.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return bool Returns true if any header names match the given header
+ * name using a case-insensitive string comparison. Returns false if
+ * no matching header name is found in the message.
+ */
+ public function hasHeader($name);
+
+ /**
+ * Retrieves a message header value by the given case-insensitive name.
+ *
+ * This method returns an array of all the header values of the given
+ * case-insensitive header name.
+ *
+ * If the header does not appear in the message, this method MUST return an
+ * empty array.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string[] An array of string values as provided for the given
+ * header. If the header does not appear in the message, this method MUST
+ * return an empty array.
+ */
+ public function getHeader($name);
+
+ /**
+ * Retrieves a comma-separated string of the values for a single header.
+ *
+ * This method returns all of the header values of the given
+ * case-insensitive header name as a string concatenated together using
+ * a comma.
+ *
+ * NOTE: Not all header values may be appropriately represented using
+ * comma concatenation. For such headers, use getHeader() instead
+ * and supply your own delimiter when concatenating.
+ *
+ * If the header does not appear in the message, this method MUST return
+ * an empty string.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @return string A string of values as provided for the given header
+ * concatenated together using a comma. If the header does not appear in
+ * the message, this method MUST return an empty string.
+ */
+ public function getHeaderLine($name);
+
+ /**
+ * Return an instance with the provided value replacing the specified header.
+ *
+ * While header names are case-insensitive, the casing of the header will
+ * be preserved by this function, and returned from getHeaders().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new and/or updated header and value.
+ *
+ * @param string $name Case-insensitive header field name.
+ * @param string|string[] $value Header value(s).
+ * @return static
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withHeader($name, $value);
+
+ /**
+ * Return an instance with the specified header appended with the given value.
+ *
+ * Existing values for the specified header will be maintained. The new
+ * value(s) will be appended to the existing list. If the header did not
+ * exist previously, it will be added.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * new header and/or value.
+ *
+ * @param string $name Case-insensitive header field name to add.
+ * @param string|string[] $value Header value(s).
+ * @return static
+ * @throws \InvalidArgumentException for invalid header names or values.
+ */
+ public function withAddedHeader($name, $value);
+
+ /**
+ * Return an instance without the specified header.
+ *
+ * Header resolution MUST be done without case-sensitivity.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the named header.
+ *
+ * @param string $name Case-insensitive header field name to remove.
+ * @return static
+ */
+ public function withoutHeader($name);
+
+ /**
+ * Gets the body of the message.
+ *
+ * @return StreamInterface Returns the body as a stream.
+ */
+ public function getBody();
+
+ /**
+ * Return an instance with the specified message body.
+ *
+ * The body MUST be a StreamInterface object.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return a new instance that has the
+ * new body stream.
+ *
+ * @param StreamInterface $body Body.
+ * @return static
+ * @throws \InvalidArgumentException When the body is not valid.
+ */
+ public function withBody(StreamInterface $body);
+}
diff --git a/akamai/vendor/psr/http-message/src/RequestInterface.php b/akamai/vendor/psr/http-message/src/RequestInterface.php
new file mode 100644
index 00000000..a96d4fd6
--- /dev/null
+++ b/akamai/vendor/psr/http-message/src/RequestInterface.php
@@ -0,0 +1,129 @@
+getQuery()`
+ * or from the `QUERY_STRING` server param.
+ *
+ * @return array
+ */
+ public function getQueryParams();
+
+ /**
+ * Return an instance with the specified query string arguments.
+ *
+ * These values SHOULD remain immutable over the course of the incoming
+ * request. They MAY be injected during instantiation, such as from PHP's
+ * $_GET superglobal, or MAY be derived from some other value such as the
+ * URI. In cases where the arguments are parsed from the URI, the data
+ * MUST be compatible with what PHP's parse_str() would return for
+ * purposes of how duplicate query parameters are handled, and how nested
+ * sets are handled.
+ *
+ * Setting query string arguments MUST NOT change the URI stored by the
+ * request, nor the values in the server params.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated query string arguments.
+ *
+ * @param array $query Array of query string arguments, typically from
+ * $_GET.
+ * @return static
+ */
+ public function withQueryParams(array $query);
+
+ /**
+ * Retrieve normalized file upload data.
+ *
+ * This method returns upload metadata in a normalized tree, with each leaf
+ * an instance of Psr\Http\Message\UploadedFileInterface.
+ *
+ * These values MAY be prepared from $_FILES or the message body during
+ * instantiation, or MAY be injected via withUploadedFiles().
+ *
+ * @return array An array tree of UploadedFileInterface instances; an empty
+ * array MUST be returned if no data is present.
+ */
+ public function getUploadedFiles();
+
+ /**
+ * Create a new instance with the specified uploaded files.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param array $uploadedFiles An array tree of UploadedFileInterface instances.
+ * @return static
+ * @throws \InvalidArgumentException if an invalid structure is provided.
+ */
+ public function withUploadedFiles(array $uploadedFiles);
+
+ /**
+ * Retrieve any parameters provided in the request body.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, this method MUST
+ * return the contents of $_POST.
+ *
+ * Otherwise, this method may return any results of deserializing
+ * the request body content; as parsing returns structured content, the
+ * potential types MUST be arrays or objects only. A null value indicates
+ * the absence of body content.
+ *
+ * @return null|array|object The deserialized body parameters, if any.
+ * These will typically be an array or object.
+ */
+ public function getParsedBody();
+
+ /**
+ * Return an instance with the specified body parameters.
+ *
+ * These MAY be injected during instantiation.
+ *
+ * If the request Content-Type is either application/x-www-form-urlencoded
+ * or multipart/form-data, and the request method is POST, use this method
+ * ONLY to inject the contents of $_POST.
+ *
+ * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of
+ * deserializing the request body content. Deserialization/parsing returns
+ * structured data, and, as such, this method ONLY accepts arrays or objects,
+ * or a null value if nothing was available to parse.
+ *
+ * As an example, if content negotiation determines that the request data
+ * is a JSON payload, this method could be used to create a request
+ * instance with the deserialized parameters.
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated body parameters.
+ *
+ * @param null|array|object $data The deserialized body data. This will
+ * typically be in an array or object.
+ * @return static
+ * @throws \InvalidArgumentException if an unsupported argument type is
+ * provided.
+ */
+ public function withParsedBody($data);
+
+ /**
+ * Retrieve attributes derived from the request.
+ *
+ * The request "attributes" may be used to allow injection of any
+ * parameters derived from the request: e.g., the results of path
+ * match operations; the results of decrypting cookies; the results of
+ * deserializing non-form-encoded message bodies; etc. Attributes
+ * will be application and request specific, and CAN be mutable.
+ *
+ * @return array Attributes derived from the request.
+ */
+ public function getAttributes();
+
+ /**
+ * Retrieve a single derived request attribute.
+ *
+ * Retrieves a single derived request attribute as described in
+ * getAttributes(). If the attribute has not been previously set, returns
+ * the default value as provided.
+ *
+ * This method obviates the need for a hasAttribute() method, as it allows
+ * specifying a default value to return if the attribute is not found.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $default Default value to return if the attribute does not exist.
+ * @return mixed
+ */
+ public function getAttribute($name, $default = null);
+
+ /**
+ * Return an instance with the specified derived request attribute.
+ *
+ * This method allows setting a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that has the
+ * updated attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @param mixed $value The value of the attribute.
+ * @return static
+ */
+ public function withAttribute($name, $value);
+
+ /**
+ * Return an instance that removes the specified derived request attribute.
+ *
+ * This method allows removing a single derived request attribute as
+ * described in getAttributes().
+ *
+ * This method MUST be implemented in such a way as to retain the
+ * immutability of the message, and MUST return an instance that removes
+ * the attribute.
+ *
+ * @see getAttributes()
+ * @param string $name The attribute name.
+ * @return static
+ */
+ public function withoutAttribute($name);
+}
diff --git a/akamai/vendor/psr/http-message/src/StreamInterface.php b/akamai/vendor/psr/http-message/src/StreamInterface.php
new file mode 100644
index 00000000..f68f3912
--- /dev/null
+++ b/akamai/vendor/psr/http-message/src/StreamInterface.php
@@ -0,0 +1,158 @@
+
+ * [user-info@]host[:port]
+ *
+ *
+ * If the port component is not set or is the standard port for the current
+ * scheme, it SHOULD NOT be included.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-3.2
+ * @return string The URI authority, in "[user-info@]host[:port]" format.
+ */
+ public function getAuthority();
+
+ /**
+ * Retrieve the user information component of the URI.
+ *
+ * If no user information is present, this method MUST return an empty
+ * string.
+ *
+ * If a user is present in the URI, this will return that value;
+ * additionally, if the password is also present, it will be appended to the
+ * user value, with a colon (":") separating the values.
+ *
+ * The trailing "@" character is not part of the user information and MUST
+ * NOT be added.
+ *
+ * @return string The URI user information, in "username[:password]" format.
+ */
+ public function getUserInfo();
+
+ /**
+ * Retrieve the host component of the URI.
+ *
+ * If no host is present, this method MUST return an empty string.
+ *
+ * The value returned MUST be normalized to lowercase, per RFC 3986
+ * Section 3.2.2.
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-3.2.2
+ * @return string The URI host.
+ */
+ public function getHost();
+
+ /**
+ * Retrieve the port component of the URI.
+ *
+ * If a port is present, and it is non-standard for the current scheme,
+ * this method MUST return it as an integer. If the port is the standard port
+ * used with the current scheme, this method SHOULD return null.
+ *
+ * If no port is present, and no scheme is present, this method MUST return
+ * a null value.
+ *
+ * If no port is present, but a scheme is present, this method MAY return
+ * the standard port for that scheme, but SHOULD return null.
+ *
+ * @return null|int The URI port.
+ */
+ public function getPort();
+
+ /**
+ * Retrieve the path component of the URI.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * Normally, the empty path "" and absolute path "/" are considered equal as
+ * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically
+ * do this normalization because in contexts with a trimmed base path, e.g.
+ * the front controller, this difference becomes significant. It's the task
+ * of the user to handle both "" and "/".
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.3.
+ *
+ * As an example, if the value should include a slash ("/") not intended as
+ * delimiter between path segments, that value MUST be passed in encoded
+ * form (e.g., "%2F") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.3
+ * @return string The URI path.
+ */
+ public function getPath();
+
+ /**
+ * Retrieve the query string of the URI.
+ *
+ * If no query string is present, this method MUST return an empty string.
+ *
+ * The leading "?" character is not part of the query and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.4.
+ *
+ * As an example, if a value in a key/value pair of the query string should
+ * include an ampersand ("&") not intended as a delimiter between values,
+ * that value MUST be passed in encoded form (e.g., "%26") to the instance.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.4
+ * @return string The URI query string.
+ */
+ public function getQuery();
+
+ /**
+ * Retrieve the fragment component of the URI.
+ *
+ * If no fragment is present, this method MUST return an empty string.
+ *
+ * The leading "#" character is not part of the fragment and MUST NOT be
+ * added.
+ *
+ * The value returned MUST be percent-encoded, but MUST NOT double-encode
+ * any characters. To determine what characters to encode, please refer to
+ * RFC 3986, Sections 2 and 3.5.
+ *
+ * @see https://tools.ietf.org/html/rfc3986#section-2
+ * @see https://tools.ietf.org/html/rfc3986#section-3.5
+ * @return string The URI fragment.
+ */
+ public function getFragment();
+
+ /**
+ * Return an instance with the specified scheme.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified scheme.
+ *
+ * Implementations MUST support the schemes "http" and "https" case
+ * insensitively, and MAY accommodate other schemes if required.
+ *
+ * An empty scheme is equivalent to removing the scheme.
+ *
+ * @param string $scheme The scheme to use with the new instance.
+ * @return static A new instance with the specified scheme.
+ * @throws \InvalidArgumentException for invalid or unsupported schemes.
+ */
+ public function withScheme($scheme);
+
+ /**
+ * Return an instance with the specified user information.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified user information.
+ *
+ * Password is optional, but the user information MUST include the
+ * user; an empty string for the user is equivalent to removing user
+ * information.
+ *
+ * @param string $user The user name to use for authority.
+ * @param null|string $password The password associated with $user.
+ * @return static A new instance with the specified user information.
+ */
+ public function withUserInfo($user, $password = null);
+
+ /**
+ * Return an instance with the specified host.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified host.
+ *
+ * An empty host value is equivalent to removing the host.
+ *
+ * @param string $host The hostname to use with the new instance.
+ * @return static A new instance with the specified host.
+ * @throws \InvalidArgumentException for invalid hostnames.
+ */
+ public function withHost($host);
+
+ /**
+ * Return an instance with the specified port.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified port.
+ *
+ * Implementations MUST raise an exception for ports outside the
+ * established TCP and UDP port ranges.
+ *
+ * A null value provided for the port is equivalent to removing the port
+ * information.
+ *
+ * @param null|int $port The port to use with the new instance; a null value
+ * removes the port information.
+ * @return static A new instance with the specified port.
+ * @throws \InvalidArgumentException for invalid ports.
+ */
+ public function withPort($port);
+
+ /**
+ * Return an instance with the specified path.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified path.
+ *
+ * The path can either be empty or absolute (starting with a slash) or
+ * rootless (not starting with a slash). Implementations MUST support all
+ * three syntaxes.
+ *
+ * If the path is intended to be domain-relative rather than path relative then
+ * it must begin with a slash ("/"). Paths not starting with a slash ("/")
+ * are assumed to be relative to some base path known to the application or
+ * consumer.
+ *
+ * Users can provide both encoded and decoded path characters.
+ * Implementations ensure the correct encoding as outlined in getPath().
+ *
+ * @param string $path The path to use with the new instance.
+ * @return static A new instance with the specified path.
+ * @throws \InvalidArgumentException for invalid paths.
+ */
+ public function withPath($path);
+
+ /**
+ * Return an instance with the specified query string.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified query string.
+ *
+ * Users can provide both encoded and decoded query characters.
+ * Implementations ensure the correct encoding as outlined in getQuery().
+ *
+ * An empty query string value is equivalent to removing the query string.
+ *
+ * @param string $query The query string to use with the new instance.
+ * @return static A new instance with the specified query string.
+ * @throws \InvalidArgumentException for invalid query strings.
+ */
+ public function withQuery($query);
+
+ /**
+ * Return an instance with the specified URI fragment.
+ *
+ * This method MUST retain the state of the current instance, and return
+ * an instance that contains the specified URI fragment.
+ *
+ * Users can provide both encoded and decoded fragment characters.
+ * Implementations ensure the correct encoding as outlined in getFragment().
+ *
+ * An empty fragment value is equivalent to removing the fragment.
+ *
+ * @param string $fragment The fragment to use with the new instance.
+ * @return static A new instance with the specified fragment.
+ */
+ public function withFragment($fragment);
+
+ /**
+ * Return the string representation as a URI reference.
+ *
+ * Depending on which components of the URI are present, the resulting
+ * string is either a full URI or relative reference according to RFC 3986,
+ * Section 4.1. The method concatenates the various components of the URI,
+ * using the appropriate delimiters:
+ *
+ * - If a scheme is present, it MUST be suffixed by ":".
+ * - If an authority is present, it MUST be prefixed by "//".
+ * - The path can be concatenated without delimiters. But there are two
+ * cases where the path has to be adjusted to make the URI reference
+ * valid as PHP does not allow to throw an exception in __toString():
+ * - If the path is rootless and an authority is present, the path MUST
+ * be prefixed by "/".
+ * - If the path is starting with more than one "/" and no authority is
+ * present, the starting slashes MUST be reduced to one.
+ * - If a query is present, it MUST be prefixed by "?".
+ * - If a fragment is present, it MUST be prefixed by "#".
+ *
+ * @see http://tools.ietf.org/html/rfc3986#section-4.1
+ * @return string
+ */
+ public function __toString();
+}
diff --git a/akamai/vendor/psr/log/.gitignore b/akamai/vendor/psr/log/.gitignore
new file mode 100644
index 00000000..22d0d82f
--- /dev/null
+++ b/akamai/vendor/psr/log/.gitignore
@@ -0,0 +1 @@
+vendor
diff --git a/akamai/vendor/psr/log/LICENSE b/akamai/vendor/psr/log/LICENSE
new file mode 100644
index 00000000..474c952b
--- /dev/null
+++ b/akamai/vendor/psr/log/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2012 PHP Framework Interoperability Group
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/akamai/vendor/psr/log/Psr/Log/AbstractLogger.php b/akamai/vendor/psr/log/Psr/Log/AbstractLogger.php
new file mode 100644
index 00000000..90e721af
--- /dev/null
+++ b/akamai/vendor/psr/log/Psr/Log/AbstractLogger.php
@@ -0,0 +1,128 @@
+log(LogLevel::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Action must be taken immediately.
+ *
+ * Example: Entire website down, database unavailable, etc. This should
+ * trigger the SMS alerts and wake you up.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function alert($message, array $context = array())
+ {
+ $this->log(LogLevel::ALERT, $message, $context);
+ }
+
+ /**
+ * Critical conditions.
+ *
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function critical($message, array $context = array())
+ {
+ $this->log(LogLevel::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Runtime errors that do not require immediate action but should typically
+ * be logged and monitored.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function error($message, array $context = array())
+ {
+ $this->log(LogLevel::ERROR, $message, $context);
+ }
+
+ /**
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
+ * that are not necessarily wrong.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function warning($message, array $context = array())
+ {
+ $this->log(LogLevel::WARNING, $message, $context);
+ }
+
+ /**
+ * Normal but significant events.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function notice($message, array $context = array())
+ {
+ $this->log(LogLevel::NOTICE, $message, $context);
+ }
+
+ /**
+ * Interesting events.
+ *
+ * Example: User logs in, SQL logs.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function info($message, array $context = array())
+ {
+ $this->log(LogLevel::INFO, $message, $context);
+ }
+
+ /**
+ * Detailed debug information.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function debug($message, array $context = array())
+ {
+ $this->log(LogLevel::DEBUG, $message, $context);
+ }
+}
diff --git a/akamai/vendor/psr/log/Psr/Log/InvalidArgumentException.php b/akamai/vendor/psr/log/Psr/Log/InvalidArgumentException.php
new file mode 100644
index 00000000..67f852d1
--- /dev/null
+++ b/akamai/vendor/psr/log/Psr/Log/InvalidArgumentException.php
@@ -0,0 +1,7 @@
+logger = $logger;
+ }
+}
diff --git a/akamai/vendor/psr/log/Psr/Log/LoggerInterface.php b/akamai/vendor/psr/log/Psr/Log/LoggerInterface.php
new file mode 100644
index 00000000..e695046e
--- /dev/null
+++ b/akamai/vendor/psr/log/Psr/Log/LoggerInterface.php
@@ -0,0 +1,125 @@
+log(LogLevel::EMERGENCY, $message, $context);
+ }
+
+ /**
+ * Action must be taken immediately.
+ *
+ * Example: Entire website down, database unavailable, etc. This should
+ * trigger the SMS alerts and wake you up.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function alert($message, array $context = array())
+ {
+ $this->log(LogLevel::ALERT, $message, $context);
+ }
+
+ /**
+ * Critical conditions.
+ *
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function critical($message, array $context = array())
+ {
+ $this->log(LogLevel::CRITICAL, $message, $context);
+ }
+
+ /**
+ * Runtime errors that do not require immediate action but should typically
+ * be logged and monitored.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function error($message, array $context = array())
+ {
+ $this->log(LogLevel::ERROR, $message, $context);
+ }
+
+ /**
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
+ * that are not necessarily wrong.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function warning($message, array $context = array())
+ {
+ $this->log(LogLevel::WARNING, $message, $context);
+ }
+
+ /**
+ * Normal but significant events.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function notice($message, array $context = array())
+ {
+ $this->log(LogLevel::NOTICE, $message, $context);
+ }
+
+ /**
+ * Interesting events.
+ *
+ * Example: User logs in, SQL logs.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function info($message, array $context = array())
+ {
+ $this->log(LogLevel::INFO, $message, $context);
+ }
+
+ /**
+ * Detailed debug information.
+ *
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ */
+ public function debug($message, array $context = array())
+ {
+ $this->log(LogLevel::DEBUG, $message, $context);
+ }
+
+ /**
+ * Logs with an arbitrary level.
+ *
+ * @param mixed $level
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ *
+ * @throws \Psr\Log\InvalidArgumentException
+ */
+ abstract public function log($level, $message, array $context = array());
+}
diff --git a/akamai/vendor/psr/log/Psr/Log/NullLogger.php b/akamai/vendor/psr/log/Psr/Log/NullLogger.php
new file mode 100644
index 00000000..c8f7293b
--- /dev/null
+++ b/akamai/vendor/psr/log/Psr/Log/NullLogger.php
@@ -0,0 +1,30 @@
+logger) { }`
+ * blocks.
+ */
+class NullLogger extends AbstractLogger
+{
+ /**
+ * Logs with an arbitrary level.
+ *
+ * @param mixed $level
+ * @param string $message
+ * @param array $context
+ *
+ * @return void
+ *
+ * @throws \Psr\Log\InvalidArgumentException
+ */
+ public function log($level, $message, array $context = array())
+ {
+ // noop
+ }
+}
diff --git a/akamai/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php b/akamai/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php
new file mode 100644
index 00000000..9ecb6c4b
--- /dev/null
+++ b/akamai/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php
@@ -0,0 +1,146 @@
+ ".
+ *
+ * Example ->error('Foo') would yield "error Foo".
+ *
+ * @return string[]
+ */
+ abstract public function getLogs();
+
+ public function testImplements()
+ {
+ $this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
+ }
+
+ /**
+ * @dataProvider provideLevelsAndMessages
+ */
+ public function testLogsAtAllLevels($level, $message)
+ {
+ $logger = $this->getLogger();
+ $logger->{$level}($message, array('user' => 'Bob'));
+ $logger->log($level, $message, array('user' => 'Bob'));
+
+ $expected = array(
+ $level.' message of level '.$level.' with context: Bob',
+ $level.' message of level '.$level.' with context: Bob',
+ );
+ $this->assertEquals($expected, $this->getLogs());
+ }
+
+ public function provideLevelsAndMessages()
+ {
+ return array(
+ LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'),
+ LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'),
+ LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'),
+ LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'),
+ LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'),
+ LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'),
+ LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'),
+ LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}'),
+ );
+ }
+
+ /**
+ * @expectedException \Psr\Log\InvalidArgumentException
+ */
+ public function testThrowsOnInvalidLevel()
+ {
+ $logger = $this->getLogger();
+ $logger->log('invalid level', 'Foo');
+ }
+
+ public function testContextReplacement()
+ {
+ $logger = $this->getLogger();
+ $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar'));
+
+ $expected = array('info {Message {nothing} Bob Bar a}');
+ $this->assertEquals($expected, $this->getLogs());
+ }
+
+ public function testObjectCastToString()
+ {
+ if (method_exists($this, 'createPartialMock')) {
+ $dummy = $this->createPartialMock('Psr\Log\Test\DummyTest', array('__toString'));
+ } else {
+ $dummy = $this->getMock('Psr\Log\Test\DummyTest', array('__toString'));
+ }
+ $dummy->expects($this->once())
+ ->method('__toString')
+ ->will($this->returnValue('DUMMY'));
+
+ $this->getLogger()->warning($dummy);
+
+ $expected = array('warning DUMMY');
+ $this->assertEquals($expected, $this->getLogs());
+ }
+
+ public function testContextCanContainAnything()
+ {
+ $closed = fopen('php://memory', 'r');
+ fclose($closed);
+
+ $context = array(
+ 'bool' => true,
+ 'null' => null,
+ 'string' => 'Foo',
+ 'int' => 0,
+ 'float' => 0.5,
+ 'nested' => array('with object' => new DummyTest),
+ 'object' => new \DateTime,
+ 'resource' => fopen('php://memory', 'r'),
+ 'closed' => $closed,
+ );
+
+ $this->getLogger()->warning('Crazy context data', $context);
+
+ $expected = array('warning Crazy context data');
+ $this->assertEquals($expected, $this->getLogs());
+ }
+
+ public function testContextExceptionKeyCanBeExceptionOrOtherValues()
+ {
+ $logger = $this->getLogger();
+ $logger->warning('Random message', array('exception' => 'oops'));
+ $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail')));
+
+ $expected = array(
+ 'warning Random message',
+ 'critical Uncaught Exception!'
+ );
+ $this->assertEquals($expected, $this->getLogs());
+ }
+}
+
+class DummyTest
+{
+ public function __toString()
+ {
+ return 'DummyTest';
+ }
+}
diff --git a/akamai/vendor/psr/log/Psr/Log/Test/TestLogger.php b/akamai/vendor/psr/log/Psr/Log/Test/TestLogger.php
new file mode 100644
index 00000000..1be32304
--- /dev/null
+++ b/akamai/vendor/psr/log/Psr/Log/Test/TestLogger.php
@@ -0,0 +1,147 @@
+ $level,
+ 'message' => $message,
+ 'context' => $context,
+ ];
+
+ $this->recordsByLevel[$record['level']][] = $record;
+ $this->records[] = $record;
+ }
+
+ public function hasRecords($level)
+ {
+ return isset($this->recordsByLevel[$level]);
+ }
+
+ public function hasRecord($record, $level)
+ {
+ if (is_string($record)) {
+ $record = ['message' => $record];
+ }
+ return $this->hasRecordThatPasses(function ($rec) use ($record) {
+ if ($rec['message'] !== $record['message']) {
+ return false;
+ }
+ if (isset($record['context']) && $rec['context'] !== $record['context']) {
+ return false;
+ }
+ return true;
+ }, $level);
+ }
+
+ public function hasRecordThatContains($message, $level)
+ {
+ return $this->hasRecordThatPasses(function ($rec) use ($message) {
+ return strpos($rec['message'], $message) !== false;
+ }, $level);
+ }
+
+ public function hasRecordThatMatches($regex, $level)
+ {
+ return $this->hasRecordThatPasses(function ($rec) use ($regex) {
+ return preg_match($regex, $rec['message']) > 0;
+ }, $level);
+ }
+
+ public function hasRecordThatPasses(callable $predicate, $level)
+ {
+ if (!isset($this->recordsByLevel[$level])) {
+ return false;
+ }
+ foreach ($this->recordsByLevel[$level] as $i => $rec) {
+ if (call_user_func($predicate, $rec, $i)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public function __call($method, $args)
+ {
+ if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
+ $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
+ $level = strtolower($matches[2]);
+ if (method_exists($this, $genericMethod)) {
+ $args[] = $level;
+ return call_user_func_array([$this, $genericMethod], $args);
+ }
+ }
+ throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
+ }
+
+ public function reset()
+ {
+ $this->records = [];
+ $this->recordsByLevel = [];
+ }
+}
diff --git a/akamai/vendor/psr/log/README.md b/akamai/vendor/psr/log/README.md
new file mode 100644
index 00000000..a9f20c43
--- /dev/null
+++ b/akamai/vendor/psr/log/README.md
@@ -0,0 +1,58 @@
+PSR Log
+=======
+
+This repository holds all interfaces/classes/traits related to
+[PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md).
+
+Note that this is not a logger of its own. It is merely an interface that
+describes a logger. See the specification for more details.
+
+Installation
+------------
+
+```bash
+composer require psr/log
+```
+
+Usage
+-----
+
+If you need a logger, you can use the interface like this:
+
+```php
+logger = $logger;
+ }
+
+ public function doSomething()
+ {
+ if ($this->logger) {
+ $this->logger->info('Doing work');
+ }
+
+ try {
+ $this->doSomethingElse();
+ } catch (Exception $exception) {
+ $this->logger->error('Oh no!', array('exception' => $exception));
+ }
+
+ // do something useful
+ }
+}
+```
+
+You can then pick one of the implementations of the interface to get a logger.
+
+If you want to implement the interface, you can require this package and
+implement `Psr\Log\LoggerInterface` in your code. Please read the
+[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md)
+for details.
diff --git a/akamai/vendor/psr/log/composer.json b/akamai/vendor/psr/log/composer.json
new file mode 100644
index 00000000..3f6d4eea
--- /dev/null
+++ b/akamai/vendor/psr/log/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "psr/log",
+ "description": "Common interface for logging libraries",
+ "keywords": ["psr", "psr-3", "log"],
+ "homepage": "https://github.com/php-fig/log",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "Psr/Log/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ }
+}
diff --git a/akamai/vendor/ralouphie/getallheaders/LICENSE b/akamai/vendor/ralouphie/getallheaders/LICENSE
new file mode 100644
index 00000000..be5540c2
--- /dev/null
+++ b/akamai/vendor/ralouphie/getallheaders/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Ralph Khattar
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/akamai/vendor/ralouphie/getallheaders/README.md b/akamai/vendor/ralouphie/getallheaders/README.md
new file mode 100644
index 00000000..9430d76b
--- /dev/null
+++ b/akamai/vendor/ralouphie/getallheaders/README.md
@@ -0,0 +1,27 @@
+getallheaders
+=============
+
+PHP `getallheaders()` polyfill. Compatible with PHP >= 5.3.
+
+[](https://travis-ci.org/ralouphie/getallheaders)
+[](https://coveralls.io/r/ralouphie/getallheaders?branch=master)
+[](https://packagist.org/packages/ralouphie/getallheaders)
+[](https://packagist.org/packages/ralouphie/getallheaders)
+[](https://packagist.org/packages/ralouphie/getallheaders)
+
+
+This is a simple polyfill for [`getallheaders()`](http://www.php.net/manual/en/function.getallheaders.php).
+
+## Install
+
+For PHP version **`>= 5.6`**:
+
+```
+composer require ralouphie/getallheaders
+```
+
+For PHP version **`< 5.6`**:
+
+```
+composer require ralouphie/getallheaders "^2"
+```
diff --git a/akamai/vendor/ralouphie/getallheaders/composer.json b/akamai/vendor/ralouphie/getallheaders/composer.json
new file mode 100644
index 00000000..de8ce62e
--- /dev/null
+++ b/akamai/vendor/ralouphie/getallheaders/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "ralouphie/getallheaders",
+ "description": "A polyfill for getallheaders.",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5 || ^6.5",
+ "php-coveralls/php-coveralls": "^2.1"
+ },
+ "autoload": {
+ "files": ["src/getallheaders.php"]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "getallheaders\\Tests\\": "tests/"
+ }
+ }
+}
diff --git a/akamai/vendor/ralouphie/getallheaders/src/getallheaders.php b/akamai/vendor/ralouphie/getallheaders/src/getallheaders.php
new file mode 100644
index 00000000..c7285a5b
--- /dev/null
+++ b/akamai/vendor/ralouphie/getallheaders/src/getallheaders.php
@@ -0,0 +1,46 @@
+ 'Content-Type',
+ 'CONTENT_LENGTH' => 'Content-Length',
+ 'CONTENT_MD5' => 'Content-Md5',
+ );
+
+ foreach ($_SERVER as $key => $value) {
+ if (substr($key, 0, 5) === 'HTTP_') {
+ $key = substr($key, 5);
+ if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) {
+ $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key))));
+ $headers[$key] = $value;
+ }
+ } elseif (isset($copy_server[$key])) {
+ $headers[$copy_server[$key]] = $value;
+ }
+ }
+
+ if (!isset($headers['Authorization'])) {
+ if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
+ $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
+ } elseif (isset($_SERVER['PHP_AUTH_USER'])) {
+ $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
+ $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass);
+ } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
+ $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST'];
+ }
+ }
+
+ return $headers;
+ }
+
+}
diff --git a/akamai/vendor/seld/cli-prompt/.gitignore b/akamai/vendor/seld/cli-prompt/.gitignore
new file mode 100644
index 00000000..42cd73d9
--- /dev/null
+++ b/akamai/vendor/seld/cli-prompt/.gitignore
@@ -0,0 +1 @@
+/vendor/
\ No newline at end of file
diff --git a/akamai/vendor/seld/cli-prompt/LICENSE b/akamai/vendor/seld/cli-prompt/LICENSE
new file mode 100644
index 00000000..c1b62a35
--- /dev/null
+++ b/akamai/vendor/seld/cli-prompt/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 Jordi Boggiano
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/akamai/vendor/seld/cli-prompt/README.md b/akamai/vendor/seld/cli-prompt/README.md
new file mode 100644
index 00000000..d5a046a1
--- /dev/null
+++ b/akamai/vendor/seld/cli-prompt/README.md
@@ -0,0 +1,61 @@
+CLI-Prompt
+==========
+
+While prompting for user input using `fgets()` is quite easy, sometimes you
+need to prompt for sensitive information. In these cases, the characters typed
+in by the user should not be directly visible, and this is quite a pain to
+do in a cross-platform way.
+
+This tiny package fixes just that for you:
+
+```php
+ Prompts the user for input and hides what they type. If this fails for any
+ > reason and `$allowFallback` is set to `true` the prompt will be done using
+ > the usual `fgets()` and characters will be visible.
+
+- `Seld\CliPrompt\CliPrompt::prompt();`
+
+ > Regular user prompt for input with characters being shown on screen.
+
+In both cases, the trailing newline the user enters when submitting the answer
+is trimmed.
+
+Requirements
+------------
+
+PHP 5.3 and above
+
+License
+-------
+
+CLI-Prompt is licensed under the MIT License - see the LICENSE file for details
+
+Acknowledgments
+---------------
+
+- This project uses hiddeninput.exe to prompt for passwords on Windows, sources
+ and details can be found on the [github page of the project](https://github.com/Seldaek/hidden-input).
diff --git a/akamai/vendor/seld/cli-prompt/composer.json b/akamai/vendor/seld/cli-prompt/composer.json
new file mode 100644
index 00000000..e3664379
--- /dev/null
+++ b/akamai/vendor/seld/cli-prompt/composer.json
@@ -0,0 +1,26 @@
+{
+ "name": "seld/cli-prompt",
+ "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type",
+ "type": "library",
+ "keywords": ["cli", "console", "hidden", "input", "prompt"],
+ "license": "MIT",
+ "require": {
+ "php": ">=5.3"
+ },
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "Seld\\CliPrompt\\": "src/"
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ }
+}
diff --git a/akamai/vendor/seld/cli-prompt/res/example.php b/akamai/vendor/seld/cli-prompt/res/example.php
new file mode 100644
index 00000000..5ce5b23f
--- /dev/null
+++ b/akamai/vendor/seld/cli-prompt/res/example.php
@@ -0,0 +1,15 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Seld\CliPrompt;
+
+class CliPrompt
+{
+ /**
+ * Prompts the user for input and shows what they type
+ *
+ * @return string
+ */
+ public static function prompt()
+ {
+ $stdin = fopen('php://stdin', 'r');
+ $answer = self::trimAnswer(fgets($stdin, 4096));
+ fclose($stdin);
+
+ return $answer;
+ }
+
+ /**
+ * Prompts the user for input and hides what they type
+ *
+ * @param bool $allowFallback If prompting fails for any reason and this is set to true the prompt
+ * will be done using the regular prompt() function, otherwise a
+ * \RuntimeException is thrown.
+ * @return string
+ * @throws RuntimeException on failure to prompt, unless $allowFallback is true
+ */
+ public static function hiddenPrompt($allowFallback = false)
+ {
+ // handle windows
+ if (defined('PHP_WINDOWS_VERSION_BUILD')) {
+ // fallback to hiddeninput executable
+ $exe = __DIR__.'\\..\\res\\hiddeninput.exe';
+
+ // handle code running from a phar
+ if ('phar:' === substr(__FILE__, 0, 5)) {
+ $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
+
+ // use stream_copy_to_stream instead of copy
+ // to work around https://bugs.php.net/bug.php?id=64634
+ $source = fopen($exe, 'r');
+ $target = fopen($tmpExe, 'w+');
+ stream_copy_to_stream($source, $target);
+ fclose($source);
+ fclose($target);
+ unset($source, $target);
+
+ $exe = $tmpExe;
+ }
+
+ $output = shell_exec($exe);
+
+ // clean up
+ if (isset($tmpExe)) {
+ unlink($tmpExe);
+ }
+
+ if ($output !== null) {
+ // output a newline to be on par with the regular prompt()
+ echo PHP_EOL;
+
+ return self::trimAnswer($output);
+ }
+ }
+
+ if (file_exists('/usr/bin/env')) {
+ // handle other OSs with bash/zsh/ksh/csh if available to hide the answer
+ $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
+ foreach (array('bash', 'zsh', 'ksh', 'csh', 'sh') as $sh) {
+ if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
+ $shell = $sh;
+ break;
+ }
+ }
+
+ if (isset($shell)) {
+ $readCmd = ($shell === 'csh') ? 'set mypassword = $<' : 'read -r mypassword';
+ $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
+ $output = shell_exec($command);
+
+ if ($output !== null) {
+ // output a newline to be on par with the regular prompt()
+ echo PHP_EOL;
+
+ return self::trimAnswer($output);
+ }
+ }
+ }
+
+ // not able to hide the answer
+ if (!$allowFallback) {
+ throw new \RuntimeException('Could not prompt for input in a secure fashion, aborting');
+ }
+
+ return self::prompt();
+ }
+
+ private static function trimAnswer($str)
+ {
+ return preg_replace('{\r?\n$}D', '', $str);
+ }
+}
diff --git a/application/views/bootstrap3/footer.php b/application/views/bootstrap3/footer.php
index 796427df..d06e86d9 100644
--- a/application/views/bootstrap3/footer.php
+++ b/application/views/bootstrap3/footer.php
@@ -19,7 +19,7 @@