Przeglądaj źródła

add requests framework

causefx 8 lat temu
rodzic
commit
777ddca630
100 zmienionych plików z 10094 dodań i 23 usunięć
  1. 2 1
      api/composer.json
  2. 50 1
      api/composer.lock
  3. 0 21
      api/functions/organizr-functions.php
  4. 31 0
      api/functions/upgrade-functions.php
  5. 1 0
      api/vendor/composer/autoload_namespaces.php
  6. 11 0
      api/vendor/composer/autoload_static.php
  7. 51 0
      api/vendor/composer/installed.json
  8. 4 0
      api/vendor/rmccue/requests/.coveralls.yml
  9. 6 0
      api/vendor/rmccue/requests/.gitignore
  10. 58 0
      api/vendor/rmccue/requests/.travis.yml
  11. 315 0
      api/vendor/rmccue/requests/CHANGELOG.md
  12. 49 0
      api/vendor/rmccue/requests/LICENSE
  13. 152 0
      api/vendor/rmccue/requests/README.md
  14. 55 0
      api/vendor/rmccue/requests/bin/create_pear_package.php
  15. 23 0
      api/vendor/rmccue/requests/composer.json
  16. 28 0
      api/vendor/rmccue/requests/docs/README.md
  17. 44 0
      api/vendor/rmccue/requests/docs/authentication-custom.md
  18. 31 0
      api/vendor/rmccue/requests/docs/authentication.md
  19. 29 0
      api/vendor/rmccue/requests/docs/goals.md
  20. 96 0
      api/vendor/rmccue/requests/docs/hooks.md
  21. 23 0
      api/vendor/rmccue/requests/docs/proxy.md
  22. 74 0
      api/vendor/rmccue/requests/docs/usage-advanced.md
  23. 154 0
      api/vendor/rmccue/requests/docs/usage.md
  24. 192 0
      api/vendor/rmccue/requests/docs/why-requests.md
  25. 16 0
      api/vendor/rmccue/requests/examples/basic-auth.php
  26. 16 0
      api/vendor/rmccue/requests/examples/cookie.php
  27. 20 0
      api/vendor/rmccue/requests/examples/cookie_jar.php
  28. 13 0
      api/vendor/rmccue/requests/examples/get.php
  29. 45 0
      api/vendor/rmccue/requests/examples/multiple.php
  30. 13 0
      api/vendor/rmccue/requests/examples/post.php
  31. 18 0
      api/vendor/rmccue/requests/examples/proxy.php
  32. 24 0
      api/vendor/rmccue/requests/examples/session.php
  33. 17 0
      api/vendor/rmccue/requests/examples/timeout.php
  34. 980 0
      api/vendor/rmccue/requests/library/Requests.php
  35. 33 0
      api/vendor/rmccue/requests/library/Requests/Auth.php
  36. 88 0
      api/vendor/rmccue/requests/library/Requests/Auth/Basic.php
  37. 500 0
      api/vendor/rmccue/requests/library/Requests/Cookie.php
  38. 175 0
      api/vendor/rmccue/requests/library/Requests/Cookie/Jar.php
  39. 62 0
      api/vendor/rmccue/requests/library/Requests/Exception.php
  40. 71 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP.php
  41. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/304.php
  42. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/305.php
  43. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/306.php
  44. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/400.php
  45. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/401.php
  46. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/402.php
  47. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/403.php
  48. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/404.php
  49. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/405.php
  50. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/406.php
  51. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/407.php
  52. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/408.php
  53. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/409.php
  54. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/410.php
  55. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/411.php
  56. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/412.php
  57. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/413.php
  58. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/414.php
  59. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/415.php
  60. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/416.php
  61. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/417.php
  62. 29 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/418.php
  63. 29 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/428.php
  64. 29 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/429.php
  65. 29 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/431.php
  66. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/500.php
  67. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/501.php
  68. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/502.php
  69. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/503.php
  70. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/504.php
  71. 27 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/505.php
  72. 29 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/511.php
  73. 44 0
      api/vendor/rmccue/requests/library/Requests/Exception/HTTP/Unknown.php
  74. 5 0
      api/vendor/rmccue/requests/library/Requests/Exception/Transport.php
  75. 56 0
      api/vendor/rmccue/requests/library/Requests/Exception/Transport/cURL.php
  76. 33 0
      api/vendor/rmccue/requests/library/Requests/Hooker.php
  77. 68 0
      api/vendor/rmccue/requests/library/Requests/Hooks.php
  78. 388 0
      api/vendor/rmccue/requests/library/Requests/IDNAEncoder.php
  79. 190 0
      api/vendor/rmccue/requests/library/Requests/IPv6.php
  80. 1084 0
      api/vendor/rmccue/requests/library/Requests/IRI.php
  81. 35 0
      api/vendor/rmccue/requests/library/Requests/Proxy.php
  82. 151 0
      api/vendor/rmccue/requests/library/Requests/Proxy/HTTP.php
  83. 121 0
      api/vendor/rmccue/requests/library/Requests/Response.php
  84. 98 0
      api/vendor/rmccue/requests/library/Requests/Response/Headers.php
  85. 152 0
      api/vendor/rmccue/requests/library/Requests/SSL.php
  86. 266 0
      api/vendor/rmccue/requests/library/Requests/Session.php
  87. 41 0
      api/vendor/rmccue/requests/library/Requests/Transport.php
  88. 542 0
      api/vendor/rmccue/requests/library/Requests/Transport/cURL.php
  89. 444 0
      api/vendor/rmccue/requests/library/Requests/Transport/fsockopen.php
  90. 103 0
      api/vendor/rmccue/requests/library/Requests/Utility/CaseInsensitiveDictionary.php
  91. 45 0
      api/vendor/rmccue/requests/library/Requests/Utility/FilteredIterator.php
  92. 60 0
      api/vendor/rmccue/requests/package.xml.tpl
  93. 87 0
      api/vendor/rmccue/requests/tests/Auth/Basic.php
  94. 93 0
      api/vendor/rmccue/requests/tests/ChunkedEncoding.php
  95. 642 0
      api/vendor/rmccue/requests/tests/Cookies.php
  96. 94 0
      api/vendor/rmccue/requests/tests/Encoding.php
  97. 102 0
      api/vendor/rmccue/requests/tests/IDNAEncoder.php
  98. 413 0
      api/vendor/rmccue/requests/tests/IRI.php
  99. 131 0
      api/vendor/rmccue/requests/tests/Proxy/HTTP.php
  100. 162 0
      api/vendor/rmccue/requests/tests/Requests.php

+ 2 - 1
api/composer.json

@@ -3,6 +3,7 @@
         "dibi/dibi": "^3.1",
         "lcobucci/jwt": "^3.2",
         "composer/semver": "^1.4",
-        "phpmailer/phpmailer": "^6.0"
+        "phpmailer/phpmailer": "^6.0",
+        "rmccue/requests": "^1.7"
     }
 }

+ 50 - 1
api/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": "24f52bef89b6c1fc56add495b9dcd9a2",
+    "content-hash": "b23a4e199a4e93b84375b6091c164a53",
     "packages": [
         {
             "name": "composer/semver",
@@ -258,6 +258,55 @@
             ],
             "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
             "time": "2018-01-05T13:19:58+00:00"
+        },
+        {
+            "name": "rmccue/requests",
+            "version": "v1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/rmccue/Requests.git",
+                "reference": "87932f52ffad70504d93f04f15690cf16a089546"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546",
+                "reference": "87932f52ffad70504d93f04f15690cf16a089546",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2"
+            },
+            "require-dev": {
+                "requests/test-server": "dev-master"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Requests": "library/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "ISC"
+            ],
+            "authors": [
+                {
+                    "name": "Ryan McCue",
+                    "homepage": "http://ryanmccue.info"
+                }
+            ],
+            "description": "A HTTP library written in PHP, for human beings.",
+            "homepage": "http://github.com/rmccue/Requests",
+            "keywords": [
+                "curl",
+                "fsockopen",
+                "http",
+                "idna",
+                "ipv6",
+                "iri",
+                "sockets"
+            ],
+            "time": "2016-10-13T00:11:37+00:00"
         }
     ],
     "packages-dev": [],

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

@@ -1,26 +1,5 @@
 <?php
 
-function upgradeCheck() {
-    $compare = new Composer\Semver\Comparator;
-	// Upgrade check start for vserion below
-	$versionCheck = '2.25.0-alpha.101';
-	$config = loadConfig();
-	if (isset($config['dbLocation']) && (!isset($config['configVersion']) ||  $compare->lessThan($config['configVersion'], $versionCheck))) {
-		$oldVer = $config['configVersion'];
-        return 'Upgraded Needed - Current Version '.$oldVer.' - New Version: '.$versionCheck;
-		// Upgrade database to latest version
-		//updateDB($GLOBALS['dbLocation'],$GLOBALS['dbName'],$oldVer);
-		// Update Version and Commit
-		//$config['configVersion'] = $versionCheck;
-		//copy('config/config.php', 'config/config['.date('Y-m-d_H-i-s').'][1.40].bak.php');
-		//$createConfigSuccess = createConfig($config);
-		//unset($config);
-	}else{
-		//unset($config);
-        return 'No Upgraded Needed - Current Version Above: '.$versionCheck;
-    }
-	return true;
-}
 function wizardConfig($array){
     foreach ($array['data'] as $items) {
         foreach ($items as $key => $value) {

+ 31 - 0
api/functions/upgrade-functions.php

@@ -0,0 +1,31 @@
+<?php
+
+function upgradeCheck() {
+	$updateDB = false;
+    $compare = new Composer\Semver\Comparator;
+	// Upgrade check start for vserion below
+	$versionCheck = '2.0.0-alpha-120';
+	$config = loadConfig();
+	$oldVer = $config['configVersion'];
+	echo 'Doing check if version '.$oldVer.' is less than '.$versionCheck.'<br />';
+	if (isset($config['dbLocation']) && (!isset($config['configVersion']) || $compare->lessThan($config['configVersion'], $versionCheck))) {
+        $updateDB = true;
+	}
+
+
+
+
+	if($updateDB == true){
+		return 'Upgraded Needed - Current Version '.$oldVer.' - New Version: '.$versionCheck;
+		// Upgrade database to latest version
+		//updateDB($GLOBALS['dbLocation'],$GLOBALS['dbName'],$oldVer);
+		// Update Version and Commit
+		//$config['configVersion'] = $versionCheck;
+		//copy('config/config.php', 'config/config['.date('Y-m-d_H-i-s').'][1.40].bak.php');
+		//$createConfigSuccess = createConfig($config);
+		//unset($config);
+	}else{
+		return 'No Upgraded Needed - Current Version Above: '.$versionCheck;
+	}
+	return true;
+}

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

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

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

@@ -40,6 +40,16 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         ),
     );
 
+    public static $prefixesPsr0 = array (
+        'R' => 
+        array (
+            'Requests' => 
+            array (
+                0 => __DIR__ . '/..' . '/rmccue/requests/library',
+            ),
+        ),
+    );
+
     public static $classMap = array (
         'Dibi\\Bridges\\Nette\\DibiExtension22' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Bridges/Nette/DibiExtension22.php',
         'Dibi\\Bridges\\Tracy\\Panel' => __DIR__ . '/..' . '/dibi/dibi/src/Dibi/Bridges/Tracy/Panel.php',
@@ -103,6 +113,7 @@ class ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb
         return \Closure::bind(function () use ($loader) {
             $loader->prefixLengthsPsr4 = ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb::$prefixLengthsPsr4;
             $loader->prefixDirsPsr4 = ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb::$prefixDirsPsr4;
+            $loader->prefixesPsr0 = ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb::$prefixesPsr0;
             $loader->classMap = ComposerStaticInitcbdc783d76f8e7563dcce7d8af053ecb::$classMap;
 
         }, null, ClassLoader::class);

+ 51 - 0
api/vendor/composer/installed.json

@@ -259,5 +259,56 @@
             }
         ],
         "description": "PHPMailer is a full-featured email creation and transfer class for PHP"
+    },
+    {
+        "name": "rmccue/requests",
+        "version": "v1.7.0",
+        "version_normalized": "1.7.0.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/rmccue/Requests.git",
+            "reference": "87932f52ffad70504d93f04f15690cf16a089546"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/rmccue/Requests/zipball/87932f52ffad70504d93f04f15690cf16a089546",
+            "reference": "87932f52ffad70504d93f04f15690cf16a089546",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.2"
+        },
+        "require-dev": {
+            "requests/test-server": "dev-master"
+        },
+        "time": "2016-10-13T00:11:37+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Requests": "library/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "ISC"
+        ],
+        "authors": [
+            {
+                "name": "Ryan McCue",
+                "homepage": "http://ryanmccue.info"
+            }
+        ],
+        "description": "A HTTP library written in PHP, for human beings.",
+        "homepage": "http://github.com/rmccue/Requests",
+        "keywords": [
+            "curl",
+            "fsockopen",
+            "http",
+            "idna",
+            "ipv6",
+            "iri",
+            "sockets"
+        ]
     }
 ]

+ 4 - 0
api/vendor/rmccue/requests/.coveralls.yml

@@ -0,0 +1,4 @@
+src_dir: library
+coverage_clover: tests/clover.xml
+json_path: tests/coveralls.json
+service_name: travis-ci

+ 6 - 0
api/vendor/rmccue/requests/.gitignore

@@ -0,0 +1,6 @@
+# Ignore coverage report
+tests/coverage/*
+
+# Ignore composer related files
+/composer.lock
+/vendor

+ 58 - 0
api/vendor/rmccue/requests/.travis.yml

@@ -0,0 +1,58 @@
+language: php
+matrix:
+  fast_finish: true
+  include:
+    - php: 5.2
+    - php: 5.3
+    - php: 5.4
+    - php: 5.5
+    - php: 5.6
+      env: TEST_COVERAGE=1
+    - php: 7.0
+    - php: hhvm
+
+# Use new container infrastructure
+sudo: false
+
+cache:
+  directories:
+    - $HOME/.cache/pip
+    - $HOME/.composer/cache
+    - vendor
+
+install:
+ # Setup the test server
+ - phpenv local 5.5
+ - composer install --dev --no-interaction
+ - TESTPHPBIN=$(phpenv which php)
+ - phpenv local --unset
+
+ # Setup the proxy
+ - pip install --user mitmproxy~=0.15
+
+before_script:
+ - PHPBIN=$TESTPHPBIN PORT=8080 vendor/bin/start.sh
+ - export REQUESTS_TEST_HOST_HTTP="localhost:8080"
+
+ # Work out of the tests directory
+ - cd tests
+ - PROXYBIN="$HOME/.local/bin/mitmdump" PORT=9002 utils/proxy/start.sh
+ - PROXYBIN="$HOME/.local/bin/mitmdump" PORT=9003 AUTH="test:pass" utils/proxy/start.sh
+ - export REQUESTS_HTTP_PROXY="localhost:9002"
+ - export REQUESTS_HTTP_PROXY_AUTH="localhost:9003"
+ - export REQUESTS_HTTP_PROXY_AUTH_USER="test"
+ - export REQUESTS_HTTP_PROXY_AUTH_PASS="pass"
+
+ # Ensure the HTTPS test instance on Heroku is spun up
+ - curl -s -I http://requests-php-tests.herokuapp.com/ > /dev/null
+
+script:
+ - phpunit --coverage-clover clover.xml
+
+after_script:
+ - utils/proxy/stop.sh
+ - cd ..
+ - phpenv local 5.5
+ - PATH=$PATH vendor/bin/stop.sh
+ - test $TEST_COVERAGE && bash <(curl -s https://codecov.io/bash)
+ - phpenv local --unset

+ 315 - 0
api/vendor/rmccue/requests/CHANGELOG.md

@@ -0,0 +1,315 @@
+Changelog
+=========
+
+1.7.0
+-----
+
+- Add support for HHVM and PHP 7
+
+  Requests is now tested against both HHVM and PHP 7, and they are supported as
+  first-party platforms.
+
+  (props @rmccue, [#106][gh-106], [#176][gh-176])
+
+- Transfer & connect timeouts, in seconds & milliseconds
+
+  cURL is unable to handle timeouts under a second in DNS lookups, so we round
+  those up to ensure 1-999ms isn't counted as an instant failure.
+
+  (props @ozh, @rmccue, [#97][gh-97], [#216][gh-216])
+
+- Rework cookie handling to be more thorough.
+
+  Cookies are now restricted to the same-origin by default, expiration is checked.
+
+  (props @catharsisjelly, @rmccue, [#120][gh-120], [#124][gh-124], [#130][gh-130], [#132][gh-132], [#156][gh-156])
+
+- Improve testing
+
+  Tests are now run locally to speed them up, as well as further general
+  improvements to the quality of the testing suite. There are now also
+  comprehensive proxy tests to ensure coverage there.
+
+  (props @rmccue, [#75][gh-75], [#107][gh-107], [#170][gh-170], [#177][gh-177], [#181][gh-181], [#183][gh-183], [#185][gh-185], [#196][gh-196], [#202][gh-202], [#203][gh-203])
+
+- Support custom HTTP methods
+
+  Previously, custom HTTP methods were only supported on sockets; they are now
+  supported across all transports.
+
+  (props @ocean90, [#227][gh-227])
+
+- Add byte limit option
+
+  (props @rmccue, [#172][gh-172])
+
+- Support a Requests_Proxy_HTTP() instance for the proxy setting.
+
+  (props @ocean90, [#223][gh-223])
+
+- Add progress hook
+
+  (props @rmccue, [#180][gh-180])
+
+- Add a before_redirect hook to alter redirects
+
+  (props @rmccue, [#205][gh-205])
+
+- Pass cURL info to after_request
+
+  (props @rmccue, [#206][gh-206])
+
+- Remove explicit autoload in Composer installation instructions
+
+  (props @SlikNL, [#86][gh-86])
+
+- Restrict CURLOPT_PROTOCOLS on `defined()` instead of `version_compare()`
+
+  (props @ozh, [#92][gh-92])
+
+- Fix doc - typo in "Authentication"
+
+  (props @remik, [#99][gh-99])
+
+- Contextually check for a valid transport
+
+  (props @ozh, [#101][gh-101])
+
+- Follow relative redirects correctly
+
+  (props @ozh, [#103][gh-103])
+
+- Use cURL's version_number
+
+  (props @mishan, [#104][gh-104])
+
+- Removed duplicated option docs
+
+  (props @staabm, [#112][gh-112])
+
+- code styling fixed
+
+  (props @imsaintx, [#113][gh-113])
+
+- Fix IRI "normalization"
+
+  (props @ozh, [#128][gh-128])
+
+- Mention two PHP extension dependencies in the README.
+
+  (props @orlitzky, [#136][gh-136])
+
+- Ignore coverage report files
+
+  (props @ozh, [#148][gh-148])
+
+- drop obsolete "return" after throw
+
+  (props @staabm, [#150][gh-150])
+
+- Updated exception message to specify both http + https
+
+  (props @beutnagel, [#162][gh-162])
+
+- Sets `stream_headers` method to public to allow calling it from other
+places.
+
+  (props @adri, [#158][gh-158])
+
+- Remove duplicated stream_get_meta_data call
+
+  (props @rmccue, [#179][gh-179])
+
+- Transmits $errno from stream_socket_client in exception
+
+  (props @laurentmartelli, [#174][gh-174])
+
+- Correct methods to use snake_case
+
+  (props @rmccue, [#184][gh-184])
+
+- Improve code quality
+
+  (props @rmccue, [#186][gh-186])
+
+- Update Build Status image
+
+  (props @rmccue, [#187][gh-187])
+
+- Fix/Rationalize transports (v2)
+
+  (props @rmccue, [#188][gh-188])
+
+- Surface cURL errors
+
+  (props @ifwe, [#194][gh-194])
+
+- Fix for memleak and curl_close() never being called
+
+  (props @kwuerl, [#200][gh-200])
+
+- addex how to install with composer
+
+  (props @royopa, [#164][gh-164])
+
+- Uppercase the method to ensure compatibility
+
+  (props @rmccue, [#207][gh-207])
+
+- Store default certificate path
+
+  (props @rmccue, [#210][gh-210])
+
+- Force closing keep-alive connections on old cURL
+
+  (props @rmccue, [#211][gh-211])
+
+- Docs: Updated HTTP links with HTTPS links where applicable
+
+  (props @ntwb, [#215][gh-215])
+
+- Remove the executable bit
+
+  (props @ocean90, [#224][gh-224])
+
+- Change more links to HTTPS
+
+  (props @rmccue, [#217][gh-217])
+
+- Bail from cURL when either `curl_init()` OR `curl_exec()` are unavailable
+
+  (props @dd32, [#230][gh-230])
+
+- Disable OpenSSL's internal peer_name checking when `verifyname` is disabled.
+
+  (props @dd32, [#239][gh-239])
+
+- Only include the port number in the `Host` header when it differs from
+default
+
+  (props @dd32, [#238][gh-238])
+
+- Respect port if specified for HTTPS connections
+
+  (props @dd32, [#237][gh-237])
+
+- Allow paths starting with a double-slash
+
+  (props @rmccue, [#240][gh-240])
+
+- Fixes bug in rfc2616 #3.6.1 implementation.
+
+  (props @stephenharris, [#236][gh-236], [#3][gh-3])
+
+- CURLOPT_HTTPHEADER在php7接受空数组导致php-fpm奔溃
+
+  (props @qibinghua, [#219][gh-219])
+
+[gh-3]: https://github.com/rmccue/Requests/issues/3
+[gh-75]: https://github.com/rmccue/Requests/issues/75
+[gh-86]: https://github.com/rmccue/Requests/issues/86
+[gh-92]: https://github.com/rmccue/Requests/issues/92
+[gh-97]: https://github.com/rmccue/Requests/issues/97
+[gh-99]: https://github.com/rmccue/Requests/issues/99
+[gh-101]: https://github.com/rmccue/Requests/issues/101
+[gh-103]: https://github.com/rmccue/Requests/issues/103
+[gh-104]: https://github.com/rmccue/Requests/issues/104
+[gh-106]: https://github.com/rmccue/Requests/issues/106
+[gh-107]: https://github.com/rmccue/Requests/issues/107
+[gh-112]: https://github.com/rmccue/Requests/issues/112
+[gh-113]: https://github.com/rmccue/Requests/issues/113
+[gh-120]: https://github.com/rmccue/Requests/issues/120
+[gh-124]: https://github.com/rmccue/Requests/issues/124
+[gh-128]: https://github.com/rmccue/Requests/issues/128
+[gh-130]: https://github.com/rmccue/Requests/issues/130
+[gh-132]: https://github.com/rmccue/Requests/issues/132
+[gh-136]: https://github.com/rmccue/Requests/issues/136
+[gh-148]: https://github.com/rmccue/Requests/issues/148
+[gh-150]: https://github.com/rmccue/Requests/issues/150
+[gh-156]: https://github.com/rmccue/Requests/issues/156
+[gh-158]: https://github.com/rmccue/Requests/issues/158
+[gh-162]: https://github.com/rmccue/Requests/issues/162
+[gh-164]: https://github.com/rmccue/Requests/issues/164
+[gh-170]: https://github.com/rmccue/Requests/issues/170
+[gh-172]: https://github.com/rmccue/Requests/issues/172
+[gh-174]: https://github.com/rmccue/Requests/issues/174
+[gh-176]: https://github.com/rmccue/Requests/issues/176
+[gh-177]: https://github.com/rmccue/Requests/issues/177
+[gh-179]: https://github.com/rmccue/Requests/issues/179
+[gh-180]: https://github.com/rmccue/Requests/issues/180
+[gh-181]: https://github.com/rmccue/Requests/issues/181
+[gh-183]: https://github.com/rmccue/Requests/issues/183
+[gh-184]: https://github.com/rmccue/Requests/issues/184
+[gh-185]: https://github.com/rmccue/Requests/issues/185
+[gh-186]: https://github.com/rmccue/Requests/issues/186
+[gh-187]: https://github.com/rmccue/Requests/issues/187
+[gh-188]: https://github.com/rmccue/Requests/issues/188
+[gh-194]: https://github.com/rmccue/Requests/issues/194
+[gh-196]: https://github.com/rmccue/Requests/issues/196
+[gh-200]: https://github.com/rmccue/Requests/issues/200
+[gh-202]: https://github.com/rmccue/Requests/issues/202
+[gh-203]: https://github.com/rmccue/Requests/issues/203
+[gh-205]: https://github.com/rmccue/Requests/issues/205
+[gh-206]: https://github.com/rmccue/Requests/issues/206
+[gh-207]: https://github.com/rmccue/Requests/issues/207
+[gh-210]: https://github.com/rmccue/Requests/issues/210
+[gh-211]: https://github.com/rmccue/Requests/issues/211
+[gh-215]: https://github.com/rmccue/Requests/issues/215
+[gh-216]: https://github.com/rmccue/Requests/issues/216
+[gh-217]: https://github.com/rmccue/Requests/issues/217
+[gh-219]: https://github.com/rmccue/Requests/issues/219
+[gh-223]: https://github.com/rmccue/Requests/issues/223
+[gh-224]: https://github.com/rmccue/Requests/issues/224
+[gh-227]: https://github.com/rmccue/Requests/issues/227
+[gh-230]: https://github.com/rmccue/Requests/issues/230
+[gh-236]: https://github.com/rmccue/Requests/issues/236
+[gh-237]: https://github.com/rmccue/Requests/issues/237
+[gh-238]: https://github.com/rmccue/Requests/issues/238
+[gh-239]: https://github.com/rmccue/Requests/issues/239
+[gh-240]: https://github.com/rmccue/Requests/issues/240
+
+1.6.0
+-----
+- [Add multiple request support][#23] - Send multiple HTTP requests with both
+  fsockopen and cURL, transparently falling back to synchronous when
+  not supported.
+
+- [Add proxy support][#70] - HTTP proxies are now natively supported via a
+  [high-level API][docs/proxy]. Major props to Ozh for his fantastic work
+  on this.
+
+- [Verify host name for SSL requests][#63] - Requests is now the first and only
+  standalone HTTP library to fully verify SSL hostnames even with socket
+  connections. Thanks to Michael Adams, Dion Hulse, Jon Cave, and Pádraic Brady
+  for reviewing the crucial code behind this.
+
+- [Add cookie support][#64] - Adds built-in support for cookies (built entirely
+  as a high-level API)
+
+- [Add sessions][#62] - To compliment cookies, [sessions][docs/usage-advanced]
+  can be created with a base URL and default options, plus a shared cookie jar.
+
+- Add [PUT][#1], [DELETE][#3], and [PATCH][#2] request support
+
+- [Add Composer support][#6] - You can now install Requests via the
+  `rmccue/requests` package on Composer
+
+[docs/proxy]: http://requests.ryanmccue.info/docs/proxy.html
+[docs/usage-advanced]: http://requests.ryanmccue.info/docs/usage-advanced.html
+
+[#1]: https://github.com/rmccue/Requests/issues/1
+[#2]: https://github.com/rmccue/Requests/issues/2
+[#3]: https://github.com/rmccue/Requests/issues/3
+[#6]: https://github.com/rmccue/Requests/issues/6
+[#9]: https://github.com/rmccue/Requests/issues/9
+[#23]: https://github.com/rmccue/Requests/issues/23
+[#62]: https://github.com/rmccue/Requests/issues/62
+[#63]: https://github.com/rmccue/Requests/issues/63
+[#64]: https://github.com/rmccue/Requests/issues/64
+[#70]: https://github.com/rmccue/Requests/issues/70
+
+[View all changes][https://github.com/rmccue/Requests/compare/v1.5.0...v1.6.0]
+
+1.5.0
+-----
+Initial release!

+ 49 - 0
api/vendor/rmccue/requests/LICENSE

@@ -0,0 +1,49 @@
+Requests
+========
+
+Copyright (c) 2010-2012 Ryan McCue and contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+ComplexPie IRI Parser
+=====================
+
+Copyright (c) 2007-2010, Geoffrey Sneddon and Steve Minutillo.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+ * Neither the name of the SimplePie Team nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.

+ 152 - 0
api/vendor/rmccue/requests/README.md

@@ -0,0 +1,152 @@
+Requests for PHP
+================
+
+[![Build Status](https://travis-ci.org/rmccue/Requests.svg?branch=master)](https://travis-ci.org/rmccue/Requests)
+[![codecov.io](http://codecov.io/github/rmccue/Requests/coverage.svg?branch=master)](http://codecov.io/github/rmccue/Requests?branch=master)
+
+Requests is a HTTP library written in PHP, for human beings. It is roughly
+based on the API from the excellent [Requests Python
+library](http://python-requests.org/). Requests is [ISC
+Licensed](https://github.com/rmccue/Requests/blob/master/LICENSE) (similar to
+the new BSD license) and has no dependencies, except for PHP 5.2+.
+
+Despite PHP's use as a language for the web, its tools for sending HTTP requests
+are severely lacking. cURL has an
+[interesting API](http://php.net/manual/en/function.curl-setopt.php), to say the
+least, and you can't always rely on it being available. Sockets provide only low
+level access, and require you to build most of the HTTP response parsing
+yourself.
+
+We all have better things to do. That's why Requests was born.
+
+```php
+$headers = array('Accept' => 'application/json');
+$options = array('auth' => array('user', 'pass'));
+$request = Requests::get('https://api.github.com/gists', $headers, $options);
+
+var_dump($request->status_code);
+// int(200)
+
+var_dump($request->headers['content-type']);
+// string(31) "application/json; charset=utf-8"
+
+var_dump($request->body);
+// string(26891) "[...]"
+```
+
+Requests allows you to send  **HEAD**, **GET**, **POST**, **PUT**, **DELETE**, 
+and **PATCH** HTTP requests. You can add headers, form data, multipart files, 
+and parameters with simple arrays, and access the response data in the same way. 
+Requests uses cURL and fsockopen, depending on what your system has available, 
+but abstracts all the nasty stuff out of your way, providing a consistent API.
+
+
+Features
+--------
+
+- International Domains and URLs
+- Browser-style SSL Verification
+- Basic/Digest Authentication
+- Automatic Decompression
+- Connection Timeouts
+
+
+Installation
+------------
+
+### Install with Composer
+If you're using [Composer](https://github.com/composer/composer) to manage
+dependencies, you can add Requests with it.
+
+```sh
+composer require rmccue/requests
+```
+
+or
+
+    {
+        "require": {
+            "rmccue/requests": ">=1.0"
+        }
+    }
+
+### Install source from GitHub
+To install the source code:
+
+    $ git clone git://github.com/rmccue/Requests.git
+
+And include it in your scripts:
+
+    require_once '/path/to/Requests/library/Requests.php';
+
+You'll probably also want to register an autoloader:
+
+    Requests::register_autoloader();
+
+
+### Install source from zip/tarball
+Alternatively, you can fetch a [tarball][] or [zipball][]:
+
+    $ curl -L https://github.com/rmccue/Requests/tarball/master | tar xzv
+    (or)
+    $ wget https://github.com/rmccue/Requests/tarball/master -O - | tar xzv
+
+[tarball]: https://github.com/rmccue/Requests/tarball/master
+[zipball]: https://github.com/rmccue/Requests/zipball/master
+
+
+### Using a Class Loader
+If you're using a class loader (e.g., [Symfony Class Loader][]) for
+[PSR-0][]-style class loading:
+
+    $loader->registerPrefix('Requests', 'path/to/vendor/Requests/library');
+
+[Symfony Class Loader]: https://github.com/symfony/ClassLoader
+[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
+
+
+Documentation
+-------------
+The best place to start is our [prose-based documentation][], which will guide
+you through using Requests.
+
+After that, take a look at [the documentation for
+`Requests::request()`][request_method], where all the parameters are fully
+documented.
+
+Requests is [100% documented with PHPDoc](http://requests.ryanmccue.info/api/).
+If you find any problems with it, [create a new
+issue](https://github.com/rmccue/Requests/issues/new)!
+
+[prose-based documentation]: https://github.com/rmccue/Requests/blob/master/docs/README.md
+[request_method]: http://requests.ryanmccue.info/api/class-Requests.html#_request
+
+Testing
+-------
+
+Requests strives to have 100% code-coverage of the library with an extensive
+set of tests. We're not quite there yet, but [we're getting close][codecov].
+
+[codecov]: http://codecov.io/github/rmccue/Requests
+
+To run the test suite, first check that you have the [PHP
+JSON extension ](http://php.net/manual/en/book.json.php) enabled. Then
+simply:
+
+    $ cd tests
+    $ phpunit
+
+If you'd like to run a single set of tests, specify just the name:
+
+    $ phpunit Transport/cURL
+
+Contribute
+----------
+
+1. Check for open issues or open a new issue for a feature request or a bug
+2. Fork [the repository][] on Github to start making your changes to the
+    `master` branch (or branch off of it)
+3. Write a test which shows that the bug was fixed or that the feature works as expected
+4. Send a pull request and bug me until I merge it
+
+[the repository]: https://github.com/rmccue/Requests

+ 55 - 0
api/vendor/rmccue/requests/bin/create_pear_package.php

@@ -0,0 +1,55 @@
+<?php
+/**
+ * PEAR package builder
+ *
+ * Inspired by Twig's create_pear_package.php.
+ * @link https://raw.github.com/fabpot/Twig/master/bin/create_pear_package.php
+ * @author Twig Team
+ * @license BSD license
+ */
+
+if (!isset($argv[1]) || $argv[1] === '-h' || $argv[1] === '--help') {
+	echo 'usage: php ' . $argv[0] . ' <version> <stability>' . PHP_EOL;
+	echo PHP_EOL;
+	echo '    version:' . PHP_EOL;
+	echo '        Version of the package, in the form of major.minor.bug' . PHP_EOL;
+	echo PHP_EOL;
+	echo '    stability:' . PHP_EOL;
+	echo '        One of alpha, beta, stable' . PHP_EOL;
+	die();
+}
+
+if (!isset($argv[2])) {
+	die('You must provide the stability (alpha, beta, or stable)');
+}
+
+$context = array(
+	'date'          => gmdate('Y-m-d'),
+	'time'          => gmdate('H:m:00'),
+	'version'       => $argv[1],
+	'api_version'   => $argv[1],
+	'stability'     => $argv[2],
+	'api_stability' => $argv[2],
+);
+
+$context['files'] = '';
+$path = realpath(dirname(__FILE__).'/../library/Requests');
+foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
+	if (preg_match('/\.php$/', $file)) 	{
+		$name = str_replace($path . DIRECTORY_SEPARATOR, '', $file);
+		$name = str_replace(DIRECTORY_SEPARATOR, '/', $name);
+		$context['files'][] = "\t\t\t\t\t" . '<file install-as="Requests/' . $name . '" name="' . $name . '" role="php" />';
+	}
+}
+
+$context['files'] = implode("\n", $context['files']);
+
+$template = file_get_contents(dirname(__FILE__).'/../package.xml.tpl');
+$content = preg_replace_callback('/\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/', 'replace_parameters', $template);
+file_put_contents(dirname(__FILE__).'/../package.xml', $content);
+
+function replace_parameters($matches) {
+	global $context;
+
+	return isset($context[$matches[1]]) ? $context[$matches[1]] : null;
+}

+ 23 - 0
api/vendor/rmccue/requests/composer.json

@@ -0,0 +1,23 @@
+{
+	"name": "rmccue/requests",
+	"description": "A HTTP library written in PHP, for human beings.",
+	"homepage": "http://github.com/rmccue/Requests",
+	"license": "ISC",
+	"keywords": ["http", "idna", "iri", "ipv6", "curl", "sockets", "fsockopen"],
+	"authors": [
+		{
+			"name": "Ryan McCue",
+			"homepage": "http://ryanmccue.info"
+		}
+	],
+	"require": {
+		"php": ">=5.2"
+	},
+	"require-dev": {
+		"requests/test-server": "dev-master"
+	},
+	"type": "library",
+	"autoload": {
+		"psr-0": {"Requests": "library/"}
+	}
+}

+ 28 - 0
api/vendor/rmccue/requests/docs/README.md

