diff --git a/lib/.configsnapshots/configsnapshot-2011-04-27 13-54-20.xml b/lib/.configsnapshots/configsnapshot-2011-04-27 13-54-20.xml
new file mode 100644
index 0000000000000000000000000000000000000000..69268a57e943db8247fa5fb2e31e8ebb48dbe9db
--- /dev/null
+++ b/lib/.configsnapshots/configsnapshot-2011-04-27 13-54-20.xml	
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<pearconfig version="1.0"><php_dir>/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/php</php_dir><ext_dir>/usr/lib/php/extensions/no-debug-non-zts-20090626</ext_dir><cfg_dir>/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/cfg</cfg_dir><doc_dir>/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/docs</doc_dir><bin_dir>/usr/bin</bin_dir><data_dir>/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/data</data_dir><www_dir>/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/www</www_dir><test_dir>/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/tests</test_dir><src_dir>/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/src</src_dir><php_bin>/usr/bin/php</php_bin><php_ini>/private/etc/php.ini</php_ini><php_prefix></php_prefix><php_suffix></php_suffix></pearconfig>
diff --git a/lib/.pear2registry b/lib/.pear2registry
index 981d851a89012802bf650edc0cf7e399f415cbc1..2c744411401dd7b7a83105483f03f40659058bd2 100644
Binary files a/lib/.pear2registry and b/lib/.pear2registry differ
diff --git a/lib/.xmlregistry/channels/channel-simplecas.googlecode.com##svn.xml b/lib/.xmlregistry/channels/channel-simplecas.googlecode.com##svn.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dc7b71483c6060965e62c14efb7b13b5e9480af3
--- /dev/null
+++ b/lib/.xmlregistry/channels/channel-simplecas.googlecode.com##svn.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<channel version="1.0" xmlns="http://pear.php.net/channel-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/channel-1.0http://pear.php.net/dtd/channel-1.0.xsd">
+ <name>simplecas.googlecode.com/svn</name>
+ <suggestedalias>simplecas</suggestedalias>
+ <summary>simplecas</summary>
+ <servers>
+  <primary>
+   <rest>
+    <baseurl type="REST1.0">http://simplecas.googlecode.com/svn/rest/</baseurl>
+    <baseurl type="REST1.1">http://simplecas.googlecode.com/svn/rest/</baseurl>
+    <baseurl type="REST1.3">http://simplecas.googlecode.com/svn/rest/</baseurl>
+   </rest>
+  </primary>
+ </servers>
+</channel>
diff --git a/lib/.xmlregistry/channels/channelalias-simplecas.txt b/lib/.xmlregistry/channels/channelalias-simplecas.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fdae489857385937081e3051151920aa6c6e6422
--- /dev/null
+++ b/lib/.xmlregistry/channels/channelalias-simplecas.txt
@@ -0,0 +1 @@
+simplecas.googlecode.com/svn
\ No newline at end of file
diff --git a/lib/.xmlregistry/packages/pear.php.net/HTTP_Request2/2.0.0beta3-info.xml b/lib/.xmlregistry/packages/pear.php.net/HTTP_Request2/2.0.0beta3-info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6a1f8a8bf4bb63b6ddb024e238bb23bf28edc5e4
--- /dev/null
+++ b/lib/.xmlregistry/packages/pear.php.net/HTTP_Request2/2.0.0beta3-info.xml
@@ -0,0 +1,456 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package 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" packagerversion="1.9.2" version="2.0" 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>HTTP_Request2</name>
+ <channel>pear.php.net</channel>
+ <extends>HTTP_Request</extends>
+ <summary>Provides an easy way to perform HTTP requests.</summary>
+ <description>PHP5 rewrite of HTTP_Request package (with parts of HTTP_Client). Provides
+cleaner API and pluggable Adapters:
+  * Socket adapter, based on old HTTP_Request code,
+  * Curl adapter, wraps around PHP's cURL extension,
+  * Mock adapter, to use for testing packages dependent on HTTP_Request2.
+Supports POST requests with data and file uploads, basic and digest 
+authentication, cookies, managing cookies across requests, proxies, gzip and
+deflate encodings, redirects, monitoring the request progress with Observers...</description>
+ <lead>
+  <name>Alexey Borzov</name>
+  <user>avb</user>
+  <email>avb@php.net</email>
+  <active>yes</active>
+ </lead>
+ <date>2011-04-27</date>
+ <time>13:58:16</time>
+ <version>
+  <release>2.0.0beta3</release>
+  <api>2.0.0</api>
+ </version>
+ <stability>
+  <release>beta</release>
+  <api>beta</api>
+ </stability>
+ <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+ <notes>
+* Added getEffectiveUrl() method to Response object, it returns the URL
+  response was received from, possibly after redirects (request #18412)
+* Curl Adapter didn't send body for PUT requests sometimes (bug #18421)
+ </notes>
+ <contents>
+  <dir name="/">
+   <file baseinstalldir="HTTP" md5sum="1740e401dcff9571ad169bf19aa448cc" name="tests/_network/uploads.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="5e7fd3d5d3b00d47e00537c439f0a41a" name="tests/_network/timeout.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="c46e248a0638a6e020526be68693d988" name="tests/_network/setcookie.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="fda4c343b048f49ecc1e6028e03f17d7" name="tests/_network/redirects.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="91254800e447670614c62002717d92da" name="tests/_network/rawpostdata.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="db9014f908c679bdbea37b5c00b62dab" name="tests/_network/postparameters.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="21da3787253321dde0c4d7991f2d8a9c" name="tests/_network/getparameters.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="9d9f06f2307c02781238eb2532774c27" name="tests/_network/digestauth.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="7d29cd6f3df453a40f362ea31f079fb7" name="tests/_network/cookies.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="415f4b4ff843b6cb7530b9571ae3f962" name="tests/_network/basicauth.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="1fb55dfe18831f8fe6280280e72ad216" name="tests/_files/response_headers" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="722328bfe89a9c9f7de5a020ed2c4589" name="tests/_files/response_gzip_broken" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="c36530c79c044fde1745b244c38d381f" name="tests/_files/response_gzip" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="12d80db889f528922a31b5c03f693647" name="tests/_files/response_deflate" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="d1d2beb78782f56e8611100a009fb1f6" name="tests/_files/response_cookies" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="120ea8a25e5d487bf68b5f7096440019" name="tests/_files/plaintext.txt" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="fc94fb0c3ed8a8f909dbc7630a0987ff" name="tests/_files/empty.gif" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="16f23f14921a2aa607c85664efa47d41" name="tests/_files/bug_18169" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="22d7f11b85dd00bd8919a4226a5a0388" name="tests/_files/bug_15305" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="6dc93662dd42cf76a457c6fff5b8df20" name="tests/TestHelper.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="c9839810b6416ce1521ab1c721853ef6" name="tests/Request2Test.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="9be337588f6c6d2b795d27d185cd1c92" name="tests/Request2/ResponseTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="c427be4a318a1002ef0df67b05a39276" name="tests/Request2/MultipartBodyTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="fc16142b51b1a110455911d3d5f4685a" name="tests/Request2/CookieJarTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="8bdcae5a16da6a577681309c7958fe68" name="tests/Request2/AllTests.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="866a71b2fcf1632f3ffddf11142fd20e" name="tests/Request2/Adapter/SocketTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="416ae359f326d574871755d6d630a2b0" name="tests/Request2/Adapter/SocketProxyTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="6ac2d3e86cb81eb739a094b72f18a609" name="tests/Request2/Adapter/SkippedTests.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="4ba446d73bb389557284233c88f26dbd" name="tests/Request2/Adapter/MockTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="d825a52bb83675833ec0f022efa50688" name="tests/Request2/Adapter/CurlTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="8a9c7037d525fc6c723db266f74ecddf" name="tests/Request2/Adapter/CommonNetworkTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="80b934c16d2876f8ef1fb6e5afc7ae19" name="tests/Request2/Adapter/AllTests.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="f9fa9893f4241ba54d8b9f758f4a5dd5" name="tests/ObserverTest.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="62c675708ac7a594cfd18137ac869dfc" name="tests/NetworkConfig.php.dist" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="0d6142d9cbf8b81c5b22c9982a750215" name="tests/AllTests.php" role="test"/>
+   <file baseinstalldir="HTTP" md5sum="0ec6a02c97f25ef76ead19b0cdbd87d3" name="Request2/Response.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="cf5d76e80409a85597a91de1e91c6ee1" name="Request2/Observer/Log.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="68ec0b653d74c8eb279882e5ee9dc8ad" name="Request2/MultipartBody.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="2df8b0b6b1393db00621fea5c12adb25" name="Request2/Exception.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="88bca86278b570e760d1b4bece6ebbb0" name="Request2/CookieJar.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+    <tasks:replace from="@data_dir@" to="data_dir" type="pear-config"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="f276265e7e4b84a85c8215e2f74caea7" name="Request2/Adapter/Socket.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="aa47b70e43fda0e597cd91e3b13fe717" name="Request2/Adapter/Mock.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="448312f853d4447325c974486e5d6b3c" name="Request2/Adapter/Curl.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="0d68ac49d4a4b87c13e0f523c069ee3b" name="Request2/Adapter.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="0a34a995006ebace077e2dd87a292a8f" name="Request2.php" role="php">
+    <tasks:replace from="@package_version@" to="version" type="package-info"/>
+   </file>
+   <file baseinstalldir="HTTP" md5sum="7e6017dfdf042dbd443ce6c8c024f40d" name="docs/examples/upload-rapidshare.php" role="doc"/>
+   <file baseinstalldir="HTTP" md5sum="46d7644aa37dd6bf9b200820a29a277c" name="data/public-suffix-list.php" role="data"/>
+   <file baseinstalldir="HTTP" md5sum="389143b973e6c1d87926d803ca5fceec" name="data/generate-list.php" role="data"/>
+  </dir>
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.2.0</min>
+   </php>
+   <pearinstaller>
+    <min>1.5.4</min>
+   </pearinstaller>
+   <package>
+    <name>Net_URL2</name>
+    <channel>pear.php.net</channel>
+    <min>0.3.0</min>
+   </package>
+  </required>
+  <optional>
+   <extension>
+    <name>curl</name>
+   </extension>
+   <extension>
+    <name>fileinfo</name>
+   </extension>
+   <extension>
+    <name>zlib</name>
+   </extension>
+   <extension>
+    <name>openssl</name>
+   </extension>
+  </optional>
+ </dependencies>
+ <phprelease>
+  <filelist>
+   <install as="generate-list.php" name="data/generate-list.php"/>
+   <install as="public-suffix-list.php" name="data/public-suffix-list.php"/>
+   <install as="examples/upload-rapidshare.php" name="docs/examples/upload-rapidshare.php"/>
+   <install as="AllTests.php" name="tests/AllTests.php"/>
+   <install as="NetworkConfig.php.dist" name="tests/NetworkConfig.php.dist"/>
+   <install as="ObserverTest.php" name="tests/ObserverTest.php"/>
+   <install as="Request2/Adapter/AllTests.php" name="tests/Request2/Adapter/AllTests.php"/>
+   <install as="Request2/Adapter/CommonNetworkTest.php" name="tests/Request2/Adapter/CommonNetworkTest.php"/>
+   <install as="Request2/Adapter/CurlTest.php" name="tests/Request2/Adapter/CurlTest.php"/>
+   <install as="Request2/Adapter/MockTest.php" name="tests/Request2/Adapter/MockTest.php"/>
+   <install as="Request2/Adapter/SkippedTests.php" name="tests/Request2/Adapter/SkippedTests.php"/>
+   <install as="Request2/Adapter/SocketProxyTest.php" name="tests/Request2/Adapter/SocketProxyTest.php"/>
+   <install as="Request2/Adapter/SocketTest.php" name="tests/Request2/Adapter/SocketTest.php"/>
+   <install as="Request2/AllTests.php" name="tests/Request2/AllTests.php"/>
+   <install as="Request2/CookieJarTest.php" name="tests/Request2/CookieJarTest.php"/>
+   <install as="Request2/MultipartBodyTest.php" name="tests/Request2/MultipartBodyTest.php"/>
+   <install as="Request2/ResponseTest.php" name="tests/Request2/ResponseTest.php"/>
+   <install as="Request2Test.php" name="tests/Request2Test.php"/>
+   <install as="TestHelper.php" name="tests/TestHelper.php"/>
+   <install as="_files/bug_15305" name="tests/_files/bug_15305"/>
+   <install as="_files/bug_18169" name="tests/_files/bug_18169"/>
+   <install as="_files/empty.gif" name="tests/_files/empty.gif"/>
+   <install as="_files/plaintext.txt" name="tests/_files/plaintext.txt"/>
+   <install as="_files/response_cookies" name="tests/_files/response_cookies"/>
+   <install as="_files/response_deflate" name="tests/_files/response_deflate"/>
+   <install as="_files/response_gzip" name="tests/_files/response_gzip"/>
+   <install as="_files/response_gzip_broken" name="tests/_files/response_gzip_broken"/>
+   <install as="_files/response_headers" name="tests/_files/response_headers"/>
+   <install as="_network/basicauth.php" name="tests/_network/basicauth.php"/>
+   <install as="_network/cookies.php" name="tests/_network/cookies.php"/>
+   <install as="_network/digestauth.php" name="tests/_network/digestauth.php"/>
+   <install as="_network/getparameters.php" name="tests/_network/getparameters.php"/>
+   <install as="_network/postparameters.php" name="tests/_network/postparameters.php"/>
+   <install as="_network/rawpostdata.php" name="tests/_network/rawpostdata.php"/>
+   <install as="_network/redirects.php" name="tests/_network/redirects.php"/>
+   <install as="_network/setcookie.php" name="tests/_network/setcookie.php"/>
+   <install as="_network/timeout.php" name="tests/_network/timeout.php"/>
+   <install as="_network/uploads.php" name="tests/_network/uploads.php"/>
+  </filelist>
+ </phprelease>
+ <changelog>
+  <release>
+   <version>
+    <release>2.0.0beta2</release>
+    <api>2.0.0</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>beta</api>
+   </stability>
+   <date>2011-03-25</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+* Unit tests can now be run under recent PHPUnit versions (3.5+)
+* Public Suffix List updated to current version
+* PHP warning produced by stream_socket_client() in Socket adapter is now 
+  added to Exception message (bug #18331)
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>2.0.0beta1</release>
+    <api>2.0.0</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>beta</api>
+   </stability>
+   <date>2011-02-27</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+Additions and changes:
+  * Implemented cookie jar that allows to store and pass cookies across HTTP
+    requests (see request #18225)
+  * Added several specialized subclasses of HTTP_Request2_Exception, they are
+    now thrown instead of the parent. Also added error codes and possibility
+    to get native error code (as returned by stream_socket_client() and 
+    curl_errno()) (request #16762)
+  * An additional 'sentBody' event is now sent to Observers (request #16828) 
+  * setBody() and addUpload() can now accept file pointers (request #16863)
+
+Bugfixes:
+  * Incorrect check in Socket Adapter prevented Keep-alive from working in
+    some cases (bug #17031)
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.6.0</release>
+    <api>0.6.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2011-02-14</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+Additions and changes:
+  * Added test suite that interacts with a webserver. Please refer to 
+    tests/NetworkConfig.php.dist for instructions.
+  * Packaging changes: docs/ and tests/ contents are installed without
+    redundant subdirectories.
+  * Added a $replace parameter to HTTP_Request2::setHeader() that controls
+    whether new header value will overwrite previous one or be appended
+    to it (request #17507)
+
+Bugfixes:
+  * Fixed a typo in Curl Adapter that prevented 'strict_redirects' from working
+  * Curl Adapter will throw an exception if CURLOPT_FOLLOWLOCATION can not be
+    enabled due to PHP setup (bug #17450)
+  * Allow parameters in manually set Content-Type headers (bug #17460)
+  * Properly reset redirect limit if multiple requests are performed with the
+    same instance of Socket Adapter (bug #17826)
+  * Response::getBody() no longer tries to decode empty strings (bug #18169)
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.5.2</release>
+    <api>0.5.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2010-04-21</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+* magic_quotes_runtime PHP setting could be incorrectly enabled after
+  performing the request (bug #16440)
+* Unit tests fixes (bugs #17079, #17106, #17326)
+* Observer_Log now appends to the log file rather than rewrites it (thanks to
+  troelskn at gmail dot com for reporting)
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.5.1</release>
+    <api>0.5.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2009-11-21</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+* Content-Type request header is no longer removed for POST and PUT requests
+  with empty request body (request #16799).
+* CURLOPT_NOBODY option is now set when doing HEAD requests with Curl adapter.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.5.0</release>
+    <api>0.5.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2009-11-18</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+* Redirect support added, new configuration parameters 'follow_redirects',
+  'max_redirects' and 'strict_redirects' available
+
+* Implemented workaround for PHP bug #47204, Curl Adapter can now handle
+  Digest authentication and redirects when doing POST requests, unfortunately
+  this requires loading the entire request body into memory.
+* Config parameter 'use_brackets' is propagated to created instances of Net_URL2
+* Prevent memory leaks due to circular references (request #16646)
+* Fixed a misleading error message when timing out due to default_socket_timeout
+* HTTP_Request2::setBody() can now accept an instance of HTTP_Request2_MultipartBody
+  without trying to convert it to string
+* Calling HTTP_Request2::setBody() now clears post parameters and uploads
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.4.1</release>
+    <api>0.4.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2009-09-14</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+* Decoding of gzipped responses failed if mbstring.func_overload was enabled
+  (bug #16555)
+* Changed boundary generation in multipart bodies to work correctly with
+  rapidshare.com, added first usage example: file uploading to rapidshare.com
+* Added forgotten optional dependency on OpenSSL PHP extension
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.4.0</release>
+    <api>0.4.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2009-05-03</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+* Added 'store_body' config parameter, if set to false it will prevent storing
+  the response body in Response object (request #15881)
+* HTTP_Request2::setHeader() method now works as documented, setHeader('name') 
+  will remove the 'name' header, while setHeader('name', '') will set 'name'
+  header to empty value (bug #15937)
+* Custom 'Host' header will not be overwritten by generated one (bug #16146)
+* When trying to reuse the connected socket in Socket adapter, make sure that
+  it is still connected (bug #16149)
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.3.0</release>
+    <api>0.3.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2009-01-28</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+API changes:
+ * Removed HTTP_Request2::getConfigValue() method
+
+Feature additions:
+ * Added digest authentication (RFC 2617) support to Socket adapter. Thanks
+   to Tom Snyder (tomsn at inetoffice dot com) who sent me a prototype
+   implementation for HTTP_Request a couple of years ago.
+ * Added HTTPS proxy support to Socket adapter, this works through CONNECT
+   request described in RFC 2817.
+ * Mock adapter can now throw an Exception instead of returning a response
+   if Exception object is added via its addResponse() method (request #15629)
+
+Other changes and fixes:
+ * Support RFC 3986 by not encoding '~' in POST body (request #15368)
+ * Prevent an error with particular versions of PHP and Curl (bug #15617)
+ * Regular expressions used in HTTP_Request2 are now class constants 
+   (request #15630)
+ * Curl adapter now throws an exception in case of malformed (non-HTTP) 
+   response rather than dies with a fatal error (bug #15716)
+ * Curl handle wasn't closed in Curl adapter in case of error (bug #15721)
+ * Curl adapter sent an extra 'sentHeaders' event and returned bogus 
+   response status when server returned 100-Continue response (bug #15785)
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.2.0</release>
+    <api>0.2.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2009-01-07</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+API changes:
+ * HTTP_Request2::getConfigValue() is deprecated and will be removed in next 
+   release. Use HTTP_Request2::getConfig().
+ * Changed HTTP_Request2::setConfig() to accept a pair of parameter name and
+   parameter value in addition to array('parameter name' =&gt; 'value')
+ * Added HTTP_Request2::getConfig() method that can return a single 
+   configuration parameter or the whole configuration array
+
+Other additions and changes:
+ * Added a debug Observer that can log request progress to a file or an 
+   instance of PEAR::Log (thanks to David Jean Louis, request #15424)
+ * Added a new 'timeout' parameter that limits total number of seconds
+   a request can take (see requests #5735 and #8964)
+ * Added various SSL protocol options: 'ssl_verify_peer', 'ssl_verify_host',
+   'ssl_cafile', 'ssl_capath', 'ssl_local_cert', 'ssl_passphrase'. Note that
+   'ssl_verify_host' option behaves differently in Socket and Curl Adapters:
+   http://bugs.php.net/bug.php?id=47030
+
+Fixes:
+ * Fixed 'data error' when processing response encoded by 'deflate'
+   encoding (bug #15305)
+ * Curl Adapter now passes full request headers in 'sentHeaders' event
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>0.1.0</release>
+    <api>0.1.0</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2008-11-17</date>
+   <license uri="http://opensource.org/licenses/bsd-license.php">BSD License</license>
+   <notes>
+Initial release. The features supported are mostly the same as those of
+HTTP_Request, with the following additional feature requests implemented:
+  * cURL extension support (request #5463)
+  * It is now possible to monitor the file upload progress with Observers
+	(request #7630)
+  * Added 'sentHeaders' notification providing the request headers to the
+    Observers (request #7633)
+  * Added support for 'deflate' encoding (request #11246)
+   </notes>
+  </release>
+ </changelog>
+</package>
diff --git a/lib/.xmlregistry/packages/pear.php.net/Net_URL2/0.3.1-info.xml b/lib/.xmlregistry/packages/pear.php.net/Net_URL2/0.3.1-info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..295977a67919e2d1df1ab71ba2f651bfcef47946
--- /dev/null
+++ b/lib/.xmlregistry/packages/pear.php.net/Net_URL2/0.3.1-info.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package 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" packagerversion="1.7.1" version="2.0" 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>Net_URL2</name>
+ <channel>pear.php.net</channel>
+ <summary>Class for parsing and handling URL.</summary>
+ <description>Provides parsing of URLs into their constituent parts (scheme, host, path etc.), URL generation, and resolving of relative URLs.</description>
+ <lead>
+  <name>David Coallier</name>
+  <user>davidc</user>
+  <email>davidc@php.net</email>
+  <active>yes</active>
+ </lead>
+ <lead>
+  <name>Christian Schmidt</name>
+  <user>schmidt</user>
+  <email>schmidt@php.net</email>
+  <active>yes</active>
+ </lead>
+ <date>2011-04-27</date>
+ <time>13:58:16</time>
+ <version>
+  <release>0.3.1</release>
+  <api>0.3.0</api>
+ </version>
+ <stability>
+  <release>beta</release>
+  <api>beta</api>
+ </stability>
+ <license uri="http://www.opensource.org/licenses/bsd-license.php">BSD</license>
+ <notes>* BC break: Removed setOption() to avoid undefined behaviour (bug #16674)
+* Fixed Bug #16854: Invalid package.xml making it impossible to install with Pyrus
+* Fixed Bug #16651: Port may be an empty string
+* Fixed Bug #16653: Don't make OPTION_SEPARATOR_(IN|OUT)PUT default to arg_separator.(in|out)put</notes>
+ <contents>
+  <dir name="/">
+   <file baseinstalldir="Net" md5sum="f0a637e921da7a47373e2b065107c7a0" name="URL2.php" role="php"/>
+   <file baseinstalldir="Net" md5sum="587a224d39fbffa47cacb9fb67b51da1" name="docs/example.php" role="doc"/>
+   <file baseinstalldir="Net" md5sum="ea8b73061588566519fd0e55a230f2a6" name="docs/6470.php" role="doc"/>
+  </dir>
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.0</min>
+   </php>
+   <pearinstaller>
+    <min>1.4.0b1</min>
+   </pearinstaller>
+  </required>
+ </dependencies>
+ <phprelease>
+  <changelog>
+   <release>
+    <version>
+     <release>0.3.0</release>
+     <api>0.3.0</api>
+    </version>
+    <stability>
+     <release>beta</release>
+     <api>beta</api>
+    </stability>
+    <date>2009-09-05</date>
+    <license>BSD</license>
+    <notes>* Fixed #14399 (Errors in URL parsing (items #1 and #3))
+* Fixed #14735 (Encode query string values)
+* Fixed #15546 (Add adding __toString())
+* Fixed #15367 (Use RFC 3986-compliant version of rawurlencode() in PHP &lt; 5.2)
+* Fixed #14289 (Add __get() and __set())</notes>
+   </release>
+   <release>
+    <version>
+     <release>0.2.0</release>
+     <api>0.2.0</api>
+    </version>
+    <stability>
+     <release>beta</release>
+     <api>beta</api>
+    </stability>
+    <date>2008-06-18</date>
+    <license>BSD</license>
+    <notes>Major rewrite to comply with RFC3986 (bug 11574).
+   Much better support for resolving relative URLs.
+   WARNING: Method and property names has changed to reflect the terminology used in the RFC - THIS RELEASE IS NOT BACKWARDS COMPATIBLE WITH VERSION 0.1.0.</notes>
+   </release>
+   <release>
+    <version>
+     <release>0.1.0</release>
+     <api>0.1.0</api>
+    </version>
+    <stability>
+     <release>beta</release>
+     <api>beta</api>
+    </stability>
+    <date>2007-05-08</date>
+    <license>BSD</license>
+    <notes>Convert to PHP5 only. PHP4 users should continue with version 1.0.15</notes>
+   </release>
+  </changelog>
+ </phprelease>
+</package>
diff --git a/lib/.xmlregistry/packages/pear.unl.edu/UNL_Auth/0.4.0-info.xml b/lib/.xmlregistry/packages/pear.unl.edu/UNL_Auth/0.4.0-info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f93fca7639b9e4b5a0d5604965737e5d3c661f0a
--- /dev/null
+++ b/lib/.xmlregistry/packages/pear.unl.edu/UNL_Auth/0.4.0-info.xml
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package 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" packagerversion="1.9.0" version="2.0" 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>UNL_Auth</name>
+ <channel>pear.unl.edu</channel>
+ <summary>An authentication framework for PHP Applications at UNL</summary>
+ <description>This package provides an authentication framework for web 
+applications developed at UNL.</description>
+ <lead>
+  <name>Brett Bieber</name>
+  <user>saltybeagle</user>
+  <email>brett.bieber@gmail.com</email>
+  <active>yes</active>
+ </lead>
+ <date>2011-04-27</date>
+ <time>13:54:20</time>
+ <version>
+  <release>0.4.0</release>
+  <api>0.4.0</api>
+ </version>
+ <stability>
+  <release>alpha</release>
+  <api>alpha</api>
+ </stability>
+ <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+ <notes>
+* Fix E_STRICT warning about static methods.
+ </notes>
+ <contents>
+  <dir name="/">
+   <file baseinstalldir="/" md5sum="b7a35f1bfe174ef2725733df1539f212" name="UNL/Auth/SimpleCAS/ZendAuth.php" role="php"/>
+   <file baseinstalldir="/" md5sum="6def037a77fd9fa49bcc5e752cbb8170" name="UNL/Auth/SimpleCAS.php" role="php"/>
+   <file baseinstalldir="/" md5sum="ada4bb738641430ba2420da94ec3e749" name="UNL/Auth/CAS/PEARAuth.php" role="php"/>
+   <file baseinstalldir="/" md5sum="76deaf815ba781ca6f7f6bbcc7095912" name="UNL/Auth/CAS.php" role="php"/>
+   <file baseinstalldir="/" md5sum="f0bb48dadf42f6511b718032203f9c28" name="UNL/Auth.php" role="php"/>
+   <file baseinstalldir="/" md5sum="c4ee1094cd276ff40fbd2b16d66068fe" name="docs/examples/Zend_SimpleCAS_example.php" role="doc"/>
+   <file baseinstalldir="/" md5sum="3a80ba084e5bc5f8b17d188b15e6a7aa" name="docs/examples/SimpleCAS_example.php" role="doc"/>
+   <file baseinstalldir="/" md5sum="3759e0e8f63d4161653c158b08cdd0ed" name="docs/examples/CAS_example.php" role="doc"/>
+   <file baseinstalldir="/" md5sum="e89e49dca8497ec59459d17140c6e63a" name="docs/examples/CASPEARAuth_example.php" role="doc"/>
+  </dir>
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.2.0</min>
+   </php>
+   <pearinstaller>
+    <min>1.4.3</min>
+   </pearinstaller>
+  </required>
+  <optional>
+   <package>
+    <name>Auth</name>
+    <channel>pear.php.net</channel>
+    <min>1.0</min>
+   </package>
+   <package>
+    <name>CAS</name>
+    <channel>pear.unl.edu</channel>
+    <min>1.0.0</min>
+   </package>
+   <package>
+    <name>SimpleCAS</name>
+    <channel>simplecas.googlecode.com/svn</channel>
+    <min>0.3.0</min>
+   </package>
+  </optional>
+ </dependencies>
+ <phprelease>
+  <changelog>
+   <release>
+    <version>
+     <release>0.1.0</release>
+     <api>0.1.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2007-12-17</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+First Release - only CAS is available.
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.1.1</release>
+     <api>0.1.1</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2008-05-20</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Check if session is already started - kabel
+* Improve PHP docs and fix example. - bbieber
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.2.0</release>
+     <api>0.2.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2008-08-22</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Upgrade CAS driver dependency to 1.0.0
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.3.0</release>
+     <api>0.3.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2008-12-09</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Enable SimpleCAS support. http://code.google.com/p/simplecas/
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.3.1</release>
+     <api>0.3.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-02-12</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Increase SimpleCAS dependency of 0.2.0 to take advantage of getRequest() so we can ignore the ssl peer verification.
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.3.2</release>
+     <api>0.3.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-03-03</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Increase SimpleCAS dependency of 0.3.0 to use new object names and array options for the constructor.
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.4.0</release>
+     <api>0.4.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-11-18</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Fix E_STRICT warning about static methods.
+   </notes>
+   </release>
+  </changelog>
+ </phprelease>
+</package>
diff --git a/lib/.xmlregistry/packages/simplecas.googlecode.com!svn/SimpleCAS/0.5.0-info.xml b/lib/.xmlregistry/packages/simplecas.googlecode.com!svn/SimpleCAS/0.5.0-info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5fc5b35c2b95028c4312ef2030f9468fa60ea644
--- /dev/null
+++ b/lib/.xmlregistry/packages/simplecas.googlecode.com!svn/SimpleCAS/0.5.0-info.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package 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" packagerversion="1.9.1" version="2.0" 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>SimpleCAS</name>
+ <channel>simplecas.googlecode.com/svn</channel>
+ <summary>A PHP5 library for CAS Authentication.</summary>
+ <description>This package is a PHP5 only library for identifying users
+in a JA-SIG CAS secured environment.</description>
+ <lead>
+  <name>Brett Bieber</name>
+  <user>saltybeagle</user>
+  <email>brett.bieber@gmail.com</email>
+  <active>yes</active>
+ </lead>
+ <helper>
+  <name>John Thiltges</name>
+  <user>jthiltges</user>
+  <email>jthiltges@gmail.com</email>
+  <active>yes</active>
+ </helper>
+ <helper>
+  <name>Kevin Abel</name>
+  <user>kevin.abel.0</user>
+  <email>kevin.abel.0@gmail.com</email>
+  <active>yes</active>
+ </helper>
+ <helper>
+  <name>Eric Rasmussen</name>
+  <user>ericrasmussen1</user>
+  <email>ericrasmussen1@gmail.com</email>
+  <active>yes</active>
+ </helper>
+ <date>2011-04-27</date>
+ <time>13:58:16</time>
+ <version>
+  <release>0.5.0</release>
+  <api>0.5.0</api>
+ </version>
+ <stability>
+  <release>beta</release>
+  <api>beta</api>
+ </stability>
+ <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+ <notes>
+* Allow service url to be customized with SimpleCAS::setURL($url); [ericrasmussen1]
+ </notes>
+ <contents>
+  <dir name="/">
+   <file baseinstalldir="/" md5sum="ad9c06f186ce8fa739d6e716f6c9b48d" name="SimpleCAS/SingleSignOut.php" role="php"/>
+   <file baseinstalldir="/" md5sum="7a49aa1c67563ed628202c3e9244dcdc" name="SimpleCAS/ProxyGranting/Storage/File.php" role="php"/>
+   <file baseinstalldir="/" md5sum="26b6d753c3f9098be6493c818aabd959" name="SimpleCAS/ProxyGranting/Storage.php" role="php"/>
+   <file baseinstalldir="/" md5sum="e96b4c13218c39664fdeb8dc8d4e7541" name="SimpleCAS/ProxyGranting.php" role="php"/>
+   <file baseinstalldir="/" md5sum="46feaaf938c6eb0f7f260125a646b3fb" name="SimpleCAS/Protocol/Version2/ValidationResponse.php" role="php"/>
+   <file baseinstalldir="/" md5sum="f4ed06c8ae5918cfb9790ca72c6256d0" name="SimpleCAS/Protocol/Version2.php" role="php"/>
+   <file baseinstalldir="/" md5sum="80862315b001dcfa1fde9348341ff432" name="SimpleCAS/Protocol/Version1.php" role="php"/>
+   <file baseinstalldir="/" md5sum="daf05e7a073e2ac47ddb0c7ea6a83e33" name="SimpleCAS/Protocol.php" role="php"/>
+   <file baseinstalldir="/" md5sum="d93480efa786598948935145b06352a6" name="SimpleCAS/Autoload.php" role="php"/>
+   <file baseinstalldir="/" md5sum="a9d96c7d2032b5432306ffba5438d0f1" name="SimpleCAS.php" role="php"/>
+   <file baseinstalldir="/" md5sum="9d686c3553b6c8be0af988ddfb363f0c" name="docs/examples/Zend_Auth_Adapter_SimpleCAS.php" role="doc"/>
+   <file baseinstalldir="/" md5sum="2254593f10efc23cd0eadab309506e15" name="docs/examples/simple.php" role="doc"/>
+  </dir>
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.2.5</min>
+   </php>
+   <pearinstaller>
+    <min>1.5.4</min>
+   </pearinstaller>
+   <package>
+    <name>HTTP_Request2</name>
+    <channel>pear.php.net</channel>
+    <min>0.1.0</min>
+   </package>
+  </required>
+ </dependencies>
+ <phprelease>
+  <changelog>
+   <release>
+    <version>
+     <release>0.1.0</release>
+     <api>0.1.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2008-12-08</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+First Release.
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.1.1</release>
+     <api>0.1.1</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2008-12-08</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Fix Notice: Trying to get property of non-object in SimpleCAS/Server/Version2/ValidationResponse.php on line 23
+* Change PHP dependency to 5.2.5
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.1.2</release>
+     <api>0.1.1</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-02-05</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Update PEAR dependency to 1.5.4
+* Match case for variables (jthiltges)
+* In CAS v2 validateTicket, typecast successful return value to string (jthiltges)
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.2.0</release>
+     <api>0.2.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-02-11</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Allow setting HTTP_Request2 object so configuration can be set.
+  $server-&gt;getRequest()-&gt;setConfig('ssl_verify_peer', false);
+* Add $server-&gt;getRequest(), $server-&gt;setRequest(HTTP_Request2 $http_request)
+Change interface for server to abstract class.
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.2.1</release>
+     <api>0.2.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-02-12</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Explicitly call __toString() for PHP 5.1 compatibility. [jthiltges]
+* Add Zend_Auth_Adapter_SimpleCAS to the examples. [jthiltges]
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.3.0</release>
+     <api>0.3.0</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-03-03</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Issue 1: Rename SimpleCAS_Server to SimpleCAS_Protocol [saltybeagle]
+* Issue 2: Switch to arrays for the protocol constructors. [saltybeagle]
+* Exit immediately after re-direct.
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.3.1</release>
+     <api>0.3.1</api>
+    </version>
+    <stability>
+     <release>alpha</release>
+     <api>alpha</api>
+    </stability>
+    <date>2009-04-06</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Prefix session variables with __SIMPLECAS [saltybeagle]
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.4.0</release>
+     <api>0.4.0</api>
+    </version>
+    <stability>
+     <release>beta</release>
+     <api>beta</api>
+    </stability>
+    <date>2010-01-08</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Allow request adapter to be customized. [Kevin]
+   </notes>
+   </release>
+   <release>
+    <version>
+     <release>0.5.0</release>
+     <api>0.5.0</api>
+    </version>
+    <stability>
+     <release>beta</release>
+     <api>beta</api>
+    </stability>
+    <date>2010-01-27</date>
+    <license uri="http://www1.unl.edu/wdn/wiki/Software_License">BSD License</license>
+    <notes>
+* Allow service url to be customized with SimpleCAS::setURL($url); [ericrasmussen1]
+   </notes>
+   </release>
+  </changelog>
+ </phprelease>
+</package>
diff --git a/lib/data/HTTP_Request2/HTTP/generate-list.php b/lib/data/HTTP_Request2/HTTP/generate-list.php
new file mode 100644
index 0000000000000000000000000000000000000000..839266bf999a42a1102588100a64653aab4ddac8
--- /dev/null
+++ b/lib/data/HTTP_Request2/HTTP/generate-list.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Helper file for downloading Public Suffix List and converting it to PHP array
+ *
+ * You can run this script to update PSL to the current version instead of
+ * waiting for a new release of HTTP_Request2.
+ *
+ * @version SVN: $Id: generate-list.php 308480 2011-02-19 11:27:13Z avb $
+ */
+
+/** URL to download Public Suffix List from */
+define('LIST_URL',    'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1');
+/** Name of PHP file to write */
+define('OUTPUT_FILE', dirname(__FILE__) . '/public-suffix-list.php');
+
+require_once 'HTTP/Request2.php';
+
+function buildSubdomain(&$node, $tldParts)
+{
+    $part = trim(array_pop($tldParts));
+
+    if (!array_key_exists($part, $node)) {
+        $node[$part] = array();
+    }
+
+    if (0 < count($tldParts)) {
+        buildSubdomain($node[$part], $tldParts);
+    }
+}
+
+function writeNode($fp, $valueTree, $key = null, $indent = 0)
+{
+    if (is_null($key)) {
+        fwrite($fp, "return ");
+
+    } else {
+        fwrite($fp, str_repeat(' ', $indent) . "'$key' => ");
+    }
+
+    if (0 == ($count = count($valueTree))) {
+        fwrite($fp, 'true');
+    } else {
+        fwrite($fp, "array(\n");
+        for ($keys = array_keys($valueTree), $i = 0; $i < $count; $i++) {
+            writeNode($fp, $valueTree[$keys[$i]], $keys[$i], $indent + 1);
+            if ($i + 1 != $count) {
+                fwrite($fp, ",\n");
+            } else {
+                fwrite($fp, "\n");
+            }
+        }
+        fwrite($fp, str_repeat(' ', $indent) . ")");
+    }
+}
+
+
+try {
+    $request  = new HTTP_Request2(LIST_URL);
+    $response = $request->send();
+    if (200 != $response->getStatus()) {
+        throw new Exception("List download URL returned status: " .
+                            $response->getStatus() . ' ' . $response->getReasonPhrase());
+    }
+    $list     = $response->getBody();
+    if (false === strpos($list, 'The Original Code is the Public Suffix List.')) {
+        throw new Exception("List download URL does not contain expected phrase");
+    }
+    if (!($fp = @fopen(OUTPUT_FILE, 'wt'))) {
+        throw new Exception("Unable to open " . OUTPUT_FILE);
+    }
+
+} catch (Exception $e) {
+    die($e->getMessage());
+}
+
+$tldTree = array();
+$license = true;
+
+fwrite($fp, "<?php\n");
+
+foreach (array_filter(array_map('trim', explode("\n", $list))) as $line) {
+    if ('//' != substr($line, 0, 2)) {
+        buildSubdomain($tldTree, explode('.', $line));
+
+    } elseif ($license) {
+        fwrite($fp, $line . "\n");
+
+        if (0 === strpos($line, "// ***** END LICENSE BLOCK")) {
+            $license = false;
+            fwrite($fp, "\n");
+        }
+    }
+}
+
+writeNode($fp, $tldTree);
+fwrite($fp, ";\n?>");
+fclose($fp);
+?>
\ No newline at end of file
diff --git a/lib/data/HTTP_Request2/HTTP/public-suffix-list.php b/lib/data/HTTP_Request2/HTTP/public-suffix-list.php
new file mode 100644
index 0000000000000000000000000000000000000000..eb68660d98f0958f40baabc54c47c61cabce4338
--- /dev/null
+++ b/lib/data/HTTP_Request2/HTTP/public-suffix-list.php
@@ -0,0 +1,4464 @@
+<?php
+// ***** BEGIN LICENSE BLOCK *****
+// Version: MPL 1.1/GPL 2.0/LGPL 2.1
+//
+// The contents of this file are subject to the Mozilla Public License Version
+// 1.1 (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+// http://www.mozilla.org/MPL/
+//
+// Software distributed under the License is distributed on an "AS IS" basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+// for the specific language governing rights and limitations under the
+// License.
+//
+// The Original Code is the Public Suffix List.
+//
+// The Initial Developer of the Original Code is
+// Jo Hermans <jo.hermans@gmail.com>.
+// Portions created by the Initial Developer are Copyright (C) 2007
+// the Initial Developer. All Rights Reserved.
+//
+// Contributor(s):
+//   Ruben Arakelyan <ruben@wackomenace.co.uk>
+//   Gervase Markham <gerv@gerv.net>
+//   Pamela Greene <pamg.bugs@gmail.com>
+//   David Triendl <david@triendl.name>
+//   Jothan Frakes <jothan@gmail.com>
+//   The kind representatives of many TLD registries
+//
+// Alternatively, the contents of this file may be used under the terms of
+// either the GNU General Public License Version 2 or later (the "GPL"), or
+// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+// in which case the provisions of the GPL or the LGPL are applicable instead
+// of those above. If you wish to allow use of your version of this file only
+// under the terms of either the GPL or the LGPL, and not to allow others to
+// use your version of this file under the terms of the MPL, indicate your
+// decision by deleting the provisions above and replace them with the notice
+// and other provisions required by the GPL or the LGPL. If you do not delete
+// the provisions above, a recipient may use your version of this file under
+// the terms of any one of the MPL, the GPL or the LGPL.
+//
+// ***** END LICENSE BLOCK *****
+
+return array(
+ 'ac' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'mil' => true,
+  'org' => true
+ ),
+ 'ad' => array(
+  'nom' => true
+ ),
+ 'ae' => array(
+  'co' => true,
+  'net' => true,
+  'org' => true,
+  'sch' => true,
+  'ac' => true,
+  'gov' => true,
+  'mil' => true
+ ),
+ 'aero' => array(
+  'accident-investigation' => true,
+  'accident-prevention' => true,
+  'aerobatic' => true,
+  'aeroclub' => true,
+  'aerodrome' => true,
+  'agents' => true,
+  'aircraft' => true,
+  'airline' => true,
+  'airport' => true,
+  'air-surveillance' => true,
+  'airtraffic' => true,
+  'air-traffic-control' => true,
+  'ambulance' => true,
+  'amusement' => true,
+  'association' => true,
+  'author' => true,
+  'ballooning' => true,
+  'broker' => true,
+  'caa' => true,
+  'cargo' => true,
+  'catering' => true,
+  'certification' => true,
+  'championship' => true,
+  'charter' => true,
+  'civilaviation' => true,
+  'club' => true,
+  'conference' => true,
+  'consultant' => true,
+  'consulting' => true,
+  'control' => true,
+  'council' => true,
+  'crew' => true,
+  'design' => true,
+  'dgca' => true,
+  'educator' => true,
+  'emergency' => true,
+  'engine' => true,
+  'engineer' => true,
+  'entertainment' => true,
+  'equipment' => true,
+  'exchange' => true,
+  'express' => true,
+  'federation' => true,
+  'flight' => true,
+  'freight' => true,
+  'fuel' => true,
+  'gliding' => true,
+  'government' => true,
+  'groundhandling' => true,
+  'group' => true,
+  'hanggliding' => true,
+  'homebuilt' => true,
+  'insurance' => true,
+  'journal' => true,
+  'journalist' => true,
+  'leasing' => true,
+  'logistics' => true,
+  'magazine' => true,
+  'maintenance' => true,
+  'marketplace' => true,
+  'media' => true,
+  'microlight' => true,
+  'modelling' => true,
+  'navigation' => true,
+  'parachuting' => true,
+  'paragliding' => true,
+  'passenger-association' => true,
+  'pilot' => true,
+  'press' => true,
+  'production' => true,
+  'recreation' => true,
+  'repbody' => true,
+  'res' => true,
+  'research' => true,
+  'rotorcraft' => true,
+  'safety' => true,
+  'scientist' => true,
+  'services' => true,
+  'show' => true,
+  'skydiving' => true,
+  'software' => true,
+  'student' => true,
+  'taxi' => true,
+  'trader' => true,
+  'trading' => true,
+  'trainer' => true,
+  'union' => true,
+  'workinggroup' => true,
+  'works' => true
+ ),
+ 'af' => array(
+  'gov' => true,
+  'com' => true,
+  'org' => true,
+  'net' => true,
+  'edu' => true
+ ),
+ 'ag' => array(
+  'com' => true,
+  'org' => true,
+  'net' => true,
+  'co' => true,
+  'nom' => true
+ ),
+ 'ai' => array(
+  'off' => true,
+  'com' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'al' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'mil' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'am' => true,
+ 'an' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true
+ ),
+ 'ao' => array(
+  'ed' => true,
+  'gv' => true,
+  'og' => true,
+  'co' => true,
+  'pb' => true,
+  'it' => true
+ ),
+ 'aq' => true,
+ 'ar' => array(
+  '*' => true,
+  '!congresodelalengua3' => true,
+  '!educ' => true,
+  '!gobiernoelectronico' => true,
+  '!mecon' => true,
+  '!nacion' => true,
+  '!nic' => true,
+  '!promocion' => true,
+  '!retina' => true,
+  '!uba' => true
+ ),
+ 'arpa' => array(
+  'e164' => true,
+  'in-addr' => true,
+  'ip6' => true,
+  'iris' => true,
+  'uri' => true,
+  'urn' => true
+ ),
+ 'as' => array(
+  'gov' => true
+ ),
+ 'asia' => true,
+ 'at' => array(
+  'ac' => true,
+  'co' => true,
+  'gv' => true,
+  'or' => true,
+  'biz' => true,
+  'info' => true,
+  'priv' => true
+ ),
+ 'au' => array(
+  '*' => true,
+  'edu' => array(
+   'act' => true,
+   'nsw' => true,
+   'nt' => true,
+   'qld' => true,
+   'sa' => true,
+   'tas' => true,
+   'vic' => true,
+   'wa' => true
+  ),
+  'gov' => array(
+   'act' => true,
+   'nt' => true,
+   'qld' => true,
+   'sa' => true,
+   'tas' => true,
+   'vic' => true,
+   'wa' => true
+  ),
+  'act' => true,
+  'nsw' => true,
+  'nt' => true,
+  'qld' => true,
+  'sa' => true,
+  'tas' => true,
+  'vic' => true,
+  'wa' => true
+ ),
+ 'aw' => array(
+  'com' => true
+ ),
+ 'ax' => true,
+ 'az' => array(
+  'com' => true,
+  'net' => true,
+  'int' => true,
+  'gov' => true,
+  'org' => true,
+  'edu' => true,
+  'info' => true,
+  'pp' => true,
+  'mil' => true,
+  'name' => true,
+  'pro' => true,
+  'biz' => true
+ ),
+ 'ba' => array(
+  'org' => true,
+  'net' => true,
+  'edu' => true,
+  'gov' => true,
+  'mil' => true,
+  'unsa' => true,
+  'unbi' => true,
+  'co' => true,
+  'com' => true,
+  'rs' => true
+ ),
+ 'bb' => array(
+  'biz' => true,
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'info' => true,
+  'net' => true,
+  'org' => true,
+  'store' => true
+ ),
+ 'bd' => array(
+  '*' => true
+ ),
+ 'be' => array(
+  'ac' => true
+ ),
+ 'bf' => array(
+  'gov' => true
+ ),
+ 'bg' => array(
+  'a' => true,
+  'b' => true,
+  'c' => true,
+  'd' => true,
+  'e' => true,
+  'f' => true,
+  'g' => true,
+  'h' => true,
+  'i' => true,
+  'j' => true,
+  'k' => true,
+  'l' => true,
+  'm' => true,
+  'n' => true,
+  'o' => true,
+  'p' => true,
+  'q' => true,
+  'r' => true,
+  's' => true,
+  't' => true,
+  'u' => true,
+  'v' => true,
+  'w' => true,
+  'x' => true,
+  'y' => true,
+  'z' => true,
+  '0' => true,
+  '1' => true,
+  '2' => true,
+  '3' => true,
+  '4' => true,
+  '5' => true,
+  '6' => true,
+  '7' => true,
+  '8' => true,
+  '9' => true
+ ),
+ 'bh' => array(
+  'com' => true,
+  'edu' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true
+ ),
+ 'bi' => array(
+  'co' => true,
+  'com' => true,
+  'edu' => true,
+  'or' => true,
+  'org' => true
+ ),
+ 'biz' => true,
+ 'bj' => array(
+  'asso' => true,
+  'barreau' => true,
+  'gouv' => true
+ ),
+ 'bm' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'bn' => array(
+  '*' => true
+ ),
+ 'bo' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'gob' => true,
+  'int' => true,
+  'org' => true,
+  'net' => true,
+  'mil' => true,
+  'tv' => true
+ ),
+ 'br' => array(
+  'adm' => true,
+  'adv' => true,
+  'agr' => true,
+  'am' => true,
+  'arq' => true,
+  'art' => true,
+  'ato' => true,
+  'bio' => true,
+  'blog' => true,
+  'bmd' => true,
+  'can' => true,
+  'cim' => true,
+  'cng' => true,
+  'cnt' => true,
+  'com' => true,
+  'coop' => true,
+  'ecn' => true,
+  'edu' => true,
+  'eng' => true,
+  'esp' => true,
+  'etc' => true,
+  'eti' => true,
+  'far' => true,
+  'flog' => true,
+  'fm' => true,
+  'fnd' => true,
+  'fot' => true,
+  'fst' => true,
+  'g12' => true,
+  'ggf' => true,
+  'gov' => true,
+  'imb' => true,
+  'ind' => true,
+  'inf' => true,
+  'jor' => true,
+  'jus' => true,
+  'lel' => true,
+  'mat' => true,
+  'med' => true,
+  'mil' => true,
+  'mus' => true,
+  'net' => true,
+  'nom' => true,
+  'not' => true,
+  'ntr' => true,
+  'odo' => true,
+  'org' => true,
+  'ppg' => true,
+  'pro' => true,
+  'psc' => true,
+  'psi' => true,
+  'qsl' => true,
+  'rec' => true,
+  'slg' => true,
+  'srv' => true,
+  'tmp' => true,
+  'trd' => true,
+  'tur' => true,
+  'tv' => true,
+  'vet' => true,
+  'vlog' => true,
+  'wiki' => true,
+  'zlg' => true
+ ),
+ 'bs' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true
+ ),
+ 'bt' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'bw' => array(
+  'co' => true,
+  'org' => true
+ ),
+ 'by' => array(
+  'gov' => true,
+  'mil' => true,
+  'com' => true,
+  'of' => true
+ ),
+ 'bz' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true
+ ),
+ 'ca' => array(
+  'ab' => true,
+  'bc' => true,
+  'mb' => true,
+  'nb' => true,
+  'nf' => true,
+  'nl' => true,
+  'ns' => true,
+  'nt' => true,
+  'nu' => true,
+  'on' => true,
+  'pe' => true,
+  'qc' => true,
+  'sk' => true,
+  'yk' => true,
+  'gc' => true
+ ),
+ 'cat' => true,
+ 'cc' => true,
+ 'cd' => array(
+  'gov' => true
+ ),
+ 'cf' => true,
+ 'cg' => true,
+ 'ch' => true,
+ 'ci' => array(
+  'org' => true,
+  'or' => true,
+  'com' => true,
+  'co' => true,
+  'edu' => true,
+  'ed' => true,
+  'ac' => true,
+  'net' => true,
+  'go' => true,
+  'asso' => true,
+  'aéroport' => true,
+  'int' => true,
+  'presse' => true,
+  'md' => true,
+  'gouv' => true
+ ),
+ 'ck' => array(
+  '*' => true
+ ),
+ 'cl' => array(
+  'gov' => true,
+  'gob' => true
+ ),
+ 'cm' => array(
+  'gov' => true
+ ),
+ 'cn' => array(
+  'ac' => true,
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true,
+  'mil' => true,
+  '公司' => true,
+  '网络' => true,
+  '網絡' => true,
+  'ah' => true,
+  'bj' => true,
+  'cq' => true,
+  'fj' => true,
+  'gd' => true,
+  'gs' => true,
+  'gz' => true,
+  'gx' => true,
+  'ha' => true,
+  'hb' => true,
+  'he' => true,
+  'hi' => true,
+  'hl' => true,
+  'hn' => true,
+  'jl' => true,
+  'js' => true,
+  'jx' => true,
+  'ln' => true,
+  'nm' => true,
+  'nx' => true,
+  'qh' => true,
+  'sc' => true,
+  'sd' => true,
+  'sh' => true,
+  'sn' => true,
+  'sx' => true,
+  'tj' => true,
+  'xj' => true,
+  'xz' => true,
+  'yn' => true,
+  'zj' => true,
+  'hk' => true,
+  'mo' => true,
+  'tw' => true
+ ),
+ 'co' => array(
+  'arts' => true,
+  'com' => true,
+  'edu' => true,
+  'firm' => true,
+  'gov' => true,
+  'info' => true,
+  'int' => true,
+  'mil' => true,
+  'net' => true,
+  'nom' => true,
+  'org' => true,
+  'rec' => true,
+  'web' => true
+ ),
+ 'com' => array(
+  'ar' => true,
+  'br' => true,
+  'cn' => true,
+  'de' => true,
+  'eu' => true,
+  'gb' => true,
+  'hu' => true,
+  'jpn' => true,
+  'kr' => true,
+  'no' => true,
+  'qc' => true,
+  'ru' => true,
+  'sa' => true,
+  'se' => true,
+  'uk' => true,
+  'us' => true,
+  'uy' => true,
+  'za' => true,
+  'operaunite' => true,
+  'appspot' => true
+ ),
+ 'coop' => true,
+ 'cr' => array(
+  'ac' => true,
+  'co' => true,
+  'ed' => true,
+  'fi' => true,
+  'go' => true,
+  'or' => true,
+  'sa' => true
+ ),
+ 'cu' => array(
+  'com' => true,
+  'edu' => true,
+  'org' => true,
+  'net' => true,
+  'gov' => true,
+  'inf' => true
+ ),
+ 'cv' => true,
+ 'cx' => array(
+  'gov' => true
+ ),
+ 'cy' => array(
+  '*' => true
+ ),
+ 'cz' => true,
+ 'de' => true,
+ 'dj' => true,
+ 'dk' => true,
+ 'dm' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true
+ ),
+ 'do' => array(
+  '*' => true
+ ),
+ 'dz' => array(
+  'com' => true,
+  'org' => true,
+  'net' => true,
+  'gov' => true,
+  'edu' => true,
+  'asso' => true,
+  'pol' => true,
+  'art' => true
+ ),
+ 'ec' => array(
+  'com' => true,
+  'info' => true,
+  'net' => true,
+  'fin' => true,
+  'k12' => true,
+  'med' => true,
+  'pro' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true,
+  'gob' => true,
+  'mil' => true
+ ),
+ 'edu' => true,
+ 'ee' => array(
+  'edu' => true,
+  'gov' => true,
+  'riik' => true,
+  'lib' => true,
+  'med' => true,
+  'com' => true,
+  'pri' => true,
+  'aip' => true,
+  'org' => true,
+  'fie' => true
+ ),
+ 'eg' => array(
+  '*' => true
+ ),
+ 'er' => array(
+  '*' => true
+ ),
+ 'es' => array(
+  'com' => true,
+  'nom' => true,
+  'org' => true,
+  'gob' => true,
+  'edu' => true
+ ),
+ 'et' => array(
+  '*' => true
+ ),
+ 'eu' => true,
+ 'fi' => array(
+  'aland' => true,
+  'iki' => true
+ ),
+ 'fj' => array(
+  '*' => true
+ ),
+ 'fk' => array(
+  '*' => true
+ ),
+ 'fm' => true,
+ 'fo' => true,
+ 'fr' => array(
+  'com' => true,
+  'asso' => true,
+  'nom' => true,
+  'prd' => true,
+  'presse' => true,
+  'tm' => true,
+  'aeroport' => true,
+  'assedic' => true,
+  'avocat' => true,
+  'avoues' => true,
+  'cci' => true,
+  'chambagri' => true,
+  'chirurgiens-dentistes' => true,
+  'experts-comptables' => true,
+  'geometre-expert' => true,
+  'gouv' => true,
+  'greta' => true,
+  'huissier-justice' => true,
+  'medecin' => true,
+  'notaires' => true,
+  'pharmacien' => true,
+  'port' => true,
+  'veterinaire' => true
+ ),
+ 'ga' => true,
+ 'gd' => true,
+ 'ge' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true,
+  'mil' => true,
+  'net' => true,
+  'pvt' => true
+ ),
+ 'gf' => true,
+ 'gg' => array(
+  'co' => true,
+  'org' => true,
+  'net' => true,
+  'sch' => true,
+  'gov' => true
+ ),
+ 'gh' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true,
+  'mil' => true
+ ),
+ 'gi' => array(
+  'com' => true,
+  'ltd' => true,
+  'gov' => true,
+  'mod' => true,
+  'edu' => true,
+  'org' => true
+ ),
+ 'gl' => true,
+ 'gm' => true,
+ 'gn' => array(
+  'ac' => true,
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true,
+  'net' => true
+ ),
+ 'gov' => true,
+ 'gp' => array(
+  'com' => true,
+  'net' => true,
+  'mobi' => true,
+  'edu' => true,
+  'org' => true,
+  'asso' => true
+ ),
+ 'gq' => true,
+ 'gr' => array(
+  'com' => true,
+  'edu' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true
+ ),
+ 'gs' => true,
+ 'gt' => array(
+  '*' => true
+ ),
+ 'gu' => array(
+  '*' => true
+ ),
+ 'gw' => true,
+ 'gy' => array(
+  'co' => true,
+  'com' => true,
+  'net' => true
+ ),
+ 'hk' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'idv' => true,
+  'net' => true,
+  'org' => true,
+  '公司' => true,
+  '教育' => true,
+  '敎育' => true,
+  '政府' => true,
+  '個人' => true,
+  '个人' => true,
+  '箇人' => true,
+  '網络' => true,
+  '网络' => true,
+  '组織' => true,
+  '網絡' => true,
+  '网絡' => true,
+  '组织' => true,
+  '組織' => true,
+  '組织' => true
+ ),
+ 'hm' => true,
+ 'hn' => array(
+  'com' => true,
+  'edu' => true,
+  'org' => true,
+  'net' => true,
+  'mil' => true,
+  'gob' => true
+ ),
+ 'hr' => array(
+  'iz' => true,
+  'from' => true,
+  'name' => true,
+  'com' => true
+ ),
+ 'ht' => array(
+  'com' => true,
+  'shop' => true,
+  'firm' => true,
+  'info' => true,
+  'adult' => true,
+  'net' => true,
+  'pro' => true,
+  'org' => true,
+  'med' => true,
+  'art' => true,
+  'coop' => true,
+  'pol' => true,
+  'asso' => true,
+  'edu' => true,
+  'rel' => true,
+  'gouv' => true,
+  'perso' => true
+ ),
+ 'hu' => array(
+  'co' => true,
+  'info' => true,
+  'org' => true,
+  'priv' => true,
+  'sport' => true,
+  'tm' => true,
+  '2000' => true,
+  'agrar' => true,
+  'bolt' => true,
+  'casino' => true,
+  'city' => true,
+  'erotica' => true,
+  'erotika' => true,
+  'film' => true,
+  'forum' => true,
+  'games' => true,
+  'hotel' => true,
+  'ingatlan' => true,
+  'jogasz' => true,
+  'konyvelo' => true,
+  'lakas' => true,
+  'media' => true,
+  'news' => true,
+  'reklam' => true,
+  'sex' => true,
+  'shop' => true,
+  'suli' => true,
+  'szex' => true,
+  'tozsde' => true,
+  'utazas' => true,
+  'video' => true
+ ),
+ 'id' => array(
+  'ac' => true,
+  'co' => true,
+  'go' => true,
+  'mil' => true,
+  'net' => true,
+  'or' => true,
+  'sch' => true,
+  'web' => true
+ ),
+ 'ie' => array(
+  'gov' => true
+ ),
+ 'il' => array(
+  '*' => true
+ ),
+ 'im' => array(
+  'co' => array(
+   'ltd' => true,
+   'plc' => true
+  ),
+  'net' => true,
+  'gov' => true,
+  'org' => true,
+  'nic' => true,
+  'ac' => true
+ ),
+ 'in' => array(
+  'co' => true,
+  'firm' => true,
+  'net' => true,
+  'org' => true,
+  'gen' => true,
+  'ind' => true,
+  'nic' => true,
+  'ac' => true,
+  'edu' => true,
+  'res' => true,
+  'gov' => true,
+  'mil' => true
+ ),
+ 'info' => true,
+ 'int' => array(
+  'eu' => true
+ ),
+ 'io' => array(
+  'com' => true
+ ),
+ 'iq' => array(
+  'gov' => true,
+  'edu' => true,
+  'mil' => true,
+  'com' => true,
+  'org' => true,
+  'net' => true
+ ),
+ 'ir' => array(
+  'ac' => true,
+  'co' => true,
+  'gov' => true,
+  'id' => true,
+  'net' => true,
+  'org' => true,
+  'sch' => true,
+  'ایران' => true,
+  'ايران' => true
+ ),
+ 'is' => array(
+  'net' => true,
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true,
+  'int' => true
+ ),
+ 'it' => array(
+  'gov' => true,
+  'edu' => true,
+  'agrigento' => true,
+  'ag' => true,
+  'alessandria' => true,
+  'al' => true,
+  'ancona' => true,
+  'an' => true,
+  'aosta' => true,
+  'aoste' => true,
+  'ao' => true,
+  'arezzo' => true,
+  'ar' => true,
+  'ascoli-piceno' => true,
+  'ascolipiceno' => true,
+  'ap' => true,
+  'asti' => true,
+  'at' => true,
+  'avellino' => true,
+  'av' => true,
+  'bari' => true,
+  'ba' => true,
+  'andria-barletta-trani' => true,
+  'andriabarlettatrani' => true,
+  'trani-barletta-andria' => true,
+  'tranibarlettaandria' => true,
+  'barletta-trani-andria' => true,
+  'barlettatraniandria' => true,
+  'andria-trani-barletta' => true,
+  'andriatranibarletta' => true,
+  'trani-andria-barletta' => true,
+  'traniandriabarletta' => true,
+  'bt' => true,
+  'belluno' => true,
+  'bl' => true,
+  'benevento' => true,
+  'bn' => true,
+  'bergamo' => true,
+  'bg' => true,
+  'biella' => true,
+  'bi' => true,
+  'bologna' => true,
+  'bo' => true,
+  'bolzano' => true,
+  'bozen' => true,
+  'balsan' => true,
+  'alto-adige' => true,
+  'altoadige' => true,
+  'suedtirol' => true,
+  'bz' => true,
+  'brescia' => true,
+  'bs' => true,
+  'brindisi' => true,
+  'br' => true,
+  'cagliari' => true,
+  'ca' => true,
+  'caltanissetta' => true,
+  'cl' => true,
+  'campobasso' => true,
+  'cb' => true,
+  'carboniaiglesias' => true,
+  'carbonia-iglesias' => true,
+  'iglesias-carbonia' => true,
+  'iglesiascarbonia' => true,
+  'ci' => true,
+  'caserta' => true,
+  'ce' => true,
+  'catania' => true,
+  'ct' => true,
+  'catanzaro' => true,
+  'cz' => true,
+  'chieti' => true,
+  'ch' => true,
+  'como' => true,
+  'co' => true,
+  'cosenza' => true,
+  'cs' => true,
+  'cremona' => true,
+  'cr' => true,
+  'crotone' => true,
+  'kr' => true,
+  'cuneo' => true,
+  'cn' => true,
+  'dell-ogliastra' => true,
+  'dellogliastra' => true,
+  'ogliastra' => true,
+  'og' => true,
+  'enna' => true,
+  'en' => true,
+  'ferrara' => true,
+  'fe' => true,
+  'fermo' => true,
+  'fm' => true,
+  'firenze' => true,
+  'florence' => true,
+  'fi' => true,
+  'foggia' => true,
+  'fg' => true,
+  'forli-cesena' => true,
+  'forlicesena' => true,
+  'cesena-forli' => true,
+  'cesenaforli' => true,
+  'fc' => true,
+  'frosinone' => true,
+  'fr' => true,
+  'genova' => true,
+  'genoa' => true,
+  'ge' => true,
+  'gorizia' => true,
+  'go' => true,
+  'grosseto' => true,
+  'gr' => true,
+  'imperia' => true,
+  'im' => true,
+  'isernia' => true,
+  'is' => true,
+  'laquila' => true,
+  'aquila' => true,
+  'aq' => true,
+  'la-spezia' => true,
+  'laspezia' => true,
+  'sp' => true,
+  'latina' => true,
+  'lt' => true,
+  'lecce' => true,
+  'le' => true,
+  'lecco' => true,
+  'lc' => true,
+  'livorno' => true,
+  'li' => true,
+  'lodi' => true,
+  'lo' => true,
+  'lucca' => true,
+  'lu' => true,
+  'macerata' => true,
+  'mc' => true,
+  'mantova' => true,
+  'mn' => true,
+  'massa-carrara' => true,
+  'massacarrara' => true,
+  'carrara-massa' => true,
+  'carraramassa' => true,
+  'ms' => true,
+  'matera' => true,
+  'mt' => true,
+  'medio-campidano' => true,
+  'mediocampidano' => true,
+  'campidano-medio' => true,
+  'campidanomedio' => true,
+  'vs' => true,
+  'messina' => true,
+  'me' => true,
+  'milano' => true,
+  'milan' => true,
+  'mi' => true,
+  'modena' => true,
+  'mo' => true,
+  'monza' => true,
+  'monza-brianza' => true,
+  'monzabrianza' => true,
+  'monzaebrianza' => true,
+  'monzaedellabrianza' => true,
+  'monza-e-della-brianza' => true,
+  'mb' => true,
+  'napoli' => true,
+  'naples' => true,
+  'na' => true,
+  'novara' => true,
+  'no' => true,
+  'nuoro' => true,
+  'nu' => true,
+  'oristano' => true,
+  'or' => true,
+  'padova' => true,
+  'padua' => true,
+  'pd' => true,
+  'palermo' => true,
+  'pa' => true,
+  'parma' => true,
+  'pr' => true,
+  'pavia' => true,
+  'pv' => true,
+  'perugia' => true,
+  'pg' => true,
+  'pescara' => true,
+  'pe' => true,
+  'pesaro-urbino' => true,
+  'pesarourbino' => true,
+  'urbino-pesaro' => true,
+  'urbinopesaro' => true,
+  'pu' => true,
+  'piacenza' => true,
+  'pc' => true,
+  'pisa' => true,
+  'pi' => true,
+  'pistoia' => true,
+  'pt' => true,
+  'pordenone' => true,
+  'pn' => true,
+  'potenza' => true,
+  'pz' => true,
+  'prato' => true,
+  'po' => true,
+  'ragusa' => true,
+  'rg' => true,
+  'ravenna' => true,
+  'ra' => true,
+  'reggio-calabria' => true,
+  'reggiocalabria' => true,
+  'rc' => true,
+  'reggio-emilia' => true,
+  'reggioemilia' => true,
+  're' => true,
+  'rieti' => true,
+  'ri' => true,
+  'rimini' => true,
+  'rn' => true,
+  'roma' => true,
+  'rome' => true,
+  'rm' => true,
+  'rovigo' => true,
+  'ro' => true,
+  'salerno' => true,
+  'sa' => true,
+  'sassari' => true,
+  'ss' => true,
+  'savona' => true,
+  'sv' => true,
+  'siena' => true,
+  'si' => true,
+  'siracusa' => true,
+  'sr' => true,
+  'sondrio' => true,
+  'so' => true,
+  'taranto' => true,
+  'ta' => true,
+  'tempio-olbia' => true,
+  'tempioolbia' => true,
+  'olbia-tempio' => true,
+  'olbiatempio' => true,
+  'ot' => true,
+  'teramo' => true,
+  'te' => true,
+  'terni' => true,
+  'tr' => true,
+  'torino' => true,
+  'turin' => true,
+  'to' => true,
+  'trapani' => true,
+  'tp' => true,
+  'trento' => true,
+  'trentino' => true,
+  'tn' => true,
+  'treviso' => true,
+  'tv' => true,
+  'trieste' => true,
+  'ts' => true,
+  'udine' => true,
+  'ud' => true,
+  'varese' => true,
+  'va' => true,
+  'venezia' => true,
+  'venice' => true,
+  've' => true,
+  'verbania' => true,
+  'vb' => true,
+  'vercelli' => true,
+  'vc' => true,
+  'verona' => true,
+  'vr' => true,
+  'vibo-valentia' => true,
+  'vibovalentia' => true,
+  'vv' => true,
+  'vicenza' => true,
+  'vi' => true,
+  'viterbo' => true,
+  'vt' => true
+ ),
+ 'je' => array(
+  'co' => true,
+  'org' => true,
+  'net' => true,
+  'sch' => true,
+  'gov' => true
+ ),
+ 'jm' => array(
+  '*' => true
+ ),
+ 'jo' => array(
+  'com' => true,
+  'org' => true,
+  'net' => true,
+  'edu' => true,
+  'sch' => true,
+  'gov' => true,
+  'mil' => true,
+  'name' => true
+ ),
+ 'jobs' => true,
+ 'jp' => array(
+  'ac' => true,
+  'ad' => true,
+  'co' => true,
+  'ed' => true,
+  'go' => true,
+  'gr' => true,
+  'lg' => true,
+  'ne' => true,
+  'or' => true,
+  'aichi' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'akita' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'aomori' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'chiba' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'ehime' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'fukui' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'fukuoka' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'fukushima' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'gifu' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'gunma' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'hiroshima' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'hokkaido' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'hyogo' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'ibaraki' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'ishikawa' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'iwate' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'kagawa' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'kagoshima' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'kanagawa' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'kawasaki' => array(
+   '*' => true,
+   '!city' => true
+  ),
+  'kitakyushu' => array(
+   '*' => true,
+   '!city' => true
+  ),
+  'kobe' => array(
+   '*' => true,
+   '!city' => true
+  ),
+  'kochi' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'kumamoto' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'kyoto' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'mie' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'miyagi' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'miyazaki' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'nagano' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'nagasaki' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'nagoya' => array(
+   '*' => true,
+   '!city' => true
+  ),
+  'nara' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'niigata' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'oita' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'okayama' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'okinawa' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'osaka' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'saga' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'saitama' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'sapporo' => array(
+   '*' => true,
+   '!city' => true
+  ),
+  'sendai' => array(
+   '*' => true,
+   '!city' => true
+  ),
+  'shiga' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'shimane' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'shizuoka' => array(
+   '*' => true,
+   '!pref' => true,
+   '!city' => true
+  ),
+  'tochigi' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'tokushima' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'tokyo' => array(
+   '*' => true,
+   '!metro' => true
+  ),
+  'tottori' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'toyama' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'wakayama' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'yamagata' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'yamaguchi' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'yamanashi' => array(
+   '*' => true,
+   '!pref' => true
+  ),
+  'yokohama' => array(
+   '*' => true,
+   '!city' => true
+  )
+ ),
+ 'ke' => array(
+  '*' => true
+ ),
+ 'kg' => array(
+  'org' => true,
+  'net' => true,
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'mil' => true
+ ),
+ 'kh' => array(
+  '*' => true
+ ),
+ 'ki' => array(
+  'edu' => true,
+  'biz' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'info' => true,
+  'com' => true
+ ),
+ 'km' => array(
+  'org' => true,
+  'nom' => true,
+  'gov' => true,
+  'prd' => true,
+  'tm' => true,
+  'edu' => true,
+  'mil' => true,
+  'ass' => true,
+  'com' => true,
+  'coop' => true,
+  'asso' => true,
+  'presse' => true,
+  'medecin' => true,
+  'notaires' => true,
+  'pharmaciens' => true,
+  'veterinaire' => true,
+  'gouv' => true
+ ),
+ 'kn' => array(
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true
+ ),
+ 'kp' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true,
+  'rep' => true,
+  'tra' => true
+ ),
+ 'kr' => array(
+  'ac' => true,
+  'co' => true,
+  'es' => true,
+  'go' => true,
+  'hs' => true,
+  'kg' => true,
+  'mil' => true,
+  'ms' => true,
+  'ne' => true,
+  'or' => true,
+  'pe' => true,
+  're' => true,
+  'sc' => true,
+  'busan' => true,
+  'chungbuk' => true,
+  'chungnam' => true,
+  'daegu' => true,
+  'daejeon' => true,
+  'gangwon' => true,
+  'gwangju' => true,
+  'gyeongbuk' => true,
+  'gyeonggi' => true,
+  'gyeongnam' => true,
+  'incheon' => true,
+  'jeju' => true,
+  'jeonbuk' => true,
+  'jeonnam' => true,
+  'seoul' => true,
+  'ulsan' => true
+ ),
+ 'kw' => array(
+  '*' => true
+ ),
+ 'ky' => array(
+  'edu' => true,
+  'gov' => true,
+  'com' => true,
+  'org' => true,
+  'net' => true
+ ),
+ 'kz' => array(
+  'org' => true,
+  'edu' => true,
+  'net' => true,
+  'gov' => true,
+  'mil' => true,
+  'com' => true
+ ),
+ 'la' => array(
+  'int' => true,
+  'net' => true,
+  'info' => true,
+  'edu' => true,
+  'gov' => true,
+  'per' => true,
+  'com' => true,
+  'org' => true,
+  'c' => true
+ ),
+ 'lb' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'lc' => array(
+  'com' => true,
+  'net' => true,
+  'co' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true
+ ),
+ 'li' => true,
+ 'lk' => array(
+  'gov' => true,
+  'sch' => true,
+  'net' => true,
+  'int' => true,
+  'com' => true,
+  'org' => true,
+  'edu' => true,
+  'ngo' => true,
+  'soc' => true,
+  'web' => true,
+  'ltd' => true,
+  'assn' => true,
+  'grp' => true,
+  'hotel' => true
+ ),
+ 'local' => true,
+ 'lr' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true,
+  'net' => true
+ ),
+ 'ls' => array(
+  'co' => true,
+  'org' => true
+ ),
+ 'lt' => array(
+  'gov' => true
+ ),
+ 'lu' => true,
+ 'lv' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true,
+  'mil' => true,
+  'id' => true,
+  'net' => true,
+  'asn' => true,
+  'conf' => true
+ ),
+ 'ly' => array(
+  'com' => true,
+  'net' => true,
+  'gov' => true,
+  'plc' => true,
+  'edu' => true,
+  'sch' => true,
+  'med' => true,
+  'org' => true,
+  'id' => true
+ ),
+ 'ma' => array(
+  'co' => true,
+  'net' => true,
+  'gov' => true,
+  'org' => true,
+  'ac' => true,
+  'press' => true
+ ),
+ 'mc' => array(
+  'tm' => true,
+  'asso' => true
+ ),
+ 'md' => true,
+ 'me' => array(
+  'co' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'ac' => true,
+  'gov' => true,
+  'its' => true,
+  'priv' => true
+ ),
+ 'mg' => array(
+  'org' => true,
+  'nom' => true,
+  'gov' => true,
+  'prd' => true,
+  'tm' => true,
+  'edu' => true,
+  'mil' => true,
+  'com' => true
+ ),
+ 'mh' => true,
+ 'mil' => true,
+ 'mk' => array(
+  'com' => true,
+  'org' => true,
+  'net' => true,
+  'edu' => true,
+  'gov' => true,
+  'inf' => true,
+  'name' => true
+ ),
+ 'ml' => array(
+  'com' => true,
+  'edu' => true,
+  'gouv' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true,
+  'presse' => true
+ ),
+ 'mm' => array(
+  '*' => true
+ ),
+ 'mn' => array(
+  'gov' => true,
+  'edu' => true,
+  'org' => true
+ ),
+ 'mo' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true
+ ),
+ 'mobi' => true,
+ 'mp' => true,
+ 'mq' => true,
+ 'mr' => array(
+  'gov' => true
+ ),
+ 'ms' => true,
+ 'mt' => array(
+  '*' => true
+ ),
+ 'mu' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'ac' => true,
+  'co' => true,
+  'or' => true
+ ),
+ 'museum' => array(
+  'academy' => true,
+  'agriculture' => true,
+  'air' => true,
+  'airguard' => true,
+  'alabama' => true,
+  'alaska' => true,
+  'amber' => true,
+  'ambulance' => true,
+  'american' => true,
+  'americana' => true,
+  'americanantiques' => true,
+  'americanart' => true,
+  'amsterdam' => true,
+  'and' => true,
+  'annefrank' => true,
+  'anthro' => true,
+  'anthropology' => true,
+  'antiques' => true,
+  'aquarium' => true,
+  'arboretum' => true,
+  'archaeological' => true,
+  'archaeology' => true,
+  'architecture' => true,
+  'art' => true,
+  'artanddesign' => true,
+  'artcenter' => true,
+  'artdeco' => true,
+  'arteducation' => true,
+  'artgallery' => true,
+  'arts' => true,
+  'artsandcrafts' => true,
+  'asmatart' => true,
+  'assassination' => true,
+  'assisi' => true,
+  'association' => true,
+  'astronomy' => true,
+  'atlanta' => true,
+  'austin' => true,
+  'australia' => true,
+  'automotive' => true,
+  'aviation' => true,
+  'axis' => true,
+  'badajoz' => true,
+  'baghdad' => true,
+  'bahn' => true,
+  'bale' => true,
+  'baltimore' => true,
+  'barcelona' => true,
+  'baseball' => true,
+  'basel' => true,
+  'baths' => true,
+  'bauern' => true,
+  'beauxarts' => true,
+  'beeldengeluid' => true,
+  'bellevue' => true,
+  'bergbau' => true,
+  'berkeley' => true,
+  'berlin' => true,
+  'bern' => true,
+  'bible' => true,
+  'bilbao' => true,
+  'bill' => true,
+  'birdart' => true,
+  'birthplace' => true,
+  'bonn' => true,
+  'boston' => true,
+  'botanical' => true,
+  'botanicalgarden' => true,
+  'botanicgarden' => true,
+  'botany' => true,
+  'brandywinevalley' => true,
+  'brasil' => true,
+  'bristol' => true,
+  'british' => true,
+  'britishcolumbia' => true,
+  'broadcast' => true,
+  'brunel' => true,
+  'brussel' => true,
+  'brussels' => true,
+  'bruxelles' => true,
+  'building' => true,
+  'burghof' => true,
+  'bus' => true,
+  'bushey' => true,
+  'cadaques' => true,
+  'california' => true,
+  'cambridge' => true,
+  'can' => true,
+  'canada' => true,
+  'capebreton' => true,
+  'carrier' => true,
+  'cartoonart' => true,
+  'casadelamoneda' => true,
+  'castle' => true,
+  'castres' => true,
+  'celtic' => true,
+  'center' => true,
+  'chattanooga' => true,
+  'cheltenham' => true,
+  'chesapeakebay' => true,
+  'chicago' => true,
+  'children' => true,
+  'childrens' => true,
+  'childrensgarden' => true,
+  'chiropractic' => true,
+  'chocolate' => true,
+  'christiansburg' => true,
+  'cincinnati' => true,
+  'cinema' => true,
+  'circus' => true,
+  'civilisation' => true,
+  'civilization' => true,
+  'civilwar' => true,
+  'clinton' => true,
+  'clock' => true,
+  'coal' => true,
+  'coastaldefence' => true,
+  'cody' => true,
+  'coldwar' => true,
+  'collection' => true,
+  'colonialwilliamsburg' => true,
+  'coloradoplateau' => true,
+  'columbia' => true,
+  'columbus' => true,
+  'communication' => true,
+  'communications' => true,
+  'community' => true,
+  'computer' => true,
+  'computerhistory' => true,
+  'comunicações' => true,
+  'contemporary' => true,
+  'contemporaryart' => true,
+  'convent' => true,
+  'copenhagen' => true,
+  'corporation' => true,
+  'correios-e-telecomunicações' => true,
+  'corvette' => true,
+  'costume' => true,
+  'countryestate' => true,
+  'county' => true,
+  'crafts' => true,
+  'cranbrook' => true,
+  'creation' => true,
+  'cultural' => true,
+  'culturalcenter' => true,
+  'culture' => true,
+  'cyber' => true,
+  'cymru' => true,
+  'dali' => true,
+  'dallas' => true,
+  'database' => true,
+  'ddr' => true,
+  'decorativearts' => true,
+  'delaware' => true,
+  'delmenhorst' => true,
+  'denmark' => true,
+  'depot' => true,
+  'design' => true,
+  'detroit' => true,
+  'dinosaur' => true,
+  'discovery' => true,
+  'dolls' => true,
+  'donostia' => true,
+  'durham' => true,
+  'eastafrica' => true,
+  'eastcoast' => true,
+  'education' => true,
+  'educational' => true,
+  'egyptian' => true,
+  'eisenbahn' => true,
+  'elburg' => true,
+  'elvendrell' => true,
+  'embroidery' => true,
+  'encyclopedic' => true,
+  'england' => true,
+  'entomology' => true,
+  'environment' => true,
+  'environmentalconservation' => true,
+  'epilepsy' => true,
+  'essex' => true,
+  'estate' => true,
+  'ethnology' => true,
+  'exeter' => true,
+  'exhibition' => true,
+  'family' => true,
+  'farm' => true,
+  'farmequipment' => true,
+  'farmers' => true,
+  'farmstead' => true,
+  'field' => true,
+  'figueres' => true,
+  'filatelia' => true,
+  'film' => true,
+  'fineart' => true,
+  'finearts' => true,
+  'finland' => true,
+  'flanders' => true,
+  'florida' => true,
+  'force' => true,
+  'fortmissoula' => true,
+  'fortworth' => true,
+  'foundation' => true,
+  'francaise' => true,
+  'frankfurt' => true,
+  'franziskaner' => true,
+  'freemasonry' => true,
+  'freiburg' => true,
+  'fribourg' => true,
+  'frog' => true,
+  'fundacio' => true,
+  'furniture' => true,
+  'gallery' => true,
+  'garden' => true,
+  'gateway' => true,
+  'geelvinck' => true,
+  'gemological' => true,
+  'geology' => true,
+  'georgia' => true,
+  'giessen' => true,
+  'glas' => true,
+  'glass' => true,
+  'gorge' => true,
+  'grandrapids' => true,
+  'graz' => true,
+  'guernsey' => true,
+  'halloffame' => true,
+  'hamburg' => true,
+  'handson' => true,
+  'harvestcelebration' => true,
+  'hawaii' => true,
+  'health' => true,
+  'heimatunduhren' => true,
+  'hellas' => true,
+  'helsinki' => true,
+  'hembygdsforbund' => true,
+  'heritage' => true,
+  'histoire' => true,
+  'historical' => true,
+  'historicalsociety' => true,
+  'historichouses' => true,
+  'historisch' => true,
+  'historisches' => true,
+  'history' => true,
+  'historyofscience' => true,
+  'horology' => true,
+  'house' => true,
+  'humanities' => true,
+  'illustration' => true,
+  'imageandsound' => true,
+  'indian' => true,
+  'indiana' => true,
+  'indianapolis' => true,
+  'indianmarket' => true,
+  'intelligence' => true,
+  'interactive' => true,
+  'iraq' => true,
+  'iron' => true,
+  'isleofman' => true,
+  'jamison' => true,
+  'jefferson' => true,
+  'jerusalem' => true,
+  'jewelry' => true,
+  'jewish' => true,
+  'jewishart' => true,
+  'jfk' => true,
+  'journalism' => true,
+  'judaica' => true,
+  'judygarland' => true,
+  'juedisches' => true,
+  'juif' => true,
+  'karate' => true,
+  'karikatur' => true,
+  'kids' => true,
+  'koebenhavn' => true,
+  'koeln' => true,
+  'kunst' => true,
+  'kunstsammlung' => true,
+  'kunstunddesign' => true,
+  'labor' => true,
+  'labour' => true,
+  'lajolla' => true,
+  'lancashire' => true,
+  'landes' => true,
+  'lans' => true,
+  'läns' => true,
+  'larsson' => true,
+  'lewismiller' => true,
+  'lincoln' => true,
+  'linz' => true,
+  'living' => true,
+  'livinghistory' => true,
+  'localhistory' => true,
+  'london' => true,
+  'losangeles' => true,
+  'louvre' => true,
+  'loyalist' => true,
+  'lucerne' => true,
+  'luxembourg' => true,
+  'luzern' => true,
+  'mad' => true,
+  'madrid' => true,
+  'mallorca' => true,
+  'manchester' => true,
+  'mansion' => true,
+  'mansions' => true,
+  'manx' => true,
+  'marburg' => true,
+  'maritime' => true,
+  'maritimo' => true,
+  'maryland' => true,
+  'marylhurst' => true,
+  'media' => true,
+  'medical' => true,
+  'medizinhistorisches' => true,
+  'meeres' => true,
+  'memorial' => true,
+  'mesaverde' => true,
+  'michigan' => true,
+  'midatlantic' => true,
+  'military' => true,
+  'mill' => true,
+  'miners' => true,
+  'mining' => true,
+  'minnesota' => true,
+  'missile' => true,
+  'missoula' => true,
+  'modern' => true,
+  'moma' => true,
+  'money' => true,
+  'monmouth' => true,
+  'monticello' => true,
+  'montreal' => true,
+  'moscow' => true,
+  'motorcycle' => true,
+  'muenchen' => true,
+  'muenster' => true,
+  'mulhouse' => true,
+  'muncie' => true,
+  'museet' => true,
+  'museumcenter' => true,
+  'museumvereniging' => true,
+  'music' => true,
+  'national' => true,
+  'nationalfirearms' => true,
+  'nationalheritage' => true,
+  'nativeamerican' => true,
+  'naturalhistory' => true,
+  'naturalhistorymuseum' => true,
+  'naturalsciences' => true,
+  'nature' => true,
+  'naturhistorisches' => true,
+  'natuurwetenschappen' => true,
+  'naumburg' => true,
+  'naval' => true,
+  'nebraska' => true,
+  'neues' => true,
+  'newhampshire' => true,
+  'newjersey' => true,
+  'newmexico' => true,
+  'newport' => true,
+  'newspaper' => true,
+  'newyork' => true,
+  'niepce' => true,
+  'norfolk' => true,
+  'north' => true,
+  'nrw' => true,
+  'nuernberg' => true,
+  'nuremberg' => true,
+  'nyc' => true,
+  'nyny' => true,
+  'oceanographic' => true,
+  'oceanographique' => true,
+  'omaha' => true,
+  'online' => true,
+  'ontario' => true,
+  'openair' => true,
+  'oregon' => true,
+  'oregontrail' => true,
+  'otago' => true,
+  'oxford' => true,
+  'pacific' => true,
+  'paderborn' => true,
+  'palace' => true,
+  'paleo' => true,
+  'palmsprings' => true,
+  'panama' => true,
+  'paris' => true,
+  'pasadena' => true,
+  'pharmacy' => true,
+  'philadelphia' => true,
+  'philadelphiaarea' => true,
+  'philately' => true,
+  'phoenix' => true,
+  'photography' => true,
+  'pilots' => true,
+  'pittsburgh' => true,
+  'planetarium' => true,
+  'plantation' => true,
+  'plants' => true,
+  'plaza' => true,
+  'portal' => true,
+  'portland' => true,
+  'portlligat' => true,
+  'posts-and-telecommunications' => true,
+  'preservation' => true,
+  'presidio' => true,
+  'press' => true,
+  'project' => true,
+  'public' => true,
+  'pubol' => true,
+  'quebec' => true,
+  'railroad' => true,
+  'railway' => true,
+  'research' => true,
+  'resistance' => true,
+  'riodejaneiro' => true,
+  'rochester' => true,
+  'rockart' => true,
+  'roma' => true,
+  'russia' => true,
+  'saintlouis' => true,
+  'salem' => true,
+  'salvadordali' => true,
+  'salzburg' => true,
+  'sandiego' => true,
+  'sanfrancisco' => true,
+  'santabarbara' => true,
+  'santacruz' => true,
+  'santafe' => true,
+  'saskatchewan' => true,
+  'satx' => true,
+  'savannahga' => true,
+  'schlesisches' => true,
+  'schoenbrunn' => true,
+  'schokoladen' => true,
+  'school' => true,
+  'schweiz' => true,
+  'science' => true,
+  'scienceandhistory' => true,
+  'scienceandindustry' => true,
+  'sciencecenter' => true,
+  'sciencecenters' => true,
+  'science-fiction' => true,
+  'sciencehistory' => true,
+  'sciences' => true,
+  'sciencesnaturelles' => true,
+  'scotland' => true,
+  'seaport' => true,
+  'settlement' => true,
+  'settlers' => true,
+  'shell' => true,
+  'sherbrooke' => true,
+  'sibenik' => true,
+  'silk' => true,
+  'ski' => true,
+  'skole' => true,
+  'society' => true,
+  'sologne' => true,
+  'soundandvision' => true,
+  'southcarolina' => true,
+  'southwest' => true,
+  'space' => true,
+  'spy' => true,
+  'square' => true,
+  'stadt' => true,
+  'stalbans' => true,
+  'starnberg' => true,
+  'state' => true,
+  'stateofdelaware' => true,
+  'station' => true,
+  'steam' => true,
+  'steiermark' => true,
+  'stjohn' => true,
+  'stockholm' => true,
+  'stpetersburg' => true,
+  'stuttgart' => true,
+  'suisse' => true,
+  'surgeonshall' => true,
+  'surrey' => true,
+  'svizzera' => true,
+  'sweden' => true,
+  'sydney' => true,
+  'tank' => true,
+  'tcm' => true,
+  'technology' => true,
+  'telekommunikation' => true,
+  'television' => true,
+  'texas' => true,
+  'textile' => true,
+  'theater' => true,
+  'time' => true,
+  'timekeeping' => true,
+  'topology' => true,
+  'torino' => true,
+  'touch' => true,
+  'town' => true,
+  'transport' => true,
+  'tree' => true,
+  'trolley' => true,
+  'trust' => true,
+  'trustee' => true,
+  'uhren' => true,
+  'ulm' => true,
+  'undersea' => true,
+  'university' => true,
+  'usa' => true,
+  'usantiques' => true,
+  'usarts' => true,
+  'uscountryestate' => true,
+  'usculture' => true,
+  'usdecorativearts' => true,
+  'usgarden' => true,
+  'ushistory' => true,
+  'ushuaia' => true,
+  'uslivinghistory' => true,
+  'utah' => true,
+  'uvic' => true,
+  'valley' => true,
+  'vantaa' => true,
+  'versailles' => true,
+  'viking' => true,
+  'village' => true,
+  'virginia' => true,
+  'virtual' => true,
+  'virtuel' => true,
+  'vlaanderen' => true,
+  'volkenkunde' => true,
+  'wales' => true,
+  'wallonie' => true,
+  'war' => true,
+  'washingtondc' => true,
+  'watchandclock' => true,
+  'watch-and-clock' => true,
+  'western' => true,
+  'westfalen' => true,
+  'whaling' => true,
+  'wildlife' => true,
+  'williamsburg' => true,
+  'windmill' => true,
+  'workshop' => true,
+  'york' => true,
+  'yorkshire' => true,
+  'yosemite' => true,
+  'youth' => true,
+  'zoological' => true,
+  'zoology' => true,
+  'ירושלים' => true,
+  'иком' => true
+ ),
+ 'mv' => array(
+  'aero' => true,
+  'biz' => true,
+  'com' => true,
+  'coop' => true,
+  'edu' => true,
+  'gov' => true,
+  'info' => true,
+  'int' => true,
+  'mil' => true,
+  'museum' => true,
+  'name' => true,
+  'net' => true,
+  'org' => true,
+  'pro' => true
+ ),
+ 'mw' => array(
+  'ac' => true,
+  'biz' => true,
+  'co' => true,
+  'com' => true,
+  'coop' => true,
+  'edu' => true,
+  'gov' => true,
+  'int' => true,
+  'museum' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'mx' => array(
+  'com' => true,
+  'org' => true,
+  'gob' => true,
+  'edu' => true,
+  'net' => true
+ ),
+ 'my' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'edu' => true,
+  'mil' => true,
+  'name' => true
+ ),
+ 'mz' => array(
+  '*' => true
+ ),
+ 'na' => array(
+  'info' => true,
+  'pro' => true,
+  'name' => true,
+  'school' => true,
+  'or' => true,
+  'dr' => true,
+  'us' => true,
+  'mx' => true,
+  'ca' => true,
+  'in' => true,
+  'cc' => true,
+  'tv' => true,
+  'ws' => true,
+  'mobi' => true,
+  'co' => true,
+  'com' => true,
+  'org' => true
+ ),
+ 'name' => true,
+ 'nc' => array(
+  'asso' => true
+ ),
+ 'ne' => true,
+ 'net' => array(
+  'gb' => true,
+  'se' => true,
+  'uk' => true,
+  'za' => true
+ ),
+ 'nf' => array(
+  'com' => true,
+  'net' => true,
+  'per' => true,
+  'rec' => true,
+  'web' => true,
+  'arts' => true,
+  'firm' => true,
+  'info' => true,
+  'other' => true,
+  'store' => true
+ ),
+ 'ng' => array(
+  'ac' => true,
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'ni' => array(
+  '*' => true
+ ),
+ 'nl' => array(
+  'bv' => true
+ ),
+ 'no' => array(
+  'fhs' => true,
+  'vgs' => true,
+  'fylkesbibl' => true,
+  'folkebibl' => true,
+  'museum' => true,
+  'idrett' => true,
+  'priv' => true,
+  'mil' => true,
+  'stat' => true,
+  'dep' => true,
+  'kommune' => true,
+  'herad' => true,
+  'aa' => array(
+   'gs' => true
+  ),
+  'ah' => array(
+   'gs' => true
+  ),
+  'bu' => array(
+   'gs' => true
+  ),
+  'fm' => array(
+   'gs' => true
+  ),
+  'hl' => array(
+   'gs' => true
+  ),
+  'hm' => array(
+   'gs' => true
+  ),
+  'jan-mayen' => array(
+   'gs' => true
+  ),
+  'mr' => array(
+   'gs' => true
+  ),
+  'nl' => array(
+   'gs' => true
+  ),
+  'nt' => array(
+   'gs' => true
+  ),
+  'of' => array(
+   'gs' => true
+  ),
+  'ol' => array(
+   'gs' => true
+  ),
+  'oslo' => array(
+   'gs' => true
+  ),
+  'rl' => array(
+   'gs' => true
+  ),
+  'sf' => array(
+   'gs' => true
+  ),
+  'st' => array(
+   'gs' => true
+  ),
+  'svalbard' => array(
+   'gs' => true
+  ),
+  'tm' => array(
+   'gs' => true
+  ),
+  'tr' => array(
+   'gs' => true
+  ),
+  'va' => array(
+   'gs' => true
+  ),
+  'vf' => array(
+   'gs' => true
+  ),
+  'akrehamn' => true,
+  'åkrehamn' => true,
+  'algard' => true,
+  'ålgård' => true,
+  'arna' => true,
+  'brumunddal' => true,
+  'bryne' => true,
+  'bronnoysund' => true,
+  'brønnøysund' => true,
+  'drobak' => true,
+  'drøbak' => true,
+  'egersund' => true,
+  'fetsund' => true,
+  'floro' => true,
+  'florø' => true,
+  'fredrikstad' => true,
+  'hokksund' => true,
+  'honefoss' => true,
+  'hønefoss' => true,
+  'jessheim' => true,
+  'jorpeland' => true,
+  'jørpeland' => true,
+  'kirkenes' => true,
+  'kopervik' => true,
+  'krokstadelva' => true,
+  'langevag' => true,
+  'langevåg' => true,
+  'leirvik' => true,
+  'mjondalen' => true,
+  'mjøndalen' => true,
+  'mo-i-rana' => true,
+  'mosjoen' => true,
+  'mosjøen' => true,
+  'nesoddtangen' => true,
+  'orkanger' => true,
+  'osoyro' => true,
+  'osøyro' => true,
+  'raholt' => true,
+  'råholt' => true,
+  'sandnessjoen' => true,
+  'sandnessjøen' => true,
+  'skedsmokorset' => true,
+  'slattum' => true,
+  'spjelkavik' => true,
+  'stathelle' => true,
+  'stavern' => true,
+  'stjordalshalsen' => true,
+  'stjørdalshalsen' => true,
+  'tananger' => true,
+  'tranby' => true,
+  'vossevangen' => true,
+  'afjord' => true,
+  'åfjord' => true,
+  'agdenes' => true,
+  'al' => true,
+  'ål' => true,
+  'alesund' => true,
+  'ålesund' => true,
+  'alstahaug' => true,
+  'alta' => true,
+  'áltá' => true,
+  'alaheadju' => true,
+  'álaheadju' => true,
+  'alvdal' => true,
+  'amli' => true,
+  'åmli' => true,
+  'amot' => true,
+  'åmot' => true,
+  'andebu' => true,
+  'andoy' => true,
+  'andøy' => true,
+  'andasuolo' => true,
+  'ardal' => true,
+  'årdal' => true,
+  'aremark' => true,
+  'arendal' => true,
+  'ås' => true,
+  'aseral' => true,
+  'åseral' => true,
+  'asker' => true,
+  'askim' => true,
+  'askvoll' => true,
+  'askoy' => true,
+  'askøy' => true,
+  'asnes' => true,
+  'åsnes' => true,
+  'audnedaln' => true,
+  'aukra' => true,
+  'aure' => true,
+  'aurland' => true,
+  'aurskog-holand' => true,
+  'aurskog-høland' => true,
+  'austevoll' => true,
+  'austrheim' => true,
+  'averoy' => true,
+  'averøy' => true,
+  'balestrand' => true,
+  'ballangen' => true,
+  'balat' => true,
+  'bálát' => true,
+  'balsfjord' => true,
+  'bahccavuotna' => true,
+  'báhccavuotna' => true,
+  'bamble' => true,
+  'bardu' => true,
+  'beardu' => true,
+  'beiarn' => true,
+  'bajddar' => true,
+  'bájddar' => true,
+  'baidar' => true,
+  'báidár' => true,
+  'berg' => true,
+  'bergen' => true,
+  'berlevag' => true,
+  'berlevåg' => true,
+  'bearalvahki' => true,
+  'bearalváhki' => true,
+  'bindal' => true,
+  'birkenes' => true,
+  'bjarkoy' => true,
+  'bjarkøy' => true,
+  'bjerkreim' => true,
+  'bjugn' => true,
+  'bodo' => true,
+  'bodø' => true,
+  'badaddja' => true,
+  'bådåddjå' => true,
+  'budejju' => true,
+  'bokn' => true,
+  'bremanger' => true,
+  'bronnoy' => true,
+  'brønnøy' => true,
+  'bygland' => true,
+  'bykle' => true,
+  'barum' => true,
+  'bærum' => true,
+  'telemark' => array(
+   'bo' => true,
+   'bø' => true
+  ),
+  'nordland' => array(
+   'bo' => true,
+   'bø' => true,
+   'heroy' => true,
+   'herøy' => true
+  ),
+  'bievat' => true,
+  'bievát' => true,
+  'bomlo' => true,
+  'bømlo' => true,
+  'batsfjord' => true,
+  'båtsfjord' => true,
+  'bahcavuotna' => true,
+  'báhcavuotna' => true,
+  'dovre' => true,
+  'drammen' => true,
+  'drangedal' => true,
+  'dyroy' => true,
+  'dyrøy' => true,
+  'donna' => true,
+  'dønna' => true,
+  'eid' => true,
+  'eidfjord' => true,
+  'eidsberg' => true,
+  'eidskog' => true,
+  'eidsvoll' => true,
+  'eigersund' => true,
+  'elverum' => true,
+  'enebakk' => true,
+  'engerdal' => true,
+  'etne' => true,
+  'etnedal' => true,
+  'evenes' => true,
+  'evenassi' => true,
+  'evenášši' => true,
+  'evje-og-hornnes' => true,
+  'farsund' => true,
+  'fauske' => true,
+  'fuossko' => true,
+  'fuoisku' => true,
+  'fedje' => true,
+  'fet' => true,
+  'finnoy' => true,
+  'finnøy' => true,
+  'fitjar' => true,
+  'fjaler' => true,
+  'fjell' => true,
+  'flakstad' => true,
+  'flatanger' => true,
+  'flekkefjord' => true,
+  'flesberg' => true,
+  'flora' => true,
+  'fla' => true,
+  'flå' => true,
+  'folldal' => true,
+  'forsand' => true,
+  'fosnes' => true,
+  'frei' => true,
+  'frogn' => true,
+  'froland' => true,
+  'frosta' => true,
+  'frana' => true,
+  'fræna' => true,
+  'froya' => true,
+  'frøya' => true,
+  'fusa' => true,
+  'fyresdal' => true,
+  'forde' => true,
+  'førde' => true,
+  'gamvik' => true,
+  'gangaviika' => true,
+  'gáŋgaviika' => true,
+  'gaular' => true,
+  'gausdal' => true,
+  'gildeskal' => true,
+  'gildeskål' => true,
+  'giske' => true,
+  'gjemnes' => true,
+  'gjerdrum' => true,
+  'gjerstad' => true,
+  'gjesdal' => true,
+  'gjovik' => true,
+  'gjøvik' => true,
+  'gloppen' => true,
+  'gol' => true,
+  'gran' => true,
+  'grane' => true,
+  'granvin' => true,
+  'gratangen' => true,
+  'grimstad' => true,
+  'grong' => true,
+  'kraanghke' => true,
+  'kråanghke' => true,
+  'grue' => true,
+  'gulen' => true,
+  'hadsel' => true,
+  'halden' => true,
+  'halsa' => true,
+  'hamar' => true,
+  'hamaroy' => true,
+  'habmer' => true,
+  'hábmer' => true,
+  'hapmir' => true,
+  'hápmir' => true,
+  'hammerfest' => true,
+  'hammarfeasta' => true,
+  'hámmárfeasta' => true,
+  'haram' => true,
+  'hareid' => true,
+  'harstad' => true,
+  'hasvik' => true,
+  'aknoluokta' => true,
+  'ákŋoluokta' => true,
+  'hattfjelldal' => true,
+  'aarborte' => true,
+  'haugesund' => true,
+  'hemne' => true,
+  'hemnes' => true,
+  'hemsedal' => true,
+  'more-og-romsdal' => array(
+   'heroy' => true,
+   'sande' => true
+  ),
+  'møre-og-romsdal' => array(
+   'herøy' => true,
+   'sande' => true
+  ),
+  'hitra' => true,
+  'hjartdal' => true,
+  'hjelmeland' => true,
+  'hobol' => true,
+  'hobøl' => true,
+  'hof' => true,
+  'hol' => true,
+  'hole' => true,
+  'holmestrand' => true,
+  'holtalen' => true,
+  'holtålen' => true,
+  'hornindal' => true,
+  'horten' => true,
+  'hurdal' => true,
+  'hurum' => true,
+  'hvaler' => true,
+  'hyllestad' => true,
+  'hagebostad' => true,
+  'hægebostad' => true,
+  'hoyanger' => true,
+  'høyanger' => true,
+  'hoylandet' => true,
+  'høylandet' => true,
+  'ha' => true,
+  'hå' => true,
+  'ibestad' => true,
+  'inderoy' => true,
+  'inderøy' => true,
+  'iveland' => true,
+  'jevnaker' => true,
+  'jondal' => true,
+  'jolster' => true,
+  'jølster' => true,
+  'karasjok' => true,
+  'karasjohka' => true,
+  'kárášjohka' => true,
+  'karlsoy' => true,
+  'galsa' => true,
+  'gálsá' => true,
+  'karmoy' => true,
+  'karmøy' => true,
+  'kautokeino' => true,
+  'guovdageaidnu' => true,
+  'klepp' => true,
+  'klabu' => true,
+  'klæbu' => true,
+  'kongsberg' => true,
+  'kongsvinger' => true,
+  'kragero' => true,
+  'kragerø' => true,
+  'kristiansand' => true,
+  'kristiansund' => true,
+  'krodsherad' => true,
+  'krødsherad' => true,
+  'kvalsund' => true,
+  'rahkkeravju' => true,
+  'ráhkkerávju' => true,
+  'kvam' => true,
+  'kvinesdal' => true,
+  'kvinnherad' => true,
+  'kviteseid' => true,
+  'kvitsoy' => true,
+  'kvitsøy' => true,
+  'kvafjord' => true,
+  'kvæfjord' => true,
+  'giehtavuoatna' => true,
+  'kvanangen' => true,
+  'kvænangen' => true,
+  'navuotna' => true,
+  'návuotna' => true,
+  'kafjord' => true,
+  'kåfjord' => true,
+  'gaivuotna' => true,
+  'gáivuotna' => true,
+  'larvik' => true,
+  'lavangen' => true,
+  'lavagis' => true,
+  'loabat' => true,
+  'loabát' => true,
+  'lebesby' => true,
+  'davvesiida' => true,
+  'leikanger' => true,
+  'leirfjord' => true,
+  'leka' => true,
+  'leksvik' => true,
+  'lenvik' => true,
+  'leangaviika' => true,
+  'leaŋgaviika' => true,
+  'lesja' => true,
+  'levanger' => true,
+  'lier' => true,
+  'lierne' => true,
+  'lillehammer' => true,
+  'lillesand' => true,
+  'lindesnes' => true,
+  'lindas' => true,
+  'lindås' => true,
+  'lom' => true,
+  'loppa' => true,
+  'lahppi' => true,
+  'láhppi' => true,
+  'lund' => true,
+  'lunner' => true,
+  'luroy' => true,
+  'lurøy' => true,
+  'luster' => true,
+  'lyngdal' => true,
+  'lyngen' => true,
+  'ivgu' => true,
+  'lardal' => true,
+  'lerdal' => true,
+  'lærdal' => true,
+  'lodingen' => true,
+  'lødingen' => true,
+  'lorenskog' => true,
+  'lørenskog' => true,
+  'loten' => true,
+  'løten' => true,
+  'malvik' => true,
+  'masoy' => true,
+  'måsøy' => true,
+  'muosat' => true,
+  'muosát' => true,
+  'mandal' => true,
+  'marker' => true,
+  'marnardal' => true,
+  'masfjorden' => true,
+  'meland' => true,
+  'meldal' => true,
+  'melhus' => true,
+  'meloy' => true,
+  'meløy' => true,
+  'meraker' => true,
+  'meråker' => true,
+  'moareke' => true,
+  'moåreke' => true,
+  'midsund' => true,
+  'midtre-gauldal' => true,
+  'modalen' => true,
+  'modum' => true,
+  'molde' => true,
+  'moskenes' => true,
+  'moss' => true,
+  'mosvik' => true,
+  'malselv' => true,
+  'målselv' => true,
+  'malatvuopmi' => true,
+  'málatvuopmi' => true,
+  'namdalseid' => true,
+  'aejrie' => true,
+  'namsos' => true,
+  'namsskogan' => true,
+  'naamesjevuemie' => true,
+  'nååmesjevuemie' => true,
+  'laakesvuemie' => true,
+  'nannestad' => true,
+  'narvik' => true,
+  'narviika' => true,
+  'naustdal' => true,
+  'nedre-eiker' => true,
+  'akershus' => array(
+   'nes' => true
+  ),
+  'buskerud' => array(
+   'nes' => true
+  ),
+  'nesna' => true,
+  'nesodden' => true,
+  'nesseby' => true,
+  'unjarga' => true,
+  'unjárga' => true,
+  'nesset' => true,
+  'nissedal' => true,
+  'nittedal' => true,
+  'nord-aurdal' => true,
+  'nord-fron' => true,
+  'nord-odal' => true,
+  'norddal' => true,
+  'nordkapp' => true,
+  'davvenjarga' => true,
+  'davvenjárga' => true,
+  'nordre-land' => true,
+  'nordreisa' => true,
+  'raisa' => true,
+  'ráisa' => true,
+  'nore-og-uvdal' => true,
+  'notodden' => true,
+  'naroy' => true,
+  'nærøy' => true,
+  'notteroy' => true,
+  'nøtterøy' => true,
+  'odda' => true,
+  'oksnes' => true,
+  'øksnes' => true,
+  'oppdal' => true,
+  'oppegard' => true,
+  'oppegård' => true,
+  'orkdal' => true,
+  'orland' => true,
+  'ørland' => true,
+  'orskog' => true,
+  'ørskog' => true,
+  'orsta' => true,
+  'ørsta' => true,
+  'hedmark' => array(
+   'os' => true,
+   'valer' => true,
+   'våler' => true
+  ),
+  'hordaland' => array(
+   'os' => true
+  ),
+  'osen' => true,
+  'osteroy' => true,
+  'osterøy' => true,
+  'ostre-toten' => true,
+  'østre-toten' => true,
+  'overhalla' => true,
+  'ovre-eiker' => true,
+  'øvre-eiker' => true,
+  'oyer' => true,
+  'øyer' => true,
+  'oygarden' => true,
+  'øygarden' => true,
+  'oystre-slidre' => true,
+  'øystre-slidre' => true,
+  'porsanger' => true,
+  'porsangu' => true,
+  'porsáŋgu' => true,
+  'porsgrunn' => true,
+  'radoy' => true,
+  'radøy' => true,
+  'rakkestad' => true,
+  'rana' => true,
+  'ruovat' => true,
+  'randaberg' => true,
+  'rauma' => true,
+  'rendalen' => true,
+  'rennebu' => true,
+  'rennesoy' => true,
+  'rennesøy' => true,
+  'rindal' => true,
+  'ringebu' => true,
+  'ringerike' => true,
+  'ringsaker' => true,
+  'rissa' => true,
+  'risor' => true,
+  'risør' => true,
+  'roan' => true,
+  'rollag' => true,
+  'rygge' => true,
+  'ralingen' => true,
+  'rælingen' => true,
+  'rodoy' => true,
+  'rødøy' => true,
+  'romskog' => true,
+  'rømskog' => true,
+  'roros' => true,
+  'røros' => true,
+  'rost' => true,
+  'røst' => true,
+  'royken' => true,
+  'røyken' => true,
+  'royrvik' => true,
+  'røyrvik' => true,
+  'rade' => true,
+  'råde' => true,
+  'salangen' => true,
+  'siellak' => true,
+  'saltdal' => true,
+  'salat' => true,
+  'sálát' => true,
+  'sálat' => true,
+  'samnanger' => true,
+  'vestfold' => array(
+   'sande' => true
+  ),
+  'sandefjord' => true,
+  'sandnes' => true,
+  'sandoy' => true,
+  'sandøy' => true,
+  'sarpsborg' => true,
+  'sauda' => true,
+  'sauherad' => true,
+  'sel' => true,
+  'selbu' => true,
+  'selje' => true,
+  'seljord' => true,
+  'sigdal' => true,
+  'siljan' => true,
+  'sirdal' => true,
+  'skaun' => true,
+  'skedsmo' => true,
+  'ski' => true,
+  'skien' => true,
+  'skiptvet' => true,
+  'skjervoy' => true,
+  'skjervøy' => true,
+  'skierva' => true,
+  'skiervá' => true,
+  'skjak' => true,
+  'skjåk' => true,
+  'skodje' => true,
+  'skanland' => true,
+  'skånland' => true,
+  'skanit' => true,
+  'skánit' => true,
+  'smola' => true,
+  'smøla' => true,
+  'snillfjord' => true,
+  'snasa' => true,
+  'snåsa' => true,
+  'snoasa' => true,
+  'snaase' => true,
+  'snåase' => true,
+  'sogndal' => true,
+  'sokndal' => true,
+  'sola' => true,
+  'solund' => true,
+  'songdalen' => true,
+  'sortland' => true,
+  'spydeberg' => true,
+  'stange' => true,
+  'stavanger' => true,
+  'steigen' => true,
+  'steinkjer' => true,
+  'stjordal' => true,
+  'stjørdal' => true,
+  'stokke' => true,
+  'stor-elvdal' => true,
+  'stord' => true,
+  'stordal' => true,
+  'storfjord' => true,
+  'omasvuotna' => true,
+  'strand' => true,
+  'stranda' => true,
+  'stryn' => true,
+  'sula' => true,
+  'suldal' => true,
+  'sund' => true,
+  'sunndal' => true,
+  'surnadal' => true,
+  'sveio' => true,
+  'svelvik' => true,
+  'sykkylven' => true,
+  'sogne' => true,
+  'søgne' => true,
+  'somna' => true,
+  'sømna' => true,
+  'sondre-land' => true,
+  'søndre-land' => true,
+  'sor-aurdal' => true,
+  'sør-aurdal' => true,
+  'sor-fron' => true,
+  'sør-fron' => true,
+  'sor-odal' => true,
+  'sør-odal' => true,
+  'sor-varanger' => true,
+  'sør-varanger' => true,
+  'matta-varjjat' => true,
+  'mátta-várjjat' => true,
+  'sorfold' => true,
+  'sørfold' => true,
+  'sorreisa' => true,
+  'sørreisa' => true,
+  'sorum' => true,
+  'sørum' => true,
+  'tana' => true,
+  'deatnu' => true,
+  'time' => true,
+  'tingvoll' => true,
+  'tinn' => true,
+  'tjeldsund' => true,
+  'dielddanuorri' => true,
+  'tjome' => true,
+  'tjøme' => true,
+  'tokke' => true,
+  'tolga' => true,
+  'torsken' => true,
+  'tranoy' => true,
+  'tranøy' => true,
+  'tromso' => true,
+  'tromsø' => true,
+  'tromsa' => true,
+  'romsa' => true,
+  'trondheim' => true,
+  'troandin' => true,
+  'trysil' => true,
+  'trana' => true,
+  'træna' => true,
+  'trogstad' => true,
+  'trøgstad' => true,
+  'tvedestrand' => true,
+  'tydal' => true,
+  'tynset' => true,
+  'tysfjord' => true,
+  'divtasvuodna' => true,
+  'divttasvuotna' => true,
+  'tysnes' => true,
+  'tysvar' => true,
+  'tysvær' => true,
+  'tonsberg' => true,
+  'tønsberg' => true,
+  'ullensaker' => true,
+  'ullensvang' => true,
+  'ulvik' => true,
+  'utsira' => true,
+  'vadso' => true,
+  'vadsø' => true,
+  'cahcesuolo' => true,
+  'čáhcesuolo' => true,
+  'vaksdal' => true,
+  'valle' => true,
+  'vang' => true,
+  'vanylven' => true,
+  'vardo' => true,
+  'vardø' => true,
+  'varggat' => true,
+  'várggát' => true,
+  'vefsn' => true,
+  'vaapste' => true,
+  'vega' => true,
+  'vegarshei' => true,
+  'vegårshei' => true,
+  'vennesla' => true,
+  'verdal' => true,
+  'verran' => true,
+  'vestby' => true,
+  'vestnes' => true,
+  'vestre-slidre' => true,
+  'vestre-toten' => true,
+  'vestvagoy' => true,
+  'vestvågøy' => true,
+  'vevelstad' => true,
+  'vik' => true,
+  'vikna' => true,
+  'vindafjord' => true,
+  'volda' => true,
+  'voss' => true,
+  'varoy' => true,
+  'værøy' => true,
+  'vagan' => true,
+  'vågan' => true,
+  'voagat' => true,
+  'vagsoy' => true,
+  'vågsøy' => true,
+  'vaga' => true,
+  'vågå' => true,
+  'ostfold' => array(
+   'valer' => true
+  ),
+  'østfold' => array(
+   'våler' => true
+  )
+ ),
+ 'np' => array(
+  '*' => true
+ ),
+ 'nr' => array(
+  'biz' => true,
+  'info' => true,
+  'gov' => true,
+  'edu' => true,
+  'org' => true,
+  'net' => true,
+  'com' => true
+ ),
+ 'nu' => true,
+ 'nz' => array(
+  '*' => true
+ ),
+ 'om' => array(
+  '*' => true,
+  '!mediaphone' => true,
+  '!nawrastelecom' => true,
+  '!nawras' => true,
+  '!omanmobile' => true,
+  '!omanpost' => true,
+  '!omantel' => true,
+  '!rakpetroleum' => true,
+  '!siemens' => true,
+  '!songfest' => true,
+  '!statecouncil' => true
+ ),
+ 'org' => array(
+  'ae' => true,
+  'za' => true
+ ),
+ 'pa' => array(
+  'ac' => true,
+  'gob' => true,
+  'com' => true,
+  'org' => true,
+  'sld' => true,
+  'edu' => true,
+  'net' => true,
+  'ing' => true,
+  'abo' => true,
+  'med' => true,
+  'nom' => true
+ ),
+ 'pe' => array(
+  'edu' => true,
+  'gob' => true,
+  'nom' => true,
+  'mil' => true,
+  'org' => true,
+  'com' => true,
+  'net' => true
+ ),
+ 'pf' => array(
+  'com' => true,
+  'org' => true,
+  'edu' => true
+ ),
+ 'pg' => array(
+  '*' => true
+ ),
+ 'ph' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'edu' => true,
+  'ngo' => true,
+  'mil' => true,
+  'i' => true
+ ),
+ 'pk' => array(
+  'com' => true,
+  'net' => true,
+  'edu' => true,
+  'org' => true,
+  'fam' => true,
+  'biz' => true,
+  'web' => true,
+  'gov' => true,
+  'gob' => true,
+  'gok' => true,
+  'gon' => true,
+  'gop' => true,
+  'gos' => true,
+  'info' => true
+ ),
+ 'pl' => array(
+  'aid' => true,
+  'agro' => true,
+  'atm' => true,
+  'auto' => true,
+  'biz' => true,
+  'com' => true,
+  'edu' => true,
+  'gmina' => true,
+  'gsm' => true,
+  'info' => true,
+  'mail' => true,
+  'miasta' => true,
+  'media' => true,
+  'mil' => true,
+  'net' => true,
+  'nieruchomosci' => true,
+  'nom' => true,
+  'org' => true,
+  'pc' => true,
+  'powiat' => true,
+  'priv' => true,
+  'realestate' => true,
+  'rel' => true,
+  'sex' => true,
+  'shop' => true,
+  'sklep' => true,
+  'sos' => true,
+  'szkola' => true,
+  'targi' => true,
+  'tm' => true,
+  'tourism' => true,
+  'travel' => true,
+  'turystyka' => true,
+  '6bone' => true,
+  'art' => true,
+  'mbone' => true,
+  'gov' => array(
+   'uw' => true,
+   'um' => true,
+   'ug' => true,
+   'upow' => true,
+   'starostwo' => true,
+   'so' => true,
+   'sr' => true,
+   'po' => true,
+   'pa' => true
+  ),
+  'ngo' => true,
+  'irc' => true,
+  'usenet' => true,
+  'augustow' => true,
+  'babia-gora' => true,
+  'bedzin' => true,
+  'beskidy' => true,
+  'bialowieza' => true,
+  'bialystok' => true,
+  'bielawa' => true,
+  'bieszczady' => true,
+  'boleslawiec' => true,
+  'bydgoszcz' => true,
+  'bytom' => true,
+  'cieszyn' => true,
+  'czeladz' => true,
+  'czest' => true,
+  'dlugoleka' => true,
+  'elblag' => true,
+  'elk' => true,
+  'glogow' => true,
+  'gniezno' => true,
+  'gorlice' => true,
+  'grajewo' => true,
+  'ilawa' => true,
+  'jaworzno' => true,
+  'jelenia-gora' => true,
+  'jgora' => true,
+  'kalisz' => true,
+  'kazimierz-dolny' => true,
+  'karpacz' => true,
+  'kartuzy' => true,
+  'kaszuby' => true,
+  'katowice' => true,
+  'kepno' => true,
+  'ketrzyn' => true,
+  'klodzko' => true,
+  'kobierzyce' => true,
+  'kolobrzeg' => true,
+  'konin' => true,
+  'konskowola' => true,
+  'kutno' => true,
+  'lapy' => true,
+  'lebork' => true,
+  'legnica' => true,
+  'lezajsk' => true,
+  'limanowa' => true,
+  'lomza' => true,
+  'lowicz' => true,
+  'lubin' => true,
+  'lukow' => true,
+  'malbork' => true,
+  'malopolska' => true,
+  'mazowsze' => true,
+  'mazury' => true,
+  'mielec' => true,
+  'mielno' => true,
+  'mragowo' => true,
+  'naklo' => true,
+  'nowaruda' => true,
+  'nysa' => true,
+  'olawa' => true,
+  'olecko' => true,
+  'olkusz' => true,
+  'olsztyn' => true,
+  'opoczno' => true,
+  'opole' => true,
+  'ostroda' => true,
+  'ostroleka' => true,
+  'ostrowiec' => true,
+  'ostrowwlkp' => true,
+  'pila' => true,
+  'pisz' => true,
+  'podhale' => true,
+  'podlasie' => true,
+  'polkowice' => true,
+  'pomorze' => true,
+  'pomorskie' => true,
+  'prochowice' => true,
+  'pruszkow' => true,
+  'przeworsk' => true,
+  'pulawy' => true,
+  'radom' => true,
+  'rawa-maz' => true,
+  'rybnik' => true,
+  'rzeszow' => true,
+  'sanok' => true,
+  'sejny' => true,
+  'siedlce' => true,
+  'slask' => true,
+  'slupsk' => true,
+  'sosnowiec' => true,
+  'stalowa-wola' => true,
+  'skoczow' => true,
+  'starachowice' => true,
+  'stargard' => true,
+  'suwalki' => true,
+  'swidnica' => true,
+  'swiebodzin' => true,
+  'swinoujscie' => true,
+  'szczecin' => true,
+  'szczytno' => true,
+  'tarnobrzeg' => true,
+  'tgory' => true,
+  'turek' => true,
+  'tychy' => true,
+  'ustka' => true,
+  'walbrzych' => true,
+  'warmia' => true,
+  'warszawa' => true,
+  'waw' => true,
+  'wegrow' => true,
+  'wielun' => true,
+  'wlocl' => true,
+  'wloclawek' => true,
+  'wodzislaw' => true,
+  'wolomin' => true,
+  'wroclaw' => true,
+  'zachpomor' => true,
+  'zagan' => true,
+  'zarow' => true,
+  'zgora' => true,
+  'zgorzelec' => true,
+  'gda' => true,
+  'gdansk' => true,
+  'gdynia' => true,
+  'med' => true,
+  'sopot' => true,
+  'gliwice' => true,
+  'krakow' => true,
+  'poznan' => true,
+  'wroc' => true,
+  'zakopane' => true,
+  'co' => true
+ ),
+ 'pn' => array(
+  'gov' => true,
+  'co' => true,
+  'org' => true,
+  'edu' => true,
+  'net' => true
+ ),
+ 'pr' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'edu' => true,
+  'isla' => true,
+  'pro' => true,
+  'biz' => true,
+  'info' => true,
+  'name' => true,
+  'est' => true,
+  'prof' => true,
+  'ac' => true
+ ),
+ 'pro' => array(
+  'aca' => true,
+  'bar' => true,
+  'cpa' => true,
+  'jur' => true,
+  'law' => true,
+  'med' => true,
+  'eng' => true
+ ),
+ 'ps' => array(
+  'edu' => true,
+  'gov' => true,
+  'sec' => true,
+  'plo' => true,
+  'com' => true,
+  'org' => true,
+  'net' => true
+ ),
+ 'pt' => array(
+  'net' => true,
+  'gov' => true,
+  'org' => true,
+  'edu' => true,
+  'int' => true,
+  'publ' => true,
+  'com' => true,
+  'nome' => true
+ ),
+ 'pw' => array(
+  'co' => true,
+  'ne' => true,
+  'or' => true,
+  'ed' => true,
+  'go' => true,
+  'belau' => true
+ ),
+ 'py' => array(
+  '*' => true
+ ),
+ 'qa' => array(
+  '*' => true
+ ),
+ 're' => array(
+  'com' => true,
+  'asso' => true,
+  'nom' => true
+ ),
+ 'ro' => array(
+  'com' => true,
+  'org' => true,
+  'tm' => true,
+  'nt' => true,
+  'nom' => true,
+  'info' => true,
+  'rec' => true,
+  'arts' => true,
+  'firm' => true,
+  'store' => true,
+  'www' => true
+ ),
+ 'rs' => array(
+  'co' => true,
+  'org' => true,
+  'edu' => true,
+  'ac' => true,
+  'gov' => true,
+  'in' => true
+ ),
+ 'ru' => array(
+  'ac' => true,
+  'com' => true,
+  'edu' => true,
+  'int' => true,
+  'net' => true,
+  'org' => true,
+  'pp' => true,
+  'adygeya' => true,
+  'altai' => true,
+  'amur' => true,
+  'arkhangelsk' => true,
+  'astrakhan' => true,
+  'bashkiria' => true,
+  'belgorod' => true,
+  'bir' => true,
+  'bryansk' => true,
+  'buryatia' => true,
+  'cbg' => true,
+  'chel' => true,
+  'chelyabinsk' => true,
+  'chita' => true,
+  'chukotka' => true,
+  'chuvashia' => true,
+  'dagestan' => true,
+  'dudinka' => true,
+  'e-burg' => true,
+  'grozny' => true,
+  'irkutsk' => true,
+  'ivanovo' => true,
+  'izhevsk' => true,
+  'jar' => true,
+  'joshkar-ola' => true,
+  'kalmykia' => true,
+  'kaluga' => true,
+  'kamchatka' => true,
+  'karelia' => true,
+  'kazan' => true,
+  'kchr' => true,
+  'kemerovo' => true,
+  'khabarovsk' => true,
+  'khakassia' => true,
+  'khv' => true,
+  'kirov' => true,
+  'koenig' => true,
+  'komi' => true,
+  'kostroma' => true,
+  'krasnoyarsk' => true,
+  'kuban' => true,
+  'kurgan' => true,
+  'kursk' => true,
+  'lipetsk' => true,
+  'magadan' => true,
+  'mari' => true,
+  'mari-el' => true,
+  'marine' => true,
+  'mordovia' => true,
+  'mosreg' => true,
+  'msk' => true,
+  'murmansk' => true,
+  'nalchik' => true,
+  'nnov' => true,
+  'nov' => true,
+  'novosibirsk' => true,
+  'nsk' => true,
+  'omsk' => true,
+  'orenburg' => true,
+  'oryol' => true,
+  'palana' => true,
+  'penza' => true,
+  'perm' => true,
+  'pskov' => true,
+  'ptz' => true,
+  'rnd' => true,
+  'ryazan' => true,
+  'sakhalin' => true,
+  'samara' => true,
+  'saratov' => true,
+  'simbirsk' => true,
+  'smolensk' => true,
+  'spb' => true,
+  'stavropol' => true,
+  'stv' => true,
+  'surgut' => true,
+  'tambov' => true,
+  'tatarstan' => true,
+  'tom' => true,
+  'tomsk' => true,
+  'tsaritsyn' => true,
+  'tsk' => true,
+  'tula' => true,
+  'tuva' => true,
+  'tver' => true,
+  'tyumen' => true,
+  'udm' => true,
+  'udmurtia' => true,
+  'ulan-ude' => true,
+  'vladikavkaz' => true,
+  'vladimir' => true,
+  'vladivostok' => true,
+  'volgograd' => true,
+  'vologda' => true,
+  'voronezh' => true,
+  'vrn' => true,
+  'vyatka' => true,
+  'yakutia' => true,
+  'yamal' => true,
+  'yaroslavl' => true,
+  'yekaterinburg' => true,
+  'yuzhno-sakhalinsk' => true,
+  'amursk' => true,
+  'baikal' => true,
+  'cmw' => true,
+  'fareast' => true,
+  'jamal' => true,
+  'kms' => true,
+  'k-uralsk' => true,
+  'kustanai' => true,
+  'kuzbass' => true,
+  'magnitka' => true,
+  'mytis' => true,
+  'nakhodka' => true,
+  'nkz' => true,
+  'norilsk' => true,
+  'oskol' => true,
+  'pyatigorsk' => true,
+  'rubtsovsk' => true,
+  'snz' => true,
+  'syzran' => true,
+  'vdonsk' => true,
+  'zgrad' => true,
+  'gov' => true,
+  'mil' => true,
+  'test' => true
+ ),
+ 'rw' => array(
+  'gov' => true,
+  'net' => true,
+  'edu' => true,
+  'ac' => true,
+  'com' => true,
+  'co' => true,
+  'int' => true,
+  'mil' => true,
+  'gouv' => true
+ ),
+ 'sa' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'med' => true,
+  'pub' => true,
+  'edu' => true,
+  'sch' => true
+ ),
+ 'sb' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'sc' => array(
+  'com' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true
+ ),
+ 'sd' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'med' => true,
+  'gov' => true,
+  'info' => true
+ ),
+ 'se' => array(
+  'a' => true,
+  'ac' => true,
+  'b' => true,
+  'bd' => true,
+  'brand' => true,
+  'c' => true,
+  'd' => true,
+  'e' => true,
+  'f' => true,
+  'fh' => true,
+  'fhsk' => true,
+  'fhv' => true,
+  'g' => true,
+  'h' => true,
+  'i' => true,
+  'k' => true,
+  'komforb' => true,
+  'kommunalforbund' => true,
+  'komvux' => true,
+  'l' => true,
+  'lanbib' => true,
+  'm' => true,
+  'n' => true,
+  'naturbruksgymn' => true,
+  'o' => true,
+  'org' => true,
+  'p' => true,
+  'parti' => true,
+  'pp' => true,
+  'press' => true,
+  'r' => true,
+  's' => true,
+  'sshn' => true,
+  't' => true,
+  'tm' => true,
+  'u' => true,
+  'w' => true,
+  'x' => true,
+  'y' => true,
+  'z' => true
+ ),
+ 'sg' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'edu' => true,
+  'per' => true
+ ),
+ 'sh' => true,
+ 'si' => true,
+ 'sk' => true,
+ 'sl' => array(
+  'com' => true,
+  'net' => true,
+  'edu' => true,
+  'gov' => true,
+  'org' => true
+ ),
+ 'sm' => true,
+ 'sn' => array(
+  'art' => true,
+  'com' => true,
+  'edu' => true,
+  'gouv' => true,
+  'org' => true,
+  'perso' => true,
+  'univ' => true
+ ),
+ 'so' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'sr' => true,
+ 'st' => array(
+  'co' => true,
+  'com' => true,
+  'consulado' => true,
+  'edu' => true,
+  'embaixada' => true,
+  'gov' => true,
+  'mil' => true,
+  'net' => true,
+  'org' => true,
+  'principe' => true,
+  'saotome' => true,
+  'store' => true
+ ),
+ 'su' => true,
+ 'sv' => array(
+  '*' => true
+ ),
+ 'sy' => array(
+  'edu' => true,
+  'gov' => true,
+  'net' => true,
+  'mil' => true,
+  'com' => true,
+  'org' => true
+ ),
+ 'sz' => array(
+  'co' => true,
+  'ac' => true,
+  'org' => true
+ ),
+ 'tc' => true,
+ 'td' => true,
+ 'tel' => true,
+ 'tf' => true,
+ 'tg' => true,
+ 'th' => array(
+  'ac' => true,
+  'co' => true,
+  'go' => true,
+  'in' => true,
+  'mi' => true,
+  'net' => true,
+  'or' => true
+ ),
+ 'tj' => array(
+  'ac' => true,
+  'biz' => true,
+  'co' => true,
+  'com' => true,
+  'edu' => true,
+  'go' => true,
+  'gov' => true,
+  'int' => true,
+  'mil' => true,
+  'name' => true,
+  'net' => true,
+  'nic' => true,
+  'org' => true,
+  'test' => true,
+  'web' => true
+ ),
+ 'tk' => true,
+ 'tl' => array(
+  'gov' => true
+ ),
+ 'tm' => true,
+ 'tn' => array(
+  'com' => true,
+  'ens' => true,
+  'fin' => true,
+  'gov' => true,
+  'ind' => true,
+  'intl' => true,
+  'nat' => true,
+  'net' => true,
+  'org' => true,
+  'info' => true,
+  'perso' => true,
+  'tourism' => true,
+  'edunet' => true,
+  'rnrt' => true,
+  'rns' => true,
+  'rnu' => true,
+  'mincom' => true,
+  'agrinet' => true,
+  'defense' => true,
+  'turen' => true
+ ),
+ 'to' => array(
+  'com' => true,
+  'gov' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'mil' => true
+ ),
+ 'tr' => array(
+  '*' => true,
+  '!nic' => true,
+  '!tsk' => true,
+  'nc' => array(
+   'gov' => true
+  )
+ ),
+ 'travel' => true,
+ 'tt' => array(
+  'co' => true,
+  'com' => true,
+  'org' => true,
+  'net' => true,
+  'biz' => true,
+  'info' => true,
+  'pro' => true,
+  'int' => true,
+  'coop' => true,
+  'jobs' => true,
+  'mobi' => true,
+  'travel' => true,
+  'museum' => true,
+  'aero' => true,
+  'name' => true,
+  'gov' => true,
+  'edu' => true
+ ),
+ 'tv' => true,
+ 'tw' => array(
+  'edu' => true,
+  'gov' => true,
+  'mil' => true,
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'idv' => true,
+  'game' => true,
+  'ebiz' => true,
+  'club' => true,
+  '網路' => true,
+  '組織' => true,
+  '商業' => true
+ ),
+ 'tz' => array(
+  'ac' => true,
+  'co' => true,
+  'go' => true,
+  'mil' => true,
+  'ne' => true,
+  'or' => true,
+  'sc' => true
+ ),
+ 'ua' => array(
+  'com' => true,
+  'edu' => true,
+  'gov' => true,
+  'in' => true,
+  'net' => true,
+  'org' => true,
+  'cherkassy' => true,
+  'chernigov' => true,
+  'chernovtsy' => true,
+  'ck' => true,
+  'cn' => true,
+  'crimea' => true,
+  'cv' => true,
+  'dn' => true,
+  'dnepropetrovsk' => true,
+  'donetsk' => true,
+  'dp' => true,
+  'if' => true,
+  'ivano-frankivsk' => true,
+  'kh' => true,
+  'kharkov' => true,
+  'kherson' => true,
+  'khmelnitskiy' => true,
+  'kiev' => true,
+  'kirovograd' => true,
+  'km' => true,
+  'kr' => true,
+  'ks' => true,
+  'kv' => true,
+  'lg' => true,
+  'lugansk' => true,
+  'lutsk' => true,
+  'lviv' => true,
+  'mk' => true,
+  'nikolaev' => true,
+  'od' => true,
+  'odessa' => true,
+  'pl' => true,
+  'poltava' => true,
+  'rovno' => true,
+  'rv' => true,
+  'sebastopol' => true,
+  'sumy' => true,
+  'te' => true,
+  'ternopil' => true,
+  'uzhgorod' => true,
+  'vinnica' => true,
+  'vn' => true,
+  'zaporizhzhe' => true,
+  'zp' => true,
+  'zhitomir' => true,
+  'zt' => true
+ ),
+ 'ug' => array(
+  'co' => true,
+  'ac' => true,
+  'sc' => true,
+  'go' => true,
+  'ne' => true,
+  'or' => true
+ ),
+ 'uk' => array(
+  '*' => true,
+  'sch' => array(
+   '*' => true
+  ),
+  '!bl' => true,
+  '!british-library' => true,
+  '!icnet' => true,
+  '!jet' => true,
+  '!nel' => true,
+  '!nhs' => true,
+  '!nls' => true,
+  '!national-library-scotland' => true,
+  '!parliament' => true
+ ),
+ 'us' => array(
+  'dni' => true,
+  'fed' => true,
+  'isa' => true,
+  'kids' => true,
+  'nsn' => true,
+  'ak' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'al' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ar' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'as' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'az' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ca' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'co' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ct' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'dc' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'de' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'fl' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ga' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'gu' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'hi' => array(
+   'cc' => true,
+   'lib' => true
+  ),
+  'ia' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'id' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'il' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'in' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ks' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ky' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'la' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ma' => array(
+   'k12' => array(
+    'pvt' => true,
+    'chtr' => true,
+    'paroch' => true
+   ),
+   'cc' => true,
+   'lib' => true
+  ),
+  'md' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'me' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'mi' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'mn' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'mo' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ms' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'mt' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'nc' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'nd' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ne' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'nh' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'nj' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'nm' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'nv' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ny' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'oh' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ok' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'or' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'pa' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'pr' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ri' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'sc' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'sd' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'tn' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'tx' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'ut' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'vi' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'vt' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'va' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'wa' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'wi' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'wv' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  ),
+  'wy' => array(
+   'k12' => true,
+   'cc' => true,
+   'lib' => true
+  )
+ ),
+ 'uy' => array(
+  '*' => true
+ ),
+ 'uz' => array(
+  'com' => true,
+  'co' => true
+ ),
+ 'va' => true,
+ 'vc' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'mil' => true,
+  'edu' => true
+ ),
+ 've' => array(
+  '*' => true
+ ),
+ 'vg' => true,
+ 'vi' => array(
+  'co' => true,
+  'com' => true,
+  'k12' => true,
+  'net' => true,
+  'org' => true
+ ),
+ 'vn' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'edu' => true,
+  'gov' => true,
+  'int' => true,
+  'ac' => true,
+  'biz' => true,
+  'info' => true,
+  'name' => true,
+  'pro' => true,
+  'health' => true
+ ),
+ 'vu' => true,
+ 'ws' => array(
+  'com' => true,
+  'net' => true,
+  'org' => true,
+  'gov' => true,
+  'edu' => true
+ ),
+ 'امارات' => true,
+ '中国' => true,
+ '中國' => true,
+ 'مصر' => true,
+ '香港' => true,
+ 'الاردن' => true,
+ 'ලංකා' => true,
+ 'இலங்கை' => true,
+ 'فلسطين' => true,
+ 'рф' => true,
+ 'قطر' => true,
+ 'السعودية' => true,
+ '新加坡' => true,
+ 'சிங்கப்பூர்' => true,
+ 'ไทย' => true,
+ 'تونس' => true,
+ '台灣' => true,
+ '台湾' => true,
+ 'ye' => array(
+  '*' => true
+ ),
+ 'yu' => array(
+  '*' => true
+ ),
+ 'za' => array(
+  '*' => true
+ ),
+ 'zm' => array(
+  '*' => true
+ ),
+ 'zw' => array(
+  '*' => true
+ )
+);
+?>
\ No newline at end of file
diff --git a/lib/docs/HTTP_Request2/HTTP/examples/upload-rapidshare.php b/lib/docs/HTTP_Request2/HTTP/examples/upload-rapidshare.php
new file mode 100644
index 0000000000000000000000000000000000000000..9773a94c48fed08bb23ad5beffda73d05ff5cd32
--- /dev/null
+++ b/lib/docs/HTTP_Request2/HTTP/examples/upload-rapidshare.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Usage example for HTTP_Request2 package: uploading a file to rapidshare.com
+ *
+ * Inspired by Perl usage example: http://images.rapidshare.com/software/rsapi.pl
+ * Rapidshare API description: http://rapidshare.com/dev.html
+ *
+ * $Id: upload-rapidshare.php 287307 2009-08-14 15:40:22Z avb $
+ */
+
+require_once 'HTTP/Request2.php';
+
+// You'll probably want to change this
+$filename = '/etc/passwd';
+
+try {
+    // First step: get an available upload server
+    $request = new HTTP_Request2(
+        'http://rapidshare.com/cgi-bin/rsapi.cgi?sub=nextuploadserver_v1'
+    );
+    $server  = $request->send()->getBody();
+    if (!preg_match('/^(\\d+)$/', $server)) {
+        throw new Exception("Invalid upload server: {$server}");
+    }
+
+    // Calculate file hash, we'll use it later to check upload
+    if (false === ($hash = @md5_file($filename))) {
+        throw new Exception("Cannot calculate MD5 hash of '{$filename}'");
+    }
+
+    // Second step: upload a file to the available server
+    $uploader = new HTTP_Request2(
+        "http://rs{$server}l3.rapidshare.com/cgi-bin/upload.cgi",
+        HTTP_Request2::METHOD_POST
+    );
+    // Adding the file
+    $uploader->addUpload('filecontent', $filename);
+    // This will tell server to return program-friendly output
+    $uploader->addPostParameter('rsapi_v1', '1');
+
+    $response = $uploader->send()->getBody();
+    if (!preg_match_all('/^(File[^=]+)=(.+)$/m', $response, $m, PREG_SET_ORDER)) {
+        throw new Exception("Invalid response: {$response}");
+    }
+    $rspAry = array();
+    foreach ($m as $item) {
+        $rspAry[$item[1]] = $item[2];
+    }
+    // Check that uploaded file has the same hash
+    if (empty($rspAry['File1.4'])) {
+        throw new Exception("MD5 hash data not found in response");
+    } elseif ($hash != strtolower($rspAry['File1.4'])) {
+        throw new Exception("Upload failed, local MD5 is {$hash}, uploaded MD5 is {$rspAry['File1.4']}");
+    }
+    echo "Upload succeeded\nDownload link: {$rspAry['File1.1']}\nDelete link: {$rspAry['File1.2']}\n";
+
+} catch (Exception $e) {
+    echo "Error: " . $e->getMessage();
+}
+?>
diff --git a/lib/docs/Net_URL2/Net/docs/6470.php b/lib/docs/Net_URL2/Net/docs/6470.php
new file mode 100644
index 0000000000000000000000000000000000000000..104de8960852ebff997e4d9d17a209c35c19cb5d
--- /dev/null
+++ b/lib/docs/Net_URL2/Net/docs/6470.php
@@ -0,0 +1,75 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003, Richard Heyes                                     |
+// | All rights reserved.                                                  |
+// |                                                                       |
+// | Redistribution and use in source and binary forms, with or without    |
+// | modification, are permitted provided that the following conditions    |
+// | are met:                                                              |
+// |                                                                       |
+// | o Redistributions of source code must retain the above copyright      |
+// |   notice, this list of conditions and the following disclaimer.       |
+// | o 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.|
+// | o The names of the authors may not 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  |
+// | OWNER OR 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.  |
+// |                                                                       |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard at php net>                            |
+// +-----------------------------------------------------------------------+
+// $Id: 6470.php 235190 2007-05-08 00:04:54Z davidc $
+/**
+* This example will decode the url given and display its
+* constituent parts.
+*/
+    error_reporting(E_ALL | E_STRICT);
+
+    require_once 'Net/URL2.php';
+
+    //$url = &new Net_URL2('https://www.example.com/foo/bar/index.php?foo=bar');
+    Net_URL2::setOption('encode_query_keys', true);
+    $url = new Net_URL2;
+    
+?>
+<html>
+<body>
+
+<pre>
+Protocol...: <?php echo $url->protocol; ?>
+
+Username...: <?php echo $url->user; ?>
+
+Password...: <?php echo $url->pass; ?>
+
+Server.....: <?php echo $url->host; ?>
+
+Port.......: <?php $url->port; ?>
+
+File/path..: <?php $url->path; ?>
+
+Querystring: <?php print_r($url->querystring); ?>
+
+Anchor.....: <?php echo $url->anchor;?>
+
+Full URL...: <?php echo $url->getUrl(); ?>
+
+
+Resolve path (/.././/foo/bar/joe/./././../jabba): <b><?php Net_URL2::resolvePath('/.././/foo/bar/joe/./././../jabba'); ?></b>
+</pre>
+
+</body>
+</html>
diff --git a/lib/docs/Net_URL2/Net/docs/example.php b/lib/docs/Net_URL2/Net/docs/example.php
new file mode 100644
index 0000000000000000000000000000000000000000..d2725ba5aaa8d854de39d43e1e44fbbd6783c1a9
--- /dev/null
+++ b/lib/docs/Net_URL2/Net/docs/example.php
@@ -0,0 +1,74 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Copyright (c) 2002-2003, Richard Heyes                                     |
+// | All rights reserved.                                                  |
+// |                                                                       |
+// | Redistribution and use in source and binary forms, with or without    |
+// | modification, are permitted provided that the following conditions    |
+// | are met:                                                              |
+// |                                                                       |
+// | o Redistributions of source code must retain the above copyright      |
+// |   notice, this list of conditions and the following disclaimer.       |
+// | o 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.|
+// | o The names of the authors may not 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  |
+// | OWNER OR 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.  |
+// |                                                                       |
+// +-----------------------------------------------------------------------+
+// | Author: Richard Heyes <richard at php net>                            |
+// +-----------------------------------------------------------------------+
+// $Id: example.php 235190 2007-05-08 00:04:54Z davidc $
+/**
+* This example will decode the url given and display its
+* constituent parts.
+*/
+    error_reporting(E_ALL | E_STRICT);
+
+    //include('../URL2.php');
+    include('Net/URL2.php');
+
+    //$url = &new Net_URL2('https://www.example.com/foo/bar/index.php?foo=bar');
+    $url = new Net_URL2('https://example.com/pls/portal30/PORTAL30.wwpob_page.changetabs?p_back_url=http%3A%2F%2Fexample.com%2Fservlet%2Fpage%3F_pageid%3D360%2C366%2C368%2C382%26_dad%3Dportal30%26_schema%3DPORTAL30&foo=bar');
+?>
+<html>
+<body>
+
+<pre>
+Protocol...: <?php echo $url->protocol; ?>
+
+Username...: <?php echo $url->user; ?>
+
+Password...: <?php echo $url->pass; ?>
+
+Server.....: <?php echo $url->host; ?>
+
+Port.......: <?php $url->port; ?>
+
+File/path..: <?php $url->path; ?>
+
+Querystring: <?php print_r($url->querystring); ?>
+
+Anchor.....: <?php echo $url->anchor;?>
+
+Full URL...: <?php echo $url->getUrl(); ?>
+
+
+Resolve path (/.././/foo/bar/joe/./././../jabba): <b><?php Net_URL2::resolvePath('/.././/foo/bar/joe/./././../jabba'); ?></b>
+</pre>
+
+</body>
+</html>
diff --git a/lib/docs/SimpleCAS/docs/examples/Zend_Auth_Adapter_SimpleCAS.php b/lib/docs/SimpleCAS/docs/examples/Zend_Auth_Adapter_SimpleCAS.php
new file mode 100644
index 0000000000000000000000000000000000000000..921d1a08b32da6b6876985491e175012331bb279
--- /dev/null
+++ b/lib/docs/SimpleCAS/docs/examples/Zend_Auth_Adapter_SimpleCAS.php
@@ -0,0 +1,134 @@
+<?php
+/**
+ * This is a Zend_Auth adapter library for CAS.
+ * It uses SimpleCAS.
+ *
+ * <code>
+ * public function casAction()
+ * {
+ *     $auth = Zend_Auth::getInstance();
+ *     $authAdapter = new UNL_CasZendAuthAdapter(
+ *         Zend_Registry::get('config')->auth->cas
+ *     );
+ * 
+ *     # User has not been identified, and there's a ticket in the URL
+ *     if (!$auth->hasIdentity() && isset($_GET['ticket'])) {
+ *         $authAdapter->setTicket($_GET['ticket']);
+ *         $result = $auth->authenticate($authAdapter);
+ * 
+ *         if ($result->isValid()) {
+ *             Zend_Session::regenerateId();
+ *         }
+ *     }
+ * 
+ *     # No ticket or ticket was invalid. Redirect to CAS.
+ *     if (!$auth->hasIdentity()) {
+ *         $this->_redirect($authAdapter->getLoginURL());
+ *     }
+ * }
+ * </code>
+ */
+
+
+/**
+ * @see Zend_Auth_Adapter_Interface
+ */
+require_once 'Zend/Auth/Adapter/Interface.php';
+
+require_once('SimpleCAS/Server/Version2.php');
+
+class Zend_Auth_Adapter_SimpleCAS implements Zend_Auth_Adapter_Interface
+{
+    /**
+     * CAS client
+     */
+    private $_protocol;
+
+    /**
+     * Service ticket
+     */
+    private $_ticket;
+
+    /**
+     * Constructor
+     *
+     * @param string $server_hostname
+     * @param string $server_port
+     * @param string $server_uri
+     * @return void
+     */ 
+    public function __construct($options)
+    {
+        $this->_protocol = new SimpleCAS_Protocol_Version2($options);
+    }
+
+    public function setTicket($ticket)
+    {
+        $this->_ticket = $ticket;
+        return $this;
+    }
+
+    /**
+     * Authenticates ticket
+     *
+     * The ticket is provided with setTicket
+     *
+     * @param return boolean
+     */ 
+    public function authenticate()
+    {
+        if ($id = $this->_protocol->validateTicket($this->_ticket, self::getURL())) {
+            return new Zend_Auth_Result(
+                Zend_Auth_Result::SUCCESS,
+                $id,
+                array("Authentication successful"));
+        } else {
+            return new Zend_Auth_Result(
+                Zend_Auth_Result::FAILURE,
+                null,
+                array("Authentication failed"));
+        }
+    }
+    
+    /**
+     * Returns the current URL without CAS affecting parameters.
+     * Copied directly from SimpleCAS.php 0.1.0
+     * 
+     * @return string url
+     */
+    static public function getURL()
+    {
+        if (isset($_SERVER['HTTPS'])
+            && !empty($_SERVER['HTTPS'])
+            && $_SERVER['HTTPS'] == 'on') {
+            $protocol = 'https';
+        } else {
+            $protocol = 'http';
+        }
+    
+        $url = $protocol.'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
+        
+        $replacements = array('/\?logout/'        => '',
+                              '/&ticket=[^&]*/'   => '',
+                              '/\?ticket=[^&;]*/' => '?',
+                              '/\?%26/'           => '?',
+                              '/\?&/'             => '?',
+                              '/\?$/'             => '');
+        
+        $url = preg_replace(array_keys($replacements),
+                            array_values($replacements), $url);
+        
+        return $url;
+    }
+
+    /**
+     * Returns the URL to login form on the CAS server.
+     *
+     * @return string
+     */
+    public function getLoginURL()
+    {
+        return $this->_protocol->getLoginURL(self::getURL());
+    }
+ 
+}
diff --git a/lib/docs/SimpleCAS/docs/examples/simple.php b/lib/docs/SimpleCAS/docs/examples/simple.php
new file mode 100644
index 0000000000000000000000000000000000000000..02f768b8868624426092901051a478966f1680a2
--- /dev/null
+++ b/lib/docs/SimpleCAS/docs/examples/simple.php
@@ -0,0 +1,27 @@
+<?php
+ini_set('display_errors', true);
+chdir(dirname(dirname(dirname(__FILE__))));
+
+require_once 'SimpleCAS/Autoload.php';
+require_once 'HTTP/Request2.php';
+
+$options = array('hostname' =>'login.unl.edu',
+                 'port'     => 443,
+                 'uri'      => 'cas');
+$protocol = new SimpleCAS_Protocol_Version2($options);
+
+$protocol->getRequest()->setConfig('ssl_verify_peer', false);
+
+$client = SimpleCAS::client($protocol);
+$client->forceAuthentication();
+
+if (isset($_GET['logout'])) {
+	$client->logout();
+}
+
+if ($client->isAuthenticated()) {
+    echo '<h1>Authentication Successful!</h1>';
+    echo '<p>The user\'s login is '.$client->getUsername().'</p>';
+}
+?>
+<a href="?logout">Logout</a>
\ No newline at end of file
diff --git a/lib/docs/UNL_Auth/docs/examples/CASPEARAuth_example.php b/lib/docs/UNL_Auth/docs/examples/CASPEARAuth_example.php
new file mode 100644
index 0000000000000000000000000000000000000000..8b2442757e45a7bf08ad841e36e340859292363a
--- /dev/null
+++ b/lib/docs/UNL_Auth/docs/examples/CASPEARAuth_example.php
@@ -0,0 +1,26 @@
+<?php
+ini_set('display_errors', true);
+error_reporting(E_ALL);
+chdir(dirname(__FILE__).'/../../');
+require_once 'UNL/Auth.php';
+
+//$auth = UNL_Auth::PEARFactory('CAS', $options=null, $loginfunction=null, false);
+$auth = UNL_Auth::PEARFactory('CAS');
+$auth->start();
+
+if (isset($_GET['logout']) && $auth->checkAuth()) {
+    $auth->logout();
+    $auth->start();
+}
+
+if ($auth->checkAuth()) {
+    /*
+     * The output of your site goes here.
+     */
+    echo 'You are authenticated, '.$auth->getUsername().'<br />';
+    echo '<a href="?logout">Logout</a>';
+} else {
+    echo 'You need to log in bro!';
+}
+
+?>
\ No newline at end of file
diff --git a/lib/docs/UNL_Auth/docs/examples/CAS_example.php b/lib/docs/UNL_Auth/docs/examples/CAS_example.php
new file mode 100644
index 0000000000000000000000000000000000000000..42acfc6dff5776434521d352519b0d0cc3c91160
--- /dev/null
+++ b/lib/docs/UNL_Auth/docs/examples/CAS_example.php
@@ -0,0 +1,22 @@
+<?php
+ini_set('display_errors', true);
+error_reporting(E_ALL);
+chdir(dirname(__FILE__).'/../../');
+require_once 'UNL/Auth.php';
+
+$auth = UNL_Auth::factory('CAS');
+
+if (isset($_GET['login'])) {
+	$auth->login();
+} elseif (isset($_GET['logout'])) {
+	$auth->logout();
+}
+
+if (!$auth->isLoggedIn()) {
+    // Could call $auth->login() here to get the party started.
+	echo "You are not logged in.\n<br />\n";
+	echo '<a href="?login=true">Click here to log in!</a>';
+} else {
+	echo "You are logged in as {$auth->getUser()}<br />";
+	echo "<a href='?logout'>logout</a>";
+}
diff --git a/lib/docs/UNL_Auth/docs/examples/SimpleCAS_example.php b/lib/docs/UNL_Auth/docs/examples/SimpleCAS_example.php
new file mode 100644
index 0000000000000000000000000000000000000000..d514e53980d381ea273aaa4aa3fec1be787c2636
--- /dev/null
+++ b/lib/docs/UNL_Auth/docs/examples/SimpleCAS_example.php
@@ -0,0 +1,22 @@
+<?php
+ini_set('display_errors', true);
+error_reporting(E_ALL);
+chdir(dirname(__FILE__).'/../../');
+require_once 'UNL/Auth.php';
+
+$auth = UNL_Auth::factory('SimpleCAS');
+
+if (isset($_GET['login'])) {
+    $auth->login();
+} elseif (isset($_GET['logout'])) {
+    $auth->logout();
+}
+
+if (!$auth->isLoggedIn()) {
+    // Could call $auth->login() here to get the party started.
+    echo "You are not logged in.\n<br />\n";
+    echo '<a href="?login=true">Click here to log in!</a>';
+} else {
+    echo "You are logged in as {$auth->getUser()}<br />";
+    echo "<a href='?logout'>logout</a>";
+}
\ No newline at end of file
diff --git a/lib/docs/UNL_Auth/docs/examples/Zend_SimpleCAS_example.php b/lib/docs/UNL_Auth/docs/examples/Zend_SimpleCAS_example.php
new file mode 100644
index 0000000000000000000000000000000000000000..adac078d28164bb35aa64c3727a047378b9eac59
--- /dev/null
+++ b/lib/docs/UNL_Auth/docs/examples/Zend_SimpleCAS_example.php
@@ -0,0 +1,26 @@
+<?php
+ini_set('display_errors', true);
+error_reporting(E_ALL);
+chdir(dirname(__FILE__).'/../../');
+require_once 'UNL/Auth.php';
+require_once 'Zend/Auth.php';
+
+$auth = Zend_Auth::getInstance();
+$authAdapter = UNL_Auth::ZendFactory('SimpleCAS');
+if (!$auth->hasIdentity()) {
+    $result = $auth->authenticate($authAdapter);
+    if (!$result->isValid()) {
+        // Authentication failed; print the reasons why
+        foreach ($result->getMessages() as $message) {
+            echo "$message\n";
+        }
+    } else {
+        // Authentication succeeded; the identity ($username) is stored
+        // in the session
+        // $result->getIdentity() === $auth->getIdentity()
+        echo 'Hello '.$result->getIdentity();
+    }
+} else {
+    echo 'Hello@';
+}
+
diff --git a/lib/downloads/HTTP_Request2-2.0.0beta3.tgz b/lib/downloads/HTTP_Request2-2.0.0beta3.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..790e40fe830bbdada2733edba199d2d0a53c55b0
Binary files /dev/null and b/lib/downloads/HTTP_Request2-2.0.0beta3.tgz differ
diff --git a/lib/downloads/Net_URL2-0.3.1.tgz b/lib/downloads/Net_URL2-0.3.1.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..a0abb1f560641c79d54f17fa9dcf7273be1b329d
Binary files /dev/null and b/lib/downloads/Net_URL2-0.3.1.tgz differ
diff --git a/lib/downloads/SimpleCAS-0.5.0.tgz b/lib/downloads/SimpleCAS-0.5.0.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..fef74eda21e32fe1e04758b9e59425a9e467992c
Binary files /dev/null and b/lib/downloads/SimpleCAS-0.5.0.tgz differ
diff --git a/lib/downloads/UNL_Auth-0.4.0.tgz b/lib/downloads/UNL_Auth-0.4.0.tgz
new file mode 100644
index 0000000000000000000000000000000000000000..006d5ec47141da50dad49eeaf0492e0393d7feae
Binary files /dev/null and b/lib/downloads/UNL_Auth-0.4.0.tgz differ
diff --git a/lib/php/HTTP/Request2.php b/lib/php/HTTP/Request2.php
new file mode 100644
index 0000000000000000000000000000000000000000..97903f78e0a49b52f535951432e45a156267d56e
--- /dev/null
+++ b/lib/php/HTTP/Request2.php
@@ -0,0 +1,1015 @@
+<?php
+/**
+ * Class representing a HTTP request message
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Request2.php 308735 2011-02-27 20:31:28Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * A class representing an URL as per RFC 3986.
+ */
+require_once 'Net/URL2.php';
+
+/**
+ * Exception class for HTTP_Request2 package
+ */
+require_once 'HTTP/Request2/Exception.php';
+
+/**
+ * Class representing a HTTP request message
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @version    Release: 2.0.0beta3
+ * @link       http://tools.ietf.org/html/rfc2616#section-5
+ */
+class HTTP_Request2 implements SplSubject
+{
+   /**#@+
+    * Constants for HTTP request methods
+    *
+    * @link http://tools.ietf.org/html/rfc2616#section-5.1.1
+    */
+    const METHOD_OPTIONS = 'OPTIONS';
+    const METHOD_GET     = 'GET';
+    const METHOD_HEAD    = 'HEAD';
+    const METHOD_POST    = 'POST';
+    const METHOD_PUT     = 'PUT';
+    const METHOD_DELETE  = 'DELETE';
+    const METHOD_TRACE   = 'TRACE';
+    const METHOD_CONNECT = 'CONNECT';
+   /**#@-*/
+
+   /**#@+
+    * Constants for HTTP authentication schemes
+    *
+    * @link http://tools.ietf.org/html/rfc2617
+    */
+    const AUTH_BASIC  = 'basic';
+    const AUTH_DIGEST = 'digest';
+   /**#@-*/
+
+   /**
+    * Regular expression used to check for invalid symbols in RFC 2616 tokens
+    * @link http://pear.php.net/bugs/bug.php?id=15630
+    */
+    const REGEXP_INVALID_TOKEN = '![\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]!';
+
+   /**
+    * Regular expression used to check for invalid symbols in cookie strings
+    * @link http://pear.php.net/bugs/bug.php?id=15630
+    * @link http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
+    */
+    const REGEXP_INVALID_COOKIE = '/[\s,;]/';
+
+   /**
+    * Fileinfo magic database resource
+    * @var  resource
+    * @see  detectMimeType()
+    */
+    private static $_fileinfoDb;
+
+   /**
+    * Observers attached to the request (instances of SplObserver)
+    * @var  array
+    */
+    protected $observers = array();
+
+   /**
+    * Request URL
+    * @var  Net_URL2
+    */
+    protected $url;
+
+   /**
+    * Request method
+    * @var  string
+    */
+    protected $method = self::METHOD_GET;
+
+   /**
+    * Authentication data
+    * @var  array
+    * @see  getAuth()
+    */
+    protected $auth;
+
+   /**
+    * Request headers
+    * @var  array
+    */
+    protected $headers = array();
+
+   /**
+    * Configuration parameters
+    * @var  array
+    * @see  setConfig()
+    */
+    protected $config = array(
+        'adapter'           => 'HTTP_Request2_Adapter_Socket',
+        'connect_timeout'   => 10,
+        'timeout'           => 0,
+        'use_brackets'      => true,
+        'protocol_version'  => '1.1',
+        'buffer_size'       => 16384,
+        'store_body'        => true,
+
+        'proxy_host'        => '',
+        'proxy_port'        => '',
+        'proxy_user'        => '',
+        'proxy_password'    => '',
+        'proxy_auth_scheme' => self::AUTH_BASIC,
+
+        'ssl_verify_peer'   => true,
+        'ssl_verify_host'   => true,
+        'ssl_cafile'        => null,
+        'ssl_capath'        => null,
+        'ssl_local_cert'    => null,
+        'ssl_passphrase'    => null,
+
+        'digest_compat_ie'  => false,
+
+        'follow_redirects'  => false,
+        'max_redirects'     => 5,
+        'strict_redirects'  => false
+    );
+
+   /**
+    * Last event in request / response handling, intended for observers
+    * @var  array
+    * @see  getLastEvent()
+    */
+    protected $lastEvent = array(
+        'name' => 'start',
+        'data' => null
+    );
+
+   /**
+    * Request body
+    * @var  string|resource
+    * @see  setBody()
+    */
+    protected $body = '';
+
+   /**
+    * Array of POST parameters
+    * @var  array
+    */
+    protected $postParams = array();
+
+   /**
+    * Array of file uploads (for multipart/form-data POST requests)
+    * @var  array
+    */
+    protected $uploads = array();
+
+   /**
+    * Adapter used to perform actual HTTP request
+    * @var  HTTP_Request2_Adapter
+    */
+    protected $adapter;
+
+   /**
+    * Cookie jar to persist cookies between requests
+    * @var HTTP_Request2_CookieJar
+    */
+    protected $cookieJar = null;
+
+   /**
+    * Constructor. Can set request URL, method and configuration array.
+    *
+    * Also sets a default value for User-Agent header.
+    *
+    * @param    string|Net_Url2     Request URL
+    * @param    string              Request method
+    * @param    array               Configuration for this Request instance
+    */
+    public function __construct($url = null, $method = self::METHOD_GET, array $config = array())
+    {
+        $this->setConfig($config);
+        if (!empty($url)) {
+            $this->setUrl($url);
+        }
+        if (!empty($method)) {
+            $this->setMethod($method);
+        }
+        $this->setHeader('user-agent', 'HTTP_Request2/2.0.0beta3 ' .
+                         '(http://pear.php.net/package/http_request2) ' .
+                         'PHP/' . phpversion());
+    }
+
+   /**
+    * Sets the URL for this request
+    *
+    * If the URL has userinfo part (username & password) these will be removed
+    * and converted to auth data. If the URL does not have a path component,
+    * that will be set to '/'.
+    *
+    * @param    string|Net_URL2 Request URL
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException
+    */
+    public function setUrl($url)
+    {
+        if (is_string($url)) {
+            $url = new Net_URL2(
+                $url, array(Net_URL2::OPTION_USE_BRACKETS => $this->config['use_brackets'])
+            );
+        }
+        if (!$url instanceof Net_URL2) {
+            throw new HTTP_Request2_LogicException(
+                'Parameter is not a valid HTTP URL',
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        // URL contains username / password?
+        if ($url->getUserinfo()) {
+            $username = $url->getUser();
+            $password = $url->getPassword();
+            $this->setAuth(rawurldecode($username), $password? rawurldecode($password): '');
+            $url->setUserinfo('');
+        }
+        if ('' == $url->getPath()) {
+            $url->setPath('/');
+        }
+        $this->url = $url;
+
+        return $this;
+    }
+
+   /**
+    * Returns the request URL
+    *
+    * @return   Net_URL2
+    */
+    public function getUrl()
+    {
+        return $this->url;
+    }
+
+   /**
+    * Sets the request method
+    *
+    * @param    string
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException if the method name is invalid
+    */
+    public function setMethod($method)
+    {
+        // Method name should be a token: http://tools.ietf.org/html/rfc2616#section-5.1.1
+        if (preg_match(self::REGEXP_INVALID_TOKEN, $method)) {
+            throw new HTTP_Request2_LogicException(
+                "Invalid request method '{$method}'",
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        $this->method = $method;
+
+        return $this;
+    }
+
+   /**
+    * Returns the request method
+    *
+    * @return   string
+    */
+    public function getMethod()
+    {
+        return $this->method;
+    }
+
+   /**
+    * Sets the configuration parameter(s)
+    *
+    * The following parameters are available:
+    * <ul>
+    *   <li> 'adapter'           - adapter to use (string)</li>
+    *   <li> 'connect_timeout'   - Connection timeout in seconds (integer)</li>
+    *   <li> 'timeout'           - Total number of seconds a request can take.
+    *                              Use 0 for no limit, should be greater than
+    *                              'connect_timeout' if set (integer)</li>
+    *   <li> 'use_brackets'      - Whether to append [] to array variable names (bool)</li>
+    *   <li> 'protocol_version'  - HTTP Version to use, '1.0' or '1.1' (string)</li>
+    *   <li> 'buffer_size'       - Buffer size to use for reading and writing (int)</li>
+    *   <li> 'store_body'        - Whether to store response body in response object.
+    *                              Set to false if receiving a huge response and
+    *                              using an Observer to save it (boolean)</li>
+    *   <li> 'proxy_host'        - Proxy server host (string)</li>
+    *   <li> 'proxy_port'        - Proxy server port (integer)</li>
+    *   <li> 'proxy_user'        - Proxy auth username (string)</li>
+    *   <li> 'proxy_password'    - Proxy auth password (string)</li>
+    *   <li> 'proxy_auth_scheme' - Proxy auth scheme, one of HTTP_Request2::AUTH_* constants (string)</li>
+    *   <li> 'ssl_verify_peer'   - Whether to verify peer's SSL certificate (bool)</li>
+    *   <li> 'ssl_verify_host'   - Whether to check that Common Name in SSL
+    *                              certificate matches host name (bool)</li>
+    *   <li> 'ssl_cafile'        - Cerificate Authority file to verify the peer
+    *                              with (use with 'ssl_verify_peer') (string)</li>
+    *   <li> 'ssl_capath'        - Directory holding multiple Certificate
+    *                              Authority files (string)</li>
+    *   <li> 'ssl_local_cert'    - Name of a file containing local cerificate (string)</li>
+    *   <li> 'ssl_passphrase'    - Passphrase with which local certificate
+    *                              was encoded (string)</li>
+    *   <li> 'digest_compat_ie'  - Whether to imitate behaviour of MSIE 5 and 6
+    *                              in using URL without query string in digest
+    *                              authentication (boolean)</li>
+    *   <li> 'follow_redirects'  - Whether to automatically follow HTTP Redirects (boolean)</li>
+    *   <li> 'max_redirects'     - Maximum number of redirects to follow (integer)</li>
+    *   <li> 'strict_redirects'  - Whether to keep request method on redirects via status 301 and
+    *                              302 (true, needed for compatibility with RFC 2616)
+    *                              or switch to GET (false, needed for compatibility with most
+    *                              browsers) (boolean)</li>
+    * </ul>
+    *
+    * @param    string|array    configuration parameter name or array
+    *                           ('parameter name' => 'parameter value')
+    * @param    mixed           parameter value if $nameOrConfig is not an array
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException If the parameter is unknown
+    */
+    public function setConfig($nameOrConfig, $value = null)
+    {
+        if (is_array($nameOrConfig)) {
+            foreach ($nameOrConfig as $name => $value) {
+                $this->setConfig($name, $value);
+            }
+
+        } else {
+            if (!array_key_exists($nameOrConfig, $this->config)) {
+                throw new HTTP_Request2_LogicException(
+                    "Unknown configuration parameter '{$nameOrConfig}'",
+                    HTTP_Request2_Exception::INVALID_ARGUMENT
+                );
+            }
+            $this->config[$nameOrConfig] = $value;
+        }
+
+        return $this;
+    }
+
+   /**
+    * Returns the value(s) of the configuration parameter(s)
+    *
+    * @param    string  parameter name
+    * @return   mixed   value of $name parameter, array of all configuration
+    *                   parameters if $name is not given
+    * @throws   HTTP_Request2_LogicException If the parameter is unknown
+    */
+    public function getConfig($name = null)
+    {
+        if (null === $name) {
+            return $this->config;
+        } elseif (!array_key_exists($name, $this->config)) {
+            throw new HTTP_Request2_LogicException(
+                "Unknown configuration parameter '{$name}'",
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        return $this->config[$name];
+    }
+
+   /**
+    * Sets the autentification data
+    *
+    * @param    string  user name
+    * @param    string  password
+    * @param    string  authentication scheme
+    * @return   HTTP_Request2
+    */
+    public function setAuth($user, $password = '', $scheme = self::AUTH_BASIC)
+    {
+        if (empty($user)) {
+            $this->auth = null;
+        } else {
+            $this->auth = array(
+                'user'     => (string)$user,
+                'password' => (string)$password,
+                'scheme'   => $scheme
+            );
+        }
+
+        return $this;
+    }
+
+   /**
+    * Returns the authentication data
+    *
+    * The array has the keys 'user', 'password' and 'scheme', where 'scheme'
+    * is one of the HTTP_Request2::AUTH_* constants.
+    *
+    * @return   array
+    */
+    public function getAuth()
+    {
+        return $this->auth;
+    }
+
+   /**
+    * Sets request header(s)
+    *
+    * The first parameter may be either a full header string 'header: value' or
+    * header name. In the former case $value parameter is ignored, in the latter
+    * the header's value will either be set to $value or the header will be
+    * removed if $value is null. The first parameter can also be an array of
+    * headers, in that case method will be called recursively.
+    *
+    * Note that headers are treated case insensitively as per RFC 2616.
+    *
+    * <code>
+    * $req->setHeader('Foo: Bar'); // sets the value of 'Foo' header to 'Bar'
+    * $req->setHeader('FoO', 'Baz'); // sets the value of 'Foo' header to 'Baz'
+    * $req->setHeader(array('foo' => 'Quux')); // sets the value of 'Foo' header to 'Quux'
+    * $req->setHeader('FOO'); // removes 'Foo' header from request
+    * </code>
+    *
+    * @param    string|array    header name, header string ('Header: value')
+    *                           or an array of headers
+    * @param    string|array|null header value if $name is not an array,
+    *                           header will be removed if value is null
+    * @param    bool            whether to replace previous header with the
+    *                           same name or append to its value
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException
+    */
+    public function setHeader($name, $value = null, $replace = true)
+    {
+        if (is_array($name)) {
+            foreach ($name as $k => $v) {
+                if (is_string($k)) {
+                    $this->setHeader($k, $v, $replace);
+                } else {
+                    $this->setHeader($v, null, $replace);
+                }
+            }
+        } else {
+            if (null === $value && strpos($name, ':')) {
+                list($name, $value) = array_map('trim', explode(':', $name, 2));
+            }
+            // Header name should be a token: http://tools.ietf.org/html/rfc2616#section-4.2
+            if (preg_match(self::REGEXP_INVALID_TOKEN, $name)) {
+                throw new HTTP_Request2_LogicException(
+                    "Invalid header name '{$name}'",
+                    HTTP_Request2_Exception::INVALID_ARGUMENT
+                );
+            }
+            // Header names are case insensitive anyway
+            $name = strtolower($name);
+            if (null === $value) {
+                unset($this->headers[$name]);
+
+            } else {
+                if (is_array($value)) {
+                    $value = implode(', ', array_map('trim', $value));
+                } elseif (is_string($value)) {
+                    $value = trim($value);
+                }
+                if (!isset($this->headers[$name]) || $replace) {
+                    $this->headers[$name] = $value;
+                } else {
+                    $this->headers[$name] .= ', ' . $value;
+                }
+            }
+        }
+
+        return $this;
+    }
+
+   /**
+    * Returns the request headers
+    *
+    * The array is of the form ('header name' => 'header value'), header names
+    * are lowercased
+    *
+    * @return   array
+    */
+    public function getHeaders()
+    {
+        return $this->headers;
+    }
+
+   /**
+    * Adds a cookie to the request
+    *
+    * If the request does not have a CookieJar object set, this method simply
+    * appends a cookie to "Cookie:" header.
+    *
+    * If a CookieJar object is available, the cookie is stored in that object.
+    * Data from request URL will be used for setting its 'domain' and 'path'
+    * parameters, 'expires' and 'secure' will be set to null and false,
+    * respectively. If you need further control, use CookieJar's methods.
+    *
+    * @param    string  cookie name
+    * @param    string  cookie value
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException
+    * @see      setCookieJar()
+    */
+    public function addCookie($name, $value)
+    {
+        if (!empty($this->cookieJar)) {
+            $this->cookieJar->store(array('name' => $name, 'value' => $value),
+                                    $this->url);
+
+        } else {
+            $cookie = $name . '=' . $value;
+            if (preg_match(self::REGEXP_INVALID_COOKIE, $cookie)) {
+                throw new HTTP_Request2_LogicException(
+                    "Invalid cookie: '{$cookie}'",
+                    HTTP_Request2_Exception::INVALID_ARGUMENT
+                );
+            }
+            $cookies = empty($this->headers['cookie'])? '': $this->headers['cookie'] . '; ';
+            $this->setHeader('cookie', $cookies . $cookie);
+        }
+
+        return $this;
+    }
+
+   /**
+    * Sets the request body
+    *
+    * If you provide file pointer rather than file name, it should support
+    * fstat() and rewind() operations.
+    *
+    * @param    string|resource|HTTP_Request2_MultipartBody  Either a string
+    *               with the body or filename containing body or pointer to
+    *               an open file or object with multipart body data
+    * @param    bool    Whether first parameter is a filename
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException
+    */
+    public function setBody($body, $isFilename = false)
+    {
+        if (!$isFilename && !is_resource($body)) {
+            if (!$body instanceof HTTP_Request2_MultipartBody) {
+                $this->body = (string)$body;
+            } else {
+                $this->body = $body;
+            }
+        } else {
+            $fileData = $this->fopenWrapper($body, empty($this->headers['content-type']));
+            $this->body = $fileData['fp'];
+            if (empty($this->headers['content-type'])) {
+                $this->setHeader('content-type', $fileData['type']);
+            }
+        }
+        $this->postParams = $this->uploads = array();
+
+        return $this;
+    }
+
+   /**
+    * Returns the request body
+    *
+    * @return   string|resource|HTTP_Request2_MultipartBody
+    */
+    public function getBody()
+    {
+        if (self::METHOD_POST == $this->method &&
+            (!empty($this->postParams) || !empty($this->uploads))
+        ) {
+            if (0 === strpos($this->headers['content-type'], 'application/x-www-form-urlencoded')) {
+                $body = http_build_query($this->postParams, '', '&');
+                if (!$this->getConfig('use_brackets')) {
+                    $body = preg_replace('/%5B\d+%5D=/', '=', $body);
+                }
+                // support RFC 3986 by not encoding '~' symbol (request #15368)
+                return str_replace('%7E', '~', $body);
+
+            } elseif (0 === strpos($this->headers['content-type'], 'multipart/form-data')) {
+                require_once 'HTTP/Request2/MultipartBody.php';
+                return new HTTP_Request2_MultipartBody(
+                    $this->postParams, $this->uploads, $this->getConfig('use_brackets')
+                );
+            }
+        }
+        return $this->body;
+    }
+
+   /**
+    * Adds a file to form-based file upload
+    *
+    * Used to emulate file upload via a HTML form. The method also sets
+    * Content-Type of HTTP request to 'multipart/form-data'.
+    *
+    * If you just want to send the contents of a file as the body of HTTP
+    * request you should use setBody() method.
+    *
+    * If you provide file pointers rather than file names, they should support
+    * fstat() and rewind() operations.
+    *
+    * @param    string  name of file-upload field
+    * @param    string|resource|array   full name of local file, pointer to
+    *               open file or an array of files
+    * @param    string  filename to send in the request
+    * @param    string  content-type of file being uploaded
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException
+    */
+    public function addUpload($fieldName, $filename, $sendFilename = null,
+                              $contentType = null)
+    {
+        if (!is_array($filename)) {
+            $fileData = $this->fopenWrapper($filename, empty($contentType));
+            $this->uploads[$fieldName] = array(
+                'fp'        => $fileData['fp'],
+                'filename'  => !empty($sendFilename)? $sendFilename
+                                :(is_string($filename)? basename($filename): 'anonymous.blob') ,
+                'size'      => $fileData['size'],
+                'type'      => empty($contentType)? $fileData['type']: $contentType
+            );
+        } else {
+            $fps = $names = $sizes = $types = array();
+            foreach ($filename as $f) {
+                if (!is_array($f)) {
+                    $f = array($f);
+                }
+                $fileData = $this->fopenWrapper($f[0], empty($f[2]));
+                $fps[]   = $fileData['fp'];
+                $names[] = !empty($f[1])? $f[1]
+                            :(is_string($f[0])? basename($f[0]): 'anonymous.blob');
+                $sizes[] = $fileData['size'];
+                $types[] = empty($f[2])? $fileData['type']: $f[2];
+            }
+            $this->uploads[$fieldName] = array(
+                'fp' => $fps, 'filename' => $names, 'size' => $sizes, 'type' => $types
+            );
+        }
+        if (empty($this->headers['content-type']) ||
+            'application/x-www-form-urlencoded' == $this->headers['content-type']
+        ) {
+            $this->setHeader('content-type', 'multipart/form-data');
+        }
+
+        return $this;
+    }
+
+   /**
+    * Adds POST parameter(s) to the request.
+    *
+    * @param    string|array    parameter name or array ('name' => 'value')
+    * @param    mixed           parameter value (can be an array)
+    * @return   HTTP_Request2
+    */
+    public function addPostParameter($name, $value = null)
+    {
+        if (!is_array($name)) {
+            $this->postParams[$name] = $value;
+        } else {
+            foreach ($name as $k => $v) {
+                $this->addPostParameter($k, $v);
+            }
+        }
+        if (empty($this->headers['content-type'])) {
+            $this->setHeader('content-type', 'application/x-www-form-urlencoded');
+        }
+
+        return $this;
+    }
+
+   /**
+    * Attaches a new observer
+    *
+    * @param    SplObserver
+    */
+    public function attach(SplObserver $observer)
+    {
+        foreach ($this->observers as $attached) {
+            if ($attached === $observer) {
+                return;
+            }
+        }
+        $this->observers[] = $observer;
+    }
+
+   /**
+    * Detaches an existing observer
+    *
+    * @param    SplObserver
+    */
+    public function detach(SplObserver $observer)
+    {
+        foreach ($this->observers as $key => $attached) {
+            if ($attached === $observer) {
+                unset($this->observers[$key]);
+                return;
+            }
+        }
+    }
+
+   /**
+    * Notifies all observers
+    */
+    public function notify()
+    {
+        foreach ($this->observers as $observer) {
+            $observer->update($this);
+        }
+    }
+
+   /**
+    * Sets the last event
+    *
+    * Adapters should use this method to set the current state of the request
+    * and notify the observers.
+    *
+    * @param    string  event name
+    * @param    mixed   event data
+    */
+    public function setLastEvent($name, $data = null)
+    {
+        $this->lastEvent = array(
+            'name' => $name,
+            'data' => $data
+        );
+        $this->notify();
+    }
+
+   /**
+    * Returns the last event
+    *
+    * Observers should use this method to access the last change in request.
+    * The following event names are possible:
+    * <ul>
+    *   <li>'connect'                 - after connection to remote server,
+    *                                   data is the destination (string)</li>
+    *   <li>'disconnect'              - after disconnection from server</li>
+    *   <li>'sentHeaders'             - after sending the request headers,
+    *                                   data is the headers sent (string)</li>
+    *   <li>'sentBodyPart'            - after sending a part of the request body,
+    *                                   data is the length of that part (int)</li>
+    *   <li>'sentBody'                - after sending the whole request body,
+    *                                   data is request body length (int)</li>
+    *   <li>'receivedHeaders'         - after receiving the response headers,
+    *                                   data is HTTP_Request2_Response object</li>
+    *   <li>'receivedBodyPart'        - after receiving a part of the response
+    *                                   body, data is that part (string)</li>
+    *   <li>'receivedEncodedBodyPart' - as 'receivedBodyPart', but data is still
+    *                                   encoded by Content-Encoding</li>
+    *   <li>'receivedBody'            - after receiving the complete response
+    *                                   body, data is HTTP_Request2_Response object</li>
+    * </ul>
+    * Different adapters may not send all the event types. Mock adapter does
+    * not send any events to the observers.
+    *
+    * @return   array   The array has two keys: 'name' and 'data'
+    */
+    public function getLastEvent()
+    {
+        return $this->lastEvent;
+    }
+
+   /**
+    * Sets the adapter used to actually perform the request
+    *
+    * You can pass either an instance of a class implementing HTTP_Request2_Adapter
+    * or a class name. The method will only try to include a file if the class
+    * name starts with HTTP_Request2_Adapter_, it will also try to prepend this
+    * prefix to the class name if it doesn't contain any underscores, so that
+    * <code>
+    * $request->setAdapter('curl');
+    * </code>
+    * will work.
+    *
+    * @param    string|HTTP_Request2_Adapter
+    * @return   HTTP_Request2
+    * @throws   HTTP_Request2_LogicException
+    */
+    public function setAdapter($adapter)
+    {
+        if (is_string($adapter)) {
+            if (!class_exists($adapter, false)) {
+                if (false === strpos($adapter, '_')) {
+                    $adapter = 'HTTP_Request2_Adapter_' . ucfirst($adapter);
+                }
+                if (preg_match('/^HTTP_Request2_Adapter_([a-zA-Z0-9]+)$/', $adapter)) {
+                    include_once str_replace('_', DIRECTORY_SEPARATOR, $adapter) . '.php';
+                }
+                if (!class_exists($adapter, false)) {
+                    throw new HTTP_Request2_LogicException(
+                        "Class {$adapter} not found",
+                        HTTP_Request2_Exception::MISSING_VALUE
+                    );
+                }
+            }
+            $adapter = new $adapter;
+        }
+        if (!$adapter instanceof HTTP_Request2_Adapter) {
+            throw new HTTP_Request2_LogicException(
+                'Parameter is not a HTTP request adapter',
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        $this->adapter = $adapter;
+
+        return $this;
+    }
+
+   /**
+    * Sets the cookie jar
+    *
+    * A cookie jar is used to maintain cookies across HTTP requests and
+    * responses. Cookies from jar will be automatically added to the request
+    * headers based on request URL.
+    *
+    * @param HTTP_Request2_CookieJar|bool   Existing CookieJar object, true to
+    *                                       create a new one, false to remove
+    */
+    public function setCookieJar($jar = true)
+    {
+        if (!class_exists('HTTP_Request2_CookieJar', false)) {
+            require_once 'HTTP/Request2/CookieJar.php';
+        }
+
+        if ($jar instanceof HTTP_Request2_CookieJar) {
+            $this->cookieJar = $jar;
+        } elseif (true === $jar) {
+            $this->cookieJar = new HTTP_Request2_CookieJar();
+        } elseif (!$jar) {
+            $this->cookieJar = null;
+        } else {
+            throw new HTTP_Request2_LogicException(
+                'Invalid parameter passed to setCookieJar()',
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+
+        return $this;
+    }
+
+   /**
+    * Returns current CookieJar object or null if none
+    *
+    * @return HTTP_Request2_CookieJar|null
+    */
+    public function getCookieJar()
+    {
+        return $this->cookieJar;
+    }
+
+   /**
+    * Sends the request and returns the response
+    *
+    * @throws   HTTP_Request2_Exception
+    * @return   HTTP_Request2_Response
+    */
+    public function send()
+    {
+        // Sanity check for URL
+        if (!$this->url instanceof Net_URL2
+            || !$this->url->isAbsolute()
+            || !in_array(strtolower($this->url->getScheme()), array('https', 'http'))
+        ) {
+            throw new HTTP_Request2_LogicException(
+                'HTTP_Request2 needs an absolute HTTP(S) request URL, '
+                . ($this->url instanceof Net_URL2
+                   ? 'none' : "'" . $this->url->__toString() . "'")
+                . ' given',
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        if (empty($this->adapter)) {
+            $this->setAdapter($this->getConfig('adapter'));
+        }
+        // magic_quotes_runtime may break file uploads and chunked response
+        // processing; see bug #4543. Don't use ini_get() here; see bug #16440.
+        if ($magicQuotes = get_magic_quotes_runtime()) {
+            set_magic_quotes_runtime(false);
+        }
+        // force using single byte encoding if mbstring extension overloads
+        // strlen() and substr(); see bug #1781, bug #10605
+        if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
+            $oldEncoding = mb_internal_encoding();
+            mb_internal_encoding('iso-8859-1');
+        }
+
+        try {
+            $response = $this->adapter->sendRequest($this);
+        } catch (Exception $e) {
+        }
+        // cleanup in either case (poor man's "finally" clause)
+        if ($magicQuotes) {
+            set_magic_quotes_runtime(true);
+        }
+        if (!empty($oldEncoding)) {
+            mb_internal_encoding($oldEncoding);
+        }
+        // rethrow the exception
+        if (!empty($e)) {
+            throw $e;
+        }
+        return $response;
+    }
+
+   /**
+    * Wrapper around fopen()/fstat() used by setBody() and addUpload()
+    *
+    * @param  string|resource file name or pointer to open file
+    * @param  bool            whether to try autodetecting MIME type of file,
+    *                         will only work if $file is a filename, not pointer
+    * @return array array('fp' => file pointer, 'size' => file size, 'type' => MIME type)
+    * @throws HTTP_Request2_LogicException
+    */
+    protected function fopenWrapper($file, $detectType = false)
+    {
+        if (!is_string($file) && !is_resource($file)) {
+            throw new HTTP_Request2_LogicException(
+                "Filename or file pointer resource expected",
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        $fileData = array(
+            'fp'   => is_string($file)? null: $file,
+            'type' => 'application/octet-stream',
+            'size' => 0
+        );
+        if (is_string($file)) {
+            $track = @ini_set('track_errors', 1);
+            if (!($fileData['fp'] = @fopen($file, 'rb'))) {
+                $e = new HTTP_Request2_LogicException(
+                    $php_errormsg, HTTP_Request2_Exception::READ_ERROR
+                );
+            }
+            @ini_set('track_errors', $track);
+            if (isset($e)) {
+                throw $e;
+            }
+            if ($detectType) {
+                $fileData['type'] = self::detectMimeType($file);
+            }
+        }
+        if (!($stat = fstat($fileData['fp']))) {
+            throw new HTTP_Request2_LogicException(
+                "fstat() call failed", HTTP_Request2_Exception::READ_ERROR
+            );
+        }
+        $fileData['size'] = $stat['size'];
+
+        return $fileData;
+    }
+
+   /**
+    * Tries to detect MIME type of a file
+    *
+    * The method will try to use fileinfo extension if it is available,
+    * deprecated mime_content_type() function in the other case. If neither
+    * works, default 'application/octet-stream' MIME type is returned
+    *
+    * @param    string  filename
+    * @return   string  file MIME type
+    */
+    protected static function detectMimeType($filename)
+    {
+        // finfo extension from PECL available
+        if (function_exists('finfo_open')) {
+            if (!isset(self::$_fileinfoDb)) {
+                self::$_fileinfoDb = @finfo_open(FILEINFO_MIME);
+            }
+            if (self::$_fileinfoDb) {
+                $info = finfo_file(self::$_fileinfoDb, $filename);
+            }
+        }
+        // (deprecated) mime_content_type function available
+        if (empty($info) && function_exists('mime_content_type')) {
+            return mime_content_type($filename);
+        }
+        return empty($info)? 'application/octet-stream': $info;
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/HTTP/Request2/Adapter.php b/lib/php/HTTP/Request2/Adapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..ca25abfc27420a498aefcef3b7601754bcb06d75
--- /dev/null
+++ b/lib/php/HTTP/Request2/Adapter.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * Base class for HTTP_Request2 adapters
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Adapter.php 308322 2011-02-14 13:58:03Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Class representing a HTTP response
+ */
+require_once 'HTTP/Request2/Response.php';
+
+/**
+ * Base class for HTTP_Request2 adapters
+ *
+ * HTTP_Request2 class itself only defines methods for aggregating the request
+ * data, all actual work of sending the request to the remote server and
+ * receiving its response is performed by adapters.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @version    Release: 2.0.0beta3
+ */
+abstract class HTTP_Request2_Adapter
+{
+   /**
+    * A list of methods that MUST NOT have a request body, per RFC 2616
+    * @var  array
+    */
+    protected static $bodyDisallowed = array('TRACE');
+
+   /**
+    * Methods having defined semantics for request body
+    *
+    * Content-Length header (indicating that the body follows, section 4.3 of
+    * RFC 2616) will be sent for these methods even if no body was added
+    *
+    * @var  array
+    * @link http://pear.php.net/bugs/bug.php?id=12900
+    * @link http://pear.php.net/bugs/bug.php?id=14740
+    */
+    protected static $bodyRequired = array('POST', 'PUT');
+
+   /**
+    * Request being sent
+    * @var  HTTP_Request2
+    */
+    protected $request;
+
+   /**
+    * Request body
+    * @var  string|resource|HTTP_Request2_MultipartBody
+    * @see  HTTP_Request2::getBody()
+    */
+    protected $requestBody;
+
+   /**
+    * Length of the request body
+    * @var  integer
+    */
+    protected $contentLength;
+
+   /**
+    * Sends request to the remote server and returns its response
+    *
+    * @param    HTTP_Request2
+    * @return   HTTP_Request2_Response
+    * @throws   HTTP_Request2_Exception
+    */
+    abstract public function sendRequest(HTTP_Request2 $request);
+
+   /**
+    * Calculates length of the request body, adds proper headers
+    *
+    * @param    array   associative array of request headers, this method will
+    *                   add proper 'Content-Length' and 'Content-Type' headers
+    *                   to this array (or remove them if not needed)
+    */
+    protected function calculateRequestLength(&$headers)
+    {
+        $this->requestBody = $this->request->getBody();
+
+        if (is_string($this->requestBody)) {
+            $this->contentLength = strlen($this->requestBody);
+        } elseif (is_resource($this->requestBody)) {
+            $stat = fstat($this->requestBody);
+            $this->contentLength = $stat['size'];
+            rewind($this->requestBody);
+        } else {
+            $this->contentLength = $this->requestBody->getLength();
+            $headers['content-type'] = 'multipart/form-data; boundary=' .
+                                       $this->requestBody->getBoundary();
+            $this->requestBody->rewind();
+        }
+
+        if (in_array($this->request->getMethod(), self::$bodyDisallowed) ||
+            0 == $this->contentLength
+        ) {
+            // No body: send a Content-Length header nonetheless (request #12900),
+            // but do that only for methods that require a body (bug #14740)
+            if (in_array($this->request->getMethod(), self::$bodyRequired)) {
+                $headers['content-length'] = 0;
+            } else {
+                unset($headers['content-length']);
+                // if the method doesn't require a body and doesn't have a
+                // body, don't send a Content-Type header. (request #16799)
+                unset($headers['content-type']);
+            }
+        } else {
+            if (empty($headers['content-type'])) {
+                $headers['content-type'] = 'application/x-www-form-urlencoded';
+            }
+            $headers['content-length'] = $this->contentLength;
+        }
+    }
+}
+?>
diff --git a/lib/php/HTTP/Request2/Adapter/Curl.php b/lib/php/HTTP/Request2/Adapter/Curl.php
new file mode 100644
index 0000000000000000000000000000000000000000..eeec8cb2fcf48c032dcef28949e5b851e1ae4822
--- /dev/null
+++ b/lib/php/HTTP/Request2/Adapter/Curl.php
@@ -0,0 +1,562 @@
+<?php
+/**
+ * Adapter for HTTP_Request2 wrapping around cURL extension
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Curl.php 309921 2011-04-03 16:43:02Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Base class for HTTP_Request2 adapters
+ */
+require_once 'HTTP/Request2/Adapter.php';
+
+/**
+ * Adapter for HTTP_Request2 wrapping around cURL extension
+ *
+ * @category    HTTP
+ * @package     HTTP_Request2
+ * @author      Alexey Borzov <avb@php.net>
+ * @version     Release: 2.0.0beta3
+ */
+class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
+{
+   /**
+    * Mapping of header names to cURL options
+    * @var  array
+    */
+    protected static $headerMap = array(
+        'accept-encoding' => CURLOPT_ENCODING,
+        'cookie'          => CURLOPT_COOKIE,
+        'referer'         => CURLOPT_REFERER,
+        'user-agent'      => CURLOPT_USERAGENT
+    );
+
+   /**
+    * Mapping of SSL context options to cURL options
+    * @var  array
+    */
+    protected static $sslContextMap = array(
+        'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,
+        'ssl_cafile'      => CURLOPT_CAINFO,
+        'ssl_capath'      => CURLOPT_CAPATH,
+        'ssl_local_cert'  => CURLOPT_SSLCERT,
+        'ssl_passphrase'  => CURLOPT_SSLCERTPASSWD
+   );
+
+   /**
+    * Mapping of CURLE_* constants to Exception subclasses and error codes
+    * @var  array
+    */
+    protected static $errorMap = array(
+        CURLE_UNSUPPORTED_PROTOCOL  => array('HTTP_Request2_MessageException',
+                                             HTTP_Request2_Exception::NON_HTTP_REDIRECT),
+        CURLE_COULDNT_RESOLVE_PROXY => array('HTTP_Request2_ConnectionException'),
+        CURLE_COULDNT_RESOLVE_HOST  => array('HTTP_Request2_ConnectionException'),
+        CURLE_COULDNT_CONNECT       => array('HTTP_Request2_ConnectionException'),
+        // error returned from write callback
+        CURLE_WRITE_ERROR           => array('HTTP_Request2_MessageException',
+                                             HTTP_Request2_Exception::NON_HTTP_REDIRECT),
+        CURLE_OPERATION_TIMEOUTED   => array('HTTP_Request2_MessageException',
+                                             HTTP_Request2_Exception::TIMEOUT),
+        CURLE_HTTP_RANGE_ERROR      => array('HTTP_Request2_MessageException'),
+        CURLE_SSL_CONNECT_ERROR     => array('HTTP_Request2_ConnectionException'),
+        CURLE_LIBRARY_NOT_FOUND     => array('HTTP_Request2_LogicException',
+                                             HTTP_Request2_Exception::MISCONFIGURATION),
+        CURLE_FUNCTION_NOT_FOUND    => array('HTTP_Request2_LogicException',
+                                             HTTP_Request2_Exception::MISCONFIGURATION),
+        CURLE_ABORTED_BY_CALLBACK   => array('HTTP_Request2_MessageException',
+                                             HTTP_Request2_Exception::NON_HTTP_REDIRECT),
+        CURLE_TOO_MANY_REDIRECTS    => array('HTTP_Request2_MessageException',
+                                             HTTP_Request2_Exception::TOO_MANY_REDIRECTS),
+        CURLE_SSL_PEER_CERTIFICATE  => array('HTTP_Request2_ConnectionException'),
+        CURLE_GOT_NOTHING           => array('HTTP_Request2_MessageException'),
+        CURLE_SSL_ENGINE_NOTFOUND   => array('HTTP_Request2_LogicException',
+                                             HTTP_Request2_Exception::MISCONFIGURATION),
+        CURLE_SSL_ENGINE_SETFAILED  => array('HTTP_Request2_LogicException',
+                                             HTTP_Request2_Exception::MISCONFIGURATION),
+        CURLE_SEND_ERROR            => array('HTTP_Request2_MessageException'),
+        CURLE_RECV_ERROR            => array('HTTP_Request2_MessageException'),
+        CURLE_SSL_CERTPROBLEM       => array('HTTP_Request2_LogicException',
+                                             HTTP_Request2_Exception::INVALID_ARGUMENT),
+        CURLE_SSL_CIPHER            => array('HTTP_Request2_ConnectionException'),
+        CURLE_SSL_CACERT            => array('HTTP_Request2_ConnectionException'),
+        CURLE_BAD_CONTENT_ENCODING  => array('HTTP_Request2_MessageException'),
+    );
+
+   /**
+    * Response being received
+    * @var  HTTP_Request2_Response
+    */
+    protected $response;
+
+   /**
+    * Whether 'sentHeaders' event was sent to observers
+    * @var  boolean
+    */
+    protected $eventSentHeaders = false;
+
+   /**
+    * Whether 'receivedHeaders' event was sent to observers
+    * @var boolean
+    */
+    protected $eventReceivedHeaders = false;
+
+   /**
+    * Position within request body
+    * @var  integer
+    * @see  callbackReadBody()
+    */
+    protected $position = 0;
+
+   /**
+    * Information about last transfer, as returned by curl_getinfo()
+    * @var  array
+    */
+    protected $lastInfo;
+
+   /**
+    * Creates a subclass of HTTP_Request2_Exception from curl error data
+    *
+    * @param resource curl handle
+    * @return HTTP_Request2_Exception
+    */
+    protected static function wrapCurlError($ch)
+    {
+        $nativeCode = curl_errno($ch);
+        $message    = 'Curl error: ' . curl_error($ch);
+        if (!isset(self::$errorMap[$nativeCode])) {
+            return new HTTP_Request2_Exception($message, 0, $nativeCode);
+        } else {
+            $class = self::$errorMap[$nativeCode][0];
+            $code  = empty(self::$errorMap[$nativeCode][1])
+                     ? 0 : self::$errorMap[$nativeCode][1];
+            return new $class($message, $code, $nativeCode);
+        }
+    }
+
+   /**
+    * Sends request to the remote server and returns its response
+    *
+    * @param    HTTP_Request2
+    * @return   HTTP_Request2_Response
+    * @throws   HTTP_Request2_Exception
+    */
+    public function sendRequest(HTTP_Request2 $request)
+    {
+        if (!extension_loaded('curl')) {
+            throw new HTTP_Request2_LogicException(
+                'cURL extension not available', HTTP_Request2_Exception::MISCONFIGURATION
+            );
+        }
+
+        $this->request              = $request;
+        $this->response             = null;
+        $this->position             = 0;
+        $this->eventSentHeaders     = false;
+        $this->eventReceivedHeaders = false;
+
+        try {
+            if (false === curl_exec($ch = $this->createCurlHandle())) {
+                $e = self::wrapCurlError($ch);
+            }
+        } catch (Exception $e) {
+        }
+        if (isset($ch)) {
+            $this->lastInfo = curl_getinfo($ch);
+            curl_close($ch);
+        }
+
+        $response = $this->response;
+        unset($this->request, $this->requestBody, $this->response);
+
+        if (!empty($e)) {
+            throw $e;
+        }
+
+        if ($jar = $request->getCookieJar()) {
+            $jar->addCookiesFromResponse($response, $request->getUrl());
+        }
+
+        if (0 < $this->lastInfo['size_download']) {
+            $request->setLastEvent('receivedBody', $response);
+        }
+        return $response;
+    }
+
+   /**
+    * Returns information about last transfer
+    *
+    * @return   array   associative array as returned by curl_getinfo()
+    */
+    public function getInfo()
+    {
+        return $this->lastInfo;
+    }
+
+   /**
+    * Creates a new cURL handle and populates it with data from the request
+    *
+    * @return   resource    a cURL handle, as created by curl_init()
+    * @throws   HTTP_Request2_LogicException
+    */
+    protected function createCurlHandle()
+    {
+        $ch = curl_init();
+
+        curl_setopt_array($ch, array(
+            // setup write callbacks
+            CURLOPT_HEADERFUNCTION => array($this, 'callbackWriteHeader'),
+            CURLOPT_WRITEFUNCTION  => array($this, 'callbackWriteBody'),
+            // buffer size
+            CURLOPT_BUFFERSIZE     => $this->request->getConfig('buffer_size'),
+            // connection timeout
+            CURLOPT_CONNECTTIMEOUT => $this->request->getConfig('connect_timeout'),
+            // save full outgoing headers, in case someone is interested
+            CURLINFO_HEADER_OUT    => true,
+            // request url
+            CURLOPT_URL            => $this->request->getUrl()->getUrl()
+        ));
+
+        // set up redirects
+        if (!$this->request->getConfig('follow_redirects')) {
+            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
+        } else {
+            if (!@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)) {
+                throw new HTTP_Request2_LogicException(
+                    'Redirect support in curl is unavailable due to open_basedir or safe_mode setting',
+                    HTTP_Request2_Exception::MISCONFIGURATION
+                );
+            }
+            curl_setopt($ch, CURLOPT_MAXREDIRS, $this->request->getConfig('max_redirects'));
+            // limit redirects to http(s), works in 5.2.10+
+            if (defined('CURLOPT_REDIR_PROTOCOLS')) {
+                curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
+            }
+            // works in 5.3.2+, http://bugs.php.net/bug.php?id=49571
+            if ($this->request->getConfig('strict_redirects') && defined('CURLOPT_POSTREDIR')) {
+                curl_setopt($ch, CURLOPT_POSTREDIR, 3);
+            }
+        }
+
+        // request timeout
+        if ($timeout = $this->request->getConfig('timeout')) {
+            curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+        }
+
+        // set HTTP version
+        switch ($this->request->getConfig('protocol_version')) {
+            case '1.0':
+                curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+                break;
+            case '1.1':
+                curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+        }
+
+        // set request method
+        switch ($this->request->getMethod()) {
+            case HTTP_Request2::METHOD_GET:
+                curl_setopt($ch, CURLOPT_HTTPGET, true);
+                break;
+            case HTTP_Request2::METHOD_POST:
+                curl_setopt($ch, CURLOPT_POST, true);
+                break;
+            case HTTP_Request2::METHOD_HEAD:
+                curl_setopt($ch, CURLOPT_NOBODY, true);
+                break;
+            case HTTP_Request2::METHOD_PUT:
+                curl_setopt($ch, CURLOPT_UPLOAD, true);
+                break;
+            default:
+                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());
+        }
+
+        // set proxy, if needed
+        if ($host = $this->request->getConfig('proxy_host')) {
+            if (!($port = $this->request->getConfig('proxy_port'))) {
+                throw new HTTP_Request2_LogicException(
+                    'Proxy port not provided', HTTP_Request2_Exception::MISSING_VALUE
+                );
+            }
+            curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);
+            if ($user = $this->request->getConfig('proxy_user')) {
+                curl_setopt($ch, CURLOPT_PROXYUSERPWD, $user . ':' .
+                            $this->request->getConfig('proxy_password'));
+                switch ($this->request->getConfig('proxy_auth_scheme')) {
+                    case HTTP_Request2::AUTH_BASIC:
+                        curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
+                        break;
+                    case HTTP_Request2::AUTH_DIGEST:
+                        curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
+                }
+            }
+        }
+
+        // set authentication data
+        if ($auth = $this->request->getAuth()) {
+            curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);
+            switch ($auth['scheme']) {
+                case HTTP_Request2::AUTH_BASIC:
+                    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+                    break;
+                case HTTP_Request2::AUTH_DIGEST:
+                    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
+            }
+        }
+
+        // set SSL options
+        if (0 == strcasecmp($this->request->getUrl()->getScheme(), 'https')) {
+            foreach ($this->request->getConfig() as $name => $value) {
+                if ('ssl_verify_host' == $name && null !== $value) {
+                    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $value? 2: 0);
+                } elseif (isset(self::$sslContextMap[$name]) && null !== $value) {
+                    curl_setopt($ch, self::$sslContextMap[$name], $value);
+                }
+            }
+        }
+
+        $headers = $this->request->getHeaders();
+        // make cURL automagically send proper header
+        if (!isset($headers['accept-encoding'])) {
+            $headers['accept-encoding'] = '';
+        }
+
+        if (($jar = $this->request->getCookieJar())
+            && ($cookies = $jar->getMatching($this->request->getUrl(), true))
+        ) {
+            $headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
+        }
+
+        // set headers having special cURL keys
+        foreach (self::$headerMap as $name => $option) {
+            if (isset($headers[$name])) {
+                curl_setopt($ch, $option, $headers[$name]);
+                unset($headers[$name]);
+            }
+        }
+
+        $this->calculateRequestLength($headers);
+        if (isset($headers['content-length'])) {
+            $this->workaroundPhpBug47204($ch, $headers);
+        }
+
+        // set headers not having special keys
+        $headersFmt = array();
+        foreach ($headers as $name => $value) {
+            $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
+            $headersFmt[]  = $canonicalName . ': ' . $value;
+        }
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headersFmt);
+
+        return $ch;
+    }
+
+   /**
+    * Workaround for PHP bug #47204 that prevents rewinding request body
+    *
+    * The workaround consists of reading the entire request body into memory
+    * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large
+    * file uploads, use Socket adapter instead.
+    *
+    * @param    resource    cURL handle
+    * @param    array       Request headers
+    */
+    protected function workaroundPhpBug47204($ch, &$headers)
+    {
+        // no redirects, no digest auth -> probably no rewind needed
+        if (!$this->request->getConfig('follow_redirects')
+            && (!($auth = $this->request->getAuth())
+                || HTTP_Request2::AUTH_DIGEST != $auth['scheme'])
+        ) {
+            curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));
+
+        // rewind may be needed, read the whole body into memory
+        } else {
+            if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {
+                $this->requestBody = $this->requestBody->__toString();
+
+            } elseif (is_resource($this->requestBody)) {
+                $fp = $this->requestBody;
+                $this->requestBody = '';
+                while (!feof($fp)) {
+                    $this->requestBody .= fread($fp, 16384);
+                }
+            }
+            // curl hangs up if content-length is present
+            unset($headers['content-length']);
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $this->requestBody);
+        }
+    }
+
+   /**
+    * Callback function called by cURL for reading the request body
+    *
+    * @param    resource    cURL handle
+    * @param    resource    file descriptor (not used)
+    * @param    integer     maximum length of data to return
+    * @return   string      part of the request body, up to $length bytes
+    */
+    protected function callbackReadBody($ch, $fd, $length)
+    {
+        if (!$this->eventSentHeaders) {
+            $this->request->setLastEvent(
+                'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
+            );
+            $this->eventSentHeaders = true;
+        }
+        if (in_array($this->request->getMethod(), self::$bodyDisallowed) ||
+            0 == $this->contentLength || $this->position >= $this->contentLength
+        ) {
+            return '';
+        }
+        if (is_string($this->requestBody)) {
+            $string = substr($this->requestBody, $this->position, $length);
+        } elseif (is_resource($this->requestBody)) {
+            $string = fread($this->requestBody, $length);
+        } else {
+            $string = $this->requestBody->read($length);
+        }
+        $this->request->setLastEvent('sentBodyPart', strlen($string));
+        $this->position += strlen($string);
+        return $string;
+    }
+
+   /**
+    * Callback function called by cURL for saving the response headers
+    *
+    * @param    resource    cURL handle
+    * @param    string      response header (with trailing CRLF)
+    * @return   integer     number of bytes saved
+    * @see      HTTP_Request2_Response::parseHeaderLine()
+    */
+    protected function callbackWriteHeader($ch, $string)
+    {
+        // we may receive a second set of headers if doing e.g. digest auth
+        if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {
+            // don't bother with 100-Continue responses (bug #15785)
+            if (!$this->eventSentHeaders ||
+                $this->response->getStatus() >= 200
+            ) {
+                $this->request->setLastEvent(
+                    'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)
+                );
+            }
+            $upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);
+            // if body wasn't read by a callback, send event with total body size
+            if ($upload > $this->position) {
+                $this->request->setLastEvent(
+                    'sentBodyPart', $upload - $this->position
+                );
+                $this->position = $upload;
+            }
+            if ($upload && (!$this->eventSentHeaders
+                            || $this->response->getStatus() >= 200)
+            ) {
+                $this->request->setLastEvent('sentBody', $upload);
+            }
+            $this->eventSentHeaders = true;
+            // we'll need a new response object
+            if ($this->eventReceivedHeaders) {
+                $this->eventReceivedHeaders = false;
+                $this->response             = null;
+            }
+        }
+        if (empty($this->response)) {
+            $this->response = new HTTP_Request2_Response(
+                $string, false, curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)
+            );
+        } else {
+            $this->response->parseHeaderLine($string);
+            if ('' == trim($string)) {
+                // don't bother with 100-Continue responses (bug #15785)
+                if (200 <= $this->response->getStatus()) {
+                    $this->request->setLastEvent('receivedHeaders', $this->response);
+                }
+
+                if ($this->request->getConfig('follow_redirects') && $this->response->isRedirect()) {
+                    $redirectUrl = new Net_URL2($this->response->getHeader('location'));
+
+                    // for versions lower than 5.2.10, check the redirection URL protocol
+                    if (!defined('CURLOPT_REDIR_PROTOCOLS') && $redirectUrl->isAbsolute()
+                        && !in_array($redirectUrl->getScheme(), array('http', 'https'))
+                    ) {
+                        return -1;
+                    }
+
+                    if ($jar = $this->request->getCookieJar()) {
+                        $jar->addCookiesFromResponse($this->response, $this->request->getUrl());
+                        if (!$redirectUrl->isAbsolute()) {
+                            $redirectUrl = $this->request->getUrl()->resolve($redirectUrl);
+                        }
+                        if ($cookies = $jar->getMatching($redirectUrl, true)) {
+                            curl_setopt($ch, CURLOPT_COOKIE, $cookies);
+                        }
+                    }
+                }
+                $this->eventReceivedHeaders = true;
+            }
+        }
+        return strlen($string);
+    }
+
+   /**
+    * Callback function called by cURL for saving the response body
+    *
+    * @param    resource    cURL handle (not used)
+    * @param    string      part of the response body
+    * @return   integer     number of bytes saved
+    * @see      HTTP_Request2_Response::appendBody()
+    */
+    protected function callbackWriteBody($ch, $string)
+    {
+        // cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if
+        // response doesn't start with proper HTTP status line (see bug #15716)
+        if (empty($this->response)) {
+            throw new HTTP_Request2_MessageException(
+                "Malformed response: {$string}",
+                HTTP_Request2_Exception::MALFORMED_RESPONSE
+            );
+        }
+        if ($this->request->getConfig('store_body')) {
+            $this->response->appendBody($string);
+        }
+        $this->request->setLastEvent('receivedBodyPart', $string);
+        return strlen($string);
+    }
+}
+?>
diff --git a/lib/php/HTTP/Request2/Adapter/Mock.php b/lib/php/HTTP/Request2/Adapter/Mock.php
new file mode 100644
index 0000000000000000000000000000000000000000..8e761c87353f42574c708d6f56460a28255f8627
--- /dev/null
+++ b/lib/php/HTTP/Request2/Adapter/Mock.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * Mock adapter intended for testing
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Mock.php 308322 2011-02-14 13:58:03Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Base class for HTTP_Request2 adapters
+ */
+require_once 'HTTP/Request2/Adapter.php';
+
+/**
+ * Mock adapter intended for testing
+ *
+ * Can be used to test applications depending on HTTP_Request2 package without
+ * actually performing any HTTP requests. This adapter will return responses
+ * previously added via addResponse()
+ * <code>
+ * $mock = new HTTP_Request2_Adapter_Mock();
+ * $mock->addResponse("HTTP/1.1 ... ");
+ *
+ * $request = new HTTP_Request2();
+ * $request->setAdapter($mock);
+ *
+ * // This will return the response set above
+ * $response = $req->send();
+ * </code>
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @version    Release: 2.0.0beta3
+ */
+class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter
+{
+   /**
+    * A queue of responses to be returned by sendRequest()
+    * @var  array
+    */
+    protected $responses = array();
+
+   /**
+    * Returns the next response from the queue built by addResponse()
+    *
+    * If the queue is empty it will return default empty response with status 400,
+    * if an Exception object was added to the queue it will be thrown.
+    *
+    * @param    HTTP_Request2
+    * @return   HTTP_Request2_Response
+    * @throws   Exception
+    */
+    public function sendRequest(HTTP_Request2 $request)
+    {
+        if (count($this->responses) > 0) {
+            $response = array_shift($this->responses);
+            if ($response instanceof HTTP_Request2_Response) {
+                return $response;
+            } else {
+                // rethrow the exception
+                $class   = get_class($response);
+                $message = $response->getMessage();
+                $code    = $response->getCode();
+                throw new $class($message, $code);
+            }
+        } else {
+            return self::createResponseFromString("HTTP/1.1 400 Bad Request\r\n\r\n");
+        }
+    }
+
+   /**
+    * Adds response to the queue
+    *
+    * @param    mixed   either a string, a pointer to an open file,
+    *                   an instance of HTTP_Request2_Response or Exception
+    * @throws   HTTP_Request2_Exception
+    */
+    public function addResponse($response)
+    {
+        if (is_string($response)) {
+            $response = self::createResponseFromString($response);
+        } elseif (is_resource($response)) {
+            $response = self::createResponseFromFile($response);
+        } elseif (!$response instanceof HTTP_Request2_Response &&
+                  !$response instanceof Exception
+        ) {
+            throw new HTTP_Request2_Exception('Parameter is not a valid response');
+        }
+        $this->responses[] = $response;
+    }
+
+   /**
+    * Creates a new HTTP_Request2_Response object from a string
+    *
+    * @param    string
+    * @return   HTTP_Request2_Response
+    * @throws   HTTP_Request2_Exception
+    */
+    public static function createResponseFromString($str)
+    {
+        $parts       = preg_split('!(\r?\n){2}!m', $str, 2);
+        $headerLines = explode("\n", $parts[0]);
+        $response    = new HTTP_Request2_Response(array_shift($headerLines));
+        foreach ($headerLines as $headerLine) {
+            $response->parseHeaderLine($headerLine);
+        }
+        $response->parseHeaderLine('');
+        if (isset($parts[1])) {
+            $response->appendBody($parts[1]);
+        }
+        return $response;
+    }
+
+   /**
+    * Creates a new HTTP_Request2_Response object from a file
+    *
+    * @param    resource    file pointer returned by fopen()
+    * @return   HTTP_Request2_Response
+    * @throws   HTTP_Request2_Exception
+    */
+    public static function createResponseFromFile($fp)
+    {
+        $response = new HTTP_Request2_Response(fgets($fp));
+        do {
+            $headerLine = fgets($fp);
+            $response->parseHeaderLine($headerLine);
+        } while ('' != trim($headerLine));
+
+        while (!feof($fp)) {
+            $response->appendBody(fread($fp, 8192));
+        }
+        return $response;
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/HTTP/Request2/Adapter/Socket.php b/lib/php/HTTP/Request2/Adapter/Socket.php
new file mode 100644
index 0000000000000000000000000000000000000000..5b4dc54234f1dad6a487f1f06d26c3f3e8285b76
--- /dev/null
+++ b/lib/php/HTTP/Request2/Adapter/Socket.php
@@ -0,0 +1,1084 @@
+<?php
+/**
+ * Socket-based adapter for HTTP_Request2
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Socket.php 309921 2011-04-03 16:43:02Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Base class for HTTP_Request2 adapters
+ */
+require_once 'HTTP/Request2/Adapter.php';
+
+/**
+ * Socket-based adapter for HTTP_Request2
+ *
+ * This adapter uses only PHP sockets and will work on almost any PHP
+ * environment. Code is based on original HTTP_Request PEAR package.
+ *
+ * @category    HTTP
+ * @package     HTTP_Request2
+ * @author      Alexey Borzov <avb@php.net>
+ * @version     Release: 2.0.0beta3
+ */
+class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
+{
+   /**
+    * Regular expression for 'token' rule from RFC 2616
+    */
+    const REGEXP_TOKEN = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+';
+
+   /**
+    * Regular expression for 'quoted-string' rule from RFC 2616
+    */
+    const REGEXP_QUOTED_STRING = '"(?:\\\\.|[^\\\\"])*"';
+
+   /**
+    * Connected sockets, needed for Keep-Alive support
+    * @var  array
+    * @see  connect()
+    */
+    protected static $sockets = array();
+
+   /**
+    * Data for digest authentication scheme
+    *
+    * The keys for the array are URL prefixes.
+    *
+    * The values are associative arrays with data (realm, nonce, nonce-count,
+    * opaque...) needed for digest authentication. Stored here to prevent making
+    * duplicate requests to digest-protected resources after we have already
+    * received the challenge.
+    *
+    * @var  array
+    */
+    protected static $challenges = array();
+
+   /**
+    * Connected socket
+    * @var  resource
+    * @see  connect()
+    */
+    protected $socket;
+
+   /**
+    * Challenge used for server digest authentication
+    * @var  array
+    */
+    protected $serverChallenge;
+
+   /**
+    * Challenge used for proxy digest authentication
+    * @var  array
+    */
+    protected $proxyChallenge;
+
+   /**
+    * Sum of start time and global timeout, exception will be thrown if request continues past this time
+    * @var  integer
+    */
+    protected $deadline = null;
+
+   /**
+    * Remaining length of the current chunk, when reading chunked response
+    * @var  integer
+    * @see  readChunked()
+    */
+    protected $chunkLength = 0;
+
+   /**
+    * Remaining amount of redirections to follow
+    *
+    * Starts at 'max_redirects' configuration parameter and is reduced on each
+    * subsequent redirect. An Exception will be thrown once it reaches zero.
+    *
+    * @var  integer
+    */
+    protected $redirectCountdown = null;
+
+   /**
+    * Sends request to the remote server and returns its response
+    *
+    * @param    HTTP_Request2
+    * @return   HTTP_Request2_Response
+    * @throws   HTTP_Request2_Exception
+    */
+    public function sendRequest(HTTP_Request2 $request)
+    {
+        $this->request = $request;
+
+        // Use global request timeout if given, see feature requests #5735, #8964
+        if ($timeout = $request->getConfig('timeout')) {
+            $this->deadline = time() + $timeout;
+        } else {
+            $this->deadline = null;
+        }
+
+        try {
+            $keepAlive = $this->connect();
+            $headers   = $this->prepareHeaders();
+            if (false === @fwrite($this->socket, $headers, strlen($headers))) {
+                throw new HTTP_Request2_MessageException('Error writing request');
+            }
+            // provide request headers to the observer, see request #7633
+            $this->request->setLastEvent('sentHeaders', $headers);
+            $this->writeBody();
+
+            if ($this->deadline && time() > $this->deadline) {
+                throw new HTTP_Request2_MessageException(
+                    'Request timed out after ' .
+                    $request->getConfig('timeout') . ' second(s)',
+                    HTTP_Request2_Exception::TIMEOUT
+                );
+            }
+
+            $response = $this->readResponse();
+
+            if ($jar = $request->getCookieJar()) {
+                $jar->addCookiesFromResponse($response, $request->getUrl());
+            }
+
+            if (!$this->canKeepAlive($keepAlive, $response)) {
+                $this->disconnect();
+            }
+
+            if ($this->shouldUseProxyDigestAuth($response)) {
+                return $this->sendRequest($request);
+            }
+            if ($this->shouldUseServerDigestAuth($response)) {
+                return $this->sendRequest($request);
+            }
+            if ($authInfo = $response->getHeader('authentication-info')) {
+                $this->updateChallenge($this->serverChallenge, $authInfo);
+            }
+            if ($proxyInfo = $response->getHeader('proxy-authentication-info')) {
+                $this->updateChallenge($this->proxyChallenge, $proxyInfo);
+            }
+
+        } catch (Exception $e) {
+            $this->disconnect();
+        }
+
+        unset($this->request, $this->requestBody);
+
+        if (!empty($e)) {
+            $this->redirectCountdown = null;
+            throw $e;
+        }
+
+        if (!$request->getConfig('follow_redirects') || !$response->isRedirect()) {
+            $this->redirectCountdown = null;
+            return $response;
+        } else {
+            return $this->handleRedirect($request, $response);
+        }
+    }
+
+   /**
+    * Connects to the remote server
+    *
+    * @return   bool    whether the connection can be persistent
+    * @throws   HTTP_Request2_Exception
+    */
+    protected function connect()
+    {
+        $secure  = 0 == strcasecmp($this->request->getUrl()->getScheme(), 'https');
+        $tunnel  = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
+        $headers = $this->request->getHeaders();
+        $reqHost = $this->request->getUrl()->getHost();
+        if (!($reqPort = $this->request->getUrl()->getPort())) {
+            $reqPort = $secure? 443: 80;
+        }
+
+        if ($host = $this->request->getConfig('proxy_host')) {
+            if (!($port = $this->request->getConfig('proxy_port'))) {
+                throw new HTTP_Request2_LogicException(
+                    'Proxy port not provided',
+                    HTTP_Request2_Exception::MISSING_VALUE
+                );
+            }
+            $proxy = true;
+        } else {
+            $host  = $reqHost;
+            $port  = $reqPort;
+            $proxy = false;
+        }
+
+        if ($tunnel && !$proxy) {
+            throw new HTTP_Request2_LogicException(
+                "Trying to perform CONNECT request without proxy",
+                HTTP_Request2_Exception::MISSING_VALUE
+            );
+        }
+        if ($secure && !in_array('ssl', stream_get_transports())) {
+            throw new HTTP_Request2_LogicException(
+                'Need OpenSSL support for https:// requests',
+                HTTP_Request2_Exception::MISCONFIGURATION
+            );
+        }
+
+        // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
+        // connection token to a proxy server...
+        if ($proxy && !$secure &&
+            !empty($headers['connection']) && 'Keep-Alive' == $headers['connection']
+        ) {
+            $this->request->setHeader('connection');
+        }
+
+        $keepAlive = ('1.1' == $this->request->getConfig('protocol_version') &&
+                      empty($headers['connection'])) ||
+                     (!empty($headers['connection']) &&
+                      'Keep-Alive' == $headers['connection']);
+        $host = ((!$secure || $proxy)? 'tcp://': 'ssl://') . $host;
+
+        $options = array();
+        if ($secure || $tunnel) {
+            foreach ($this->request->getConfig() as $name => $value) {
+                if ('ssl_' == substr($name, 0, 4) && null !== $value) {
+                    if ('ssl_verify_host' == $name) {
+                        if ($value) {
+                            $options['CN_match'] = $reqHost;
+                        }
+                    } else {
+                        $options[substr($name, 4)] = $value;
+                    }
+                }
+            }
+            ksort($options);
+        }
+
+        // Changing SSL context options after connection is established does *not*
+        // work, we need a new connection if options change
+        $remote    = $host . ':' . $port;
+        $socketKey = $remote . (($secure && $proxy)? "->{$reqHost}:{$reqPort}": '') .
+                     (empty($options)? '': ':' . serialize($options));
+        unset($this->socket);
+
+        // We use persistent connections and have a connected socket?
+        // Ensure that the socket is still connected, see bug #16149
+        if ($keepAlive && !empty(self::$sockets[$socketKey]) &&
+            !feof(self::$sockets[$socketKey])
+        ) {
+            $this->socket =& self::$sockets[$socketKey];
+
+        } elseif ($secure && $proxy && !$tunnel) {
+            $this->establishTunnel();
+            $this->request->setLastEvent(
+                'connect', "ssl://{$reqHost}:{$reqPort} via {$host}:{$port}"
+            );
+            self::$sockets[$socketKey] =& $this->socket;
+
+        } else {
+            // Set SSL context options if doing HTTPS request or creating a tunnel
+            $context = stream_context_create();
+            foreach ($options as $name => $value) {
+                if (!stream_context_set_option($context, 'ssl', $name, $value)) {
+                    throw new HTTP_Request2_LogicException(
+                        "Error setting SSL context option '{$name}'"
+                    );
+                }
+            }
+            $track = @ini_set('track_errors', 1);
+            $this->socket = @stream_socket_client(
+                $remote, $errno, $errstr,
+                $this->request->getConfig('connect_timeout'),
+                STREAM_CLIENT_CONNECT, $context
+            );
+            if (!$this->socket) {
+                $e = new HTTP_Request2_ConnectionException(
+                    "Unable to connect to {$remote}. Error: "
+                     . (empty($errstr)? $php_errormsg: $errstr), 0, $errno
+                );
+            }
+            @ini_set('track_errors', $track);
+            if (isset($e)) {
+                throw $e;
+            }
+            $this->request->setLastEvent('connect', $remote);
+            self::$sockets[$socketKey] =& $this->socket;
+        }
+        return $keepAlive;
+    }
+
+   /**
+    * Establishes a tunnel to a secure remote server via HTTP CONNECT request
+    *
+    * This method will fail if 'ssl_verify_peer' is enabled. Probably because PHP
+    * sees that we are connected to a proxy server (duh!) rather than the server
+    * that presents its certificate.
+    *
+    * @link     http://tools.ietf.org/html/rfc2817#section-5.2
+    * @throws   HTTP_Request2_Exception
+    */
+    protected function establishTunnel()
+    {
+        $donor   = new self;
+        $connect = new HTTP_Request2(
+            $this->request->getUrl(), HTTP_Request2::METHOD_CONNECT,
+            array_merge($this->request->getConfig(),
+                        array('adapter' => $donor))
+        );
+        $response = $connect->send();
+        // Need any successful (2XX) response
+        if (200 > $response->getStatus() || 300 <= $response->getStatus()) {
+            throw new HTTP_Request2_ConnectionException(
+                'Failed to connect via HTTPS proxy. Proxy response: ' .
+                $response->getStatus() . ' ' . $response->getReasonPhrase()
+            );
+        }
+        $this->socket = $donor->socket;
+
+        $modes = array(
+            STREAM_CRYPTO_METHOD_TLS_CLIENT,
+            STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
+            STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
+            STREAM_CRYPTO_METHOD_SSLv2_CLIENT
+        );
+
+        foreach ($modes as $mode) {
+            if (stream_socket_enable_crypto($this->socket, true, $mode)) {
+                return;
+            }
+        }
+        throw new HTTP_Request2_ConnectionException(
+            'Failed to enable secure connection when connecting through proxy'
+        );
+    }
+
+   /**
+    * Checks whether current connection may be reused or should be closed
+    *
+    * @param    boolean                 whether connection could be persistent
+    *                                   in the first place
+    * @param    HTTP_Request2_Response  response object to check
+    * @return   boolean
+    */
+    protected function canKeepAlive($requestKeepAlive, HTTP_Request2_Response $response)
+    {
+        // Do not close socket on successful CONNECT request
+        if (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() &&
+            200 <= $response->getStatus() && 300 > $response->getStatus()
+        ) {
+            return true;
+        }
+
+        $lengthKnown = 'chunked' == strtolower($response->getHeader('transfer-encoding'))
+                       || null !== $response->getHeader('content-length')
+                       // no body possible for such responses, see also request #17031
+                       || HTTP_Request2::METHOD_HEAD == $this->request->getMethod()
+                       || in_array($response->getStatus(), array(204, 304));
+        $persistent  = 'keep-alive' == strtolower($response->getHeader('connection')) ||
+                       (null === $response->getHeader('connection') &&
+                        '1.1' == $response->getVersion());
+        return $requestKeepAlive && $lengthKnown && $persistent;
+    }
+
+   /**
+    * Disconnects from the remote server
+    */
+    protected function disconnect()
+    {
+        if (is_resource($this->socket)) {
+            fclose($this->socket);
+            $this->socket = null;
+            $this->request->setLastEvent('disconnect');
+        }
+    }
+
+   /**
+    * Handles HTTP redirection
+    *
+    * This method will throw an Exception if redirect to a non-HTTP(S) location
+    * is attempted, also if number of redirects performed already is equal to
+    * 'max_redirects' configuration parameter.
+    *
+    * @param    HTTP_Request2               Original request
+    * @param    HTTP_Request2_Response      Response containing redirect
+    * @return   HTTP_Request2_Response      Response from a new location
+    * @throws   HTTP_Request2_Exception
+    */
+    protected function handleRedirect(HTTP_Request2 $request,
+                                      HTTP_Request2_Response $response)
+    {
+        if (is_null($this->redirectCountdown)) {
+            $this->redirectCountdown = $request->getConfig('max_redirects');
+        }
+        if (0 == $this->redirectCountdown) {
+            $this->redirectCountdown = null;
+            // Copying cURL behaviour
+            throw new HTTP_Request2_MessageException (
+                'Maximum (' . $request->getConfig('max_redirects') . ') redirects followed',
+                HTTP_Request2_Exception::TOO_MANY_REDIRECTS
+            );
+        }
+        $redirectUrl = new Net_URL2(
+            $response->getHeader('location'),
+            array(Net_URL2::OPTION_USE_BRACKETS => $request->getConfig('use_brackets'))
+        );
+        // refuse non-HTTP redirect
+        if ($redirectUrl->isAbsolute()
+            && !in_array($redirectUrl->getScheme(), array('http', 'https'))
+        ) {
+            $this->redirectCountdown = null;
+            throw new HTTP_Request2_MessageException(
+                'Refusing to redirect to a non-HTTP URL ' . $redirectUrl->__toString(),
+                HTTP_Request2_Exception::NON_HTTP_REDIRECT
+            );
+        }
+        // Theoretically URL should be absolute (see http://tools.ietf.org/html/rfc2616#section-14.30),
+        // but in practice it is often not
+        if (!$redirectUrl->isAbsolute()) {
+            $redirectUrl = $request->getUrl()->resolve($redirectUrl);
+        }
+        $redirect = clone $request;
+        $redirect->setUrl($redirectUrl);
+        if (303 == $response->getStatus() || (!$request->getConfig('strict_redirects')
+             && in_array($response->getStatus(), array(301, 302)))
+        ) {
+            $redirect->setMethod(HTTP_Request2::METHOD_GET);
+            $redirect->setBody('');
+        }
+
+        if (0 < $this->redirectCountdown) {
+            $this->redirectCountdown--;
+        }
+        return $this->sendRequest($redirect);
+    }
+
+   /**
+    * Checks whether another request should be performed with server digest auth
+    *
+    * Several conditions should be satisfied for it to return true:
+    *   - response status should be 401
+    *   - auth credentials should be set in the request object
+    *   - response should contain WWW-Authenticate header with digest challenge
+    *   - there is either no challenge stored for this URL or new challenge
+    *     contains stale=true parameter (in other case we probably just failed
+    *     due to invalid username / password)
+    *
+    * The method stores challenge values in $challenges static property
+    *
+    * @param    HTTP_Request2_Response  response to check
+    * @return   boolean whether another request should be performed
+    * @throws   HTTP_Request2_Exception in case of unsupported challenge parameters
+    */
+    protected function shouldUseServerDigestAuth(HTTP_Request2_Response $response)
+    {
+        // no sense repeating a request if we don't have credentials
+        if (401 != $response->getStatus() || !$this->request->getAuth()) {
+            return false;
+        }
+        if (!$challenge = $this->parseDigestChallenge($response->getHeader('www-authenticate'))) {
+            return false;
+        }
+
+        $url    = $this->request->getUrl();
+        $scheme = $url->getScheme();
+        $host   = $scheme . '://' . $url->getHost();
+        if ($port = $url->getPort()) {
+            if ((0 == strcasecmp($scheme, 'http') && 80 != $port) ||
+                (0 == strcasecmp($scheme, 'https') && 443 != $port)
+            ) {
+                $host .= ':' . $port;
+            }
+        }
+
+        if (!empty($challenge['domain'])) {
+            $prefixes = array();
+            foreach (preg_split('/\\s+/', $challenge['domain']) as $prefix) {
+                // don't bother with different servers
+                if ('/' == substr($prefix, 0, 1)) {
+                    $prefixes[] = $host . $prefix;
+                }
+            }
+        }
+        if (empty($prefixes)) {
+            $prefixes = array($host . '/');
+        }
+
+        $ret = true;
+        foreach ($prefixes as $prefix) {
+            if (!empty(self::$challenges[$prefix]) &&
+                (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
+            ) {
+                // probably credentials are invalid
+                $ret = false;
+            }
+            self::$challenges[$prefix] =& $challenge;
+        }
+        return $ret;
+    }
+
+   /**
+    * Checks whether another request should be performed with proxy digest auth
+    *
+    * Several conditions should be satisfied for it to return true:
+    *   - response status should be 407
+    *   - proxy auth credentials should be set in the request object
+    *   - response should contain Proxy-Authenticate header with digest challenge
+    *   - there is either no challenge stored for this proxy or new challenge
+    *     contains stale=true parameter (in other case we probably just failed
+    *     due to invalid username / password)
+    *
+    * The method stores challenge values in $challenges static property
+    *
+    * @param    HTTP_Request2_Response  response to check
+    * @return   boolean whether another request should be performed
+    * @throws   HTTP_Request2_Exception in case of unsupported challenge parameters
+    */
+    protected function shouldUseProxyDigestAuth(HTTP_Request2_Response $response)
+    {
+        if (407 != $response->getStatus() || !$this->request->getConfig('proxy_user')) {
+            return false;
+        }
+        if (!($challenge = $this->parseDigestChallenge($response->getHeader('proxy-authenticate')))) {
+            return false;
+        }
+
+        $key = 'proxy://' . $this->request->getConfig('proxy_host') .
+               ':' . $this->request->getConfig('proxy_port');
+
+        if (!empty(self::$challenges[$key]) &&
+            (empty($challenge['stale']) || strcasecmp('true', $challenge['stale']))
+        ) {
+            $ret = false;
+        } else {
+            $ret = true;
+        }
+        self::$challenges[$key] = $challenge;
+        return $ret;
+    }
+
+   /**
+    * Extracts digest method challenge from (WWW|Proxy)-Authenticate header value
+    *
+    * There is a problem with implementation of RFC 2617: several of the parameters
+    * are defined as quoted-string there and thus may contain backslash escaped
+    * double quotes (RFC 2616, section 2.2). However, RFC 2617 defines unq(X) as
+    * just value of quoted-string X without surrounding quotes, it doesn't speak
+    * about removing backslash escaping.
+    *
+    * Now realm parameter is user-defined and human-readable, strange things
+    * happen when it contains quotes:
+    *   - Apache allows quotes in realm, but apparently uses realm value without
+    *     backslashes for digest computation
+    *   - Squid allows (manually escaped) quotes there, but it is impossible to
+    *     authorize with either escaped or unescaped quotes used in digest,
+    *     probably it can't parse the response (?)
+    *   - Both IE and Firefox display realm value with backslashes in
+    *     the password popup and apparently use the same value for digest
+    *
+    * HTTP_Request2 follows IE and Firefox (and hopefully RFC 2617) in
+    * quoted-string handling, unfortunately that means failure to authorize
+    * sometimes
+    *
+    * @param    string  value of WWW-Authenticate or Proxy-Authenticate header
+    * @return   mixed   associative array with challenge parameters, false if
+    *                   no challenge is present in header value
+    * @throws   HTTP_Request2_NotImplementedException in case of unsupported challenge parameters
+    */
+    protected function parseDigestChallenge($headerValue)
+    {
+        $authParam   = '(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
+                       self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')';
+        $challenge   = "!(?<=^|\\s|,)Digest ({$authParam}\\s*(,\\s*|$))+!";
+        if (!preg_match($challenge, $headerValue, $matches)) {
+            return false;
+        }
+
+        preg_match_all('!' . $authParam . '!', $matches[0], $params);
+        $paramsAry   = array();
+        $knownParams = array('realm', 'domain', 'nonce', 'opaque', 'stale',
+                             'algorithm', 'qop');
+        for ($i = 0; $i < count($params[0]); $i++) {
+            // section 3.2.1: Any unrecognized directive MUST be ignored.
+            if (in_array($params[1][$i], $knownParams)) {
+                if ('"' == substr($params[2][$i], 0, 1)) {
+                    $paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
+                } else {
+                    $paramsAry[$params[1][$i]] = $params[2][$i];
+                }
+            }
+        }
+        // we only support qop=auth
+        if (!empty($paramsAry['qop']) &&
+            !in_array('auth', array_map('trim', explode(',', $paramsAry['qop'])))
+        ) {
+            throw new HTTP_Request2_NotImplementedException(
+                "Only 'auth' qop is currently supported in digest authentication, " .
+                "server requested '{$paramsAry['qop']}'"
+            );
+        }
+        // we only support algorithm=MD5
+        if (!empty($paramsAry['algorithm']) && 'MD5' != $paramsAry['algorithm']) {
+            throw new HTTP_Request2_NotImplementedException(
+                "Only 'MD5' algorithm is currently supported in digest authentication, " .
+                "server requested '{$paramsAry['algorithm']}'"
+            );
+        }
+
+        return $paramsAry;
+    }
+
+   /**
+    * Parses [Proxy-]Authentication-Info header value and updates challenge
+    *
+    * @param    array   challenge to update
+    * @param    string  value of [Proxy-]Authentication-Info header
+    * @todo     validate server rspauth response
+    */
+    protected function updateChallenge(&$challenge, $headerValue)
+    {
+        $authParam   = '!(' . self::REGEXP_TOKEN . ')\\s*=\\s*(' .
+                       self::REGEXP_TOKEN . '|' . self::REGEXP_QUOTED_STRING . ')!';
+        $paramsAry   = array();
+
+        preg_match_all($authParam, $headerValue, $params);
+        for ($i = 0; $i < count($params[0]); $i++) {
+            if ('"' == substr($params[2][$i], 0, 1)) {
+                $paramsAry[$params[1][$i]] = substr($params[2][$i], 1, -1);
+            } else {
+                $paramsAry[$params[1][$i]] = $params[2][$i];
+            }
+        }
+        // for now, just update the nonce value
+        if (!empty($paramsAry['nextnonce'])) {
+            $challenge['nonce'] = $paramsAry['nextnonce'];
+            $challenge['nc']    = 1;
+        }
+    }
+
+   /**
+    * Creates a value for [Proxy-]Authorization header when using digest authentication
+    *
+    * @param    string  user name
+    * @param    string  password
+    * @param    string  request URL
+    * @param    array   digest challenge parameters
+    * @return   string  value of [Proxy-]Authorization request header
+    * @link     http://tools.ietf.org/html/rfc2617#section-3.2.2
+    */
+    protected function createDigestResponse($user, $password, $url, &$challenge)
+    {
+        if (false !== ($q = strpos($url, '?')) &&
+            $this->request->getConfig('digest_compat_ie')
+        ) {
+            $url = substr($url, 0, $q);
+        }
+
+        $a1 = md5($user . ':' . $challenge['realm'] . ':' . $password);
+        $a2 = md5($this->request->getMethod() . ':' . $url);
+
+        if (empty($challenge['qop'])) {
+            $digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $a2);
+        } else {
+            $challenge['cnonce'] = 'Req2.' . rand();
+            if (empty($challenge['nc'])) {
+                $challenge['nc'] = 1;
+            }
+            $nc     = sprintf('%08x', $challenge['nc']++);
+            $digest = md5($a1 . ':' . $challenge['nonce'] . ':' . $nc . ':' .
+                          $challenge['cnonce'] . ':auth:' . $a2);
+        }
+        return 'Digest username="' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $user) . '", ' .
+               'realm="' . $challenge['realm'] . '", ' .
+               'nonce="' . $challenge['nonce'] . '", ' .
+               'uri="' . $url . '", ' .
+               'response="' . $digest . '"' .
+               (!empty($challenge['opaque'])?
+                ', opaque="' . $challenge['opaque'] . '"':
+                '') .
+               (!empty($challenge['qop'])?
+                ', qop="auth", nc=' . $nc . ', cnonce="' . $challenge['cnonce'] . '"':
+                '');
+    }
+
+   /**
+    * Adds 'Authorization' header (if needed) to request headers array
+    *
+    * @param    array   request headers
+    * @param    string  request host (needed for digest authentication)
+    * @param    string  request URL (needed for digest authentication)
+    * @throws   HTTP_Request2_NotImplementedException
+    */
+    protected function addAuthorizationHeader(&$headers, $requestHost, $requestUrl)
+    {
+        if (!($auth = $this->request->getAuth())) {
+            return;
+        }
+        switch ($auth['scheme']) {
+            case HTTP_Request2::AUTH_BASIC:
+                $headers['authorization'] =
+                    'Basic ' . base64_encode($auth['user'] . ':' . $auth['password']);
+                break;
+
+            case HTTP_Request2::AUTH_DIGEST:
+                unset($this->serverChallenge);
+                $fullUrl = ('/' == $requestUrl[0])?
+                           $this->request->getUrl()->getScheme() . '://' .
+                            $requestHost . $requestUrl:
+                           $requestUrl;
+                foreach (array_keys(self::$challenges) as $key) {
+                    if ($key == substr($fullUrl, 0, strlen($key))) {
+                        $headers['authorization'] = $this->createDigestResponse(
+                            $auth['user'], $auth['password'],
+                            $requestUrl, self::$challenges[$key]
+                        );
+                        $this->serverChallenge =& self::$challenges[$key];
+                        break;
+                    }
+                }
+                break;
+
+            default:
+                throw new HTTP_Request2_NotImplementedException(
+                    "Unknown HTTP authentication scheme '{$auth['scheme']}'"
+                );
+        }
+    }
+
+   /**
+    * Adds 'Proxy-Authorization' header (if needed) to request headers array
+    *
+    * @param    array   request headers
+    * @param    string  request URL (needed for digest authentication)
+    * @throws   HTTP_Request2_NotImplementedException
+    */
+    protected function addProxyAuthorizationHeader(&$headers, $requestUrl)
+    {
+        if (!$this->request->getConfig('proxy_host') ||
+            !($user = $this->request->getConfig('proxy_user')) ||
+            (0 == strcasecmp('https', $this->request->getUrl()->getScheme()) &&
+             HTTP_Request2::METHOD_CONNECT != $this->request->getMethod())
+        ) {
+            return;
+        }
+
+        $password = $this->request->getConfig('proxy_password');
+        switch ($this->request->getConfig('proxy_auth_scheme')) {
+            case HTTP_Request2::AUTH_BASIC:
+                $headers['proxy-authorization'] =
+                    'Basic ' . base64_encode($user . ':' . $password);
+                break;
+
+            case HTTP_Request2::AUTH_DIGEST:
+                unset($this->proxyChallenge);
+                $proxyUrl = 'proxy://' . $this->request->getConfig('proxy_host') .
+                            ':' . $this->request->getConfig('proxy_port');
+                if (!empty(self::$challenges[$proxyUrl])) {
+                    $headers['proxy-authorization'] = $this->createDigestResponse(
+                        $user, $password,
+                        $requestUrl, self::$challenges[$proxyUrl]
+                    );
+                    $this->proxyChallenge =& self::$challenges[$proxyUrl];
+                }
+                break;
+
+            default:
+                throw new HTTP_Request2_NotImplementedException(
+                    "Unknown HTTP authentication scheme '" .
+                    $this->request->getConfig('proxy_auth_scheme') . "'"
+                );
+        }
+    }
+
+
+   /**
+    * Creates the string with the Request-Line and request headers
+    *
+    * @return   string
+    * @throws   HTTP_Request2_Exception
+    */
+    protected function prepareHeaders()
+    {
+        $headers = $this->request->getHeaders();
+        $url     = $this->request->getUrl();
+        $connect = HTTP_Request2::METHOD_CONNECT == $this->request->getMethod();
+        $host    = $url->getHost();
+
+        $defaultPort = 0 == strcasecmp($url->getScheme(), 'https')? 443: 80;
+        if (($port = $url->getPort()) && $port != $defaultPort || $connect) {
+            $host .= ':' . (empty($port)? $defaultPort: $port);
+        }
+        // Do not overwrite explicitly set 'Host' header, see bug #16146
+        if (!isset($headers['host'])) {
+            $headers['host'] = $host;
+        }
+
+        if ($connect) {
+            $requestUrl = $host;
+
+        } else {
+            if (!$this->request->getConfig('proxy_host') ||
+                0 == strcasecmp($url->getScheme(), 'https')
+            ) {
+                $requestUrl = '';
+            } else {
+                $requestUrl = $url->getScheme() . '://' . $host;
+            }
+            $path        = $url->getPath();
+            $query       = $url->getQuery();
+            $requestUrl .= (empty($path)? '/': $path) . (empty($query)? '': '?' . $query);
+        }
+
+        if ('1.1' == $this->request->getConfig('protocol_version') &&
+            extension_loaded('zlib') && !isset($headers['accept-encoding'])
+        ) {
+            $headers['accept-encoding'] = 'gzip, deflate';
+        }
+        if (($jar = $this->request->getCookieJar())
+            && ($cookies = $jar->getMatching($this->request->getUrl(), true))
+        ) {
+            $headers['cookie'] = (empty($headers['cookie'])? '': $headers['cookie'] . '; ') . $cookies;
+        }
+
+        $this->addAuthorizationHeader($headers, $host, $requestUrl);
+        $this->addProxyAuthorizationHeader($headers, $requestUrl);
+        $this->calculateRequestLength($headers);
+
+        $headersStr = $this->request->getMethod() . ' ' . $requestUrl . ' HTTP/' .
+                      $this->request->getConfig('protocol_version') . "\r\n";
+        foreach ($headers as $name => $value) {
+            $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
+            $headersStr   .= $canonicalName . ': ' . $value . "\r\n";
+        }
+        return $headersStr . "\r\n";
+    }
+
+   /**
+    * Sends the request body
+    *
+    * @throws   HTTP_Request2_MessageException
+    */
+    protected function writeBody()
+    {
+        if (in_array($this->request->getMethod(), self::$bodyDisallowed) ||
+            0 == $this->contentLength
+        ) {
+            return;
+        }
+
+        $position   = 0;
+        $bufferSize = $this->request->getConfig('buffer_size');
+        while ($position < $this->contentLength) {
+            if (is_string($this->requestBody)) {
+                $str = substr($this->requestBody, $position, $bufferSize);
+            } elseif (is_resource($this->requestBody)) {
+                $str = fread($this->requestBody, $bufferSize);
+            } else {
+                $str = $this->requestBody->read($bufferSize);
+            }
+            if (false === @fwrite($this->socket, $str, strlen($str))) {
+                throw new HTTP_Request2_MessageException('Error writing request');
+            }
+            // Provide the length of written string to the observer, request #7630
+            $this->request->setLastEvent('sentBodyPart', strlen($str));
+            $position += strlen($str);
+        }
+        $this->request->setLastEvent('sentBody', $this->contentLength);
+    }
+
+   /**
+    * Reads the remote server's response
+    *
+    * @return   HTTP_Request2_Response
+    * @throws   HTTP_Request2_Exception
+    */
+    protected function readResponse()
+    {
+        $bufferSize = $this->request->getConfig('buffer_size');
+
+        do {
+            $response = new HTTP_Request2_Response(
+                $this->readLine($bufferSize), true, $this->request->getUrl()
+            );
+            do {
+                $headerLine = $this->readLine($bufferSize);
+                $response->parseHeaderLine($headerLine);
+            } while ('' != $headerLine);
+        } while (in_array($response->getStatus(), array(100, 101)));
+
+        $this->request->setLastEvent('receivedHeaders', $response);
+
+        // No body possible in such responses
+        if (HTTP_Request2::METHOD_HEAD == $this->request->getMethod() ||
+            (HTTP_Request2::METHOD_CONNECT == $this->request->getMethod() &&
+             200 <= $response->getStatus() && 300 > $response->getStatus()) ||
+            in_array($response->getStatus(), array(204, 304))
+        ) {
+            return $response;
+        }
+
+        $chunked = 'chunked' == $response->getHeader('transfer-encoding');
+        $length  = $response->getHeader('content-length');
+        $hasBody = false;
+        if ($chunked || null === $length || 0 < intval($length)) {
+            // RFC 2616, section 4.4:
+            // 3. ... If a message is received with both a
+            // Transfer-Encoding header field and a Content-Length header field,
+            // the latter MUST be ignored.
+            $toRead = ($chunked || null === $length)? null: $length;
+            $this->chunkLength = 0;
+
+            while (!feof($this->socket) && (is_null($toRead) || 0 < $toRead)) {
+                if ($chunked) {
+                    $data = $this->readChunked($bufferSize);
+                } elseif (is_null($toRead)) {
+                    $data = $this->fread($bufferSize);
+                } else {
+                    $data    = $this->fread(min($toRead, $bufferSize));
+                    $toRead -= strlen($data);
+                }
+                if ('' == $data && (!$this->chunkLength || feof($this->socket))) {
+                    break;
+                }
+
+                $hasBody = true;
+                if ($this->request->getConfig('store_body')) {
+                    $response->appendBody($data);
+                }
+                if (!in_array($response->getHeader('content-encoding'), array('identity', null))) {
+                    $this->request->setLastEvent('receivedEncodedBodyPart', $data);
+                } else {
+                    $this->request->setLastEvent('receivedBodyPart', $data);
+                }
+            }
+        }
+
+        if ($hasBody) {
+            $this->request->setLastEvent('receivedBody', $response);
+        }
+        return $response;
+    }
+
+   /**
+    * Reads until either the end of the socket or a newline, whichever comes first
+    *
+    * Strips the trailing newline from the returned data, handles global
+    * request timeout. Method idea borrowed from Net_Socket PEAR package.
+    *
+    * @param    int     buffer size to use for reading
+    * @return   Available data up to the newline (not including newline)
+    * @throws   HTTP_Request2_MessageException     In case of timeout
+    */
+    protected function readLine($bufferSize)
+    {
+        $line = '';
+        while (!feof($this->socket)) {
+            if ($this->deadline) {
+                stream_set_timeout($this->socket, max($this->deadline - time(), 1));
+            }
+            $line .= @fgets($this->socket, $bufferSize);
+            $info  = stream_get_meta_data($this->socket);
+            if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
+                $reason = $this->deadline
+                          ? 'after ' . $this->request->getConfig('timeout') . ' second(s)'
+                          : 'due to default_socket_timeout php.ini setting';
+                throw new HTTP_Request2_MessageException(
+                    "Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
+                );
+            }
+            if (substr($line, -1) == "\n") {
+                return rtrim($line, "\r\n");
+            }
+        }
+        return $line;
+    }
+
+   /**
+    * Wrapper around fread(), handles global request timeout
+    *
+    * @param    int     Reads up to this number of bytes
+    * @return   Data read from socket
+    * @throws   HTTP_Request2_MessageException     In case of timeout
+    */
+    protected function fread($length)
+    {
+        if ($this->deadline) {
+            stream_set_timeout($this->socket, max($this->deadline - time(), 1));
+        }
+        $data = fread($this->socket, $length);
+        $info = stream_get_meta_data($this->socket);
+        if ($info['timed_out'] || $this->deadline && time() > $this->deadline) {
+            $reason = $this->deadline
+                      ? 'after ' . $this->request->getConfig('timeout') . ' second(s)'
+                      : 'due to default_socket_timeout php.ini setting';
+            throw new HTTP_Request2_MessageException(
+                "Request timed out {$reason}", HTTP_Request2_Exception::TIMEOUT
+            );
+        }
+        return $data;
+    }
+
+   /**
+    * Reads a part of response body encoded with chunked Transfer-Encoding
+    *
+    * @param    int     buffer size to use for reading
+    * @return   string
+    * @throws   HTTP_Request2_MessageException
+    */
+    protected function readChunked($bufferSize)
+    {
+        // at start of the next chunk?
+        if (0 == $this->chunkLength) {
+            $line = $this->readLine($bufferSize);
+            if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
+                throw new HTTP_Request2_MessageException(
+                    "Cannot decode chunked response, invalid chunk length '{$line}'",
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            } else {
+                $this->chunkLength = hexdec($matches[1]);
+                // Chunk with zero length indicates the end
+                if (0 == $this->chunkLength) {
+                    $this->readLine($bufferSize);
+                    return '';
+                }
+            }
+        }
+        $data = $this->fread(min($this->chunkLength, $bufferSize));
+        $this->chunkLength -= strlen($data);
+        if (0 == $this->chunkLength) {
+            $this->readLine($bufferSize); // Trailing CRLF
+        }
+        return $data;
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/lib/php/HTTP/Request2/CookieJar.php b/lib/php/HTTP/Request2/CookieJar.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d5cf97806868ff2d3a46ca30594ebb035ef4aac
--- /dev/null
+++ b/lib/php/HTTP/Request2/CookieJar.php
@@ -0,0 +1,499 @@
+<?php
+/**
+ * Stores cookies and passes them between HTTP requests
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: CookieJar.php 308629 2011-02-24 17:34:24Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Class representing a HTTP request message */
+require_once 'HTTP/Request2.php';
+
+/**
+ * Stores cookies and passes them between HTTP requests
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @version    Release: 2.0.0beta3
+ */
+class HTTP_Request2_CookieJar implements Serializable
+{
+   /**
+    * Array of stored cookies
+    *
+    * The array is indexed by domain, path and cookie name
+    *   .example.com
+    *     /
+    *       some_cookie => cookie data
+    *     /subdir
+    *       other_cookie => cookie data
+    *   .example.org
+    *     ...
+    *
+    * @var array
+    */
+    protected $cookies = array();
+
+   /**
+    * Whether session cookies should be serialized when serializing the jar
+    * @var bool
+    */
+    protected $serializeSession = false;
+
+   /**
+    * Whether Public Suffix List should be used for domain matching
+    * @var bool
+    */
+    protected $useList = true;
+
+   /**
+    * Array with Public Suffix List data
+    * @var  array
+    * @link http://publicsuffix.org/
+    */
+    protected static $psl = array();
+
+   /**
+    * Class constructor, sets various options
+    *
+    * @param bool Controls serializing session cookies, see {@link serializeSessionCookies()}
+    * @param bool Controls using Public Suffix List, see {@link usePublicSuffixList()}
+    */
+    public function __construct($serializeSessionCookies = false, $usePublicSuffixList = true)
+    {
+        $this->serializeSessionCookies($serializeSessionCookies);
+        $this->usePublicSuffixList($usePublicSuffixList);
+    }
+
+   /**
+    * Returns current time formatted in ISO-8601 at UTC timezone
+    *
+    * @return string
+    */
+    protected function now()
+    {
+        $dt = new DateTime();
+        $dt->setTimezone(new DateTimeZone('UTC'));
+        return $dt->format(DateTime::ISO8601);
+    }
+
+   /**
+    * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields
+    *
+    * The checks are as follows:
+    *   - cookie array should contain 'name' and 'value' fields;
+    *   - name and value should not contain disallowed symbols;
+    *   - 'expires' should be either empty parseable by DateTime;
+    *   - 'domain' and 'path' should be either not empty or an URL where
+    *     cookie was set should be provided.
+    *   - if $setter is provided, then document at that URL should be allowed
+    *     to set a cookie for that 'domain'. If $setter is not provided,
+    *     then no domain checks will be made.
+    *
+    * 'expires' field will be converted to ISO8601 format from COOKIE format,
+    * 'domain' and 'path' will be set from setter URL if empty.
+    *
+    * @param    array    cookie data, as returned by {@link HTTP_Request2_Response::getCookies()}
+    * @param    Net_URL2 URL of the document that sent Set-Cookie header
+    * @return   array    Updated cookie array
+    * @throws   HTTP_Request2_LogicException
+    * @throws   HTTP_Request2_MessageException
+    */
+    protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null)
+    {
+        if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) {
+            throw new HTTP_Request2_LogicException(
+                "Cookie array should contain 'name' and 'value' fields",
+                HTTP_Request2_Exception::MISSING_VALUE
+            );
+        }
+        if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['name'])) {
+            throw new HTTP_Request2_LogicException(
+                "Invalid cookie name: '{$cookie['name']}'",
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['value'])) {
+            throw new HTTP_Request2_LogicException(
+                "Invalid cookie value: '{$cookie['value']}'",
+                HTTP_Request2_Exception::INVALID_ARGUMENT
+            );
+        }
+        $cookie += array('domain' => '', 'path' => '', 'expires' => null, 'secure' => false);
+
+        // Need ISO-8601 date @ UTC timezone
+        if (!empty($cookie['expires'])
+            && !preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+0000$/', $cookie['expires'])
+        ) {
+            try {
+                $dt = new DateTime($cookie['expires']);
+                $dt->setTimezone(new DateTimeZone('UTC'));
+                $cookie['expires'] = $dt->format(DateTime::ISO8601);
+            } catch (Exception $e) {
+                throw new HTTP_Request2_LogicException($e->getMessage());
+            }
+        }
+
+        if (empty($cookie['domain']) || empty($cookie['path'])) {
+            if (!$setter) {
+                throw new HTTP_Request2_LogicException(
+                    'Cookie misses domain and/or path component, cookie setter URL needed',
+                    HTTP_Request2_Exception::MISSING_VALUE
+                );
+            }
+            if (empty($cookie['domain'])) {
+                if ($host = $setter->getHost()) {
+                    $cookie['domain'] = $host;
+                } else {
+                    throw new HTTP_Request2_LogicException(
+                        'Setter URL does not contain host part, can\'t set cookie domain',
+                        HTTP_Request2_Exception::MISSING_VALUE
+                    );
+                }
+            }
+            if (empty($cookie['path'])) {
+                $path = $setter->getPath();
+                $cookie['path'] = empty($path)? '/': substr($path, 0, strrpos($path, '/') + 1);
+            }
+        }
+
+        if ($setter && !$this->domainMatch($setter->getHost(), $cookie['domain'])) {
+            throw new HTTP_Request2_MessageException(
+                "Domain " . $setter->getHost() . " cannot set cookies for "
+                . $cookie['domain']
+            );
+        }
+
+        return $cookie;
+    }
+
+   /**
+    * Stores a cookie in the jar
+    *
+    * @param    array    cookie data, as returned by {@link HTTP_Request2_Response::getCookies()}
+    * @param    Net_URL2 URL of the document that sent Set-Cookie header
+    * @throws   HTTP_Request2_Exception
+    */
+    public function store(array $cookie, Net_URL2 $setter = null)
+    {
+        $cookie = $this->checkAndUpdateFields($cookie, $setter);
+
+        if (strlen($cookie['value'])
+            && (is_null($cookie['expires']) || $cookie['expires'] > $this->now())
+        ) {
+            if (!isset($this->cookies[$cookie['domain']])) {
+                $this->cookies[$cookie['domain']] = array();
+            }
+            if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
+                $this->cookies[$cookie['domain']][$cookie['path']] = array();
+            }
+            $this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
+
+        } elseif (isset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']])) {
+            unset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']]);
+        }
+    }
+
+   /**
+    * Adds cookies set in HTTP response to the jar
+    *
+    * @param HTTP_Request2_Response response
+    * @param Net_URL2               original request URL, needed for setting
+    *                               default domain/path
+    */
+    public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)
+    {
+        foreach ($response->getCookies() as $cookie) {
+            $this->store($cookie, $setter);
+        }
+    }
+
+   /**
+    * Returns all cookies matching a given request URL
+    *
+    * The following checks are made:
+    *   - cookie domain should match request host
+    *   - cookie path should be a prefix for request path
+    *   - 'secure' cookies will only be sent for HTTPS requests
+    *
+    * @param  Net_URL2
+    * @param  bool      Whether to return cookies as string for "Cookie: " header
+    * @return array
+    */
+    public function getMatching(Net_URL2 $url, $asString = false)
+    {
+        $host   = $url->getHost();
+        $path   = $url->getPath();
+        $secure = 0 == strcasecmp($url->getScheme(), 'https');
+
+        $matched = $ret = array();
+        foreach (array_keys($this->cookies) as $domain) {
+            if ($this->domainMatch($host, $domain)) {
+                foreach (array_keys($this->cookies[$domain]) as $cPath) {
+                    if (0 === strpos($path, $cPath)) {
+                        foreach ($this->cookies[$domain][$cPath] as $name => $cookie) {
+                            if (!$cookie['secure'] || $secure) {
+                                $matched[$name][strlen($cookie['path'])] = $cookie;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        foreach ($matched as $cookies) {
+            krsort($cookies);
+            $ret = array_merge($ret, $cookies);
+        }
+        if (!$asString) {
+            return $ret;
+        } else {
+            $str = '';
+            foreach ($ret as $c) {
+                $str .= (empty($str)? '': '; ') . $c['name'] . '=' . $c['value'];
+            }
+            return $str;
+        }
+    }
+
+   /**
+    * Returns all cookies stored in a jar
+    *
+    * @return array
+    */
+    public function getAll()
+    {
+        $cookies = array();
+        foreach (array_keys($this->cookies) as $domain) {
+            foreach (array_keys($this->cookies[$domain]) as $path) {
+                foreach ($this->cookies[$domain][$path] as $name => $cookie) {
+                    $cookies[] = $cookie;
+                }
+            }
+        }
+        return $cookies;
+    }
+
+   /**
+    * Sets whether session cookies should be serialized when serializing the jar
+    *
+    * @param    boolean
+    */
+    public function serializeSessionCookies($serialize)
+    {
+        $this->serializeSession = (bool)$serialize;
+    }
+
+   /**
+    * Sets whether Public Suffix List should be used for restricting cookie-setting
+    *
+    * Without PSL {@link domainMatch()} will only prevent setting cookies for
+    * top-level domains like '.com' or '.org'. However, it will not prevent
+    * setting a cookie for '.co.uk' even though only third-level registrations
+    * are possible in .uk domain.
+    *
+    * With the List it is possible to find the highest level at which a domain
+    * may be registered for a particular top-level domain and consequently
+    * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by
+    * Firefox, Chrome and Opera browsers to restrict cookie setting.
+    *
+    * Note that PSL is licensed differently to HTTP_Request2 package (refer to
+    * the license information in public-suffix-list.php), so you can disable
+    * its use if this is an issue for you.
+    *
+    * @param    boolean
+    * @link     http://publicsuffix.org/learn/
+    */
+    public function usePublicSuffixList($useList)
+    {
+        $this->useList = (bool)$useList;
+    }
+
+   /**
+    * Returns string representation of object
+    *
+    * @return string
+    * @see    Serializable::serialize()
+    */
+    public function serialize()
+    {
+        $cookies = $this->getAll();
+        if (!$this->serializeSession) {
+            for ($i = count($cookies) - 1; $i >= 0; $i--) {
+                if (empty($cookies[$i]['expires'])) {
+                    unset($cookies[$i]);
+                }
+            }
+        }
+        return serialize(array(
+            'cookies'          => $cookies,
+            'serializeSession' => $this->serializeSession,
+            'useList'          => $this->useList
+        ));
+    }
+
+   /**
+    * Constructs the object from serialized string
+    *
+    * @param string  string representation
+    * @see   Serializable::unserialize()
+    */
+    public function unserialize($serialized)
+    {
+        $data = unserialize($serialized);
+        $now  = $this->now();
+        $this->serializeSessionCookies($data['serializeSession']);
+        $this->usePublicSuffixList($data['useList']);
+        foreach ($data['cookies'] as $cookie) {
+            if (!empty($cookie['expires']) && $cookie['expires'] <= $now) {
+                continue;
+            }
+            if (!isset($this->cookies[$cookie['domain']])) {
+                $this->cookies[$cookie['domain']] = array();
+            }
+            if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {
+                $this->cookies[$cookie['domain']][$cookie['path']] = array();
+            }
+            $this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;
+        }
+    }
+
+   /**
+    * Checks whether a cookie domain matches a request host.
+    *
+    * The method is used by {@link store()} to check for whether a document
+    * at given URL can set a cookie with a given domain attribute and by
+    * {@link getMatching()} to find cookies matching the request URL.
+    *
+    * @param    string  request host
+    * @param    string  cookie domain
+    * @return   bool    match success
+    */
+    public function domainMatch($requestHost, $cookieDomain)
+    {
+        if ($requestHost == $cookieDomain) {
+            return true;
+        }
+        // IP address, we require exact match
+        if (preg_match('/^(?:\d{1,3}\.){3}\d{1,3}$/', $requestHost)) {
+            return false;
+        }
+        if ('.' != $cookieDomain[0]) {
+            $cookieDomain = '.' . $cookieDomain;
+        }
+        // prevents setting cookies for '.com' and similar domains
+        if (!$this->useList && substr_count($cookieDomain, '.') < 2
+            || $this->useList && !self::getRegisteredDomain($cookieDomain)
+        ) {
+            return false;
+        }
+        return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain;
+    }
+
+   /**
+    * Removes subdomains to get the registered domain (the first after top-level)
+    *
+    * The method will check Public Suffix List to find out where top-level
+    * domain ends and registered domain starts. It will remove domain parts
+    * to the left of registered one.
+    *
+    * @param  string        domain name
+    * @return string|bool   registered domain, will return false if $domain is
+    *                       either invalid or a TLD itself
+    */
+    public static function getRegisteredDomain($domain)
+    {
+        $domainParts = explode('.', ltrim($domain, '.'));
+
+        // load the list if needed
+        if (empty(self::$psl)) {
+            $path = '/Library/WebServer/Documents/workspace/UCOMM_Webforms/lib/data' . DIRECTORY_SEPARATOR . 'HTTP_Request2';
+            if (0 === strpos($path, '@' . 'data_dir@')) {
+                $path = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'
+                                 . DIRECTORY_SEPARATOR . 'data');
+            }
+            self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php';
+        }
+
+        if (!($result = self::checkDomainsList($domainParts, self::$psl))) {
+            // known TLD, invalid domain name
+            return false;
+        }
+
+        // unknown TLD
+        if (!strpos($result, '.')) {
+            // fallback to checking that domain "has at least two dots"
+            if (2 > ($count = count($domainParts))) {
+                return false;
+            }
+            return $domainParts[$count - 2] . '.' . $domainParts[$count - 1];
+        }
+        return $result;
+    }
+
+   /**
+    * Recursive helper method for {@link getRegisteredDomain()}
+    *
+    * @param  array         remaining domain parts
+    * @param  mixed         node in {@link HTTP_Request2_CookieJar::$psl} to check
+    * @return string|null   concatenated domain parts, null in case of error
+    */
+    protected static function checkDomainsList(array $domainParts, $listNode)
+    {
+        $sub    = array_pop($domainParts);
+        $result = null;
+
+        if (!is_array($listNode) || is_null($sub)
+            || array_key_exists('!' . $sub, $listNode)
+         ) {
+            return $sub;
+
+        } elseif (array_key_exists($sub, $listNode)) {
+            $result = self::checkDomainsList($domainParts, $listNode[$sub]);
+
+        } elseif (array_key_exists('*', $listNode)) {
+            $result = self::checkDomainsList($domainParts, $listNode['*']);
+
+        } else {
+            return $sub;
+        }
+
+        return (strlen($result) > 0) ? ($result . '.' . $sub) : null;
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/HTTP/Request2/Exception.php b/lib/php/HTTP/Request2/Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..1bae2f1f33fabcfe74a07d7465343762822a1752
--- /dev/null
+++ b/lib/php/HTTP/Request2/Exception.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * Exception classes for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Exception.php 308629 2011-02-24 17:34:24Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Base class for exceptions in PEAR
+ */
+require_once 'PEAR/Exception.php';
+
+/**
+ * Base exception class for HTTP_Request2 package
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @version    Release: 2.0.0beta3
+ * @link       http://pear.php.net/pepr/pepr-proposal-show.php?id=132
+ */
+class HTTP_Request2_Exception extends PEAR_Exception
+{
+    /** An invalid argument was passed to a method */
+    const INVALID_ARGUMENT   = 1;
+    /** Some required value was not available */
+    const MISSING_VALUE      = 2;
+    /** Request cannot be processed due to errors in PHP configuration */
+    const MISCONFIGURATION   = 3;
+    /** Error reading the local file */
+    const READ_ERROR         = 4;
+
+    /** Server returned a response that does not conform to HTTP protocol */
+    const MALFORMED_RESPONSE = 10;
+    /** Failure decoding Content-Encoding or Transfer-Encoding of response */
+    const DECODE_ERROR       = 20;
+    /** Operation timed out */
+    const TIMEOUT            = 30;
+    /** Number of redirects exceeded 'max_redirects' configuration parameter */
+    const TOO_MANY_REDIRECTS = 40;
+    /** Redirect to a protocol other than http(s):// */
+    const NON_HTTP_REDIRECT  = 50;
+
+   /**
+    * Native error code
+    * @var int
+    */
+    private $_nativeCode;
+
+   /**
+    * Constructor, can set package error code and native error code
+    *
+    * @param string exception message
+    * @param int    package error code, one of class constants
+    * @param int    error code from underlying PHP extension
+    */
+    public function __construct($message = null, $code = null, $nativeCode = null)
+    {
+        parent::__construct($message, $code);
+        $this->_nativeCode = $nativeCode;
+    }
+
+   /**
+    * Returns error code produced by underlying PHP extension
+    *
+    * For Socket Adapter this may contain error number returned by
+    * stream_socket_client(), for Curl Adapter this will contain error number
+    * returned by curl_errno()
+    *
+    * @return integer
+    */
+    public function getNativeCode()
+    {
+        return $this->_nativeCode;
+    }
+}
+
+/**
+ * Exception thrown in case of missing features
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @version    Release: 2.0.0beta3
+ */
+class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception {}
+
+/**
+ * Exception that represents error in the program logic
+ *
+ * This exception usually implies a programmer's error, like passing invalid
+ * data to methods or trying to use PHP extensions that weren't installed or
+ * enabled. Usually exceptions of this kind will be thrown before request even
+ * starts.
+ *
+ * The exception will usually contain a package error code.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @version    Release: 2.0.0beta3
+ */
+class HTTP_Request2_LogicException extends HTTP_Request2_Exception {}
+
+/**
+ * Exception thrown when connection to a web or proxy server fails
+ *
+ * The exception will not contain a package error code, but will contain
+ * native error code, as returned by stream_socket_client() or curl_errno().
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @version    Release: 2.0.0beta3
+ */
+class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception {}
+
+/**
+ * Exception thrown when sending or receiving HTTP message fails
+ *
+ * The exception may contain both package error code and native error code.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @version    Release: 2.0.0beta3
+ */
+class HTTP_Request2_MessageException extends HTTP_Request2_Exception {}
+?>
\ No newline at end of file
diff --git a/lib/php/HTTP/Request2/MultipartBody.php b/lib/php/HTTP/Request2/MultipartBody.php
new file mode 100644
index 0000000000000000000000000000000000000000..57bc5d6b59bf03affdf72183ee92aa1af3c33d71
--- /dev/null
+++ b/lib/php/HTTP/Request2/MultipartBody.php
@@ -0,0 +1,274 @@
+<?php
+/**
+ * Helper class for building multipart/form-data request body
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: MultipartBody.php 308322 2011-02-14 13:58:03Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Class for building multipart/form-data request body
+ *
+ * The class helps to reduce memory consumption by streaming large file uploads
+ * from disk, it also allows monitoring of upload progress (see request #7630)
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @version    Release: 2.0.0beta3
+ * @link       http://tools.ietf.org/html/rfc1867
+ */
+class HTTP_Request2_MultipartBody
+{
+   /**
+    * MIME boundary
+    * @var  string
+    */
+    private $_boundary;
+
+   /**
+    * Form parameters added via {@link HTTP_Request2::addPostParameter()}
+    * @var  array
+    */
+    private $_params = array();
+
+   /**
+    * File uploads added via {@link HTTP_Request2::addUpload()}
+    * @var  array
+    */
+    private $_uploads = array();
+
+   /**
+    * Header for parts with parameters
+    * @var  string
+    */
+    private $_headerParam = "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n";
+
+   /**
+    * Header for parts with uploads
+    * @var  string
+    */
+    private $_headerUpload = "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";
+
+   /**
+    * Current position in parameter and upload arrays
+    *
+    * First number is index of "current" part, second number is position within
+    * "current" part
+    *
+    * @var  array
+    */
+    private $_pos = array(0, 0);
+
+
+   /**
+    * Constructor. Sets the arrays with POST data.
+    *
+    * @param    array   values of form fields set via {@link HTTP_Request2::addPostParameter()}
+    * @param    array   file uploads set via {@link HTTP_Request2::addUpload()}
+    * @param    bool    whether to append brackets to array variable names
+    */
+    public function __construct(array $params, array $uploads, $useBrackets = true)
+    {
+        $this->_params = self::_flattenArray('', $params, $useBrackets);
+        foreach ($uploads as $fieldName => $f) {
+            if (!is_array($f['fp'])) {
+                $this->_uploads[] = $f + array('name' => $fieldName);
+            } else {
+                for ($i = 0; $i < count($f['fp']); $i++) {
+                    $upload = array(
+                        'name' => ($useBrackets? $fieldName . '[' . $i . ']': $fieldName)
+                    );
+                    foreach (array('fp', 'filename', 'size', 'type') as $key) {
+                        $upload[$key] = $f[$key][$i];
+                    }
+                    $this->_uploads[] = $upload;
+                }
+            }
+        }
+    }
+
+   /**
+    * Returns the length of the body to use in Content-Length header
+    *
+    * @return   integer
+    */
+    public function getLength()
+    {
+        $boundaryLength     = strlen($this->getBoundary());
+        $headerParamLength  = strlen($this->_headerParam) - 4 + $boundaryLength;
+        $headerUploadLength = strlen($this->_headerUpload) - 8 + $boundaryLength;
+        $length             = $boundaryLength + 6;
+        foreach ($this->_params as $p) {
+            $length += $headerParamLength + strlen($p[0]) + strlen($p[1]) + 2;
+        }
+        foreach ($this->_uploads as $u) {
+            $length += $headerUploadLength + strlen($u['name']) + strlen($u['type']) +
+                       strlen($u['filename']) + $u['size'] + 2;
+        }
+        return $length;
+    }
+
+   /**
+    * Returns the boundary to use in Content-Type header
+    *
+    * @return   string
+    */
+    public function getBoundary()
+    {
+        if (empty($this->_boundary)) {
+            $this->_boundary = '--' . md5('PEAR-HTTP_Request2-' . microtime());
+        }
+        return $this->_boundary;
+    }
+
+   /**
+    * Returns next chunk of request body
+    *
+    * @param    integer Amount of bytes to read
+    * @return   string  Up to $length bytes of data, empty string if at end
+    */
+    public function read($length)
+    {
+        $ret         = '';
+        $boundary    = $this->getBoundary();
+        $paramCount  = count($this->_params);
+        $uploadCount = count($this->_uploads);
+        while ($length > 0 && $this->_pos[0] <= $paramCount + $uploadCount) {
+            $oldLength = $length;
+            if ($this->_pos[0] < $paramCount) {
+                $param = sprintf($this->_headerParam, $boundary,
+                                 $this->_params[$this->_pos[0]][0]) .
+                         $this->_params[$this->_pos[0]][1] . "\r\n";
+                $ret    .= substr($param, $this->_pos[1], $length);
+                $length -= min(strlen($param) - $this->_pos[1], $length);
+
+            } elseif ($this->_pos[0] < $paramCount + $uploadCount) {
+                $pos    = $this->_pos[0] - $paramCount;
+                $header = sprintf($this->_headerUpload, $boundary,
+                                  $this->_uploads[$pos]['name'],
+                                  $this->_uploads[$pos]['filename'],
+                                  $this->_uploads[$pos]['type']);
+                if ($this->_pos[1] < strlen($header)) {
+                    $ret    .= substr($header, $this->_pos[1], $length);
+                    $length -= min(strlen($header) - $this->_pos[1], $length);
+                }
+                $filePos  = max(0, $this->_pos[1] - strlen($header));
+                if ($length > 0 && $filePos < $this->_uploads[$pos]['size']) {
+                    $ret     .= fread($this->_uploads[$pos]['fp'], $length);
+                    $length  -= min($length, $this->_uploads[$pos]['size'] - $filePos);
+                }
+                if ($length > 0) {
+                    $start   = $this->_pos[1] + ($oldLength - $length) -
+                               strlen($header) - $this->_uploads[$pos]['size'];
+                    $ret    .= substr("\r\n", $start, $length);
+                    $length -= min(2 - $start, $length);
+                }
+
+            } else {
+                $closing  = '--' . $boundary . "--\r\n";
+                $ret     .= substr($closing, $this->_pos[1], $length);
+                $length  -= min(strlen($closing) - $this->_pos[1], $length);
+            }
+            if ($length > 0) {
+                $this->_pos     = array($this->_pos[0] + 1, 0);
+            } else {
+                $this->_pos[1] += $oldLength;
+            }
+        }
+        return $ret;
+    }
+
+   /**
+    * Sets the current position to the start of the body
+    *
+    * This allows reusing the same body in another request
+    */
+    public function rewind()
+    {
+        $this->_pos = array(0, 0);
+        foreach ($this->_uploads as $u) {
+            rewind($u['fp']);
+        }
+    }
+
+   /**
+    * Returns the body as string
+    *
+    * Note that it reads all file uploads into memory so it is a good idea not
+    * to use this method with large file uploads and rely on read() instead.
+    *
+    * @return   string
+    */
+    public function __toString()
+    {
+        $this->rewind();
+        return $this->read($this->getLength());
+    }
+
+
+   /**
+    * Helper function to change the (probably multidimensional) associative array
+    * into the simple one.
+    *
+    * @param    string  name for item
+    * @param    mixed   item's values
+    * @param    bool    whether to append [] to array variables' names
+    * @return   array   array with the following items: array('item name', 'item value');
+    */
+    private static function _flattenArray($name, $values, $useBrackets)
+    {
+        if (!is_array($values)) {
+            return array(array($name, $values));
+        } else {
+            $ret = array();
+            foreach ($values as $k => $v) {
+                if (empty($name)) {
+                    $newName = $k;
+                } elseif ($useBrackets) {
+                    $newName = $name . '[' . $k . ']';
+                } else {
+                    $newName = $name;
+                }
+                $ret = array_merge($ret, self::_flattenArray($newName, $v, $useBrackets));
+            }
+            return $ret;
+        }
+    }
+}
+?>
diff --git a/lib/php/HTTP/Request2/Observer/Log.php b/lib/php/HTTP/Request2/Observer/Log.php
new file mode 100644
index 0000000000000000000000000000000000000000..237563d569e93a02942a97a29a68b3c5de4f8bdc
--- /dev/null
+++ b/lib/php/HTTP/Request2/Observer/Log.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * An observer useful for debugging / testing.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category HTTP
+ * @package  HTTP_Request2
+ * @author   David Jean Louis <izi@php.net>
+ * @author   Alexey Borzov <avb@php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  SVN: $Id: Log.php 308680 2011-02-25 17:40:17Z avb $
+ * @link     http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Exception class for HTTP_Request2 package
+ */
+require_once 'HTTP/Request2/Exception.php';
+
+/**
+ * A debug observer useful for debugging / testing.
+ *
+ * This observer logs to a log target data corresponding to the various request
+ * and response events, it logs by default to php://output but can be configured
+ * to log to a file or via the PEAR Log package.
+ *
+ * A simple example:
+ * <code>
+ * require_once 'HTTP/Request2.php';
+ * require_once 'HTTP/Request2/Observer/Log.php';
+ *
+ * $request  = new HTTP_Request2('http://www.example.com');
+ * $observer = new HTTP_Request2_Observer_Log();
+ * $request->attach($observer);
+ * $request->send();
+ * </code>
+ *
+ * A more complex example with PEAR Log:
+ * <code>
+ * require_once 'HTTP/Request2.php';
+ * require_once 'HTTP/Request2/Observer/Log.php';
+ * require_once 'Log.php';
+ *
+ * $request  = new HTTP_Request2('http://www.example.com');
+ * // we want to log with PEAR log
+ * $observer = new HTTP_Request2_Observer_Log(Log::factory('console'));
+ *
+ * // we only want to log received headers
+ * $observer->events = array('receivedHeaders');
+ *
+ * $request->attach($observer);
+ * $request->send();
+ * </code>
+ *
+ * @category HTTP
+ * @package  HTTP_Request2
+ * @author   David Jean Louis <izi@php.net>
+ * @author   Alexey Borzov <avb@php.net>
+ * @license  http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version  Release: 2.0.0beta3
+ * @link     http://pear.php.net/package/HTTP_Request2
+ */
+class HTTP_Request2_Observer_Log implements SplObserver
+{
+    // properties {{{
+
+    /**
+     * The log target, it can be a a resource or a PEAR Log instance.
+     *
+     * @var resource|Log $target
+     */
+    protected $target = null;
+
+    /**
+     * The events to log.
+     *
+     * @var array $events
+     */
+    public $events = array(
+        'connect',
+        'sentHeaders',
+        'sentBody',
+        'receivedHeaders',
+        'receivedBody',
+        'disconnect',
+    );
+
+    // }}}
+    // __construct() {{{
+
+    /**
+     * Constructor.
+     *
+     * @param mixed $target Can be a file path (default: php://output), a resource,
+     *                      or an instance of the PEAR Log class.
+     * @param array $events Array of events to listen to (default: all events)
+     *
+     * @return void
+     */
+    public function __construct($target = 'php://output', array $events = array())
+    {
+        if (!empty($events)) {
+            $this->events = $events;
+        }
+        if (is_resource($target) || $target instanceof Log) {
+            $this->target = $target;
+        } elseif (false === ($this->target = @fopen($target, 'ab'))) {
+            throw new HTTP_Request2_Exception("Unable to open '{$target}'");
+        }
+    }
+
+    // }}}
+    // update() {{{
+
+    /**
+     * Called when the request notifies us of an event.
+     *
+     * @param HTTP_Request2 $subject The HTTP_Request2 instance
+     *
+     * @return void
+     */
+    public function update(SplSubject $subject)
+    {
+        $event = $subject->getLastEvent();
+        if (!in_array($event['name'], $this->events)) {
+            return;
+        }
+
+        switch ($event['name']) {
+        case 'connect':
+            $this->log('* Connected to ' . $event['data']);
+            break;
+        case 'sentHeaders':
+            $headers = explode("\r\n", $event['data']);
+            array_pop($headers);
+            foreach ($headers as $header) {
+                $this->log('> ' . $header);
+            }
+            break;
+        case 'sentBody':
+            $this->log('> ' . $event['data'] . ' byte(s) sent');
+            break;
+        case 'receivedHeaders':
+            $this->log(sprintf('< HTTP/%s %s %s',
+                $event['data']->getVersion(),
+                $event['data']->getStatus(),
+                $event['data']->getReasonPhrase()));
+            $headers = $event['data']->getHeader();
+            foreach ($headers as $key => $val) {
+                $this->log('< ' . $key . ': ' . $val);
+            }
+            $this->log('< ');
+            break;
+        case 'receivedBody':
+            $this->log($event['data']->getBody());
+            break;
+        case 'disconnect':
+            $this->log('* Disconnected');
+            break;
+        }
+    }
+
+    // }}}
+    // log() {{{
+
+    /**
+     * Logs the given message to the configured target.
+     *
+     * @param string $message Message to display
+     *
+     * @return void
+     */
+    protected function log($message)
+    {
+        if ($this->target instanceof Log) {
+            $this->target->debug($message);
+        } elseif (is_resource($this->target)) {
+            fwrite($this->target, $message . "\r\n");
+        }
+    }
+
+    // }}}
+}
+
+?>
\ No newline at end of file
diff --git a/lib/php/HTTP/Request2/Response.php b/lib/php/HTTP/Request2/Response.php
new file mode 100644
index 0000000000000000000000000000000000000000..35a5ad87c3ddd6e30a87cc80cf97c81ef512fbf4
--- /dev/null
+++ b/lib/php/HTTP/Request2/Response.php
@@ -0,0 +1,629 @@
+<?php
+/**
+ * Class representing a HTTP response
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Response.php 309921 2011-04-03 16:43:02Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Exception class for HTTP_Request2 package
+ */
+require_once 'HTTP/Request2/Exception.php';
+
+/**
+ * Class representing a HTTP response
+ *
+ * The class is designed to be used in "streaming" scenario, building the
+ * response as it is being received:
+ * <code>
+ * $statusLine = read_status_line();
+ * $response = new HTTP_Request2_Response($statusLine);
+ * do {
+ *     $headerLine = read_header_line();
+ *     $response->parseHeaderLine($headerLine);
+ * } while ($headerLine != '');
+ *
+ * while ($chunk = read_body()) {
+ *     $response->appendBody($chunk);
+ * }
+ *
+ * var_dump($response->getHeader(), $response->getCookies(), $response->getBody());
+ * </code>
+ *
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @version    Release: 2.0.0beta3
+ * @link       http://tools.ietf.org/html/rfc2616#section-6
+ */
+class HTTP_Request2_Response
+{
+   /**
+    * HTTP protocol version (e.g. 1.0, 1.1)
+    * @var  string
+    */
+    protected $version;
+
+   /**
+    * Status code
+    * @var  integer
+    * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
+    */
+    protected $code;
+
+   /**
+    * Reason phrase
+    * @var  string
+    * @link http://tools.ietf.org/html/rfc2616#section-6.1.1
+    */
+    protected $reasonPhrase;
+
+   /**
+    * Effective URL (may be different from original request URL in case of redirects)
+    * @var  string
+    */
+    protected $effectiveUrl;
+
+   /**
+    * Associative array of response headers
+    * @var  array
+    */
+    protected $headers = array();
+
+   /**
+    * Cookies set in the response
+    * @var  array
+    */
+    protected $cookies = array();
+
+   /**
+    * Name of last header processed by parseHederLine()
+    *
+    * Used to handle the headers that span multiple lines
+    *
+    * @var  string
+    */
+    protected $lastHeader = null;
+
+   /**
+    * Response body
+    * @var  string
+    */
+    protected $body = '';
+
+   /**
+    * Whether the body is still encoded by Content-Encoding
+    *
+    * cURL provides the decoded body to the callback; if we are reading from
+    * socket the body is still gzipped / deflated
+    *
+    * @var  bool
+    */
+    protected $bodyEncoded;
+
+   /**
+    * Associative array of HTTP status code / reason phrase.
+    *
+    * @var  array
+    * @link http://tools.ietf.org/html/rfc2616#section-10
+    */
+    protected static $phrases = array(
+
+        // 1xx: Informational - Request received, continuing process
+        100 => 'Continue',
+        101 => 'Switching Protocols',
+
+        // 2xx: Success - The action was successfully received, understood and
+        // accepted
+        200 => 'OK',
+        201 => 'Created',
+        202 => 'Accepted',
+        203 => 'Non-Authoritative Information',
+        204 => 'No Content',
+        205 => 'Reset Content',
+        206 => 'Partial Content',
+
+        // 3xx: Redirection - Further action must be taken in order to complete
+        // the request
+        300 => 'Multiple Choices',
+        301 => 'Moved Permanently',
+        302 => 'Found',  // 1.1
+        303 => 'See Other',
+        304 => 'Not Modified',
+        305 => 'Use Proxy',
+        307 => 'Temporary Redirect',
+
+        // 4xx: Client Error - The request contains bad syntax or cannot be
+        // fulfilled
+        400 => 'Bad Request',
+        401 => 'Unauthorized',
+        402 => 'Payment Required',
+        403 => 'Forbidden',
+        404 => 'Not Found',
+        405 => 'Method Not Allowed',
+        406 => 'Not Acceptable',
+        407 => 'Proxy Authentication Required',
+        408 => 'Request Timeout',
+        409 => 'Conflict',
+        410 => 'Gone',
+        411 => 'Length Required',
+        412 => 'Precondition Failed',
+        413 => 'Request Entity Too Large',
+        414 => 'Request-URI Too Long',
+        415 => 'Unsupported Media Type',
+        416 => 'Requested Range Not Satisfiable',
+        417 => 'Expectation Failed',
+
+        // 5xx: Server Error - The server failed to fulfill an apparently
+        // valid request
+        500 => 'Internal Server Error',
+        501 => 'Not Implemented',
+        502 => 'Bad Gateway',
+        503 => 'Service Unavailable',
+        504 => 'Gateway Timeout',
+        505 => 'HTTP Version Not Supported',
+        509 => 'Bandwidth Limit Exceeded',
+
+    );
+
+   /**
+    * Constructor, parses the response status line
+    *
+    * @param    string Response status line (e.g. "HTTP/1.1 200 OK")
+    * @param    bool   Whether body is still encoded by Content-Encoding
+    * @param    string Effective URL of the response
+    * @throws   HTTP_Request2_MessageException if status line is invalid according to spec
+    */
+    public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)
+    {
+        if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {
+            throw new HTTP_Request2_MessageException(
+                "Malformed response: {$statusLine}",
+                HTTP_Request2_Exception::MALFORMED_RESPONSE
+            );
+        }
+        $this->version = $m[1];
+        $this->code    = intval($m[2]);
+        if (!empty($m[3])) {
+            $this->reasonPhrase = trim($m[3]);
+        } elseif (!empty(self::$phrases[$this->code])) {
+            $this->reasonPhrase = self::$phrases[$this->code];
+        }
+        $this->bodyEncoded  = (bool)$bodyEncoded;
+        $this->effectiveUrl = (string)$effectiveUrl;
+    }
+
+   /**
+    * Parses the line from HTTP response filling $headers array
+    *
+    * The method should be called after reading the line from socket or receiving
+    * it into cURL callback. Passing an empty string here indicates the end of
+    * response headers and triggers additional processing, so be sure to pass an
+    * empty string in the end.
+    *
+    * @param    string  Line from HTTP response
+    */
+    public function parseHeaderLine($headerLine)
+    {
+        $headerLine = trim($headerLine, "\r\n");
+
+        // empty string signals the end of headers, process the received ones
+        if ('' == $headerLine) {
+            if (!empty($this->headers['set-cookie'])) {
+                $cookies = is_array($this->headers['set-cookie'])?
+                           $this->headers['set-cookie']:
+                           array($this->headers['set-cookie']);
+                foreach ($cookies as $cookieString) {
+                    $this->parseCookie($cookieString);
+                }
+                unset($this->headers['set-cookie']);
+            }
+            foreach (array_keys($this->headers) as $k) {
+                if (is_array($this->headers[$k])) {
+                    $this->headers[$k] = implode(', ', $this->headers[$k]);
+                }
+            }
+
+        // string of the form header-name: header value
+        } elseif (preg_match('!^([^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+):(.+)$!', $headerLine, $m)) {
+            $name  = strtolower($m[1]);
+            $value = trim($m[2]);
+            if (empty($this->headers[$name])) {
+                $this->headers[$name] = $value;
+            } else {
+                if (!is_array($this->headers[$name])) {
+                    $this->headers[$name] = array($this->headers[$name]);
+                }
+                $this->headers[$name][] = $value;
+            }
+            $this->lastHeader = $name;
+
+        // continuation of a previous header
+        } elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {
+            if (!is_array($this->headers[$this->lastHeader])) {
+                $this->headers[$this->lastHeader] .= ' ' . trim($m[1]);
+            } else {
+                $key = count($this->headers[$this->lastHeader]) - 1;
+                $this->headers[$this->lastHeader][$key] .= ' ' . trim($m[1]);
+            }
+        }
+    }
+
+   /**
+    * Parses a Set-Cookie header to fill $cookies array
+    *
+    * @param    string    value of Set-Cookie header
+    * @link     http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html
+    */
+    protected function parseCookie($cookieString)
+    {
+        $cookie = array(
+            'expires' => null,
+            'domain'  => null,
+            'path'    => null,
+            'secure'  => false
+        );
+
+        // Only a name=value pair
+        if (!strpos($cookieString, ';')) {
+            $pos = strpos($cookieString, '=');
+            $cookie['name']  = trim(substr($cookieString, 0, $pos));
+            $cookie['value'] = trim(substr($cookieString, $pos + 1));
+
+        // Some optional parameters are supplied
+        } else {
+            $elements = explode(';', $cookieString);
+            $pos = strpos($elements[0], '=');
+            $cookie['name']  = trim(substr($elements[0], 0, $pos));
+            $cookie['value'] = trim(substr($elements[0], $pos + 1));
+
+            for ($i = 1; $i < count($elements); $i++) {
+                if (false === strpos($elements[$i], '=')) {
+                    $elName  = trim($elements[$i]);
+                    $elValue = null;
+                } else {
+                    list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
+                }
+                $elName = strtolower($elName);
+                if ('secure' == $elName) {
+                    $cookie['secure'] = true;
+                } elseif ('expires' == $elName) {
+                    $cookie['expires'] = str_replace('"', '', $elValue);
+                } elseif ('path' == $elName || 'domain' == $elName) {
+                    $cookie[$elName] = urldecode($elValue);
+                } else {
+                    $cookie[$elName] = $elValue;
+                }
+            }
+        }
+        $this->cookies[] = $cookie;
+    }
+
+   /**
+    * Appends a string to the response body
+    * @param    string
+    */
+    public function appendBody($bodyChunk)
+    {
+        $this->body .= $bodyChunk;
+    }
+
+   /**
+    * Returns the effective URL of the response
+    *
+    * This may be different from the request URL if redirects were followed.
+    *
+    * @return string
+    * @link   http://pear.php.net/bugs/bug.php?id=18412
+    */
+    public function getEffectiveUrl()
+    {
+        return $this->effectiveUrl;
+    }
+
+   /**
+    * Returns the status code
+    * @return   integer
+    */
+    public function getStatus()
+    {
+        return $this->code;
+    }
+
+   /**
+    * Returns the reason phrase
+    * @return   string
+    */
+    public function getReasonPhrase()
+    {
+        return $this->reasonPhrase;
+    }
+
+   /**
+    * Whether response is a redirect that can be automatically handled by HTTP_Request2
+    * @return   bool
+    */
+    public function isRedirect()
+    {
+        return in_array($this->code, array(300, 301, 302, 303, 307))
+               && isset($this->headers['location']);
+    }
+
+   /**
+    * Returns either the named header or all response headers
+    *
+    * @param    string          Name of header to return
+    * @return   string|array    Value of $headerName header (null if header is
+    *                           not present), array of all response headers if
+    *                           $headerName is null
+    */
+    public function getHeader($headerName = null)
+    {
+        if (null === $headerName) {
+            return $this->headers;
+        } else {
+            $headerName = strtolower($headerName);
+            return isset($this->headers[$headerName])? $this->headers[$headerName]: null;
+        }
+    }
+
+   /**
+    * Returns cookies set in response
+    *
+    * @return   array
+    */
+    public function getCookies()
+    {
+        return $this->cookies;
+    }
+
+   /**
+    * Returns the body of the response
+    *
+    * @return   string
+    * @throws   HTTP_Request2_Exception if body cannot be decoded
+    */
+    public function getBody()
+    {
+        if (0 == strlen($this->body) || !$this->bodyEncoded ||
+            !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))
+        ) {
+            return $this->body;
+
+        } else {
+            if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
+                $oldEncoding = mb_internal_encoding();
+                mb_internal_encoding('iso-8859-1');
+            }
+
+            try {
+                switch (strtolower($this->getHeader('content-encoding'))) {
+                    case 'gzip':
+                        $decoded = self::decodeGzip($this->body);
+                        break;
+                    case 'deflate':
+                        $decoded = self::decodeDeflate($this->body);
+                }
+            } catch (Exception $e) {
+            }
+
+            if (!empty($oldEncoding)) {
+                mb_internal_encoding($oldEncoding);
+            }
+            if (!empty($e)) {
+                throw $e;
+            }
+            return $decoded;
+        }
+    }
+
+   /**
+    * Get the HTTP version of the response
+    *
+    * @return   string
+    */
+    public function getVersion()
+    {
+        return $this->version;
+    }
+
+   /**
+    * Decodes the message-body encoded by gzip
+    *
+    * The real decoding work is done by gzinflate() built-in function, this
+    * method only parses the header and checks data for compliance with
+    * RFC 1952
+    *
+    * @param    string  gzip-encoded data
+    * @return   string  decoded data
+    * @throws   HTTP_Request2_LogicException
+    * @throws   HTTP_Request2_MessageException
+    * @link     http://tools.ietf.org/html/rfc1952
+    */
+    public static function decodeGzip($data)
+    {
+        $length = strlen($data);
+        // If it doesn't look like gzip-encoded data, don't bother
+        if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
+            return $data;
+        }
+        if (!function_exists('gzinflate')) {
+            throw new HTTP_Request2_LogicException(
+                'Unable to decode body: gzip extension not available',
+                HTTP_Request2_Exception::MISCONFIGURATION
+            );
+        }
+        $method = ord(substr($data, 2, 1));
+        if (8 != $method) {
+            throw new HTTP_Request2_MessageException(
+                'Error parsing gzip header: unknown compression method',
+                HTTP_Request2_Exception::DECODE_ERROR
+            );
+        }
+        $flags = ord(substr($data, 3, 1));
+        if ($flags & 224) {
+            throw new HTTP_Request2_MessageException(
+                'Error parsing gzip header: reserved bits are set',
+                HTTP_Request2_Exception::DECODE_ERROR
+            );
+        }
+
+        // header is 10 bytes minimum. may be longer, though.
+        $headerLength = 10;
+        // extra fields, need to skip 'em
+        if ($flags & 4) {
+            if ($length - $headerLength - 2 < 8) {
+                throw new HTTP_Request2_MessageException(
+                    'Error parsing gzip header: data too short',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $extraLength = unpack('v', substr($data, 10, 2));
+            if ($length - $headerLength - 2 - $extraLength[1] < 8) {
+                throw new HTTP_Request2_MessageException(
+                    'Error parsing gzip header: data too short',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $headerLength += $extraLength[1] + 2;
+        }
+        // file name, need to skip that
+        if ($flags & 8) {
+            if ($length - $headerLength - 1 < 8) {
+                throw new HTTP_Request2_MessageException(
+                    'Error parsing gzip header: data too short',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $filenameLength = strpos(substr($data, $headerLength), chr(0));
+            if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
+                throw new HTTP_Request2_MessageException(
+                    'Error parsing gzip header: data too short',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $headerLength += $filenameLength + 1;
+        }
+        // comment, need to skip that also
+        if ($flags & 16) {
+            if ($length - $headerLength - 1 < 8) {
+                throw new HTTP_Request2_MessageException(
+                    'Error parsing gzip header: data too short',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $commentLength = strpos(substr($data, $headerLength), chr(0));
+            if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
+                throw new HTTP_Request2_MessageException(
+                    'Error parsing gzip header: data too short',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $headerLength += $commentLength + 1;
+        }
+        // have a CRC for header. let's check
+        if ($flags & 2) {
+            if ($length - $headerLength - 2 < 8) {
+                throw new HTTP_Request2_MessageException(
+                    'Error parsing gzip header: data too short',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $crcReal   = 0xffff & crc32(substr($data, 0, $headerLength));
+            $crcStored = unpack('v', substr($data, $headerLength, 2));
+            if ($crcReal != $crcStored[1]) {
+                throw new HTTP_Request2_MessageException(
+                    'Header CRC check failed',
+                    HTTP_Request2_Exception::DECODE_ERROR
+                );
+            }
+            $headerLength += 2;
+        }
+        // unpacked data CRC and size at the end of encoded data
+        $tmp = unpack('V2', substr($data, -8));
+        $dataCrc  = $tmp[1];
+        $dataSize = $tmp[2];
+
+        // finally, call the gzinflate() function
+        // don't pass $dataSize to gzinflate, see bugs #13135, #14370
+        $unpacked = gzinflate(substr($data, $headerLength, -8));
+        if (false === $unpacked) {
+            throw new HTTP_Request2_MessageException(
+                'gzinflate() call failed',
+                HTTP_Request2_Exception::DECODE_ERROR
+            );
+        } elseif ($dataSize != strlen($unpacked)) {
+            throw new HTTP_Request2_MessageException(
+                'Data size check failed',
+                HTTP_Request2_Exception::DECODE_ERROR
+            );
+        } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
+            throw new HTTP_Request2_Exception(
+                'Data CRC check failed',
+                HTTP_Request2_Exception::DECODE_ERROR
+            );
+        }
+        return $unpacked;
+    }
+
+   /**
+    * Decodes the message-body encoded by deflate
+    *
+    * @param    string  deflate-encoded data
+    * @return   string  decoded data
+    * @throws   HTTP_Request2_LogicException
+    */
+    public static function decodeDeflate($data)
+    {
+        if (!function_exists('gzuncompress')) {
+            throw new HTTP_Request2_LogicException(
+                'Unable to decode body: gzip extension not available',
+                HTTP_Request2_Exception::MISCONFIGURATION
+            );
+        }
+        // RFC 2616 defines 'deflate' encoding as zlib format from RFC 1950,
+        // while many applications send raw deflate stream from RFC 1951.
+        // We should check for presence of zlib header and use gzuncompress() or
+        // gzinflate() as needed. See bug #15305
+        $header = unpack('n', substr($data, 0, 2));
+        return (0 == $header[1] % 31)? gzuncompress($data): gzinflate($data);
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/Net/URL2.php b/lib/php/Net/URL2.php
new file mode 100644
index 0000000000000000000000000000000000000000..bbc9f124d3e3797bfde922d8627f8a252897b17e
--- /dev/null
+++ b/lib/php/Net/URL2.php
@@ -0,0 +1,894 @@
+<?php
+/**
+ * Net_URL2, a class representing a URL as per RFC 3986.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2007-2009, Peytz & Co. A/S
+ * 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 Net_URL2 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 OWNER OR
+ * 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.
+ *
+ * @category  Networking
+ * @package   Net_URL2
+ * @author    Christian Schmidt <schmidt@php.net>
+ * @copyright 2007-2009 Peytz & Co. A/S
+ * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version   CVS: $Id: URL2.php 290036 2009-10-28 19:52:49Z schmidt $
+ * @link      http://www.rfc-editor.org/rfc/rfc3986.txt
+ */
+
+/**
+ * Represents a URL as per RFC 3986.
+ *
+ * @category  Networking
+ * @package   Net_URL2
+ * @author    Christian Schmidt <schmidt@php.net>
+ * @copyright 2007-2009 Peytz & Co. A/S
+ * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version   Release: @package_version@
+ * @link      http://pear.php.net/package/Net_URL2
+ */
+class Net_URL2
+{
+    /**
+     * Do strict parsing in resolve() (see RFC 3986, section 5.2.2). Default
+     * is true.
+     */
+    const OPTION_STRICT = 'strict';
+
+    /**
+     * Represent arrays in query using PHP's [] notation. Default is true.
+     */
+    const OPTION_USE_BRACKETS = 'use_brackets';
+
+    /**
+     * URL-encode query variable keys. Default is true.
+     */
+    const OPTION_ENCODE_KEYS = 'encode_keys';
+
+    /**
+     * Query variable separators when parsing the query string. Every character
+     * is considered a separator. Default is "&".
+     */
+    const OPTION_SEPARATOR_INPUT = 'input_separator';
+
+    /**
+     * Query variable separator used when generating the query string. Default
+     * is "&".
+     */
+    const OPTION_SEPARATOR_OUTPUT = 'output_separator';
+
+    /**
+     * Default options corresponds to how PHP handles $_GET.
+     */
+    private $_options = array(
+        self::OPTION_STRICT           => true,
+        self::OPTION_USE_BRACKETS     => true,
+        self::OPTION_ENCODE_KEYS      => true,
+        self::OPTION_SEPARATOR_INPUT  => '&',
+        self::OPTION_SEPARATOR_OUTPUT => '&',
+        );
+
+    /**
+     * @var  string|bool
+     */
+    private $_scheme = false;
+
+    /**
+     * @var  string|bool
+     */
+    private $_userinfo = false;
+
+    /**
+     * @var  string|bool
+     */
+    private $_host = false;
+
+    /**
+     * @var  string|bool
+     */
+    private $_port = false;
+
+    /**
+     * @var  string
+     */
+    private $_path = '';
+
+    /**
+     * @var  string|bool
+     */
+    private $_query = false;
+
+    /**
+     * @var  string|bool
+     */
+    private $_fragment = false;
+
+    /**
+     * Constructor.
+     *
+     * @param string $url     an absolute or relative URL
+     * @param array  $options an array of OPTION_xxx constants
+     */
+    public function __construct($url, array $options = array())
+    {
+        foreach ($options as $optionName => $value) {
+            if (array_key_exists($optionName, $this->_options)) {
+                $this->_options[$optionName] = $value;
+            }
+        }
+
+        // The regular expression is copied verbatim from RFC 3986, appendix B.
+        // The expression does not validate the URL but matches any string.
+        preg_match('!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!',
+                   $url,
+                   $matches);
+
+        // "path" is always present (possibly as an empty string); the rest
+        // are optional.
+        $this->_scheme = !empty($matches[1]) ? $matches[2] : false;
+        $this->setAuthority(!empty($matches[3]) ? $matches[4] : false);
+        $this->_path = $matches[5];
+        $this->_query = !empty($matches[6]) ? $matches[7] : false;
+        $this->_fragment = !empty($matches[8]) ? $matches[9] : false;
+    }
+
+    /**
+     * Magic Setter.
+     *
+     * This method will magically set the value of a private variable ($var)
+     * with the value passed as the args
+     *
+     * @param  string $var      The private variable to set.
+     * @param  mixed  $arg      An argument of any type.
+     * @return void
+     */
+    public function __set($var, $arg)
+    {
+        $method = 'set' . $var;
+        if (method_exists($this, $method)) {
+            $this->$method($arg);
+        }
+    }
+    
+    /**
+     * Magic Getter.
+     *
+     * This is the magic get method to retrieve the private variable 
+     * that was set by either __set() or it's setter...
+     * 
+     * @param  string $var         The property name to retrieve.
+     * @return mixed  $this->$var  Either a boolean false if the
+     *                             property is not set or the value
+     *                             of the private property.
+     */
+    public function __get($var)
+    {
+        $method = 'get' . $var;
+        if (method_exists($this, $method)) {
+            return $this->$method();
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Returns the scheme, e.g. "http" or "urn", or false if there is no
+     * scheme specified, i.e. if this is a relative URL.
+     *
+     * @return  string|bool
+     */
+    public function getScheme()
+    {
+        return $this->_scheme;
+    }
+
+    /**
+     * Sets the scheme, e.g. "http" or "urn". Specify false if there is no
+     * scheme specified, i.e. if this is a relative URL.
+     *
+     * @param string|bool $scheme e.g. "http" or "urn", or false if there is no
+     *                            scheme specified, i.e. if this is a relative
+     *                            URL
+     *
+     * @return void
+     * @see    getScheme()
+     */
+    public function setScheme($scheme)
+    {
+        $this->_scheme = $scheme;
+    }
+
+    /**
+     * Returns the user part of the userinfo part (the part preceding the first
+     *  ":"), or false if there is no userinfo part.
+     *
+     * @return  string|bool
+     */
+    public function getUser()
+    {
+        return $this->_userinfo !== false
+            ? preg_replace('@:.*$@', '', $this->_userinfo)
+            : false;
+    }
+
+    /**
+     * Returns the password part of the userinfo part (the part after the first
+     *  ":"), or false if there is no userinfo part (i.e. the URL does not
+     * contain "@" in front of the hostname) or the userinfo part does not
+     * contain ":".
+     *
+     * @return  string|bool
+     */
+    public function getPassword()
+    {
+        return $this->_userinfo !== false
+            ? substr(strstr($this->_userinfo, ':'), 1)
+            : false;
+    }
+
+    /**
+     * Returns the userinfo part, or false if there is none, i.e. if the
+     * authority part does not contain "@".
+     *
+     * @return  string|bool
+     */
+    public function getUserinfo()
+    {
+        return $this->_userinfo;
+    }
+
+    /**
+     * Sets the userinfo part. If two arguments are passed, they are combined
+     * in the userinfo part as username ":" password.
+     *
+     * @param string|bool $userinfo userinfo or username
+     * @param string|bool $password optional password, or false
+     *
+     * @return void
+     */
+    public function setUserinfo($userinfo, $password = false)
+    {
+        $this->_userinfo = $userinfo;
+        if ($password !== false) {
+            $this->_userinfo .= ':' . $password;
+        }
+    }
+
+    /**
+     * Returns the host part, or false if there is no authority part, e.g.
+     * relative URLs.
+     *
+     * @return  string|bool a hostname, an IP address, or false
+     */
+    public function getHost()
+    {
+        return $this->_host;
+    }
+
+    /**
+     * Sets the host part. Specify false if there is no authority part, e.g.
+     * relative URLs.
+     *
+     * @param string|bool $host a hostname, an IP address, or false
+     *
+     * @return void
+     */
+    public function setHost($host)
+    {
+        $this->_host = $host;
+    }
+
+    /**
+     * Returns the port number, or false if there is no port number specified,
+     * i.e. if the default port is to be used.
+     *
+     * @return  string|bool
+     */
+    public function getPort()
+    {
+        return $this->_port;
+    }
+
+    /**
+     * Sets the port number. Specify false if there is no port number specified,
+     * i.e. if the default port is to be used.
+     *
+     * @param string|bool $port a port number, or false
+     *
+     * @return void
+     */
+    public function setPort($port)
+    {
+        $this->_port = $port;
+    }
+
+    /**
+     * Returns the authority part, i.e. [ userinfo "@" ] host [ ":" port ], or
+     * false if there is no authority.
+     *
+     * @return string|bool
+     */
+    public function getAuthority()
+    {
+        if (!$this->_host) {
+            return false;
+        }
+
+        $authority = '';
+
+        if ($this->_userinfo !== false) {
+            $authority .= $this->_userinfo . '@';
+        }
+
+        $authority .= $this->_host;
+
+        if ($this->_port !== false) {
+            $authority .= ':' . $this->_port;
+        }
+
+        return $authority;
+    }
+
+    /**
+     * Sets the authority part, i.e. [ userinfo "@" ] host [ ":" port ]. Specify
+     * false if there is no authority.
+     *
+     * @param string|false $authority a hostname or an IP addresse, possibly
+     *                                with userinfo prefixed and port number
+     *                                appended, e.g. "foo:bar@example.org:81".
+     *
+     * @return void
+     */
+    public function setAuthority($authority)
+    {
+        $this->_userinfo = false;
+        $this->_host     = false;
+        $this->_port     = false;
+        if (preg_match('@^(([^\@]*)\@)?([^:]+)(:(\d*))?$@', $authority, $reg)) {
+            if ($reg[1]) {
+                $this->_userinfo = $reg[2];
+            }
+
+            $this->_host = $reg[3];
+            if (isset($reg[5])) {
+                $this->_port = $reg[5];
+            }
+        }
+    }
+
+    /**
+     * Returns the path part (possibly an empty string).
+     *
+     * @return string
+     */
+    public function getPath()
+    {
+        return $this->_path;
+    }
+
+    /**
+     * Sets the path part (possibly an empty string).
+     *
+     * @param string $path a path
+     *
+     * @return void
+     */
+    public function setPath($path)
+    {
+        $this->_path = $path;
+    }
+
+    /**
+     * Returns the query string (excluding the leading "?"), or false if "?"
+     * is not present in the URL.
+     *
+     * @return  string|bool
+     * @see     self::getQueryVariables()
+     */
+    public function getQuery()
+    {
+        return $this->_query;
+    }
+
+    /**
+     * Sets the query string (excluding the leading "?"). Specify false if "?"
+     * is not present in the URL.
+     *
+     * @param string|bool $query a query string, e.g. "foo=1&bar=2"
+     *
+     * @return void
+     * @see   self::setQueryVariables()
+     */
+    public function setQuery($query)
+    {
+        $this->_query = $query;
+    }
+
+    /**
+     * Returns the fragment name, or false if "#" is not present in the URL.
+     *
+     * @return  string|bool
+     */
+    public function getFragment()
+    {
+        return $this->_fragment;
+    }
+
+    /**
+     * Sets the fragment name. Specify false if "#" is not present in the URL.
+     *
+     * @param string|bool $fragment a fragment excluding the leading "#", or
+     *                              false
+     *
+     * @return void
+     */
+    public function setFragment($fragment)
+    {
+        $this->_fragment = $fragment;
+    }
+
+    /**
+     * Returns the query string like an array as the variables would appear in
+     * $_GET in a PHP script. If the URL does not contain a "?", an empty array
+     * is returned.
+     *
+     * @return  array
+     */
+    public function getQueryVariables()
+    {
+        $pattern = '/[' .
+                   preg_quote($this->getOption(self::OPTION_SEPARATOR_INPUT), '/') .
+                   ']/';
+        $parts   = preg_split($pattern, $this->_query, -1, PREG_SPLIT_NO_EMPTY);
+        $return  = array();
+
+        foreach ($parts as $part) {
+            if (strpos($part, '=') !== false) {
+                list($key, $value) = explode('=', $part, 2);
+            } else {
+                $key   = $part;
+                $value = null;
+            }
+
+            if ($this->getOption(self::OPTION_ENCODE_KEYS)) {
+                $key = rawurldecode($key);
+            }
+            $value = rawurldecode($value);
+
+            if ($this->getOption(self::OPTION_USE_BRACKETS) &&
+                preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) {
+
+                $key = $matches[1];
+                $idx = $matches[2];
+
+                // Ensure is an array
+                if (empty($return[$key]) || !is_array($return[$key])) {
+                    $return[$key] = array();
+                }
+
+                // Add data
+                if ($idx === '') {
+                    $return[$key][] = $value;
+                } else {
+                    $return[$key][$idx] = $value;
+                }
+            } elseif (!$this->getOption(self::OPTION_USE_BRACKETS)
+                      && !empty($return[$key])
+            ) {
+                $return[$key]   = (array) $return[$key];
+                $return[$key][] = $value;
+            } else {
+                $return[$key] = $value;
+            }
+        }
+
+        return $return;
+    }
+
+    /**
+     * Sets the query string to the specified variable in the query string.
+     *
+     * @param array $array (name => value) array
+     *
+     * @return void
+     */
+    public function setQueryVariables(array $array)
+    {
+        if (!$array) {
+            $this->_query = false;
+        } else {
+            foreach ($array as $name => $value) {
+                if ($this->getOption(self::OPTION_ENCODE_KEYS)) {
+                    $name = self::urlencode($name);
+                }
+
+                if (is_array($value)) {
+                    foreach ($value as $k => $v) {
+                        $parts[] = $this->getOption(self::OPTION_USE_BRACKETS)
+                            ? sprintf('%s[%s]=%s', $name, $k, $v)
+                            : ($name . '=' . $v);
+                    }
+                } elseif (!is_null($value)) {
+                    $parts[] = $name . '=' . self::urlencode($value);
+                } else {
+                    $parts[] = $name;
+                }
+            }
+            $this->_query = implode($this->getOption(self::OPTION_SEPARATOR_OUTPUT),
+                                    $parts);
+        }
+    }
+
+    /**
+     * Sets the specified variable in the query string.
+     *
+     * @param string $name  variable name
+     * @param mixed  $value variable value
+     *
+     * @return  array
+     */
+    public function setQueryVariable($name, $value)
+    {
+        $array = $this->getQueryVariables();
+        $array[$name] = $value;
+        $this->setQueryVariables($array);
+    }
+
+    /**
+     * Removes the specifed variable from the query string.
+     *
+     * @param string $name a query string variable, e.g. "foo" in "?foo=1"
+     *
+     * @return void
+     */
+    public function unsetQueryVariable($name)
+    {
+        $array = $this->getQueryVariables();
+        unset($array[$name]);
+        $this->setQueryVariables($array);
+    }
+
+    /**
+     * Returns a string representation of this URL.
+     *
+     * @return  string
+     */
+    public function getURL()
+    {
+        // See RFC 3986, section 5.3
+        $url = "";
+
+        if ($this->_scheme !== false) {
+            $url .= $this->_scheme . ':';
+        }
+
+        $authority = $this->getAuthority();
+        if ($authority !== false) {
+            $url .= '//' . $authority;
+        }
+        $url .= $this->_path;
+
+        if ($this->_query !== false) {
+            $url .= '?' . $this->_query;
+        }
+
+        if ($this->_fragment !== false) {
+            $url .= '#' . $this->_fragment;
+        }
+    
+        return $url;
+    }
+
+    /**
+     * Returns a string representation of this URL.
+     *
+     * @return  string
+     * @see toString()
+     */
+    public function __toString()
+    {
+        return $this->getURL();
+    }
+
+    /** 
+     * Returns a normalized string representation of this URL. This is useful
+     * for comparison of URLs.
+     *
+     * @return  string
+     */
+    public function getNormalizedURL()
+    {
+        $url = clone $this;
+        $url->normalize();
+        return $url->getUrl();
+    }
+
+    /** 
+     * Returns a normalized Net_URL2 instance.
+     *
+     * @return  Net_URL2
+     */
+    public function normalize()
+    {
+        // See RFC 3886, section 6
+
+        // Schemes are case-insensitive
+        if ($this->_scheme) {
+            $this->_scheme = strtolower($this->_scheme);
+        }
+
+        // Hostnames are case-insensitive
+        if ($this->_host) {
+            $this->_host = strtolower($this->_host);
+        }
+
+        // Remove default port number for known schemes (RFC 3986, section 6.2.3)
+        if ($this->_port &&
+            $this->_scheme &&
+            $this->_port == getservbyname($this->_scheme, 'tcp')) {
+
+            $this->_port = false;
+        }
+
+        // Normalize case of %XX percentage-encodings (RFC 3986, section 6.2.2.1)
+        foreach (array('_userinfo', '_host', '_path') as $part) {
+            if ($this->$part) {
+                $this->$part = preg_replace('/%[0-9a-f]{2}/ie',
+                                            'strtoupper("\0")',
+                                            $this->$part);
+            }
+        }
+
+        // Path segment normalization (RFC 3986, section 6.2.2.3)
+        $this->_path = self::removeDotSegments($this->_path);
+
+        // Scheme based normalization (RFC 3986, section 6.2.3)
+        if ($this->_host && !$this->_path) {
+            $this->_path = '/';
+        }
+    }
+
+    /**
+     * Returns whether this instance represents an absolute URL.
+     *
+     * @return  bool
+     */
+    public function isAbsolute()
+    {
+        return (bool) $this->_scheme;
+    }
+
+    /**
+     * Returns an Net_URL2 instance representing an absolute URL relative to
+     * this URL.
+     *
+     * @param Net_URL2|string $reference relative URL
+     *
+     * @return Net_URL2
+     */
+    public function resolve($reference)
+    {
+        if (!$reference instanceof Net_URL2) {
+            $reference = new self($reference);
+        }
+        if (!$this->isAbsolute()) {
+            throw new Exception('Base-URL must be absolute');
+        }
+
+        // A non-strict parser may ignore a scheme in the reference if it is
+        // identical to the base URI's scheme.
+        if (!$this->getOption(self::OPTION_STRICT) && $reference->_scheme == $this->_scheme) {
+            $reference->_scheme = false;
+        }
+
+        $target = new self('');
+        if ($reference->_scheme !== false) {
+            $target->_scheme = $reference->_scheme;
+            $target->setAuthority($reference->getAuthority());
+            $target->_path  = self::removeDotSegments($reference->_path);
+            $target->_query = $reference->_query;
+        } else {
+            $authority = $reference->getAuthority();
+            if ($authority !== false) {
+                $target->setAuthority($authority);
+                $target->_path  = self::removeDotSegments($reference->_path);
+                $target->_query = $reference->_query;
+            } else {
+                if ($reference->_path == '') {
+                    $target->_path = $this->_path;
+                    if ($reference->_query !== false) {
+                        $target->_query = $reference->_query;
+                    } else {
+                        $target->_query = $this->_query;
+                    }
+                } else {
+                    if (substr($reference->_path, 0, 1) == '/') {
+                        $target->_path = self::removeDotSegments($reference->_path);
+                    } else {
+                        // Merge paths (RFC 3986, section 5.2.3)
+                        if ($this->_host !== false && $this->_path == '') {
+                            $target->_path = '/' . $this->_path;
+                        } else {
+                            $i = strrpos($this->_path, '/');
+                            if ($i !== false) {
+                                $target->_path = substr($this->_path, 0, $i + 1);
+                            }
+                            $target->_path .= $reference->_path;
+                        }
+                        $target->_path = self::removeDotSegments($target->_path);
+                    }
+                    $target->_query = $reference->_query;
+                }
+                $target->setAuthority($this->getAuthority());
+            }
+            $target->_scheme = $this->_scheme;
+        }
+
+        $target->_fragment = $reference->_fragment;
+
+        return $target;
+    }
+
+    /**
+     * Removes dots as described in RFC 3986, section 5.2.4, e.g.
+     * "/foo/../bar/baz" => "/bar/baz"
+     *
+     * @param string $path a path
+     *
+     * @return string a path
+     */
+    public static function removeDotSegments($path)
+    {
+        $output = '';
+
+        // Make sure not to be trapped in an infinite loop due to a bug in this
+        // method
+        $j = 0; 
+        while ($path && $j++ < 100) {
+            if (substr($path, 0, 2) == './') {
+                // Step 2.A
+                $path = substr($path, 2);
+            } elseif (substr($path, 0, 3) == '../') {
+                // Step 2.A
+                $path = substr($path, 3);
+            } elseif (substr($path, 0, 3) == '/./' || $path == '/.') {
+                // Step 2.B
+                $path = '/' . substr($path, 3);
+            } elseif (substr($path, 0, 4) == '/../' || $path == '/..') {
+                // Step 2.C
+                $path   = '/' . substr($path, 4);
+                $i      = strrpos($output, '/');
+                $output = $i === false ? '' : substr($output, 0, $i);
+            } elseif ($path == '.' || $path == '..') {
+                // Step 2.D
+                $path = '';
+            } else {
+                // Step 2.E
+                $i = strpos($path, '/');
+                if ($i === 0) {
+                    $i = strpos($path, '/', 1);
+                }
+                if ($i === false) {
+                    $i = strlen($path);
+                }
+                $output .= substr($path, 0, $i);
+                $path = substr($path, $i);
+            }
+        }
+
+        return $output;
+    }
+
+    /**
+     * Percent-encodes all non-alphanumeric characters except these: _ . - ~
+     * Similar to PHP's rawurlencode(), except that it also encodes ~ in PHP
+     * 5.2.x and earlier.
+     *
+     * @param  $raw the string to encode
+     * @return string
+     */
+    public static function urlencode($string)
+    {
+    	$encoded = rawurlencode($string);
+	// This is only necessary in PHP < 5.3.
+	$encoded = str_replace('%7E', '~', $encoded);
+	return $encoded;
+    }
+
+    /**
+     * Returns a Net_URL2 instance representing the canonical URL of the
+     * currently executing PHP script.
+     * 
+     * @return  string
+     */
+    public static function getCanonical()
+    {
+        if (!isset($_SERVER['REQUEST_METHOD'])) {
+            // ALERT - no current URL
+            throw new Exception('Script was not called through a webserver');
+        }
+
+        // Begin with a relative URL
+        $url = new self($_SERVER['PHP_SELF']);
+        $url->_scheme = isset($_SERVER['HTTPS']) ? 'https' : 'http';
+        $url->_host   = $_SERVER['SERVER_NAME'];
+        $port = $_SERVER['SERVER_PORT'];
+        if ($url->_scheme == 'http' && $port != 80 ||
+            $url->_scheme == 'https' && $port != 443) {
+
+            $url->_port = $port;
+        }
+        return $url;
+    }
+
+    /**
+     * Returns the URL used to retrieve the current request.
+     *
+     * @return  string
+     */
+    public static function getRequestedURL()
+    {
+        return self::getRequested()->getUrl();
+    }
+
+    /**
+     * Returns a Net_URL2 instance representing the URL used to retrieve the
+     * current request.
+     *
+     * @return  Net_URL2
+     */
+    public static function getRequested()
+    {
+        if (!isset($_SERVER['REQUEST_METHOD'])) {
+            // ALERT - no current URL
+            throw new Exception('Script was not called through a webserver');
+        }
+
+        // Begin with a relative URL
+        $url = new self($_SERVER['REQUEST_URI']);
+        $url->_scheme = isset($_SERVER['HTTPS']) ? 'https' : 'http';
+        // Set host and possibly port
+        $url->setAuthority($_SERVER['HTTP_HOST']);
+        return $url;
+    }
+
+    /**
+     * Returns the value of the specified option.
+     *
+     * @param string $optionName The name of the option to retrieve
+     *
+     * @return  mixed
+     */
+    function getOption($optionName)
+    {
+        return isset($this->_options[$optionName])
+            ? $this->_options[$optionName] : false;
+    }
+}
diff --git a/lib/php/SimpleCAS.php b/lib/php/SimpleCAS.php
new file mode 100644
index 0000000000000000000000000000000000000000..6de5c28dd4eede7019b3026b7fba1bd5ce629e31
--- /dev/null
+++ b/lib/php/SimpleCAS.php
@@ -0,0 +1,274 @@
+<?php
+/**
+ * This is a CAS client authentication library for PHP 5.
+ * 
+ * <code>
+ * <?php
+ * $protocol = new SimpleCAS_Protocol_Version2('login.unl.edu', 443, 'cas');
+ * $client = SimpleCAS::client($protocol);
+ * $client->forceAuthentication();
+ * 
+ * if (isset($_GET['logout'])) {
+ *     $client->logout();
+ * }
+ * 
+ * if ($client->isAuthenticated()) {
+ *     echo '<h1>Authentication Successful!</h1>';
+ *     echo '<p>The user\'s login is '.$client->getUsername().'</p>';
+ *     echo '<a href="?logout">Logout</a>';
+ * }
+ * </code>
+ * 
+ * PHP version 5
+ * 
+ * @category  Authentication 
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ */
+class SimpleCAS
+{
+    /**
+     * Version of the CAS library.
+     */
+    const VERSION = '0.0.1';
+    
+    /**
+     * Singleton CAS object
+     *
+     * @var CAS
+     */
+    static private $_instance;
+    
+    /**
+     * Is user authenticated?
+     *
+     * @var bool
+     */
+    private $_authenticated = false;
+    
+    /**
+     * Protocol for the server running the CAS service.
+     *
+     * @var SimpleCAS_Protocol
+     */
+    protected $protocol;
+    
+    /**
+     * User's login name if authenticated.
+     *
+     * @var string
+     */
+    protected $username;
+
+    /**
+     * (Optional) alternative service URL to return to after CAS authentication.
+     *
+     * @var string
+     */
+    static protected $url;
+    
+    /**
+     * Construct a CAS client object.
+     *
+     * @param SimpleCAS_Protocol $protocol Protocol to use for authentication.
+     */
+    private function __construct(SimpleCAS_Protocol $protocol)
+    {
+        $this->protocol = $protocol;
+        
+        if ($this->protocol instanceof SimpleCAS_SingleSignOut
+            && isset($_POST)) {
+            if ($ticket = $this->protocol->validateLogoutRequest($_POST)) {
+                $this->logout($ticket);
+            }
+        }
+        
+        if (session_id() == '') {
+            session_start();
+        }
+        
+        if (isset($_SESSION['__SIMPLECAS_TICKET'])) {
+            $this->_authenticated = true;
+        }
+        
+        
+        if ($this->_authenticated == false
+            && isset($_GET['ticket'])) {
+            $this->validateTicket($_GET['ticket']);
+        }
+    }
+    
+    /**
+     * Checks a ticket to see if it is valid.
+     * 
+     * If the CAS server verifies the ticket, a session is created and the user
+     * is marked as authenticated.
+     *
+     * @param string $ticket Ticket from the CAS Server
+     * 
+     * @return bool
+     */
+    protected function validateTicket($ticket)
+    {
+        if ($uid = $this->protocol->validateTicket($ticket, self::getURL())) {
+            $this->setAuthenticated($uid);
+            $this->redirect(self::getURL());
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    /**
+     * Marks the current session as authenticated.
+     *
+     * @param string $uid User name returned by the CAS server.
+     * 
+     * @return void
+     */
+    protected function setAuthenticated($uid)
+    {
+        $_SESSION['__SIMPLECAS_TICKET'] = true;
+        $_SESSION['__SIMPLECAS_UID']    = $uid;
+        $this->_authenticated           = true;
+    }
+    
+    /**
+     * Return the authenticated user's login name.
+     *
+     * @return string
+     */
+    public function getUsername()
+    {
+        return $_SESSION['__SIMPLECAS_UID'];
+    }
+    
+    /**
+     * Singleton interface, returns CAS object.
+     * 
+     * @param CAS_Server $server CAS Server object
+     * 
+     * @return CAS
+     */
+    static public function client(SimpleCAS_Protocol $protocol)
+    {
+        if (!isset(self::$_instance)) {
+            self::$_instance = new self($protocol);
+        }
+        
+        return self::$_instance;
+    }
+    
+    /**
+     * If client is not authenticated, this will redirecting to login and exit.
+     * 
+     * Otherwise, return the CAS object.
+     *
+     * @return CAS
+     */
+    function forceAuthentication()
+    {
+        if (!$this->isAuthenticated()) {
+            self::redirect($this->protocol->getLoginURL(self::getURL()));
+        }
+        return $this;
+    }
+    
+    /**
+     * Check if this user has been authenticated or not.
+     * 
+     * @return bool
+     */
+    function isAuthenticated()
+    {
+        return $this->_authenticated;
+    }
+    
+    /**
+     * Destroys session data for this client, redirects to the server logout
+     * url.
+     * 
+     * @param string $url URL to provide the client on logout.
+     * 
+     * @return void
+     */
+    public function logout($url = '')
+    {
+        session_destroy();
+        if (empty($url)) {
+            $url = self::getURL();
+        }
+        $this->redirect($this->protocol->getLogoutURL($url));
+    }
+    
+    /**
+     * Returns the current URL without CAS affecting parameters.
+     * 
+     * @return string url
+     */
+    static public function getURL()
+    {
+        if (!empty(self::$url)) {
+            return self::$url;
+        }
+        if (isset($_SERVER['HTTPS'])
+            && !empty($_SERVER['HTTPS'])
+            && $_SERVER['HTTPS'] == 'on') {
+            $protocol = 'https';
+        } else {
+            $protocol = 'http';
+        }
+    
+        $url = $protocol.'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
+        
+        $replacements = array('/\?logout/'        => '',
+                              '/&ticket=[^&]*/'   => '',
+                              '/\?ticket=[^&;]*/' => '?',
+                              '/\?%26/'           => '?',
+                              '/\?&/'             => '?',
+                              '/\?$/'             => '');
+        
+        $url = preg_replace(array_keys($replacements),
+                            array_values($replacements), $url);
+        
+        return $url;
+    }
+    
+   /**
+    * Set an alternative return URL
+    * 
+    * @param string $url alternative return URL
+    * 
+    * @return void
+    */ 
+    public static function setURL($url)
+    {
+        self::$url = $url; 
+    }
+    
+    /**
+     * Send a header to redirect the client to another URL.
+     *
+     * @param string $url URL to redirect the client to.
+     * 
+     * @return void
+     */
+    public static function redirect($url)
+    {
+        header("Location: $url");
+        exit();
+    }
+    
+    /**
+     * Get the version of the CAS library
+     *
+     * @return string
+     */
+    static public function getVersion()
+    {
+        return self::VERSION;
+    }
+}
diff --git a/lib/php/SimpleCAS/Autoload.php b/lib/php/SimpleCAS/Autoload.php
new file mode 100644
index 0000000000000000000000000000000000000000..b26f5a07131625c54f2c59ae6d65bfa9391284de
--- /dev/null
+++ b/lib/php/SimpleCAS/Autoload.php
@@ -0,0 +1,62 @@
+<?php
+function SimpleCAS_Autoload($class)
+{
+    if (substr($class, 0, 9) !== 'SimpleCAS') {
+        return false;
+    }
+    $fp = @fopen(str_replace('_', '/', $class) . '.php', 'r', true);
+    if ($fp) {
+        fclose($fp);
+        require str_replace('_', '/', $class) . '.php';
+        if (!class_exists($class, false) && !interface_exists($class, false)) {
+            die(new Exception('Class ' . $class . ' was not present in ' .
+                str_replace('_', '/', $class) . '.php (include_path="' . get_include_path() .
+                '") [SimpleCAS_Autoload version 0.1.0]'));
+        }
+        return true;
+    }
+    $e = new Exception('Class ' . $class . ' could not be loaded from ' .
+        str_replace('_', '/', $class) . '.php, file does not exist (include_path="' . get_include_path() .
+        '") [SimpleCAS_Autoload version 0.1.0]');
+    $trace = $e->getTrace();
+    if (isset($trace[2]) && isset($trace[2]['function']) &&
+          in_array($trace[2]['function'], array('class_exists', 'interface_exists'))) {
+        return false;
+    }
+    if (isset($trace[1]) && isset($trace[1]['function']) &&
+          in_array($trace[1]['function'], array('class_exists', 'interface_exists'))) {
+        return false;
+    }
+    die ((string) $e);
+}
+
+// set up __autoload
+if (function_exists('spl_autoload_register')) {
+    if (!($_____t = spl_autoload_functions()) || !in_array('SimpleCAS_Autoload', spl_autoload_functions())) {
+        spl_autoload_register('SimpleCAS_Autoload');
+        if (function_exists('__autoload') && ($_____t === false)) {
+            // __autoload() was being used, but now would be ignored, add
+            // it to the autoload stack
+            spl_autoload_register('__autoload');
+        }
+    }
+    unset($_____t);
+} elseif (!function_exists('__autoload')) {
+    function __autoload($class) { return SimpleCAS_Autoload($class); }
+}
+
+// set up include_path if it doesn't register our current location
+$____paths = explode(PATH_SEPARATOR, get_include_path());
+$____found = false;
+foreach ($____paths as $____path) {
+    if ($____path == dirname(dirname(__FILE__))) {
+        $____found = true;
+        break;
+    }
+}
+if (!$____found) {
+    set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(__FILE__)));
+}
+unset($____paths);
+unset($____path);
+unset($____found);
diff --git a/lib/php/SimpleCAS/Protocol.php b/lib/php/SimpleCAS/Protocol.php
new file mode 100644
index 0000000000000000000000000000000000000000..d050a6d4b7534e739f57498ac4963501ceebef40
--- /dev/null
+++ b/lib/php/SimpleCAS/Protocol.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Interface all CAS servers must implement.
+ * 
+ * Each concrete class which implements this server interface must provide
+ * all the following functions.
+ * 
+ * PHP version 5
+ * 
+ * @category  Authentication 
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ */
+abstract class SimpleCAS_Protocol
+{
+    const DEFAULT_REQUEST_CLASS = 'HTTP_Request2';
+    
+    protected $requestClass;
+    protected $request;
+    
+    /**
+     * Returns the login URL for the cas server.
+     *
+     * @param string $service The URL to the service requesting authentication.
+     * 
+     * @return string
+     */
+    abstract function getLoginURL($service);
+    
+    /**
+     * Returns the logout url for the CAS server.
+     *
+     * @param string $service A URL to provide the user upon logout.
+     * 
+     * @return string
+     */
+    abstract function getLogoutURL($service = null);
+    
+    /**
+     * Returns the version of this cas server.
+     * 
+     * @return string
+     */
+    abstract function getVersion();
+    
+    /**
+     * Function to validate a ticket and service combination.
+     *
+     * @param string $ticket  Ticket given by the CAS Server
+     * @param string $service Service requesting authentication
+     * 
+     * @return false|string False on failure, user name on success.
+     */
+    abstract function validateTicket($ticket, $service);
+    
+    /**
+     * Get the HTTP_Request2 object.
+     *
+     * @return HTTP_Request
+     */
+    function getRequest()
+    {
+        $class = empty($this->requestClass) ? self::DEFAULT_REQUEST_CLASS : $this->requestClass;
+        if (!$this->request instanceof $class) {
+            $this->request = new $class();
+        }
+        return $this->request; 
+    }
+    
+    /**
+     * Set the HTTP Request object.
+     *
+     * @param $request
+     */
+    function setRequest($request)
+    {
+        $this->request = $request;
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/SimpleCAS/Protocol/Version1.php b/lib/php/SimpleCAS/Protocol/Version1.php
new file mode 100644
index 0000000000000000000000000000000000000000..7879522facf558b73840c2f4453c0dcf7bdeeb00
--- /dev/null
+++ b/lib/php/SimpleCAS/Protocol/Version1.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Class representing a CAS server which supports the CAS1 protocol.
+ * 
+ * PHP version 5
+ * 
+ * @category  Authentication 
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ */
+class SimpleCAS_Protocol_Version1 extends SimpleCAS_Protocol
+{
+    const VERSION = '1.0';
+    
+    protected $request;
+    
+    /**
+     * Construct a new SimpleCAS server object.
+     *
+     *  <code>
+     *  $options = array('hostname' => 'login.unl.edu',
+     *                   'port'     => 443,
+     *                   'uri'      => 'cas');
+     *  $protocol = new SimpleCAS_Protocol_Version1($options);
+     *  </code>
+     *
+     * @param array()
+     */
+    function __construct($options)
+    {
+        foreach ($options as $option=>$val) {
+            $this->$option = $val;
+        }
+    }
+    
+    /**
+     * Returns the URL used to validate a ticket.
+     *
+     * @param string $ticket  Ticket to validate
+     * @param string $service URL to the service requesting authentication
+     * 
+     * @return string
+     */
+    function getValidationURL($ticket, $service)
+    {
+        return 'https://' . $this->hostname . '/'
+                          . $this->uri . '/validate?'
+                          . 'service=' . urlencode($service)
+                          . '&ticket=' . $ticket;
+    }
+    
+    /**
+     * Returns the URL to login form for the CAS server.
+     *
+     * @param string $service Service url requesting authentication.
+     * 
+     * @return string
+     */
+    function getLoginURL($service)
+    {
+        return 'https://' . $this->hostname
+                          . '/'.$this->uri
+                          . '/login?service='
+                          . urlencode($service);
+    }
+    
+    /**
+     * Returns the URL to logout of the CAS server.
+     *
+     * @param string $service Service url provided to the user.
+     * 
+     * @return string
+     */
+    function getLogoutURL($service = '')
+    {
+        if (isset($service)) {
+            $service = '?url='.urlencode($service);
+        }
+        
+        return 'https://' . $this->hostname
+                          . '/'.$this->uri
+                          . '/logout'
+                          . $service;
+    }
+    
+    /**
+     * Function to validate a ticket and service combination.
+     *
+     * @param string $ticket  Ticket given by the CAS Server
+     * @param string $service Service requesting authentication
+     * 
+     * @return false|string False on failure, user name on success.
+     */
+    function validateTicket($ticket, $service)
+    {
+        $validation_url = $this->getValidationURL($ticket, $service);
+        
+        $http_request = clone $this->getRequest();
+        
+        $defaultClass = SimpleCAS_Protocol::DEFAULT_REQUEST_CLASS;
+        if ($http_request instanceof $defaultClass) {
+            $http_request->setURL($validation_url);
+            
+            $response = $http_request->send();
+        } else {
+            $http_request->setUri($validation_url);
+            
+            $response = $http_request->request();
+        }
+        
+        
+        if ($response->getStatus() == 200
+            && substr($response->getBody(), 0, 3) == 'yes') {
+            list($message, $uid) = explode("\n", $response->getBody());
+            return $uid;
+        }
+        return false;
+    }
+    
+    /**
+     * Returns the CAS server protocol this object implements.
+     *
+     * @return string
+     */
+    function getVersion()
+    {
+        return self::VERSION;
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/SimpleCAS/Protocol/Version2.php b/lib/php/SimpleCAS/Protocol/Version2.php
new file mode 100644
index 0000000000000000000000000000000000000000..e32d665aad1533dde18e05d9d664540869648569
--- /dev/null
+++ b/lib/php/SimpleCAS/Protocol/Version2.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Class representing a CAS server which supports the CAS2 protocol.
+ *
+ * PHP version 5
+ *
+ * @category  Authentication
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ */
+class SimpleCAS_Protocol_Version2 extends SimpleCAS_Protocol_Version1 implements SimpleCAS_SingleSignOut, SimpleCAS_ProxyGranting
+{
+    const VERSION = '2.0';
+    
+    /**
+     * Returns the URL used to validate a ticket.
+     *
+     * @param string $ticket  Ticket to validate
+     * @param string $service URL to the service requesting authentication
+     *
+     * @return string
+     */
+    function getValidationURL($ticket, $service, $pgtUrl = null)
+    {
+        return 'https://' . $this->hostname . '/'
+                          . $this->uri . '/serviceValidate?'
+                          . 'service=' . urlencode($service)
+                          . '&ticket=' . $ticket
+                          . '&pgtUrl=' . urlencode($pgtUrl);
+    }
+    
+    /**
+     * Function to validate a ticket and service combination.
+     *
+     * @param string $ticket  Ticket given by the CAS Server
+     * @param string $service Service requesting authentication
+     *
+     * @return false|string False on failure, user name on success.
+     */
+    function validateTicket($ticket, $service)
+    {
+        $validation_url = $this->getValidationURL($ticket, $service);
+        
+        $http_request = clone $this->getRequest();
+        
+        $defaultClass = SimpleCAS_Protocol::DEFAULT_REQUEST_CLASS;
+        if ($http_request instanceof $defaultClass) {
+            $http_request->setURL($validation_url);
+            
+            $response = $http_request->send();
+        } else {
+            $http_request->setUri($validation_url);
+            
+            $response = $http_request->request();
+        }
+        
+        if ($response->getStatus() == 200) {
+            $validationResponse = new SimpleCAS_Protocol_Version2_ValidationResponse($response->getBody());
+            if ($validationResponse->authenticationSuccess()) {
+                return $validationResponse->__toString();
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Validates a single sign out logout request.
+     *
+     * @param mixed $post $_POST data
+     *
+     * @return bool
+     */
+    function validateLogoutRequest($post)
+    {
+        if (false) {
+            return $ticket;
+        }
+        return false;
+    }
+    
+    function getProxyTicket()
+    {
+        throw new Exception('not implemented');
+    }
+    
+    function validateProxyTicket($ticket)
+    {
+        throw new Exception('not implemented');
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/SimpleCAS/Protocol/Version2/ValidationResponse.php b/lib/php/SimpleCAS/Protocol/Version2/ValidationResponse.php
new file mode 100644
index 0000000000000000000000000000000000000000..225a759b32680705d8b2c538e0927c61e0efae33
--- /dev/null
+++ b/lib/php/SimpleCAS/Protocol/Version2/ValidationResponse.php
@@ -0,0 +1,62 @@
+<?php
+class SimpleCAS_Protocol_Version2_ValidationResponse
+{
+    protected $authenticationSuccess = false;
+    protected $user    = false;
+    protected $pgtiou  = false;
+    protected $proxies = array();
+
+    /**
+     * Construct a validation repsonse object from the CAS server's response.
+     * 
+     * @param string $response
+     */
+    function __construct($response)
+    {
+        $xml = new DOMDocument();
+        if ($xml->loadXML($response)) {
+            if ($success = $xml->getElementsByTagName('authenticationSuccess')) {
+                if ($success->length > 0
+                    && $uid = $success->item(0)->getElementsByTagName('user')) {
+                    // We have the user name, check for PGTIOU
+                    if ($iou = $success->item(0)->getElementsByTagName('proxyGrantingTicket')) {
+                        if ($iou->length) {
+                            $this->pgtiou = $iou->item(0)->nodeValue;
+                        }
+                    }
+                    $this->authenticationSuccess = true;
+                    $this->user = $uid->item(0)->nodeValue;
+                }
+            }
+        }
+    }
+    
+    function authenticationSuccess()
+    {
+        return $this->authenticationSuccess;
+    }
+    
+    function getPGTIOU()
+    {
+        return $this->pgtiou;
+    }
+    
+    function getUser()
+    {
+        return $this->userid;
+    }
+
+    function __toString()
+    {
+        if ($this->authenticationSuccess()) {
+            return $this->user;
+        }
+        throw new Exception('Validation was not successful');
+    }
+    
+    function logout()
+    {
+        
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/SimpleCAS/ProxyGranting.php b/lib/php/SimpleCAS/ProxyGranting.php
new file mode 100644
index 0000000000000000000000000000000000000000..3ab250ce5855859b82d0cd1a01c3ebd74afb3850
--- /dev/null
+++ b/lib/php/SimpleCAS/ProxyGranting.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Interface for servers that implement proxy granting tickets.
+ *
+ * PHP version 5
+ *
+ * @category  Authentication
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ */
+interface SimpleCAS_ProxyGranting
+{
+    
+    /**
+     * get a proxy ticket
+     *
+     * @return string
+     */
+    function getProxyTicket();
+    
+    /**
+     * try and validate a proxy ticket
+     *
+     * @param unknown_type $ticket
+     */
+    function validateProxyTicket($ticket);
+}
+?>
\ No newline at end of file
diff --git a/lib/php/SimpleCAS/ProxyGranting/Storage.php b/lib/php/SimpleCAS/ProxyGranting/Storage.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5560410893ade9aefe2365605ae2fdee53f44e9
--- /dev/null
+++ b/lib/php/SimpleCAS/ProxyGranting/Storage.php
@@ -0,0 +1,7 @@
+<?php
+interface SimpleCAS_ProxyGranting_Storage
+{
+    function saveIOU($iou);
+    function getProxyGrantingTicket($iou);
+}
+?>
\ No newline at end of file
diff --git a/lib/php/SimpleCAS/ProxyGranting/Storage/File.php b/lib/php/SimpleCAS/ProxyGranting/Storage/File.php
new file mode 100644
index 0000000000000000000000000000000000000000..b345c7768e84a62d4f4c5e8cb4d460f73270942f
--- /dev/null
+++ b/lib/php/SimpleCAS/ProxyGranting/Storage/File.php
@@ -0,0 +1,14 @@
+<?php
+class SimpleCAS_ProxyGranting_Storage_File implements SimpleCAS_ProxyGranting_Storage
+{
+    function saveIOU($iou)
+    {
+        throw new Exception('not implemented');
+    }
+    
+    function getProxyGrantingTicket($iou)
+    {
+        throw new Exception('not implemented');
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/SimpleCAS/SingleSignOut.php b/lib/php/SimpleCAS/SingleSignOut.php
new file mode 100644
index 0000000000000000000000000000000000000000..1b0e97f4399580eeb372c631ced1751228df5827
--- /dev/null
+++ b/lib/php/SimpleCAS/SingleSignOut.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Interface for servers that implement single sign out.
+ * 
+ * PHP version 5
+ * 
+ * @category  Authentication 
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ */
+interface SimpleCAS_SingleSignOut
+{
+    /**
+     * Determines if the posted request is a valid single sign out request.
+     *
+     * @param mixed $post $_POST data sent to the service.
+     * 
+     * @return bool
+     */
+    function validateLogoutRequest($post);
+}
\ No newline at end of file
diff --git a/lib/php/UNL/Auth.php b/lib/php/UNL/Auth.php
new file mode 100644
index 0000000000000000000000000000000000000000..a2a403d51f5dadbde799dc39855782fd1572b77a
--- /dev/null
+++ b/lib/php/UNL/Auth.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * This is a generic authentication framework for UNL which will return customized
+ * containers for use at UNL.
+ * 
+ * <code>
+ * <?php
+ * require_once 'UNL/Auth.php';
+ * $a = UNL_Auth::factory('CAS');
+ * if ($a->isLoggedIn()) {
+ *     echo 'Hello ' . $a->getUser();
+ * } else {
+ *     echo 'Sorry, you must log in.';
+ * }
+ * </code>
+ *
+ * PHP version 5
+ * 
+ * @category  Authentication 
+ * @package   UNL_Auth
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2009 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://pear.unl.edu/package/UNL_Auth
+ */
+class UNL_Auth
+{
+    protected static $_instance = null;
+    
+    public static function getInstance()
+    {
+        if (null === self::$_instance) {
+            self::$_instance = new self();
+        }
+
+        return self::$_instance;
+    }
+    
+    private function __construct()
+    {}
+    
+    private function __clone()
+    {}
+    
+    /**
+     * Abstract factory, used to get drivers for any of the authentication methods
+     * on campus.
+     *
+     * @param string $auth_type CAS, LDAP, LotusNotes, etc
+     * @param mixed  $options   Options for the specific container
+     * 
+     * @return mixed
+     */
+    public static function factory($auth_type, $options = null)
+    {
+        $auth_class = 'UNL_Auth_'.$auth_type;
+        $class_file = dirname(__FILE__).'/Auth/'.$auth_type.'.php';
+        return self::discoverAndReturn($auth_class, $class_file, $options);
+    }
+    
+    /**
+     * Returns an auth container for use with systems compatible with PEAR Auth
+     *
+     * @param string $auth_type CAS, LDAP, LotusNotes, etc
+     * @param mixed  $options   Options for the container
+     * 
+     * @return mixed
+     */
+    public static function PEARFactory($auth_type, $options = null, $loginFunction = null, $showLogin = true)
+    {
+        require_once 'Auth/Auth.php';
+        /// Get the class... return the pear auth container.
+        $auth_class = 'UNL_Auth_'.$auth_type.'_PEARAuth';
+        $class_file = dirname(__FILE__).'/Auth/'.$auth_type.'/PEARAuth.php';
+        $container = self::discoverAndReturn($auth_class, $class_file, $options);
+        return $container->getPEARAuth($options, $loginFunction, $showLogin);
+    }
+    
+    public static function ZendFactory($auth_type, $options = null)
+    {
+        throw new Exception('not implemented yet!');
+        /// Get the class name, return the Zend Auth extended class
+        $auth_class = 'UNL_Auth_'.$auth_type.'_ZendAuth';
+        $class_file = dirname(__FILE__).'/Auth/'.$auth_type.'/ZendAuth.php';
+        $container = self::discoverAndReturn($auth_class, $class_file, $options);
+        return $container;
+    }
+    
+    /**
+     * This is a class used to discover and return a new class based given a class
+     * name and file.
+     *
+     * @param string $class      name of the class to load UNL_Auth_CAS
+     * @param string $class_file ./Auth/CAS.php
+     * 
+     * @return object
+     */
+    protected static function discoverAndReturn($class, $class_file, $options = null)
+    {
+        if (!class_exists($class)) {
+            if (file_exists($class_file)) {
+                require_once $class_file;
+            } else {
+                throw new Exception('Cannot find authentication class that matches '.
+                                    $auth_type.' I tried '.$class_file);
+            }
+        }
+        if (method_exists($class, 'getInstance')) {
+            return call_user_func(array($class, 'getInstance'), $options);
+        } else {
+            return new $class($options);
+        }
+        
+    }
+}
+
+
+?>
\ No newline at end of file
diff --git a/lib/php/UNL/Auth/CAS.php b/lib/php/UNL/Auth/CAS.php
new file mode 100644
index 0000000000000000000000000000000000000000..a73d4d1440d39413c6faf307cb084158cfb23428
--- /dev/null
+++ b/lib/php/UNL/Auth/CAS.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * This is a CAS central authentication.
+ *
+ * DO NOT MODIFY THIS FILE.
+ * This file remains part of the UNL Login public API and is subject to change.
+ * If you require features built into this class, please contact us by email at
+ * <accounts@answers4families.org>.
+ *
+ * based on the Answers4Families [http://www.answers4families.org/] Account Services 
+ * LDAP-CAS API.
+ *
+ * 
+ * PHP version 5
+ * 
+ * @category  Authentication 
+ * @package   UNL_Auth
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @author    Ryan Lim <rlim@ccfl.unl.edu>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://pear.unl.edu/package/UNL_Auth
+ */
+
+require_once 'CAS.php';
+
+
+/**
+ * UNL_Auth_CAS
+ *
+ * This is the CAS UserAccount class.
+ * This class takes care of user authentication using CAS and obtains the user
+ * account information via LDAP.
+ *
+ * This class does not handle changes to the user account information. All account
+ * information changes are handled by http://login.unl.edu/
+ * 
+ */
+class UNL_Auth_CAS extends UNL_Auth
+{
+    
+    /**
+     * Boolean flag to if the user is authenticated or not.
+     * 
+     * @var bool
+     */
+    protected $isAuth = false;
+
+    /**
+     * $uid is the LDAP uid value of the authenticated user.
+     * 
+     * @var string
+     */
+    protected $uid;
+    
+    /**
+     * Options for the CAS server
+     *
+     * @var array
+     */
+    protected $cas_options = array('host' => 'login.unl.edu',
+                                   'port' => 443,
+                                   'path' => 'cas');
+
+    /**
+     * The class constructor used to initialize the phpCAS class settings.
+     */
+    private function __construct(array $options = null)
+    {
+        if (session_id() != '') {
+            $start_session = false;
+        } else {
+            $start_session = true;
+        }
+        phpCAS::setDebug(false);
+        phpCAS::client(CAS_VERSION_2_0,
+            $this->cas_options['host'], $this->cas_options['port'], $this->cas_options['path'],
+            $start_session);
+        phpCAS::setNoCasServerValidation();
+        phpCAS::setCacheTimesForAuthRecheck(-1);
+
+        $this->isAuth = phpCAS::checkAuthentication();
+    }
+    
+    /**
+     * get a singleton instance of this class
+     *
+     * @return UNL_Auth_CAS
+     */
+    public static function getInstance()
+    {
+        if (null === self::$_instance) {
+            self::$_instance = new self();
+        }
+
+        return self::$_instance;
+    }
+    
+    /**
+     * Log in the user.
+     */
+    function login()
+    {
+        phpCAS::forceAuthentication();
+        $this->isAuth = true;
+        $this->uid    = phpCAS::getUser();
+    }
+
+    /**
+     * Log out the user.
+     */
+    function logout()
+    {
+        $this->isAuth = false;
+        phpCAS::forceAuthentication();
+        if (!empty($_SERVER['HTTP_REFERER'])) {
+            phpCAS::logoutWithUrl($_SERVER['HTTP_REFERER']);
+        } else {
+            phpCAS::logout();
+        }
+    }
+
+    /**
+     * Checks to see if the user is logged in.
+     * 
+     * @return bool true if logged in, false otherwise.
+     */
+    function isLoggedIn()
+    {
+        return $this->isAuth;
+    }
+
+    /**
+     * Get the LDAP-uid.
+     *
+     * @return string | bool The LDAP uid of the logged in user.
+     */
+    function getUser()
+    {
+        if ($this->isAuth) {
+            return phpCAS::getUser();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Stores the LDAP-uid internally in this instance of the class.
+     *
+     * @return string The LDAP uid of the logged in user. If the user is not logged in, return false.
+     */
+    function getUid()
+    {
+        $this->uid = $this->getUser();
+        return $this->uid;
+    }
+}
diff --git a/lib/php/UNL/Auth/CAS/PEARAuth.php b/lib/php/UNL/Auth/CAS/PEARAuth.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2f441bf5b64d9670e95fd6f8160b47519df4079
--- /dev/null
+++ b/lib/php/UNL/Auth/CAS/PEARAuth.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * PEAR Auth compatible container for CAS
+ *
+ * PHP version 5
+ * 
+ * @category  Default 
+ * @package   UNL_Auth
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://pear.unl.edu/package/UNL_Auth
+ */
+
+include_once 'Auth/Container.php';
+require_once 'UNL/Auth/CAS.php';
+
+class UNL_Auth_CAS_PEARAuth extends Auth_Container
+{
+    protected $cas;
+    
+    public function __construct($options)
+    {
+        $this->cas = UNL_Auth_CAS::getInstance();
+    }
+    
+    public function getPEARAuth($options = null, $loginFunction = null, $showLogin = true)
+    {
+        if (!isset($loginFunction)) {
+            $loginFunction = array('UNL_Auth_CAS_PEARAuth', 'login');
+        }
+        $auth = new Auth($this, $options, $loginFunction, $showLogin);
+        if ($this->checkAuth()) {
+            $auth->setAuth($this->getUsername());
+        }
+        $auth->setLogoutCallback(array('UNL_Auth_CAS_PEARAuth','logout'));
+        return $auth;
+    }
+    
+    public function login()
+    {
+        UNL_Auth_CAS::getInstance()->login();
+    }
+    
+    public function logout()
+    {
+        return UNL_Auth_CAS::getInstance()->logout();
+    }
+    
+    public function getAuth()
+    {
+        return UNL_Auth_CAS::getInstance()->isLoggedIn();
+    }
+    
+    public function checkAuth()
+    {
+        return UNL_Auth_CAS::getInstance()->isLoggedIn();
+    }
+    
+    public function getUsername()
+    {
+        return UNL_Auth_CAS::getInstance()->getUser();
+    }
+    
+}
diff --git a/lib/php/UNL/Auth/SimpleCAS.php b/lib/php/UNL/Auth/SimpleCAS.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f2cd0cfb1be2d0c7281e752d9723b671ab2c268
--- /dev/null
+++ b/lib/php/UNL/Auth/SimpleCAS.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * This is a CAS central authentication.
+ *
+ * PHP version 5
+ * 
+ * @category  Authentication 
+ * @package   UNL_Auth
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://pear.unl.edu/package/UNL_Auth
+ */
+
+require_once 'SimpleCAS/Autoload.php';
+require_once 'HTTP/Request2.php';
+
+/**
+ * UNL_Auth_SimpleCAS
+ *
+ * This is the CAS UserAccount class.
+ * This class takes care of user authentication using CAS and obtains the user
+ * account information via LDAP.
+ *
+ * This class does not handle changes to the user account information. All account
+ * information changes are handled by http://login.unl.edu/
+ * 
+ */
+class UNL_Auth_SimpleCAS extends UNL_Auth
+{
+    /**
+     * Boolean flag to if the user is authenticated or not.
+     * 
+     * @var bool
+     */
+    protected $isAuth = false;
+
+    /**
+     * $uid is the LDAP uid value of the authenticated user.
+     * 
+     * @var string
+     */
+    protected $uid;
+    
+    /**
+     * Options for the CAS server
+     *
+     * @var array
+     */
+    protected $options = array('hostname' => 'login.unl.edu',
+                               'port'     => 443,
+                               'uri'      => 'cas');
+    
+    protected $client;
+    
+    /**
+     * The class constructor used to initialize the SimpleCAS class settings.
+     */
+    private function __construct(array $options = array())
+    {
+        $options = array_merge($this->options, $options);
+        $protocol = new SimpleCAS_Protocol_Version2($this->options);
+        
+        $protocol->getRequest()->setConfig('ssl_verify_peer', false);
+        
+        $this->client = SimpleCAS::client($protocol);
+        if ($this->client->isAuthenticated()) {
+            $this->isAuth = true;
+            $this->uid    = $this->client->getUsername();
+        }
+    }
+    
+    /**
+     * get a singleton instance of this class
+     *
+     * @return UNL_Auth_SimpleCAS
+     */
+    public static function getInstance()
+    {
+        if (null === self::$_instance) {
+            self::$_instance = new self();
+        }
+
+        return self::$_instance;
+    }
+    
+    function isLoggedIn()
+    {
+        return $this->isAuth;
+    }
+    
+    function getUser()
+    {
+        return $this->client->getUsername();
+    }
+    
+    function login()
+    {
+        return $this->client->forceAuthentication();
+    }
+    
+    function logout()
+    {
+        return $this->client->logout();
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/php/UNL/Auth/SimpleCAS/ZendAuth.php b/lib/php/UNL/Auth/SimpleCAS/ZendAuth.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a759b39286f1178b7da0078874314594b9b4b5b
--- /dev/null
+++ b/lib/php/UNL/Auth/SimpleCAS/ZendAuth.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * This is a Zend_Auth adapter library for CAS.
+ * It uses SimpleCAS.
+ *
+ * <code>
+ * public function casAction()
+ * {
+ *     $auth = Zend_Auth::getInstance();
+ *     $authAdapter = UNL_Auth::factory('SimpleCAS', Zend_Registry::get('config')->auth->cas);
+ * 
+ *     # User has not been identified, and there's a ticket in the URL
+ *     if (!$auth->hasIdentity() && isset($_GET['ticket'])) {
+ *         $authAdapter->setTicket($_GET['ticket']);
+ *         $result = $auth->authenticate($authAdapter);
+ * 
+ *         if ($result->isValid()) {
+ *             Zend_Session::regenerateId();
+ *         }
+ *     }
+ * 
+ *     # No ticket or ticket was invalid. Redirect to CAS.
+ *     if (!$auth->hasIdentity()) {
+ *         $this->_redirect($authAdapter->getLoginURL());
+ *     }
+ * }
+ * </code>
+ */
+
+
+/**
+ * @see Zend_Auth_Adapter_Interface
+ */
+require_once 'Zend/Auth/Adapter/Interface.php';
+
+require_once 'UNL/Auth/SimpleCAS.php';
+
+class UNL_Auth_SimpleCAS_ZendAuth implements Zend_Auth_Adapter_Interface
+{
+    /**
+     * CAS client
+     * 
+     * @var UNL_Auth_SimpleCAS
+     */
+    protected $_simplecas;
+
+    /**
+     * Constructor
+     *
+     * @return void
+     */ 
+    public function __construct()
+    {
+        $this->_simplecas = UNL_Auth::factory('SimpleCAS');
+    }
+
+    /**
+     * Authenticates the user
+     *
+     * @return Zend_Auth_Result
+     */ 
+    public function authenticate()
+    {
+        $this->_simplecas->login();
+        if ($this->_simplecas->isLoggedIn()) {
+            return new Zend_Auth_Result(
+                Zend_Auth_Result::SUCCESS,
+                $this->_simplecas->getUser(),
+                array("Authentication successful"));
+        } else {
+            return new Zend_Auth_Result(
+                Zend_Auth_Result::FAILURE,
+                null,
+                array("Authentication failed"));
+        }
+    }
+ 
+}
diff --git a/lib/tests/HTTP_Request2/HTTP/AllTests.php b/lib/tests/HTTP_Request2/HTTP/AllTests.php
new file mode 100644
index 0000000000000000000000000000000000000000..bd3341ff5a6471285a800520340d5017c9087b38
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/AllTests.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: AllTests.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'HTTP_Request2_AllTests::main');
+}
+
+require_once dirname(__FILE__) . '/Request2Test.php';
+require_once dirname(__FILE__) . '/ObserverTest.php';
+require_once dirname(__FILE__) . '/Request2/AllTests.php';
+
+class HTTP_Request2_AllTests
+{
+    public static function main()
+    {
+        if (!function_exists('phpunit_autoload')) {
+            require_once 'PHPUnit/TextUI/TestRunner.php';
+        }
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('HTTP_Request2 package');
+
+        $suite->addTest(Request2_AllTests::suite());
+        $suite->addTestSuite('HTTP_Request2Test');
+        $suite->addTestSuite('HTTP_Request2_ObserverTest');
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'HTTP_Request2_AllTests::main') {
+    HTTP_Request2_AllTests::main();
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/NetworkConfig.php.dist b/lib/tests/HTTP_Request2/HTTP/NetworkConfig.php.dist
new file mode 100644
index 0000000000000000000000000000000000000000..0412ca4629e3040847caee0cbdb3a103cf06e28f
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/NetworkConfig.php.dist
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: NetworkConfig.php.dist 308299 2011-02-12 23:20:23Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * This file contains configuration needed for running HTTP_Request2 tests
+ * that interact with the network. Do not edit this file, copy it to
+ * NetworkConfig.php and edit the copy instead.
+ */
+
+/**
+ * Base URL for HTTP_Request2 Adapters tests
+ *
+ * To enable the tests that actually perform network interaction, you should
+ * copy the contents of _network directory to a directory under your web
+ * server's document root or create a symbolic link to _network directory
+ * there. Set this constant to point to the URL of that directory.
+ */
+define('HTTP_REQUEST2_TESTS_BASE_URL',          null);
+
+/**#@+
+ * Proxy setup for Socket Adapter tests
+ *
+ * Set these constants to run additional tests for Socket Adapter using a HTTP
+ * proxy. If proxy host is not set then the tests will not be run.
+ */
+define('HTTP_REQUEST2_TESTS_PROXY_HOST',        null);
+define('HTTP_REQUEST2_TESTS_PROXY_PORT',        8080);
+define('HTTP_REQUEST2_TESTS_PROXY_USER',        '');
+define('HTTP_REQUEST2_TESTS_PROXY_PASSWORD',    '');
+define('HTTP_REQUEST2_TESTS_PROXY_AUTH_SCHEME', 'basic');
+/**#@-*/
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/ObserverTest.php b/lib/tests/HTTP_Request2/HTTP/ObserverTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..50b22ffd1b2cbc423f03e9e8126a385c571855ac
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/ObserverTest.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: ObserverTest.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Class representing a HTTP request
+ */
+require_once 'HTTP/Request2.php';
+
+/** Helper for PHPUnit includes */
+require_once dirname(__FILE__) . '/TestHelper.php';
+
+/**
+ * Mock observer
+ */
+class HTTP_Request2_MockObserver implements SplObserver
+{
+    public $calls = 0;
+
+    public $event;
+
+    public function update (SplSubject $subject)
+    {
+        $this->calls++;
+        $this->event = $subject->getLastEvent();
+    }
+}
+
+/**
+ * Unit test for subject-observer pattern implementation in HTTP_Request2
+ */
+class HTTP_Request2_ObserverTest extends PHPUnit_Framework_TestCase
+{
+    public function testSetLastEvent()
+    {
+        $request  = new HTTP_Request2();
+        $observer = new HTTP_Request2_MockObserver();
+        $request->attach($observer);
+
+        $request->setLastEvent('foo', 'bar');
+        $this->assertEquals(1, $observer->calls);
+        $this->assertEquals(array('name' => 'foo', 'data' => 'bar'), $observer->event);
+
+        $request->setLastEvent('baz');
+        $this->assertEquals(2, $observer->calls);
+        $this->assertEquals(array('name' => 'baz', 'data' => null), $observer->event);
+    }
+
+    public function testAttachOnlyOnce()
+    {
+        $request   = new HTTP_Request2();
+        $observer  = new HTTP_Request2_MockObserver();
+        $observer2 = new HTTP_Request2_MockObserver();
+        $request->attach($observer);
+        $request->attach($observer2);
+        $request->attach($observer);
+
+        $request->setLastEvent('event', 'data');
+        $this->assertEquals(1, $observer->calls);
+        $this->assertEquals(1, $observer2->calls);
+    }
+
+    public function testDetach()
+    {
+        $request   = new HTTP_Request2();
+        $observer  = new HTTP_Request2_MockObserver();
+        $observer2 = new HTTP_Request2_MockObserver();
+
+        $request->attach($observer);
+        $request->detach($observer2); // should not be a error
+        $request->setLastEvent('first');
+
+        $request->detach($observer);
+        $request->setLastEvent('second');
+        $this->assertEquals(1, $observer->calls);
+        $this->assertEquals(array('name' => 'first', 'data' => null), $observer->event);
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/AllTests.php b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/AllTests.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae6aa96eadc725794d814dd60739732ce387145f
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/AllTests.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: AllTests.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Request2_Adapter_AllTests::main');
+}
+
+require_once dirname(__FILE__) . '/MockTest.php';
+require_once dirname(__FILE__) . '/SkippedTests.php';
+require_once dirname(__FILE__) . '/SocketTest.php';
+require_once dirname(__FILE__) . '/SocketProxyTest.php';
+require_once dirname(__FILE__) . '/CurlTest.php';
+
+class Request2_Adapter_AllTests
+{
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('HTTP_Request2 package - Request2 - Adapter');
+
+        $suite->addTestSuite('HTTP_Request2_Adapter_MockTest');
+        if (defined('HTTP_REQUEST2_TESTS_BASE_URL') && HTTP_REQUEST2_TESTS_BASE_URL) {
+            $suite->addTestSuite('HTTP_Request2_Adapter_SocketTest');
+        } else {
+            $suite->addTestSuite('HTTP_Request2_Adapter_Skip_SocketTest');
+        }
+        if (defined('HTTP_REQUEST2_TESTS_PROXY_HOST') && HTTP_REQUEST2_TESTS_PROXY_HOST
+            && defined('HTTP_REQUEST2_TESTS_BASE_URL') && HTTP_REQUEST2_TESTS_BASE_URL
+        ) {
+            $suite->addTestSuite('HTTP_Request2_Adapter_SocketProxyTest');
+        } else {
+            $suite->addTestSuite('HTTP_Request2_Adapter_Skip_SocketProxyTest');
+        }
+        if (defined('HTTP_REQUEST2_TESTS_BASE_URL') && HTTP_REQUEST2_TESTS_BASE_URL
+            && extension_loaded('curl')
+        ) {
+            $suite->addTestSuite('HTTP_Request2_Adapter_CurlTest');
+        } else {
+            $suite->addTestSuite('HTTP_Request2_Adapter_Skip_CurlTest');
+        }
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Request2_Adapter_AllTests::main') {
+    Request2_Adapter_AllTests::main();
+}
+?>
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/CommonNetworkTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/CommonNetworkTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..976aae358f4fa0e84b1e634585280525ab39b01c
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/CommonNetworkTest.php
@@ -0,0 +1,309 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: CommonNetworkTest.php 309921 2011-04-03 16:43:02Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Class representing a HTTP request */
+require_once 'HTTP/Request2.php';
+
+/** Helper for PHPUnit includes */
+require_once dirname(dirname(dirname(__FILE__))) . '/TestHelper.php';
+
+/**
+ * Tests for HTTP_Request2 package that require a working webserver
+ *
+ * The class contains some common tests that should be run for all Adapters,
+ * it is extended by their unit tests.
+ *
+ * You need to properly set up this test suite, refer to NetworkConfig.php.dist
+ */
+abstract class HTTP_Request2_Adapter_CommonNetworkTest extends PHPUnit_Framework_TestCase
+{
+   /**
+    * HTTP Request object
+    * @var HTTP_Request2
+    */
+    protected $request;
+
+   /**
+    * Base URL for remote test files
+    * @var string
+    */
+    protected $baseUrl;
+
+   /**
+    * Configuration for HTTP Request object
+    * @var array
+    */
+    protected $config = array();
+
+    protected function setUp()
+    {
+        if (!defined('HTTP_REQUEST2_TESTS_BASE_URL') || !HTTP_REQUEST2_TESTS_BASE_URL) {
+            $this->markTestSkipped('Base URL is not configured');
+
+        } else {
+            $this->baseUrl = rtrim(HTTP_REQUEST2_TESTS_BASE_URL, '/') . '/';
+            $name = strtolower(preg_replace('/^test/i', '', $this->getName())) . '.php';
+
+            $this->request = new HTTP_Request2(
+                $this->baseUrl . $name, HTTP_Request2::METHOD_GET, $this->config
+            );
+        }
+    }
+
+   /**
+    * Tests possibility to send GET parameters
+    *
+    * NB: Currently there are problems with Net_URL2::setQueryVariables(), thus
+    * array structure is simple: http://pear.php.net/bugs/bug.php?id=18267
+    */
+    public function testGetParameters()
+    {
+        $data = array(
+            'bar' => array(
+                'key' => 'value'
+            ),
+            'foo' => 'some value',
+            'numbered' => array('first', 'second')
+        );
+
+        $this->request->getUrl()->setQueryVariables($data);
+        $response = $this->request->send();
+        $this->assertEquals($response->getBody(), serialize($data));
+    }
+
+    public function testPostParameters()
+    {
+        $data = array(
+            'bar' => array(
+                'key' => 'some other value'
+            ),
+            'baz' => array(
+                'key1' => array(
+                    'key2' => 'yet another value'
+                )
+            ),
+            'foo' => 'some value',
+            'indexed' => array('first', 'second')
+        );
+
+        $this->request->setMethod(HTTP_Request2::METHOD_POST)
+                      ->addPostParameter($data);
+
+        $response = $this->request->send();
+        $this->assertEquals($response->getBody(), serialize($data));
+    }
+
+    public function testUploads()
+    {
+        $this->request->setMethod(HTTP_Request2::METHOD_POST)
+                      ->addUpload('foo', dirname(dirname(dirname(__FILE__))) . '/_files/empty.gif', 'picture.gif', 'image/gif')
+                      ->addUpload('bar', array(
+                                    array(dirname(dirname(dirname(__FILE__))) . '/_files/empty.gif', null, 'image/gif'),
+                                    array(dirname(dirname(dirname(__FILE__))) . '/_files/plaintext.txt', 'secret.txt', 'text/x-whatever')
+                                  ));
+
+        $response = $this->request->send();
+        $this->assertContains("foo picture.gif image/gif 43", $response->getBody());
+        $this->assertContains("bar[0] empty.gif image/gif 43", $response->getBody());
+        $this->assertContains("bar[1] secret.txt text/x-whatever 15", $response->getBody());
+    }
+
+    public function testRawPostData()
+    {
+        $data = 'Nothing to see here, move along';
+
+        $this->request->setMethod(HTTP_Request2::METHOD_POST)
+                      ->setBody($data);
+        $response = $this->request->send();
+        $this->assertEquals($response->getBody(), $data);
+    }
+
+    public function testCookies()
+    {
+        $cookies = array(
+            'CUSTOMER'    => 'WILE_E_COYOTE',
+            'PART_NUMBER' => 'ROCKET_LAUNCHER_0001'
+        );
+
+        foreach ($cookies as $k => $v) {
+            $this->request->addCookie($k, $v);
+        }
+        $response = $this->request->send();
+        $this->assertEquals($response->getBody(), serialize($cookies));
+    }
+
+    public function testTimeout()
+    {
+        $this->request->setConfig('timeout', 2);
+        try {
+            $this->request->send();
+            $this->fail('Expected HTTP_Request2_Exception was not thrown');
+        } catch (HTTP_Request2_MessageException $e) {
+            $this->assertEquals(HTTP_Request2_Exception::TIMEOUT, $e->getCode());
+        }
+    }
+
+    public function testBasicAuth()
+    {
+        $this->request->getUrl()->setQueryVariables(array(
+            'user' => 'luser',
+            'pass' => 'qwerty'
+        ));
+        $wrong = clone $this->request;
+
+        $this->request->setAuth('luser', 'qwerty');
+        $response = $this->request->send();
+        $this->assertEquals(200, $response->getStatus());
+
+        $wrong->setAuth('luser', 'password');
+        $response = $wrong->send();
+        $this->assertEquals(401, $response->getStatus());
+    }
+
+    public function testDigestAuth()
+    {
+        $this->request->getUrl()->setQueryVariables(array(
+            'user' => 'luser',
+            'pass' => 'qwerty'
+        ));
+        $wrong = clone $this->request;
+
+        $this->request->setAuth('luser', 'qwerty', HTTP_Request2::AUTH_DIGEST);
+        $response = $this->request->send();
+        $this->assertEquals(200, $response->getStatus());
+
+        $wrong->setAuth('luser', 'password', HTTP_Request2::AUTH_DIGEST);
+        $response = $wrong->send();
+        $this->assertEquals(401, $response->getStatus());
+    }
+
+    public function testRedirectsDefault()
+    {
+        $this->request->setUrl($this->baseUrl . 'redirects.php')
+                      ->setConfig(array('follow_redirects' => true, 'strict_redirects' => false))
+                      ->setMethod(HTTP_Request2::METHOD_POST)
+                      ->addPostParameter('foo', 'foo value');
+
+        $response = $this->request->send();
+        $this->assertContains('Method=GET', $response->getBody());
+        $this->assertNotContains('foo', $response->getBody());
+        $this->assertEquals($this->baseUrl . 'redirects.php?redirects=0', $response->getEffectiveUrl());
+    }
+
+    public function testRedirectsStrict()
+    {
+        $this->request->setUrl($this->baseUrl . 'redirects.php')
+                      ->setConfig(array('follow_redirects' => true, 'strict_redirects' => true))
+                      ->setMethod(HTTP_Request2::METHOD_POST)
+                      ->addPostParameter('foo', 'foo value');
+
+        $response = $this->request->send();
+        $this->assertContains('Method=POST', $response->getBody());
+        $this->assertContains('foo', $response->getBody());
+    }
+
+    public function testRedirectsLimit()
+    {
+        $this->request->setUrl($this->baseUrl . 'redirects.php?redirects=4')
+                      ->setConfig(array('follow_redirects' => true, 'max_redirects' => 2));
+
+        try {
+            $this->request->send();
+            $this->fail('Expected HTTP_Request2_Exception was not thrown');
+        } catch (HTTP_Request2_MessageException $e) {
+            $this->assertEquals(HTTP_Request2_Exception::TOO_MANY_REDIRECTS, $e->getCode());
+        }
+    }
+
+    public function testRedirectsRelative()
+    {
+        $this->request->setUrl($this->baseUrl . 'redirects.php?special=relative')
+                      ->setConfig(array('follow_redirects' => true));
+
+        $response = $this->request->send();
+        $this->assertContains('did relative', $response->getBody());
+    }
+
+    public function testRedirectsNonHTTP()
+    {
+        $this->request->setUrl($this->baseUrl . 'redirects.php?special=ftp')
+                      ->setConfig(array('follow_redirects' => true));
+
+        try {
+            $this->request->send();
+            $this->fail('Expected HTTP_Request2_Exception was not thrown');
+        } catch (HTTP_Request2_MessageException $e) {
+            $this->assertEquals(HTTP_Request2_Exception::NON_HTTP_REDIRECT, $e->getCode());
+        }
+    }
+
+    public function testCookieJar()
+    {
+        $this->request->setUrl($this->baseUrl . 'setcookie.php?name=cookie_name&value=cookie_value');
+        $req2 = clone $this->request;
+
+        $this->request->setCookieJar()->send();
+        $jar = $this->request->getCookieJar();
+        $jar->store(
+            array('name' => 'foo', 'value' => 'bar'),
+            $this->request->getUrl()
+        );
+
+        $response = $req2->setUrl($this->baseUrl . 'cookies.php')->setCookieJar($jar)->send();
+        $this->assertEquals(
+            serialize(array('cookie_name' => 'cookie_value', 'foo' => 'bar')),
+            $response->getBody()
+        );
+    }
+
+    public function testCookieJarAndRedirect()
+    {
+        $this->request->setUrl($this->baseUrl . 'redirects.php?special=cookie')
+                      ->setConfig('follow_redirects', true)
+                      ->setCookieJar();
+
+        $response = $this->request->send();
+        $this->assertEquals(serialize(array('cookie_on_redirect' => 'success')), $response->getBody());
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/CurlTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/CurlTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..05fc5080f2999f43eb6fa71ddeb1227fd35090ea
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/CurlTest.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: CurlTest.php 308629 2011-02-24 17:34:24Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Tests for HTTP_Request2 package that require a working webserver */
+require_once dirname(__FILE__) . '/CommonNetworkTest.php';
+
+/** Adapter for HTTP_Request2 wrapping around cURL extension */
+
+/**
+ * Unit test for Curl Adapter of HTTP_Request2
+ */
+class HTTP_Request2_Adapter_CurlTest extends HTTP_Request2_Adapter_CommonNetworkTest
+{
+   /**
+    * Configuration for HTTP Request object
+    * @var array
+    */
+    protected $config = array(
+        'adapter' => 'HTTP_Request2_Adapter_Curl'
+    );
+
+   /**
+    * Checks whether redirect support in cURL is disabled by safe_mode or open_basedir
+    * @return bool
+    */
+    protected function isRedirectSupportDisabled()
+    {
+        return ini_get('safe_mode') || ini_get('open_basedir');
+    }
+
+    public function testRedirectsDefault()
+    {
+        if ($this->isRedirectSupportDisabled()) {
+            $this->markTestSkipped('Redirect support in cURL is disabled by safe_mode or open_basedir setting');
+        } else {
+            parent::testRedirectsDefault();
+        }
+    }
+
+    public function testRedirectsStrict()
+    {
+        if ($this->isRedirectSupportDisabled()) {
+            $this->markTestSkipped('Redirect support in cURL is disabled by safe_mode or open_basedir setting');
+        } else {
+            parent::testRedirectsStrict();
+        }
+    }
+
+    public function testRedirectsLimit()
+    {
+        if ($this->isRedirectSupportDisabled()) {
+            $this->markTestSkipped('Redirect support in cURL is disabled by safe_mode or open_basedir setting');
+        } else {
+            parent::testRedirectsLimit();
+        }
+    }
+
+    public function testRedirectsRelative()
+    {
+        if ($this->isRedirectSupportDisabled()) {
+            $this->markTestSkipped('Redirect support in cURL is disabled by safe_mode or open_basedir setting');
+        } else {
+            parent::testRedirectsRelative();
+        }
+    }
+
+    public function testRedirectsNonHTTP()
+    {
+        if ($this->isRedirectSupportDisabled()) {
+            $this->markTestSkipped('Redirect support in cURL is disabled by safe_mode or open_basedir setting');
+        } else {
+            parent::testRedirectsNonHTTP();
+        }
+    }
+
+    public function testCookieJarAndRedirect()
+    {
+        if ($this->isRedirectSupportDisabled()) {
+            $this->markTestSkipped('Redirect support in cURL is disabled by safe_mode or open_basedir setting');
+        } else {
+            parent::testCookieJarAndRedirect();
+        }
+    }
+
+    public function testBug17450()
+    {
+        if (!$this->isRedirectSupportDisabled()) {
+            $this->markTestSkipped('Neither safe_mode nor open_basedir is enabled');
+        }
+
+        $this->request->setUrl($this->baseUrl . 'redirects.php')
+                      ->setConfig(array('follow_redirects' => true));
+
+        try {
+            $this->request->send();
+            $this->fail('Expected HTTP_Request2_Exception was not thrown');
+
+        } catch (HTTP_Request2_LogicException $e) {
+            $this->assertEquals(HTTP_Request2_Exception::MISCONFIGURATION, $e->getCode());
+        }
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/MockTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/MockTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..06b7a24e262535ab895acfeeb554ae9913debbe0
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/MockTest.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: MockTest.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Class representing a HTTP request
+ */
+require_once 'HTTP/Request2.php';
+
+/**
+ * Mock adapter intended for testing
+ */
+require_once 'HTTP/Request2/Adapter/Mock.php';
+
+/** Helper for PHPUnit includes */
+require_once dirname(dirname(dirname(__FILE__))) . '/TestHelper.php';
+
+/**
+ * Unit test for HTTP_Request2_Response class
+ */
+class HTTP_Request2_Adapter_MockTest extends PHPUnit_Framework_TestCase
+{
+    public function testDefaultResponse()
+    {
+        $req = new HTTP_Request2('http://www.example.com/', HTTP_Request2::METHOD_GET,
+                                 array('adapter' => 'mock'));
+        $response = $req->send();
+        $this->assertEquals(400, $response->getStatus());
+        $this->assertEquals(0, count($response->getHeader()));
+        $this->assertEquals('', $response->getBody());
+    }
+
+    public function testResponseFromString()
+    {
+        $mock = new HTTP_Request2_Adapter_Mock();
+        $mock->addResponse(
+            "HTTP/1.1 200 OK\r\n" .
+            "Content-Type: text/plain; charset=iso-8859-1\r\n" .
+            "\r\n" .
+            "This is a string"
+        );
+        $req = new HTTP_Request2('http://www.example.com/');
+        $req->setAdapter($mock);
+
+        $response = $req->send();
+        $this->assertEquals(200, $response->getStatus());
+        $this->assertEquals(1, count($response->getHeader()));
+        $this->assertEquals('This is a string', $response->getBody());
+    }
+
+    public function testResponseFromFile()
+    {
+        $mock = new HTTP_Request2_Adapter_Mock();
+        $mock->addResponse(fopen(dirname(dirname(dirname(__FILE__))) .
+                           '/_files/response_headers', 'rb'));
+
+        $req = new HTTP_Request2('http://www.example.com/');
+        $req->setAdapter($mock);
+
+        $response = $req->send();
+        $this->assertEquals(200, $response->getStatus());
+        $this->assertEquals(7, count($response->getHeader()));
+        $this->assertEquals('Nothing to see here, move along.', $response->getBody());
+    }
+
+    public function testResponsesQueue()
+    {
+        $mock = new HTTP_Request2_Adapter_Mock();
+        $mock->addResponse(
+            "HTTP/1.1 301 Over there\r\n" .
+            "Location: http://www.example.com/newpage.html\r\n" .
+            "\r\n" .
+            "The document is over there"
+        );
+        $mock->addResponse(
+            "HTTP/1.1 200 OK\r\n" .
+            "Content-Type: text/plain; charset=iso-8859-1\r\n" .
+            "\r\n" .
+            "This is a string"
+        );
+
+        $req = new HTTP_Request2('http://www.example.com/');
+        $req->setAdapter($mock);
+        $this->assertEquals(301, $req->send()->getStatus());
+        $this->assertEquals(200, $req->send()->getStatus());
+        $this->assertEquals(400, $req->send()->getStatus());
+    }
+
+    public function testResponseException()
+    {
+        $mock = new HTTP_Request2_Adapter_Mock();
+        $mock->addResponse(
+            new HTTP_Request2_Exception('Shit happens')
+        );
+        $req = new HTTP_Request2('http://www.example.com/');
+        $req->setAdapter($mock);
+        try {
+            $req->send();
+        } catch (Exception $e) {
+            $this->assertEquals('Shit happens', $e->getMessage());
+            return;
+        }
+        $this->fail('Expected HTTP_Request2_Exception was not thrown');
+    }
+}
+?>
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SkippedTests.php b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SkippedTests.php
new file mode 100644
index 0000000000000000000000000000000000000000..3b2c4945c68fadc72b00fea2393b6813462c7e03
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SkippedTests.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: SkippedTests.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Helper for PHPUnit includes */
+require_once dirname(dirname(dirname(__FILE__))) . '/TestHelper.php';
+
+/**
+ * Shows a skipped test if networked tests are not configured
+ */
+class HTTP_Request2_Adapter_Skip_SocketTest extends PHPUnit_Framework_TestCase
+{
+    public function testSocketAdapter()
+    {
+        $this->markTestSkipped('Socket Adapter tests need base URL configured.');
+    }
+}
+
+/**
+ * Shows a skipped test if proxy is not configured
+ */
+class HTTP_Request2_Adapter_Skip_SocketProxyTest extends PHPUnit_Framework_TestCase
+{
+    public function testSocketAdapterWithProxy()
+    {
+        $this->markTestSkipped('Socket Adapter proxy tests need base URL and proxy configured');
+    }
+}
+
+/**
+ * Shows a skipped test if networked tests are not configured or cURL extension is unavailable
+ */
+class HTTP_Request2_Adapter_Skip_CurlTest extends PHPUnit_Framework_TestCase
+{
+    public function testCurlAdapter()
+    {
+        $this->markTestSkipped('Curl Adapter tests need base URL configured and curl extension available');
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SocketProxyTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SocketProxyTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..14db8630e6fd139fb629ff9956ca77d5e47560b0
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SocketProxyTest.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: SocketProxyTest.php 308299 2011-02-12 23:20:23Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Tests for HTTP_Request2 package that require a working webserver */
+require_once dirname(__FILE__) . '/CommonNetworkTest.php';
+
+/**
+ * Unit test for Socket Adapter of HTTP_Request2 working through proxy
+ */
+class HTTP_Request2_Adapter_SocketProxyTest extends HTTP_Request2_Adapter_CommonNetworkTest
+{
+   /**
+    * Configuration for HTTP Request object
+    * @var array
+    */
+    protected $config = array(
+        'adapter' => 'HTTP_Request2_Adapter_Socket'
+    );
+
+    protected function setUp()
+    {
+        if (!defined('HTTP_REQUEST2_TESTS_PROXY_HOST') || !HTTP_REQUEST2_TESTS_PROXY_HOST) {
+            $this->markTestSkipped('Proxy is not configured');
+
+        } else {
+            $this->config += array(
+                'proxy_host'        => HTTP_REQUEST2_TESTS_PROXY_HOST,
+                'proxy_port'        => HTTP_REQUEST2_TESTS_PROXY_PORT,
+                'proxy_user'        => HTTP_REQUEST2_TESTS_PROXY_USER,
+                'proxy_password'    => HTTP_REQUEST2_TESTS_PROXY_PASSWORD,
+                'proxy_auth_scheme' => HTTP_REQUEST2_TESTS_PROXY_AUTH_SCHEME,
+            );
+            parent::setUp();
+        }
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SocketTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SocketTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..71ca6e62c0fe3d67523394c759ce31286650a668
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/Adapter/SocketTest.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: SocketTest.php 308301 2011-02-13 13:02:20Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Tests for HTTP_Request2 package that require a working webserver */
+require_once dirname(__FILE__) . '/CommonNetworkTest.php';
+
+/** Socket-based adapter for HTTP_Request2 */
+require_once 'HTTP/Request2/Adapter/Socket.php';
+
+/**
+ * Unit test for Socket Adapter of HTTP_Request2
+ */
+class HTTP_Request2_Adapter_SocketTest extends HTTP_Request2_Adapter_CommonNetworkTest
+{
+   /**
+    * Configuration for HTTP Request object
+    * @var array
+    */
+    protected $config = array(
+        'adapter' => 'HTTP_Request2_Adapter_Socket'
+    );
+
+    public function testBug17826()
+    {
+        $adapter = new HTTP_Request2_Adapter_Socket();
+
+        $request1 = new HTTP_Request2($this->baseUrl . 'redirects.php?redirects=2');
+        $request1->setConfig(array('follow_redirects' => true, 'max_redirects' => 3))
+                 ->setAdapter($adapter)
+                 ->send();
+
+        $request2 = new HTTP_Request2($this->baseUrl . 'redirects.php?redirects=2');
+        $request2->setConfig(array('follow_redirects' => true, 'max_redirects' => 3))
+                 ->setAdapter($adapter)
+                 ->send();
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/AllTests.php b/lib/tests/HTTP_Request2/HTTP/Request2/AllTests.php
new file mode 100644
index 0000000000000000000000000000000000000000..0d709074e39160da8cf603cc4db5fa5dd293752b
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/AllTests.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: AllTests.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Request2_AllTests::main');
+}
+
+require_once dirname(__FILE__) . '/CookieJarTest.php';
+require_once dirname(__FILE__) . '/MultipartBodyTest.php';
+require_once dirname(__FILE__) . '/ResponseTest.php';
+require_once dirname(__FILE__) . '/Adapter/AllTests.php';
+
+class Request2_AllTests
+{
+    public static function main()
+    {
+        if (!function_exists('phpunit_autoload')) {
+            require_once 'PHPUnit/TextUI/TestRunner.php';
+        }
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('HTTP_Request2 package - Request2');
+
+        $suite->addTestSuite('HTTP_Request2_CookieJarTest');
+        $suite->addTestSuite('HTTP_Request2_MultipartBodyTest');
+        $suite->addTestSuite('HTTP_Request2_ResponseTest');
+        $suite->addTest(Request2_Adapter_AllTests::suite());
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Request2_AllTests::main') {
+    Request2_AllTests::main();
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/CookieJarTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/CookieJarTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4529c071da2d300d5a1dd25456610b9a921b7601
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/CookieJarTest.php
@@ -0,0 +1,393 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: CookieJarTest.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Stores cookies and passes them between HTTP requests */
+require_once 'HTTP/Request2/CookieJar.php';
+/** Helper for PHPUnit includes */
+require_once dirname(dirname(__FILE__)) . '/TestHelper.php';
+
+/**
+ * Unit test for HTTP_Request2_CookieJar class
+ */
+class HTTP_Request2_CookieJarTest extends PHPUnit_Framework_TestCase
+{
+   /**
+    * Cookie jar instance being tested
+    * @var HTTP_Request2_CookieJar
+    */
+    protected $jar;
+
+    protected function setUp()
+    {
+        $this->jar = new HTTP_Request2_CookieJar();
+    }
+
+   /**
+    * Test that we can't store junk "cookies" in jar
+    *
+    * @dataProvider invalidCookieProvider
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testStoreInvalid($cookie)
+    {
+        $this->jar->store($cookie);
+    }
+
+   /**
+    *
+    * @dataProvider noPSLDomainsProvider
+    */
+    public function testDomainMatchNoPSL($requestHost, $cookieDomain, $expected)
+    {
+        $this->jar->usePublicSuffixList(false);
+        $this->assertEquals($expected, $this->jar->domainMatch($requestHost, $cookieDomain));
+    }
+
+   /**
+    *
+    * @dataProvider PSLDomainsProvider
+    */
+    public function testDomainMatchPSL($requestHost, $cookieDomain, $expected)
+    {
+        $this->jar->usePublicSuffixList(true);
+        $this->assertEquals($expected, $this->jar->domainMatch($requestHost, $cookieDomain));
+    }
+
+    public function testConvertExpiresToISO8601()
+    {
+        $dt = new DateTime();
+        $dt->setTimezone(new DateTimeZone('UTC'));
+        $dt->modify('+1 day');
+
+        $this->jar->store(array(
+            'name'    => 'foo',
+            'value'   => 'bar',
+            'domain'  => '.example.com',
+            'path'    => '/',
+            'expires' => $dt->format(DateTime::COOKIE),
+            'secure'  => false
+        ));
+        $cookies = $this->jar->getAll();
+        $this->assertEquals($cookies[0]['expires'], $dt->format(DateTime::ISO8601));
+    }
+
+    public function testProblem2038()
+    {
+        $this->jar->store(array(
+            'name'    => 'foo',
+            'value'   => 'bar',
+            'domain'  => '.example.com',
+            'path'    => '/',
+            'expires' => 'Sun, 01 Jan 2040 03:04:05 GMT',
+            'secure'  => false
+        ));
+        $cookies = $this->jar->getAll();
+        $this->assertEquals(array(array(
+            'name'    => 'foo',
+            'value'   => 'bar',
+            'domain'  => '.example.com',
+            'path'    => '/',
+            'expires' => '2040-01-01T03:04:05+0000',
+            'secure'  => false
+        )), $cookies);
+    }
+
+    public function testStoreExpired()
+    {
+        $base = array(
+            'name'    => 'foo',
+            'value'   => 'bar',
+            'domain'  => '.example.com',
+            'path'    => '/',
+            'secure'  => false
+        );
+
+        $dt = new DateTime();
+        $dt->setTimezone(new DateTimeZone('UTC'));
+        $dt->modify('-1 day');
+        $yesterday = $dt->format(DateTime::COOKIE);
+
+        $dt->modify('+2 days');
+        $tomorrow = $dt->format(DateTime::COOKIE);
+
+        $this->jar->store($base + array('expires' => $yesterday));
+        $this->assertEquals(0, count($this->jar->getAll()));
+
+        $this->jar->store($base + array('expires' => $tomorrow));
+        $this->assertEquals(1, count($this->jar->getAll()));
+        $this->jar->store($base + array('expires' => $yesterday));
+        $this->assertEquals(0, count($this->jar->getAll()));
+    }
+
+   /**
+    *
+    * @dataProvider cookieAndSetterProvider
+    */
+    public function testGetDomainAndPathFromSetter($cookie, $setter, $expected)
+    {
+        $this->jar->store($cookie, $setter);
+        $expected = array_merge($cookie, $expected);
+        $cookies  = $this->jar->getAll();
+        $this->assertEquals($expected, $cookies[0]);
+    }
+
+   /**
+    *
+    * @dataProvider cookieMatchProvider
+    */
+    public function testGetMatchingCookies($url, $expectedCount)
+    {
+        $cookies = array(
+            array('domain' => '.example.com', 'path' => '/', 'secure' => false),
+            array('domain' => '.example.com', 'path' => '/', 'secure' => true),
+            array('domain' => '.example.com', 'path' => '/path', 'secure' => false),
+            array('domain' => '.example.com', 'path' => '/other', 'secure' => false),
+            array('domain' => 'example.com', 'path' => '/', 'secure' => false),
+            array('domain' => 'www.example.com', 'path' => '/', 'secure' => false),
+            array('domain' => 'specific.example.com', 'path' => '/path', 'secure' => false),
+            array('domain' => 'nowww.example.com', 'path' => '/', 'secure' => false),
+        );
+
+        for ($i = 0; $i < count($cookies); $i++) {
+            $this->jar->store($cookies[$i] + array('expires' => null, 'name' => "cookie{$i}", 'value' => "cookie_{$i}_value"));
+        }
+
+        $this->assertEquals($expectedCount, count($this->jar->getMatching(new Net_URL2($url))));
+    }
+
+    public function testLongestPathFirst()
+    {
+        $cookie = array(
+            'name'    => 'foo',
+            'domain'  => '.example.com',
+        );
+        foreach (array('/', '/specific/path/', '/specific/') as $path) {
+            $this->jar->store($cookie + array('path' => $path, 'value' => str_replace('/', '_', $path)));
+        }
+        $this->assertEquals(
+            'foo=_specific_path_; foo=_specific_; foo=_',
+            $this->jar->getMatching(new Net_URL2('http://example.com/specific/path/file.php'), true)
+        );
+    }
+
+    public function testSerializable()
+    {
+        $dt = new DateTime();
+        $dt->setTimezone(new DateTimeZone('UTC'));
+        $dt->modify('+1 day');
+        $cookie = array('domain' => '.example.com', 'path' => '/', 'secure' => false, 'value' => 'foo');
+
+        $this->jar->store($cookie + array('name' => 'session', 'expires' => null));
+        $this->jar->store($cookie + array('name' => 'long', 'expires' => $dt->format(DateTime::COOKIE)));
+
+        $newJar  = unserialize(serialize($this->jar));
+        $cookies = $newJar->getAll();
+        $this->assertEquals(1, count($cookies));
+        $this->assertEquals('long', $cookies[0]['name']);
+
+        $this->jar->serializeSessionCookies(true);
+        $newJar = unserialize(serialize($this->jar));
+        $this->assertEquals($this->jar->getAll(), $newJar->getAll());
+    }
+
+    public function testRemoveExpiredOnUnserialize()
+    {
+        $dt = new DateTime();
+        $dt->setTimezone(new DateTimeZone('UTC'));
+        $dt->modify('+2 seconds');
+
+        $this->jar->store(array(
+            'name'    => 'foo',
+            'value'   => 'bar',
+            'domain'  => '.example.com',
+            'path'    => '/',
+            'expires' => $dt->format(DateTime::COOKIE),
+        ));
+
+        $serialized = serialize($this->jar);
+        sleep(2);
+        $newJar = unserialize($serialized);
+        $this->assertEquals(array(), $newJar->getAll());
+    }
+
+    public static function invalidCookieProvider()
+    {
+        return array(
+            array(array()),
+            array(array('name' => 'foo')),
+            array(array(
+                'name'    => 'a name',
+                'value'   => 'bar',
+                'domain'  => '.example.com',
+                'path'    => '/',
+            )),
+            array(array(
+                'name'    => 'foo',
+                'value'   => 'a value',
+                'domain'  => '.example.com',
+                'path'    => '/',
+            )),
+            array(array(
+                'name'    => 'foo',
+                'value'   => 'bar',
+                'domain'  => '.example.com',
+                'path'    => null,
+            )),
+            array(array(
+                'name'    => 'foo',
+                'value'   => 'bar',
+                'domain'  => null,
+                'path'    => '/',
+            )),
+            array(array(
+                'name'    => 'foo',
+                'value'   => 'bar',
+                'domain'  => '.example.com',
+                'path'    => '/',
+                'expires' => 'invalid date',
+            )),
+        );
+    }
+
+    public static function noPSLdomainsProvider()
+    {
+        return array(
+            array('localhost', 'localhost', true),
+            array('www.example.com', 'www.example.com', true),
+            array('127.0.0.1', '127.0.0.1', true),
+            array('127.0.0.1', '.0.0.1', false),
+            array('www.example.com', '.example.com', true),
+            array('deep.within.example.com', '.example.com', true),
+            array('example.com', '.com', false),
+            array('anotherexample.com', 'example.com', false),
+            array('whatever.msk.ru', '.msk.ru', true),
+            array('whatever.co.uk', '.co.uk', true),
+            array('whatever.uk', '.whatever.uk', true),
+            array('whatever.tokyo.jp', '.whatever.tokyo.jp', true),
+            array('metro.tokyo.jp', '.metro.tokyo.jp', true),
+            array('foo.bar', '.foo.bar', true)
+        );
+    }
+
+    public static function PSLdomainsProvider()
+    {
+        return array(
+            array('localhost', 'localhost', true),
+            array('www.example.com', 'www.example.com', true),
+            array('127.0.0.1', '127.0.0.1', true),
+            array('127.0.0.1', '.0.0.1', false),
+            array('www.example.com', '.example.com', true),
+            array('deep.within.example.com', '.example.com', true),
+            array('example.com', '.com', false),
+            array('anotherexample.com', 'example.com', false),
+            array('whatever.msk.ru', '.msk.ru', false),
+            array('whatever.co.uk', '.co.uk', false),
+            array('whatever.uk', '.whatever.uk', false),
+            array('whatever.tokyo.jp', '.whatever.tokyo.jp', false),
+            array('metro.tokyo.jp', '.metro.tokyo.jp', true),
+            array('foo.bar', '.foo.bar', true)
+        );
+    }
+
+    public static function cookieAndSetterProvider()
+    {
+        return array(
+            array(
+                array(
+                    'name'    => 'foo',
+                    'value'   => 'bar',
+                    'domain'  => null,
+                    'path'    => null,
+                    'expires' => null,
+                    'secure'  => false
+                ),
+                new Net_Url2('http://example.com/directory/file.php'),
+                array(
+                    'domain'  => 'example.com',
+                    'path'    => '/directory/'
+                )
+            ),
+            array(
+                array(
+                    'name'    => 'foo',
+                    'value'   => 'bar',
+                    'domain'  => '.example.com',
+                    'path'    => null,
+                    'expires' => null,
+                    'secure'  => false
+                ),
+                new Net_Url2('http://example.com/path/to/file.php'),
+                array(
+                    'path'    => '/path/to/'
+                )
+            ),
+            array(
+                array(
+                    'name'    => 'foo',
+                    'value'   => 'bar',
+                    'domain'  => null,
+                    'path'    => '/',
+                    'expires' => null,
+                    'secure'  => false
+                ),
+                new Net_Url2('http://example.com/another/file.php'),
+                array(
+                    'domain'  => 'example.com'
+                )
+            )
+        );
+    }
+
+    public static function cookieMatchProvider()
+    {
+        return array(
+            array('http://www.example.com/path/file.php', 4),
+            array('https://www.example.com/path/file.php', 5),
+            array('http://example.com/path/file.php', 3),
+            array('http://specific.example.com/path/file.php', 4),
+            array('http://specific.example.com/other/file.php', 3),
+            array('http://another.example.com/another', 2)
+        );
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/MultipartBodyTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/MultipartBodyTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..585800fbf54bbdd06f82302033898e5771b90470
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/MultipartBodyTest.php
@@ -0,0 +1,125 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: MultipartBodyTest.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Class representing a HTTP request
+ */
+require_once 'HTTP/Request2.php';
+
+/** Helper for PHPUnit includes */
+require_once dirname(dirname(__FILE__)) . '/TestHelper.php';
+
+/**
+ * Unit test for HTTP_Request2_MultipartBody class
+ */
+class HTTP_Request2_MultipartBodyTest extends PHPUnit_Framework_TestCase
+{
+    public function testUploadSimple()
+    {
+        $req = new HTTP_Request2(null, HTTP_Request2::METHOD_POST);
+        $body = $req->addPostParameter('foo', 'I am a parameter')
+                    ->addUpload('upload', dirname(dirname(__FILE__)) . '/_files/plaintext.txt')
+                    ->getBody();
+
+        $this->assertTrue($body instanceof HTTP_Request2_MultipartBody);
+        $asString = $body->__toString();
+        $boundary = $body->getBoundary();
+        $this->assertEquals($body->getLength(), strlen($asString));
+        $this->assertContains('This is a test.', $asString);
+        $this->assertContains('I am a parameter', $asString);
+        $this->assertRegexp("!--{$boundary}--\r\n$!", $asString);
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testRequest16863()
+    {
+        $req  = new HTTP_Request2(null, HTTP_Request2::METHOD_POST);
+        $fp   = fopen(dirname(dirname(__FILE__)) . '/_files/plaintext.txt', 'rb');
+        $body = $req->addUpload('upload', $fp)
+                    ->getBody();
+
+        $asString = $body->__toString();
+        $this->assertContains('name="upload"; filename="anonymous.blob"', $asString);
+        $this->assertContains('This is a test.', $asString);
+
+        $req->addUpload('bad_upload', fopen('php://input', 'rb'));
+    }
+
+    public function testStreaming()
+    {
+        $req = new HTTP_Request2(null, HTTP_Request2::METHOD_POST);
+        $body = $req->addPostParameter('foo', 'I am a parameter')
+                    ->addUpload('upload', dirname(dirname(__FILE__)) . '/_files/plaintext.txt')
+                    ->getBody();
+        $asString = '';
+        while ($part = $body->read(10)) {
+            $asString .= $part;
+        }
+        $this->assertEquals($body->getLength(), strlen($asString));
+        $this->assertContains('This is a test.', $asString);
+        $this->assertContains('I am a parameter', $asString);
+    }
+
+    public function testUploadArray()
+    {
+        $req = new HTTP_Request2(null, HTTP_Request2::METHOD_POST);
+        $body = $req->addUpload('upload', array(
+                                    array(dirname(dirname(__FILE__)) . '/_files/plaintext.txt', 'bio.txt', 'text/plain'),
+                                    array(fopen(dirname(dirname(__FILE__)) . '/_files/empty.gif', 'rb'), 'photo.gif', 'image/gif')
+                                ))
+                    ->getBody();
+        $asString = $body->__toString();
+        $this->assertContains(file_get_contents(dirname(dirname(__FILE__)) . '/_files/empty.gif'), $asString);
+        $this->assertContains('name="upload[0]"; filename="bio.txt"', $asString);
+        $this->assertContains('name="upload[1]"; filename="photo.gif"', $asString);
+
+        $body2 = $req->setConfig(array('use_brackets' => false))->getBody();
+        $asString = $body2->__toString();
+        $this->assertContains('name="upload"; filename="bio.txt"', $asString);
+        $this->assertContains('name="upload"; filename="photo.gif"', $asString);
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2/ResponseTest.php b/lib/tests/HTTP_Request2/HTTP/Request2/ResponseTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a4898f193d36c6d9d8dd0f99e75d740d0e5193ce
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2/ResponseTest.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: ResponseTest.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Class representing a HTTP response
+ */
+require_once 'HTTP/Request2/Response.php';
+
+/** Helper for PHPUnit includes */
+require_once dirname(dirname(__FILE__)) . '/TestHelper.php';
+
+/**
+ * Unit test for HTTP_Request2_Response class
+ */
+class HTTP_Request2_ResponseTest extends PHPUnit_Framework_TestCase
+{
+   /**
+    *
+    * @expectedException HTTP_Request2_MessageException
+    */
+    public function testParseStatusLine()
+    {
+        $response = new HTTP_Request2_Response('HTTP/1.1 200 OK');
+        $this->assertEquals('1.1', $response->getVersion());
+        $this->assertEquals(200, $response->getStatus());
+        $this->assertEquals('OK', $response->getReasonPhrase());
+
+        $response2 = new HTTP_Request2_Response('HTTP/1.2 222 Nishtyak!');
+        $this->assertEquals('1.2', $response2->getVersion());
+        $this->assertEquals(222, $response2->getStatus());
+        $this->assertEquals('Nishtyak!', $response2->getReasonPhrase());
+
+        $response3 = new HTTP_Request2_Response('Invalid status line');
+    }
+
+    public function testParseHeaders()
+    {
+        $response = $this->readResponseFromFile('response_headers');
+        $this->assertEquals(7, count($response->getHeader()));
+        $this->assertEquals('PHP/6.2.2', $response->getHeader('X-POWERED-BY'));
+        $this->assertEquals('text/html; charset=windows-1251', $response->getHeader('cOnTeNt-TyPe'));
+        $this->assertEquals('accept-charset, user-agent', $response->getHeader('vary'));
+    }
+
+    public function testParseCookies()
+    {
+        $response = $this->readResponseFromFile('response_cookies');
+        $cookies  = $response->getCookies();
+        $this->assertEquals(4, count($cookies));
+        $expected = array(
+            array('name' => 'foo', 'value' => 'bar', 'expires' => null,
+                  'domain' => null, 'path' => null, 'secure' => false),
+            array('name' => 'PHPSESSID', 'value' => '1234567890abcdef1234567890abcdef',
+                  'expires' => null, 'domain' => null, 'path' => '/', 'secure' => true),
+            array('name' => 'A', 'value' => 'B=C', 'expires' => null,
+                  'domain' => null, 'path' => null, 'secure' => false),
+            array('name' => 'baz', 'value' => '%20a%20value', 'expires' => 'Sun, 03 Jan 2010 03:04:05 GMT',
+                  'domain' => 'pear.php.net', 'path' => null, 'secure' => false),
+        );
+        foreach ($cookies as $k => $cookie) {
+            $this->assertEquals($expected[$k], $cookie);
+        }
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_MessageException
+    */
+    public function testGzipEncoding()
+    {
+        $response = $this->readResponseFromFile('response_gzip');
+        $this->assertEquals('0e964e9273c606c46afbd311b5ad4d77', md5($response->getBody()));
+
+        $response = $this->readResponseFromFile('response_gzip_broken');
+        $body = $response->getBody();
+    }
+
+    public function testDeflateEncoding()
+    {
+        $response = $this->readResponseFromFile('response_deflate');
+        $this->assertEquals('0e964e9273c606c46afbd311b5ad4d77', md5($response->getBody()));
+    }
+
+    public function testBug15305()
+    {
+        $response = $this->readResponseFromFile('bug_15305');
+        $this->assertEquals('c8c5088fc8a7652afef380f086c010a6', md5($response->getBody()));
+    }
+
+    public function testBug18169()
+    {
+        $response = $this->readResponseFromFile('bug_18169');
+        $this->assertEquals('', $response->getBody());
+    }
+
+    protected function readResponseFromFile($filename)
+    {
+        $fp       = fopen(dirname(dirname(__FILE__)) . '/_files/' . $filename, 'rb');
+        $response = new HTTP_Request2_Response(fgets($fp));
+        do {
+            $headerLine = fgets($fp);
+            $response->parseHeaderLine($headerLine);
+        } while ('' != trim($headerLine));
+
+        while (!feof($fp)) {
+            $response->appendBody(fread($fp, 1024));
+        }
+        return $response;
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/Request2Test.php b/lib/tests/HTTP_Request2/HTTP/Request2Test.php
new file mode 100644
index 0000000000000000000000000000000000000000..10fc934ff1e774b80aa45b5d86179105244445b7
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/Request2Test.php
@@ -0,0 +1,381 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: Request2Test.php 309665 2011-03-24 21:03:48Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Class representing a HTTP request
+ */
+require_once 'HTTP/Request2.php';
+
+/** Helper for PHPUnit includes */
+require_once dirname(__FILE__) . '/TestHelper.php';
+
+/**
+ * Unit test for HTTP_Request2 class
+ */
+class HTTP_Request2Test extends PHPUnit_Framework_TestCase
+{
+    public function testConstructorSetsDefaults()
+    {
+        $url = new Net_URL2('http://www.example.com/foo');
+        $req = new HTTP_Request2($url, HTTP_Request2::METHOD_POST, array('connect_timeout' => 666));
+
+        $this->assertSame($url, $req->getUrl());
+        $this->assertEquals(HTTP_Request2::METHOD_POST, $req->getMethod());
+        $this->assertEquals(666, $req->getConfig('connect_timeout'));
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testSetUrl()
+    {
+        $urlString = 'http://www.example.com/foo/bar.php';
+        $url       = new Net_URL2($urlString);
+
+        $req1 = new HTTP_Request2();
+        $req1->setUrl($url);
+        $this->assertSame($url, $req1->getUrl());
+
+        $req2 = new HTTP_Request2();
+        $req2->setUrl($urlString);
+        $this->assertType('Net_URL2', $req2->getUrl());
+        $this->assertEquals($urlString, $req2->getUrl()->getUrl());
+
+        $req3 = new HTTP_Request2();
+        $req3->setUrl(array('This will cause an error'));
+    }
+
+    public function testConvertUserinfoToAuth()
+    {
+        $req = new HTTP_Request2();
+        $req->setUrl('http://foo:b%40r@www.example.com/');
+
+        $this->assertEquals('', (string)$req->getUrl()->getUserinfo());
+        $this->assertEquals(
+            array('user' => 'foo', 'password' => 'b@r', 'scheme' => HTTP_Request2::AUTH_BASIC),
+            $req->getAuth()
+        );
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testSetMethod()
+    {
+        $req = new HTTP_Request2();
+        $req->setMethod(HTTP_Request2::METHOD_PUT);
+        $this->assertEquals(HTTP_Request2::METHOD_PUT, $req->getMethod());
+
+        $req->setMethod('Invalid method');
+    }
+
+    public function testSetAndGetConfig()
+    {
+        $req = new HTTP_Request2();
+        $this->assertArrayHasKey('connect_timeout', $req->getConfig());
+
+        $req->setConfig(array('connect_timeout' => 123));
+        $this->assertEquals(123, $req->getConfig('connect_timeout'));
+        try {
+            $req->setConfig(array('foo' => 'unknown parameter'));
+            $this->fail('Expected HTTP_Request2_LogicException was not thrown');
+        } catch (HTTP_Request2_LogicException $e) {}
+
+        try {
+            $req->getConfig('bar');
+            $this->fail('Expected HTTP_Request2_LogicException was not thrown');
+        } catch (HTTP_Request2_LogicException $e) {}
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testHeaders()
+    {
+        $req = new HTTP_Request2();
+        $autoHeaders = $req->getHeaders();
+
+        $req->setHeader('Foo', 'Bar');
+        $req->setHeader('Foo-Bar: value');
+        $req->setHeader(array('Another-Header' => 'another value', 'Yet-Another: other_value'));
+        $this->assertEquals(
+            array('foo-bar' => 'value', 'another-header' => 'another value',
+            'yet-another' => 'other_value', 'foo' => 'Bar') + $autoHeaders,
+            $req->getHeaders()
+        );
+
+        $req->setHeader('FOO-BAR');
+        $req->setHeader(array('aNOTHER-hEADER'));
+        $this->assertEquals(
+            array('yet-another' => 'other_value', 'foo' => 'Bar') + $autoHeaders,
+            $req->getHeaders()
+        );
+
+        $req->setHeader('Invalid header', 'value');
+    }
+
+    public function testBug15937()
+    {
+        $req = new HTTP_Request2();
+        $autoHeaders = $req->getHeaders();
+
+        $req->setHeader('Expect: ');
+        $req->setHeader('Foo', '');
+        $this->assertEquals(
+            array('expect' => '', 'foo' => '') + $autoHeaders,
+            $req->getHeaders()
+        );
+    }
+
+    public function testRequest17507()
+    {
+        $req = new HTTP_Request2();
+
+        $req->setHeader('accept-charset', 'iso-8859-1');
+        $req->setHeader('accept-charset', array('windows-1251', 'utf-8'), false);
+
+        $req->setHeader(array('accept' => 'text/html'));
+        $req->setHeader(array('accept' => 'image/gif'), null, false);
+
+        $headers = $req->getHeaders();
+
+        $this->assertEquals('iso-8859-1, windows-1251, utf-8', $headers['accept-charset']);
+        $this->assertEquals('text/html, image/gif', $headers['accept']);
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testCookies()
+    {
+        $req = new HTTP_Request2();
+        $req->addCookie('name', 'value');
+        $req->addCookie('foo', 'bar');
+        $headers = $req->getHeaders();
+        $this->assertEquals('name=value; foo=bar', $headers['cookie']);
+
+        $req->addCookie('invalid cookie', 'value');
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testPlainBody()
+    {
+        $req = new HTTP_Request2();
+        $req->setBody('A string');
+        $this->assertEquals('A string', $req->getBody());
+
+        $req->setBody(dirname(__FILE__) . '/_files/plaintext.txt', true);
+        $headers = $req->getHeaders();
+        $this->assertRegexp(
+            '!^(text/plain|application/octet-stream)!',
+            $headers['content-type']
+        );
+        $this->assertEquals('This is a test.', fread($req->getBody(), 1024));
+
+        $req->setBody('missing file', true);
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testRequest16863()
+    {
+        $req = new HTTP_Request2();
+        $req->setBody(fopen(dirname(__FILE__) . '/_files/plaintext.txt', 'rb'));
+        $headers = $req->getHeaders();
+        $this->assertEquals('application/octet-stream', $headers['content-type']);
+
+        $req->setBody(fopen('php://input', 'rb'));
+    }
+
+    public function testUrlencodedBody()
+    {
+        $req = new HTTP_Request2(null, HTTP_Request2::METHOD_POST);
+        $req->addPostParameter('foo', 'bar');
+        $req->addPostParameter(array('baz' => 'quux'));
+        $req->addPostParameter('foobar', array('one', 'two'));
+        $this->assertEquals(
+            'foo=bar&baz=quux&foobar%5B0%5D=one&foobar%5B1%5D=two',
+            $req->getBody()
+        );
+
+        $req->setConfig(array('use_brackets' => false));
+        $this->assertEquals(
+            'foo=bar&baz=quux&foobar=one&foobar=two',
+            $req->getBody()
+        );
+    }
+
+    public function testRequest15368()
+    {
+        $req = new HTTP_Request2(null, HTTP_Request2::METHOD_POST);
+        $req->addPostParameter('foo', 'te~st');
+        $this->assertContains('~', $req->getBody());
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testUpload()
+    {
+        $req = new HTTP_Request2(null, HTTP_Request2::METHOD_POST);
+        $req->addUpload('upload', dirname(__FILE__) . '/_files/plaintext.txt');
+
+        $headers = $req->getHeaders();
+        $this->assertEquals('multipart/form-data', $headers['content-type']);
+
+        $req->addUpload('upload_2', 'missing file');
+    }
+
+    public function testPropagateUseBracketsToNetURL2()
+    {
+        $req = new HTTP_Request2('http://www.example.com/', HTTP_Request2::METHOD_GET,
+                                 array('use_brackets' => false));
+        $req->getUrl()->setQueryVariable('foo', array('bar', 'baz'));
+        $this->assertEquals('http://www.example.com/?foo=bar&foo=baz', $req->getUrl()->__toString());
+
+        $req->setConfig('use_brackets', true)->setUrl('http://php.example.com/');
+        $req->getUrl()->setQueryVariable('foo', array('bar', 'baz'));
+        $this->assertEquals('http://php.example.com/?foo[0]=bar&foo[1]=baz', $req->getUrl()->__toString());
+    }
+
+    public function testSetBodyRemovesPostParameters()
+    {
+        $req = new HTTP_Request2('http://www.example.com/', HTTP_Request2::METHOD_POST);
+        $req->addPostParameter('foo', 'bar');
+        $req->setBody('');
+        $this->assertEquals('', $req->getBody());
+    }
+
+    public function testPostParametersPrecedeSetBodyForPost()
+    {
+        $req = new HTTP_Request2('http://www.example.com/', HTTP_Request2::METHOD_POST);
+        $req->setBody('Request body');
+        $req->addPostParameter('foo', 'bar');
+
+        $this->assertEquals('foo=bar', $req->getBody());
+
+        $req->setMethod(HTTP_Request2::METHOD_PUT);
+        $this->assertEquals('Request body', $req->getBody());
+    }
+
+    public function testSetMultipartBody()
+    {
+        require_once 'HTTP/Request2/MultipartBody.php';
+
+        $req = new HTTP_Request2('http://www.example.com/', HTTP_Request2::METHOD_POST);
+        $body = new HTTP_Request2_MultipartBody(array('foo' => 'bar'), array());
+        $req->setBody($body);
+        $this->assertSame($body, $req->getBody());
+    }
+
+    public function testBug17460()
+    {
+        $req = new HTTP_Request2('http://www.example.com/', HTTP_Request2::METHOD_POST);
+        $req->addPostParameter('foo', 'bar')
+            ->setHeader('content-type', 'application/x-www-form-urlencoded; charset=UTF-8');
+
+        $this->assertEquals('foo=bar', $req->getBody());
+    }
+
+   /**
+    *
+    * @expectedException HTTP_Request2_LogicException
+    */
+    public function testCookieJar()
+    {
+        $req = new HTTP_Request2();
+        $this->assertNull($req->getCookieJar());
+
+        $req->setCookieJar();
+        $jar = $req->getCookieJar();
+        $this->assertType('HTTP_Request2_CookieJar', $jar);
+
+        $req2 = new HTTP_Request2();
+        $req2->setCookieJar($jar);
+        $this->assertSame($jar, $req2->getCookieJar());
+
+        $req2->setCookieJar(null);
+        $this->assertNull($req2->getCookieJar());
+
+        $req2->setCookieJar('foo');
+    }
+
+    public function testAddCookieToJar()
+    {
+        $req = new HTTP_Request2();
+        $req->setCookieJar();
+
+        try {
+            $req->addCookie('foo', 'bar');
+            $this->fail('Expected HTTP_Request2_Exception was not thrown');
+        } catch (HTTP_Request2_LogicException $e) { }
+
+        $req->setUrl('http://example.com/path/file.php');
+        $req->addCookie('foo', 'bar');
+
+        $this->assertArrayNotHasKey('cookie', $req->getHeaders());
+        $cookies = $req->getCookieJar()->getAll();
+        $this->assertEquals(
+            array(
+                'name'    => 'foo',
+                'value'   => 'bar',
+                'domain'  => 'example.com',
+                'path'    => '/path/',
+                'expires' => null,
+                'secure'  => false
+            ),
+            $cookies[0]
+        );
+    }
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/TestHelper.php b/lib/tests/HTTP_Request2/HTTP/TestHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..bbd2bf635fe0800bef8a1250c5896ad5be42be98
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/TestHelper.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Unit tests for HTTP_Request2 package
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: TestHelper.php 309682 2011-03-25 09:53:38Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/** Include PHPUnit dependencies based on version */
+require_once 'PHPUnit/Runner/Version.php';
+
+$phpunitVersion = PHPUnit_Runner_Version::id();
+if ($phpunitVersion == '@' . 'package_version@' || !version_compare($phpunitVersion, '3.6', '<=')) {
+    echo "This version of PHPUnit is not supported.";
+    exit(1);
+} elseif (version_compare($phpunitVersion, '3.5.0', '>=')) {
+    require_once 'PHPUnit/Autoload.php';
+} else {
+    require_once 'PHPUnit/Framework.php';
+}
+
+if (!defined('HTTP_REQUEST2_TESTS_BASE_URL')
+    && is_readable(dirname(__FILE__) . '/NetworkConfig.php')
+) {
+    require_once dirname(__FILE__) . '/NetworkConfig.php';
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/bug_15305 b/lib/tests/HTTP_Request2/HTTP/_files/bug_15305
new file mode 100644
index 0000000000000000000000000000000000000000..bbf6c70006b8062fd656063ee9cbbff16edf7f04
Binary files /dev/null and b/lib/tests/HTTP_Request2/HTTP/_files/bug_15305 differ
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/bug_18169 b/lib/tests/HTTP_Request2/HTTP/_files/bug_18169
new file mode 100644
index 0000000000000000000000000000000000000000..c50dae1472683f231d16dd5f70a713425cc259fa
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_files/bug_18169
@@ -0,0 +1,9 @@
+HTTP/1.1 200 OK
+Date: Fri, 01 Jan 2010 02:03:04 GMT
+Server: Apache/3.0.1 (Unix)
+X-Powered-By: PHP/6.2.2
+Content-Type: text/plain; charset=iso-8859-1
+Content-Encoding: deflate
+Content-Length: 0
+Connection: close
+
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/empty.gif b/lib/tests/HTTP_Request2/HTTP/_files/empty.gif
new file mode 100644
index 0000000000000000000000000000000000000000..1d11fa9ada9e93505b3d736acb204083f45d5fbf
Binary files /dev/null and b/lib/tests/HTTP_Request2/HTTP/_files/empty.gif differ
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/plaintext.txt b/lib/tests/HTTP_Request2/HTTP/_files/plaintext.txt
new file mode 100644
index 0000000000000000000000000000000000000000..273c1a9ffdc201dbca7d19b275bf1cbc88aaa4cb
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_files/plaintext.txt
@@ -0,0 +1 @@
+This is a test.
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/response_cookies b/lib/tests/HTTP_Request2/HTTP/_files/response_cookies
new file mode 100644
index 0000000000000000000000000000000000000000..8f0ab6b64d490cd12b0adc653e03211a44822b4b
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_files/response_cookies
@@ -0,0 +1,13 @@
+HTTP/1.1 200 OK
+Date: Fri, 01 Jan 2010 02:03:04 GMT
+Server: Apache/3.0.1 (Unix)
+X-Powered-By: PHP/6.2.2
+Set-Cookie: foo=bar
+Set-Cookie: PHPSESSID=1234567890abcdef1234567890abcdef; path=/; secure
+Set-Cookie: A=B=C
+Set-Cookie: baz=%20a%20value; expires=Sun, 03 Jan 2010 03:04:05 GMT; domain=pear.php.net
+Content-Type: text/html; charset=windows-1251
+Content-Length: 32
+Connection: close
+
+Nothing to see here, move along.
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/response_deflate b/lib/tests/HTTP_Request2/HTTP/_files/response_deflate
new file mode 100644
index 0000000000000000000000000000000000000000..e4e8adfd0d46af40addef96b0e95dad6243e6232
Binary files /dev/null and b/lib/tests/HTTP_Request2/HTTP/_files/response_deflate differ
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/response_gzip b/lib/tests/HTTP_Request2/HTTP/_files/response_gzip
new file mode 100644
index 0000000000000000000000000000000000000000..79ad3b6eaac6737c9ae4a577347cb52e26ea5209
Binary files /dev/null and b/lib/tests/HTTP_Request2/HTTP/_files/response_gzip differ
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/response_gzip_broken b/lib/tests/HTTP_Request2/HTTP/_files/response_gzip_broken
new file mode 100644
index 0000000000000000000000000000000000000000..0df0d1522f8a377ac905b20db95eb29dc1428493
Binary files /dev/null and b/lib/tests/HTTP_Request2/HTTP/_files/response_gzip_broken differ
diff --git a/lib/tests/HTTP_Request2/HTTP/_files/response_headers b/lib/tests/HTTP_Request2/HTTP/_files/response_headers
new file mode 100644
index 0000000000000000000000000000000000000000..f60787bd566db41bc4680d2e6a93aba607e3a34f
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_files/response_headers
@@ -0,0 +1,12 @@
+HTTP/1.1 200 OK
+Date: Fri, 01 Jan 2010 02:03:04 GMT
+Vary: accept-charset
+Server: Apache/3.0.1 (Unix)
+X-Powered-By:                PHP/6.2.2
+Vary: user-agent
+Content-Type: text/html;
+    charset=windows-1251
+Content-Length: 32
+Connection: close
+
+Nothing to see here, move along.
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/basicauth.php b/lib/tests/HTTP_Request2/HTTP/_network/basicauth.php
new file mode 100644
index 0000000000000000000000000000000000000000..383a78525068dcd3879dac61fb13087274191987
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/basicauth.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: basicauth.php 308300 2011-02-13 12:24:18Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+$user       = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : null;
+$pass       = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : null;
+$wantedUser = isset($_GET['user']) ? $_GET['user'] : null;
+$wantedPass = isset($_GET['pass']) ? $_GET['pass'] : null;
+
+if (!$user || !$pass || $user != $wantedUser || $pass != $wantedPass) {
+    header('WWW-Authenticate: Basic realm="HTTP_Request2 tests"', true, 401);
+    echo "Login required";
+} else {
+    echo "Username={$user};Password={$pass}";
+}
+
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/cookies.php b/lib/tests/HTTP_Request2/HTTP/_network/cookies.php
new file mode 100644
index 0000000000000000000000000000000000000000..5ab966c5b5856ccc832f6e7fadc31f9342976e09
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/cookies.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: cookies.php 308299 2011-02-12 23:20:23Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+ksort($_COOKIE);
+echo serialize($_COOKIE);
+
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/digestauth.php b/lib/tests/HTTP_Request2/HTTP/_network/digestauth.php
new file mode 100644
index 0000000000000000000000000000000000000000..463f25a42f8a670ffc610363af3fa1614bd2bb14
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/digestauth.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: digestauth.php 308300 2011-02-13 12:24:18Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+/**
+ * Mostly borrowed from PHP manual and Socket Adapter implementation
+ *
+ * @link http://php.net/manual/en/features.http-auth.php
+ */
+
+/**
+ * Parses the Digest auth header
+ *
+ * @param string $txt
+ */
+function http_digest_parse($txt)
+{
+    $token  = '[^\x00-\x1f\x7f-\xff()<>@,;:\\\\"/\[\]?={}\s]+';
+    $quoted = '"(?:\\\\.|[^\\\\"])*"';
+
+    // protect against missing data
+    $needed_parts = array_flip(array('nonce', 'nc', 'cnonce', 'qop', 'username', 'uri', 'response'));
+    $data         = array();
+
+    preg_match_all("!({$token})\\s*=\\s*({$token}|{$quoted})!", $txt, $matches);
+    for ($i = 0; $i < count($matches[0]); $i++) {
+        // ignore unneeded parameters
+        if (isset($needed_parts[$matches[1][$i]])) {
+            unset($needed_parts[$matches[1][$i]]);
+            if ('"' == substr($matches[2][$i], 0, 1)) {
+                $data[$matches[1][$i]] = substr($matches[2][$i], 1, -1);
+            } else {
+                $data[$matches[1][$i]] = $matches[2][$i];
+            }
+        }
+    }
+
+    return !empty($needed_parts) ? false : $data;
+}
+
+$realm      = 'HTTP_Request2 tests';
+$wantedUser = isset($_GET['user']) ? $_GET['user'] : null;
+$wantedPass = isset($_GET['pass']) ? $_GET['pass'] : null;
+$validAuth  = false;
+
+if (!empty($_SERVER['PHP_AUTH_DIGEST'])
+    && ($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']))
+    && $wantedUser == $data['username']
+) {
+    // generate the valid response
+    $a1       = md5($data['username'] . ':' . $realm . ':' . $wantedPass);
+    $a2       = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']);
+    $response = md5($a1. ':' . $data['nonce'] . ':' . $data['nc'] . ':'
+                    . $data['cnonce'] . ':' . $data['qop'] . ':' . $a2);
+
+    // check valid response against existing one
+    $validAuth = ($data['response'] == $response);
+}
+
+if (!$validAuth || empty($_SERVER['PHP_AUTH_DIGEST'])) {
+    header('WWW-Authenticate: Digest realm="' . $realm .
+           '",qop="auth",nonce="' . uniqid() . '"', true, 401);
+    echo "Login required";
+} else {
+    echo "Username={$user}";
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/getparameters.php b/lib/tests/HTTP_Request2/HTTP/_network/getparameters.php
new file mode 100644
index 0000000000000000000000000000000000000000..334a132e57deb6c1dae224cbccd18d57d6ba0e2a
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/getparameters.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: getparameters.php 308299 2011-02-12 23:20:23Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+ksort($_GET);
+echo serialize($_GET);
+
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/postparameters.php b/lib/tests/HTTP_Request2/HTTP/_network/postparameters.php
new file mode 100644
index 0000000000000000000000000000000000000000..7037d889854669cf724a7df6d65850979f52b5d4
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/postparameters.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: postparameters.php 308300 2011-02-13 12:24:18Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+ksort($_POST);
+echo serialize($_POST);
+
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/rawpostdata.php b/lib/tests/HTTP_Request2/HTTP/_network/rawpostdata.php
new file mode 100644
index 0000000000000000000000000000000000000000..e6a1d26b4fa8cddad1b6cc5053bd056f8b760c78
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/rawpostdata.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: rawpostdata.php 308300 2011-02-13 12:24:18Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+readfile('php://input');
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/redirects.php b/lib/tests/HTTP_Request2/HTTP/_network/redirects.php
new file mode 100644
index 0000000000000000000000000000000000000000..f7a7f815e68514c68c6eca438dfb963a0cab30bf
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/redirects.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: redirects.php 308480 2011-02-19 11:27:13Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+$redirects = isset($_GET['redirects'])? $_GET['redirects']: 1;
+$https     = !empty($_SERVER['HTTPS']) && ('off' != strtolower($_SERVER['HTTPS']));
+$special   = isset($_GET['special'])? $_GET['special']: null;
+
+if ('ftp' == $special) {
+    header('Location: ftp://localhost/pub/exploit.exe', true, 301);
+
+} elseif ('relative' == $special) {
+    header('Location: ./getparameters.php?msg=did%20relative%20redirect', true, 302);
+
+} elseif ('cookie' == $special) {
+    setcookie('cookie_on_redirect', 'success');
+    header('Location: ./cookies.php', true, 302);
+
+} elseif ($redirects > 0) {
+    $url = ($https? 'https': 'http') . '://' . $_SERVER['SERVER_NAME']
+           . (($https && 443 == $_SERVER['SERVER_PORT'] || !$https && 80 == $_SERVER['SERVER_PORT'])
+              ? '' : ':' . $_SERVER['SERVER_PORT'])
+           . $_SERVER['PHP_SELF'] . '?redirects=' . (--$redirects);
+    header('Location: ' . $url, true, 302);
+
+} else {
+    echo "Method=" . $_SERVER['REQUEST_METHOD'] . ';';
+    var_dump($_POST);
+    var_dump($_GET);
+}
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/setcookie.php b/lib/tests/HTTP_Request2/HTTP/_network/setcookie.php
new file mode 100644
index 0000000000000000000000000000000000000000..bece10339869839d4811ad0a0f997653f46bd608
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/setcookie.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: setcookie.php 308480 2011-02-19 11:27:13Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+$name  = empty($_GET['name'])? 'foo': $_GET['name'];
+$value = empty($_GET['value'])? 'bar': $_GET['value'];
+
+setcookie($name, $value);
+
+echo "Cookie set!";
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/timeout.php b/lib/tests/HTTP_Request2/HTTP/_network/timeout.php
new file mode 100644
index 0000000000000000000000000000000000000000..f99d871d006e02a263807521405b8b7757a13cbf
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/timeout.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: timeout.php 308299 2011-02-12 23:20:23Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+sleep(5);
+
+?>
\ No newline at end of file
diff --git a/lib/tests/HTTP_Request2/HTTP/_network/uploads.php b/lib/tests/HTTP_Request2/HTTP/_network/uploads.php
new file mode 100644
index 0000000000000000000000000000000000000000..7a124de73a1b9acc94c26f85a2babdfe6afca540
--- /dev/null
+++ b/lib/tests/HTTP_Request2/HTTP/_network/uploads.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Helper files for HTTP_Request2 unit tests. Should be accessible via HTTP.
+ *
+ * PHP version 5
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>
+ * 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.
+ *    * The names of the authors may not 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 OWNER OR
+ * 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.
+ *
+ * @category   HTTP
+ * @package    HTTP_Request2
+ * @author     Alexey Borzov <avb@php.net>
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version    SVN: $Id: uploads.php 308300 2011-02-13 12:24:18Z avb $
+ * @link       http://pear.php.net/package/HTTP_Request2
+ */
+
+if (!empty($_FILES)) {
+    foreach ($_FILES as $name => $file) {
+        if (is_array($file['name'])) {
+            foreach($file['name'] as $k => $v) {
+                echo "{$name}[{$k}] {$v} {$file['type'][$k]} {$file['size'][$k]}\n";
+            }
+        } else {
+            echo "{$name} {$file['name']} {$file['type']} {$file['size']}\n";
+        }
+    }
+}
+?>
\ No newline at end of file