From 1fda22c9654f022bf1f2f545e67828e2c339113d Mon Sep 17 00:00:00 2001
From: David Maus <maus@hab.de>
Date: Thu, 19 Apr 2018 13:08:04 +0200
Subject: [PATCH] Verwende willdurand/negotiation

---
 .gitmodules                                   |   3 +
 composer.json                                 |   3 +-
 composer.lock                                 |  54 ++++-
 vendor/composer/autoload_psr4.php             |   1 +
 vendor/composer/autoload_static.php           |   8 +
 vendor/composer/installed.json                |  54 +++++
 vendor/willdurand/negotiation/.gitignore      |   2 +
 vendor/willdurand/negotiation/.travis.yml     |  19 ++
 vendor/willdurand/negotiation/CONTRIBUTING.md |  33 +++
 vendor/willdurand/negotiation/LICENSE         |  19 ++
 vendor/willdurand/negotiation/README.md       | 162 +++++++++++++++
 vendor/willdurand/negotiation/appveyor.yml    |  30 +++
 vendor/willdurand/negotiation/composer.json   |  27 +++
 .../willdurand/negotiation/phpunit.xml.dist   |  23 +++
 .../src/Negotiation/AbstractNegotiator.php    | 118 +++++++++++
 .../negotiation/src/Negotiation/Accept.php    |  46 +++++
 .../src/Negotiation/AcceptCharset.php         |   7 +
 .../src/Negotiation/AcceptEncoding.php        |   7 +
 .../src/Negotiation/AcceptHeader.php          |   7 +
 .../src/Negotiation/AcceptLanguage.php        |  49 +++++
 .../src/Negotiation/BaseAccept.php            | 154 ++++++++++++++
 .../src/Negotiation/CharsetNegotiator.php     |  14 ++
 .../src/Negotiation/EncodingNegotiator.php    |  14 ++
 .../src/Negotiation/Exception/Exception.php   |   7 +
 .../Negotiation/Exception/InvalidArgument.php |   7 +
 .../Negotiation/Exception/InvalidHeader.php   |   7 +
 .../Negotiation/Exception/InvalidLanguage.php |   7 +
 .../Exception/InvalidMediaType.php            |   7 +
 .../src/Negotiation/LanguageNegotiator.php    |  41 ++++
 .../negotiation/src/Negotiation/Match.php     |  62 ++++++
 .../src/Negotiation/Negotiator.php            |  89 ++++++++
 .../Negotiation/Tests/AcceptLanguageTest.php  |  52 +++++
 .../tests/Negotiation/Tests/AcceptTest.php    |  86 ++++++++
 .../Negotiation/Tests/BaseAcceptTest.php      |  84 ++++++++
 .../Tests/CharsetNegotiatorTest.php           | 121 +++++++++++
 .../Tests/EncodingNegotiatorTest.php          |  76 +++++++
 .../Tests/LanguageNegotiatorTest.php          |  81 ++++++++
 .../tests/Negotiation/Tests/MatchTest.php     |  56 +++++
 .../Negotiation/Tests/NegotiatorTest.php      | 195 ++++++++++++++++++
 .../tests/Negotiation/Tests/TestCase.php      |  15 ++
 .../negotiation/tests/bootstrap.php           |  15 ++
 41 files changed, 1860 insertions(+), 2 deletions(-)
 create mode 100644 .gitmodules
 create mode 100644 vendor/willdurand/negotiation/.gitignore
 create mode 100644 vendor/willdurand/negotiation/.travis.yml
 create mode 100644 vendor/willdurand/negotiation/CONTRIBUTING.md
 create mode 100644 vendor/willdurand/negotiation/LICENSE
 create mode 100644 vendor/willdurand/negotiation/README.md
 create mode 100644 vendor/willdurand/negotiation/appveyor.yml
 create mode 100644 vendor/willdurand/negotiation/composer.json
 create mode 100644 vendor/willdurand/negotiation/phpunit.xml.dist
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/AbstractNegotiator.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Accept.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/AcceptCharset.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/AcceptEncoding.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/AcceptHeader.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/AcceptLanguage.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/BaseAccept.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/CharsetNegotiator.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/EncodingNegotiator.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Exception/Exception.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidArgument.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidHeader.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidLanguage.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidMediaType.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/LanguageNegotiator.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Match.php
 create mode 100644 vendor/willdurand/negotiation/src/Negotiation/Negotiator.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptLanguageTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/BaseAcceptTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/CharsetNegotiatorTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/EncodingNegotiatorTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/LanguageNegotiatorTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/MatchTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/NegotiatorTest.php
 create mode 100644 vendor/willdurand/negotiation/tests/Negotiation/Tests/TestCase.php
 create mode 100644 vendor/willdurand/negotiation/tests/bootstrap.php

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..909f8d85f
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "vendor\\pica2mods"]
+	path = vendor\\pica2mods
+	url = https://github.com/dmj/pica2mods.git
diff --git a/composer.json b/composer.json
index 86ac1c844..6234bd579 100644
--- a/composer.json
+++ b/composer.json
@@ -3,6 +3,7 @@
         "symfony/http-foundation": "^3.4",
         "hab/picarecord": "^1.1",
         "hab/picareader": "^1.2",
-        "hab/picawriter": "^1.0"
+        "hab/picawriter": "^1.0",
+        "willdurand/negotiation": "^2.3"
     }
 }
diff --git a/composer.lock b/composer.lock
index 06f673931..30ec0a181 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "7b4e0ab48493485011f66d6e7fc1e6b2",
+    "content-hash": "d60aaa0891d9bd50b170b054a1e81a63",
     "packages": [
         {
             "name": "hab/picareader",
@@ -333,6 +333,58 @@
                 "shim"
             ],
             "time": "2018-01-30T19:27:44+00:00"
+        },
+        {
+            "name": "willdurand/negotiation",
+            "version": "v2.3.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/willdurand/Negotiation.git",
+                "reference": "03436ededa67c6e83b9b12defac15384cb399dc9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/03436ededa67c6e83b9b12defac15384cb399dc9",
+                "reference": "03436ededa67c6e83b9b12defac15384cb399dc9",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~4.5"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Negotiation\\": "src/Negotiation"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "William Durand",
+                    "email": "will+git@drnd.me"
+                }
+            ],
+            "description": "Content Negotiation tools for PHP provided as a standalone library.",
+            "homepage": "http://williamdurand.fr/Negotiation/",
+            "keywords": [
+                "accept",
+                "content",
+                "format",
+                "header",
+                "negotiation"
+            ],
+            "time": "2017-05-14T17:21:12+00:00"
         }
     ],
     "packages-dev": [],
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
index f9ff74ebe..0348a818e 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -9,4 +9,5 @@ return array(
     'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'),
     'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
     'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
+    'Negotiation\\' => array($vendorDir . '/willdurand/negotiation/src/Negotiation'),
 );
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index 207e20e69..545298306 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -19,6 +19,10 @@ class ComposerStaticInit78daec5e1761b48dba06a78068db3ccf
             'Symfony\\Polyfill\\Mbstring\\' => 26,
             'Symfony\\Component\\HttpFoundation\\' => 33,
         ),
+        'N' => 
+        array (
+            'Negotiation\\' => 12,
+        ),
     );
 
     public static $prefixDirsPsr4 = array (
@@ -34,6 +38,10 @@ class ComposerStaticInit78daec5e1761b48dba06a78068db3ccf
         array (
             0 => __DIR__ . '/..' . '/symfony/http-foundation',
         ),
+        'Negotiation\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/willdurand/negotiation/src/Negotiation',
+        ),
     );
 
     public static $prefixesPsr0 = array (
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index ddc76dc70..343b63b24 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -340,5 +340,59 @@
             "portable",
             "shim"
         ]
+    },
+    {
+        "name": "willdurand/negotiation",
+        "version": "v2.3.1",
+        "version_normalized": "2.3.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/willdurand/Negotiation.git",
+            "reference": "03436ededa67c6e83b9b12defac15384cb399dc9"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/03436ededa67c6e83b9b12defac15384cb399dc9",
+            "reference": "03436ededa67c6e83b9b12defac15384cb399dc9",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.4.0"
+        },
+        "require-dev": {
+            "phpunit/phpunit": "~4.5"
+        },
+        "time": "2017-05-14T17:21:12+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.3-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Negotiation\\": "src/Negotiation"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "William Durand",
+                "email": "will+git@drnd.me"
+            }
+        ],
+        "description": "Content Negotiation tools for PHP provided as a standalone library.",
+        "homepage": "http://williamdurand.fr/Negotiation/",
+        "keywords": [
+            "accept",
+            "content",
+            "format",
+            "header",
+            "negotiation"
+        ]
     }
 ]