@@ -0,0 +1,28 @@
+Documentation
+=============
+
+If you're here, you're looking for documentation for Requests! The documents
+here are prose; you might also want to check out the [API documentation][].
+
+[API documentation]: http://requests.ryanmccue.info/api/
+
+* Introduction
+	* [Goals][goals]
+	* [Why should I use Requests instead of X?][why-requests]
+* Usage
+	* [Making a request][usage]
+	* [Advanced usage][usage-advanced]
+	* [Authenticating your request][authentication]
+* Advanced Usage
+	* [Custom authentication][authentication-custom]
+	* [Requests through proxy][proxy]
+	* [Hooking system][hooks]
+
+[goals]: goals.md
+[why-requests]: why-requests.md
+[usage]: usage.md
+[usage-advanced]: usage-advanced.md
+[authentication]: authentication.md
+[authentication-custom]: authentication-custom.md
+[hooks]: hooks.md
+[proxy]: proxy.md

+ 44 - 0
api/vendor/rmccue/requests/docs/authentication-custom.md

@@ -0,0 +1,44 @@
+Custom Authentication
+=====================
+Custom authentication handlers are designed to be extremely simple to write.
+In order to write a handler, you'll need to implement the `Requests_Auth`
+interface.
+
+An instance of this handler is then passed in by the user via the `auth`
+option, just like for normal authentication.
+
+Let's say we have a HTTP endpoint that checks for the `Hotdog` header and
+authenticates you if said header is set to `Yummy`. (I don't know of any
+services that do this; perhaps this is a market waiting to be tapped?)
+
+```php
+class MySoftware_Auth_Hotdog implements Requests_Auth {
+	protected $password;
+
+	public function __construct($password) {
+		$this->password = $password;
+	}
+
+	public function register(Requests_Hooks &$hooks) {
+		$hooks->register('requests.before_request', array(&$this, 'before_request'));
+	}
+
+	public function before_request(&$url, &$headers, &$data, &$type, &$options) {
+		$headers['Hotdog'] = $this->password;
+	}
+}
+```
+
+We then use this in our request calls:
+
+```
+$options = array(
+	'auth' => new MySoftware_Auth_Hotdog('yummy')
+);
+$response = Requests::get('http://hotdogbin.org/admin', array(), $options);
+```
+
+(For more information on how to register and use hooks, see the [hooking
+system documentation][hooks])
+
+[hooks]: hooks.md

+ 31 - 0
api/vendor/rmccue/requests/docs/authentication.md

@@ -0,0 +1,31 @@
+Authentication
+==============
+Many requests that you make will require authentication of some type. Requests
+includes support out of the box for HTTP Basic authentication, with more
+built-ins coming soon.
+
+Making a Basic authenticated call is ridiculously easy:
+
+```php
+$options = array(
+	'auth' => new Requests_Auth_Basic(array('user', 'password'))
+);
+Requests::get('http://httpbin.org/basic-auth/user/password', array(), $options);
+```
+
+As Basic authentication is usually what you want when you specify a username
+and password, you can also just pass in an array as a shorthand:
+
+```php
+$options = array(
+	'auth' => array('user', 'password')
+);
+Requests::get('http://httpbin.org/basic-auth/user/password', array(), $options);
+```
+
+Note that POST/PUT can also take a data parameter, so you also need that
+before `$options`:
+
+```php
+Requests::post('http://httpbin.org/basic-auth/user/password', array(), null, $options);
+```

+ 29 - 0
api/vendor/rmccue/requests/docs/goals.md

@@ -0,0 +1,29 @@
+Goals
+=====
+
+1. **Simple interface**
+
+   Requests is designed to provide a simple, unified interface to making
+   requests, regardless of what is available on the system. This means not worrying.
+
+2. **Fully tested code**
+
+   Requests strives to have 90%+ code coverage from the unit tests, aiming for
+   the ideal 100%. Introducing new features always means introducing new tests
+
+   (Note: some parts of the code are not covered by design. These sections are
+   marked with `@codeCoverageIgnore` tags)
+
+3. **Maximum compatibility**
+
+   No matter what you have installed on your system, you should be able to run
+   Requests. We use cURL if it's available, and fallback to sockets otherwise.
+   We require only a baseline of PHP 5.2, leaving the choice of PHP minimum
+   requirement fully in your hands, and giving you the ability to support many
+   more hosts.
+
+4. **No dependencies**
+
+   Requests is designed to be entirely self-contained and doesn't require
+   anything else at all. You can run Requests on an entirely stock PHP build
+   without any additional extensions outside the standard library.

+ 96 - 0
api/vendor/rmccue/requests/docs/hooks.md

@@ -0,0 +1,96 @@
+Hooks
+=====
+Requests has a hook system that you can use to manipulate parts of the request
+process along with internal transport hooks.
+
+Check out the [API documentation for `Requests_Hooks`][requests_hooks] for more
+information on how to use the hook system.
+
+Available Hooks
+---------------
+
+* `requests.before_request`
+
+    Alter the request before it's sent to the transport.
+
+    Parameters: `string &$url`, `array &$headers`, `array|string &$data`,
+    `string &$type`, `array &$options`
+
+* `requests.before_parse`
+
+    Alter the raw HTTP response before parsing
+
+    Parameters: `string &$response`
+
+* `requests.after_request`
+
+    Alter the response object before it's returned to the user
+
+    Parameters: `Requests_Response &$return`
+
+* `curl.before_request`
+
+    Set cURL options before the transport sets any (note that Requests may
+    override these)
+
+    Parameters: `cURL resource &$fp`
+
+* `curl.before_send`
+
+    Set cURL options just before the request is actually sent via `curl_exec`
+
+    Parameters: `cURL resource &$fp`
+
+* `curl.after_request`
+
+    Alter the raw HTTP response before returning for parsing
+
+    Parameters: `string &$response, array &$info`
+
+    `$info` contains the associated array as defined in [curl-getinfo-returnvalues](http://php.net/manual/en/function.curl-getinfo.php#refsect1-function.curl-getinfo-returnvalues)
+
+* `fsockopen.before_request`
+
+    Run events before the transport does anything
+
+* `fsockopen.after_headers`
+
+    Add extra headers before the body begins (i.e. before `\r\n\r\n`)
+
+    Parameters: `string &$out`
+
+* `fsockopen.before_send`
+
+    Add body data before sending the request
+
+    Parameters: `string &$out`
+
+* `fsockopen.after_send`
+
+   Run events after writing the data to the socket
+
+* `fsockopen.after_request`
+
+    Alter the raw HTTP response before returning for parsing
+
+    Parameters: `string &$response, array &$info`
+
+    `$info` contains the associated array as defined in [stream-get-meta-data-returnvalues](http://php.net/manual/en/function.stream-get-meta-data.php#refsect1-function.stream-get-meta-data-returnvalues)
+
+
+Registering Hooks
+-----------------
+Note: if you're doing this in an authentication handler, see the [Custom
+Authentication guide][authentication-custom] instead.
+
+[authentication-custom]: authentication-custom.md
+
+In order to register your own hooks, you need to instantiate `Requests_hooks`
+and pass this in via the 'hooks' option.
+
+```php
+$hooks = new Requests_Hooks();
+$hooks->register('requests.after_request', 'mycallback');
+
+$request = Requests::get('http://httpbin.org/get', array(), array('hooks' => $hooks));
+```

+ 23 - 0
api/vendor/rmccue/requests/docs/proxy.md

@@ -0,0 +1,23 @@
+Proxy Support
+=============
+
+You can easily make requests through HTTP proxies.
+
+To make requests through an open proxy, specify the following options:
+
+```php
+$options = array(
+	'proxy' => '127.0.0.1:3128'
+);
+Requests::get('http://httpbin.org/ip', array(), $options);
+```
+
+If your proxy needs you to authenticate, the option will become an array like
+the following:
+
+```php
+$options = array(
+	'proxy' => array( '127.0.0.1:3128', 'my_username', 'my_password' )
+);
+Requests::get('http://httpbin.org/ip', array(), $options);
+```

+ 74 - 0
api/vendor/rmccue/requests/docs/usage-advanced.md

@@ -0,0 +1,74 @@
+Advanced Usage
+==============
+
+Session Handling
+----------------
+Making multiple requests to the same site with similar options can be a pain,
+since you end up repeating yourself. The Session object can be used to set
+default parameters for these.
+
+Let's simulate communicating with GitHub.
+
+```php
+$session = new Requests_Session('https://api.github.com/');
+$session->headers['X-ContactAuthor'] = 'rmccue';
+$session->useragent = 'My-Awesome-App';
+
+$response = $session->get('/zen');
+```
+
+You can use the `url`, `headers`, `data` and `options` properties of the Session
+object to set the defaults for this session, and the constructor also takes
+parameters in the same order as `Requests::request()`. Accessing any other
+properties will set the corresponding key in the options array; that is:
+
+```php
+// Setting the property...
+$session->useragent = 'My-Awesome-App';
+
+// ...is the same as setting the option
+$session->options['useragent'] = 'My-Awesome-App';
+```
+
+
+Secure Requests with SSL
+------------------------
+By default, HTTPS requests will use the most secure options available:
+
+```php
+$response = Requests::get('https://httpbin.org/');
+```
+
+Requests bundles certificates from the [Mozilla certificate authority list][],
+which is the same list of root certificates used in most browsers. If you're
+accessing sites with certificates from other CAs, or self-signed certificates,
+you can point Requests to a custom CA list in PEM form (the same format
+accepted by cURL and OpenSSL):
+
+```php
+$options = array(
+	'verify' => '/path/to/cacert.pem'
+);
+$response = Requests::get('https://httpbin.org/', array(), $options);
+```
+
+Alternatively, if you want to disable verification completely, this is possible
+with `'verify' => false`, but note that this is extremely insecure and should be
+avoided.
+
+### Security Note
+Requests supports SSL across both cURL and fsockopen in a transparent manner.
+Unlike other PHP HTTP libraries, support for verifying the certificate name is
+built-in; that is, a request for `https://github.com/` will actually verify the
+certificate's name even with the fsockopen transport. This makes Requests the
+first and currently only PHP HTTP library that supports full SSL verification.
+
+(Note that WordPress now also supports this verification, thanks to efforts by
+the Requests development team.)
+
+(See also the [related PHP][php-bug-47030] and [OpenSSL-related][php-bug-55820]
+bugs in PHP for more information on Subject Alternate Name field.)
+
+[Mozilla certificate authority list]: http://www.mozilla.org/projects/security/certs/
+[php-bug-47030]: https://bugs.php.net/bug.php?id=47030
+[php-bug-55820]:https://bugs.php.net/bug.php?id=55820

+ 154 - 0
api/vendor/rmccue/requests/docs/usage.md

@@ -0,0 +1,154 @@
+Usage
+=====
+
+Ready to go? Make sure you have Requests installed before attempting any of the
+steps in this guide.
+
+
+Loading Requests
+----------------
+Before we can load Requests up, we'll need to make sure it's loaded. This is a
+simple two-step:
+
+```php
+// First, include Requests
+include('/path/to/library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+```
+
+If you'd like to bring along your own autoloader, you can forget about this
+completely.
+
+
+Make a GET Request
+------------------
+One of the most basic things you can do with HTTP is make a GET request.
+
+Let's grab GitHub's public timeline:
+
+```php
+$response = Requests::get('https://github.com/timeline.json');
+```
+
+`$response` is now a **Requests_Response** object. Response objects are what
+you'll be working with whenever you want to get data back from your request.
+
+
+Using the Response Object
+-------------------------
+Now that we have the response from GitHub, let's get the body of the response.
+
+```php
+var_dump($response->body);
+// string(42865) "[{"repository":{"url":"...
+```
+
+
+Custom Headers
+--------------
+If you want to add custom headers to the request, simply pass them in as an
+associative array as the second parameter:
+
+```php
+$response = Requests::get('https://github.com/timeline.json', array('X-Requests' => 'Is Awesome!'));
+```
+
+
+Make a POST Request
+-------------------
+Making a POST request is very similar to making a GET:
+
+```php
+$response = Requests::post('http://httpbin.org/post');
+```
+
+You'll probably also want to pass in some data. You can pass in either a
+string, an array or an object (Requests uses [`http_build_query`][build_query]
+internally) as the third parameter (after the URL and headers):
+
+[build_query]: http://php.net/http_build_query
+
+```php
+$data = array('key1' => 'value1', 'key2' => 'value2');
+$response = Requests::post('http://httpbin.org/post', array(), $data);
+var_dump($response->body);
+```
+
+This gives the output:
+
+	string(503) "{
+	  "origin": "124.191.162.147", 
+	  "files": {}, 
+	  "form": {
+	    "key2": "value2", 
+	    "key1": "value1"
+	  }, 
+	  "headers": {
+	    "Content-Length": "23", 
+	    "Accept-Encoding": "deflate;q=1.0, compress;q=0.5, gzip;q=0.5", 
+	    "X-Forwarded-Port": "80", 
+	    "Connection": "keep-alive", 
+	    "User-Agent": "php-requests/1.6-dev", 
+	    "Host": "httpbin.org", 
+	    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
+	  }, 
+	  "url": "http://httpbin.org/post", 
+	  "args": {}, 
+	  "data": ""
+	}"
+
+To send raw data, simply pass in a string instead. You'll probably also want to
+set the Content-Type header to ensure the remote server knows what you're
+sending it:
+
+```php
+$url = 'https://api.github.com/some/endpoint';
+$headers = array('Content-Type' => 'application/json');
+$data = array('some' => 'data');
+$response = Requests::post($url, $headers, json_encode($data));
+```
+
+Note that if you don't manually specify a Content-Type header, Requests has
+undefined behaviour for the header. It may be set to various values depending
+on the internal execution path, so it's recommended to set this explicitly if
+you need to.
+
+
+Status Codes
+------------
+The Response object also gives you access to the status code:
+
+```php
+var_dump($response->status_code);
+// int(200)
+```
+
+You can also easily check if this status code is a success code, or if it's an
+error:
+
+```php
+var_dump($response->success);
+// bool(true)
+```
+
+
+Response Headers
+----------------
+We can also grab headers pretty easily:
+
+```php
+var_dump($response->headers['Date']);
+// string(29) "Thu, 09 Feb 2012 15:22:06 GMT"
+```
+
+Note that this is case-insensitive, so the following are all equivalent:
+
+* `$response->headers['Date']`
+* `$response->headers['date']`
+* `$response->headers['DATE']`
+* `$response->headers['dAtE']`
+
+If a header isn't set, this will give `null`. You can also check with
+`isset($response->headers['date'])`

+ 192 - 0
api/vendor/rmccue/requests/docs/why-requests.md

@@ -0,0 +1,192 @@
+Why Requests Instead of X?
+==========================
+This is a quick look at why you should use Requests instead of another
+solution. Keep in mind though that these are my point of view, and they may not
+be issues for you.
+
+As always with software, you should choose what you think is best.
+
+
+Why should I use Requests?
+--------------------------
+1. **Designed for maximum compatibility**
+
+   The realities of working with widely deployable software mean that awesome
+   PHP features aren't always available. PHP 5.3, cURL, OpenSSL and more are not
+   necessarily going to be available on every system. While you're welcome to
+   require PHP 5.3, 5.4 or even 5.5, it's not our job to force you to use those.
+
+   (The WordPress project estimates [about 60%][wpstats] of hosts are running
+   PHP 5.2, so this is a serious issue for developers working on large
+   deployable projects.)
+
+   Don't worry though, Requests will automatically use better features where
+   possible, giving you an extra speed boost with cURL.
+
+2. **Simple API**
+
+   Requests' API is designed to be able to be learnt in 10 minutes. Everything
+   from basic requests all the way up to advanced usage involving custom SSL
+   certificates and stored cookies is handled by a simple API.
+
+   Other HTTP libraries optimize for the library developer's time; **Requests
+   optimizes for your time**.
+
+3. **Thoroughly tested**
+
+   Requests is [continuously integrated with Travis][travis] and test coverage
+   is [constantly monitored with Coveralls][coveralls] to give you confidence in
+   the library. We aim for test coverage **over 90%** at all times, and new
+   features require new tests to go along with them. This ensures that you can
+   be confident in the quality of the code, as well as being able to update to
+   the latest version of Requests without worrying about compatibility.
+
+4. **Secure by default**
+
+   Unlike other HTTP libraries, Requests is secure by default. Requests is the
+   **first and currently only** standalone HTTP library to
+   **[fully verify][requests_ssl] all HTTPS requests** even without cURL. We
+   also bundle the latest root certificate authorities to ensure that your
+   secure requests are actually secure.
+
+   (Of note is that WordPress as of version 3.7 also supports full checking of
+   the certificates, thanks to [evangelism efforts on our behalf][wpssl].
+   Together, we are the only HTTP libraries in PHP to fully verify certificates
+   to the same level as browsers.)
+
+5. **Extensible from the core**
+
+   If you need low-level access to Requests' internals, simply plug your
+   callbacks in via the built-in [hooking system][] and mess around as much as
+   you want. Requests' simple hooking system is so powerful that both
+   authentication handlers and cookie support is actually handled internally
+   with hooks.
+
+[coveralls]: https://coveralls.io/r/rmccue/Requests
+[hooking system]: hooks.md
+[requests_ssl]: https://github.com/rmccue/Requests/blob/master/library/Requests/SSL.php
+[travis]: https://travis-ci.org/rmccue/Requests
+[wpssl]: http://core.trac.wordpress.org/ticket/25007
+
+
+Why shouldn't I use...
+----------------------
+Requests isn't the first or only HTTP library in PHP and it's important to
+acknowledge the other solutions out there. Here's why you should use Requests
+instead of something else, in our opinion.
+
+
+### cURL
+
+1. **Not every host has cURL installed**
+
+   cURL is far from being ubiquitous, so you can't rely on it always being
+   available when distributing software. Anecdotal data collected from various
+   projects indicates that cURL is available on roughly 90% of hosts, but that
+   leaves 10% of hosts without it.
+
+2. **cURL's interface sucks**
+
+   cURL's interface was designed for PHP 4, and hence uses resources with
+   horrible functions such as `curl_setopt()`. Combined with that, it uses 229
+   global constants, polluting the global namespace horribly.
+
+   Requests, on the other hand, exposes only a handful of classes to the
+   global namespace, most of which are for internal use. You can learn to use
+   the `Requests::request()` method and the `Requests_Response` object in the
+   space of 10 minutes and you already know how to use Requests.
+
+
+### Guzzle
+
+1. **Requires cURL and PHP 5.3+**
+
+   Guzzle is designed to be a client to fit a large number of installations, but
+   as a result of optimizing for Guzzle developer time, it uses cURL as an
+   underlying transport. As noted above, this is a majority of systems, but
+   far from all.
+
+   The same is true for PHP 5.3+. While we'd all love to rely on PHP's newer
+   features, the fact is that a huge percentage of hosts are still running on
+   PHP 5.2. (The WordPress project estimates [about 60%][wpstats] of hosts are
+   running PHP 5.2.)
+
+2. **Not just a HTTP client**
+
+   Guzzle is not intended to just be a HTTP client, but rather to be a
+   full-featured REST client. Requests is just a HTTP client, intentionally. Our
+   development strategy is to act as a low-level library that REST clients can
+   easily be built on, not to provide the whole kitchen sink for you.
+
+   If you want to rapidly develop a web service client using a framework, Guzzle
+   will suit you perfectly. On the other hand, if you want a HTTP client without
+   all the rest, Requests is the way to go.
+
+[wpstats]: http://wordpress.org/about/stats/
+
+
+### Buzz
+
+1. **Requires PHP 5.3+**
+
+   As with Guzzle, while PHP 5.3+ is awesome, you can't always rely on it being
+   on a host. With widely distributable software, this is a huge problem.
+
+2. **Not transport-transparent**
+
+   For making certain types of requests, such as multi-requests, you can't rely
+   on a high-level abstraction and instead have to use the low-level transports.
+   This really gains nothing (other than a fancy interface) over just using the
+   methods directly and means that you can't rely on features to be available.
+
+
+### fsockopen
+
+1. **Very low-level**
+
+   fsockopen is used for working with sockets directly, so it only knows about
+   the transport layer (TCP in our case), not anything higher (i.e. HTTP on the
+   application layer). To be able to use fsockopen as a HTTP client, you need
+   to write all the HTTP code yourself, and once you're done, you'll end up
+   with something that is almost exactly like Requests.
+
+
+### PEAR HTTP_Request2
+
+1. **Requires PEAR**
+
+   PEAR is (in theory) a great distribution system (with a less than wonderful
+   implementation), however it is not ubiquitous, as many hosts disable it to
+   save on space that most people aren't going to use anyway.
+
+   PEAR is also a pain for users. Users want to be able to download a zip of
+   your project without needing to install anything else from PEAR.
+
+   (If you really want though, Requests is available via PEAR. Check the README
+   to see how to grab it.)
+
+2. **Depends on other PEAR utilities**
+
+   HTTP\_Request2 requires Net_URL2 in order to function, locking you in to
+   using PEAR for your project.
+
+   Requests is entirely self-contained, and includes all the libraries it needs
+   (for example, Requests\_IRI is based on ComplexPie\_IRI by Geoffrey Sneddon).
+
+
+### PECL HttpRequest
+
+1. **Requires a PECL extension**
+
+   Similar to PEAR, users aren't big fans of installing extra libraries. Unlike
+   PEAR though, PECL extensions require compiling, which end users will be
+   unfamiliar with. In addition, on systems where users do not have full
+   control over PHP, they will be unable to install custom extensions.
+
+
+### Zend Framework's Zend\_Http\_Client
+
+1. **Requires other parts of the Zend Framework**
+
+   Similar to HTTP_Request2, Zend's client is not fully self-contained and
+   requires other components from the framework.

+ 16 - 0
api/vendor/rmccue/requests/examples/basic-auth.php

@@ -0,0 +1,16 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Now let's make a request!
+$options = array(
+	'auth' => array('someuser', 'password')
+);
+$request = Requests::get('http://httpbin.org/basic-auth/someuser/password', array(), $options);
+
+// Check what we received
+var_dump($request);

+ 16 - 0
api/vendor/rmccue/requests/examples/cookie.php

@@ -0,0 +1,16 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Say you need to fake a login cookie
+$c = new Requests_Cookie('login_uid', 'something');
+
+// Now let's make a request!
+$request = Requests::get('http://httpbin.org/cookies', array('Cookie' => $c->formatForHeader()));
+
+// Check what we received
+var_dump($request);

+ 20 - 0
api/vendor/rmccue/requests/examples/cookie_jar.php

@@ -0,0 +1,20 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Say you need to fake a login cookie
+$c = new Requests_Cookie_Jar(['login_uid' =>  'something']);
+
+// Now let's make a request!
+$request = Requests::get(
+	'http://httpbin.org/cookies', // Url
+	[],  // No need to set the headers the Jar does this for us
+	['cookies' => $c] // Pass in the Jar as an option
+);
+
+// Check what we received
+var_dump($request);

+ 13 - 0
api/vendor/rmccue/requests/examples/get.php

@@ -0,0 +1,13 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Now let's make a request!
+$request = Requests::get('http://httpbin.org/get', array('Accept' => 'application/json'));
+
+// Check what we received
+var_dump($request);

+ 45 - 0
api/vendor/rmccue/requests/examples/multiple.php

@@ -0,0 +1,45 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Setup what we want to request
+$requests = array(
+	array(
+		'url' => 'http://httpbin.org/get',
+		'headers' => array('Accept' => 'application/javascript'),
+	),
+	'post' => array(
+		'url' => 'http://httpbin.org/post',
+		'data' => array('mydata' => 'something'),
+	),
+	'delayed' => array(
+		'url' => 'http://httpbin.org/delay/10',
+		'options' => array(
+			'timeout' => 20,
+		),
+	),
+);
+
+// Setup a callback
+function my_callback(&$request, $id) {
+	var_dump($id, $request);
+}
+
+// Tell Requests to use the callback
+$options = array(
+	'complete' => 'my_callback',
+);
+
+// Send the request!
+$responses = Requests::request_multiple($requests, $options);
+
+// Note: the response from the above call will be an associative array matching
+// $requests with the response data, however we've already handled it in
+// my_callback() anyway!
+//
+// If you don't believe me, uncomment this:
+# var_dump($responses);

+ 13 - 0
api/vendor/rmccue/requests/examples/post.php

@@ -0,0 +1,13 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Now let's make a request!
+$request = Requests::post('http://httpbin.org/post', array(), array('mydata' => 'something'));
+
+// Check what we received
+var_dump($request);

+ 18 - 0
api/vendor/rmccue/requests/examples/proxy.php

@@ -0,0 +1,18 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Now let's make a request via a proxy.
+$options = array(
+	'proxy' => '127.0.0.1:8080', // syntax: host:port, eg 12.13.14.14:8080 or someproxy.com:3128
+	// If you need to authenticate, use the following syntax:
+	// 'proxy' => array( '127.0.0.1:8080', 'username', 'password' ),
+);
+$request = Requests::get('http://httpbin.org/ip', array(), $options );
+
+// See result
+var_dump($request->body);

+ 24 - 0
api/vendor/rmccue/requests/examples/session.php

@@ -0,0 +1,24 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Set up our session
+$session = new Requests_Session('http://httpbin.org/');
+$session->headers['Accept'] = 'application/json';
+$session->useragent = 'Awesomesauce';
+
+// Now let's make a request!
+$request = $session->get('/get');
+
+// Check what we received
+var_dump($request);
+
+// Let's check our user agent!
+$request = $session->get('/user-agent');
+
+// And check again
+var_dump($request);

+ 17 - 0
api/vendor/rmccue/requests/examples/timeout.php

@@ -0,0 +1,17 @@
+<?php
+
+// First, include Requests
+include('../library/Requests.php');
+
+// Next, make sure Requests can load internal classes
+Requests::register_autoloader();
+
+// Define a timeout of 2.5 seconds
+$options = array(
+	'timeout' => 2.5,
+);
+
+// Now let's make a request to a page that will delay its response by 3 seconds
+$request = Requests::get('http://httpbin.org/delay/3', array(), $options);
+
+// An exception will be thrown, stating a timeout of the request !

+ 980 - 0
api/vendor/rmccue/requests/library/Requests.php