diff --git a/vendor/willdurand/negotiation/.gitignore b/vendor/willdurand/negotiation/.gitignore
new file mode 100644
index 000000000..3a9875b46
--- /dev/null
+++ b/vendor/willdurand/negotiation/.gitignore
@@ -0,0 +1,2 @@
+/vendor/
+composer.lock
diff --git a/vendor/willdurand/negotiation/.travis.yml b/vendor/willdurand/negotiation/.travis.yml
new file mode 100644
index 000000000..d4eacb7e3
--- /dev/null
+++ b/vendor/willdurand/negotiation/.travis.yml
@@ -0,0 +1,19 @@
+sudo: false
+language: php
+
+php:
+    - 5.4
+    - 5.5
+    - 5.6
+    - 7.0
+    - hhvm
+
+matrix:
+    allow_failures:
+        - php: hhvm
+
+before_script:
+    - composer self-update
+    - composer install --prefer-dist --no-interaction
+
+script: phpunit --coverage-text
diff --git a/vendor/willdurand/negotiation/CONTRIBUTING.md b/vendor/willdurand/negotiation/CONTRIBUTING.md
new file mode 100644
index 000000000..3677a2cf0
--- /dev/null
+++ b/vendor/willdurand/negotiation/CONTRIBUTING.md
@@ -0,0 +1,33 @@
+Contributing
+============
+
+First of all, **thank you** for contributing, **you are awesome**!
+
+Here are a few rules to follow in order to ease code reviews, and discussions before
+maintainers accept and merge your work.
+
+You MUST follow the [PSR-1](http://www.php-fig.org/psr/1/) and
+[PSR-2](http://www.php-fig.org/psr/2/). If you don't know about any of them, you
+should really read the recommendations. Can't wait? Use the [PHP-CS-Fixer
+tool](http://cs.sensiolabs.org/).
+
+You MUST run the test suite.
+
+You MUST write (or update) unit tests.
+
+You SHOULD write documentation.
+
+Please, write [commit messages that make
+sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
+and [rebase your branch](http://git-scm.com/book/en/Git-Branching-Rebasing)
+before submitting your Pull Request.
+
+One may ask you to [squash your
+commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html)
+too. This is used to "clean" your Pull Request before merging it (we don't want
+commits such as `fix tests`, `fix 2`, `fix 3`, etc.).
+
+Also, while creating your Pull Request on GitHub, you MUST write a description
+which gives the context and/or explains why you are creating it.
+
+Thank you!
diff --git a/vendor/willdurand/negotiation/LICENSE b/vendor/willdurand/negotiation/LICENSE
new file mode 100644
index 000000000..3546ac1b5
--- /dev/null
+++ b/vendor/willdurand/negotiation/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) William Durand <will+git@drnd.me>
+
+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/vendor/willdurand/negotiation/README.md b/vendor/willdurand/negotiation/README.md
new file mode 100644
index 000000000..1e7032fbb
--- /dev/null
+++ b/vendor/willdurand/negotiation/README.md
@@ -0,0 +1,162 @@
+Negotiation
+===========
+
+[![Build
+Status](https://travis-ci.org/willdurand/Negotiation.png?branch=master)](http://travis-ci.org/willdurand/Negotiation)
+[![Build
+status](https://ci.appveyor.com/api/projects/status/6tbe8j3gofdlfm4v?svg=true)](https://ci.appveyor.com/project/willdurand/negotiation)
+[![Total
+Downloads](https://poser.pugx.org/willdurand/Negotiation/downloads.png)](https://packagist.org/packages/willdurand/Negotiation)
+[![Latest Stable
+Version](https://poser.pugx.org/willdurand/Negotiation/v/stable.png)](https://packagist.org/packages/willdurand/Negotiation)
+![PHP 7 ready](https://img.shields.io/badge/PHP%207-ready-green.svg)
+
+**Negotiation** is a standalone library without any dependencies that allows you
+to implement [content
+negotiation](https://tools.ietf.org/html/rfc7231#section-5.3) in your
+application, whatever framework you use.  This library is based on [RFC
+7231](https://tools.ietf.org/html/rfc7231). Negotiation is easy to use, and
+extensively unit tested!
+
+> **Important:** You are browsing the documentation of Negotiation **2.x**.
+Documentation for version **1.x** is available here: [Negotiation 1.x
+documentation](https://github.com/willdurand/Negotiation/blob/1.x/README.md#usage).
+You might also be interested in this: [**What's new in Negotiation 2?**](https://github.com/willdurand/Negotiation/releases/tag/v2.0.0-alpha1)
+
+
+Installation
+------------
+
+The recommended way to install Negotiation is through
+[Composer](http://getcomposer.org/):
+
+```bash
+$ composer require willdurand/negotiation
+```
+
+
+Usage Examples
+--------------
+
+### Media Type Negotiation
+
+``` php
+$negotiator = new \Negotiation\Negotiator();
+
+$acceptHeader = 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8';
+$priorities   = array('text/html; charset=UTF-8', 'application/json', 'application/xml;q=0.5');
+
+$mediaType = $negotiator->getBest($acceptHeader, $priorities);
+
+$value = $mediaType->getValue();
+// $value == 'text/html; charset=UTF-8'
+```
+
+The `Negotiator` returns an instance of `Accept`, or `null` if negotiating the
+best media type has failed.
+
+### Language Negotiation
+
+``` php
+<?php
+
+$negotiator = new \Negotiation\LanguageNegotiator();
+
+$acceptLangageHeader = 'en; q=0.1, fr; q=0.4, fu; q=0.9, de; q=0.2';
+$priorities          = array('de', 'fu', 'en');
+
+$bestLanguage = $negotiator->getBest($acceptLangageHeader, $priorities);
+
+$type = $bestLanguage->getType();
+// $type == 'fu';
+
+$quality = $bestLanguage->getQuality();
+// $quality == 0.9
+```
+
+The `LanguageNegotiator` returns an instance of `AcceptLanguage`.
+
+### Encoding Negotiation
+
+``` php
+<?php
+
+$negotiator = new \Negotiation\EncodingNegotiator();
+$encoding   = $negotiator->getBest($acceptHeader, $priorities);
+```
+
+The `EncodingNegotiator` returns an instance of `AcceptEncoding`.
+
+### Charset Negotiation
+
+``` php
+<?php
+
+$negotiator = new \Negotiation\CharsetNegotiator();
+
+$acceptCharsetHeader = 'ISO-8859-1, UTF-8; q=0.9';
+$priorities          = array('iso-8859-1;q=0.3', 'utf-8;q=0.9', 'utf-16;q=1.0');  
+
+$bestCharset = $negotiator->getBest($acceptCharsetHeader, $priorities);
+
+$type = $bestCharset->getType();
+// $type == 'utf-8';
+
+$quality = $bestCharset->getQuality();
+// $quality == 0.81
+```
+
+The `CharsetNegotiator` returns an instance of `AcceptCharset`.
+
+### `Accept*` Classes
+
+`Accept` and `Accept*` classes share common methods such as:
+
+* `getValue()` returns the accept value (e.g. `text/html; z=y; a=b; c=d`)
+* `getNormalizedValue()` returns the value with parameters sorted (e.g.
+  `text/html; a=b; c=d; z=y`)
+* `getQuality()` returns the quality if available (`q` parameter)
+* `getType()` returns the accept type (e.g. `text/html`)
+* `getParameters()` returns the set of parameters (excluding the `q` parameter
+  if provided)
+* `getParameter()` allows to retrieve a given parameter by its name. Fallback to
+  a `$default` (nullable) value otherwise.
+* `hasParameter()` indicates whether a parameter exists.
+
+
+Unit Tests
+----------
+
+Setup the test suite using Composer:
+
+    $ composer install --dev
+
+Run it using PHPUnit:
+
+    $ phpunit
+
+
+Contributing
+------------
+
+See [CONTRIBUTING](CONTRIBUTING.md) file.
+
+
+Credits
+-------
+
+* Some parts of this library are inspired by:
+
+    * [Symfony](http://github.com/symfony/symfony) framework;
+    * [FOSRest](http://github.com/FriendsOfSymfony/FOSRest);
+    * [PEAR HTTP2](https://github.com/pear/HTTP2).
+
+* William Durand <will+git@drnd.me>
+* [@neural-wetware](https://github.com/neural-wetware)
+
+
+License
+-------
+
+Negotiation is released under the MIT License. See the bundled LICENSE file for
+details.
diff --git a/vendor/willdurand/negotiation/appveyor.yml b/vendor/willdurand/negotiation/appveyor.yml
new file mode 100644
index 000000000..7280bcce5
--- /dev/null
+++ b/vendor/willdurand/negotiation/appveyor.yml
@@ -0,0 +1,30 @@
+build: false
+shallow_clone: true
+platform: x86
+clone_folder: c:\projects\willdurand\negotiation
+
+cache:
+  - '%LOCALAPPDATA%\Composer\files'
+
+init:
+  - SET PATH=C:\Program Files\OpenSSL;c:\tools\php;c:\tools\php71;%PATH%
+
+install:
+  - ps: Set-Service wuauserv -StartupType Manual
+  - cinst -y OpenSSL.Light
+  - cinst -y php
+  - cd c:\tools\php71
+  - copy php.ini-production php.ini /Y
+  - echo date.timezone="UTC" >> php.ini
+  - echo extension_dir=ext >> php.ini
+  - echo extension=php_openssl.dll >> php.ini
+  - echo extension=php_mbstring.dll >> php.ini
+  - echo extension=php_fileinfo.dll >> php.ini
+  - echo memory_limit=1G >> php.ini
+  - cd c:\projects\willdurand\negotiation
+  - php -r "readfile('http://getcomposer.org/installer');" | php
+  - php composer.phar update --no-interaction --no-progress
+
+test_script:
+  - cd c:\projects\willdurand\negotiation
+  - vendor\bin\phpunit.bat --verbose
diff --git a/vendor/willdurand/negotiation/composer.json b/vendor/willdurand/negotiation/composer.json
new file mode 100644
index 000000000..6418b4181
--- /dev/null
+++ b/vendor/willdurand/negotiation/composer.json
@@ -0,0 +1,27 @@
+{
+    "name": "willdurand/negotiation",
+    "description": "Content Negotiation tools for PHP provided as a standalone library.",
+    "keywords": [ "content", "negotiation", "format", "accept", "header" ],
+    "license": "MIT",
+    "homepage": "http://williamdurand.fr/Negotiation/",
+    "authors": [
+        {
+            "name": "William Durand",
+            "email": "will+git@drnd.me"
+        }
+    ],
+    "require": {
+        "php": ">=5.4.0"
+    },
+    "autoload": {
+        "psr-4": { "Negotiation\\": "src/Negotiation" }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.3-dev"
+        }
+    },
+    "require-dev": {
+        "phpunit/phpunit": "~4.5"
+    }
+}
diff --git a/vendor/willdurand/negotiation/phpunit.xml.dist b/vendor/willdurand/negotiation/phpunit.xml.dist
new file mode 100644
index 000000000..ac6f0f92e
--- /dev/null
+++ b/vendor/willdurand/negotiation/phpunit.xml.dist
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit backupGlobals="false"
+    backupStaticAttributes="false"
+    colors="true"
+    convertErrorsToExceptions="true"
+    convertNoticesToExceptions="true"
+    convertWarningsToExceptions="true"
+    processIsolation="false"
+    stopOnFailure="false"
+    syntaxCheck="false"
+    bootstrap="tests/bootstrap.php"
+    >
+    <testsuites>
+        <testsuite name="Negotiation Test Suite">
+            <directory>./tests/</directory>
+        </testsuite>
+    </testsuites>
+    <filter>
+        <whitelist>
+            <directory>./src/Negotiation/</directory>
+        </whitelist>
+    </filter>
+</phpunit>
diff --git a/vendor/willdurand/negotiation/src/Negotiation/AbstractNegotiator.php b/vendor/willdurand/negotiation/src/Negotiation/AbstractNegotiator.php
new file mode 100644
index 000000000..2cd839e53
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/AbstractNegotiator.php
@@ -0,0 +1,118 @@
+<?php
+
+namespace Negotiation;
+
+use Negotiation\Exception\InvalidArgument;
+use Negotiation\Exception\InvalidHeader;
+
+abstract class AbstractNegotiator
+{
+    /**
+     * @param string $header     A string containing an `Accept|Accept-*` header.
+     * @param array  $priorities A set of server priorities.
+     *
+     * @return AcceptHeader|null best matching type
+     */
+    public function getBest($header, array $priorities)
+    {
+        if (empty($priorities)) {
+            throw new InvalidArgument('A set of server priorities should be given.');
+        }
+
+        if (!$header) {
+            throw new InvalidArgument('The header string should not be empty.');
+        }
+
+        // Once upon a time, two `array_map` calls were sitting there, but for
+        // some reasons, they triggered `E_WARNING` time to time (because of
+        // PHP bug [55416](https://bugs.php.net/bug.php?id=55416). Now, they
+        // are gone.
+        // See: https://github.com/willdurand/Negotiation/issues/81
+        $acceptedHeaders = array();
+        foreach ($this->parseHeader($header) as $h) {
+            try {
+                $acceptedHeaders[] = $this->acceptFactory($h);
+            } catch (Exception\Exception $e) {
+                // silently skip in case of invalid headers coming in from a client
+            }
+        }
+        $acceptedPriorities = array();
+        foreach ($priorities as $p) {
+            $acceptedPriorities[] = $this->acceptFactory($p);
+        }
+        $matches         = $this->findMatches($acceptedHeaders, $acceptedPriorities);
+        $specificMatches = array_reduce($matches, 'Negotiation\Match::reduce', []);
+
+        usort($specificMatches, 'Negotiation\Match::compare');
+
+        $match = array_shift($specificMatches);
+
+        return null === $match ? null : $acceptedPriorities[$match->index];
+    }
+
+    /**
+     * @param string $header accept header part or server priority
+     *
+     * @return AcceptHeader Parsed header object
+     */
+    abstract protected function acceptFactory($header);
+
+    /**
+     * @param AcceptHeader $header
+     * @param AcceptHeader $priority
+     * @param integer      $index
+     *
+     * @return Match|null Headers matched
+     */
+    protected function match(AcceptHeader $header, AcceptHeader $priority, $index)
+    {
+        $ac = $header->getType();
+        $pc = $priority->getType();
+
+        $equal = !strcasecmp($ac, $pc);
+
+        if ($equal || $ac === '*') {
+            $score = 1 * $equal;
+
+            return new Match($header->getQuality() * $priority->getQuality(), $score, $index);
+        }
+
+        return null;
+    }
+
+    /**
+     * @param string $header A string that contains an `Accept*` header.
+     *
+     * @return AcceptHeader[]
+     */
+    private function parseHeader($header)
+    {
+        $res = preg_match_all('/(?:[^,"]*+(?:"[^"]*+")?)+[^,"]*+/', $header, $matches);
+
+        if (!$res) {
+            throw new InvalidHeader(sprintf('Failed to parse accept header: "%s"', $header));
+        }
+
+        return array_values(array_filter(array_map('trim', $matches[0])));
+    }
+
+    /**
+     * @param AcceptHeader[] $headerParts
+     * @param Priority[]     $priorities  Configured priorities
+     *
+     * @return Match[] Headers matched
+     */
+    private function findMatches(array $headerParts, array $priorities)
+    {
+        $matches = [];
+        foreach ($priorities as $index => $p) {
+            foreach ($headerParts as $h) {
+                if (null !== $match = $this->match($h, $p, $index)) {
+                    $matches[] = $match;
+                }
+            }
+        }
+
+        return $matches;
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Accept.php b/vendor/willdurand/negotiation/src/Negotiation/Accept.php
new file mode 100644
index 000000000..281ae27d7
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Accept.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Negotiation;
+
+use Negotiation\Exception\InvalidMediaType;
+
+final class Accept extends BaseAccept implements AcceptHeader
+{
+    private $basePart;
+
+    private $subPart;
+
+    public function __construct($value)
+    {
+        parent::__construct($value);
+
+        if ($this->type === '*') {
+            $this->type = '*/*';
+        }
+
+        $parts = explode('/', $this->type);
+
+        if (count($parts) !== 2 || !$parts[0] || !$parts[1]) {
+            throw new InvalidMediaType();
+        }
+
+        $this->basePart = $parts[0];
+        $this->subPart  = $parts[1];
+    }
+
+    /**
+     * @return string
+     */
+    public function getSubPart()
+    {
+        return $this->subPart;
+    }
+
+    /**
+     * @return string
+     */
+    public function getBasePart()
+    {
+        return $this->basePart;
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/AcceptCharset.php b/vendor/willdurand/negotiation/src/Negotiation/AcceptCharset.php
new file mode 100644
index 000000000..7ce34908e
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/AcceptCharset.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation;
+
+final class AcceptCharset extends BaseAccept implements AcceptHeader
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/AcceptEncoding.php b/vendor/willdurand/negotiation/src/Negotiation/AcceptEncoding.php
new file mode 100644
index 000000000..8165a7f85
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/AcceptEncoding.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation;
+
+final class AcceptEncoding extends BaseAccept implements AcceptHeader
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/AcceptHeader.php b/vendor/willdurand/negotiation/src/Negotiation/AcceptHeader.php
new file mode 100644
index 000000000..3f5f8c579
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/AcceptHeader.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation;
+
+interface AcceptHeader
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/AcceptLanguage.php b/vendor/willdurand/negotiation/src/Negotiation/AcceptLanguage.php
new file mode 100644
index 000000000..ad1c03236
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/AcceptLanguage.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Negotiation;
+
+use Negotiation\Exception\InvalidLanguage;
+
+final class AcceptLanguage extends BaseAccept implements AcceptHeader
+{
+    private $language;
+    private $script;
+    private $region;
+
+    public function __construct($value)
+    {
+        parent::__construct($value);
+
+        $parts = explode('-', $this->type);
+
+        if (2 === count($parts)) {
+            $this->language = $parts[0];
+            $this->region   = $parts[1];
+        } elseif (1 === count($parts)) {
+            $this->language = $parts[0];
+        } elseif (3 === count($parts)) {
+            $this->language = $parts[0];
+            $this->script   = $parts[1];
+            $this->region   = $parts[2];
+        } else {
+            // TODO: this part is never reached...
+            throw new InvalidLanguage();
+        }
+    }
+
+    /**
+     * @return string
+     */
+    public function getSubPart()
+    {
+        return $this->region;
+    }
+
+    /**
+     * @return string
+     */
+    public function getBasePart()
+    {
+        return $this->language;
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/BaseAccept.php b/vendor/willdurand/negotiation/src/Negotiation/BaseAccept.php
new file mode 100644
index 000000000..3c584479c
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/BaseAccept.php
@@ -0,0 +1,154 @@
+<?php
+
+namespace Negotiation;
+
+abstract class BaseAccept
+{
+    /**
+     * @var float
+     */
+    private $quality = 1.0;
+
+    /**
+     * @var string
+     */
+    private $normalized;
+
+    /**
+     * @var string
+     */
+    private $value;
+
+    /**
+     * @var array
+     */
+    private $parameters;
+
+    /**
+     * @var string
+     */
+    protected $type;
+
+    /**
+     * @param string $value
+     */
+    public function __construct($value)
+    {
+        list($type, $parameters) = $this->parseParameters($value);
+
+        if (isset($parameters['q'])) {
+            $this->quality = (float) $parameters['q'];
+            unset($parameters['q']);
+        }
+
+        $type = trim(strtolower($type));
+
+        $this->value      = $value;
+        $this->normalized = $type . ($parameters ? "; " . $this->buildParametersString($parameters) : '');
+        $this->type       = $type;
+        $this->parameters = $parameters;
+    }
+
+    /**
+     * @return string
+     */
+    public function getNormalizedValue()
+    {
+        return $this->normalized;
+    }
+
+    /**
+     * @return string
+     */
+    public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * @return float
+     */
+    public function getQuality()
+    {
+        return $this->quality;
+    }
+
+    /**
+     * @return array
+     */
+    public function getParameters()
+    {
+        return $this->parameters;
+    }
+
+    /**
+     * @param string $key
+     * @param mixed  $default
+     *
+     * @return string|null
+     */
+    public function getParameter($key, $default = null)
+    {
+        return isset($this->parameters[$key]) ? $this->parameters[$key] : $default;
+    }
+
+    /**
+     * @param string $key
+     *
+     * @return boolean
+     */
+    public function hasParameter($key)
+    {
+        return isset($this->parameters[$key]);
+    }
+
+    /**
+     *
+     * @param  string $acceptPart
+     * @return array
+     */
+    private function parseParameters($acceptPart)
+    {
+        $parts = explode(';', $acceptPart);
+        $type  = array_shift($parts);
+
+        $parameters = [];
+        foreach ($parts as $part) {
+            $part = explode('=', $part);
+
+            if (2 !== count($part)) {
+                continue; // TODO: throw exception here?
+            }
+
+            $key = strtolower(trim($part[0])); // TODO: technically not allowed space around "=". throw exception?
+            $parameters[$key] = trim($part[1], ' "');
+        }
+
+        return [ $type, $parameters ];
+    }
+
+    /**
+     * @param string $parameters
+     *
+     * @return string
+     */
+    private function buildParametersString($parameters)
+    {
+        $parts = [];
+
+        ksort($parameters);
+        foreach ($parameters as $key => $val) {
+            $parts[] = sprintf('%s=%s', $key, $val);
+        }
+
+        return implode('; ', $parts);
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/CharsetNegotiator.php b/vendor/willdurand/negotiation/src/Negotiation/CharsetNegotiator.php
new file mode 100644
index 000000000..c1f9a4b66
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/CharsetNegotiator.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Negotiation;
+
+class CharsetNegotiator extends AbstractNegotiator
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function acceptFactory($accept)
+    {
+        return new AcceptCharset($accept);
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/EncodingNegotiator.php b/vendor/willdurand/negotiation/src/Negotiation/EncodingNegotiator.php
new file mode 100644
index 000000000..6b97fb738
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/EncodingNegotiator.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Negotiation;
+
+class EncodingNegotiator extends AbstractNegotiator
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function acceptFactory($accept)
+    {
+        return new AcceptEncoding($accept);
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Exception/Exception.php b/vendor/willdurand/negotiation/src/Negotiation/Exception/Exception.php
new file mode 100644
index 000000000..aca5d784a
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Exception/Exception.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation\Exception;
+
+interface Exception
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidArgument.php b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidArgument.php
new file mode 100644
index 000000000..c84e7e486
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidArgument.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation\Exception;
+
+class InvalidArgument extends \InvalidArgumentException implements Exception
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidHeader.php b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidHeader.php
new file mode 100644
index 000000000..eed3efe82
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidHeader.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation\Exception;
+
+class InvalidHeader extends \RuntimeException implements Exception
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidLanguage.php b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidLanguage.php
new file mode 100644
index 000000000..2285a7144
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidLanguage.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation\Exception;
+
+class InvalidLanguage extends \RuntimeException implements Exception
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidMediaType.php b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidMediaType.php
new file mode 100644
index 000000000..6c6a47997
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Exception/InvalidMediaType.php
@@ -0,0 +1,7 @@
+<?php
+
+namespace Negotiation\Exception;
+
+class InvalidMediaType extends \RuntimeException implements Exception
+{
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/LanguageNegotiator.php b/vendor/willdurand/negotiation/src/Negotiation/LanguageNegotiator.php
new file mode 100644
index 000000000..ac9381403
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/LanguageNegotiator.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Negotiation;
+
+class LanguageNegotiator extends AbstractNegotiator
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function acceptFactory($accept)
+    {
+        return new AcceptLanguage($accept);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function match(AcceptHeader $acceptLanguage, AcceptHeader $priority, $index)
+    {
+        if (!$acceptLanguage instanceof AcceptLanguage || !$priority instanceof AcceptLanguage) {
+            return null;
+        }
+
+        $ab = $acceptLanguage->getBasePart();
+        $pb = $priority->getBasePart();
+
+        $as = $acceptLanguage->getSubPart();
+        $ps = $priority->getSubPart();
+
+        $baseEqual = !strcasecmp($ab, $pb);
+        $subEqual  = !strcasecmp($as, $ps);
+
+        if (($ab == '*' || $baseEqual) && ($as === null || $subEqual)) {
+            $score = 10 * $baseEqual + $subEqual;
+
+            return new Match($acceptLanguage->getQuality() * $priority->getQuality(), $score, $index);
+        }
+
+        return null;
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Match.php b/vendor/willdurand/negotiation/src/Negotiation/Match.php
new file mode 100644
index 000000000..5b0e014e2
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Match.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Negotiation;
+
+final class Match
+{
+    /**
+     * @var float
+     */
+    public $quality;
+
+    /**
+     * @var int
+     */
+    public $score;
+
+    /**
+     * @var int
+     */
+    public $index;
+
+    public function __construct($quality, $score, $index)
+    {
+        $this->quality = $quality;
+        $this->score   = $score;
+        $this->index   = $index;
+    }
+
+    /**
+     * @param Match $a
+     * @param Match $b
+     *
+     * @return int
+     */
+    public static function compare(Match $a, Match $b)
+    {
+        if ($a->quality !== $b->quality) {
+            return $a->quality > $b->quality ? -1 : 1;
+        }
+
+        if ($a->index !== $b->index) {
+            return $a->index > $b->index ? 1 : -1;
+        }
+
+        return 0;
+    }
+
+    /**
+     * @param array $carry reduced array
+     * @param Match $match match to be reduced
+     *
+     * @return Match[]
+     */
+    public static function reduce(array $carry, Match $match)
+    {
+        if (!isset($carry[$match->index]) || $carry[$match->index]->score < $match->score) {
+            $carry[$match->index] = $match;
+        }
+
+        return $carry;
+    }
+}
diff --git a/vendor/willdurand/negotiation/src/Negotiation/Negotiator.php b/vendor/willdurand/negotiation/src/Negotiation/Negotiator.php
new file mode 100644
index 000000000..d083fa1e0
--- /dev/null
+++ b/vendor/willdurand/negotiation/src/Negotiation/Negotiator.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Negotiation;
+
+class Negotiator extends AbstractNegotiator
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function acceptFactory($accept)
+    {
+        return new Accept($accept);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function match(AcceptHeader $accept, AcceptHeader $priority, $index)
+    {
+        if (!$accept instanceof Accept || !$priority instanceof Accept) {
+            return null;
+        }
+
+        $acceptBase = $accept->getBasePart();
+        $priorityBase = $priority->getBasePart();
+
+        $acceptSub = $accept->getSubPart();
+        $prioritySub = $priority->getSubPart();
+
+        $intersection = array_intersect_assoc($accept->getParameters(), $priority->getParameters());
+
+        $baseEqual = !strcasecmp($acceptBase, $priorityBase);
+        $subEqual  = !strcasecmp($acceptSub, $prioritySub);
+
+        if (($acceptBase === '*' || $baseEqual)
+            && ($acceptSub === '*' || $subEqual)
+            && count($intersection) === count($accept->getParameters())
+        ) {
+            $score = 100 * $baseEqual + 10 * $subEqual + count($intersection);
+
+            return new Match($accept->getQuality() * $priority->getQuality(), $score, $index);
+        }
+
+        if (!strstr($acceptSub, '+') || !strstr($prioritySub, '+')) {
+            return null;
+        }
+
+        // Handle "+" segment wildcards
+        list($acceptSub, $acceptPlus) = $this->splitSubPart($acceptSub);
+        list($prioritySub, $priorityPlus) = $this->splitSubPart($prioritySub);
+
+        // If no wildcards in either the subtype or + segment, do nothing.
+        if (!($acceptBase === '*' || $baseEqual)
+            || !($acceptSub === '*' || $prioritySub === '*' || $acceptPlus === '*' || $priorityPlus === '*')
+        ) {
+            return null;
+        }
+
+        $subEqual  = !strcasecmp($acceptSub, $prioritySub);
+        $plusEqual = !strcasecmp($acceptPlus, $priorityPlus);
+
+        if (($acceptSub === '*' || $prioritySub === '*' || $subEqual)
+            && ($acceptPlus === '*' || $priorityPlus === '*' || $plusEqual)
+            && count($intersection) === count($accept->getParameters())
+        ) {
+            $score = 100 * $baseEqual + 10 * $subEqual + $plusEqual + count($intersection);
+
+            return new Match($accept->getQuality() * $priority->getQuality(), $score, $index);
+        }
+
+        return null;
+    }
+
+    /**
+     * Split a subpart into the subpart and "plus" part.
+     *
+     * For media-types of the form "application/vnd.example+json", matching
+     * should allow wildcards for either the portion before the "+" or
+     * after. This method splits the subpart to allow such matching.
+     */
+    protected function splitSubPart($subPart)
+    {
+        if (!strstr($subPart, '+')) {
+            return [$subPart, ''];
+        }
+
+        return explode('+', $subPart, 2);
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptLanguageTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptLanguageTest.php
new file mode 100644
index 000000000..bc8ab2489
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptLanguageTest.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\AcceptLanguage;
+
+class AcceptLanguageTest extends TestCase
+{
+
+    /**
+     * @dataProvider dataProviderForGetType
+     */
+    public function testGetType($header, $expected)
+    {
+        $accept = new AcceptLanguage($header);
+        $actual = $accept->getType();
+        $this->assertEquals($expected, $actual);
+    }
+
+    public static function dataProviderForGetType()
+    {
+        return array(
+           array('en;q=0.7', 'en'),
+           array('en-GB;q=0.8', 'en-gb'),
+           array('da', 'da'),
+           array('en-gb;q=0.8', 'en-gb'),
+           array('es;q=0.7', 'es'),
+           array('fr ; q= 0.1', 'fr'),
+           array('', null),
+           array(null, null),
+       );
+    }
+
+    /**
+     * @dataProvider dataProviderForGetValue
+     */
+    public function testGetValue($header, $expected)
+    {
+        $accept = new AcceptLanguage($header);
+        $actual = $accept->getValue();
+        $this->assertEquals($expected, $actual);
+
+    }
+
+    public static function dataProviderForGetValue()
+    {
+        return array(
+           array('en;q=0.7', 'en;q=0.7'),
+           array('en-GB;q=0.8', 'en-GB;q=0.8'),
+        );
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptTest.php
new file mode 100644
index 000000000..f76219e85
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/AcceptTest.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\Accept;
+
+class AcceptTest extends TestCase
+{
+    public function testGetParameter()
+    {
+        $accept = new Accept('foo/bar; q=1; hello=world');
+
+        $this->assertTrue($accept->hasParameter('hello'));
+        $this->assertEquals('world', $accept->getParameter('hello'));
+        $this->assertFalse($accept->hasParameter('unknown'));
+        $this->assertNull($accept->getParameter('unknown'));
+        $this->assertFalse($accept->getParameter('unknown', false));
+        $this->assertSame('world', $accept->getParameter('hello', 'goodbye'));
+    }
+
+    /**
+     * @dataProvider dataProviderForTestGetNormalizedValue
+     */
+    public function testGetNormalizedValue($header, $expected)
+    {
+        $accept = new Accept($header);
+        $actual = $accept->getNormalizedValue();
+        $this->assertEquals($expected, $actual);
+    }
+
+    public static function dataProviderForTestGetNormalizedValue()
+    {
+        return array(
+            array('text/html; z=y; a=b; c=d', 'text/html; a=b; c=d; z=y'),
+            array('application/pdf; q=1; param=p',  'application/pdf; param=p')
+        );
+    }
+
+    /**
+     * @dataProvider dataProviderForGetType
+     */
+    public function testGetType($header, $expected)
+    {
+        $accept = new Accept($header);
+        $actual = $accept->getType();
+        $this->assertEquals($expected, $actual);
+    }
+
+    public static function dataProviderForGetType()
+    {
+        return array(
+            array('text/html;hello=world', 'text/html'),
+            array('application/pdf', 'application/pdf'),
+            array('application/xhtml+xml;q=0.9', 'application/xhtml+xml'),
+            array('text/plain; q=0.5', 'text/plain'),
+            array('text/html;level=2;q=0.4', 'text/html'),
+            array('text/html ; level = 2   ; q = 0.4', 'text/html'),
+            array('text/*', 'text/*'),
+            array('text/* ;q=1 ;level=2', 'text/*'),
+            array('*/*', '*/*'),
+            array('*', '*/*'),
+            array('*/* ; param=555', '*/*'),
+            array('* ; param=555', '*/*'),
+            array('TEXT/hTmL;leVel=2; Q=0.4', 'text/html'),
+        );
+    }
+
+    /**
+     * @dataProvider dataProviderForGetValue
+     */
+    public function testGetValue($header, $expected)
+    {
+        $accept = new Accept($header);
+        $actual = $accept->getValue();
+        $this->assertEquals($expected, $actual);
+
+    }
+
+    public static function dataProviderForGetValue()
+    {
+        return array(
+            array('text/html;hello=world  ;q=0.5', 'text/html;hello=world  ;q=0.5'),
+            array('application/pdf', 'application/pdf'),
+        );
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/BaseAcceptTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/BaseAcceptTest.php
new file mode 100644
index 000000000..3fcf1f986
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/BaseAcceptTest.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\BaseAccept;
+
+class BaseAcceptTest extends TestCase
+{
+    /**
+     * @dataProvider dataProviderForParseParameters
+     */
+    public function testParseParameters($value, $expected)
+    {
+        $accept     = new DummyAccept($value);
+        $parameters = $accept->getParameters();
+
+        // TODO: hack-ish... this is needed because logic in BaseAccept
+        //constructor drops the quality from the parameter set.
+        if (false !== strpos($value, 'q')) {
+            $parameters['q'] = $accept->getQuality();
+        }
+
+        $this->assertCount(count($expected), $parameters);
+
+        foreach ($expected as $key => $value) {
+            $this->assertArrayHasKey($key, $parameters);
+            $this->assertEquals($value, $parameters[$key]);
+        }
+    }
+
+    public static function dataProviderForParseParameters()
+    {
+        return array(
+            array(
+                'application/json ;q=1.0; level=2;foo= bar',
+                array(
+                    'q' => 1.0,
+                    'level' => 2,
+                    'foo'   => 'bar',
+                ),
+            ),
+            array(
+                'application/json ;q = 1.0; level = 2;     FOO  = bAr',
+                array(
+                    'q' => 1.0,
+                    'level' => 2,
+                    'foo'   => 'bAr',
+                ),
+            ),
+            array(
+                'application/json;q=1.0',
+                array(
+                    'q' => 1.0,
+                ),
+            ),
+            array(
+                'application/json;foo',
+                array(),
+            ),
+        );
+    }
+
+    /**
+     * @dataProvider dataProviderBuildParametersString
+     */
+
+    public function testBuildParametersString($value, $expected)
+    {
+        $accept = new DummyAccept($value);
+
+        $this->assertEquals($expected, $accept->getNormalizedValue());
+    }
+
+    public static function dataProviderBuildParametersString()
+    {
+        return array(
+            array('media/type; xxx = 1.0;level=2;foo=bar', 'media/type; foo=bar; level=2; xxx=1.0'),
+        );
+    }
+}
+
+class DummyAccept extends BaseAccept
+{
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/CharsetNegotiatorTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/CharsetNegotiatorTest.php
new file mode 100644
index 000000000..832a067c0
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/CharsetNegotiatorTest.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\CharsetNegotiator;
+
+class CharsetNegotiatorTest extends TestCase
+{
+
+    /**
+     * @var CharsetNegotiator
+     */
+    private $negotiator;
+
+    protected function setUp()
+    {
+        $this->negotiator = new CharsetNegotiator();
+    }
+
+    public function testGetBestReturnsNullWithUnmatchedHeader()
+    {
+        $this->assertNull($this->negotiator->getBest('foo, bar, yo', array('baz')));
+    }
+
+    /**
+     * 'bu' has the highest quality rating, but is non-existent,
+     * so we expect the next highest rated 'fr' content to be returned.
+     *
+     * See: http://svn.apache.org/repos/asf/httpd/test/framework/trunk/t/modules/negotiation.t
+     */
+    public function testGetBestIgnoresNonExistentContent()
+    {
+        $acceptCharset = 'en; q=0.1, fr; q=0.4, bu; q=1.0';
+        $accept        = $this->negotiator->getBest($acceptCharset, array('en', 'fr'));
+
+        $this->assertInstanceOf('Negotiation\AcceptCharset', $accept);
+        $this->assertEquals('fr', $accept->getValue());
+    }
+
+    /**
+     * @dataProvider dataProviderForTestGetBest
+     */
+    public function testGetBest($accept, $priorities, $expected)
+    {
+        if (is_null($expected))
+            $this->setExpectedException('Negotiation\Exception\InvalidArgument');
+
+        $accept = $this->negotiator->getBest($accept, $priorities);
+        if (null === $accept) {
+            $this->assertNull($expected);
+        } else {
+            $this->assertInstanceOf('Negotiation\AcceptCharset', $accept);
+            $this->assertSame($expected, $accept->getValue());
+        }
+    }
+
+    public static function dataProviderForTestGetBest()
+    {
+        $pearCharset  = 'ISO-8859-1, Big5;q=0.6,utf-8;q=0.7, *;q=0.5';
+        $pearCharset2 = 'ISO-8859-1, Big5;q=0.6,utf-8;q=0.7';
+
+        return array(
+            array($pearCharset, array( 'utf-8', 'big5', 'iso-8859-1', 'shift-jis',), 'iso-8859-1'),
+            array($pearCharset, array( 'utf-8', 'big5', 'shift-jis',), 'utf-8'),
+            array($pearCharset, array( 'Big5', 'shift-jis',), 'Big5'),
+            array($pearCharset, array( 'shift-jis',), 'shift-jis'),
+            array($pearCharset2, array( 'utf-8', 'big5', 'iso-8859-1', 'shift-jis',), 'iso-8859-1'),
+            array($pearCharset2, array( 'utf-8', 'big5', 'shift-jis',), 'utf-8'),
+            array($pearCharset2, array( 'Big5', 'shift-jis',), 'Big5'),
+            array('utf-8;q=0.6,iso-8859-5;q=0.9', array( 'iso-8859-5', 'utf-8',), 'iso-8859-5'),
+            array('', array( 'iso-8859-5', 'utf-8',), null),
+            array('en, *;q=0.9', array('fr'), 'fr'),
+            # Quality of source factors
+            array($pearCharset, array('iso-8859-1;q=0.5', 'utf-8', 'utf-16;q=1.0'), 'utf-8'),
+            array($pearCharset, array('iso-8859-1;q=0.8', 'utf-8', 'utf-16;q=1.0'), 'iso-8859-1;q=0.8'),
+        );
+    }
+
+    public function testGetBestRespectsPriorities()
+    {
+        $accept = $this->negotiator->getBest('foo, bar, yo', array('yo'));
+
+        $this->assertInstanceOf('Negotiation\AcceptCharset', $accept);
+        $this->assertEquals('yo', $accept->getValue());
+    }
+
+    public function testGetBestDoesNotMatchPriorities()
+    {
+        $acceptCharset = 'en, de';
+        $priorities           = array('fr');
+
+        $this->assertNull($this->negotiator->getBest($acceptCharset, $priorities));
+    }
+
+    public function testGetBestRespectsQualityOfSource()
+    {
+        $accept = $this->negotiator->getBest('utf-8;q=0.5,iso-8859-1', array('iso-8859-1;q=0.3', 'utf-8;q=0.9', 'utf-16;q=1.0'));
+        $this->assertInstanceOf('Negotiation\AcceptCharset', $accept);
+        $this->assertEquals('utf-8', $accept->getType());
+    }
+
+    /**
+     * @dataProvider dataProviderForTestParseHeader
+     */
+    public function testParseHeader($header, $expected)
+    {
+        $accepts = $this->call_private_method('Negotiation\CharsetNegotiator', 'parseHeader', $this->negotiator, array($header));
+
+        $this->assertSame($expected, $accepts);
+    }
+
+    public static function dataProviderForTestParseHeader()
+    {
+        return array(
+            array('*;q=0.3,ISO-8859-1,utf-8;q=0.7', array('*;q=0.3', 'ISO-8859-1', 'utf-8;q=0.7')),
+            array('*;q=0.3,ISO-8859-1;q=0.7,utf-8;q=0.7', array('*;q=0.3', 'ISO-8859-1;q=0.7', 'utf-8;q=0.7')),
+            array('*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7', array('*;q=0.3', 'utf-8;q=0.7', 'ISO-8859-1;q=0.7')),
+            array('iso-8859-5, unicode-1-1;q=0.8', array('iso-8859-5', 'unicode-1-1;q=0.8')),
+        );
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/EncodingNegotiatorTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/EncodingNegotiatorTest.php
new file mode 100644
index 000000000..3a2a2c994
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/EncodingNegotiatorTest.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\EncodingNegotiator;
+
+class EncodingNegotiatorTest extends TestCase
+{
+
+    /**
+     * @var EncodingNegotiator
+     */
+    private $negotiator;
+
+    protected function setUp()
+    {
+        $this->negotiator = new EncodingNegotiator();
+    }
+
+    public function testGetBestReturnsNullWithUnmatchedHeader()
+    {
+        $this->assertNull($this->negotiator->getBest('foo, bar, yo', array('baz')));
+    }
+
+    /**
+     * @dataProvider dataProviderForTestGetBest
+     */
+    public function testGetBest($accept, $priorities, $expected)
+    {
+        $accept = $this->negotiator->getBest($accept, $priorities);
+
+        if (null === $accept) {
+            $this->assertNull($expected);
+        } else {
+            $this->assertInstanceOf('Negotiation\AcceptEncoding', $accept);
+            $this->assertEquals($expected, $accept->getValue());
+        }
+    }
+
+    public static function dataProviderForTestGetBest()
+    {
+        return array(
+            array('gzip;q=1.0, identity; q=0.5, *;q=0', array('identity'), 'identity'),
+            array('gzip;q=0.5, identity; q=0.5, *;q=0.7', array('bzip', 'foo'), 'bzip'),
+            array('gzip;q=0.7, identity; q=0.5, *;q=0.7', array('gzip', 'foo'), 'gzip'),
+            # Quality of source factors
+            array('gzip;q=0.7,identity', array('identity;q=0.5', 'gzip;q=0.9'), 'gzip;q=0.9'),
+        );
+    }
+
+    public function testGetBestRespectsQualityOfSource()
+    {
+        $accept = $this->negotiator->getBest('gzip;q=0.7,identity', array('identity;q=0.5', 'gzip;q=0.9'));
+        $this->assertInstanceOf('Negotiation\AcceptEncoding', $accept);
+        $this->assertEquals('gzip', $accept->getType());
+    }
+
+    /**
+     * @dataProvider dataProviderForTestParseAcceptHeader
+     */
+    public function testParseAcceptHeader($header, $expected)
+    {
+        $accepts = $this->call_private_method('Negotiation\Negotiator', 'parseHeader', $this->negotiator, array($header));
+
+        $this->assertSame($expected, $accepts);
+    }
+
+    public static function dataProviderForTestParseAcceptHeader()
+    {
+        return array(
+            array('gzip,deflate,sdch', array('gzip', 'deflate', 'sdch')),
+            array("gzip, deflate\t,sdch", array('gzip', 'deflate', 'sdch')),
+            array('gzip;q=1.0, identity; q=0.5, *;q=0', array('gzip;q=1.0', 'identity; q=0.5', '*;q=0')),
+        );
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/LanguageNegotiatorTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/LanguageNegotiatorTest.php
new file mode 100644
index 000000000..d11f3dcbe
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/LanguageNegotiatorTest.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\Exception\InvalidArgument;
+use Negotiation\LanguageNegotiator;
+
+class LanguageNegotiatorTest extends TestCase
+{
+
+    /**
+     * @var LanguageNegotiator
+     */
+    private $negotiator;
+
+    protected function setUp()
+    {
+        $this->negotiator = new LanguageNegotiator();
+    }
+
+    /**
+     * @dataProvider dataProviderForTestGetBest
+     */
+    public function testGetBest($accept, $priorities, $expected)
+    {
+        try {
+            $accept = $this->negotiator->getBest($accept, $priorities);
+
+            if (null === $accept) {
+                $this->assertNull($expected);
+            } else {
+                $this->assertInstanceOf('Negotiation\AcceptLanguage', $accept);
+                $this->assertEquals($expected, $accept->getValue());
+            }
+        } catch (\Exception $e) {
+            $this->assertEquals($expected, $e);
+        }
+    }
+
+    public static function dataProviderForTestGetBest()
+    {
+        return array(
+            array('en, de', array('fr'), null),
+            array('foo, bar, yo', array('baz', 'biz'), null),
+            array('fr-FR, en;q=0.8', array('en-US', 'de-DE'), 'en-US'),
+            array('en, *;q=0.9', array('fr'), 'fr'),
+            array('foo, bar, yo', array('yo'), 'yo'),
+            array('en; q=0.1, fr; q=0.4, bu; q=1.0', array('en', 'fr'), 'fr'),
+            array('en; q=0.1, fr; q=0.4, fu; q=0.9, de; q=0.2', array('en', 'fu'), 'fu'),
+            array('', array('en', 'fu'), new InvalidArgument('The header string should not be empty.')),
+            array('fr, zh-Hans-CN;q=0.3', array('fr'), 'fr'),
+            # Quality of source factors
+            array('en;q=0.5,de', array('de;q=0.3', 'en;q=0.9'), 'en;q=0.9'),
+        );
+    }
+
+    public function testGetBestRespectsQualityOfSource()
+    {
+        $accept = $this->negotiator->getBest('en;q=0.5,de', array('de;q=0.3', 'en;q=0.9'));
+        $this->assertInstanceOf('Negotiation\AcceptLanguage', $accept);
+        $this->assertEquals('en', $accept->getType());
+    }
+
+    /**
+     * @dataProvider dataProviderForTestParseHeader
+     */
+    public function testParseHeader($header, $expected)
+    {
+        $accepts = $this->call_private_method('Negotiation\Negotiator', 'parseHeader', $this->negotiator, array($header));
+
+        $this->assertSame($expected, $accepts);
+    }
+
+    public static function dataProviderForTestParseHeader()
+    {
+        return array(
+            array('en; q=0.1, fr; q=0.4, bu; q=1.0', array('en; q=0.1', 'fr; q=0.4', 'bu; q=1.0')),
+            array('en; q=0.1, fr; q=0.4, fu; q=0.9, de; q=0.2', array('en; q=0.1', 'fr; q=0.4', 'fu; q=0.9', 'de; q=0.2')),
+        );
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/MatchTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/MatchTest.php
new file mode 100644
index 000000000..c570a0a58
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/MatchTest.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\Match;
+
+class MatchTest extends TestCase
+{
+    /**
+     * @dataProvider dataProviderForTestCompare
+     */
+    public function testCompare($match1, $match2, $expected)
+    {
+        $this->assertEquals($expected, Match::compare($match1, $match2));
+    }
+
+    public static function dataProviderForTestCompare()
+    {
+        return array(
+            array(new Match(1.0, 110, 1), new Match(1.0, 111, 1),    0),
+            array(new Match(0.1, 10,  1), new Match(0.1,  10, 2),   -1),
+            array(new Match(0.5, 110, 5), new Match(0.5,  11, 4),    1),
+            array(new Match(0.4, 110, 1), new Match(0.6, 111, 3),    1),
+            array(new Match(0.6, 110, 1), new Match(0.4, 111, 3),   -1),
+        );
+    }
+
+    /**
+     * @dataProvider dataProviderForTestReduce
+     */
+    public function testReduce($carry, $match, $expected)
+    {
+        $this->assertEquals($expected, Match::reduce($carry, $match));
+    }
+
+    public static function dataProviderForTestReduce()
+    {
+        return array(
+            array(
+                array(1 => new Match(1.0, 10, 1)),
+                new Match(0.5, 111, 1),
+                array(1 => new Match(0.5, 111, 1)),
+            ),
+            array(
+                array(1 => new Match(1.0, 110, 1)),
+                new Match(0.5, 11, 1),
+                array(1 => new Match(1.0, 110, 1)),
+            ),
+            array(
+                array(0 => new Match(1.0, 10, 1)),
+                new Match(0.5, 111, 1),
+                array(0 => new Match(1.0, 10, 1), 1 => new Match(0.5, 111, 1)),
+            ),
+        );
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/NegotiatorTest.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/NegotiatorTest.php
new file mode 100644
index 000000000..fe3ff767a
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/NegotiatorTest.php
@@ -0,0 +1,195 @@
+<?php
+
+namespace Negotiation\Tests;
+
+use Negotiation\Exception\InvalidArgument;
+use Negotiation\Exception\InvalidMediaType;
+use Negotiation\Negotiator;
+use Negotiation\Accept;
+use Negotiation\Match;
+
+class NegotiatorTest extends TestCase
+{
+
+    /**
+     * @var Negotiator
+     */
+    private $negotiator;
+
+    protected function setUp()
+    {
+        $this->negotiator = new Negotiator();
+    }
+
+    /**
+     * @dataProvider dataProviderForTestGetBest
+     */
+    public function testGetBest($header, $priorities, $expected)
+    {
+        try {
+            $acceptHeader = $this->negotiator->getBest($header, $priorities);
+        } catch (\Exception $e) {
+            $this->assertEquals($expected, $e);
+
+            return;
+        }
+
+        if ($acceptHeader === null) {
+            $this->assertNull($expected);
+
+            return;
+        }
+
+        $this->assertInstanceOf('Negotiation\Accept', $acceptHeader);
+
+        $this->assertSame($expected[0], $acceptHeader->getType());
+        $this->assertSame($expected[1], $acceptHeader->getParameters());
+    }
+
+    public static function dataProviderForTestGetBest()
+    {
+        $pearAcceptHeader = 'text/html,application/xhtml+xml,application/xml;q=0.9,text/*;q=0.7,*/*,image/gif; q=0.8, image/jpeg; q=0.6, image/*';
+        $rfcHeader = 'text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5';
+
+        return array(
+            # exceptions
+            array('/qwer', array('f/g'), null),
+            array('/qwer,f/g', array('f/g'), array('f/g', array())),
+            array('foo/bar', array('/qwer'), new InvalidMediaType()),
+            array('', array('foo/bar'), new InvalidArgument('The header string should not be empty.')),
+            array('*/*', array(), new InvalidArgument('A set of server priorities should be given.')),
+
+            # See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
+            array($rfcHeader, array('text/html;level=1'), array('text/html', array('level' => '1'))),
+            array($rfcHeader, array('text/html'), array('text/html', array())),
+            array($rfcHeader, array('text/plain'), array('text/plain', array())),
+            array($rfcHeader, array('image/jpeg',), array('image/jpeg', array())),
+            array($rfcHeader, array('text/html;level=2'), array('text/html', array('level' => '2'))),
+            array($rfcHeader, array('text/html;level=3'), array('text/html', array( 'level' => '3'))),
+
+            array('text/*;q=0.7, text/html;q=0.3, */*;q=0.5, image/png;q=0.4', array('text/html', 'image/png'), array('image/png', array())),
+            array('image/png;q=0.1, text/plain, audio/ogg;q=0.9', array('image/png', 'text/plain', 'audio/ogg'), array('text/plain', array())),
+            array('image/png, text/plain, audio/ogg', array('baz/asdf'), null),
+            array('image/png, text/plain, audio/ogg', array('audio/ogg'), array('audio/ogg', array())),
+            array('image/png, text/plain, audio/ogg', array('YO/SuP'), null),
+            array('text/html; charset=UTF-8, application/pdf', array('text/html; charset=UTF-8'), array('text/html', array('charset' => 'UTF-8'))),
+            array('text/html; charset=UTF-8, application/pdf', array('text/html'), null),
+            array('text/html, application/pdf', array('text/html; charset=UTF-8'), array('text/html', array('charset' => 'UTF-8'))),
+            # PEAR HTTP2 tests - have been altered from original!
+            array($pearAcceptHeader, array('image/gif', 'image/png', 'application/xhtml+xml', 'application/xml', 'text/html', 'image/jpeg', 'text/plain',), array('image/png', array())),
+            array($pearAcceptHeader, array('image/gif', 'application/xhtml+xml', 'application/xml', 'image/jpeg', 'text/plain',), array('application/xhtml+xml', array())),
+            array($pearAcceptHeader, array('image/gif', 'application/xml', 'image/jpeg', 'text/plain',), array('application/xml', array())),
+            array($pearAcceptHeader, array('image/gif', 'image/jpeg', 'text/plain'), array('image/gif', array())),
+            array($pearAcceptHeader, array('text/plain', 'image/png', 'image/jpeg'), array('image/png', array())),
+            array($pearAcceptHeader, array('image/jpeg', 'image/gif',), array('image/gif', array())),
+            array($pearAcceptHeader, array('image/png',), array('image/png', array())),
+            array($pearAcceptHeader, array('audio/midi',), array('audio/midi', array())),
+            array('text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', array( 'application/rss+xml'), array('application/rss+xml', array())),
+            # LWS / case sensitivity
+            array('text/* ; q=0.3, TEXT/html ;Q=0.7, text/html ; level=1, texT/Html ;leVel = 2 ;q=0.4, */* ; q=0.5', array( 'text/html; level=2'), array('text/html', array( 'level' => '2'))),
+            array('text/* ; q=0.3, text/html;Q=0.7, text/html ;level=1, text/html; level=2;q=0.4, */*;q=0.5', array( 'text/HTML; level=3'), array('text/html', array( 'level' => '3'))),
+            # Incompatible
+            array('text/html', array( 'application/rss'), null),
+            # IE8 Accept header
+            array('image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, */*', array( 'text/html', 'application/xhtml+xml'), array('text/html', array())),
+            # Quality of source factors
+            array($rfcHeader, array('text/html;q=0.4', 'text/plain'), array('text/plain', array())),
+            # Wildcard "plus" parts (e.g., application/vnd.api+json)
+            array('application/vnd.api+json', array('application/json', 'application/*+json'), array('application/*+json', array())),
+            array('application/json;q=0.7, application/*+json;q=0.7', array('application/hal+json', 'application/problem+json'), array('application/hal+json', array())),
+            array('application/json;q=0.7, application/problem+*;q=0.7', array('application/hal+xml', 'application/problem+xml'), array('application/problem+xml', array())),
+            array($pearAcceptHeader, array('application/*+xml'), array('application/*+xml', array())),
+            # @see https://github.com/willdurand/Negotiation/issues/93
+            array('application/hal+json', array('application/ld+json', 'application/hal+json', 'application/xml', 'text/xml', 'application/json', 'text/html'), array('application/hal+json', array())),
+        );
+    }
+
+    public function testGetBestRespectsQualityOfSource()
+    {
+        $accept = $this->negotiator->getBest('text/html,text/*;q=0.7', array('text/html;q=0.5', 'text/plain;q=0.9'));
+        $this->assertInstanceOf('Negotiation\Accept', $accept);
+        $this->assertEquals('text/plain', $accept->getType());
+    }
+
+    /**
+     * @dataProvider dataProviderForTestParseHeader
+     */
+    public function testParseHeader($header, $expected)
+    {
+        $accepts = $this->call_private_method('Negotiation\Negotiator', 'parseHeader', $this->negotiator, array($header));
+
+        $this->assertSame($expected, $accepts);
+    }
+
+    public static function dataProviderForTestParseHeader()
+    {
+        return array(
+            array('text/html ;   q=0.9', array('text/html ;   q=0.9')),
+            array('text/html,application/xhtml+xml', array('text/html', 'application/xhtml+xml')),
+            array(',,text/html;q=0.8 , , ', array('text/html;q=0.8')),
+            array('text/html;charset=utf-8; q=0.8', array('text/html;charset=utf-8; q=0.8')),
+            array('text/html; foo="bar"; q=0.8 ', array('text/html; foo="bar"; q=0.8')),
+            array('text/html; foo="bar"; qwer="asdf", image/png', array('text/html; foo="bar"; qwer="asdf"', "image/png")),
+            array('text/html ; quoted_comma="a,b  ,c,",application/xml;q=0.9,*/*;charset=utf-8; q=0.8', array('text/html ; quoted_comma="a,b  ,c,"', 'application/xml;q=0.9', '*/*;charset=utf-8; q=0.8')),
+            array('text/html, application/json;q=0.8, text/csv;q=0.7', array('text/html', 'application/json;q=0.8', 'text/csv;q=0.7'))
+        );
+    }
+
+    /**
+     * @dataProvider dataProviderForTestFindMatches
+     */
+    public function testFindMatches($headerParts, $priorities, $expected)
+    {
+        $neg = new Negotiator();
+
+        $matches = $this->call_private_method('Negotiation\Negotiator', 'findMatches', $neg, array($headerParts, $priorities));
+
+        $this->assertEquals($expected, $matches);
+    }
+
+    public static function dataProviderForTestFindMatches()
+    {
+        return array(
+            array(
+                array(new Accept('text/html; charset=UTF-8'), new Accept('image/png; foo=bar; q=0.7'), new Accept('*/*; foo=bar; q=0.4')),
+                array(new Accept('text/html; charset=UTF-8'), new Accept('image/png; foo=bar'), new Accept('application/pdf')),
+                array(
+                    new Match(1.0, 111, 0),
+                    new Match(0.7, 111, 1),
+                    new Match(0.4, 1,   1),
+                )
+            ),
+            array(
+                array(new Accept('text/html'), new Accept('image/*; q=0.7')),
+                array(new Accept('text/html; asfd=qwer'), new Accept('image/png'), new Accept('application/pdf')),
+                array(
+                    new Match(1.0, 110, 0),
+                    new Match(0.7, 100, 1),
+                )
+            ),
+            array( # https://tools.ietf.org/html/rfc7231#section-5.3.2
+                array(new Accept('text/*; q=0.3'), new Accept('text/html; q=0.7'), new Accept('text/html; level=1'), new Accept('text/html; level=2; q=0.4'), new Accept('*/*; q=0.5')),
+                array(new Accept('text/html; level=1'), new Accept('text/html'), new Accept('text/plain'), new Accept('image/jpeg'), new Accept('text/html; level=2'), new Accept('text/html; level=3')),
+                array(
+                    new Match(0.3,    100,    0),
+                    new Match(0.7,    110,    0),
+                    new Match(1.0,    111,    0),
+                    new Match(0.5,      0,    0),
+                    new Match(0.3,    100,    1),
+                    new Match(0.7,    110,    1),
+                    new Match(0.5,      0,    1),
+                    new Match(0.3,    100,    2),
+                    new Match(0.5,      0,    2),
+                    new Match(0.5,      0,    3),
+                    new Match(0.3,    100,    4),
+                    new Match(0.7,    110,    4),
+                    new Match(0.4,    111,    4),
+                    new Match(0.5,      0,    4),
+                    new Match(0.3,    100,    5),
+                    new Match(0.7,    110,    5),
+                    new Match(0.5,      0,    5),
+                )
+            )
+        );
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/Negotiation/Tests/TestCase.php b/vendor/willdurand/negotiation/tests/Negotiation/Tests/TestCase.php
new file mode 100644
index 000000000..37f936404
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/Negotiation/Tests/TestCase.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Negotiation\Tests;
+
+abstract class TestCase extends \PHPUnit_Framework_TestCase
+{
+    protected function call_private_method($class, $method, $object, $params)
+    {
+        $method = new \ReflectionMethod($class, $method);
+
+        $method->setAccessible(true);
+
+        return $method->invokeArgs($object, $params);
+    }
+}
diff --git a/vendor/willdurand/negotiation/tests/bootstrap.php b/vendor/willdurand/negotiation/tests/bootstrap.php
new file mode 100644
index 000000000..c63e17a68
--- /dev/null
+++ b/vendor/willdurand/negotiation/tests/bootstrap.php
@@ -0,0 +1,15 @@
+<?php
+
+if (! ($loader = @include __DIR__ . '/../vendor/autoload.php')) {
+    die(<<<EOT
+You need to install the project dependencies using Composer:
+$ wget http://getcomposer.org/composer.phar
+OR
+$ curl -s https://getcomposer.org/installer | php
+$ php composer.phar install --dev
+$ phpunit
+EOT
+    );
+}
+
+$loader->add('Negotiation\Tests', __DIR__);
-- 
GitLab