@@ -0,0 +1,980 @@
+<?php
+/**
+ * Requests for PHP
+ *
+ * Inspired by Requests for Python.
+ *
+ * Based on concepts from SimplePie_File, RequestCore and WP_Http.
+ *
+ * @package Requests
+ */
+
+/**
+ * Requests for PHP
+ *
+ * Inspired by Requests for Python.
+ *
+ * Based on concepts from SimplePie_File, RequestCore and WP_Http.
+ *
+ * @package Requests
+ */
+class Requests {
+	/**
+	 * POST method
+	 *
+	 * @var string
+	 */
+	const POST = 'POST';
+
+	/**
+	 * PUT method
+	 *
+	 * @var string
+	 */
+	const PUT = 'PUT';
+
+	/**
+	 * GET method
+	 *
+	 * @var string
+	 */
+	const GET = 'GET';
+
+	/**
+	 * HEAD method
+	 *
+	 * @var string
+	 */
+	const HEAD = 'HEAD';
+
+	/**
+	 * DELETE method
+	 *
+	 * @var string
+	 */
+	const DELETE = 'DELETE';
+
+	/**
+	 * OPTIONS method
+	 *
+	 * @var string
+	 */
+	const OPTIONS = 'OPTIONS';
+
+	/**
+	 * TRACE method
+	 *
+	 * @var string
+	 */
+	const TRACE = 'TRACE';
+
+	/**
+	 * PATCH method
+	 *
+	 * @link https://tools.ietf.org/html/rfc5789
+	 * @var string
+	 */
+	const PATCH = 'PATCH';
+
+	/**
+	 * Default size of buffer size to read streams
+	 *
+	 * @var integer
+	 */
+	const BUFFER_SIZE = 1160;
+
+	/**
+	 * Current version of Requests
+	 *
+	 * @var string
+	 */
+	const VERSION = '1.7';
+
+	/**
+	 * Registered transport classes
+	 *
+	 * @var array
+	 */
+	protected static $transports = array();
+
+	/**
+	 * Selected transport name
+	 *
+	 * Use {@see get_transport()} instead
+	 *
+	 * @var array
+	 */
+	public static $transport = array();
+
+	/**
+	 * Default certificate path.
+	 *
+	 * @see Requests::get_certificate_path()
+	 * @see Requests::set_certificate_path()
+	 *
+	 * @var string
+	 */
+	protected static $certificate_path;
+
+	/**
+	 * This is a static class, do not instantiate it
+	 *
+	 * @codeCoverageIgnore
+	 */
+	private function __construct() {}
+
+	/**
+	 * Autoloader for Requests
+	 *
+	 * Register this with {@see register_autoloader()} if you'd like to avoid
+	 * having to create your own.
+	 *
+	 * (You can also use `spl_autoload_register` directly if you'd prefer.)
+	 *
+	 * @codeCoverageIgnore
+	 *
+	 * @param string $class Class name to load
+	 */
+	public static function autoloader($class) {
+		// Check that the class starts with "Requests"
+		if (strpos($class, 'Requests') !== 0) {
+			return;
+		}
+
+		$file = str_replace('_', '/', $class);
+		if (file_exists(dirname(__FILE__) . '/' . $file . '.php')) {
+			require_once(dirname(__FILE__) . '/' . $file . '.php');
+		}
+	}
+
+	/**
+	 * Register the built-in autoloader
+	 *
+	 * @codeCoverageIgnore
+	 */
+	public static function register_autoloader() {
+		spl_autoload_register(array('Requests', 'autoloader'));
+	}
+
+	/**
+	 * Register a transport
+	 *
+	 * @param string $transport Transport class to add, must support the Requests_Transport interface
+	 */
+	public static function add_transport($transport) {
+		if (empty(self::$transports)) {
+			self::$transports = array(
+				'Requests_Transport_cURL',
+				'Requests_Transport_fsockopen',
+			);
+		}
+
+		self::$transports = array_merge(self::$transports, array($transport));
+	}
+
+	/**
+	 * Get a working transport
+	 *
+	 * @throws Requests_Exception If no valid transport is found (`notransport`)
+	 * @return Requests_Transport
+	 */
+	protected static function get_transport($capabilities = array()) {
+		// Caching code, don't bother testing coverage
+		// @codeCoverageIgnoreStart
+		// array of capabilities as a string to be used as an array key
+		ksort($capabilities);
+		$cap_string = serialize($capabilities);
+
+		// Don't search for a transport if it's already been done for these $capabilities
+		if (isset(self::$transport[$cap_string]) && self::$transport[$cap_string] !== null) {
+			return new self::$transport[$cap_string]();
+		}
+		// @codeCoverageIgnoreEnd
+
+		if (empty(self::$transports)) {
+			self::$transports = array(
+				'Requests_Transport_cURL',
+				'Requests_Transport_fsockopen',
+			);
+		}
+
+		// Find us a working transport
+		foreach (self::$transports as $class) {
+			if (!class_exists($class)) {
+				continue;
+			}
+
+			$result = call_user_func(array($class, 'test'), $capabilities);
+			if ($result) {
+				self::$transport[$cap_string] = $class;
+				break;
+			}
+		}
+		if (self::$transport[$cap_string] === null) {
+			throw new Requests_Exception('No working transports found', 'notransport', self::$transports);
+		}
+
+		return new self::$transport[$cap_string]();
+	}
+
+	/**#@+
+	 * @see request()
+	 * @param string $url
+	 * @param array $headers
+	 * @param array $options
+	 * @return Requests_Response
+	 */
+	/**
+	 * Send a GET request
+	 */
+	public static function get($url, $headers = array(), $options = array()) {
+		return self::request($url, $headers, null, self::GET, $options);
+	}
+
+	/**
+	 * Send a HEAD request
+	 */
+	public static function head($url, $headers = array(), $options = array()) {
+		return self::request($url, $headers, null, self::HEAD, $options);
+	}
+
+	/**
+	 * Send a DELETE request
+	 */
+	public static function delete($url, $headers = array(), $options = array()) {
+		return self::request($url, $headers, null, self::DELETE, $options);
+	}
+
+	/**
+	 * Send a TRACE request
+	 */
+	public static function trace($url, $headers = array(), $options = array()) {
+		return self::request($url, $headers, null, self::TRACE, $options);
+	}
+	/**#@-*/
+
+	/**#@+
+	 * @see request()
+	 * @param string $url
+	 * @param array $headers
+	 * @param array $data
+	 * @param array $options
+	 * @return Requests_Response
+	 */
+	/**
+	 * Send a POST request
+	 */
+	public static function post($url, $headers = array(), $data = array(), $options = array()) {
+		return self::request($url, $headers, $data, self::POST, $options);
+	}
+	/**
+	 * Send a PUT request
+	 */
+	public static function put($url, $headers = array(), $data = array(), $options = array()) {
+		return self::request($url, $headers, $data, self::PUT, $options);
+	}
+
+	/**
+	 * Send an OPTIONS request
+	 */
+	public static function options($url, $headers = array(), $data = array(), $options = array()) {
+		return self::request($url, $headers, $data, self::OPTIONS, $options);
+	}
+
+	/**
+	 * Send a PATCH request
+	 *
+	 * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
+	 * specification recommends that should send an ETag
+	 *
+	 * @link https://tools.ietf.org/html/rfc5789
+	 */
+	public static function patch($url, $headers, $data = array(), $options = array()) {
+		return self::request($url, $headers, $data, self::PATCH, $options);
+	}
+	/**#@-*/
+
+	/**
+	 * Main interface for HTTP requests
+	 *
+	 * This method initiates a request and sends it via a transport before
+	 * parsing.
+	 *
+	 * The `$options` parameter takes an associative array with the following
+	 * options:
+	 *
+	 * - `timeout`: How long should we wait for a response?
+	 *    Note: for cURL, a minimum of 1 second applies, as DNS resolution
+	 *    operates at second-resolution only.
+	 *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
+	 * - `connect_timeout`: How long should we wait while trying to connect?
+	 *    (float, seconds with a millisecond precision, default: 10, example: 0.01)
+	 * - `useragent`: Useragent to send to the server
+	 *    (string, default: php-requests/$version)
+	 * - `follow_redirects`: Should we follow 3xx redirects?
+	 *    (boolean, default: true)
+	 * - `redirects`: How many times should we redirect before erroring?
+	 *    (integer, default: 10)
+	 * - `blocking`: Should we block processing on this request?
+	 *    (boolean, default: true)
+	 * - `filename`: File to stream the body to instead.
+	 *    (string|boolean, default: false)
+	 * - `auth`: Authentication handler or array of user/password details to use
+	 *    for Basic authentication
+	 *    (Requests_Auth|array|boolean, default: false)
+	 * - `proxy`: Proxy details to use for proxy by-passing and authentication
+	 *    (Requests_Proxy|array|string|boolean, default: false)
+	 * - `max_bytes`: Limit for the response body size.
+	 *    (integer|boolean, default: false)
+	 * - `idn`: Enable IDN parsing
+	 *    (boolean, default: true)
+	 * - `transport`: Custom transport. Either a class name, or a
+	 *    transport object. Defaults to the first working transport from
+	 *    {@see getTransport()}
+	 *    (string|Requests_Transport, default: {@see getTransport()})
+	 * - `hooks`: Hooks handler.
+	 *    (Requests_Hooker, default: new Requests_Hooks())
+	 * - `verify`: Should we verify SSL certificates? Allows passing in a custom
+	 *    certificate file as a string. (Using true uses the system-wide root
+	 *    certificate store instead, but this may have different behaviour
+	 *    across transports.)
+	 *    (string|boolean, default: library/Requests/Transport/cacert.pem)
+	 * - `verifyname`: Should we verify the common name in the SSL certificate?
+	 *    (boolean: default, true)
+	 * - `data_format`: How should we send the `$data` parameter?
+	 *    (string, one of 'query' or 'body', default: 'query' for
+	 *    HEAD/GET/DELETE, 'body' for POST/PUT/OPTIONS/PATCH)
+	 *
+	 * @throws Requests_Exception On invalid URLs (`nonhttp`)
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Extra headers to send with the request
+	 * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
+	 * @param string $type HTTP request type (use Requests constants)
+	 * @param array $options Options for the request (see description for more information)
+	 * @return Requests_Response
+	 */
+	public static function request($url, $headers = array(), $data = array(), $type = self::GET, $options = array()) {
+		if (empty($options['type'])) {
+			$options['type'] = $type;
+		}
+		$options = array_merge(self::get_default_options(), $options);
+
+		self::set_defaults($url, $headers, $data, $type, $options);
+
+		$options['hooks']->dispatch('requests.before_request', array(&$url, &$headers, &$data, &$type, &$options));
+
+		if (!empty($options['transport'])) {
+			$transport = $options['transport'];
+
+			if (is_string($options['transport'])) {
+				$transport = new $transport();
+			}
+		}
+		else {
+			$need_ssl = (0 === stripos($url, 'https://'));
+			$capabilities = array('ssl' => $need_ssl);
+			$transport = self::get_transport($capabilities);
+		}
+		$response = $transport->request($url, $headers, $data, $options);
+
+		$options['hooks']->dispatch('requests.before_parse', array(&$response, $url, $headers, $data, $type, $options));
+
+		return self::parse_response($response, $url, $headers, $data, $options);
+	}
+
+	/**
+	 * Send multiple HTTP requests simultaneously
+	 *
+	 * The `$requests` parameter takes an associative or indexed array of
+	 * request fields. The key of each request can be used to match up the
+	 * request with the returned data, or with the request passed into your
+	 * `multiple.request.complete` callback.
+	 *
+	 * The request fields value is an associative array with the following keys:
+	 *
+	 * - `url`: Request URL Same as the `$url` parameter to
+	 *    {@see Requests::request}
+	 *    (string, required)
+	 * - `headers`: Associative array of header fields. Same as the `$headers`
+	 *    parameter to {@see Requests::request}
+	 *    (array, default: `array()`)
+	 * - `data`: Associative array of data fields or a string. Same as the
+	 *    `$data` parameter to {@see Requests::request}
+	 *    (array|string, default: `array()`)
+	 * - `type`: HTTP request type (use Requests constants). Same as the `$type`
+	 *    parameter to {@see Requests::request}
+	 *    (string, default: `Requests::GET`)
+	 * - `cookies`: Associative array of cookie name to value, or cookie jar.
+	 *    (array|Requests_Cookie_Jar)
+	 *
+	 * If the `$options` parameter is specified, individual requests will
+	 * inherit options from it. This can be used to use a single hooking system,
+	 * or set all the types to `Requests::POST`, for example.
+	 *
+	 * In addition, the `$options` parameter takes the following global options:
+	 *
+	 * - `complete`: A callback for when a request is complete. Takes two
+	 *    parameters, a Requests_Response/Requests_Exception reference, and the
+	 *    ID from the request array (Note: this can also be overridden on a
+	 *    per-request basis, although that's a little silly)
+	 *    (callback)
+	 *
+	 * @param array $requests Requests data (see description for more information)
+	 * @param array $options Global and default options (see {@see Requests::request})
+	 * @return array Responses (either Requests_Response or a Requests_Exception object)
+	 */
+	public static function request_multiple($requests, $options = array()) {
+		$options = array_merge(self::get_default_options(true), $options);
+
+		if (!empty($options['hooks'])) {
+			$options['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
+			if (!empty($options['complete'])) {
+				$options['hooks']->register('multiple.request.complete', $options['complete']);
+			}
+		}
+
+		foreach ($requests as $id => &$request) {
+			if (!isset($request['headers'])) {
+				$request['headers'] = array();
+			}
+			if (!isset($request['data'])) {
+				$request['data'] = array();
+			}
+			if (!isset($request['type'])) {
+				$request['type'] = self::GET;
+			}
+			if (!isset($request['options'])) {
+				$request['options'] = $options;
+				$request['options']['type'] = $request['type'];
+			}
+			else {
+				if (empty($request['options']['type'])) {
+					$request['options']['type'] = $request['type'];
+				}
+				$request['options'] = array_merge($options, $request['options']);
+			}
+
+			self::set_defaults($request['url'], $request['headers'], $request['data'], $request['type'], $request['options']);
+
+			// Ensure we only hook in once
+			if ($request['options']['hooks'] !== $options['hooks']) {
+				$request['options']['hooks']->register('transport.internal.parse_response', array('Requests', 'parse_multiple'));
+				if (!empty($request['options']['complete'])) {
+					$request['options']['hooks']->register('multiple.request.complete', $request['options']['complete']);
+				}
+			}
+		}
+		unset($request);
+
+		if (!empty($options['transport'])) {
+			$transport = $options['transport'];
+
+			if (is_string($options['transport'])) {
+				$transport = new $transport();
+			}
+		}
+		else {
+			$transport = self::get_transport();
+		}
+		$responses = $transport->request_multiple($requests, $options);
+
+		foreach ($responses as $id => &$response) {
+			// If our hook got messed with somehow, ensure we end up with the
+			// correct response
+			if (is_string($response)) {
+				$request = $requests[$id];
+				self::parse_multiple($response, $request);
+				$request['options']['hooks']->dispatch('multiple.request.complete', array(&$response, $id));
+			}
+		}
+
+		return $responses;
+	}
+
+	/**
+	 * Get the default options
+	 *
+	 * @see Requests::request() for values returned by this method
+	 * @param boolean $multirequest Is this a multirequest?
+	 * @return array Default option values
+	 */
+	protected static function get_default_options($multirequest = false) {
+		$defaults = array(
+			'timeout' => 10,
+			'connect_timeout' => 10,
+			'useragent' => 'php-requests/' . self::VERSION,
+			'protocol_version' => 1.1,
+			'redirected' => 0,
+			'redirects' => 10,
+			'follow_redirects' => true,
+			'blocking' => true,
+			'type' => self::GET,
+			'filename' => false,
+			'auth' => false,
+			'proxy' => false,
+			'cookies' => false,
+			'max_bytes' => false,
+			'idn' => true,
+			'hooks' => null,
+			'transport' => null,
+			'verify' => Requests::get_certificate_path(),
+			'verifyname' => true,
+		);
+		if ($multirequest !== false) {
+			$defaults['complete'] = null;
+		}
+		return $defaults;
+	}
+
+	/**
+	 * Get default certificate path.
+	 *
+	 * @return string Default certificate path.
+	 */
+	public static function get_certificate_path() {
+		if ( ! empty( Requests::$certificate_path ) ) {
+			return Requests::$certificate_path;
+		}
+
+		return dirname(__FILE__) . '/Requests/Transport/cacert.pem';
+	}
+
+	/**
+	 * Set default certificate path.
+	 *
+	 * @param string $path Certificate path, pointing to a PEM file.
+	 */
+	public static function set_certificate_path( $path ) {
+		Requests::$certificate_path = $path;
+	}
+
+	/**
+	 * Set the default values
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Extra headers to send with the request
+	 * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
+	 * @param string $type HTTP request type
+	 * @param array $options Options for the request
+	 * @return array $options
+	 */
+	protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) {
+		if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) {
+			throw new Requests_Exception('Only HTTP(S) requests are handled.', 'nonhttp', $url);
+		}
+
+		if (empty($options['hooks'])) {
+			$options['hooks'] = new Requests_Hooks();
+		}
+
+		if (is_array($options['auth'])) {
+			$options['auth'] = new Requests_Auth_Basic($options['auth']);
+		}
+		if ($options['auth'] !== false) {
+			$options['auth']->register($options['hooks']);
+		}
+
+		if (is_string($options['proxy']) || is_array($options['proxy'])) {
+			$options['proxy'] = new Requests_Proxy_HTTP($options['proxy']);
+		}
+		if ($options['proxy'] !== false) {
+			$options['proxy']->register($options['hooks']);
+		}
+
+		if (is_array($options['cookies'])) {
+			$options['cookies'] = new Requests_Cookie_Jar($options['cookies']);
+		}
+		elseif (empty($options['cookies'])) {
+			$options['cookies'] = new Requests_Cookie_Jar();
+		}
+		if ($options['cookies'] !== false) {
+			$options['cookies']->register($options['hooks']);
+		}
+
+		if ($options['idn'] !== false) {
+			$iri = new Requests_IRI($url);
+			$iri->host = Requests_IDNAEncoder::encode($iri->ihost);
+			$url = $iri->uri;
+		}
+
+		// Massage the type to ensure we support it.
+		$type = strtoupper($type);
+
+		if (!isset($options['data_format'])) {
+			if (in_array($type, array(self::HEAD, self::GET, self::DELETE))) {
+				$options['data_format'] = 'query';
+			}
+			else {
+				$options['data_format'] = 'body';
+			}
+		}
+	}
+
+	/**
+	 * HTTP response parser
+	 *
+	 * @throws Requests_Exception On missing head/body separator (`requests.no_crlf_separator`)
+	 * @throws Requests_Exception On missing head/body separator (`noversion`)
+	 * @throws Requests_Exception On missing head/body separator (`toomanyredirects`)
+	 *
+	 * @param string $headers Full response text including headers and body
+	 * @param string $url Original request URL
+	 * @param array $req_headers Original $headers array passed to {@link request()}, in case we need to follow redirects
+	 * @param array $req_data Original $data array passed to {@link request()}, in case we need to follow redirects
+	 * @param array $options Original $options array passed to {@link request()}, in case we need to follow redirects
+	 * @return Requests_Response
+	 */
+	protected static function parse_response($headers, $url, $req_headers, $req_data, $options) {
+		$return = new Requests_Response();
+		if (!$options['blocking']) {
+			return $return;
+		}
+
+		$return->raw = $headers;
+		$return->url = $url;
+
+		if (!$options['filename']) {
+			if (($pos = strpos($headers, "\r\n\r\n")) === false) {
+				// Crap!
+				throw new Requests_Exception('Missing header/body separator', 'requests.no_crlf_separator');
+			}
+
+			$headers = substr($return->raw, 0, $pos);
+			$return->body = substr($return->raw, $pos + strlen("\n\r\n\r"));
+		}
+		else {
+			$return->body = '';
+		}
+		// Pretend CRLF = LF for compatibility (RFC 2616, section 19.3)
+		$headers = str_replace("\r\n", "\n", $headers);
+		// Unfold headers (replace [CRLF] 1*( SP | HT ) with SP) as per RFC 2616 (section 2.2)
+		$headers = preg_replace('/\n[ \t]/', ' ', $headers);
+		$headers = explode("\n", $headers);
+		preg_match('#^HTTP/(1\.\d)[ \t]+(\d+)#i', array_shift($headers), $matches);
+		if (empty($matches)) {
+			throw new Requests_Exception('Response could not be parsed', 'noversion', $headers);
+		}
+		$return->protocol_version = (float) $matches[1];
+		$return->status_code = (int) $matches[2];
+		if ($return->status_code >= 200 && $return->status_code < 300) {
+			$return->success = true;
+		}
+
+		foreach ($headers as $header) {
+			list($key, $value) = explode(':', $header, 2);
+			$value = trim($value);
+			preg_replace('#(\s+)#i', ' ', $value);
+			$return->headers[$key] = $value;
+		}
+		if (isset($return->headers['transfer-encoding'])) {
+			$return->body = self::decode_chunked($return->body);
+			unset($return->headers['transfer-encoding']);
+		}
+		if (isset($return->headers['content-encoding'])) {
+			$return->body = self::decompress($return->body);
+		}
+
+		//fsockopen and cURL compatibility
+		if (isset($return->headers['connection'])) {
+			unset($return->headers['connection']);
+		}
+
+		$options['hooks']->dispatch('requests.before_redirect_check', array(&$return, $req_headers, $req_data, $options));
+
+		if ($return->is_redirect() && $options['follow_redirects'] === true) {
+			if (isset($return->headers['location']) && $options['redirected'] < $options['redirects']) {
+				if ($return->status_code === 303) {
+					$options['type'] = self::GET;
+				}
+				$options['redirected']++;
+				$location = $return->headers['location'];
+				if (strpos($location, 'http://') !== 0 && strpos($location, 'https://') !== 0) {
+					// relative redirect, for compatibility make it absolute
+					$location = Requests_IRI::absolutize($url, $location);
+					$location = $location->uri;
+				}
+
+				$hook_args = array(
+					&$location,
+					&$req_headers,
+					&$req_data,
+					&$options,
+					$return
+				);
+				$options['hooks']->dispatch('requests.before_redirect', $hook_args);
+				$redirected = self::request($location, $req_headers, $req_data, $options['type'], $options);
+				$redirected->history[] = $return;
+				return $redirected;
+			}
+			elseif ($options['redirected'] >= $options['redirects']) {
+				throw new Requests_Exception('Too many redirects', 'toomanyredirects', $return);
+			}
+		}
+
+		$return->redirects = $options['redirected'];
+
+		$options['hooks']->dispatch('requests.after_request', array(&$return, $req_headers, $req_data, $options));
+		return $return;
+	}
+
+	/**
+	 * Callback for `transport.internal.parse_response`
+	 *
+	 * Internal use only. Converts a raw HTTP response to a Requests_Response
+	 * while still executing a multiple request.
+	 *
+	 * @param string $response Full response text including headers and body (will be overwritten with Response instance)
+	 * @param array $request Request data as passed into {@see Requests::request_multiple()}
+	 * @return null `$response` is either set to a Requests_Response instance, or a Requests_Exception object
+	 */
+	public static function parse_multiple(&$response, $request) {
+		try {
+			$url = $request['url'];
+			$headers = $request['headers'];
+			$data = $request['data'];
+			$options = $request['options'];
+			$response = self::parse_response($response, $url, $headers, $data, $options);
+		}
+		catch (Requests_Exception $e) {
+			$response = $e;
+		}
+	}
+
+	/**
+	 * Decoded a chunked body as per RFC 2616
+	 *
+	 * @see https://tools.ietf.org/html/rfc2616#section-3.6.1
+	 * @param string $data Chunked body
+	 * @return string Decoded body
+	 */
+	protected static function decode_chunked($data) {
+		if (!preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', trim($data))) {
+			return $data;
+		}
+
+
+
+		$decoded = '';
+		$encoded = $data;
+
+		while (true) {
+			$is_chunked = (bool) preg_match('/^([0-9a-f]+)(?:;(?:[\w-]*)(?:=(?:(?:[\w-]*)*|"(?:[^\r\n])*"))?)*\r\n/i', $encoded, $matches);
+			if (!$is_chunked) {
+				// Looks like it's not chunked after all
+				return $data;
+			}
+
+			$length = hexdec(trim($matches[1]));
+			if ($length === 0) {
+				// Ignore trailer headers
+				return $decoded;
+			}
+
+			$chunk_length = strlen($matches[0]);
+			$decoded .= substr($encoded, $chunk_length, $length);
+			$encoded = substr($encoded, $chunk_length + $length + 2);
+
+			if (trim($encoded) === '0' || empty($encoded)) {
+				return $decoded;
+			}
+		}
+
+		// We'll never actually get down here
+		// @codeCoverageIgnoreStart
+	}
+	// @codeCoverageIgnoreEnd
+
+	/**
+	 * Convert a key => value array to a 'key: value' array for headers
+	 *
+	 * @param array $array Dictionary of header values
+	 * @return array List of headers
+	 */
+	public static function flatten($array) {
+		$return = array();
+		foreach ($array as $key => $value) {
+			$return[] = sprintf('%s: %s', $key, $value);
+		}
+		return $return;
+	}
+
+	/**
+	 * Convert a key => value array to a 'key: value' array for headers
+	 *
+	 * @codeCoverageIgnore
+	 * @deprecated Misspelling of {@see Requests::flatten}
+	 * @param array $array Dictionary of header values
+	 * @return array List of headers
+	 */
+	public static function flattern($array) {
+		return self::flatten($array);
+	}
+
+	/**
+	 * Decompress an encoded body
+	 *
+	 * Implements gzip, compress and deflate. Guesses which it is by attempting
+	 * to decode.
+	 *
+	 * @param string $data Compressed data in one of the above formats
+	 * @return string Decompressed string
+	 */
+	public static function decompress($data) {
+		if (substr($data, 0, 2) !== "\x1f\x8b" && substr($data, 0, 2) !== "\x78\x9c") {
+			// Not actually compressed. Probably cURL ruining this for us.
+			return $data;
+		}
+
+		if (function_exists('gzdecode') && ($decoded = @gzdecode($data)) !== false) {
+			return $decoded;
+		}
+		elseif (function_exists('gzinflate') && ($decoded = @gzinflate($data)) !== false) {
+			return $decoded;
+		}
+		elseif (($decoded = self::compatible_gzinflate($data)) !== false) {
+			return $decoded;
+		}
+		elseif (function_exists('gzuncompress') && ($decoded = @gzuncompress($data)) !== false) {
+			return $decoded;
+		}
+
+		return $data;
+	}
+
+	/**
+	 * Decompression of deflated string while staying compatible with the majority of servers.
+	 *
+	 * Certain Servers will return deflated data with headers which PHP's gzinflate()
+	 * function cannot handle out of the box. The following function has been created from
+	 * various snippets on the gzinflate() PHP documentation.
+	 *
+	 * Warning: Magic numbers within. Due to the potential different formats that the compressed
+	 * data may be returned in, some "magic offsets" are needed to ensure proper decompression
+	 * takes place. For a simple progmatic way to determine the magic offset in use, see:
+	 * https://core.trac.wordpress.org/ticket/18273
+	 *
+	 * @since 2.8.1
+	 * @link https://core.trac.wordpress.org/ticket/18273
+	 * @link https://secure.php.net/manual/en/function.gzinflate.php#70875
+	 * @link https://secure.php.net/manual/en/function.gzinflate.php#77336
+	 *
+	 * @param string $gzData String to decompress.
+	 * @return string|bool False on failure.
+	 */
+	public static function compatible_gzinflate($gzData) {
+		// Compressed data might contain a full zlib header, if so strip it for
+		// gzinflate()
+		if (substr($gzData, 0, 3) == "\x1f\x8b\x08") {
+			$i = 10;
+			$flg = ord(substr($gzData, 3, 1));
+			if ($flg > 0) {
+				if ($flg & 4) {
+					list($xlen) = unpack('v', substr($gzData, $i, 2));
+					$i = $i + 2 + $xlen;
+				}
+				if ($flg & 8) {
+					$i = strpos($gzData, "\0", $i) + 1;
+				}
+				if ($flg & 16) {
+					$i = strpos($gzData, "\0", $i) + 1;
+				}
+				if ($flg & 2) {
+					$i = $i + 2;
+				}
+			}
+			$decompressed = self::compatible_gzinflate(substr($gzData, $i));
+			if (false !== $decompressed) {
+				return $decompressed;
+			}
+		}
+
+		// If the data is Huffman Encoded, we must first strip the leading 2
+		// byte Huffman marker for gzinflate()
+		// The response is Huffman coded by many compressors such as
+		// java.util.zip.Deflater, Ruby’s Zlib::Deflate, and .NET's
+		// System.IO.Compression.DeflateStream.
+		//
+		// See https://decompres.blogspot.com/ for a quick explanation of this
+		// data type
+		$huffman_encoded = false;
+
+		// low nibble of first byte should be 0x08
+		list(, $first_nibble)    = unpack('h', $gzData);
+
+		// First 2 bytes should be divisible by 0x1F
+		list(, $first_two_bytes) = unpack('n', $gzData);
+
+		if (0x08 == $first_nibble && 0 == ($first_two_bytes % 0x1F)) {
+			$huffman_encoded = true;
+		}
+
+		if ($huffman_encoded) {
+			if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) {
+				return $decompressed;
+			}
+		}
+
+		if ("\x50\x4b\x03\x04" == substr($gzData, 0, 4)) {
+			// ZIP file format header
+			// Offset 6: 2 bytes, General-purpose field
+			// Offset 26: 2 bytes, filename length
+			// Offset 28: 2 bytes, optional field length
+			// Offset 30: Filename field, followed by optional field, followed
+			// immediately by data
+			list(, $general_purpose_flag) = unpack('v', substr($gzData, 6, 2));
+
+			// If the file has been compressed on the fly, 0x08 bit is set of
+			// the general purpose field. We can use this to differentiate
+			// between a compressed document, and a ZIP file
+			$zip_compressed_on_the_fly = (0x08 == (0x08 & $general_purpose_flag));
+
+			if (!$zip_compressed_on_the_fly) {
+				// Don't attempt to decode a compressed zip file
+				return $gzData;
+			}
+
+			// Determine the first byte of data, based on the above ZIP header
+			// offsets:
+			$first_file_start = array_sum(unpack('v2', substr($gzData, 26, 4)));
+			if (false !== ($decompressed = @gzinflate(substr($gzData, 30 + $first_file_start)))) {
+				return $decompressed;
+			}
+			return false;
+		}
+
+		// Finally fall back to straight gzinflate
+		if (false !== ($decompressed = @gzinflate($gzData))) {
+			return $decompressed;
+		}
+
+		// Fallback for all above failing, not expected, but included for
+		// debugging and preventing regressions and to track stats
+		if (false !== ($decompressed = @gzinflate(substr($gzData, 2)))) {
+			return $decompressed;
+		}
+
+		return false;
+	}
+
+	public static function match_domain($host, $reference) {
+		// Check for a direct match
+		if ($host === $reference) {
+			return true;
+		}
+
+		// Calculate the valid wildcard match if the host is not an IP address
+		// Also validates that the host has 3 parts or more, as per Firefox's
+		// ruleset.
+		$parts = explode('.', $host);
+		if (ip2long($host) === false && count($parts) >= 3) {
+			$parts[0] = '*';
+			$wildcard = implode('.', $parts);
+			if ($wildcard === $reference) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+}

+ 33 - 0
api/vendor/rmccue/requests/library/Requests/Auth.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * Authentication provider interface
+ *
+ * @package Requests
+ * @subpackage Authentication
+ */
+
+/**
+ * Authentication provider interface
+ *
+ * Implement this interface to act as an authentication provider.
+ *
+ * Parameters should be passed via the constructor where possible, as this
+ * makes it much easier for users to use your provider.
+ *
+ * @see Requests_Hooks
+ * @package Requests
+ * @subpackage Authentication
+ */
+interface Requests_Auth {
+	/**
+	 * Register hooks as needed
+	 *
+	 * This method is called in {@see Requests::request} when the user has set
+	 * an instance as the 'auth' option. Use this callback to register all the
+	 * hooks you'll need.
+	 *
+	 * @see Requests_Hooks::register
+	 * @param Requests_Hooks $hooks Hook system
+	 */
+	public function register(Requests_Hooks &$hooks);
+}

+ 88 - 0
api/vendor/rmccue/requests/library/Requests/Auth/Basic.php

@@ -0,0 +1,88 @@
+<?php
+/**
+ * Basic Authentication provider
+ *
+ * @package Requests
+ * @subpackage Authentication
+ */
+
+/**
+ * Basic Authentication provider
+ *
+ * Provides a handler for Basic HTTP authentication via the Authorization
+ * header.
+ *
+ * @package Requests
+ * @subpackage Authentication
+ */
+class Requests_Auth_Basic implements Requests_Auth {
+	/**
+	 * Username
+	 *
+	 * @var string
+	 */
+	public $user;
+
+	/**
+	 * Password
+	 *
+	 * @var string
+	 */
+	public $pass;
+
+	/**
+	 * Constructor
+	 *
+	 * @throws Requests_Exception On incorrect number of arguments (`authbasicbadargs`)
+	 * @param array|null $args Array of user and password. Must have exactly two elements
+	 */
+	public function __construct($args = null) {
+		if (is_array($args)) {
+			if (count($args) !== 2) {
+				throw new Requests_Exception('Invalid number of arguments', 'authbasicbadargs');
+			}
+
+			list($this->user, $this->pass) = $args;
+		}
+	}
+
+	/**
+	 * Register the necessary callbacks
+	 *
+	 * @see curl_before_send
+	 * @see fsockopen_header
+	 * @param Requests_Hooks $hooks Hook system
+	 */
+	public function register(Requests_Hooks &$hooks) {
+		$hooks->register('curl.before_send', array(&$this, 'curl_before_send'));
+		$hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header'));
+	}
+
+	/**
+	 * Set cURL parameters before the data is sent
+	 *
+	 * @param resource $handle cURL resource
+	 */
+	public function curl_before_send(&$handle) {
+		curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+		curl_setopt($handle, CURLOPT_USERPWD, $this->getAuthString());
+	}
+
+	/**
+	 * Add extra headers to the request before sending
+	 *
+	 * @param string $out HTTP header string
+	 */
+	public function fsockopen_header(&$out) {
+		$out .= sprintf("Authorization: Basic %s\r\n", base64_encode($this->getAuthString()));
+	}
+
+	/**
+	 * Get the authentication string (user:pass)
+	 *
+	 * @return string
+	 */
+	public function getAuthString() {
+		return $this->user . ':' . $this->pass;
+	}
+}

+ 500 - 0
api/vendor/rmccue/requests/library/Requests/Cookie.php

@@ -0,0 +1,500 @@
+<?php
+/**
+ * Cookie storage object
+ *
+ * @package Requests
+ * @subpackage Cookies
+ */
+
+/**
+ * Cookie storage object
+ *
+ * @package Requests
+ * @subpackage Cookies
+ */
+class Requests_Cookie {
+	/**
+	 * Cookie name.
+	 *
+	 * @var string
+	 */
+	public $name;
+
+	/**
+	 * Cookie value.
+	 *
+	 * @var string
+	 */
+	public $value;
+
+	/**
+	 * Cookie attributes
+	 *
+	 * Valid keys are (currently) path, domain, expires, max-age, secure and
+	 * httponly.
+	 *
+	 * @var Requests_Utility_CaseInsensitiveDictionary|array Array-like object
+	 */
+	public $attributes = array();
+
+	/**
+	 * Cookie flags
+	 *
+	 * Valid keys are (currently) creation, last-access, persistent and
+	 * host-only.
+	 *
+	 * @var array
+	 */
+	public $flags = array();
+
+	/**
+	 * Reference time for relative calculations
+	 *
+	 * This is used in place of `time()` when calculating Max-Age expiration and
+	 * checking time validity.
+	 *
+	 * @var int
+	 */
+	public $reference_time = 0;
+
+	/**
+	 * Create a new cookie object
+	 *
+	 * @param string $name
+	 * @param string $value
+	 * @param array|Requests_Utility_CaseInsensitiveDictionary $attributes Associative array of attribute data
+	 */
+	public function __construct($name, $value, $attributes = array(), $flags = array(), $reference_time = null) {
+		$this->name = $name;
+		$this->value = $value;
+		$this->attributes = $attributes;
+		$default_flags = array(
+			'creation' => time(),
+			'last-access' => time(),
+			'persistent' => false,
+			'host-only' => true,
+		);
+		$this->flags = array_merge($default_flags, $flags);
+
+		$this->reference_time = time();
+		if ($reference_time !== null) {
+			$this->reference_time = $reference_time;
+		}
+
+		$this->normalize();
+	}
+
+	/**
+	 * Check if a cookie is expired.
+	 *
+	 * Checks the age against $this->reference_time to determine if the cookie
+	 * is expired.
+	 *
+	 * @return boolean True if expired, false if time is valid.
+	 */
+	public function is_expired() {
+		// RFC6265, s. 4.1.2.2:
+		// If a cookie has both the Max-Age and the Expires attribute, the Max-
+		// Age attribute has precedence and controls the expiration date of the
+		// cookie.
+		if (isset($this->attributes['max-age'])) {
+			$max_age = $this->attributes['max-age'];
+			return $max_age < $this->reference_time;
+		}
+
+		if (isset($this->attributes['expires'])) {
+			$expires = $this->attributes['expires'];
+			return $expires < $this->reference_time;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Check if a cookie is valid for a given URI
+	 *
+	 * @param Requests_IRI $uri URI to check
+	 * @return boolean Whether the cookie is valid for the given URI
+	 */
+	public function uri_matches(Requests_IRI $uri) {
+		if (!$this->domain_matches($uri->host)) {
+			return false;
+		}
+
+		if (!$this->path_matches($uri->path)) {
+			return false;
+		}
+
+		return empty($this->attributes['secure']) || $uri->scheme === 'https';
+	}
+
+	/**
+	 * Check if a cookie is valid for a given domain
+	 *
+	 * @param string $string Domain to check
+	 * @return boolean Whether the cookie is valid for the given domain
+	 */
+	public function domain_matches($string) {
+		if (!isset($this->attributes['domain'])) {
+			// Cookies created manually; cookies created by Requests will set
+			// the domain to the requested domain
+			return true;
+		}
+
+		$domain_string = $this->attributes['domain'];
+		if ($domain_string === $string) {
+			// The domain string and the string are identical.
+			return true;
+		}
+
+		// If the cookie is marked as host-only and we don't have an exact
+		// match, reject the cookie
+		if ($this->flags['host-only'] === true) {
+			return false;
+		}
+
+		if (strlen($string) <= strlen($domain_string)) {
+			// For obvious reasons, the string cannot be a suffix if the domain
+			// is shorter than the domain string
+			return false;
+		}
+
+		if (substr($string, -1 * strlen($domain_string)) !== $domain_string) {
+			// The domain string should be a suffix of the string.
+			return false;
+		}
+
+		$prefix = substr($string, 0, strlen($string) - strlen($domain_string));
+		if (substr($prefix, -1) !== '.') {
+			// The last character of the string that is not included in the
+			// domain string should be a %x2E (".") character.
+			return false;
+		}
+
+		// The string should be a host name (i.e., not an IP address).
+		return !preg_match('#^(.+\.)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $string);
+	}
+
+	/**
+	 * Check if a cookie is valid for a given path
+	 *
+	 * From the path-match check in RFC 6265 section 5.1.4
+	 *
+	 * @param string $request_path Path to check
+	 * @return boolean Whether the cookie is valid for the given path
+	 */
+	public function path_matches($request_path) {
+		if (empty($request_path)) {
+			// Normalize empty path to root
+			$request_path = '/';
+		}
+
+		if (!isset($this->attributes['path'])) {
+			// Cookies created manually; cookies created by Requests will set
+			// the path to the requested path
+			return true;
+		}
+
+		$cookie_path = $this->attributes['path'];
+
+		if ($cookie_path === $request_path) {
+			// The cookie-path and the request-path are identical.
+			return true;
+		}
+
+		if (strlen($request_path) > strlen($cookie_path) && substr($request_path, 0, strlen($cookie_path)) === $cookie_path) {
+			if (substr($cookie_path, -1) === '/') {
+				// The cookie-path is a prefix of the request-path, and the last
+				// character of the cookie-path is %x2F ("/").
+				return true;
+			}
+
+			if (substr($request_path, strlen($cookie_path), 1) === '/') {
+				// 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.
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Normalize cookie and attributes
+	 *
+	 * @return boolean Whether the cookie was successfully normalized
+	 */
+	public function normalize() {
+		foreach ($this->attributes as $key => $value) {
+			$orig_value = $value;
+			$value = $this->normalize_attribute($key, $value);
+			if ($value === null) {
+				unset($this->attributes[$key]);
+				continue;
+			}
+
+			if ($value !== $orig_value) {
+				$this->attributes[$key] = $value;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Parse an individual cookie attribute
+	 *
+	 * Handles parsing individual attributes from the cookie values.
+	 *
+	 * @param string $name Attribute name
+	 * @param string|boolean $value Attribute value (string value, or true if empty/flag)
+	 * @return mixed Value if available, or null if the attribute value is invalid (and should be skipped)
+	 */
+	protected function normalize_attribute($name, $value) {
+		switch (strtolower($name)) {
+			case 'expires':
+				// Expiration parsing, as per RFC 6265 section 5.2.1
+				if (is_int($value)) {
+					return $value;
+				}
+
+				$expiry_time = strtotime($value);
+				if ($expiry_time === false) {
+					return null;
+				}
+
+				return $expiry_time;
+
+			case 'max-age':
+				// Expiration parsing, as per RFC 6265 section 5.2.2
+				if (is_int($value)) {
+					return $value;
+				}
+
+				// Check that we have a valid age
+				if (!preg_match('/^-?\d+$/', $value)) {
+					return null;
+				}
+
+				$delta_seconds = (int) $value;
+				if ($delta_seconds <= 0) {
+					$expiry_time = 0;
+				}
+				else {
+					$expiry_time = $this->reference_time + $delta_seconds;
+				}
+
+				return $expiry_time;
+
+			case 'domain':
+				// Domain normalization, as per RFC 6265 section 5.2.3
+				if ($value[0] === '.') {
+					$value = substr($value, 1);
+				}
+
+				return $value;
+
+			default:
+				return $value;
+		}
+	}
+
+	/**
+	 * Format a cookie for a Cookie header
+	 *
+	 * This is used when sending cookies to a server.
+	 *
+	 * @return string Cookie formatted for Cookie header
+	 */
+	public function format_for_header() {
+		return sprintf('%s=%s', $this->name, $this->value);
+	}
+
+	/**
+	 * Format a cookie for a Cookie header
+	 *
+	 * @codeCoverageIgnore
+	 * @deprecated Use {@see Requests_Cookie::format_for_header}
+	 * @return string
+	 */
+	public function formatForHeader() {
+		return $this->format_for_header();
+	}
+
+	/**
+	 * Format a cookie for a Set-Cookie header
+	 *
+	 * This is used when sending cookies to clients. This isn't really
+	 * applicable to client-side usage, but might be handy for debugging.
+	 *
+	 * @return string Cookie formatted for Set-Cookie header
+	 */
+	public function format_for_set_cookie() {
+		$header_value = $this->format_for_header();
+		if (!empty($this->attributes)) {
+			$parts = array();
+			foreach ($this->attributes as $key => $value) {
+				// Ignore non-associative attributes
+				if (is_numeric($key)) {
+					$parts[] = $value;
+				}
+				else {
+					$parts[] = sprintf('%s=%s', $key, $value);
+				}
+			}
+
+			$header_value .= '; ' . implode('; ', $parts);
+		}
+		return $header_value;
+	}
+
+	/**
+	 * Format a cookie for a Set-Cookie header
+	 *
+	 * @codeCoverageIgnore
+	 * @deprecated Use {@see Requests_Cookie::format_for_set_cookie}
+	 * @return string
+	 */
+	public function formatForSetCookie() {
+		return $this->format_for_set_cookie();
+	}
+
+	/**
+	 * Get the cookie value
+	 *
+	 * Attributes and other data can be accessed via methods.
+	 */
+	public function __toString() {
+		return $this->value;
+	}
+
+	/**
+	 * Parse a cookie string into a cookie object
+	 *
+	 * Based on Mozilla's parsing code in Firefox and related projects, which
+	 * is an intentional deviation from RFC 2109 and RFC 2616. RFC 6265
+	 * specifies some of this handling, but not in a thorough manner.
+	 *
+	 * @param string Cookie header value (from a Set-Cookie header)
+	 * @return Requests_Cookie Parsed cookie object
+	 */
+	public static function parse($string, $name = '', $reference_time = null) {
+		$parts = explode(';', $string);
+		$kvparts = array_shift($parts);
+
+		if (!empty($name)) {
+			$value = $string;
+		}
+		elseif (strpos($kvparts, '=') === false) {
+			// Some sites might only have a value without the equals separator.
+			// Deviate from RFC 6265 and pretend it was actually a blank name
+			// (`=foo`)
+			//
+			// https://bugzilla.mozilla.org/show_bug.cgi?id=169091
+			$name = '';
+			$value = $kvparts;
+		}
+		else {
+			list($name, $value) = explode('=', $kvparts, 2);
+		}
+		$name = trim($name);
+		$value = trim($value);
+
+		// Attribute key are handled case-insensitively
+		$attributes = new Requests_Utility_CaseInsensitiveDictionary();
+
+		if (!empty($parts)) {
+			foreach ($parts as $part) {
+				if (strpos($part, '=') === false) {
+					$part_key = $part;
+					$part_value = true;
+				}
+				else {
+					list($part_key, $part_value) = explode('=', $part, 2);
+					$part_value = trim($part_value);
+				}
+
+				$part_key = trim($part_key);
+				$attributes[$part_key] = $part_value;
+			}
+		}
+
+		return new Requests_Cookie($name, $value, $attributes, array(), $reference_time);
+	}
+
+	/**
+	 * Parse all Set-Cookie headers from request headers
+	 *
+	 * @param Requests_Response_Headers $headers Headers to parse from
+	 * @param Requests_IRI|null $origin URI for comparing cookie origins
+	 * @param int|null $time Reference time for expiration calculation
+	 * @return array
+	 */
+	public static function parse_from_headers(Requests_Response_Headers $headers, Requests_IRI $origin = null, $time = null) {
+		$cookie_headers = $headers->getValues('Set-Cookie');
+		if (empty($cookie_headers)) {
+			return array();
+		}
+
+		$cookies = array();
+		foreach ($cookie_headers as $header) {
+			$parsed = self::parse($header, '', $time);
+
+			// Default domain/path attributes
+			if (empty($parsed->attributes['domain']) && !empty($origin)) {
+				$parsed->attributes['domain'] = $origin->host;
+				$parsed->flags['host-only'] = true;
+			}
+			else {
+				$parsed->flags['host-only'] = false;
+			}
+
+			$path_is_valid = (!empty($parsed->attributes['path']) && $parsed->attributes['path'][0] === '/');
+			if (!$path_is_valid && !empty($origin)) {
+				$path = $origin->path;
+
+				// Default path normalization as per RFC 6265 section 5.1.4
+				if (substr($path, 0, 1) !== '/') {
+					// If the uri-path is empty or if the first character of
+					// the uri-path is not a %x2F ("/") character, output
+					// %x2F ("/") and skip the remaining steps.
+					$path = '/';
+				}
+				elseif (substr_count($path, '/') === 1) {
+					// If the uri-path contains no more than one %x2F ("/")
+					// character, output %x2F ("/") and skip the remaining
+					// step.
+					$path = '/';
+				}
+				else {
+					// Output the characters of the uri-path from the first
+					// character up to, but not including, the right-most
+					// %x2F ("/").
+					$path = substr($path, 0, strrpos($path, '/'));
+				}
+				$parsed->attributes['path'] = $path;
+			}
+
+			// Reject invalid cookie domains
+			if (!empty($origin) && !$parsed->domain_matches($origin->host)) {
+				continue;
+			}
+
+			$cookies[$parsed->name] = $parsed;
+		}
+
+		return $cookies;
+	}
+
+	/**
+	 * Parse all Set-Cookie headers from request headers
+	 *
+	 * @codeCoverageIgnore
+	 * @deprecated Use {@see Requests_Cookie::parse_from_headers}
+	 * @return string
+	 */
+	public static function parseFromHeaders(Requests_Response_Headers $headers) {
+		return self::parse_from_headers($headers);
+	}
+}

+ 175 - 0
api/vendor/rmccue/requests/library/Requests/Cookie/Jar.php

@@ -0,0 +1,175 @@
+<?php
+/**
+ * Cookie holder object
+ *
+ * @package Requests
+ * @subpackage Cookies
+ */
+
+/**
+ * Cookie holder object
+ *
+ * @package Requests
+ * @subpackage Cookies
+ */
+class Requests_Cookie_Jar implements ArrayAccess, IteratorAggregate {
+	/**
+	 * Actual item data
+	 *
+	 * @var array
+	 */
+	protected $cookies = array();
+
+	/**
+	 * Create a new jar
+	 *
+	 * @param array $cookies Existing cookie values
+	 */
+	public function __construct($cookies = array()) {
+		$this->cookies = $cookies;
+	}
+
+	/**
+	 * Normalise cookie data into a Requests_Cookie
+	 *
+	 * @param string|Requests_Cookie $cookie
+	 * @return Requests_Cookie
+	 */
+	public function normalize_cookie($cookie, $key = null) {
+		if ($cookie instanceof Requests_Cookie) {
+			return $cookie;
+		}
+
+		return Requests_Cookie::parse($cookie, $key);
+	}
+
+	/**
+	 * Normalise cookie data into a Requests_Cookie
+	 *
+	 * @codeCoverageIgnore
+	 * @deprecated Use {@see Requests_Cookie_Jar::normalize_cookie}
+	 * @return Requests_Cookie
+	 */
+	public function normalizeCookie($cookie, $key = null) {
+		return $this->normalize_cookie($cookie, $key);
+	}
+
+	/**
+	 * Check if the given item exists
+	 *
+	 * @param string $key Item key
+	 * @return boolean Does the item exist?
+	 */
+	public function offsetExists($key) {
+		return isset($this->cookies[$key]);
+	}
+
+	/**
+	 * Get the value for the item
+	 *
+	 * @param string $key Item key
+	 * @return string Item value
+	 */
+	public function offsetGet($key) {
+		if (!isset($this->cookies[$key])) {
+			return null;
+		}
+
+		return $this->cookies[$key];
+	}
+
+	/**
+	 * Set the given item
+	 *
+	 * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
+	 *
+	 * @param string $key Item name
+	 * @param string $value Item value
+	 */
+	public function offsetSet($key, $value) {
+		if ($key === null) {
+			throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
+		}
+
+		$this->cookies[$key] = $value;
+	}
+
+	/**
+	 * Unset the given header
+	 *
+	 * @param string $key
+	 */
+	public function offsetUnset($key) {
+		unset($this->cookies[$key]);
+	}
+
+	/**
+	 * Get an iterator for the data
+	 *
+	 * @return ArrayIterator
+	 */
+	public function getIterator() {
+		return new ArrayIterator($this->cookies);
+	}
+
+	/**
+	 * Register the cookie handler with the request's hooking system
+	 *
+	 * @param Requests_Hooker $hooks Hooking system
+	 */
+	public function register(Requests_Hooker $hooks) {
+		$hooks->register('requests.before_request', array($this, 'before_request'));
+		$hooks->register('requests.before_redirect_check', array($this, 'before_redirect_check'));
+	}
+
+	/**
+	 * Add Cookie header to a request if we have any
+	 *
+	 * As per RFC 6265, cookies are separated by '; '
+	 *
+	 * @param string $url
+	 * @param array $headers
+	 * @param array $data
+	 * @param string $type
+	 * @param array $options
+	 */
+	public function before_request($url, &$headers, &$data, &$type, &$options) {
+		if (!$url instanceof Requests_IRI) {
+			$url = new Requests_IRI($url);
+		}
+
+		if (!empty($this->cookies)) {
+			$cookies = array();
+			foreach ($this->cookies as $key => $cookie) {
+				$cookie = $this->normalize_cookie($cookie, $key);
+
+				// Skip expired cookies
+				if ($cookie->is_expired()) {
+					continue;
+				}
+
+				if ($cookie->domain_matches($url->host)) {
+					$cookies[] = $cookie->format_for_header();
+				}
+			}
+
+			$headers['Cookie'] = implode('; ', $cookies);
+		}
+	}
+
+	/**
+	 * Parse all cookies from a response and attach them to the response
+	 *
+	 * @var Requests_Response $response
+	 */
+	public function before_redirect_check(Requests_Response &$return) {
+		$url = $return->url;
+		if (!$url instanceof Requests_IRI) {
+			$url = new Requests_IRI($url);
+		}
+
+		$cookies = Requests_Cookie::parse_from_headers($return->headers, $url);
+		$this->cookies = array_merge($this->cookies, $cookies);
+		$return->cookies = $this;
+	}
+}

+ 62 - 0
api/vendor/rmccue/requests/library/Requests/Exception.php

@@ -0,0 +1,62 @@
+<?php
+/**
+ * Exception for HTTP requests
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for HTTP requests
+ *
+ * @package Requests
+ */
+class Requests_Exception extends Exception {
+	/**
+	 * Type of exception
+	 *
+	 * @var string
+	 */
+	protected $type;
+
+	/**
+	 * Data associated with the exception
+	 *
+	 * @var mixed
+	 */
+	protected $data;
+
+	/**
+	 * Create a new exception
+	 *
+	 * @param string $message Exception message
+	 * @param string $type Exception type
+	 * @param mixed $data Associated data
+	 * @param integer $code Exception numerical code, if applicable
+	 */
+	public function __construct($message, $type, $data = null, $code = 0) {
+		parent::__construct($message, $code);
+
+		$this->type = $type;
+		$this->data = $data;
+	}
+
+	/**
+	 * Like {@see getCode()}, but a string code.
+	 *
+	 * @codeCoverageIgnore
+	 * @return string
+	 */
+	public function getType() {
+		return $this->type;
+	}
+
+	/**
+	 * Gives any relevant data
+	 *
+	 * @codeCoverageIgnore
+	 * @return mixed
+	 */
+	public function getData() {
+		return $this->data;
+	}
+}

+ 71 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP.php

@@ -0,0 +1,71 @@
+<?php
+/**
+ * Exception based on HTTP response
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception based on HTTP response
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP extends Requests_Exception {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 0;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Unknown';
+
+	/**
+	 * Create a new exception
+	 *
+	 * There is no mechanism to pass in the status code, as this is set by the
+	 * subclass used. Reason phrases can vary, however.
+	 *
+	 * @param string|null $reason Reason phrase
+	 * @param mixed $data Associated data
+	 */
+	public function __construct($reason = null, $data = null) {
+		if ($reason !== null) {
+			$this->reason = $reason;
+		}
+
+		$message = sprintf('%d %s', $this->code, $this->reason);
+		parent::__construct($message, 'httpresponse', $data, $this->code);
+	}
+
+	/**
+	 * Get the status message
+	 */
+	public function getReason() {
+		return $this->reason;
+	}
+
+	/**
+	 * Get the correct exception class for a given error code
+	 *
+	 * @param int|bool $code HTTP status code, or false if unavailable
+	 * @return string Exception class name to use
+	 */
+	public static function get_class($code) {
+		if (!$code) {
+			return 'Requests_Exception_HTTP_Unknown';
+		}
+
+		$class = sprintf('Requests_Exception_HTTP_%d', $code);
+		if (class_exists($class)) {
+			return $class;
+		}
+
+		return 'Requests_Exception_HTTP_Unknown';
+	}
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/304.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 304 Not Modified responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 304 Not Modified responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_304 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 304;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Not Modified';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/305.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 305 Use Proxy responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 305 Use Proxy responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_305 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 305;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Use Proxy';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/306.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 306 Switch Proxy responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 306 Switch Proxy responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_306 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 306;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Switch Proxy';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/400.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 400 Bad Request responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 400 Bad Request responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_400 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 400;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Bad Request';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/401.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 401 Unauthorized responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 401 Unauthorized responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_401 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 401;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Unauthorized';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/402.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 402 Payment Required responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 402 Payment Required responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_402 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 402;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Payment Required';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/403.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 403 Forbidden responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 403 Forbidden responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_403 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 403;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Forbidden';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/404.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 404 Not Found responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 404 Not Found responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_404 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 404;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Not Found';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/405.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 405 Method Not Allowed responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 405 Method Not Allowed responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_405 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 405;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Method Not Allowed';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/406.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 406 Not Acceptable responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 406 Not Acceptable responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_406 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 406;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Not Acceptable';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/407.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 407 Proxy Authentication Required responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 407 Proxy Authentication Required responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_407 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 407;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Proxy Authentication Required';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/408.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 408 Request Timeout responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 408 Request Timeout responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_408 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 408;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Request Timeout';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/409.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 409 Conflict responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 409 Conflict responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_409 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 409;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Conflict';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/410.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 410 Gone responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 410 Gone responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_410 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 410;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Gone';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/411.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 411 Length Required responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 411 Length Required responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_411 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 411;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Length Required';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/412.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 412 Precondition Failed responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 412 Precondition Failed responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_412 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 412;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Precondition Failed';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/413.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 413 Request Entity Too Large responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 413 Request Entity Too Large responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_413 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 413;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Request Entity Too Large';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/414.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 414 Request-URI Too Large responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 414 Request-URI Too Large responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_414 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 414;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Request-URI Too Large';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/415.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 415 Unsupported Media Type responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 415 Unsupported Media Type responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_415 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 415;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Unsupported Media Type';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/416.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 416 Requested Range Not Satisfiable responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 416 Requested Range Not Satisfiable responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_416 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 416;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Requested Range Not Satisfiable';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/417.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 417 Expectation Failed responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 417 Expectation Failed responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_417 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 417;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Expectation Failed';
+}

+ 29 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/418.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Exception for 418 I'm A Teapot responses
+ *
+ * @see https://tools.ietf.org/html/rfc2324
+ * @package Requests
+ */
+
+/**
+ * Exception for 418 I'm A Teapot responses
+ *
+ * @see https://tools.ietf.org/html/rfc2324
+ * @package Requests
+ */
+class Requests_Exception_HTTP_418 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 418;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = "I'm A Teapot";
+}

+ 29 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/428.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Exception for 428 Precondition Required responses
+ *
+ * @see https://tools.ietf.org/html/rfc6585
+ * @package Requests
+ */
+
+/**
+ * Exception for 428 Precondition Required responses
+ *
+ * @see https://tools.ietf.org/html/rfc6585
+ * @package Requests
+ */
+class Requests_Exception_HTTP_428 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 428;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Precondition Required';
+}

+ 29 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/429.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Exception for 429 Too Many Requests responses
+ *
+ * @see https://tools.ietf.org/html/draft-nottingham-http-new-status-04
+ * @package Requests
+ */
+
+/**
+ * Exception for 429 Too Many Requests responses
+ *
+ * @see https://tools.ietf.org/html/draft-nottingham-http-new-status-04
+ * @package Requests
+ */
+class Requests_Exception_HTTP_429 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 429;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Too Many Requests';
+}

+ 29 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/431.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Exception for 431 Request Header Fields Too Large responses
+ *
+ * @see https://tools.ietf.org/html/rfc6585
+ * @package Requests
+ */
+
+/**
+ * Exception for 431 Request Header Fields Too Large responses
+ *
+ * @see https://tools.ietf.org/html/rfc6585
+ * @package Requests
+ */
+class Requests_Exception_HTTP_431 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 431;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Request Header Fields Too Large';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/500.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 500 Internal Server Error responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 500 Internal Server Error responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_500 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 500;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Internal Server Error';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/501.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 501 Not Implemented responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 501 Not Implemented responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_501 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 501;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Not Implemented';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/502.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 502 Bad Gateway responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 502 Bad Gateway responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_502 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 502;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Bad Gateway';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/503.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 503 Service Unavailable responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 503 Service Unavailable responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_503 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 503;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Service Unavailable';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/504.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 504 Gateway Timeout responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 504 Gateway Timeout responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_504 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 504;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Gateway Timeout';
+}

+ 27 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/505.php

@@ -0,0 +1,27 @@
+<?php
+/**
+ * Exception for 505 HTTP Version Not Supported responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for 505 HTTP Version Not Supported responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_505 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 505;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'HTTP Version Not Supported';
+}

+ 29 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/511.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Exception for 511 Network Authentication Required responses
+ *
+ * @see https://tools.ietf.org/html/rfc6585
+ * @package Requests
+ */
+
+/**
+ * Exception for 511 Network Authentication Required responses
+ *
+ * @see https://tools.ietf.org/html/rfc6585
+ * @package Requests
+ */
+class Requests_Exception_HTTP_511 extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer
+	 */
+	protected $code = 511;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Network Authentication Required';
+}

+ 44 - 0
api/vendor/rmccue/requests/library/Requests/Exception/HTTP/Unknown.php

@@ -0,0 +1,44 @@
+<?php
+/**
+ * Exception for unknown status responses
+ *
+ * @package Requests
+ */
+
+/**
+ * Exception for unknown status responses
+ *
+ * @package Requests
+ */
+class Requests_Exception_HTTP_Unknown extends Requests_Exception_HTTP {
+	/**
+	 * HTTP status code
+	 *
+	 * @var integer|bool Code if available, false if an error occurred
+	 */
+	protected $code = 0;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Unknown';
+
+	/**
+	 * Create a new exception
+	 *
+	 * If `$data` is an instance of {@see Requests_Response}, uses the status
+	 * code from it. Otherwise, sets as 0
+	 *
+	 * @param string|null $reason Reason phrase
+	 * @param mixed $data Associated data
+	 */
+	public function __construct($reason = null, $data = null) {
+		if ($data instanceof Requests_Response) {
+			$this->code = $data->status_code;
+		}
+
+		parent::__construct($reason, $data);
+	}
+}

+ 5 - 0
api/vendor/rmccue/requests/library/Requests/Exception/Transport.php

@@ -0,0 +1,5 @@
+<?php
+
+class Requests_Exception_Transport extends Requests_Exception {
+
+}

+ 56 - 0
api/vendor/rmccue/requests/library/Requests/Exception/Transport/cURL.php

@@ -0,0 +1,56 @@
+<?php
+
+class Requests_Exception_Transport_cURL extends Requests_Exception_Transport {
+
+	const EASY = 'cURLEasy';
+	const MULTI = 'cURLMulti';
+	const SHARE = 'cURLShare';
+
+	/**
+	 * cURL error code
+	 *
+	 * @var integer
+	 */
+	protected $code = -1;
+
+	/**
+	 * Which type of cURL error
+	 *
+	 * EASY|MULTI|SHARE
+	 *
+	 * @var string
+	 */
+	protected $type = 'Unknown';
+
+	/**
+	 * Clear text error message
+	 *
+	 * @var string
+	 */
+	protected $reason = 'Unknown';
+
+	public function __construct($message, $type, $data = null, $code = 0) {
+		if ($type !== null) {
+			$this->type = $type;
+		}
+
+		if ($code !== null) {
+			$this->code = $code;
+		}
+
+		if ($message !== null) {
+			$this->reason = $message;
+		}
+
+		$message = sprintf('%d %s', $this->code, $this->reason);
+		parent::__construct($message, $this->type, $data, $this->code);
+	}
+
+	/**
+	 * Get the error message
+	 */
+	public function getReason() {
+		return $this->reason;
+	}
+
+}

+ 33 - 0
api/vendor/rmccue/requests/library/Requests/Hooker.php

@@ -0,0 +1,33 @@
+<?php
+/**
+ * Event dispatcher
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+
+/**
+ * Event dispatcher
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+interface Requests_Hooker {
+	/**
+	 * Register a callback for a hook
+	 *
+	 * @param string $hook Hook name
+	 * @param callback $callback Function/method to call on event
+	 * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
+	 */
+	public function register($hook, $callback, $priority = 0);
+
+	/**
+	 * Dispatch a message
+	 *
+	 * @param string $hook Hook name
+	 * @param array $parameters Parameters to pass to callbacks
+	 * @return boolean Successfulness
+	 */
+	public function dispatch($hook, $parameters = array());
+}

+ 68 - 0
api/vendor/rmccue/requests/library/Requests/Hooks.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Handles adding and dispatching events
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+
+/**
+ * Handles adding and dispatching events
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+class Requests_Hooks implements Requests_Hooker {
+	/**
+	 * Registered callbacks for each hook
+	 *
+	 * @var array
+	 */
+	protected $hooks = array();
+
+	/**
+	 * Constructor
+	 */
+	public function __construct() {
+		// pass
+	}
+
+	/**
+	 * Register a callback for a hook
+	 *
+	 * @param string $hook Hook name
+	 * @param callback $callback Function/method to call on event
+	 * @param int $priority Priority number. <0 is executed earlier, >0 is executed later
+	 */
+	public function register($hook, $callback, $priority = 0) {
+		if (!isset($this->hooks[$hook])) {
+			$this->hooks[$hook] = array();
+		}
+		if (!isset($this->hooks[$hook][$priority])) {
+			$this->hooks[$hook][$priority] = array();
+		}
+
+		$this->hooks[$hook][$priority][] = $callback;
+	}
+
+	/**
+	 * Dispatch a message
+	 *
+	 * @param string $hook Hook name
+	 * @param array $parameters Parameters to pass to callbacks
+	 * @return boolean Successfulness
+	 */
+	public function dispatch($hook, $parameters = array()) {
+		if (empty($this->hooks[$hook])) {
+			return false;
+		}
+
+		foreach ($this->hooks[$hook] as $priority => $hooked) {
+			foreach ($hooked as $callback) {
+				call_user_func_array($callback, $parameters);
+			}
+		}
+
+		return true;
+	}
+}

+ 388 - 0
api/vendor/rmccue/requests/library/Requests/IDNAEncoder.php

@@ -0,0 +1,388 @@
+<?php
+
+/**
+ * IDNA URL encoder
+ *
+ * Note: Not fully compliant, as nameprep does nothing yet.
+ *
+ * @package Requests
+ * @subpackage Utilities
+ * @see https://tools.ietf.org/html/rfc3490 IDNA specification
+ * @see https://tools.ietf.org/html/rfc3492 Punycode/Bootstrap specification
+ */
+class Requests_IDNAEncoder {
+	/**
+	 * ACE prefix used for IDNA
+	 *
+	 * @see https://tools.ietf.org/html/rfc3490#section-5
+	 * @var string
+	 */
+	const ACE_PREFIX = 'xn--';
+
+	/**#@+
+	 * Bootstrap constant for Punycode
+	 *
+	 * @see https://tools.ietf.org/html/rfc3492#section-5
+	 * @var int
+	 */
+	const BOOTSTRAP_BASE         = 36;
+	const BOOTSTRAP_TMIN         = 1;
+	const BOOTSTRAP_TMAX         = 26;
+	const BOOTSTRAP_SKEW         = 38;
+	const BOOTSTRAP_DAMP         = 700;
+	const BOOTSTRAP_INITIAL_BIAS = 72;
+	const BOOTSTRAP_INITIAL_N    = 128;
+	/**#@-*/
+
+	/**
+	 * Encode a hostname using Punycode
+	 *
+	 * @param string $string Hostname
+	 * @return string Punycode-encoded hostname
+	 */
+	public static function encode($string) {
+		$parts = explode('.', $string);
+		foreach ($parts as &$part) {
+			$part = self::to_ascii($part);
+		}
+		return implode('.', $parts);
+	}
+
+	/**
+	 * Convert a UTF-8 string to an ASCII string using Punycode
+	 *
+	 * @throws Requests_Exception Provided string longer than 64 ASCII characters (`idna.provided_too_long`)
+	 * @throws Requests_Exception Prepared string longer than 64 ASCII characters (`idna.prepared_too_long`)
+	 * @throws Requests_Exception Provided string already begins with xn-- (`idna.provided_is_prefixed`)
+	 * @throws Requests_Exception Encoded string longer than 64 ASCII characters (`idna.encoded_too_long`)
+	 *
+	 * @param string $string ASCII or UTF-8 string (max length 64 characters)
+	 * @return string ASCII string
+	 */
+	public static function to_ascii($string) {
+		// Step 1: Check if the string is already ASCII
+		if (self::is_ascii($string)) {
+			// Skip to step 7
+			if (strlen($string) < 64) {
+				return $string;
+			}
+
+			throw new Requests_Exception('Provided string is too long', 'idna.provided_too_long', $string);
+		}
+
+		// Step 2: nameprep
+		$string = self::nameprep($string);
+
+		// Step 3: UseSTD3ASCIIRules is false, continue
+		// Step 4: Check if it's ASCII now
+		if (self::is_ascii($string)) {
+			// Skip to step 7
+			if (strlen($string) < 64) {
+				return $string;
+			}
+
+			throw new Requests_Exception('Prepared string is too long', 'idna.prepared_too_long', $string);
+		}
+
+		// Step 5: Check ACE prefix
+		if (strpos($string, self::ACE_PREFIX) === 0) {
+			throw new Requests_Exception('Provided string begins with ACE prefix', 'idna.provided_is_prefixed', $string);
+		}
+
+		// Step 6: Encode with Punycode
+		$string = self::punycode_encode($string);
+
+		// Step 7: Prepend ACE prefix
+		$string = self::ACE_PREFIX . $string;
+
+		// Step 8: Check size
+		if (strlen($string) < 64) {
+			return $string;
+		}
+
+		throw new Requests_Exception('Encoded string is too long', 'idna.encoded_too_long', $string);
+	}
+
+	/**
+	 * Check whether a given string contains only ASCII characters
+	 *
+	 * @internal (Testing found regex was the fastest implementation)
+	 *
+	 * @param string $string
+	 * @return bool Is the string ASCII-only?
+	 */
+	protected static function is_ascii($string) {
+		return (preg_match('/(?:[^\x00-\x7F])/', $string) !== 1);
+	}
+
+	/**
+	 * Prepare a string for use as an IDNA name
+	 *
+	 * @todo Implement this based on RFC 3491 and the newer 5891
+	 * @param string $string
+	 * @return string Prepared string
+	 */
+	protected static function nameprep($string) {
+		return $string;
+	}
+
+	/**
+	 * Convert a UTF-8 string to a UCS-4 codepoint array
+	 *
+	 * Based on Requests_IRI::replace_invalid_with_pct_encoding()
+	 *
+	 * @throws Requests_Exception Invalid UTF-8 codepoint (`idna.invalidcodepoint`)
+	 * @param string $input
+	 * @return array Unicode code points
+	 */
+	protected static function utf8_to_codepoints($input) {
+		$codepoints = array();
+
+		// Get number of bytes
+		$strlen = strlen($input);
+
+		for ($position = 0; $position < $strlen; $position++) {
+			$value = ord($input[$position]);
+
+			// One byte sequence:
+			if ((~$value & 0x80) === 0x80) {
+				$character = $value;
+				$length = 1;
+				$remaining = 0;
+			}
+			// Two byte sequence:
+			elseif (($value & 0xE0) === 0xC0) {
+				$character = ($value & 0x1F) << 6;
+				$length = 2;
+				$remaining = 1;
+			}
+			// Three byte sequence:
+			elseif (($value & 0xF0) === 0xE0) {
+				$character = ($value & 0x0F) << 12;
+				$length = 3;
+				$remaining = 2;
+			}
+			// Four byte sequence:
+			elseif (($value & 0xF8) === 0xF0) {
+				$character = ($value & 0x07) << 18;
+				$length = 4;
+				$remaining = 3;
+			}
+			// Invalid byte:
+			else {
+				throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $value);
+			}
+
+			if ($remaining > 0) {
+				if ($position + $length > $strlen) {
+					throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
+				}
+				for ($position++; $remaining > 0; $position++) {
+					$value = ord($input[$position]);
+
+					// If it is invalid, count the sequence as invalid and reprocess the current byte:
+					if (($value & 0xC0) !== 0x80) {
+						throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
+					}
+
+					$character |= ($value & 0x3F) << (--$remaining * 6);
+				}
+				$position--;
+			}
+
+			if (
+				// Non-shortest form sequences are invalid
+				   $length > 1 && $character <= 0x7F
+				|| $length > 2 && $character <= 0x7FF
+				|| $length > 3 && $character <= 0xFFFF
+				// Outside of range of ucschar codepoints
+				// Noncharacters
+				|| ($character & 0xFFFE) === 0xFFFE
+				|| $character >= 0xFDD0 && $character <= 0xFDEF
+				|| (
+					// Everything else not in ucschar
+					   $character > 0xD7FF && $character < 0xF900
+					|| $character < 0x20
+					|| $character > 0x7E && $character < 0xA0
+					|| $character > 0xEFFFD
+				)
+			) {
+				throw new Requests_Exception('Invalid Unicode codepoint', 'idna.invalidcodepoint', $character);
+			}
+
+			$codepoints[] = $character;
+		}
+
+		return $codepoints;
+	}
+
+	/**
+	 * RFC3492-compliant encoder
+	 *
+	 * @internal Pseudo-code from Section 6.3 is commented with "#" next to relevant code
+	 * @throws Requests_Exception On character outside of the domain (never happens with Punycode) (`idna.character_outside_domain`)
+	 *
+	 * @param string $input UTF-8 encoded string to encode
+	 * @return string Punycode-encoded string
+	 */
+	public static function punycode_encode($input) {
+		$output = '';
+#		let n = initial_n
+		$n = self::BOOTSTRAP_INITIAL_N;
+#		let delta = 0
+		$delta = 0;
+#		let bias = initial_bias
+		$bias = self::BOOTSTRAP_INITIAL_BIAS;
+#		let h = b = the number of basic code points in the input
+		$h = $b = 0; // see loop
+#		copy them to the output in order
+		$codepoints = self::utf8_to_codepoints($input);
+		$extended = array();
+
+		foreach ($codepoints as $char) {
+			if ($char < 128) {
+				// Character is valid ASCII
+				// TODO: this should also check if it's valid for a URL
+				$output .= chr($char);
+				$h++;
+			}
+			// Check if the character is non-ASCII, but below initial n
+			// This never occurs for Punycode, so ignore in coverage
+			// @codeCoverageIgnoreStart
+			elseif ($char < $n) {
+				throw new Requests_Exception('Invalid character', 'idna.character_outside_domain', $char);
+			}
+			// @codeCoverageIgnoreEnd
+			else {
+				$extended[$char] = true;
+			}
+		}
+		$extended = array_keys($extended);
+		sort($extended);
+		$b = $h;
+#		[copy them] followed by a delimiter if b > 0
+		if (strlen($output) > 0) {
+			$output .= '-';
+		}
+#		{if the input contains a non-basic code point < n then fail}
+#		while h < length(input) do begin
+		while ($h < count($codepoints)) {
+#			let m = the minimum code point >= n in the input
+			$m = array_shift($extended);
+			//printf('next code point to insert is %s' . PHP_EOL, dechex($m));
+#			let delta = delta + (m - n) * (h + 1), fail on overflow
+			$delta += ($m - $n) * ($h + 1);
+#			let n = m
+			$n = $m;
+#			for each code point c in the input (in order) do begin
+			for ($num = 0; $num < count($codepoints); $num++) {
+				$c = $codepoints[$num];
+#				if c < n then increment delta, fail on overflow
+				if ($c < $n) {
+					$delta++;
+				}
+#				if c == n then begin
+				elseif ($c === $n) {
+#					let q = delta
+					$q = $delta;
+#					for k = base to infinity in steps of base do begin
+					for ($k = self::BOOTSTRAP_BASE; ; $k += self::BOOTSTRAP_BASE) {
+#						let t = tmin if k <= bias {+ tmin}, or
+#								tmax if k >= bias + tmax, or k - bias otherwise
+						if ($k <= ($bias + self::BOOTSTRAP_TMIN)) {
+							$t = self::BOOTSTRAP_TMIN;
+						}
+						elseif ($k >= ($bias + self::BOOTSTRAP_TMAX)) {
+							$t = self::BOOTSTRAP_TMAX;
+						}
+						else {
+							$t = $k - $bias;
+						}
+#						if q < t then break
+						if ($q < $t) {
+							break;
+						}
+#						output the code point for digit t + ((q - t) mod (base - t))
+						$digit = $t + (($q - $t) % (self::BOOTSTRAP_BASE - $t));
+						$output .= self::digit_to_char($digit);
+#						let q = (q - t) div (base - t)
+						$q = floor(($q - $t) / (self::BOOTSTRAP_BASE - $t));
+#					end
+					}
+#					output the code point for digit q
+					$output .= self::digit_to_char($q);
+#					let bias = adapt(delta, h + 1, test h equals b?)
+					$bias = self::adapt($delta, $h + 1, $h === $b);
+#					let delta = 0
+					$delta = 0;
+#					increment h
+					$h++;
+#				end
+				}
+#			end
+			}
+#			increment delta and n
+			$delta++;
+			$n++;
+#		end
+		}
+
+		return $output;
+	}
+
+	/**
+	 * Convert a digit to its respective character
+	 *
+	 * @see https://tools.ietf.org/html/rfc3492#section-5
+	 * @throws Requests_Exception On invalid digit (`idna.invalid_digit`)
+	 *
+	 * @param int $digit Digit in the range 0-35
+	 * @return string Single character corresponding to digit
+	 */
+	protected static function digit_to_char($digit) {
+		// @codeCoverageIgnoreStart
+		// As far as I know, this never happens, but still good to be sure.
+		if ($digit < 0 || $digit > 35) {
+			throw new Requests_Exception(sprintf('Invalid digit %d', $digit), 'idna.invalid_digit', $digit);
+		}
+		// @codeCoverageIgnoreEnd
+		$digits = 'abcdefghijklmnopqrstuvwxyz0123456789';
+		return substr($digits, $digit, 1);
+	}
+
+	/**
+	 * Adapt the bias
+	 *
+	 * @see https://tools.ietf.org/html/rfc3492#section-6.1
+	 * @param int $delta
+	 * @param int $numpoints
+	 * @param bool $firsttime
+	 * @return int New bias
+	 */
+	protected static function adapt($delta, $numpoints, $firsttime) {
+#	function adapt(delta,numpoints,firsttime):
+#		if firsttime then let delta = delta div damp
+		if ($firsttime) {
+			$delta = floor($delta / self::BOOTSTRAP_DAMP);
+		}
+#		else let delta = delta div 2
+		else {
+			$delta = floor($delta / 2);
+		}
+#		let delta = delta + (delta div numpoints)
+		$delta += floor($delta / $numpoints);
+#		let k = 0
+		$k = 0;
+#		while delta > ((base - tmin) * tmax) div 2 do begin
+		$max = floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN) * self::BOOTSTRAP_TMAX) / 2);
+		while ($delta > $max) {
+#			let delta = delta div (base - tmin)
+			$delta = floor($delta / (self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN));
+#			let k = k + base
+			$k += self::BOOTSTRAP_BASE;
+#		end
+		}
+#		return k + (((base - tmin + 1) * delta) div (delta + skew))
+		return $k + floor(((self::BOOTSTRAP_BASE - self::BOOTSTRAP_TMIN + 1) * $delta) / ($delta + self::BOOTSTRAP_SKEW));
+	}
+}

+ 190 - 0
api/vendor/rmccue/requests/library/Requests/IPv6.php

@@ -0,0 +1,190 @@
+<?php
+/**
+ * Class to validate and to work with IPv6 addresses
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+
+/**
+ * Class to validate and to work with IPv6 addresses
+ *
+ * This was originally based on the PEAR class of the same name, but has been
+ * entirely rewritten.
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+class Requests_IPv6 {
+	/**
+	 * Uncompresses an IPv6 address
+	 *
+	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
+	 * '::'. This method expects a valid IPv6 address and expands the '::' to
+	 * the required number of zero pieces.
+	 *
+	 * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
+	 *           ::1         ->  0:0:0:0:0:0:0:1
+	 *
+	 * @author Alexander Merz <alexander.merz@web.de>
+	 * @author elfrink at introweb dot nl
+	 * @author Josh Peck <jmp at joshpeck dot org>
+	 * @copyright 2003-2005 The PHP Group
+	 * @license http://www.opensource.org/licenses/bsd-license.php
+	 * @param string $ip An IPv6 address
+	 * @return string The uncompressed IPv6 address
+	 */
+	public static function uncompress($ip) {
+		if (substr_count($ip, '::') !== 1) {
+			return $ip;
+		}
+
+		list($ip1, $ip2) = explode('::', $ip);
+		$c1 = ($ip1 === '') ? -1 : substr_count($ip1, ':');
+		$c2 = ($ip2 === '') ? -1 : substr_count($ip2, ':');
+
+		if (strpos($ip2, '.') !== false) {
+			$c2++;
+		}
+		// ::
+		if ($c1 === -1 && $c2 === -1) {
+			$ip = '0:0:0:0:0:0:0:0';
+		}
+		// ::xxx
+		else if ($c1 === -1) {
+			$fill = str_repeat('0:', 7 - $c2);
+			$ip = str_replace('::', $fill, $ip);
+		}
+		// xxx::
+		else if ($c2 === -1) {
+			$fill = str_repeat(':0', 7 - $c1);
+			$ip = str_replace('::', $fill, $ip);
+		}
+		// xxx::xxx
+		else {
+			$fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
+			$ip = str_replace('::', $fill, $ip);
+		}
+		return $ip;
+	}
+
+	/**
+	 * Compresses an IPv6 address
+	 *
+	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
+	 * '::'. This method expects a valid IPv6 address and compresses consecutive
+	 * zero pieces to '::'.
+	 *
+	 * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
+	 *           0:0:0:0:0:0:0:1        ->  ::1
+	 *
+	 * @see uncompress()
+	 * @param string $ip An IPv6 address
+	 * @return string The compressed IPv6 address
+	 */
+	public static function compress($ip) {
+		// Prepare the IP to be compressed
+		$ip = self::uncompress($ip);
+		$ip_parts = self::split_v6_v4($ip);
+
+		// Replace all leading zeros
+		$ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
+
+		// Find bunches of zeros
+		if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
+			$max = 0;
+			$pos = null;
+			foreach ($matches[0] as $match) {
+				if (strlen($match[0]) > $max) {
+					$max = strlen($match[0]);
+					$pos = $match[1];
+				}
+			}
+
+			$ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
+		}
+
+		if ($ip_parts[1] !== '') {
+			return implode(':', $ip_parts);
+		}
+		else {
+			return $ip_parts[0];
+		}
+	}
+
+	/**
+	 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
+	 *
+	 * RFC 4291 allows you to represent the last two parts of an IPv6 address
+	 * using the standard IPv4 representation
+	 *
+	 * Example:  0:0:0:0:0:0:13.1.68.3
+	 *           0:0:0:0:0:FFFF:129.144.52.38
+	 *
+	 * @param string $ip An IPv6 address
+	 * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
+	 */
+	protected static function split_v6_v4($ip) {
+		if (strpos($ip, '.') !== false) {
+			$pos = strrpos($ip, ':');
+			$ipv6_part = substr($ip, 0, $pos);
+			$ipv4_part = substr($ip, $pos + 1);
+			return array($ipv6_part, $ipv4_part);
+		}
+		else {
+			return array($ip, '');
+		}
+	}
+
+	/**
+	 * Checks an IPv6 address
+	 *
+	 * Checks if the given IP is a valid IPv6 address
+	 *
+	 * @param string $ip An IPv6 address
+	 * @return bool true if $ip is a valid IPv6 address
+	 */
+	public static function check_ipv6($ip) {
+		$ip = self::uncompress($ip);
+		list($ipv6, $ipv4) = self::split_v6_v4($ip);
+		$ipv6 = explode(':', $ipv6);
+		$ipv4 = explode('.', $ipv4);
+		if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
+			foreach ($ipv6 as $ipv6_part) {
+				// The section can't be empty
+				if ($ipv6_part === '') {
+					return false;
+				}
+
+				// Nor can it be over four characters
+				if (strlen($ipv6_part) > 4) {
+					return false;
+				}
+
+				// Remove leading zeros (this is safe because of the above)
+				$ipv6_part = ltrim($ipv6_part, '0');
+				if ($ipv6_part === '') {
+					$ipv6_part = '0';
+				}
+
+				// Check the value is valid
+				$value = hexdec($ipv6_part);
+				if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
+					return false;
+				}
+			}
+			if (count($ipv4) === 4) {
+				foreach ($ipv4 as $ipv4_part) {
+					$value = (int) $ipv4_part;
+					if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
+						return false;
+					}
+				}
+			}
+			return true;
+		}
+		else {
+			return false;
+		}
+	}
+}

+ 1084 - 0
api/vendor/rmccue/requests/library/Requests/IRI.php

@@ -0,0 +1,1084 @@
+<?php
+/**
+ * IRI parser/serialiser/normaliser
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+
+/**
+ * IRI parser/serialiser/normaliser
+ *
+ * Copyright (c) 2007-2010, Geoffrey Sneddon and Steve Minutillo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of the SimplePie Team nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package Requests
+ * @subpackage Utilities
+ * @author Geoffrey Sneddon
+ * @author Steve Minutillo
+ * @copyright 2007-2009 Geoffrey Sneddon and Steve Minutillo
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @link http://hg.gsnedders.com/iri/
+ *
+ * @property string $iri IRI we're working with
+ * @property-read string $uri IRI in URI form, {@see to_uri}
+ * @property string $scheme Scheme part of the IRI
+ * @property string $authority Authority part, formatted for a URI (userinfo + host + port)
+ * @property string $iauthority Authority part of the IRI (userinfo + host + port)
+ * @property string $userinfo Userinfo part, formatted for a URI (after '://' and before '@')
+ * @property string $iuserinfo Userinfo part of the IRI (after '://' and before '@')
+ * @property string $host Host part, formatted for a URI
+ * @property string $ihost Host part of the IRI
+ * @property string $port Port part of the IRI (after ':')
+ * @property string $path Path part, formatted for a URI (after first '/')
+ * @property string $ipath Path part of the IRI (after first '/')
+ * @property string $query Query part, formatted for a URI (after '?')
+ * @property string $iquery Query part of the IRI (after '?')
+ * @property string $fragment Fragment, formatted for a URI (after '#')
+ * @property string $ifragment Fragment part of the IRI (after '#')
+ */
+class Requests_IRI {
+	/**
+	 * Scheme
+	 *
+	 * @var string
+	 */
+	protected $scheme = null;
+
+	/**
+	 * User Information
+	 *
+	 * @var string
+	 */
+	protected $iuserinfo = null;
+
+	/**
+	 * ihost
+	 *
+	 * @var string
+	 */
+	protected $ihost = null;
+
+	/**
+	 * Port
+	 *
+	 * @var string
+	 */
+	protected $port = null;
+
+	/**
+	 * ipath
+	 *
+	 * @var string
+	 */
+	protected $ipath = '';
+
+	/**
+	 * iquery
+	 *
+	 * @var string
+	 */
+	protected $iquery = null;
+
+	/**
+	 * ifragment
+	 *
+	 * @var string
+	 */
+	protected $ifragment = null;
+
+	/**
+	 * Normalization database
+	 *
+	 * Each key is the scheme, each value is an array with each key as the IRI
+	 * part and value as the default value for that part.
+	 */
+	protected $normalization = array(
+		'acap' => array(
+			'port' => 674
+		),
+		'dict' => array(
+			'port' => 2628
+		),
+		'file' => array(
+			'ihost' => 'localhost'
+		),
+		'http' => array(
+			'port' => 80,
+		),
+		'https' => array(
+			'port' => 443,
+		),
+	);
+
+	/**
+	 * Return the entire IRI when you try and read the object as a string
+	 *
+	 * @return string
+	 */
+	public function __toString() {
+		return $this->get_iri();
+	}
+
+	/**
+	 * Overload __set() to provide access via properties
+	 *
+	 * @param string $name Property name
+	 * @param mixed $value Property value
+	 */
+	public function __set($name, $value) {
+		if (method_exists($this, 'set_' . $name)) {
+			call_user_func(array($this, 'set_' . $name), $value);
+		}
+		elseif (
+			   $name === 'iauthority'
+			|| $name === 'iuserinfo'
+			|| $name === 'ihost'
+			|| $name === 'ipath'
+			|| $name === 'iquery'
+			|| $name === 'ifragment'
+		) {
+			call_user_func(array($this, 'set_' . substr($name, 1)), $value);
+		}
+	}
+
+	/**
+	 * Overload __get() to provide access via properties
+	 *
+	 * @param string $name Property name
+	 * @return mixed
+	 */
+	public function __get($name) {
+		// isset() returns false for null, we don't want to do that
+		// Also why we use array_key_exists below instead of isset()
+		$props = get_object_vars($this);
+
+		if (
+			$name === 'iri' ||
+			$name === 'uri' ||
+			$name === 'iauthority' ||
+			$name === 'authority'
+		) {
+			$method = 'get_' . $name;
+			$return = $this->$method();
+		}
+		elseif (array_key_exists($name, $props)) {
+			$return = $this->$name;
+		}
+		// host -> ihost
+		elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) {
+			$name = $prop;
+			$return = $this->$prop;
+		}
+		// ischeme -> scheme
+		elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) {
+			$name = $prop;
+			$return = $this->$prop;
+		}
+		else {
+			trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
+			$return = null;
+		}
+
+		if ($return === null && isset($this->normalization[$this->scheme][$name])) {
+			return $this->normalization[$this->scheme][$name];
+		}
+		else {
+			return $return;
+		}
+	}
+
+	/**
+	 * Overload __isset() to provide access via properties
+	 *
+	 * @param string $name Property name
+	 * @return bool
+	 */
+	public function __isset($name) {
+		return (method_exists($this, 'get_' . $name) || isset($this->$name));
+	}
+
+	/**
+	 * Overload __unset() to provide access via properties
+	 *
+	 * @param string $name Property name
+	 */
+	public function __unset($name) {
+		if (method_exists($this, 'set_' . $name)) {
+			call_user_func(array($this, 'set_' . $name), '');
+		}
+	}
+
+	/**
+	 * Create a new IRI object, from a specified string
+	 *
+	 * @param string|null $iri
+	 */
+	public function __construct($iri = null) {
+		$this->set_iri($iri);
+	}
+
+	/**
+	 * Create a new IRI object by resolving a relative IRI
+	 *
+	 * Returns false if $base is not absolute, otherwise an IRI.
+	 *
+	 * @param IRI|string $base (Absolute) Base IRI
+	 * @param IRI|string $relative Relative IRI
+	 * @return IRI|false
+	 */
+	public static function absolutize($base, $relative) {
+		if (!($relative instanceof Requests_IRI)) {
+			$relative = new Requests_IRI($relative);
+		}
+		if (!$relative->is_valid()) {
+			return false;
+		}
+		elseif ($relative->scheme !== null) {
+			return clone $relative;
+		}
+
+		if (!($base instanceof Requests_IRI)) {
+			$base = new Requests_IRI($base);
+		}
+		if ($base->scheme === null || !$base->is_valid()) {
+			return false;
+		}
+
+		if ($relative->get_iri() !== '') {
+			if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) {
+				$target = clone $relative;
+				$target->scheme = $base->scheme;
+			}
+			else {
+				$target = new Requests_IRI;
+				$target->scheme = $base->scheme;
+				$target->iuserinfo = $base->iuserinfo;
+				$target->ihost = $base->ihost;
+				$target->port = $base->port;
+				if ($relative->ipath !== '') {
+					if ($relative->ipath[0] === '/') {
+						$target->ipath = $relative->ipath;
+					}
+					elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') {
+						$target->ipath = '/' . $relative->ipath;
+					}
+					elseif (($last_segment = strrpos($base->ipath, '/')) !== false) {
+						$target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
+					}
+					else {
+						$target->ipath = $relative->ipath;
+					}
+					$target->ipath = $target->remove_dot_segments($target->ipath);
+					$target->iquery = $relative->iquery;
+				}
+				else {
+					$target->ipath = $base->ipath;
+					if ($relative->iquery !== null) {
+						$target->iquery = $relative->iquery;
+					}
+					elseif ($base->iquery !== null) {
+						$target->iquery = $base->iquery;
+					}
+				}
+				$target->ifragment = $relative->ifragment;
+			}
+		}
+		else {
+			$target = clone $base;
+			$target->ifragment = null;
+		}
+		$target->scheme_normalization();
+		return $target;
+	}
+
+	/**
+	 * Parse an IRI into scheme/authority/path/query/fragment segments
+	 *
+	 * @param string $iri
+	 * @return array
+	 */
+	protected function parse_iri($iri) {
+		$iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
+		$has_match = preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match);
+		if (!$has_match) {
+			throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri);
+		}
+
+		if ($match[1] === '') {
+			$match['scheme'] = null;
+		}
+		if (!isset($match[3]) || $match[3] === '') {
+			$match['authority'] = null;
+		}
+		if (!isset($match[5])) {
+			$match['path'] = '';
+		}
+		if (!isset($match[6]) || $match[6] === '') {
+			$match['query'] = null;
+		}
+		if (!isset($match[8]) || $match[8] === '') {
+			$match['fragment'] = null;
+		}
+		return $match;
+	}
+
+	/**
+	 * Remove dot segments from a path
+	 *
+	 * @param string $input
+	 * @return string
+	 */
+	protected function remove_dot_segments($input) {
+		$output = '';
+		while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') {
+			// A: If the input buffer begins with a prefix of "../" or "./",
+			// then remove that prefix from the input buffer; otherwise,
+			if (strpos($input, '../') === 0) {
+				$input = substr($input, 3);
+			}
+			elseif (strpos($input, './') === 0) {
+				$input = substr($input, 2);
+			}
+			// B: if the input buffer begins with a prefix of "/./" or "/.",
+			// where "." is a complete path segment, then replace that prefix
+			// with "/" in the input buffer; otherwise,
+			elseif (strpos($input, '/./') === 0) {
+				$input = substr($input, 2);
+			}
+			elseif ($input === '/.') {
+				$input = '/';
+			}
+			// C: if the input buffer begins with a prefix of "/../" or "/..",
+			// where ".." is a complete path segment, then replace that prefix
+			// with "/" in the input buffer and remove the last segment and its
+			// preceding "/" (if any) from the output buffer; otherwise,
+			elseif (strpos($input, '/../') === 0) {
+				$input = substr($input, 3);
+				$output = substr_replace($output, '', strrpos($output, '/'));
+			}
+			elseif ($input === '/..') {
+				$input = '/';
+				$output = substr_replace($output, '', strrpos($output, '/'));
+			}
+			// D: if the input buffer consists only of "." or "..", then remove
+			// that from the input buffer; otherwise,
+			elseif ($input === '.' || $input === '..') {
+				$input = '';
+			}
+			// E: move the first path segment in the input buffer to the end of
+			// the output buffer, including the initial "/" character (if any)
+			// and any subsequent characters up to, but not including, the next
+			// "/" character or the end of the input buffer
+			elseif (($pos = strpos($input, '/', 1)) !== false) {
+				$output .= substr($input, 0, $pos);
+				$input = substr_replace($input, '', 0, $pos);
+			}
+			else {
+				$output .= $input;
+				$input = '';
+			}
+		}
+		return $output . $input;
+	}
+
+	/**
+	 * Replace invalid character with percent encoding
+	 *
+	 * @param string $string Input string
+	 * @param string $extra_chars Valid characters not in iunreserved or
+	 *                            iprivate (this is ASCII-only)
+	 * @param bool $iprivate Allow iprivate
+	 * @return string
+	 */
+	protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) {
+		// Normalize as many pct-encoded sections as possible
+		$string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
+
+		// Replace invalid percent characters
+		$string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
+
+		// Add unreserved and % to $extra_chars (the latter is safe because all
+		// pct-encoded sections are now valid).
+		$extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
+
+		// Now replace any bytes that aren't allowed with their pct-encoded versions
+		$position = 0;
+		$strlen = strlen($string);
+		while (($position += strspn($string, $extra_chars, $position)) < $strlen) {
+			$value = ord($string[$position]);
+
+			// Start position
+			$start = $position;
+
+			// By default we are valid
+			$valid = true;
+
+			// No one byte sequences are valid due to the while.
+			// Two byte sequence:
+			if (($value & 0xE0) === 0xC0) {
+				$character = ($value & 0x1F) << 6;
+				$length = 2;
+				$remaining = 1;
+			}
+			// Three byte sequence:
+			elseif (($value & 0xF0) === 0xE0) {
+				$character = ($value & 0x0F) << 12;
+				$length = 3;
+				$remaining = 2;
+			}
+			// Four byte sequence:
+			elseif (($value & 0xF8) === 0xF0) {
+				$character = ($value & 0x07) << 18;
+				$length = 4;
+				$remaining = 3;
+			}
+			// Invalid byte:
+			else {
+				$valid = false;
+				$length = 1;
+				$remaining = 0;
+			}
+
+			if ($remaining) {
+				if ($position + $length <= $strlen) {
+					for ($position++; $remaining; $position++) {
+						$value = ord($string[$position]);
+
+						// Check that the byte is valid, then add it to the character:
+						if (($value & 0xC0) === 0x80) {
+							$character |= ($value & 0x3F) << (--$remaining * 6);
+						}
+						// If it is invalid, count the sequence as invalid and reprocess the current byte:
+						else {
+							$valid = false;
+							$position--;
+							break;
+						}
+					}
+				}
+				else {
+					$position = $strlen - 1;
+					$valid = false;
+				}
+			}
+
+			// Percent encode anything invalid or not in ucschar
+			if (
+				// Invalid sequences
+				!$valid
+				// Non-shortest form sequences are invalid
+				|| $length > 1 && $character <= 0x7F
+				|| $length > 2 && $character <= 0x7FF
+				|| $length > 3 && $character <= 0xFFFF
+				// Outside of range of ucschar codepoints
+				// Noncharacters
+				|| ($character & 0xFFFE) === 0xFFFE
+				|| $character >= 0xFDD0 && $character <= 0xFDEF
+				|| (
+					// Everything else not in ucschar
+					   $character > 0xD7FF && $character < 0xF900
+					|| $character < 0xA0
+					|| $character > 0xEFFFD
+				)
+				&& (
+					// Everything not in iprivate, if it applies
+					   !$iprivate
+					|| $character < 0xE000
+					|| $character > 0x10FFFD
+				)
+			) {
+				// If we were a character, pretend we weren't, but rather an error.
+				if ($valid) {
+					$position--;
+				}
+
+				for ($j = $start; $j <= $position; $j++) {
+					$string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
+					$j += 2;
+					$position += 2;
+					$strlen += 2;
+				}
+			}
+		}
+
+		return $string;
+	}
+
+	/**
+	 * Callback function for preg_replace_callback.
+	 *
+	 * Removes sequences of percent encoded bytes that represent UTF-8
+	 * encoded characters in iunreserved
+	 *
+	 * @param array $match PCRE match
+	 * @return string Replacement
+	 */
+	protected function remove_iunreserved_percent_encoded($match) {
+		// As we just have valid percent encoded sequences we can just explode
+		// and ignore the first member of the returned array (an empty string).
+		$bytes = explode('%', $match[0]);
+
+		// Initialize the new string (this is what will be returned) and that
+		// there are no bytes remaining in the current sequence (unsurprising
+		// at the first byte!).
+		$string = '';
+		$remaining = 0;
+
+		// Loop over each and every byte, and set $value to its value
+		for ($i = 1, $len = count($bytes); $i < $len; $i++) {
+			$value = hexdec($bytes[$i]);
+
+			// If we're the first byte of sequence:
+			if (!$remaining) {
+				// Start position
+				$start = $i;
+
+				// By default we are valid
+				$valid = true;
+
+				// One byte sequence:
+				if ($value <= 0x7F) {
+					$character = $value;
+					$length = 1;
+				}
+				// Two byte sequence:
+				elseif (($value & 0xE0) === 0xC0) {
+					$character = ($value & 0x1F) << 6;
+					$length = 2;
+					$remaining = 1;
+				}
+				// Three byte sequence:
+				elseif (($value & 0xF0) === 0xE0) {
+					$character = ($value & 0x0F) << 12;
+					$length = 3;
+					$remaining = 2;
+				}
+				// Four byte sequence:
+				elseif (($value & 0xF8) === 0xF0) {
+					$character = ($value & 0x07) << 18;
+					$length = 4;
+					$remaining = 3;
+				}
+				// Invalid byte:
+				else {
+					$valid = false;
+					$remaining = 0;
+				}
+			}
+			// Continuation byte:
+			else {
+				// Check that the byte is valid, then add it to the character:
+				if (($value & 0xC0) === 0x80) {
+					$remaining--;
+					$character |= ($value & 0x3F) << ($remaining * 6);
+				}
+				// If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
+				else {
+					$valid = false;
+					$remaining = 0;
+					$i--;
+				}
+			}
+
+			// If we've reached the end of the current byte sequence, append it to Unicode::$data
+			if (!$remaining) {
+				// Percent encode anything invalid or not in iunreserved
+				if (
+					// Invalid sequences
+					!$valid
+					// Non-shortest form sequences are invalid
+					|| $length > 1 && $character <= 0x7F
+					|| $length > 2 && $character <= 0x7FF
+					|| $length > 3 && $character <= 0xFFFF
+					// Outside of range of iunreserved codepoints
+					|| $character < 0x2D
+					|| $character > 0xEFFFD
+					// Noncharacters
+					|| ($character & 0xFFFE) === 0xFFFE
+					|| $character >= 0xFDD0 && $character <= 0xFDEF
+					// Everything else not in iunreserved (this is all BMP)
+					|| $character === 0x2F
+					|| $character > 0x39 && $character < 0x41
+					|| $character > 0x5A && $character < 0x61
+					|| $character > 0x7A && $character < 0x7E
+					|| $character > 0x7E && $character < 0xA0
+					|| $character > 0xD7FF && $character < 0xF900
+				) {
+					for ($j = $start; $j <= $i; $j++) {
+						$string .= '%' . strtoupper($bytes[$j]);
+					}
+				}
+				else {
+					for ($j = $start; $j <= $i; $j++) {
+						$string .= chr(hexdec($bytes[$j]));
+					}
+				}
+			}
+		}
+
+		// If we have any bytes left over they are invalid (i.e., we are
+		// mid-way through a multi-byte sequence)
+		if ($remaining) {
+			for ($j = $start; $j < $len; $j++) {
+				$string .= '%' . strtoupper($bytes[$j]);
+			}
+		}
+
+		return $string;
+	}
+
+	protected function scheme_normalization() {
+		if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) {
+			$this->iuserinfo = null;
+		}
+		if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) {
+			$this->ihost = null;
+		}
+		if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) {
+			$this->port = null;
+		}
+		if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) {
+			$this->ipath = '';
+		}
+		if (isset($this->ihost) && empty($this->ipath)) {
+			$this->ipath = '/';
+		}
+		if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) {
+			$this->iquery = null;
+		}
+		if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) {
+			$this->ifragment = null;
+		}
+	}
+
+	/**
+	 * Check if the object represents a valid IRI. This needs to be done on each
+	 * call as some things change depending on another part of the IRI.
+	 *
+	 * @return bool
+	 */
+	public function is_valid() {
+		$isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
+		if ($this->ipath !== '' &&
+			(
+				$isauthority && $this->ipath[0] !== '/' ||
+				(
+					$this->scheme === null &&
+					!$isauthority &&
+					strpos($this->ipath, ':') !== false &&
+					(strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
+				)
+			)
+		) {
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * Set the entire IRI. Returns true on success, false on failure (if there
+	 * are any invalid characters).
+	 *
+	 * @param string $iri
+	 * @return bool
+	 */
+	protected function set_iri($iri) {
+		static $cache;
+		if (!$cache) {
+			$cache = array();
+		}
+
+		if ($iri === null) {
+			return true;
+		}
+		if (isset($cache[$iri])) {
+			list($this->scheme,
+				 $this->iuserinfo,
+				 $this->ihost,
+				 $this->port,
+				 $this->ipath,
+				 $this->iquery,
+				 $this->ifragment,
+				 $return) = $cache[$iri];
+			return $return;
+		}
+
+		$parsed = $this->parse_iri((string) $iri);
+
+		$return = $this->set_scheme($parsed['scheme'])
+			&& $this->set_authority($parsed['authority'])
+			&& $this->set_path($parsed['path'])
+			&& $this->set_query($parsed['query'])
+			&& $this->set_fragment($parsed['fragment']);
+
+		$cache[$iri] = array($this->scheme,
+							 $this->iuserinfo,
+							 $this->ihost,
+							 $this->port,
+							 $this->ipath,
+							 $this->iquery,
+							 $this->ifragment,
+							 $return);
+		return $return;
+	}
+
+	/**
+	 * Set the scheme. Returns true on success, false on failure (if there are
+	 * any invalid characters).
+	 *
+	 * @param string $scheme
+	 * @return bool
+	 */
+	protected function set_scheme($scheme) {
+		if ($scheme === null) {
+			$this->scheme = null;
+		}
+		elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) {
+			$this->scheme = null;
+			return false;
+		}
+		else {
+			$this->scheme = strtolower($scheme);
+		}
+		return true;
+	}
+
+	/**
+	 * Set the authority. Returns true on success, false on failure (if there are
+	 * any invalid characters).
+	 *
+	 * @param string $authority
+	 * @return bool
+	 */
+	protected function set_authority($authority) {
+		static $cache;
+		if (!$cache) {
+			$cache = array();
+		}
+
+		if ($authority === null) {
+			$this->iuserinfo = null;
+			$this->ihost = null;
+			$this->port = null;
+			return true;
+		}
+		if (isset($cache[$authority])) {
+			list($this->iuserinfo,
+				 $this->ihost,
+				 $this->port,
+				 $return) = $cache[$authority];
+
+			return $return;
+		}
+
+		$remaining = $authority;
+		if (($iuserinfo_end = strrpos($remaining, '@')) !== false) {
+			$iuserinfo = substr($remaining, 0, $iuserinfo_end);
+			$remaining = substr($remaining, $iuserinfo_end + 1);
+		}
+		else {
+			$iuserinfo = null;
+		}
+		if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) {
+			$port = substr($remaining, $port_start + 1);
+			if ($port === false || $port === '') {
+				$port = null;
+			}
+			$remaining = substr($remaining, 0, $port_start);
+		}
+		else {
+			$port = null;
+		}
+
+		$return = $this->set_userinfo($iuserinfo) &&
+				  $this->set_host($remaining) &&
+				  $this->set_port($port);
+
+		$cache[$authority] = array($this->iuserinfo,
+								   $this->ihost,
+								   $this->port,
+								   $return);
+
+		return $return;
+	}
+
+	/**
+	 * Set the iuserinfo.
+	 *
+	 * @param string $iuserinfo
+	 * @return bool
+	 */
+	protected function set_userinfo($iuserinfo) {
+		if ($iuserinfo === null) {
+			$this->iuserinfo = null;
+		}
+		else {
+			$this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
+			$this->scheme_normalization();
+		}
+
+		return true;
+	}
+
+	/**
+	 * Set the ihost. Returns true on success, false on failure (if there are
+	 * any invalid characters).
+	 *
+	 * @param string $ihost
+	 * @return bool
+	 */
+	protected function set_host($ihost) {
+		if ($ihost === null) {
+			$this->ihost = null;
+			return true;
+		}
+		if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') {
+			if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) {
+				$this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']';
+			}
+			else {
+				$this->ihost = null;
+				return false;
+			}
+		}
+		else {
+			$ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
+
+			// Lowercase, but ignore pct-encoded sections (as they should
+			// remain uppercase). This must be done after the previous step
+			// as that can add unescaped characters.
+			$position = 0;
+			$strlen = strlen($ihost);
+			while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) {
+				if ($ihost[$position] === '%') {
+					$position += 3;
+				}
+				else {
+					$ihost[$position] = strtolower($ihost[$position]);
+					$position++;
+				}
+			}
+
+			$this->ihost = $ihost;
+		}
+
+		$this->scheme_normalization();
+
+		return true;
+	}
+
+	/**
+	 * Set the port. Returns true on success, false on failure (if there are
+	 * any invalid characters).
+	 *
+	 * @param string $port
+	 * @return bool
+	 */
+	protected function set_port($port) {
+		if ($port === null) {
+			$this->port = null;
+			return true;
+		}
+
+		if (strspn($port, '0123456789') === strlen($port)) {
+			$this->port = (int) $port;
+			$this->scheme_normalization();
+			return true;
+		}
+
+		$this->port = null;
+		return false;
+	}
+
+	/**
+	 * Set the ipath.
+	 *
+	 * @param string $ipath
+	 * @return bool
+	 */
+	protected function set_path($ipath) {
+		static $cache;
+		if (!$cache) {
+			$cache = array();
+		}
+
+		$ipath = (string) $ipath;
+
+		if (isset($cache[$ipath])) {
+			$this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
+		}
+		else {
+			$valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
+			$removed = $this->remove_dot_segments($valid);
+
+			$cache[$ipath] = array($valid, $removed);
+			$this->ipath = ($this->scheme !== null) ? $removed : $valid;
+		}
+		$this->scheme_normalization();
+		return true;
+	}
+
+	/**
+	 * Set the iquery.
+	 *
+	 * @param string $iquery
+	 * @return bool
+	 */
+	protected function set_query($iquery) {
+		if ($iquery === null) {
+			$this->iquery = null;
+		}
+		else {
+			$this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
+			$this->scheme_normalization();
+		}
+		return true;
+	}
+
+	/**
+	 * Set the ifragment.
+	 *
+	 * @param string $ifragment
+	 * @return bool
+	 */
+	protected function set_fragment($ifragment) {
+		if ($ifragment === null) {
+			$this->ifragment = null;
+		}
+		else {
+			$this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
+			$this->scheme_normalization();
+		}
+		return true;
+	}
+
+	/**
+	 * Convert an IRI to a URI (or parts thereof)
+	 *
+	 * @param string|bool IRI to convert (or false from {@see get_iri})
+	 * @return string|false URI if IRI is valid, false otherwise.
+	 */
+	protected function to_uri($string) {
+		if (!is_string($string)) {
+			return false;
+		}
+
+		static $non_ascii;
+		if (!$non_ascii) {
+			$non_ascii = implode('', range("\x80", "\xFF"));
+		}
+
+		$position = 0;
+		$strlen = strlen($string);
+		while (($position += strcspn($string, $non_ascii, $position)) < $strlen) {
+			$string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
+			$position += 3;
+			$strlen += 2;
+		}
+
+		return $string;
+	}
+
+	/**
+	 * Get the complete IRI
+	 *
+	 * @return string
+	 */
+	protected function get_iri() {
+		if (!$this->is_valid()) {
+			return false;
+		}
+
+		$iri = '';
+		if ($this->scheme !== null) {
+			$iri .= $this->scheme . ':';
+		}
+		if (($iauthority = $this->get_iauthority()) !== null) {
+			$iri .= '//' . $iauthority;
+		}
+		$iri .= $this->ipath;
+		if ($this->iquery !== null) {
+			$iri .= '?' . $this->iquery;
+		}
+		if ($this->ifragment !== null) {
+			$iri .= '#' . $this->ifragment;
+		}
+
+		return $iri;
+	}
+
+	/**
+	 * Get the complete URI
+	 *
+	 * @return string
+	 */
+	protected function get_uri() {
+		return $this->to_uri($this->get_iri());
+	}
+
+	/**
+	 * Get the complete iauthority
+	 *
+	 * @return string
+	 */
+	protected function get_iauthority() {
+		if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) {
+			return null;
+		}
+
+		$iauthority = '';
+		if ($this->iuserinfo !== null) {
+			$iauthority .= $this->iuserinfo . '@';
+		}
+		if ($this->ihost !== null) {
+			$iauthority .= $this->ihost;
+		}
+		if ($this->port !== null) {
+			$iauthority .= ':' . $this->port;
+		}
+		return $iauthority;
+	}
+
+	/**
+	 * Get the complete authority
+	 *
+	 * @return string
+	 */
+	protected function get_authority() {
+		$iauthority = $this->get_iauthority();
+		if (is_string($iauthority)) {
+			return $this->to_uri($iauthority);
+		}
+		else {
+			return $iauthority;
+		}
+	}
+}

+ 35 - 0
api/vendor/rmccue/requests/library/Requests/Proxy.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * Proxy connection interface
+ *
+ * @package Requests
+ * @subpackage Proxy
+ * @since 1.6
+ */
+
+/**
+ * Proxy connection interface
+ *
+ * Implement this interface to handle proxy settings and authentication
+ *
+ * Parameters should be passed via the constructor where possible, as this
+ * makes it much easier for users to use your provider.
+ *
+ * @see Requests_Hooks
+ * @package Requests
+ * @subpackage Proxy
+ * @since 1.6
+ */
+interface Requests_Proxy {
+	/**
+	 * Register hooks as needed
+	 *
+	 * This method is called in {@see Requests::request} when the user has set
+	 * an instance as the 'auth' option. Use this callback to register all the
+	 * hooks you'll need.
+	 *
+	 * @see Requests_Hooks::register
+	 * @param Requests_Hooks $hooks Hook system
+	 */
+	public function register(Requests_Hooks &$hooks);
+}

+ 151 - 0
api/vendor/rmccue/requests/library/Requests/Proxy/HTTP.php

@@ -0,0 +1,151 @@
+<?php
+/**
+ * HTTP Proxy connection interface
+ *
+ * @package Requests
+ * @subpackage Proxy
+ * @since 1.6
+ */
+
+/**
+ * HTTP Proxy connection interface
+ *
+ * Provides a handler for connection via an HTTP proxy
+ *
+ * @package Requests
+ * @subpackage Proxy
+ * @since 1.6
+ */
+class Requests_Proxy_HTTP implements Requests_Proxy {
+	/**
+	 * Proxy host and port
+	 *
+	 * Notation: "host:port" (eg 127.0.0.1:8080 or someproxy.com:3128)
+	 *
+	 * @var string
+	 */
+	public $proxy;
+
+	/**
+	 * Username
+	 *
+	 * @var string
+	 */
+	public $user;
+
+	/**
+	 * Password
+	 *
+	 * @var string
+	 */
+	public $pass;
+
+	/**
+	 * Do we need to authenticate? (ie username & password have been provided)
+	 *
+	 * @var boolean
+	 */
+	public $use_authentication;
+
+	/**
+	 * Constructor
+	 *
+	 * @since 1.6
+	 * @throws Requests_Exception On incorrect number of arguments (`authbasicbadargs`)
+	 * @param array|null $args Array of user and password. Must have exactly two elements
+	 */
+	public function __construct($args = null) {
+		if (is_string($args)) {
+			$this->proxy = $args;
+		}
+		elseif (is_array($args)) {
+			if (count($args) == 1) {
+				list($this->proxy) = $args;
+			}
+			elseif (count($args) == 3) {
+				list($this->proxy, $this->user, $this->pass) = $args;
+				$this->use_authentication = true;
+			}
+			else {
+				throw new Requests_Exception('Invalid number of arguments', 'proxyhttpbadargs');
+			}
+		}
+	}
+
+	/**
+	 * Register the necessary callbacks
+	 *
+	 * @since 1.6
+	 * @see curl_before_send
+	 * @see fsockopen_remote_socket
+	 * @see fsockopen_remote_host_path
+	 * @see fsockopen_header
+	 * @param Requests_Hooks $hooks Hook system
+	 */
+	public function register(Requests_Hooks &$hooks) {
+		$hooks->register('curl.before_send', array(&$this, 'curl_before_send'));
+
+		$hooks->register('fsockopen.remote_socket', array(&$this, 'fsockopen_remote_socket'));
+		$hooks->register('fsockopen.remote_host_path', array(&$this, 'fsockopen_remote_host_path'));
+		if ($this->use_authentication) {
+			$hooks->register('fsockopen.after_headers', array(&$this, 'fsockopen_header'));
+		}
+	}
+
+	/**
+	 * Set cURL parameters before the data is sent
+	 *
+	 * @since 1.6
+	 * @param resource $handle cURL resource
+	 */
+	public function curl_before_send(&$handle) {
+		curl_setopt($handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+		curl_setopt($handle, CURLOPT_PROXY, $this->proxy);
+
+		if ($this->use_authentication) {
+			curl_setopt($handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+			curl_setopt($handle, CURLOPT_PROXYUSERPWD, $this->get_auth_string());
+		}
+	}
+
+	/**
+	 * Alter remote socket information before opening socket connection
+	 *
+	 * @since 1.6
+	 * @param string $remote_socket Socket connection string
+	 */
+	public function fsockopen_remote_socket(&$remote_socket) {
+		$remote_socket = $this->proxy;
+	}
+
+	/**
+	 * Alter remote path before getting stream data
+	 *
+	 * @since 1.6
+	 * @param string $path Path to send in HTTP request string ("GET ...")
+	 * @param string $url Full URL we're requesting
+	 */
+	public function fsockopen_remote_host_path(&$path, $url) {
+		$path = $url;
+	}
+
+	/**
+	 * Add extra headers to the request before sending
+	 *
+	 * @since 1.6
+	 * @param string $out HTTP header string
+	 */
+	public function fsockopen_header(&$out) {
+		$out .= sprintf("Proxy-Authorization: Basic %s\r\n", base64_encode($this->get_auth_string()));
+	}
+
+	/**
+	 * Get the authentication string (user:pass)
+	 *
+	 * @since 1.6
+	 * @return string
+	 */
+	public function get_auth_string() {
+		return $this->user . ':' . $this->pass;
+	}
+}

+ 121 - 0
api/vendor/rmccue/requests/library/Requests/Response.php

@@ -0,0 +1,121 @@
+<?php
+/**
+ * HTTP response class
+ *
+ * Contains a response from Requests::request()
+ * @package Requests
+ */
+
+/**
+ * HTTP response class
+ *
+ * Contains a response from Requests::request()
+ * @package Requests
+ */
+class Requests_Response {
+	/**
+	 * Constructor
+	 */
+	public function __construct() {
+		$this->headers = new Requests_Response_Headers();
+		$this->cookies = new Requests_Cookie_Jar();
+	}
+
+	/**
+	 * Response body
+	 *
+	 * @var string
+	 */
+	public $body = '';
+
+	/**
+	 * Raw HTTP data from the transport
+	 *
+	 * @var string
+	 */
+	public $raw = '';
+
+	/**
+	 * Headers, as an associative array
+	 *
+	 * @var Requests_Response_Headers Array-like object representing headers
+	 */
+	public $headers = array();
+
+	/**
+	 * Status code, false if non-blocking
+	 *
+	 * @var integer|boolean
+	 */
+	public $status_code = false;
+
+	/**
+	 * Protocol version, false if non-blocking
+	 * @var float|boolean
+	 */
+	public $protocol_version = false;
+
+	/**
+	 * Whether the request succeeded or not
+	 *
+	 * @var boolean
+	 */
+	public $success = false;
+
+	/**
+	 * Number of redirects the request used
+	 *
+	 * @var integer
+	 */
+	public $redirects = 0;
+
+	/**
+	 * URL requested
+	 *
+	 * @var string
+	 */
+	public $url = '';
+
+	/**
+	 * Previous requests (from redirects)
+	 *
+	 * @var array Array of Requests_Response objects
+	 */
+	public $history = array();
+
+	/**
+	 * Cookies from the request
+	 *
+	 * @var Requests_Cookie_Jar Array-like object representing a cookie jar
+	 */
+	public $cookies = array();
+
+	/**
+	 * Is the response a redirect?
+	 *
+	 * @return boolean True if redirect (3xx status), false if not.
+	 */
+	public function is_redirect() {
+		$code = $this->status_code;
+		return in_array($code, array(300, 301, 302, 303, 307)) || $code > 307 && $code < 400;
+	}
+
+	/**
+	 * Throws an exception if the request was not successful
+	 *
+	 * @throws Requests_Exception If `$allow_redirects` is false, and code is 3xx (`response.no_redirects`)
+	 * @throws Requests_Exception_HTTP On non-successful status code. Exception class corresponds to code (e.g. {@see Requests_Exception_HTTP_404})
+	 * @param boolean $allow_redirects Set to false to throw on a 3xx as well
+	 */
+	public function throw_for_status($allow_redirects = true) {
+		if ($this->is_redirect()) {
+			if (!$allow_redirects) {
+				throw new Requests_Exception('Redirection not allowed', 'response.no_redirects', $this);
+			}
+		}
+		elseif (!$this->success) {
+			$exception = Requests_Exception_HTTP::get_class($this->status_code);
+			throw new $exception(null, $this);
+		}
+	}
+}

+ 98 - 0
api/vendor/rmccue/requests/library/Requests/Response/Headers.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * Case-insensitive dictionary, suitable for HTTP headers
+ *
+ * @package Requests
+ */
+
+/**
+ * Case-insensitive dictionary, suitable for HTTP headers
+ *
+ * @package Requests
+ */
+class Requests_Response_Headers extends Requests_Utility_CaseInsensitiveDictionary {
+	/**
+	 * Get the given header
+	 *
+	 * Unlike {@see self::getValues()}, this returns a string. If there are
+	 * multiple values, it concatenates them with a comma as per RFC2616.
+	 *
+	 * Avoid using this where commas may be used unquoted in values, such as
+	 * Set-Cookie headers.
+	 *
+	 * @param string $key
+	 * @return string Header value
+	 */
+	public function offsetGet($key) {
+		$key = strtolower($key);
+		if (!isset($this->data[$key])) {
+			return null;
+		}
+
+		return $this->flatten($this->data[$key]);
+	}
+
+	/**
+	 * Set the given item
+	 *
+	 * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
+	 *
+	 * @param string $key Item name
+	 * @param string $value Item value
+	 */
+	public function offsetSet($key, $value) {
+		if ($key === null) {
+			throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
+		}
+
+		$key = strtolower($key);
+
+		if (!isset($this->data[$key])) {
+			$this->data[$key] = array();
+		}
+
+		$this->data[$key][] = $value;
+	}
+
+	/**
+	 * Get all values for a given header
+	 *
+	 * @param string $key
+	 * @return array Header values
+	 */
+	public function getValues($key) {
+		$key = strtolower($key);
+		if (!isset($this->data[$key])) {
+			return null;
+		}
+
+		return $this->data[$key];
+	}
+
+	/**
+	 * Flattens a value into a string
+	 *
+	 * Converts an array into a string by imploding values with a comma, as per
+	 * RFC2616's rules for folding headers.
+	 *
+	 * @param string|array $value Value to flatten
+	 * @return string Flattened value
+	 */
+	public function flatten($value) {
+		if (is_array($value)) {
+			$value = implode(',', $value);
+		}
+
+		return $value;
+	}
+
+	/**
+	 * Get an iterator for the data
+	 *
+	 * Converts the internal
+	 * @return ArrayIterator
+	 */
+	public function getIterator() {
+		return new Requests_Utility_FilteredIterator($this->data, array($this, 'flatten'));
+	}
+}

+ 152 - 0
api/vendor/rmccue/requests/library/Requests/SSL.php

@@ -0,0 +1,152 @@
+<?php
+/**
+ * SSL utilities for Requests
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+
+/**
+ * SSL utilities for Requests
+ *
+ * Collection of utilities for working with and verifying SSL certificates.
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+class Requests_SSL {
+	/**
+	 * Verify the certificate against common name and subject alternative names
+	 *
+	 * Unfortunately, PHP doesn't check the certificate against the alternative
+	 * names, leading things like 'https://www.github.com/' to be invalid.
+	 * Instead
+	 *
+	 * @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
+	 *
+	 * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
+	 * @param string $host Host name to verify against
+	 * @param array $cert Certificate data from openssl_x509_parse()
+	 * @return bool
+	 */
+	public static function verify_certificate($host, $cert) {
+		// Calculate the valid wildcard match if the host is not an IP address
+		$parts = explode('.', $host);
+		if (ip2long($host) === false) {
+			$parts[0] = '*';
+		}
+		$wildcard = implode('.', $parts);
+
+		$has_dns_alt = false;
+
+		// Check the subjectAltName
+		if (!empty($cert['extensions']) && !empty($cert['extensions']['subjectAltName'])) {
+			$altnames = explode(',', $cert['extensions']['subjectAltName']);
+			foreach ($altnames as $altname) {
+				$altname = trim($altname);
+				if (strpos($altname, 'DNS:') !== 0) {
+					continue;
+				}
+
+				$has_dns_alt = true;
+
+				// Strip the 'DNS:' prefix and trim whitespace
+				$altname = trim(substr($altname, 4));
+
+				// Check for a match
+				if (self::match_domain($host, $altname) === true) {
+					return true;
+				}
+			}
+		}
+
+		// Fall back to checking the common name if we didn't get any dNSName
+		// alt names, as per RFC2818
+		if (!$has_dns_alt && !empty($cert['subject']['CN'])) {
+			// Check for a match
+			if (self::match_domain($host, $cert['subject']['CN']) === true) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Verify that a reference name is valid
+	 *
+	 * Verifies a dNSName for HTTPS usage, (almost) as per Firefox's rules:
+	 * - Wildcards can only occur in a name with more than 3 components
+	 * - Wildcards can only occur as the last character in the first
+	 *   component
+	 * - Wildcards may be preceded by additional characters
+	 *
+	 * We modify these rules to be a bit stricter and only allow the wildcard
+	 * character to be the full first component; that is, with the exclusion of
+	 * the third rule.
+	 *
+	 * @param string $reference Reference dNSName
+	 * @return boolean Is the name valid?
+	 */
+	public static function verify_reference_name($reference) {
+		$parts = explode('.', $reference);
+
+		// Check the first part of the name
+		$first = array_shift($parts);
+
+		if (strpos($first, '*') !== false) {
+			// Check that the wildcard is the full part
+			if ($first !== '*') {
+				return false;
+			}
+
+			// Check that we have at least 3 components (including first)
+			if (count($parts) < 2) {
+				return false;
+			}
+		}
+
+		// Check the remaining parts
+		foreach ($parts as $part) {
+			if (strpos($part, '*') !== false) {
+				return false;
+			}
+		}
+
+		// Nothing found, verified!
+		return true;
+	}
+
+	/**
+	 * Match a hostname against a dNSName reference
+	 *
+	 * @param string $host Requested host
+	 * @param string $reference dNSName to match against
+	 * @return boolean Does the domain match?
+	 */
+	public static function match_domain($host, $reference) {
+		// Check if the reference is blacklisted first
+		if (self::verify_reference_name($reference) !== true) {
+			return false;
+		}
+
+		// Check for a direct match
+		if ($host === $reference) {
+			return true;
+		}
+
+		// Calculate the valid wildcard match if the host is not an IP address
+		// Also validates that the host has 3 parts or more, as per Firefox's
+		// ruleset.
+		if (ip2long($host) === false) {
+			$parts = explode('.', $host);
+			$parts[0] = '*';
+			$wildcard = implode('.', $parts);
+			if ($wildcard === $reference) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+}

+ 266 - 0
api/vendor/rmccue/requests/library/Requests/Session.php

@@ -0,0 +1,266 @@
+<?php
+/**
+ * Session handler for persistent requests and default parameters
+ *
+ * @package Requests
+ * @subpackage Session Handler
+ */
+
+/**
+ * Session handler for persistent requests and default parameters
+ *
+ * Allows various options to be set as default values, and merges both the
+ * options and URL properties together. A base URL can be set for all requests,
+ * with all subrequests resolved from this. Base options can be set (including
+ * a shared cookie jar), then overridden for individual requests.
+ *
+ * @package Requests
+ * @subpackage Session Handler
+ */
+class Requests_Session {
+	/**
+	 * Base URL for requests
+	 *
+	 * URLs will be made absolute using this as the base
+	 * @var string|null
+	 */
+	public $url = null;
+
+	/**
+	 * Base headers for requests
+	 * @var array
+	 */
+	public $headers = array();
+
+	/**
+	 * Base data for requests
+	 *
+	 * If both the base data and the per-request data are arrays, the data will
+	 * be merged before sending the request.
+	 *
+	 * @var array
+	 */
+	public $data = array();
+
+	/**
+	 * Base options for requests
+	 *
+	 * The base options are merged with the per-request data for each request.
+	 * The only default option is a shared cookie jar between requests.
+	 *
+	 * Values here can also be set directly via properties on the Session
+	 * object, e.g. `$session->useragent = 'X';`
+	 *
+	 * @var array
+	 */
+	public $options = array();
+
+	/**
+	 * Create a new session
+	 *
+	 * @param string|null $url Base URL for requests
+	 * @param array $headers Default headers for requests
+	 * @param array $data Default data for requests
+	 * @param array $options Default options for requests
+	 */
+	public function __construct($url = null, $headers = array(), $data = array(), $options = array()) {
+		$this->url = $url;
+		$this->headers = $headers;
+		$this->data = $data;
+		$this->options = $options;
+
+		if (empty($this->options['cookies'])) {
+			$this->options['cookies'] = new Requests_Cookie_Jar();
+		}
+	}
+
+	/**
+	 * Get a property's value
+	 *
+	 * @param string $key Property key
+	 * @return mixed|null Property value, null if none found
+	 */
+	public function __get($key) {
+		if (isset($this->options[$key])) {
+			return $this->options[$key];
+		}
+
+		return null;
+	}
+
+	/**
+	 * Set a property's value
+	 *
+	 * @param string $key Property key
+	 * @param mixed $value Property value
+	 */
+	public function __set($key, $value) {
+		$this->options[$key] = $value;
+	}
+
+	/**
+	 * Remove a property's value
+	 *
+	 * @param string $key Property key
+	 */
+	public function __isset($key) {
+		return isset($this->options[$key]);
+	}
+
+	/**
+	 * Remove a property's value
+	 *
+	 * @param string $key Property key
+	 */
+	public function __unset($key) {
+		if (isset($this->options[$key])) {
+			unset($this->options[$key]);
+		}
+	}
+
+	/**#@+
+	 * @see request()
+	 * @param string $url
+	 * @param array $headers
+	 * @param array $options
+	 * @return Requests_Response
+	 */
+	/**
+	 * Send a GET request
+	 */
+	public function get($url, $headers = array(), $options = array()) {
+		return $this->request($url, $headers, null, Requests::GET, $options);
+	}
+
+	/**
+	 * Send a HEAD request
+	 */
+	public function head($url, $headers = array(), $options = array()) {
+		return $this->request($url, $headers, null, Requests::HEAD, $options);
+	}
+
+	/**
+	 * Send a DELETE request
+	 */
+	public function delete($url, $headers = array(), $options = array()) {
+		return $this->request($url, $headers, null, Requests::DELETE, $options);
+	}
+	/**#@-*/
+
+	/**#@+
+	 * @see request()
+	 * @param string $url
+	 * @param array $headers
+	 * @param array $data
+	 * @param array $options
+	 * @return Requests_Response
+	 */
+	/**
+	 * Send a POST request
+	 */
+	public function post($url, $headers = array(), $data = array(), $options = array()) {
+		return $this->request($url, $headers, $data, Requests::POST, $options);
+	}
+
+	/**
+	 * Send a PUT request
+	 */
+	public function put($url, $headers = array(), $data = array(), $options = array()) {
+		return $this->request($url, $headers, $data, Requests::PUT, $options);
+	}
+
+	/**
+	 * Send a PATCH request
+	 *
+	 * Note: Unlike {@see post} and {@see put}, `$headers` is required, as the
+	 * specification recommends that should send an ETag
+	 *
+	 * @link https://tools.ietf.org/html/rfc5789
+	 */
+	public function patch($url, $headers, $data = array(), $options = array()) {
+		return $this->request($url, $headers, $data, Requests::PATCH, $options);
+	}
+	/**#@-*/
+
+	/**
+	 * Main interface for HTTP requests
+	 *
+	 * This method initiates a request and sends it via a transport before
+	 * parsing.
+	 *
+	 * @see Requests::request()
+	 *
+	 * @throws Requests_Exception On invalid URLs (`nonhttp`)
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Extra headers to send with the request
+	 * @param array|null $data Data to send either as a query string for GET/HEAD requests, or in the body for POST requests
+	 * @param string $type HTTP request type (use Requests constants)
+	 * @param array $options Options for the request (see {@see Requests::request})
+	 * @return Requests_Response
+	 */
+	public function request($url, $headers = array(), $data = array(), $type = Requests::GET, $options = array()) {
+		$request = $this->merge_request(compact('url', 'headers', 'data', 'options'));
+
+		return Requests::request($request['url'], $request['headers'], $request['data'], $type, $request['options']);
+	}
+
+	/**
+	 * Send multiple HTTP requests simultaneously
+	 *
+	 * @see Requests::request_multiple()
+	 *
+	 * @param array $requests Requests data (see {@see Requests::request_multiple})
+	 * @param array $options Global and default options (see {@see Requests::request})
+	 * @return array Responses (either Requests_Response or a Requests_Exception object)
+	 */
+	public function request_multiple($requests, $options = array()) {
+		foreach ($requests as $key => $request) {
+			$requests[$key] = $this->merge_request($request, false);
+		}
+
+		$options = array_merge($this->options, $options);
+
+		// Disallow forcing the type, as that's a per request setting
+		unset($options['type']);
+
+		return Requests::request_multiple($requests, $options);
+	}
+
+	/**
+	 * Merge a request's data with the default data
+	 *
+	 * @param array $request Request data (same form as {@see request_multiple})
+	 * @param boolean $merge_options Should we merge options as well?
+	 * @return array Request data
+	 */
+	protected function merge_request($request, $merge_options = true) {
+		if ($this->url !== null) {
+			$request['url'] = Requests_IRI::absolutize($this->url, $request['url']);
+			$request['url'] = $request['url']->uri;
+		}
+
+		if (empty($request['headers'])) {
+			$request['headers'] = array();
+		}
+		$request['headers'] = array_merge($this->headers, $request['headers']);
+
+		if (empty($request['data'])) {
+			if (is_array($this->data)) {
+				$request['data'] = $this->data;
+			}
+		}
+		elseif (is_array($request['data']) && is_array($this->data)) {
+			$request['data'] = array_merge($this->data, $request['data']);
+		}
+
+		if ($merge_options !== false) {
+			$request['options'] = array_merge($this->options, $request['options']);
+
+			// Disallow forcing the type, as that's a per request setting
+			unset($request['options']['type']);
+		}
+
+		return $request;
+	}
+}

+ 41 - 0
api/vendor/rmccue/requests/library/Requests/Transport.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * Base HTTP transport
+ *
+ * @package Requests
+ * @subpackage Transport
+ */
+
+/**
+ * Base HTTP transport
+ *
+ * @package Requests
+ * @subpackage Transport
+ */
+interface Requests_Transport {
+	/**
+	 * Perform a request
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Associative array of request headers
+	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
+	 * @param array $options Request options, see {@see Requests::response()} for documentation
+	 * @return string Raw HTTP result
+	 */
+	public function request($url, $headers = array(), $data = array(), $options = array());
+
+	/**
+	 * Send multiple requests simultaneously
+	 *
+	 * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
+	 * @param array $options Global options, see {@see Requests::response()} for documentation
+	 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
+	 */
+	public function request_multiple($requests, $options);
+
+	/**
+	 * Self-test whether the transport can be used
+	 * @return bool
+	 */
+	public static function test();
+}

+ 542 - 0
api/vendor/rmccue/requests/library/Requests/Transport/cURL.php

@@ -0,0 +1,542 @@
+<?php
+/**
+ * cURL HTTP transport
+ *
+ * @package Requests
+ * @subpackage Transport
+ */
+
+/**
+ * cURL HTTP transport
+ *
+ * @package Requests
+ * @subpackage Transport
+ */
+class Requests_Transport_cURL implements Requests_Transport {
+	const CURL_7_10_5 = 0x070A05;
+	const CURL_7_16_2 = 0x071002;
+
+	/**
+	 * Raw HTTP data
+	 *
+	 * @var string
+	 */
+	public $headers = '';
+
+	/**
+	 * Raw body data
+	 *
+	 * @var string
+	 */
+	public $response_data = '';
+
+	/**
+	 * Information on the current request
+	 *
+	 * @var array cURL information array, see {@see https://secure.php.net/curl_getinfo}
+	 */
+	public $info;
+
+	/**
+	 * Version string
+	 *
+	 * @var long
+	 */
+	public $version;
+
+	/**
+	 * cURL handle
+	 *
+	 * @var resource
+	 */
+	protected $handle;
+
+	/**
+	 * Hook dispatcher instance
+	 *
+	 * @var Requests_Hooks
+	 */
+	protected $hooks;
+
+	/**
+	 * Have we finished the headers yet?
+	 *
+	 * @var boolean
+	 */
+	protected $done_headers = false;
+
+	/**
+	 * If streaming to a file, keep the file pointer
+	 *
+	 * @var resource
+	 */
+	protected $stream_handle;
+
+	/**
+	 * How many bytes are in the response body?
+	 *
+	 * @var int
+	 */
+	protected $response_bytes;
+
+	/**
+	 * What's the maximum number of bytes we should keep?
+	 *
+	 * @var int|bool Byte count, or false if no limit.
+	 */
+	protected $response_byte_limit;
+
+	/**
+	 * Constructor
+	 */
+	public function __construct() {
+		$curl = curl_version();
+		$this->version = $curl['version_number'];
+		$this->handle = curl_init();
+
+		curl_setopt($this->handle, CURLOPT_HEADER, false);
+		curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1);
+		if ($this->version >= self::CURL_7_10_5) {
+			curl_setopt($this->handle, CURLOPT_ENCODING, '');
+		}
+		if (defined('CURLOPT_PROTOCOLS')) {
+			curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
+		}
+		if (defined('CURLOPT_REDIR_PROTOCOLS')) {
+			curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
+		}
+	}
+
+	/**
+	 * Destructor
+	 */
+	public function __destruct() {
+		if (is_resource($this->handle)) {
+			curl_close($this->handle);
+		}
+	}
+
+	/**
+	 * Perform a request
+	 *
+	 * @throws Requests_Exception On a cURL error (`curlerror`)
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Associative array of request headers
+	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
+	 * @param array $options Request options, see {@see Requests::response()} for documentation
+	 * @return string Raw HTTP result
+	 */
+	public function request($url, $headers = array(), $data = array(), $options = array()) {
+		$this->hooks = $options['hooks'];
+
+		$this->setup_handle($url, $headers, $data, $options);
+
+		$options['hooks']->dispatch('curl.before_send', array(&$this->handle));
+
+		if ($options['filename'] !== false) {
+			$this->stream_handle = fopen($options['filename'], 'wb');
+		}
+
+		$this->response_data = '';
+		$this->response_bytes = 0;
+		$this->response_byte_limit = false;
+		if ($options['max_bytes'] !== false) {
+			$this->response_byte_limit = $options['max_bytes'];
+		}
+
+		if (isset($options['verify'])) {
+			if ($options['verify'] === false) {
+				curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
+				curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0);
+			}
+			elseif (is_string($options['verify'])) {
+				curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']);
+			}
+		}
+
+		if (isset($options['verifyname']) && $options['verifyname'] === false) {
+			curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
+		}
+
+		curl_exec($this->handle);
+		$response = $this->response_data;
+
+		$options['hooks']->dispatch('curl.after_send', array());
+
+		if (curl_errno($this->handle) === 23 || curl_errno($this->handle) === 61) {
+			// Reset encoding and try again
+			curl_setopt($this->handle, CURLOPT_ENCODING, 'none');
+
+			$this->response_data = '';
+			$this->response_bytes = 0;
+			curl_exec($this->handle);
+			$response = $this->response_data;
+		}
+
+		$this->process_response($response, $options);
+
+		// Need to remove the $this reference from the curl handle.
+		// Otherwise Requests_Transport_cURL wont be garbage collected and the curl_close() will never be called.
+		curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
+		curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);
+
+		return $this->headers;
+	}
+
+	/**
+	 * Send multiple requests simultaneously
+	 *
+	 * @param array $requests Request data
+	 * @param array $options Global options
+	 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
+	 */
+	public function request_multiple($requests, $options) {
+		// If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
+		if (empty($requests)) {
+			return array();
+		}
+
+		$multihandle = curl_multi_init();
+		$subrequests = array();
+		$subhandles = array();
+
+		$class = get_class($this);
+		foreach ($requests as $id => $request) {
+			$subrequests[$id] = new $class();
+			$subhandles[$id] = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
+			$request['options']['hooks']->dispatch('curl.before_multi_add', array(&$subhandles[$id]));
+			curl_multi_add_handle($multihandle, $subhandles[$id]);
+		}
+
+		$completed = 0;
+		$responses = array();
+
+		$request['options']['hooks']->dispatch('curl.before_multi_exec', array(&$multihandle));
+
+		do {
+			$active = false;
+
+			do {
+				$status = curl_multi_exec($multihandle, $active);
+			}
+			while ($status === CURLM_CALL_MULTI_PERFORM);
+
+			$to_process = array();
+
+			// Read the information as needed
+			while ($done = curl_multi_info_read($multihandle)) {
+				$key = array_search($done['handle'], $subhandles, true);
+				if (!isset($to_process[$key])) {
+					$to_process[$key] = $done;
+				}
+			}
+
+			// Parse the finished requests before we start getting the new ones
+			foreach ($to_process as $key => $done) {
+				$options = $requests[$key]['options'];
+				if (CURLE_OK !== $done['result']) {
+					//get error string for handle.
+					$reason = curl_error($done['handle']);
+					$exception = new Requests_Exception_Transport_cURL(
+									$reason,
+									Requests_Exception_Transport_cURL::EASY,
+									$done['handle'],
+									$done['result']
+								);
+					$responses[$key] = $exception;
+					$options['hooks']->dispatch('transport.internal.parse_error', array(&$responses[$key], $requests[$key]));
+				}
+				else {
+					$responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options);
+
+					$options['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$key], $requests[$key]));
+				}
+
+				curl_multi_remove_handle($multihandle, $done['handle']);
+				curl_close($done['handle']);
+
+				if (!is_string($responses[$key])) {
+					$options['hooks']->dispatch('multiple.request.complete', array(&$responses[$key], $key));
+				}
+				$completed++;
+			}
+		}
+		while ($active || $completed < count($subrequests));
+
+		$request['options']['hooks']->dispatch('curl.after_multi_exec', array(&$multihandle));
+
+		curl_multi_close($multihandle);
+
+		return $responses;
+	}
+
+	/**
+	 * Get the cURL handle for use in a multi-request
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Associative array of request headers
+	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
+	 * @param array $options Request options, see {@see Requests::response()} for documentation
+	 * @return resource Subrequest's cURL handle
+	 */
+	public function &get_subrequest_handle($url, $headers, $data, $options) {
+		$this->setup_handle($url, $headers, $data, $options);
+
+		if ($options['filename'] !== false) {
+			$this->stream_handle = fopen($options['filename'], 'wb');
+		}
+
+		$this->response_data = '';
+		$this->response_bytes = 0;
+		$this->response_byte_limit = false;
+		if ($options['max_bytes'] !== false) {
+			$this->response_byte_limit = $options['max_bytes'];
+		}
+		$this->hooks = $options['hooks'];
+
+		return $this->handle;
+	}
+
+	/**
+	 * Setup the cURL handle for the given data
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Associative array of request headers
+	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
+	 * @param array $options Request options, see {@see Requests::response()} for documentation
+	 */
+	protected function setup_handle($url, $headers, $data, $options) {
+		$options['hooks']->dispatch('curl.before_request', array(&$this->handle));
+
+		// Force closing the connection for old versions of cURL (<7.22).
+		if ( ! isset( $headers['Connection'] ) ) {
+			$headers['Connection'] = 'close';
+		}
+
+		$headers = Requests::flatten($headers);
+
+		if (!empty($data)) {
+			$data_format = $options['data_format'];
+
+			if ($data_format === 'query') {
+				$url = self::format_get($url, $data);
+				$data = '';
+			}
+			elseif (!is_string($data)) {
+				$data = http_build_query($data, null, '&');
+			}
+		}
+
+		switch ($options['type']) {
+			case Requests::POST:
+				curl_setopt($this->handle, CURLOPT_POST, true);
+				curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
+				break;
+			case Requests::HEAD:
+				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
+				curl_setopt($this->handle, CURLOPT_NOBODY, true);
+				break;
+			case Requests::TRACE:
+				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
+				break;
+			case Requests::PATCH:
+			case Requests::PUT:
+			case Requests::DELETE:
+			case Requests::OPTIONS:
+			default:
+				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
+				if (!empty($data)) {
+					curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
+				}
+		}
+
+		// cURL requires a minimum timeout of 1 second when using the system
+		// DNS resolver, as it uses `alarm()`, which is second resolution only.
+		// There's no way to detect which DNS resolver is being used from our
+		// end, so we need to round up regardless of the supplied timeout.
+		//
+		// https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609
+		$timeout = max($options['timeout'], 1);
+
+		if (is_int($timeout) || $this->version < self::CURL_7_16_2) {
+			curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout));
+		}
+		else {
+			curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000));
+		}
+
+		if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) {
+			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout']));
+		}
+		else {
+			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000));
+		}
+		curl_setopt($this->handle, CURLOPT_URL, $url);
+		curl_setopt($this->handle, CURLOPT_REFERER, $url);
+		curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
+		if (!empty($headers)) {
+			curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
+		}
+		if ($options['protocol_version'] === 1.1) {
+			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+		}
+		else {
+			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+		}
+
+		if (true === $options['blocking']) {
+			curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, array(&$this, 'stream_headers'));
+			curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, array(&$this, 'stream_body'));
+			curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
+		}
+	}
+
+	/**
+	 * Process a response
+	 *
+	 * @param string $response Response data from the body
+	 * @param array $options Request options
+	 * @return string HTTP response data including headers
+	 */
+	public function process_response($response, $options) {
+		if ($options['blocking'] === false) {
+			$fake_headers = '';
+			$options['hooks']->dispatch('curl.after_request', array(&$fake_headers));
+			return false;
+		}
+		if ($options['filename'] !== false) {
+			fclose($this->stream_handle);
+			$this->headers = trim($this->headers);
+		}
+		else {
+			$this->headers .= $response;
+		}
+
+		if (curl_errno($this->handle)) {
+			$error = sprintf(
+				'cURL error %s: %s',
+				curl_errno($this->handle),
+				curl_error($this->handle)
+			);
+			throw new Requests_Exception($error, 'curlerror', $this->handle);
+		}
+		$this->info = curl_getinfo($this->handle);
+
+		$options['hooks']->dispatch('curl.after_request', array(&$this->headers, &$this->info));
+		return $this->headers;
+	}
+
+	/**
+	 * Collect the headers as they are received
+	 *
+	 * @param resource $handle cURL resource
+	 * @param string $headers Header string
+	 * @return integer Length of provided header
+	 */
+	public function stream_headers($handle, $headers) {
+		// Why do we do this? cURL will send both the final response and any
+		// interim responses, such as a 100 Continue. We don't need that.
+		// (We may want to keep this somewhere just in case)
+		if ($this->done_headers) {
+			$this->headers = '';
+			$this->done_headers = false;
+		}
+		$this->headers .= $headers;
+
+		if ($headers === "\r\n") {
+			$this->done_headers = true;
+		}
+		return strlen($headers);
+	}
+
+	/**
+	 * Collect data as it's received
+	 *
+	 * @since 1.6.1
+	 *
+	 * @param resource $handle cURL resource
+	 * @param string $data Body data
+	 * @return integer Length of provided data
+	 */
+	public function stream_body($handle, $data) {
+		$this->hooks->dispatch('request.progress', array($data, $this->response_bytes, $this->response_byte_limit));
+		$data_length = strlen($data);
+
+		// Are we limiting the response size?
+		if ($this->response_byte_limit) {
+			if ($this->response_bytes === $this->response_byte_limit) {
+				// Already at maximum, move on
+				return $data_length;
+			}
+
+			if (($this->response_bytes + $data_length) > $this->response_byte_limit) {
+				// Limit the length
+				$limited_length = ($this->response_byte_limit - $this->response_bytes);
+				$data = substr($data, 0, $limited_length);
+			}
+		}
+
+		if ($this->stream_handle) {
+			fwrite($this->stream_handle, $data);
+		}
+		else {
+			$this->response_data .= $data;
+		}
+
+		$this->response_bytes += strlen($data);
+		return $data_length;
+	}
+
+	/**
+	 * Format a URL given GET data
+	 *
+	 * @param string $url
+	 * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query}
+	 * @return string URL with data
+	 */
+	protected static function format_get($url, $data) {
+		if (!empty($data)) {
+			$url_parts = parse_url($url);
+			if (empty($url_parts['query'])) {
+				$query = $url_parts['query'] = '';
+			}
+			else {
+				$query = $url_parts['query'];
+			}
+
+			$query .= '&' . http_build_query($data, null, '&');
+			$query = trim($query, '&');
+
+			if (empty($url_parts['query'])) {
+				$url .= '?' . $query;
+			}
+			else {
+				$url = str_replace($url_parts['query'], $query, $url);
+			}
+		}
+		return $url;
+	}
+
+	/**
+	 * Whether this transport is valid
+	 *
+	 * @codeCoverageIgnore
+	 * @return boolean True if the transport is valid, false otherwise.
+	 */
+	public static function test($capabilities = array()) {
+		if (!function_exists('curl_init') || !function_exists('curl_exec')) {
+			return false;
+		}
+
+		// If needed, check that our installed curl version supports SSL
+		if (isset($capabilities['ssl']) && $capabilities['ssl']) {
+			$curl_version = curl_version();
+			if (!(CURL_VERSION_SSL & $curl_version['features'])) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+}

+ 444 - 0
api/vendor/rmccue/requests/library/Requests/Transport/fsockopen.php

@@ -0,0 +1,444 @@
+<?php
+/**
+ * fsockopen HTTP transport
+ *
+ * @package Requests
+ * @subpackage Transport
+ */
+
+/**
+ * fsockopen HTTP transport
+ *
+ * @package Requests
+ * @subpackage Transport
+ */
+class Requests_Transport_fsockopen implements Requests_Transport {
+	/**
+	 * Second to microsecond conversion
+	 *
+	 * @var integer
+	 */
+	const SECOND_IN_MICROSECONDS = 1000000;
+
+	/**
+	 * Raw HTTP data
+	 *
+	 * @var string
+	 */
+	public $headers = '';
+
+	/**
+	 * Stream metadata
+	 *
+	 * @var array Associative array of properties, see {@see https://secure.php.net/stream_get_meta_data}
+	 */
+	public $info;
+
+	/**
+	 * What's the maximum number of bytes we should keep?
+	 *
+	 * @var int|bool Byte count, or false if no limit.
+	 */
+	protected $max_bytes = false;
+
+	protected $connect_error = '';
+
+	/**
+	 * Perform a request
+	 *
+	 * @throws Requests_Exception On failure to connect to socket (`fsockopenerror`)
+	 * @throws Requests_Exception On socket timeout (`timeout`)
+	 *
+	 * @param string $url URL to request
+	 * @param array $headers Associative array of request headers
+	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
+	 * @param array $options Request options, see {@see Requests::response()} for documentation
+	 * @return string Raw HTTP result
+	 */
+	public function request($url, $headers = array(), $data = array(), $options = array()) {
+		$options['hooks']->dispatch('fsockopen.before_request');
+
+		$url_parts = parse_url($url);
+		if (empty($url_parts)) {
+			throw new Requests_Exception('Invalid URL.', 'invalidurl', $url);
+		}
+		$host = $url_parts['host'];
+		$context = stream_context_create();
+		$verifyname = false;
+		$case_insensitive_headers = new Requests_Utility_CaseInsensitiveDictionary($headers);
+
+		// HTTPS support
+		if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
+			$remote_socket = 'ssl://' . $host;
+			if (!isset($url_parts['port'])) {
+				$url_parts['port'] = 443;
+			}
+
+			$context_options = array(
+				'verify_peer' => true,
+				// 'CN_match' => $host,
+				'capture_peer_cert' => true
+			);
+			$verifyname = true;
+
+			// SNI, if enabled (OpenSSL >=0.9.8j)
+			if (defined('OPENSSL_TLSEXT_SERVER_NAME') && OPENSSL_TLSEXT_SERVER_NAME) {
+				$context_options['SNI_enabled'] = true;
+				if (isset($options['verifyname']) && $options['verifyname'] === false) {
+					$context_options['SNI_enabled'] = false;
+				}
+			}
+
+			if (isset($options['verify'])) {
+				if ($options['verify'] === false) {
+					$context_options['verify_peer'] = false;
+				}
+				elseif (is_string($options['verify'])) {
+					$context_options['cafile'] = $options['verify'];
+				}
+			}
+
+			if (isset($options['verifyname']) && $options['verifyname'] === false) {
+				$context_options['verify_peer_name'] = false;
+				$verifyname = false;
+			}
+
+			stream_context_set_option($context, array('ssl' => $context_options));
+		}
+		else {
+			$remote_socket = 'tcp://' . $host;
+		}
+
+		$this->max_bytes = $options['max_bytes'];
+
+		if (!isset($url_parts['port'])) {
+			$url_parts['port'] = 80;
+		}
+		$remote_socket .= ':' . $url_parts['port'];
+
+		set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE);
+
+		$options['hooks']->dispatch('fsockopen.remote_socket', array(&$remote_socket));
+
+		$socket = stream_socket_client($remote_socket, $errno, $errstr, ceil($options['connect_timeout']), STREAM_CLIENT_CONNECT, $context);
+
+		restore_error_handler();
+
+		if ($verifyname && !$this->verify_certificate_from_context($host, $context)) {
+			throw new Requests_Exception('SSL certificate did not match the requested domain name', 'ssl.no_match');
+		}
+
+		if (!$socket) {
+			if ($errno === 0) {
+				// Connection issue
+				throw new Requests_Exception(rtrim($this->connect_error), 'fsockopen.connect_error');
+			}
+
+			throw new Requests_Exception($errstr, 'fsockopenerror', null, $errno);
+		}
+
+		$data_format = $options['data_format'];
+
+		if ($data_format === 'query') {
+			$path = self::format_get($url_parts, $data);
+			$data = '';
+		}
+		else {
+			$path = self::format_get($url_parts, array());
+		}
+
+		$options['hooks']->dispatch('fsockopen.remote_host_path', array(&$path, $url));
+
+		$request_body = '';
+		$out = sprintf("%s %s HTTP/%.1f\r\n", $options['type'], $path, $options['protocol_version']);
+
+		if ($options['type'] !== Requests::TRACE) {
+			if (is_array($data)) {
+				$request_body = http_build_query($data, null, '&');
+			}
+			else {
+				$request_body = $data;
+			}
+
+			if (!empty($data)) {
+				if (!isset($case_insensitive_headers['Content-Length'])) {
+					$headers['Content-Length'] = strlen($request_body);
+				}
+
+				if (!isset($case_insensitive_headers['Content-Type'])) {
+					$headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
+				}
+			}
+		}
+
+		if (!isset($case_insensitive_headers['Host'])) {
+			$out .= sprintf('Host: %s', $url_parts['host']);
+
+			if (( 'http' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 80 ) || ( 'https' === strtolower($url_parts['scheme']) && $url_parts['port'] !== 443 )) {
+				$out .= ':' . $url_parts['port'];
+			}
+			$out .= "\r\n";
+		}
+
+		if (!isset($case_insensitive_headers['User-Agent'])) {
+			$out .= sprintf("User-Agent: %s\r\n", $options['useragent']);
+		}
+
+		$accept_encoding = $this->accept_encoding();
+		if (!isset($case_insensitive_headers['Accept-Encoding']) && !empty($accept_encoding)) {
+			$out .= sprintf("Accept-Encoding: %s\r\n", $accept_encoding);
+		}
+
+		$headers = Requests::flatten($headers);
+
+		if (!empty($headers)) {
+			$out .= implode($headers, "\r\n") . "\r\n";
+		}
+
+		$options['hooks']->dispatch('fsockopen.after_headers', array(&$out));
+
+		if (substr($out, -2) !== "\r\n") {
+			$out .= "\r\n";
+		}
+
+		if (!isset($case_insensitive_headers['Connection'])) {
+			$out .= "Connection: Close\r\n";
+		}
+
+		$out .= "\r\n" . $request_body;
+
+		$options['hooks']->dispatch('fsockopen.before_send', array(&$out));
+
+		fwrite($socket, $out);
+		$options['hooks']->dispatch('fsockopen.after_send', array($out));
+
+		if (!$options['blocking']) {
+			fclose($socket);
+			$fake_headers = '';
+			$options['hooks']->dispatch('fsockopen.after_request', array(&$fake_headers));
+			return '';
+		}
+
+		$timeout_sec = (int) floor($options['timeout']);
+		if ($timeout_sec == $options['timeout']) {
+			$timeout_msec = 0;
+		}
+		else {
+			$timeout_msec = self::SECOND_IN_MICROSECONDS * $options['timeout'] % self::SECOND_IN_MICROSECONDS;
+		}
+		stream_set_timeout($socket, $timeout_sec, $timeout_msec);
+
+		$response = $body = $headers = '';
+		$this->info = stream_get_meta_data($socket);
+		$size = 0;
+		$doingbody = false;
+		$download = false;
+		if ($options['filename']) {
+			$download = fopen($options['filename'], 'wb');
+		}
+
+		while (!feof($socket)) {
+			$this->info = stream_get_meta_data($socket);
+			if ($this->info['timed_out']) {
+				throw new Requests_Exception('fsocket timed out', 'timeout');
+			}
+
+			$block = fread($socket, Requests::BUFFER_SIZE);
+			if (!$doingbody) {
+				$response .= $block;
+				if (strpos($response, "\r\n\r\n")) {
+					list($headers, $block) = explode("\r\n\r\n", $response, 2);
+					$doingbody = true;
+				}
+			}
+
+			// Are we in body mode now?
+			if ($doingbody) {
+				$options['hooks']->dispatch('request.progress', array($block, $size, $this->max_bytes));
+				$data_length = strlen($block);
+				if ($this->max_bytes) {
+					// Have we already hit a limit?
+					if ($size === $this->max_bytes) {
+						continue;
+					}
+					if (($size + $data_length) > $this->max_bytes) {
+						// Limit the length
+						$limited_length = ($this->max_bytes - $size);
+						$block = substr($block, 0, $limited_length);
+					}
+				}
+
+				$size += strlen($block);
+				if ($download) {
+					fwrite($download, $block);
+				}
+				else {
+					$body .= $block;
+				}
+			}
+		}
+		$this->headers = $headers;
+
+		if ($download) {
+			fclose($download);
+		}
+		else {
+			$this->headers .= "\r\n\r\n" . $body;
+		}
+		fclose($socket);
+
+		$options['hooks']->dispatch('fsockopen.after_request', array(&$this->headers, &$this->info));
+		return $this->headers;
+	}
+
+	/**
+	 * Send multiple requests simultaneously
+	 *
+	 * @param array $requests Request data (array of 'url', 'headers', 'data', 'options') as per {@see Requests_Transport::request}
+	 * @param array $options Global options, see {@see Requests::response()} for documentation
+	 * @return array Array of Requests_Response objects (may contain Requests_Exception or string responses as well)
+	 */
+	public function request_multiple($requests, $options) {
+		$responses = array();
+		$class = get_class($this);
+		foreach ($requests as $id => $request) {
+			try {
+				$handler = new $class();
+				$responses[$id] = $handler->request($request['url'], $request['headers'], $request['data'], $request['options']);
+
+				$request['options']['hooks']->dispatch('transport.internal.parse_response', array(&$responses[$id], $request));
+			}
+			catch (Requests_Exception $e) {
+				$responses[$id] = $e;
+			}
+
+			if (!is_string($responses[$id])) {
+				$request['options']['hooks']->dispatch('multiple.request.complete', array(&$responses[$id], $id));
+			}
+		}
+
+		return $responses;
+	}
+
+	/**
+	 * Retrieve the encodings we can accept
+	 *
+	 * @return string Accept-Encoding header value
+	 */
+	protected static function accept_encoding() {
+		$type = array();
+		if (function_exists('gzinflate')) {
+			$type[] = 'deflate;q=1.0';
+		}
+
+		if (function_exists('gzuncompress')) {
+			$type[] = 'compress;q=0.5';
+		}
+
+		$type[] = 'gzip;q=0.5';
+
+		return implode(', ', $type);
+	}
+
+	/**
+	 * Format a URL given GET data
+	 *
+	 * @param array $url_parts
+	 * @param array|object $data Data to build query using, see {@see https://secure.php.net/http_build_query}
+	 * @return string URL with data
+	 */
+	protected static function format_get($url_parts, $data) {
+		if (!empty($data)) {
+			if (empty($url_parts['query'])) {
+				$url_parts['query'] = '';
+			}
+
+			$url_parts['query'] .= '&' . http_build_query($data, null, '&');
+			$url_parts['query'] = trim($url_parts['query'], '&');
+		}
+		if (isset($url_parts['path'])) {
+			if (isset($url_parts['query'])) {
+				$get = $url_parts['path'] . '?' . $url_parts['query'];
+			}
+			else {
+				$get = $url_parts['path'];
+			}
+		}
+		else {
+			$get = '/';
+		}
+		return $get;
+	}
+
+	/**
+	 * Error handler for stream_socket_client()
+	 *
+	 * @param int $errno Error number (e.g. E_WARNING)
+	 * @param string $errstr Error message
+	 */
+	public function connect_error_handler($errno, $errstr) {
+		// Double-check we can handle it
+		if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) {
+			// Return false to indicate the default error handler should engage
+			return false;
+		}
+
+		$this->connect_error .= $errstr . "\n";
+		return true;
+	}
+
+	/**
+	 * Verify the certificate against common name and subject alternative names
+	 *
+	 * Unfortunately, PHP doesn't check the certificate against the alternative
+	 * names, leading things like 'https://www.github.com/' to be invalid.
+	 * Instead
+	 *
+	 * @see https://tools.ietf.org/html/rfc2818#section-3.1 RFC2818, Section 3.1
+	 *
+	 * @throws Requests_Exception On failure to connect via TLS (`fsockopen.ssl.connect_error`)
+	 * @throws Requests_Exception On not obtaining a match for the host (`fsockopen.ssl.no_match`)
+	 * @param string $host Host name to verify against
+	 * @param resource $context Stream context
+	 * @return bool
+	 */
+	public function verify_certificate_from_context($host, $context) {
+		$meta = stream_context_get_options($context);
+
+		// If we don't have SSL options, then we couldn't make the connection at
+		// all
+		if (empty($meta) || empty($meta['ssl']) || empty($meta['ssl']['peer_certificate'])) {
+			throw new Requests_Exception(rtrim($this->connect_error), 'ssl.connect_error');
+		}
+
+		$cert = openssl_x509_parse($meta['ssl']['peer_certificate']);
+
+		return Requests_SSL::verify_certificate($host, $cert);
+	}
+
+	/**
+	 * Whether this transport is valid
+	 *
+	 * @codeCoverageIgnore
+	 * @return boolean True if the transport is valid, false otherwise.
+	 */
+	public static function test($capabilities = array()) {
+		if (!function_exists('fsockopen')) {
+			return false;
+		}
+
+		// If needed, check that streams support SSL
+		if (isset($capabilities['ssl']) && $capabilities['ssl']) {
+			if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) {
+				return false;
+			}
+
+			// Currently broken, thanks to https://github.com/facebook/hhvm/issues/2156
+			if (defined('HHVM_VERSION')) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+}

+ 103 - 0
api/vendor/rmccue/requests/library/Requests/Utility/CaseInsensitiveDictionary.php

@@ -0,0 +1,103 @@
+<?php
+/**
+ * Case-insensitive dictionary, suitable for HTTP headers
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+
+/**
+ * Case-insensitive dictionary, suitable for HTTP headers
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+class Requests_Utility_CaseInsensitiveDictionary implements ArrayAccess, IteratorAggregate {
+	/**
+	 * Actual item data
+	 *
+	 * @var array
+	 */
+	protected $data = array();
+
+	/**
+	 * Creates a case insensitive dictionary.
+	 *
+	 * @param array $data Dictionary/map to convert to case-insensitive
+	 */
+	public function __construct(array $data = array()) {
+		foreach ($data as $key => $value) {
+			$this->offsetSet($key, $value);
+		}
+	}
+
+	/**
+	 * Check if the given item exists
+	 *
+	 * @param string $key Item key
+	 * @return boolean Does the item exist?
+	 */
+	public function offsetExists($key) {
+		$key = strtolower($key);
+		return isset($this->data[$key]);
+	}
+
+	/**
+	 * Get the value for the item
+	 *
+	 * @param string $key Item key
+	 * @return string Item value
+	 */
+	public function offsetGet($key) {
+		$key = strtolower($key);
+		if (!isset($this->data[$key])) {
+			return null;
+		}
+
+		return $this->data[$key];
+	}
+
+	/**
+	 * Set the given item
+	 *
+	 * @throws Requests_Exception On attempting to use dictionary as list (`invalidset`)
+	 *
+	 * @param string $key Item name
+	 * @param string $value Item value
+	 */
+	public function offsetSet($key, $value) {
+		if ($key === null) {
+			throw new Requests_Exception('Object is a dictionary, not a list', 'invalidset');
+		}
+
+		$key = strtolower($key);
+		$this->data[$key] = $value;
+	}
+
+	/**
+	 * Unset the given header
+	 *
+	 * @param string $key
+	 */
+	public function offsetUnset($key) {
+		unset($this->data[strtolower($key)]);
+	}
+
+	/**
+	 * Get an iterator for the data
+	 *
+	 * @return ArrayIterator
+	 */
+	public function getIterator() {
+		return new ArrayIterator($this->data);
+	}
+
+	/**
+	 * Get the headers as an array
+	 *
+	 * @return array Header data
+	 */
+	public function getAll() {
+		return $this->data;
+	}
+}

+ 45 - 0
api/vendor/rmccue/requests/library/Requests/Utility/FilteredIterator.php

@@ -0,0 +1,45 @@
+<?php
+/**
+ * Iterator for arrays requiring filtered values
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+
+/**
+ * Iterator for arrays requiring filtered values
+ *
+ * @package Requests
+ * @subpackage Utilities
+ */
+class Requests_Utility_FilteredIterator extends ArrayIterator {
+	/**
+	 * Callback to run as a filter
+	 *
+	 * @var callable
+	 */
+	protected $callback;
+
+	/**
+	 * Create a new iterator
+	 *
+	 * @param array $data
+	 * @param callable $callback Callback to be called on each value
+	 */
+	public function __construct($data, $callback) {
+		parent::__construct($data);
+
+		$this->callback = $callback;
+	}
+
+	/**
+	 * Get the current item's value after filtering
+	 *
+	 * @return string
+	 */
+	public function current() {
+		$value = parent::current();
+		$value = call_user_func($this->callback, $value);
+		return $value;
+	}
+}

+ 60 - 0
api/vendor/rmccue/requests/package.xml.tpl

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.8.0" version="2.0"
+	xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+				http://pear.php.net/dtd/tasks-1.0.xsd
+				http://pear.php.net/dtd/package-2.0
+				http://pear.php.net/dtd/package-2.0.xsd">
+	<name>Requests</name>
+	<channel>pear.ryanmccue.info</channel>
+	<summary>A HTTP library written in PHP, for human beings.</summary>
+	<description>
+			Requests is a HTTP library written in PHP, for human beings. It is
+			roughly based on the API from the excellent Requests Python library.
+			Requests is ISC Licensed (similar to the new BSD license) and has
+			no dependencies.
+	</description>
+	<lead>
+		<name>Ryan McCue</name>
+		<user>rmccue</user>
+		<email>me+pear@ryanmccue dot info</email>
+		<active>yes</active>
+	</lead>
+	<date>{{ date }}</date>
+	<time>{{ time }}</time>
+	<version>
+		<release>{{ version }}</release>
+		<api>{{ api_version }}</api>
+	</version>
+	<stability>
+		<release>{{ stability }}</release>
+		<api>{{ stability }}</api>
+	</stability>
+	<license uri="https://github.com/rmccue/Requests/blob/master/LICENSE" filesource="LICENSE">ISC</license>
+	<notes>-</notes>
+	<contents>
+		<dir name="/">
+			<file name="CHANGELOG.md" role="doc" />
+			<file name="LICENSE" role="doc" />
+			<file name="README.md" role="doc" />
+			<dir name="library">
+				<file install-as="Requests.php" name="Requests.php" role="php" />
+				<dir name="Requests">
+{{ files }}
+				</dir>
+			</dir>
+			<file name="library/Requests/Transport/cacert.pem" install-as="library/Requests/Transport/cacert.pem" role="data" />
+		</dir>
+	</contents>
+	<dependencies>
+		<required>
+			<php>
+				<min>5.2.0</min>
+			</php>
+			<pearinstaller>
+				<min>1.4.0</min>
+			</pearinstaller>
+		</required>
+	</dependencies>
+	<phprelease />
+</package>

+ 87 - 0
api/vendor/rmccue/requests/tests/Auth/Basic.php

@@ -0,0 +1,87 @@
+<?php
+
+class RequestsTest_Auth_Basic extends PHPUnit_Framework_TestCase {
+	public static function transportProvider() {
+		$transports = array(
+			array('Requests_Transport_fsockopen'),
+			array('Requests_Transport_cURL'),
+		);
+		return $transports;
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testUsingArray($transport) {
+		if (!call_user_func(array($transport, 'test'))) {
+			$this->markTestSkipped($transport . ' is not available');
+			return;
+		}
+
+		$options = array(
+			'auth' => array('user', 'passwd'),
+			'transport' => $transport,
+		);
+		$request = Requests::get(httpbin('/basic-auth/user/passwd'), array(), $options);
+		$this->assertEquals(200, $request->status_code);
+
+		$result = json_decode($request->body);
+		$this->assertEquals(true, $result->authenticated);
+		$this->assertEquals('user', $result->user);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testUsingInstantiation($transport) {
+		if (!call_user_func(array($transport, 'test'))) {
+			$this->markTestSkipped($transport . ' is not available');
+			return;
+		}
+
+		$options = array(
+			'auth' => new Requests_Auth_Basic(array('user', 'passwd')),
+			'transport' => $transport,
+		);
+		$request = Requests::get(httpbin('/basic-auth/user/passwd'), array(), $options);
+		$this->assertEquals(200, $request->status_code);
+
+		$result = json_decode($request->body);
+		$this->assertEquals(true, $result->authenticated);
+		$this->assertEquals('user', $result->user);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testPOSTUsingInstantiation($transport) {
+		if (!call_user_func(array($transport, 'test'))) {
+			$this->markTestSkipped($transport . ' is not available');
+			return;
+		}
+
+		$options = array(
+			'auth' => new Requests_Auth_Basic(array('user', 'passwd')),
+			'transport' => $transport,
+		);
+		$data = 'test';
+		$request = Requests::post(httpbin('/post'), array(), $data, $options);
+		$this->assertEquals(200, $request->status_code);
+
+		$result = json_decode($request->body);
+
+		$auth = $result->headers->Authorization;
+		$auth = explode(' ', $auth);
+
+		$this->assertEquals(base64_encode('user:passwd'), $auth[1]);
+        $this->assertEquals('test', $result->data);
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testMissingPassword() {
+		$auth = new Requests_Auth_Basic(array('user'));
+	}
+
+}

+ 93 - 0
api/vendor/rmccue/requests/tests/ChunkedEncoding.php

@@ -0,0 +1,93 @@
+<?php
+
+class RequestsTest_ChunkedDecoding extends PHPUnit_Framework_TestCase {
+	public static function chunkedProvider() {
+		return array(
+			array(
+				"25\r\nThis is the data in the first chunk\r\n\r\n1A\r\nand this is the second one\r\n0\r\n",
+				"This is the data in the first chunk\r\nand this is the second one"
+			),
+			array(
+				"02\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0\r\nnothing\n",
+				"abra\ncadabra"
+			),
+			array(
+				"02\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0c\r\n\nall we got\n",
+				"abra\ncadabra\nall we got\n"
+			),
+			array(
+				"02;foo=bar;hello=world\r\nab\r\n04;foo=baz\r\nra\nc\r\n06;justfoo\r\nadabra\r\n0c\r\n\nall we got\n",
+				"abra\ncadabra\nall we got\n"
+			),
+			array(
+				"02;foo=\"quoted value\"\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0c\r\n\nall we got\n",
+				"abra\ncadabra\nall we got\n"
+			),
+			array(
+				"02;foo-bar=baz\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0c\r\n\nall we got\n",
+				"abra\ncadabra\nall we got\n"
+			),
+		);
+	}
+
+	/**
+	 * @dataProvider chunkedProvider
+	 */
+	public function testChunked($body, $expected){
+		$transport = new MockTransport();
+		$transport->body = $body;
+		$transport->chunked = true;
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+
+		$this->assertEquals($expected, $response->body);
+	}
+
+	public static function notChunkedProvider() {
+		return array(
+			'invalid chunk size' => array( 'Hello! This is a non-chunked response!' ),
+			'invalid chunk extension' => array( '1BNot chunked\r\nLooks chunked but it is not\r\n' ),
+			'unquoted chunk-ext-val with space' => array( "02;foo=unquoted with space\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0c\r\n\nall we got\n" ),
+			'unquoted chunk-ext-val with forbidden character' => array( "02;foo={unquoted}\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0c\r\n\nall we got\n" ),
+			'invalid chunk-ext-name' => array( "02;{foo}=bar\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0c\r\n\nall we got\n" ),
+			'incomplete quote for chunk-ext-value' => array( "02;foo=\"no end quote\r\nab\r\n04\r\nra\nc\r\n06\r\nadabra\r\n0c\r\n\nall we got\n" ),
+		);
+	}
+
+	/**
+	 * Response says it's chunked, but actually isn't
+	 * @dataProvider notChunkedProvider
+	 */
+	public function testNotActuallyChunked($body) {
+		$transport = new MockTransport();
+		$transport->body = $body;
+		$transport->chunked = true;
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+
+		$this->assertEquals($transport->body, $response->body);
+	}
+
+
+	/**
+	 * Response says it's chunked and starts looking like it is, but turns out
+	 * that they're lying to us
+	 */
+	public function testMixedChunkiness() {
+		$transport = new MockTransport();
+		$transport->body = "02\r\nab\r\nNot actually chunked!";
+		$transport->chunked = true;
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+		$this->assertEquals($transport->body, $response->body);
+	}
+}

+ 642 - 0
api/vendor/rmccue/requests/tests/Cookies.php

@@ -0,0 +1,642 @@
+<?php
+
+class RequestsTest_Cookies extends PHPUnit_Framework_TestCase {
+	public function testBasicCookie() {
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue');
+
+		$this->assertEquals('requests-testcookie', $cookie->name);
+		$this->assertEquals('testvalue', $cookie->value);
+		$this->assertEquals('testvalue', (string) $cookie);
+
+		$this->assertEquals('requests-testcookie=testvalue', $cookie->format_for_header());
+		$this->assertEquals('requests-testcookie=testvalue', $cookie->format_for_set_cookie());
+	}
+
+	public function testCookieWithAttributes() {
+		$attributes = array(
+			'httponly',
+			'path' => '/'
+		);
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue', $attributes);
+
+		$this->assertEquals('requests-testcookie=testvalue', $cookie->format_for_header());
+		$this->assertEquals('requests-testcookie=testvalue; httponly; path=/', $cookie->format_for_set_cookie());
+	}
+
+	public function testEmptyCookieName() {
+		$cookie = Requests_Cookie::parse('test');
+		$this->assertEquals('', $cookie->name);
+		$this->assertEquals('test', $cookie->value);
+	}
+
+	public function testEmptyAttributes() {
+		$cookie = Requests_Cookie::parse('foo=bar; HttpOnly');
+		$this->assertTrue($cookie->attributes['httponly']);
+	}
+
+	public function testCookieJarSetter() {
+		$jar1 = new Requests_Cookie_Jar();
+		$jar1['requests-testcookie'] = 'testvalue';
+
+		$jar2 = new Requests_Cookie_Jar(array(
+			'requests-testcookie' => 'testvalue',
+		));
+		$this->assertEquals($jar1, $jar2);
+	}
+
+	public function testCookieJarUnsetter() {
+		$jar = new Requests_Cookie_Jar();
+		$jar['requests-testcookie'] = 'testvalue';
+
+		$this->assertEquals('testvalue', $jar['requests-testcookie']);
+
+		unset($jar['requests-testcookie']);
+		$this->assertEmpty($jar['requests-testcookie']);
+		$this->assertFalse(isset($jar['requests-testcookie']));
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testCookieJarAsList() {
+		$cookies = new Requests_Cookie_Jar();
+		$cookies[] = 'requests-testcookie1=testvalue1';
+	}
+
+	public function testCookieJarIterator() {
+		$cookies = array(
+			'requests-testcookie1' => 'testvalue1',
+			'requests-testcookie2' => 'testvalue2',
+		);
+		$jar = new Requests_Cookie_Jar($cookies);
+
+		foreach ($jar as $key => $value) {
+			$this->assertEquals($cookies[$key], $value);
+		}
+	}
+
+	public function testReceivingCookies() {
+		$options = array(
+			'follow_redirects' => false,
+		);
+		$url = httpbin('/cookies/set?requests-testcookie=testvalue');
+
+		$response = Requests::get($url, array(), $options);
+
+		$cookie = $response->cookies['requests-testcookie'];
+		$this->assertNotEmpty( $cookie );
+		$this->assertEquals( 'testvalue', $cookie->value );
+	}
+
+	public function testPersistenceOnRedirect() {
+		$options = array(
+			'follow_redirects' => true,
+		);
+		$url = httpbin('/cookies/set?requests-testcookie=testvalue');
+
+		$response = Requests::get($url, array(), $options);
+
+		$cookie = $response->cookies['requests-testcookie'];
+		$this->assertNotEmpty( $cookie );
+		$this->assertEquals( 'testvalue', $cookie->value );
+	}
+
+	protected function setCookieRequest($cookies) {
+		$options = array(
+			'cookies' => $cookies,
+		);
+		$response = Requests::get(httpbin('/cookies/set'), array(), $options);
+
+		$data = json_decode($response->body, true);
+		$this->assertInternalType('array', $data);
+		$this->assertArrayHasKey('cookies', $data);
+		return $data['cookies'];
+	}
+
+	public function testSendingCookie() {
+		$cookies = array(
+			'requests-testcookie1' => 'testvalue1',
+		);
+
+		$data = $this->setCookieRequest($cookies);
+
+		$this->assertArrayHasKey('requests-testcookie1', $data);
+		$this->assertEquals('testvalue1', $data['requests-testcookie1']);
+	}
+
+	/**
+	 * @depends testSendingCookie
+	 */
+	public function testCookieExpiration() {
+		$options = array(
+			'follow_redirects' => true,
+		);
+		$url = httpbin('/cookies/set/testcookie/testvalue');
+		$url .= '?expiry=1';
+
+		$response = Requests::get($url, array(), $options);
+		$response->throw_for_status();
+
+		$data = json_decode($response->body, true);
+		$this->assertEmpty($data['cookies']);
+	}
+
+	public function testSendingCookieWithJar() {
+		$cookies = new Requests_Cookie_Jar(array(
+			'requests-testcookie1' => 'testvalue1',
+		));
+		$data = $this->setCookieRequest($cookies);
+
+		$this->assertArrayHasKey('requests-testcookie1', $data);
+		$this->assertEquals('testvalue1', $data['requests-testcookie1']);
+	}
+
+	public function testSendingMultipleCookies() {
+		$cookies = array(
+			'requests-testcookie1' => 'testvalue1',
+			'requests-testcookie2' => 'testvalue2',
+		);
+		$data = $this->setCookieRequest($cookies);
+
+		$this->assertArrayHasKey('requests-testcookie1', $data);
+		$this->assertEquals('testvalue1', $data['requests-testcookie1']);
+
+		$this->assertArrayHasKey('requests-testcookie2', $data);
+		$this->assertEquals('testvalue2', $data['requests-testcookie2']);
+	}
+
+	public function testSendingMultipleCookiesWithJar() {
+		$cookies = new Requests_Cookie_Jar(array(
+			'requests-testcookie1' => 'testvalue1',
+			'requests-testcookie2' => 'testvalue2',
+		));
+		$data = $this->setCookieRequest($cookies);
+
+		$this->assertArrayHasKey('requests-testcookie1', $data);
+		$this->assertEquals('testvalue1', $data['requests-testcookie1']);
+
+		$this->assertArrayHasKey('requests-testcookie2', $data);
+		$this->assertEquals('testvalue2', $data['requests-testcookie2']);
+	}
+
+	public function testSendingPrebakedCookie() {
+		$cookies = new Requests_Cookie_Jar(array(
+			new Requests_Cookie('requests-testcookie', 'testvalue'),
+		));
+		$data = $this->setCookieRequest($cookies);
+
+		$this->assertArrayHasKey('requests-testcookie', $data);
+		$this->assertEquals('testvalue', $data['requests-testcookie']);
+	}
+
+	public function domainMatchProvider() {
+		return array(
+			array('example.com', 'example.com',     true,  true),
+			array('example.com', 'www.example.com', false, true),
+			array('example.com', 'example.net',     false, false),
+
+			// Leading period
+			array('.example.com', 'example.com',     true,  true),
+			array('.example.com', 'www.example.com', false, true),
+			array('.example.com', 'example.net',     false, false),
+
+			// Prefix, but not subdomain
+			array('example.com', 'notexample.com',  false, false),
+			array('example.com', 'notexample.net',  false, false),
+
+			// Reject IP address prefixes
+			array('127.0.0.1',   '127.0.0.1',     true, true),
+			array('127.0.0.1',   'abc.127.0.0.1', false, false),
+			array('127.0.0.1',   'example.com',   false, false),
+
+			// Check that we're checking the actual length
+			array('127.com', 'test.127.com', false, true),
+		);
+	}
+
+	/**
+	 * @dataProvider domainMatchProvider
+	 */
+	public function testDomainExactMatch($original, $check, $matches, $domain_matches) {
+		$attributes = new Requests_Utility_CaseInsensitiveDictionary();
+		$attributes['domain'] = $original;
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue', $attributes);
+		$this->assertEquals($matches, $cookie->domain_matches($check));
+	}
+
+	/**
+	 * @dataProvider domainMatchProvider
+	 */
+	public function testDomainMatch($original, $check, $matches, $domain_matches) {
+		$attributes = new Requests_Utility_CaseInsensitiveDictionary();
+		$attributes['domain'] = $original;
+		$flags = array(
+			'host-only' => false
+		);
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue', $attributes, $flags);
+		$this->assertEquals($domain_matches, $cookie->domain_matches($check));
+	}
+
+	public function pathMatchProvider() {
+		return array(
+			array('/',      '',       true),
+			array('/',      '/',      true),
+
+			array('/',      '/test',  true),
+			array('/',      '/test/', true),
+
+			array('/test',  '/',          false),
+			array('/test',  '/test',      true),
+			array('/test',  '/testing',   false),
+			array('/test',  '/test/',     true),
+			array('/test',  '/test/ing',  true),
+			array('/test',  '/test/ing/', true),
+
+			array('/test/', '/test/', true),
+			array('/test/', '/',      false),
+		);
+	}
+
+	/**
+	 * @dataProvider pathMatchProvider
+	 */
+	public function testPathMatch($original, $check, $matches) {
+		$attributes = new Requests_Utility_CaseInsensitiveDictionary();
+		$attributes['path'] = $original;
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue', $attributes);
+		$this->assertEquals($matches, $cookie->path_matches($check));
+	}
+
+	public function urlMatchProvider() {
+		return array(
+			// Domain handling
+			array( 'example.com', '/', 'http://example.com/',     true,  true ),
+			array( 'example.com', '/', 'http://www.example.com/', false, true ),
+			array( 'example.com', '/', 'http://example.net/',     false, false ),
+			array( 'example.com', '/', 'http://www.example.net/', false, false ),
+
+			// /test
+			array( 'example.com', '/test', 'http://example.com/',            false, false ),
+			array( 'example.com', '/test', 'http://www.example.com/',        false, false ),
+
+			array( 'example.com', '/test', 'http://example.com/test',        true,  true ),
+			array( 'example.com', '/test', 'http://www.example.com/test',    false, true ),
+
+			array( 'example.com', '/test', 'http://example.com/testing',     false, false ),
+			array( 'example.com', '/test', 'http://www.example.com/testing', false, false ),
+
+			array( 'example.com', '/test', 'http://example.com/test/',       true,  true ),
+			array( 'example.com', '/test', 'http://www.example.com/test/',   false, true ),
+
+			// /test/
+			array( 'example.com', '/test/', 'http://example.com/',     false, false ),
+			array( 'example.com', '/test/', 'http://www.example.com/', false, false ),
+		);
+	}
+
+	/**
+	 * @depends testDomainExactMatch
+	 * @depends testPathMatch
+	 * @dataProvider urlMatchProvider
+	 */
+	public function testUrlExactMatch($domain, $path, $check, $matches, $domain_matches) {
+		$attributes = new Requests_Utility_CaseInsensitiveDictionary();
+		$attributes['domain'] = $domain;
+		$attributes['path']   = $path;
+		$check = new Requests_IRI($check);
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue', $attributes);
+		$this->assertEquals($matches, $cookie->uri_matches($check));
+	}
+
+	/**
+	 * @depends testDomainMatch
+	 * @depends testPathMatch
+	 * @dataProvider urlMatchProvider
+	 */
+	public function testUrlMatch($domain, $path, $check, $matches, $domain_matches) {
+		$attributes = new Requests_Utility_CaseInsensitiveDictionary();
+		$attributes['domain'] = $domain;
+		$attributes['path']   = $path;
+		$flags = array(
+			'host-only' => false
+		);
+		$check = new Requests_IRI($check);
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue', $attributes, $flags);
+		$this->assertEquals($domain_matches, $cookie->uri_matches($check));
+	}
+
+	public function testUrlMatchSecure() {
+		$attributes = new Requests_Utility_CaseInsensitiveDictionary();
+		$attributes['domain'] = 'example.com';
+		$attributes['path']   = '/';
+		$attributes['secure'] = true;
+		$flags = array(
+			'host-only' => false,
+		);
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue', $attributes, $flags);
+
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('https://example.com/')));
+		$this->assertFalse($cookie->uri_matches(new Requests_IRI('http://example.com/')));
+
+		// Double-check host-only
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('https://www.example.com/')));
+		$this->assertFalse($cookie->uri_matches(new Requests_IRI('http://www.example.com/')));
+	}
+
+	/**
+	 * Manually set cookies without a domain/path set should always be valid
+	 *
+	 * Cookies parsed from headers internally in Requests will always have a
+	 * domain/path set, but those created manually will not. Manual cookies
+	 * should be regarded as "global" cookies (that is, set for `.`)
+	 */
+	public function testUrlMatchManuallySet() {
+		$cookie = new Requests_Cookie('requests-testcookie', 'testvalue');
+		$this->assertTrue($cookie->domain_matches('example.com'));
+		$this->assertTrue($cookie->domain_matches('example.net'));
+		$this->assertTrue($cookie->path_matches('/'));
+		$this->assertTrue($cookie->path_matches('/test'));
+		$this->assertTrue($cookie->path_matches('/test/'));
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('http://example.com/')));
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('http://example.com/test')));
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('http://example.com/test/')));
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('http://example.net/')));
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('http://example.net/test')));
+		$this->assertTrue($cookie->uri_matches(new Requests_IRI('http://example.net/test/')));
+	}
+
+	public static function parseResultProvider() {
+		return array(
+			// Basic parsing
+			array(
+				'foo=bar',
+				array( 'name' => 'foo', 'value' => 'bar' ),
+			),
+			array(
+				'bar',
+				array( 'name' => '', 'value' => 'bar' ),
+			),
+
+			// Expiration
+			// RFC 822, updated by RFC 1123
+			array(
+				'foo=bar; Expires=Thu, 5-Dec-2013 04:50:12 GMT',
+				array( 'expired' => true ),
+				array( 'expires' => gmmktime( 4, 50, 12, 12, 5, 2013 ) ),
+			),
+			array(
+				'foo=bar; Expires=Fri, 5-Dec-2014 04:50:12 GMT',
+				array( 'expired' => false ),
+				array( 'expires' => gmmktime( 4, 50, 12, 12, 5, 2014 ) ),
+			),
+			// RFC 850, obsoleted by RFC 1036
+			array(
+				'foo=bar; Expires=Thursday, 5-Dec-2013 04:50:12 GMT',
+				array( 'expired' => true ),
+				array( 'expires' => gmmktime( 4, 50, 12, 12, 5, 2013 ) ),
+			),
+			array(
+				'foo=bar; Expires=Friday, 5-Dec-2014 04:50:12 GMT',
+				array( 'expired' => false ),
+				array( 'expires' => gmmktime( 4, 50, 12, 12, 5, 2014 ) ),
+			),
+			// asctime()
+			array(
+				'foo=bar; Expires=Thu Dec  5 04:50:12 2013',
+				array( 'expired' => true ),
+				array( 'expires' => gmmktime( 4, 50, 12, 12, 5, 2013 ) ),
+			),
+			array(
+				'foo=bar; Expires=Fri Dec  5 04:50:12 2014',
+				array( 'expired' => false ),
+				array( 'expires' => gmmktime( 4, 50, 12, 12, 5, 2014 ) ),
+			),
+			array(
+				// Invalid
+				'foo=bar; Expires=never',
+				array(),
+				array( 'expires' => null ),
+			),
+
+			// Max-Age
+			array(
+				'foo=bar; Max-Age=10',
+				array( 'expired' => false ),
+				array( 'max-age' => gmmktime( 0, 0, 10, 1, 1, 2014 ) ),
+			),
+			array(
+				'foo=bar; Max-Age=3660',
+				array( 'expired' => false ),
+				array( 'max-age' => gmmktime( 1, 1, 0, 1, 1, 2014 ) ),
+			),
+			array(
+				'foo=bar; Max-Age=0',
+				array( 'expired' => true ),
+				array( 'max-age' => 0 ),
+			),
+			array(
+				'foo=bar; Max-Age=-1000',
+				array( 'expired' => true ),
+				array( 'max-age' => 0 ),
+			),
+			array(
+				// Invalid (non-digit character)
+				'foo=bar; Max-Age=1e6',
+				array( 'expired' => false ),
+				array( 'max-age' => null ),
+			)
+		);
+	}
+
+	protected function check_parsed_cookie($cookie, $expected, $expected_attributes, $expected_flags = array()) {
+		if (isset($expected['name'])) {
+			$this->assertEquals($expected['name'], $cookie->name);
+		}
+		if (isset($expected['value'])) {
+			$this->assertEquals($expected['value'], $cookie->value);
+		}
+		if (isset($expected['expired'])) {
+			$this->assertEquals($expected['expired'], $cookie->is_expired());
+		}
+		if (isset($expected_attributes)) {
+			foreach ($expected_attributes as $attr_key => $attr_val) {
+				$this->assertEquals($attr_val, $cookie->attributes[$attr_key], "$attr_key should match supplied");
+			}
+		}
+		if (isset($expected_flags)) {
+			foreach ($expected_flags as $flag_key => $flag_val) {
+				$this->assertEquals($flag_val, $cookie->flags[$flag_key], "$flag_key should match supplied");
+			}
+		}
+	}
+
+	/**
+	 * @dataProvider parseResultProvider
+	 */
+	public function testParsingHeader($header, $expected, $expected_attributes = array(), $expected_flags = array()) {
+		// Set the reference time to 2014-01-01 00:00:00
+		$reference_time = gmmktime( 0, 0, 0, 1, 1, 2014 );
+
+		$cookie = Requests_Cookie::parse($header, null, $reference_time);
+		$this->check_parsed_cookie($cookie, $expected, $expected_attributes);
+	}
+
+	/**
+	 * Double-normalizes the cookie data to ensure we catch any issues there
+	 *
+	 * @dataProvider parseResultProvider
+	 */
+	public function testParsingHeaderDouble($header, $expected, $expected_attributes = array(), $expected_flags = array()) {
+		// Set the reference time to 2014-01-01 00:00:00
+		$reference_time = gmmktime( 0, 0, 0, 1, 1, 2014 );
+
+		$cookie = Requests_Cookie::parse($header, null, $reference_time);
+
+		// Normalize the value again
+		$cookie->normalize();
+
+		$this->check_parsed_cookie($cookie, $expected, $expected_attributes, $expected_flags);
+	}
+
+	/**
+	 * @dataProvider parseResultProvider
+	 */
+	public function testParsingHeaderObject($header, $expected, $expected_attributes = array(), $expected_flags = array()) {
+		$headers = new Requests_Response_Headers();
+		$headers['Set-Cookie'] = $header;
+
+		// Set the reference time to 2014-01-01 00:00:00
+		$reference_time = gmmktime( 0, 0, 0, 1, 1, 2014 );
+
+		$parsed = Requests_Cookie::parse_from_headers($headers, null, $reference_time);
+		$this->assertCount(1, $parsed);
+
+		$cookie = reset($parsed);
+		$this->check_parsed_cookie($cookie, $expected, $expected_attributes);
+	}
+
+	public function parseFromHeadersProvider() {
+		return array(
+			# Varying origin path
+			array(
+				'name=value',
+				'http://example.com/',
+				array(),
+				array( 'path' => '/' ),
+				array( 'host-only' => true ),
+			),
+			array(
+				'name=value',
+				'http://example.com/test',
+				array(),
+				array( 'path' => '/' ),
+				array( 'host-only' => true ),
+			),
+			array(
+				'name=value',
+				'http://example.com/test/',
+				array(),
+				array( 'path' => '/test' ),
+				array( 'host-only' => true ),
+			),
+			array(
+				'name=value',
+				'http://example.com/test/abc',
+				array(),
+				array( 'path' => '/test' ),
+				array( 'host-only' => true ),
+			),
+			array(
+				'name=value',
+				'http://example.com/test/abc/',
+				array(),
+				array( 'path' => '/test/abc' ),
+				array( 'host-only' => true ),
+			),
+
+			# With specified path
+			array(
+				'name=value; path=/',
+				'http://example.com/',
+				array(),
+				array( 'path' => '/' ),
+				array( 'host-only' => true ),
+			),
+			array(
+				'name=value; path=/test',
+				'http://example.com/',
+				array(),
+				array( 'path' => '/test' ),
+				array( 'host-only' => true ),
+			),
+			array(
+				'name=value; path=/test/',
+				'http://example.com/',
+				array(),
+				array( 'path' => '/test/' ),
+				array( 'host-only' => true ),
+			),
+
+			# Invalid path
+			array(
+				'name=value; path=yolo',
+				'http://example.com/',
+				array(),
+				array( 'path' => '/' ),
+				array( 'host-only' => true ),
+			),
+			array(
+				'name=value; path=yolo',
+				'http://example.com/test/',
+				array(),
+				array( 'path' => '/test' ),
+				array( 'host-only' => true ),
+			),
+
+			# Cross-origin cookies, reject!
+			array(
+				'name=value; domain=example.org',
+				'http://example.com/',
+				array( 'invalid' => false ),
+			),
+
+			# Subdomain cookies
+			array(
+				'name=value; domain=test.example.com',
+				'http://test.example.com/',
+				array(),
+				array( 'domain' => 'test.example.com' ),
+				array( 'host-only' => false )
+			),
+			array(
+				'name=value; domain=example.com',
+				'http://test.example.com/',
+				array(),
+				array( 'domain' => 'example.com' ),
+				array( 'host-only' => false )
+			),
+		);
+	}
+
+	/**
+	 * @dataProvider parseFromHeadersProvider
+	 */
+	public function testParsingHeaderWithOrigin($header, $origin, $expected, $expected_attributes = array(), $expected_flags = array()) {
+		$origin = new Requests_IRI($origin);
+		$headers = new Requests_Response_Headers();
+		$headers['Set-Cookie'] = $header;
+
+		// Set the reference time to 2014-01-01 00:00:00
+		$reference_time = gmmktime( 0, 0, 0, 1, 1, 2014 );
+
+		$parsed = Requests_Cookie::parse_from_headers($headers, $origin, $reference_time);
+		if (isset($expected['invalid'])) {
+			$this->assertCount(0, $parsed);
+			return;
+		}
+		$this->assertCount(1, $parsed);
+
+		$cookie = reset($parsed);
+		$this->check_parsed_cookie($cookie, $expected, $expected_attributes, $expected_flags);
+	}
+}

+ 94 - 0
api/vendor/rmccue/requests/tests/Encoding.php

@@ -0,0 +1,94 @@
+<?php
+
+class RequestsTests_Encoding extends PHPUnit_Framework_TestCase {
+	protected static function mapData($type, $data) {
+		$real_data = array();
+		foreach ($data as $value) {
+			$key = $type . ': ' . $value[0];
+			$real_data[$key] = $value;
+		}
+		return $real_data;
+	}
+
+	public static function gzipData() {
+		return array(
+			array(
+				'foobar',
+				"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x4b\xcb\xcf\x4f\x4a"
+				. "\x2c\x02\x00\x95\x1f\xf6\x9e\x06\x00\x00\x00",
+			),
+			array(
+				'Requests for PHP',
+				"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x0b\x4a\x2d\x2c\x4d"
+				. "\x2d\x2e\x29\x56\x48\xcb\x2f\x52\x08\xf0\x08\x00\x00\x58\x35"
+				. "\x18\x17\x10\x00\x00\x00",
+			),
+		);
+	}
+
+	public static function deflateData() {
+		return array(
+			array(
+				'foobar',
+				"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x78\x9c\x4b\xcb\xcf"
+				. "\x4f\x4a\x2c\x02\x00\x08\xab\x02\x7a"
+			),
+			array(
+				'Requests for PHP',
+				"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x78\x9c\x0b\x4a\x2d"
+				. "\x2c\x4d\x2d\x2e\x29\x56\x48\xcb\x2f\x52\x08\xf0\x08\x00\x00"
+				. "\x34\x68\x05\xcc"
+			)
+		);
+	}
+	public static function deflateWithoutHeadersData() {
+		return array(
+			array(
+				'foobar',
+				"\x78\x9c\x4b\xcb\xcf\x4f\x4a\x2c\x02\x00\x08\xab\x02\x7a"
+			),
+			array(
+				'Requests for PHP',
+				"\x78\x9c\x0b\x4a\x2d\x2c\x4d\x2d\x2e\x29\x56\x48\xcb\x2f\x52"
+				. "\x08\xf0\x08\x00\x00\x34\x68\x05\xcc"
+			)
+		);
+	}
+
+	public static function encodedData() {
+		$datasets = array();
+		$datasets['gzip'] = self::gzipData();
+		$datasets['deflate'] = self::deflateData();
+		$datasets['deflate without zlib headers'] = self::deflateWithoutHeadersData();
+
+		$data = array();
+		foreach ($datasets as $key => $set) {
+			$real_set = self::mapData($key, $set);
+			$data = array_merge($data, $real_set);
+		}
+		return $data;
+	}
+
+	/**
+	 * @dataProvider encodedData
+	 */
+	public function testDecompress($original, $encoded) {
+		$decoded = Requests::decompress($encoded);
+		$this->assertEquals($original, $decoded);
+	}
+
+	/**
+	 * @dataProvider encodedData
+	 */
+	public function testCompatibleInflate($original, $encoded) {
+		$decoded = Requests::compatible_gzinflate($encoded);
+		$this->assertEquals($original, $decoded);
+	}
+
+	protected function bin2hex($field) {
+		$field = bin2hex($field);
+		$field = chunk_split($field,2,"\\x");
+		$field = "\\x" . substr($field,0,-2);
+		return $field;
+	}
+}

+ 102 - 0
api/vendor/rmccue/requests/tests/IDNAEncoder.php

@@ -0,0 +1,102 @@
+<?php
+
+class RequestsTest_IDNAEncoder extends PHPUnit_Framework_TestCase {
+	public static function specExamples() {
+		return array(
+			array(
+				"\xe4\xbb\x96\xe4\xbb\xac\xe4\xb8\xba\xe4\xbb\x80\xe4\xb9\x88\xe4\xb8\x8d\xe8\xaf\xb4\xe4\xb8\xad\xe6\x96\x87",
+				"xn--ihqwcrb4cv8a8dqg056pqjye"
+			),
+			array(
+				"\x33\xe5\xb9\xb4\x42\xe7\xb5\x84\xe9\x87\x91\xe5\x85\xab\xe5\x85\x88\xe7\x94\x9f",
+				"xn--3B-ww4c5e180e575a65lsy2b",
+			)
+		);
+	}
+
+	/**
+	 * @dataProvider specExamples
+	 */
+	public function testEncoding($data, $expected) {
+		$result = Requests_IDNAEncoder::encode($data);
+		$this->assertEquals($expected, $result);
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testASCIITooLong() {
+		$data = str_repeat("abcd", 20);
+		$result = Requests_IDNAEncoder::encode($data);
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testEncodedTooLong() {
+		$data = str_repeat("\xe4\xbb\x96", 60);
+		$result = Requests_IDNAEncoder::encode($data);
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testAlreadyPrefixed() {
+		$result = Requests_IDNAEncoder::encode("xn--\xe4\xbb\x96");
+	}
+
+	public function testASCIICharacter() {
+		$result = Requests_IDNAEncoder::encode("a");
+		$this->assertEquals('a', $result);
+	}
+
+	public function testTwoByteCharacter() {
+		$result = Requests_IDNAEncoder::encode("\xc2\xb6"); // Pilcrow character
+		$this->assertEquals('xn--tba', $result);
+	}
+
+	public function testThreeByteCharacter() {
+		$result = Requests_IDNAEncoder::encode("\xe2\x82\xac"); // Euro symbol
+		$this->assertEquals('xn--lzg', $result);
+	}
+
+	public function testFourByteCharacter() {
+		$result = Requests_IDNAEncoder::encode("\xf0\xa4\xad\xa2"); // Chinese symbol?
+		$this->assertEquals('xn--ww6j', $result);
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testFiveByteCharacter() {
+		$result = Requests_IDNAEncoder::encode("\xfb\xb6\xb6\xb6\xb6");
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testSixByteCharacter() {
+		$result = Requests_IDNAEncoder::encode("\xfd\xb6\xb6\xb6\xb6\xb6");
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testInvalidASCIICharacterWithMultibyte() {
+		$result = Requests_IDNAEncoder::encode("\0\xc2\xb6");
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testUnfinishedMultibyte() {
+		$result = Requests_IDNAEncoder::encode("\xc2");
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testPartialMultibyte() {
+		$result = Requests_IDNAEncoder::encode("\xc2\xc2\xb6");
+	}
+}

+ 413 - 0
api/vendor/rmccue/requests/tests/IRI.php

@@ -0,0 +1,413 @@
+<?php
+
+/**
+ * IRI test cases
+ *
+ * Copyright (c) 2008-2010 Geoffrey Sneddon.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 	* Redistributions of source code must retain the above copyright notice,
+ *	  this list of conditions and the following disclaimer.
+ *
+ * 	* Redistributions in binary form must reproduce the above copyright notice,
+ *	  this list of conditions and the following disclaimer in the documentation
+ *	  and/or other materials provided with the distribution.
+ *
+ * 	* Neither the name of the SimplePie Team nor the names of its contributors
+ *	  may be used to endorse or promote products derived from this software
+ *	  without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package IRI
+ * @author Geoffrey Sneddon
+ * @copyright 2008-2010 Geoffrey Sneddon
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @link http://hg.gsnedders.com/iri/
+ *
+ */
+
+class RequestsTest_IRI extends PHPUnit_Framework_TestCase
+{
+	public static function rfc3986_tests()
+	{
+		return array(
+			// Normal
+			array('g:h', 'g:h'),
+			array('g', 'http://a/b/c/g'),
+			array('./g', 'http://a/b/c/g'),
+			array('g/', 'http://a/b/c/g/'),
+			array('/g', 'http://a/g'),
+			array('//g', 'http://g/'),
+			array('?y', 'http://a/b/c/d;p?y'),
+			array('g?y', 'http://a/b/c/g?y'),
+			array('#s', 'http://a/b/c/d;p?q#s'),
+			array('g#s', 'http://a/b/c/g#s'),
+			array('g?y#s', 'http://a/b/c/g?y#s'),
+			array(';x', 'http://a/b/c/;x'),
+			array('g;x', 'http://a/b/c/g;x'),
+			array('g;x?y#s', 'http://a/b/c/g;x?y#s'),
+			array('', 'http://a/b/c/d;p?q'),
+			array('.', 'http://a/b/c/'),
+			array('./', 'http://a/b/c/'),
+			array('..', 'http://a/b/'),
+			array('../', 'http://a/b/'),
+			array('../g', 'http://a/b/g'),
+			array('../..', 'http://a/'),
+			array('../../', 'http://a/'),
+			array('../../g', 'http://a/g'),
+			// Abnormal
+			array('../../../g', 'http://a/g'),
+			array('../../../../g', 'http://a/g'),
+			array('/./g', 'http://a/g'),
+			array('/../g', 'http://a/g'),
+			array('g.', 'http://a/b/c/g.'),
+			array('.g', 'http://a/b/c/.g'),
+			array('g..', 'http://a/b/c/g..'),
+			array('..g', 'http://a/b/c/..g'),
+			array('./../g', 'http://a/b/g'),
+			array('./g/.', 'http://a/b/c/g/'),
+			array('g/./h', 'http://a/b/c/g/h'),
+			array('g/../h', 'http://a/b/c/h'),
+			array('g;x=1/./y', 'http://a/b/c/g;x=1/y'),
+			array('g;x=1/../y', 'http://a/b/c/y'),
+			array('g?y/./x', 'http://a/b/c/g?y/./x'),
+			array('g?y/../x', 'http://a/b/c/g?y/../x'),
+			array('g#s/./x', 'http://a/b/c/g#s/./x'),
+			array('g#s/../x', 'http://a/b/c/g#s/../x'),
+			array('http:g', 'http:g'),
+		);
+	}
+
+	/**
+	 * @dataProvider rfc3986_tests
+	 */
+	public function testStringRFC3986($relative, $expected)
+	{
+		$base = new Requests_IRI('http://a/b/c/d;p?q');
+		$this->assertEquals($expected, Requests_IRI::absolutize($base, $relative)->iri);
+		$this->assertEquals($expected, (string) Requests_IRI::absolutize($base, $relative));
+	}
+
+	/**
+	 * @dataProvider rfc3986_tests
+	 */
+	public function testBothStringRFC3986($relative, $expected)
+	{
+		$base = 'http://a/b/c/d;p?q';
+		$this->assertEquals($expected, Requests_IRI::absolutize($base, $relative)->iri);
+		$this->assertEquals($expected, (string) Requests_IRI::absolutize($base, $relative));
+	}
+
+	/**
+	 * @dataProvider rfc3986_tests
+	 */
+	public function testObjectRFC3986($relative, $expected)
+	{
+		$base = new Requests_IRI('http://a/b/c/d;p?q');
+		$expected = new Requests_IRI($expected);
+		$this->assertEquals($expected, Requests_IRI::absolutize($base, $relative));
+	}
+
+	public static function sp_tests()
+	{
+		return array(
+			array('http://a/b/c/d', 'f%0o', 'http://a/b/c/f%250o'),
+			array('http://a/b/', 'c', 'http://a/b/c'),
+			array('http://a/', 'b', 'http://a/b'),
+			array('http://a/', '/b', 'http://a/b'),
+			array('http://a/b', 'c', 'http://a/c'),
+			array('http://a/b/', "c\x0Ad", 'http://a/b/c%0Ad'),
+			array('http://a/b/', "c\x0A\x0B", 'http://a/b/c%0A%0B'),
+			array('http://a/b/c', '//0', 'http://0/'),
+			array('http://a/b/c', '0', 'http://a/b/0'),
+			array('http://a/b/c', '?0', 'http://a/b/c?0'),
+			array('http://a/b/c', '#0', 'http://a/b/c#0'),
+			array('http://0/b/c', 'd', 'http://0/b/d'),
+			array('http://a/b/c?0', 'd', 'http://a/b/d'),
+			array('http://a/b/c#0', 'd', 'http://a/b/d'),
+			array('http://example.com', '//example.net', 'http://example.net/'),
+			array('http:g', 'a', 'http:a'),
+		);
+	}
+
+	/**
+	 * @dataProvider sp_tests
+	 */
+	public function testStringSP($base, $relative, $expected)
+	{
+		$base = new Requests_IRI($base);
+		$this->assertEquals($expected, Requests_IRI::absolutize($base, $relative)->iri);
+		$this->assertEquals($expected, (string) Requests_IRI::absolutize($base, $relative));
+	}
+
+	/**
+	 * @dataProvider sp_tests
+	 */
+	public function testObjectSP($base, $relative, $expected)
+	{
+		$base = new Requests_IRI($base);
+		$expected = new Requests_IRI($expected);
+		$this->assertEquals($expected, Requests_IRI::absolutize($base, $relative));
+	}
+
+	public static function absolutize_tests()
+	{
+		return array(
+			array('http://example.com/', 'foo/111:bar', 'http://example.com/foo/111:bar'),
+			array('http://example.com/#foo', '', 'http://example.com/'),
+		);
+	}
+
+	/**
+	 * @dataProvider absolutize_tests
+	 */
+	public function testAbsolutizeString($base, $relative, $expected)
+	{
+		$base = new Requests_IRI($base);
+		$this->assertEquals($expected, Requests_IRI::absolutize($base, $relative)->iri);
+	}
+
+	/**
+	 * @dataProvider absolutize_tests
+	 */
+	public function testAbsolutizeObject($base, $relative, $expected)
+	{
+		$base = new Requests_IRI($base);
+		$expected = new Requests_IRI($expected);
+		$this->assertEquals($expected, Requests_IRI::absolutize($base, $relative));
+	}
+
+	public static function normalization_tests()
+	{
+		return array(
+			array('example://a/b/c/%7Bfoo%7D', 'example://a/b/c/%7Bfoo%7D'),
+			array('eXAMPLE://a/./b/../b/%63/%7bfoo%7d', 'example://a/b/c/%7Bfoo%7D'),
+			array('example://%61/', 'example://a/'),
+			array('example://%41/', 'example://a/'),
+			array('example://A/', 'example://a/'),
+			array('example://a/', 'example://a/'),
+			array('example://%25A/', 'example://%25a/'),
+			array('HTTP://EXAMPLE.com/', 'http://example.com/'),
+			array('http://example.com/', 'http://example.com/'),
+			array('http://example.com:', 'http://example.com/'),
+			array('http://example.com:80', 'http://example.com/'),
+			array('http://@example.com', 'http://@example.com/'),
+			array('http://', 'http:///'),
+			array('http://example.com?', 'http://example.com/?'),
+			array('http://example.com#', 'http://example.com/#'),
+			array('https://example.com/', 'https://example.com/'),
+			array('https://example.com:', 'https://example.com/'),
+			array('https://@example.com', 'https://@example.com/'),
+			array('https://example.com?', 'https://example.com/?'),
+			array('https://example.com#', 'https://example.com/#'),
+			array('file://localhost/foobar', 'file:/foobar'),
+			array('http://[0:0:0:0:0:0:0:1]', 'http://[::1]/'),
+			array('http://[2001:db8:85a3:0000:0000:8a2e:370:7334]', 'http://[2001:db8:85a3::8a2e:370:7334]/'),
+			array('http://[0:0:0:0:0:ffff:c0a8:a01]', 'http://[::ffff:c0a8:a01]/'),
+			array('http://[ffff:0:0:0:0:0:0:0]', 'http://[ffff::]/'),
+			array('http://[::ffff:192.0.2.128]', 'http://[::ffff:192.0.2.128]/'),
+			array('http://[invalid]', 'http:'),
+			array('http://[0:0:0:0:0:0:0:1]:', 'http://[::1]/'),
+			array('http://[0:0:0:0:0:0:0:1]:80', 'http://[::1]/'),
+			array('http://[0:0:0:0:0:0:0:1]:1234', 'http://[::1]:1234/'),
+			// Punycode decoding helps with normalisation of IRIs, but is not
+			// needed for URIs, so we don't really care about it for Requests
+			//array('http://xn--tdali-d8a8w.lv', 'http://tūdaliņ.lv/'),
+			//array('http://t%C5%ABdali%C5%86.lv', 'http://tūdaliņ.lv/'),
+			array('http://Aa@example.com', 'http://Aa@example.com/'),
+			array('http://example.com?Aa', 'http://example.com/?Aa'),
+			array('http://example.com/Aa', 'http://example.com/Aa'),
+			array('http://example.com#Aa', 'http://example.com/#Aa'),
+			array('http://[0:0:0:0:0:0:0:0]', 'http://[::]/'),
+			array('http:.', 'http:'),
+			array('http:..', 'http:'),
+			array('http:./', 'http:'),
+			array('http:../', 'http:'),
+			array('http://example.com/%3A', 'http://example.com/%3A'),
+			array('http://example.com/:', 'http://example.com/:'),
+			array('http://example.com/%C2', 'http://example.com/%C2'),
+			array('http://example.com/%C2a', 'http://example.com/%C2a'),
+			array('http://example.com/%C2%00', 'http://example.com/%C2%00'),
+			array('http://example.com/%C3%A9', 'http://example.com/é'),
+			array('http://example.com/%C3%A9%00', 'http://example.com/é%00'),
+			array('http://example.com/%C3%A9cole', 'http://example.com/école'),
+			array('http://example.com/%FF', 'http://example.com/%FF'),
+			array("http://example.com/\xF3\xB0\x80\x80", 'http://example.com/%F3%B0%80%80'),
+			array("http://example.com/\xF3\xB0\x80\x80%00", 'http://example.com/%F3%B0%80%80%00'),
+			array("http://example.com/\xF3\xB0\x80\x80a", 'http://example.com/%F3%B0%80%80a'),
+			array("http://example.com?\xF3\xB0\x80\x80", "http://example.com/?\xF3\xB0\x80\x80"),
+			array("http://example.com?\xF3\xB0\x80\x80%00", "http://example.com/?\xF3\xB0\x80\x80%00"),
+			array("http://example.com?\xF3\xB0\x80\x80a", "http://example.com/?\xF3\xB0\x80\x80a"),
+			array("http://example.com/\xEE\x80\x80", 'http://example.com/%EE%80%80'),
+			array("http://example.com/\xEE\x80\x80%00", 'http://example.com/%EE%80%80%00'),
+			array("http://example.com/\xEE\x80\x80a", 'http://example.com/%EE%80%80a'),
+			array("http://example.com?\xEE\x80\x80", "http://example.com/?\xEE\x80\x80"),
+			array("http://example.com?\xEE\x80\x80%00", "http://example.com/?\xEE\x80\x80%00"),
+			array("http://example.com?\xEE\x80\x80a", "http://example.com/?\xEE\x80\x80a"),
+			array("http://example.com/\xC2", 'http://example.com/%C2'),
+			array("http://example.com/\xC2a", 'http://example.com/%C2a'),
+			array("http://example.com/\xC2\x00", 'http://example.com/%C2%00'),
+			array("http://example.com/\xC3\xA9", 'http://example.com/é'),
+			array("http://example.com/\xC3\xA9\x00", 'http://example.com/é%00'),
+			array("http://example.com/\xC3\xA9cole", 'http://example.com/école'),
+			array("http://example.com/\xFF", 'http://example.com/%FF'),
+			array("http://example.com/\xFF%00", 'http://example.com/%FF%00'),
+			array("http://example.com/\xFFa", 'http://example.com/%FFa'),
+			array('http://example.com/%61', 'http://example.com/a'),
+			array('http://example.com?%26', 'http://example.com/?%26'),
+			array('http://example.com?%61', 'http://example.com/?a'),
+			array('///', '///'),
+		);
+	}
+
+	/**
+	 * @dataProvider normalization_tests
+	 */
+	public function testStringNormalization($input, $output)
+	{
+		$input = new Requests_IRI($input);
+		$this->assertEquals($output, $input->iri);
+		$this->assertEquals($output, (string) $input);
+	}
+
+	/**
+	 * @dataProvider normalization_tests
+	 */
+	public function testObjectNormalization($input, $output)
+	{
+		$input = new Requests_IRI($input);
+		$output = new Requests_IRI($output);
+		$this->assertEquals($output, $input);
+	}
+
+	public static function equivalence_tests()
+	{
+		return array(
+			array('http://É.com', 'http://%C3%89.com'),
+		);
+	}
+
+	/**
+	 * @dataProvider equivalence_tests
+	 */
+	public function testObjectEquivalence($input, $output)
+	{
+		$input = new Requests_IRI($input);
+		$output = new Requests_IRI($output);
+		$this->assertEquals($output, $input);
+	}
+
+	public static function not_equivalence_tests()
+	{
+		return array(
+			array('http://example.com/foo/bar', 'http://example.com/foo%2Fbar'),
+		);
+	}
+
+	/**
+	 * @dataProvider not_equivalence_tests
+	 */
+	public function testObjectNotEquivalence($input, $output)
+	{
+		$input = new Requests_IRI($input);
+		$output = new Requests_IRI($output);
+		$this->assertNotEquals($output, $input);
+	}
+
+	public function testInvalidAbsolutizeBase()
+	{
+		$this->assertFalse(Requests_IRI::absolutize('://not a URL', '../'));
+	}
+
+	public function testFullGamut()
+	{
+		$iri = new Requests_IRI();
+		$iri->scheme = 'http';
+		$iri->userinfo = 'user:password';
+		$iri->host = 'example.com';
+		$iri->path = '/test/';
+		$iri->fragment = 'test';
+
+		$this->assertEquals('http', $iri->scheme);
+		$this->assertEquals('user:password', $iri->userinfo);
+		$this->assertEquals('example.com', $iri->host);
+		$this->assertEquals(80, $iri->port);
+		$this->assertEquals('/test/', $iri->path);
+		$this->assertEquals('test', $iri->fragment);
+	}
+
+	public function testReadAliased()
+	{
+		$iri = new Requests_IRI();
+		$iri->scheme = 'http';
+		$iri->userinfo = 'user:password';
+		$iri->host = 'example.com';
+		$iri->path = '/test/';
+		$iri->fragment = 'test';
+
+		$this->assertEquals('http', $iri->ischeme);
+		$this->assertEquals('user:password', $iri->iuserinfo);
+		$this->assertEquals('example.com', $iri->ihost);
+		$this->assertEquals(80, $iri->iport);
+		$this->assertEquals('/test/', $iri->ipath);
+		$this->assertEquals('test', $iri->ifragment);
+	}
+
+	public function testWriteAliased()
+	{
+		$iri = new Requests_IRI();
+		$iri->scheme = 'http';
+		$iri->iuserinfo = 'user:password';
+		$iri->ihost = 'example.com';
+		$iri->ipath = '/test/';
+		$iri->ifragment = 'test';
+
+		$this->assertEquals('http', $iri->scheme);
+		$this->assertEquals('user:password', $iri->userinfo);
+		$this->assertEquals('example.com', $iri->host);
+		$this->assertEquals(80, $iri->port);
+		$this->assertEquals('/test/', $iri->path);
+		$this->assertEquals('test', $iri->fragment);
+	}
+
+	/**
+	 * @expectedException PHPUnit_Framework_Error_Notice
+	 */
+	public function testNonexistantProperty()
+	{
+		$iri = new Requests_IRI();
+		$this->assertFalse(isset($iri->nonexistant_prop));
+		$should_fail = $iri->nonexistant_prop;
+	}
+
+	public function testBlankHost()
+	{
+		$iri = new Requests_IRI('http://example.com/a/?b=c#d');
+		$iri->host = null;
+
+		$this->assertEquals(null, $iri->host);
+		$this->assertEquals('http:/a/?b=c#d', (string) $iri);
+	}
+
+	public function testBadPort()
+	{
+		$iri = new Requests_IRI();
+		$iri->port = 'example';
+
+		$this->assertEquals(null, $iri->port);
+	}
+}

+ 131 - 0
api/vendor/rmccue/requests/tests/Proxy/HTTP.php

@@ -0,0 +1,131 @@
+<?php
+
+class RequestsTest_Proxy_HTTP extends PHPUnit_Framework_TestCase {
+	protected function checkProxyAvailable($type = '') {
+		switch ($type) {
+			case 'auth':
+				$has_proxy = defined('REQUESTS_HTTP_PROXY_AUTH') && REQUESTS_HTTP_PROXY_AUTH;
+				break;
+
+			default:
+				$has_proxy = defined('REQUESTS_HTTP_PROXY') && REQUESTS_HTTP_PROXY;
+				break;
+		}
+
+		if (!$has_proxy) {
+			$this->markTestSkipped('Proxy not available');
+		}
+	}
+
+	public function transportProvider() {
+		return array(
+			array('Requests_Transport_cURL'),
+			array('Requests_Transport_fsockopen'),
+		);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testConnectWithString($transport) {
+		$this->checkProxyAvailable();
+
+		$options = array(
+			'proxy' => REQUESTS_HTTP_PROXY,
+			'transport' => $transport,
+		);
+		$response = Requests::get(httpbin('/get'), array(), $options);
+		$this->assertEquals('http', $response->headers['x-requests-proxied']);
+
+		$data = json_decode($response->body, true);
+		$this->assertEquals('http', $data['headers']['x-requests-proxy']);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testConnectWithArray($transport) {
+		$this->checkProxyAvailable();
+
+		$options = array(
+			'proxy' => array(REQUESTS_HTTP_PROXY),
+			'transport' => $transport,
+		);
+		$response = Requests::get(httpbin('/get'), array(), $options);
+		$this->assertEquals('http', $response->headers['x-requests-proxied']);
+
+		$data = json_decode($response->body, true);
+		$this->assertEquals('http', $data['headers']['x-requests-proxy']);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 * @expectedException Requests_Exception
+	 */
+	public function testConnectInvalidParameters($transport) {
+		$this->checkProxyAvailable();
+
+		$options = array(
+			'proxy' => array(REQUESTS_HTTP_PROXY, 'testuser', 'password', 'something'),
+			'transport' => $transport,
+		);
+		$response = Requests::get(httpbin('/get'), array(), $options);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testConnectWithInstance($transport) {
+		$this->checkProxyAvailable();
+
+		$options = array(
+			'proxy' => new Requests_Proxy_HTTP(REQUESTS_HTTP_PROXY),
+			'transport' => $transport,
+		);
+		$response = Requests::get(httpbin('/get'), array(), $options);
+		$this->assertEquals('http', $response->headers['x-requests-proxied']);
+
+		$data = json_decode($response->body, true);
+		$this->assertEquals('http', $data['headers']['x-requests-proxy']);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testConnectWithAuth($transport) {
+		$this->checkProxyAvailable('auth');
+
+		$options = array(
+			'proxy' => array(
+				REQUESTS_HTTP_PROXY_AUTH,
+				REQUESTS_HTTP_PROXY_AUTH_USER,
+				REQUESTS_HTTP_PROXY_AUTH_PASS
+			),
+			'transport' => $transport,
+		);
+		$response = Requests::get(httpbin('/get'), array(), $options);
+		$this->assertEquals(200, $response->status_code);
+		$this->assertEquals('http', $response->headers['x-requests-proxied']);
+
+		$data = json_decode($response->body, true);
+		$this->assertEquals('http', $data['headers']['x-requests-proxy']);
+	}
+
+	/**
+	 * @dataProvider transportProvider
+	 */
+	public function testConnectWithInvalidAuth($transport) {
+		$this->checkProxyAvailable('auth');
+
+		$options = array(
+			'proxy' => array(
+				REQUESTS_HTTP_PROXY_AUTH,
+				REQUESTS_HTTP_PROXY_AUTH_USER . '!',
+				REQUESTS_HTTP_PROXY_AUTH_PASS . '!'
+			),
+			'transport' => $transport,
+		);
+		$response = Requests::get(httpbin('/get'), array(), $options);
+		$this->assertEquals(407, $response->status_code);
+	}
+}

+ 162 - 0
api/vendor/rmccue/requests/tests/Requests.php

@@ -0,0 +1,162 @@
+<?php
+
+class RequestsTest_Requests extends PHPUnit_Framework_TestCase {
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testInvalidProtocol() {
+		$request = Requests::request('ftp://128.0.0.1/');
+	}
+
+	public function testDefaultTransport() {
+		$request = Requests::get(httpbin('/get'));
+		$this->assertEquals(200, $request->status_code);
+	}
+
+	/**
+	 * Standard response header parsing
+	 */
+	public function testHeaderParsing() {
+		$transport = new RawTransport();
+		$transport->data =
+			"HTTP/1.0 200 OK\r\n".
+			"Host: localhost\r\n".
+			"Host: ambiguous\r\n".
+			"Nospace:here\r\n".
+			"Muchspace:  there   \r\n".
+			"Empty:\r\n".
+			"Empty2: \r\n".
+			"Folded: one\r\n".
+			"\ttwo\r\n".
+			"  three\r\n\r\n".
+			"stop\r\n";
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+		$expected = new Requests_Response_Headers();
+		$expected['host'] = 'localhost,ambiguous';
+		$expected['nospace'] = 'here';
+		$expected['muchspace'] = 'there';
+		$expected['empty'] = '';
+		$expected['empty2'] = '';
+		$expected['folded'] = 'one two  three';
+		foreach ($expected as $key => $value) {
+			$this->assertEquals($value, $response->headers[$key]);
+		}
+
+		foreach ($response->headers as $key => $value) {
+			$this->assertEquals($value, $expected[$key]);
+		}
+	}
+
+	public function testProtocolVersionParsing() {
+		$transport = new RawTransport();
+		$transport->data =
+			"HTTP/1.0 200 OK\r\n".
+			"Host: localhost\r\n\r\n";
+
+		$options = array(
+			'transport' => $transport
+		);
+
+		$response = Requests::get('http://example.com/', array(), $options);
+		$this->assertEquals(1.0, $response->protocol_version);
+	}
+
+	public function testRawAccess() {
+		$transport = new RawTransport();
+		$transport->data =
+			"HTTP/1.0 200 OK\r\n".
+			"Host: localhost\r\n\r\n".
+			"Test";
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+		$this->assertEquals($transport->data, $response->raw);
+	}
+
+	/**
+	 * Headers with only \n delimiting should be treated as if they're \r\n
+	 */
+	public function testHeaderOnlyLF() {
+		$transport = new RawTransport();
+		$transport->data = "HTTP/1.0 200 OK\r\nTest: value\nAnother-Test: value\r\n\r\n";
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+		$this->assertEquals('value', $response->headers['test']);
+		$this->assertEquals('value', $response->headers['another-test']);
+	}
+
+	/**
+	 * Check that invalid protocols are not accepted
+	 *
+	 * We do not support HTTP/0.9. If this is really an issue for you, file a
+	 * new issue, and update your server/proxy to support a proper protocol.
+	 *
+	 * @expectedException Requests_Exception
+	 */
+	public function testInvalidProtocolVersion() {
+		$transport = new RawTransport();
+		$transport->data = "HTTP/0.9 200 OK\r\n\r\n<p>Test";
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+	}
+
+	/**
+	 * HTTP/0.9 also appears to use a single CRLF instead of two
+	 *
+	 * @expectedException Requests_Exception
+	 */
+	public function testSingleCRLFSeparator() {
+		$transport = new RawTransport();
+		$transport->data = "HTTP/0.9 200 OK\r\n<p>Test";
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testInvalidStatus() {
+		$transport = new RawTransport();
+		$transport->data = "HTTP/1.1 OK\r\nTest: value\nAnother-Test: value\r\n\r\nTest";
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+	}
+
+	public function test30xWithoutLocation() {
+		$transport = new MockTransport();
+		$transport->code = 302;
+
+		$options = array(
+			'transport' => $transport
+		);
+		$response = Requests::get('http://example.com/', array(), $options);
+		$this->assertEquals(302, $response->status_code);
+		$this->assertEquals(0, $response->redirects);
+	}
+
+	/**
+	 * @expectedException Requests_Exception
+	 */
+	public function testTimeoutException() {
+		$options = array('timeout' => 0.5);
+		$response = Requests::get(httpbin('/delay/3'), array(), $options);
+	}
+}

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików