Merge commit '70fb0c8' into httplib2_v0.11.3 Inital commit of httplib2 v0.11.3 with history am: bcaab4fb9e
am: 290292844f

Change-Id: I8a97fd8c63c5c17eed92d1b7dc2e3c3a5c35180e
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0a800f2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,42 @@
+*.py[cod]
+venv*/
+
+# C extensions
+*.so
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+lib
+lib64
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+nosetests.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# Mercurial
+.hg
+
+# httplib2
+.cache
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..259a27f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,86 @@
+sudo: false
+language: python
+
+cache:
+  apt: true
+  ccache: true
+  pip: true
+  directories:
+    - $HOME/.cache
+
+env:
+  global:
+    - pip_install_common='pip>=9.0 setuptools>=36.2 wheel>=0.30'
+python:
+  - 2.7
+  - 3.3
+  - 3.4
+  - 3.5
+  - 3.6
+  - pypy
+matrix:
+  fast_finish: true
+install: pip install $pip_install_common 'codecov>=2.0.15' -r requirements-test.txt
+script: script/test -sv && codecov
+
+stages:
+  - test
+  - release
+jobs:
+  include:
+    - stage: test
+      env: _=py2-pep8
+      python: 2.7
+      install: pip install -r requirements-test.txt
+      script: test_group=pep8 script/test
+    - stage: test
+      env: _=py3-pep8
+      python: 3.6
+      install: pip install -r requirements-test.txt
+      script: test_group=pep8 script/test
+    - stage: test
+      env: _=py2-package
+      python: 2.7
+      install: pip install $pip_install_common
+      script: test_group=package script/test
+    - stage: test
+      env: _=py3-package
+      python: 3.6
+      install: pip install $pip_install_common
+      script: test_group=package script/test
+    - stage: release
+      if: (branch = master)
+      env: _=pypi-upload-test
+      python: 3.6
+      install: pip install $pip_install_common
+      script: script/release -auto
+      deploy:
+        provider: pypi
+        server: https://test.pypi.org/legacy/
+        user: httplib2.release.test
+        password:
+          secure: "XN3oxobC+26UPiS+F1MvL4c6XtytejZ13SkLXCHfgVDPSASzKqF81CnR4EhsnbfZLvSgGHgSlfY5Jve5HF2VR9GzpJMc6wzcfkkeBg6PeRHuMppIqmuoq7BTw81SZL9X62/mju/vxXs2cHpVkwNTSE7W1JH1bVXPj86oAR9xXo9waRuXcyPGNuSqmOd1NPOMbFmeuz+HeArk2Fz7wwo6H5BJuXjOrEOHWD1rzeRchH901PBUrftm54Id2TIVMARW8jm1saQY2FtPWaBv2v/DJC1fKWMJpcNQ3mmcvrrTFC1IJ00dk9XJfqx5hnsRaergc0UvzHoOGEQKSMdg0PUAkvNohAoCf+3GddPkvk8MaZ+aQlijoK6wp93A5dfTxBVZqdhmEdheolbYiJPunzS60bWvaEv6/D15/xyMiwGamUmF1Tx7UIvvm/zj6tAOBWbNEgLRyvQ0qx2RE95GLtp+RXK4pT+Kig1+cof5hrWODuEl1SSLMBySaNLWO73IN9esZu0X1JS7svnROLRJCAvRjppJYswwCPziP+B8XQDeMrhIDMHNzdbtxOPpBAXpYUE764FkzaUTMsK83Q+ugE3Dx8xtrAzT4M0fdiFv+3QEhSUtfvWsLH9zS9wXC5Px9kPKU3FO8mdUyf7A0bIasvJLNcApDJigKjBukToOIsZVFok="
+        # TODO: sdist bdist_wheel
+        # but wheels don't roll well with our 2/3 split code base
+        distributions: "sdist"
+        skip_cleanup: true
+        on:
+          repo: httplib2/httplib2
+    - stage: release
+      if: (tag IS present)
+      env: _=pypi-upload-public
+      python: 3.6
+      install: pip install $pip_install_common
+      script: script/release -auto
+      deploy:
+        provider: pypi
+        user: httplib2.release
+        password:
+          secure: "jZAyMFnmbhYChjsb3gRYfESWlio6pgmWEWBRxtBQXYZf+tzyKVISyHuyWkJvOVTP+lOpp2MTPZ2s1UgxGwfzZ/VE034Cz5iA/C6wafmgtSW+wK+KEJFPseHBBA7Gh4ReiAPi2a+i1UXdsJpFNhv36E9tbTq2sEinbisE2lSEQ0KHadjkc+6pvCjlyhmes7QyM5GviWYlWRNj2OIkT8SUuUcWQt7ZEl6kN82MoMHCaf1YxE/i4JUP3VLomWK3RLZJP356Y4IDkzlVhFU4MJ4ubNtoQ/ECM0uQ+nsHzO0k1uGWdF6mMTna7U5gLqUi9rfCK3bLMeVSo+TUCpjI7HkWDaBgVXGTe5dUMJCDfRgqeYa0GnriI74XYJu8NGjMLv30uO58t9E7VQGo2NrFRJDzKAIHANejWnpUPY3XgoN1rlrh52seMjaU2+jO40EC8HvIqeRRwPwhkqCSV2y+IZT2bOFp2nbMWhkUMsxIX7OXt+sy8GvK/ilMleEl7r0tnudsT7lGdnMwXlttI3CIAFGE7E+0zwnxNiMzQDzo+ILVR7ezrCK9M9xVYKGa3i8gkpSn0Fblnltgg7HaEI8YC3rMZe4iu1t0D6cZZUAAp2ZUo3NCJcZ35iUFBhlFvjVDbe2upJgU6GFgtDLjyzCJiKbz8qLRgMFYgT0CGr512e1jBo0="
+        # TODO: sdist bdist_wheel
+        # but wheels don't roll well with our 2/3 split code base
+        distributions: "sdist"
+        skip_cleanup: true
+        on:
+          repo: httplib2/httplib2
+          tags: true
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..05d69ac
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,50 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+filegroup {
+    // "cacerts.txt" are identical save for the fact that py3 cacerts.txt has
+    // a newline at the end while py2 cacerts.txt doesn't.
+    name: "cacert_data",
+    srcs: ["python3/httplib2/cacerts.txt"],
+    path: "python3/httplib2",
+}
+
+filegroup {
+    name: "py2_httplib2_srcs",
+    srcs: ["python2/httplib2/*.py"],
+    path: "python2/httplib2",
+}
+
+filegroup {
+    name: "py3_httplib2_srcs",
+    srcs: ["python3/httplib2/*.py"],
+    path: "python3/httplib2",
+}
+
+python_library {
+    name: "py-httplib2",
+    host_supported: true,
+    data: [":cacert_data"],
+    pkg_path: "httplib2",
+    version: {
+          py2: {
+              enabled: true,
+              srcs: [":py2_httplib2_srcs"],
+          },
+          py3: {
+              enabled: true,
+              srcs: [":py3_httplib2_srcs"],
+          },
+    },
+}
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..c04f914
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,316 @@
+0.11.3
+
+  No changes, just reupload of 0.11.2 after fixing automatic release conditions in Travis.
+
+0.11.2
+
+  proxy: py3 NameError basestring
+  https://github.com/httplib2/httplib2/pull/100
+
+0.11.1
+
+  Fix HTTP(S)ConnectionWithTimeout AttributeError proxy_info
+  https://github.com/httplib2/httplib2/pull/97
+
+0.11.0
+
+  Add DigiCert Global Root G2 serial 033af1e6a711a9a0bb2864b11d09fae5
+  https://github.com/httplib2/httplib2/pull/91
+
+  python3 proxy support
+  https://github.com/httplib2/httplib2/pull/90
+
+  If no_proxy environment value ends with comma then proxy is not used
+  https://github.com/httplib2/httplib2/issues/11
+
+  fix UnicodeDecodeError using socks5 proxy
+  https://github.com/httplib2/httplib2/pull/64
+
+  Respect NO_PROXY env var in proxy_info_from_url
+  https://github.com/httplib2/httplib2/pull/58
+
+  NO_PROXY=bar was matching foobar (suffix without dot delimiter)
+  New behavior matches curl/wget:
+  - no_proxy=foo.bar will only skip proxy for exact hostname match
+  - no_proxy=.wild.card will skip proxy for any.subdomains.wild.card
+  https://github.com/httplib2/httplib2/issues/94
+
+  Bugfix for Content-Encoding: deflate
+  https://stackoverflow.com/a/22311297
+
+0.10.3
+
+  Fix certificate validation on Python<=2.7.8 without ssl.CertificateError
+  https://github.com/httplib2/httplib2/issues/45
+
+0.10.2
+
+  Just a reupload of 0.10.1, which was broken for Python3
+  because wheel distribution doesn't play well with our 2/3 split code base.
+  https://github.com/httplib2/httplib2/issues/43
+
+0.10.1
+
+  This is the first release by new httplib2 team. See post by Joe
+  https://bitworking.org/news/2016/03/an_update_on_httplib2
+
+  Remove VeriSign Class 3 CA from trusted certs
+  https://googleonlinesecurity.blogspot.com/2015/12/proactive-measures-in-digital.html
+
+  Add IdenTrust DST Root CA X3
+  https://github.com/httplib2/httplib2/pull/26
+
+  Support for specifying the SSL protocol version (Python v2)
+  https://github.com/jcgregorio/httplib2/issues/329
+
+  On App Engine use urlfetch's default deadline if None is passed.
+
+  Fix TypeError on AppEngine “__init__() got an unexpected keyword argument 'ssl_version’”
+  https://github.com/httplib2/httplib2/pull/12
+
+  Send SNI data for SSL connections on Python 2.7.9+
+  Verify the server hostname if certificate validation is enabled
+  https://github.com/httplib2/httplib2/pull/13
+
+  Add proxy_headers argument to ProxyInfo constructor
+  https://github.com/httplib2/httplib2/pull/21
+
+  Make disable_ssl_certificate_validation work with Python 3.5.
+  https://github.com/httplib2/httplib2/pull/15
+
+  Fix socket error handling
+  https://github.com/httplib2/httplib2/commit/eb7468561714a5b700d5a3d8fa1a8794de02b9ef
+  https://github.com/httplib2/httplib2/commit/e7f6e622047107e701ee70e7ec586717d97b0cbb
+
+0.9.2
+
+  Fixes in this release:
+
+   https://github.com/jcgregorio/httplib2/pull/313
+
+    Fix incorrect ResponseNotReady exceptions, retry on transient errors.
+
+0.9.1
+
+  Fixes in this release:
+
+    https://github.com/jcgregorio/httplib2/pull/296
+
+        There was a problem with headers when a binary string is passed (like
+        b'Authorization').
+
+    https://github.com/jcgregorio/httplib2/pull/276
+
+        Default to doing DNS resolution through a proxy server if present.
+
+0.9
+  Heartbleed
+
+0.8
+  More fixes for the App Engine support.
+
+  Added a new feature that allows you to supply your own provider for the
+  CA_CERTS file. Just create a module named ca_certs_locater that has a method
+  get() that returns the file location of the CA_CERTS file.
+
+  Lots of clean up of the code formatting to make it more consistent.
+
+0.7.7
+   More fixes for App Engine, now less likely to swallow important exceptions.
+   Adding proxy_info_from_* methods to Python3. Reviewed in https://codereview.appspot.com/6588078/.
+   Added GeoTrust cert
+   Make httplib2.Http() instances pickleable. Reviewed in https://codereview.appspot.com/6506074/
+
+   The following issues have been fixed:
+
+   229 python3 httplib2 clobbers multiple headers of same key
+   230 Expose meaningful exception for App Engine URLFetch ResponseTooLargeError
+   231 Expose App Engine URLFetch DeadlineExceededError for debugging purposes
+
+0.7.6
+   Fixes for App Engine 2.7.
+
+0.7.5
+   Keys are lowercase in a Response object, regardless of how Response object is constructed.
+   Add control so that Authorization: headers aren't forwarded on a 3xx response by default.
+   Set the reason correctly when running on App Engine. Patch from Alain Vongsouvanh. Reviewed in http://codereview.appspot.com/6422051/
+   Fix proxy socks for SSL connections. Fixes issue #199.
+   You can now set httplib2.RETRIES to the number of retries before a request
+     is considered to fail It is set to a default of 2 to mimic the traditional
+     behavior of httplib2.
+
+   The following issues have been addressed:
+
+     223 HEAD requests fail calling the close() method of ResponseDict instance.
+     222 Can't disable cert validation in appengine
+     204 Credentials can leak in HTTP redirects
+     210 Different API between Python 2 and Python 3 version breaks wsgi_intercept
+     214 ValueError on malformated cache entries
+     204 Credentials can leak in HTTP redirects
+
+
+0.7.3
+    ProxyInfo objects now can construct themselves from environment
+    variables commonly-used in Unix environments. By default, the Http
+    class will construct a ProxyInfo instance based on these environment
+    variables. To achieve the previous behavior, where environment
+    variables are ignored, pass proxy_info=None to Http().
+
+    The following issues have been addressed:
+
+    Issue 159: automatic detection of proxy configuration.
+    Issue 179: Allow unicode in proxy hostname.
+    Issue 194: Added support for setuptools.
+    Fixes for HTTP CONNECT proxies.
+
+0.7.1
+    Fix failure to install cacerts.txt for 2.x installs.
+
+0.7.0
+    The two major changes in this release are SSL Certificate
+    checking and App Engine support. By default the certificates
+    of an HTTPS connection are checked, but that can be disabled
+    via disable_ssl_certificate_validation. The second change
+    is that on App Engine there is a new connection object
+    that utilizes the urlfetch capabilities on App Engine, including
+    setting timeouts and validating certificates.
+
+    The following issues have been addressed:
+
+    Fixes issue 72. Always lowercase authorization header.
+    Fix issue 47. Redirects that become a GET should not have a body.
+    Fixes issue 19. Set Content-location on redirected HEAD requests
+    Fixes issue 139. Redirect with a GET on 302 regardless of the originating method.
+    Fixes issue 138. Handle unicode in headers when writing and retrieving cache entries. Who says headers have to be ASCII!
+    Add certificate validation. Work initially started by Christoph Kern.
+    Set a version number. Fixes issue # 135.
+    Sync to latest version of socks.py
+    Add gzip to the user-agent, in case we are making a request to an app engine project: http://code.google.com/appengine/kb/general.html#compression
+    Uses a custom httplib shim on App Engine to wrap urlfetch, as opposed
+    Add default support for optimistic concurrency on PATCH requests
+    Fixes issue 126. IPv6 under various conditions would fail.
+    Fixes issue 131. Handle socket.timeout's that occur during send.
+    proxy support: degrade gracefully when socket.socket is unavailable
+
+
+0.6.0
+
+   The following issues have been addressed:
+
+    #51 - Failure to handle server legitimately closing connection before request body is fully sent
+    #77 - Duplicated caching test
+    #65 - Transform _normalize_headers into a method of Http class
+    #45 - Vary header
+    #73 - All files in Mercurial are executable
+    #81 - Have a useful .hgignore
+    #78 - Add release tags to the Mercurial repository
+    #67 - HEAD requests cause next request to be retried
+
+   Mostly bug fixes, the big enhancement is the addition of proper Vary: header
+   handling. Thanks to Chris Dent for that change.
+
+   The other big change is the build process for distributions so that both python2 and python3
+   are included in the same .tar.gz/.zip file.
+
+0.5.0
+
+   Added Python 3 support
+
+   Fixed the following bugs:
+
+      #12 - Cache-Control: only-if-cached incorrectly does request if item not in cache
+      #39 - Deprecation warnings in Python 2.6
+      #54 - Http.request fails accessing Google account via http proxy
+      #56 - Block on response.read() for HEAD requests.
+      #57 - Timeout ignore for Python 2.6
+      #58 - Fixed parsing of Cache-Control: header to make it more robust
+
+  Also fixed a deprecation warning that appeared between Python 3.0 and 3.1.
+
+0.4.0
+
+   Added support for proxies if the Socksipy module is installed.
+
+   Fixed bug with some HEAD responses having content-length set to
+   zero incorrectly.
+
+   Fixed most except's to catch a specific exception.
+
+   Added 'connection_type' parameter to Http.request().
+
+   The default for 'force_exception_to_status_code' was changed to False. Defaulting
+   to True was causing quite a bit of confusion.
+
+
+0.3.0
+   Calling Http.request() with a relative URI, as opposed to an absolute URI,
+   will now throw a specific exception.
+
+   Http() now has an additional optional parameter for the socket timeout.
+
+   Exceptions can now be forced into responses. That is, instead of
+   throwing an exception, a good httlib2.Response object is returned
+   that describe the error with an appropriate status code.
+
+   Many improvements to the file cache:
+
+     1.  The names in the cache are now much less
+         opaque, which should help with debugging.
+
+     2.  The disk cache is now Apache mod_asis compatible.
+
+     3.  A Content-Location: header is supplied and stored in the
+         cache which points to the original requested URI.
+
+   User supplied If-* headers now override httplib2 supplied
+   versions.
+
+   IRIs are now fully supported. Note that they MUST be passed in
+   as unicode objects.
+
+   Http.add_credentials() now takes an optional domain to restrict
+   the credentials to being only used on that domain.
+
+   Added Http.add_certificate() which allows setting
+   a key and cert for SSL connections.
+
+   Many other bugs fixed.
+
+
+0.2.0
+   Added support for Google Auth.
+
+   Added experimental support for HMACDigest.
+
+   Added support for a pluggable caching system. Now supports
+   the old system of using the file system and now memcached.
+
+   Added httplib2.debuglevel which turns on debugging.
+
+   Change Response._previous to Response.previous.
+
+   Added Http.follow_all_redirects which forces
+   httplib2 to follow all redirects, as opposed to
+   following only the safe redirects. This makes the
+   GData protocol easier to use.
+
+   All known bugs fixed to date.
+
+0.1.1
+
+    Fixed several bugs raised by James Antill:
+    1. HEAD didn't get an Accept: header added like GET.
+    2. HEAD requests did not use the cache.
+    3. GET requests with Range: headers would erroneously return a full cached response.
+    4. Subsequent requests to resources that had timed out would raise an exception.
+    And one feature request for 'method' to default to GET.
+
+    Xavier Verges Farrero supplied what I needed to make the
+    library work with Python 2.3.
+
+    I added distutils based setup.py.
+
+0.1 Rev 86
+
+    Initial Release
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ae38286
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+Httplib2 Software License
+
+Copyright (c) 2006 by Joe Gregorio
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..b8bb4a9
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+recursive-include python2 *.py *.txt
+recursive-include python3 *.py *.txt
+include python2/httplib2/test/*.txt
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..57f8ac2
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,17 @@
+name: "httplib2"
+description:
+    "httplib2 is a comprehensive HTTP client library, httplib2.py supports "
+    "many features left out of other HTTP libraries."
+
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://github.com/httplib2/httplib2"
+  }
+  url {
+    type: GIT
+    value: "https://github.com/httplib2/httplib2/"
+  }
+  version: "0.11.3"
+  last_upgrade_date { year: 2018 month: 6 day: 4 }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ed8c013
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,42 @@
+tests:
+	-cd python2 && python2.4 httplib2test.py
+	-cd python2 && python2.5 httplib2test.py
+	-cd python2 && python2.6 httplib2test.py
+	-cd python2 && python2.6 httplib2test_appengine.py
+	cd python2 && python2.7 httplib2test.py
+	cd python2 && python2.7 httplib2test_appengine.py
+	cd python3 && python3.2 httplib2test.py
+
+VERSION = $(shell python setup.py --version)
+INLINE_VERSION = $(shell cd python2; python -c "import httplib2;print httplib2.__version__")
+INLINE_VERSION_3 = $(shell cd python3; ~/bin/python3.2 -c "import httplib2;print(httplib2.__version__)")
+DST = dist/httplib2-$(VERSION)
+
+release:
+	echo $(INLINE_VERSION_3)
+	echo $(INLINE_VERSION)
+	# Check for version number mismatch
+	if [ $(VERSION) -ne $(INLINE_VERSION_3) ]; then exit 1; fi
+	if [ $(VERSION) -ne $(INLINE_VERSION) ]; then exit 1; fi
+
+	-find . -name "*.pyc" | xargs rm 
+	-find . -name "*.orig" | xargs rm 
+	-rm -rf python2/.cache
+	-rm -rf python3/.cache
+	-mkdir dist
+	-rm -rf dist/httplib2-$(VERSION)
+	-rm dist/httplib2-$(VERSION).tar.gz
+	-rm dist/httplib2-$(VERSION).zip
+	-mkdir dist/httplib2-$(VERSION)
+	cp -r python2 $(DST) 
+	cp -r python3 $(DST) 
+	cp setup.py README.md MANIFEST.in CHANGELOG $(DST)
+	cd dist && tar -czv -f httplib2-$(VERSION).tar.gz httplib2-$(VERSION) 
+	cd dist && zip httplib2-$(VERSION).zip -r httplib2-$(VERSION)
+	cd dist/httplib2-$(VERSION) && python setup.py sdist --formats=gztar,zip upload
+	wget "http://support.googlecode.com/svn/trunk/scripts/googlecode_upload.py" -O googlecode_upload.py
+	python googlecode_upload.py --summary="Version $(shell python setup.py --version)" --project=httplib2 dist/*.tar.gz
+	python googlecode_upload.py --summary="Version $(shell python setup.py --version)" --project=httplib2 dist/*.zip
+
+docs:
+	pudge -v -f --modules=httplib2 --dest=build/doc 
diff --git a/NOTICE b/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..329c4a4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,113 @@
+Introduction
+============
+
+httplib2 is a comprehensive HTTP client library, httplib2.py supports many
+features left out of other HTTP libraries.
+
+### HTTP and HTTPS
+
+HTTPS support is only available if the socket module was
+compiled with SSL support.
+    
+### Keep-Alive
+
+Supports HTTP 1.1 Keep-Alive, keeping the socket open and
+performing multiple requests over the same connection if
+possible.
+    
+### Authentication
+
+The following three types of HTTP Authentication are
+supported. These can be used over both HTTP and HTTPS.
+
+* Digest
+* Basic
+* WSSE
+
+### Caching
+
+The module can optionally operate with a private cache that
+understands the Cache-Control: header and uses both the ETag
+and Last-Modified cache validators.
+    
+### All Methods
+
+The module can handle any HTTP request method, not just GET
+and POST.
+    
+### Redirects
+
+Automatically follows 3XX redirects on GETs.
+    
+### Compression
+
+Handles both 'deflate' and 'gzip' types of compression.
+    
+### Lost update support
+
+Automatically adds back ETags into PUT requests to resources
+we have already cached. This implements Section 3.2 of
+Detecting the Lost Update Problem Using Unreserved Checkout.
+    
+### Unit Tested
+
+A large and growing set of unit tests.
+
+
+Installation
+============
+
+
+    $ pip install httplib2
+
+
+Usage
+=====
+
+A simple retrieval:
+
+```python
+import httplib2
+h = httplib2.Http(".cache")
+(resp_headers, content) = h.request("http://example.org/", "GET")
+```
+
+The 'content' is the content retrieved from the URL. The content
+is already decompressed or unzipped if necessary.
+
+To PUT some content to a server that uses SSL and Basic authentication:
+
+```python
+import httplib2
+h = httplib2.Http(".cache")
+h.add_credentials('name', 'password')
+(resp, content) = h.request("https://example.org/chapter/2",
+                            "PUT", body="This is text",
+                            headers={'content-type':'text/plain'} )
+```
+
+Use the Cache-Control: header to control how the caching operates.
+
+```python
+import httplib2
+h = httplib2.Http(".cache")
+(resp, content) = h.request("http://bitworking.org/", "GET")
+...
+(resp, content) = h.request("http://bitworking.org/", "GET",
+                            headers={'cache-control':'no-cache'})
+```
+
+The first request will be cached and since this is a request
+to bitworking.org it will be set to be cached for two hours,
+because that is how I have my server configured. Any subsequent
+GET to that URI will return the value from the on-disk cache
+and no request will be made to the server. You can use the
+Cache-Control: header to change the caches behavior and in
+this example the second request adds the Cache-Control:
+header with a value of 'no-cache' which tells the library
+that the cached copy must not be used when handling this request.
+
+More example usage can be found at:
+
+ * https://github.com/httplib2/httplib2/wiki/Examples
+ * https://github.com/httplib2/httplib2/wiki/Examples-Python3
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100755
index 0000000..8ffdea8
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,68 @@
+# Makefile for Sphinx documentation

+#

+

+# You can set these variables from the command line.

+SPHINXOPTS    =

+SPHINXBUILD   = sphinx-build

+PAPER         =

+

+# Internal variables.

+PAPEROPT_a4     = -D latex_paper_size=a4

+PAPEROPT_letter = -D latex_paper_size=letter

+ALLSPHINXOPTS   = -d .build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .

+

+.PHONY: help clean html web htmlhelp latex changes linkcheck

+

+help:

+	@echo "Please use \`make <target>' where <target> is one of"

+	@echo "  html      to make standalone HTML files"

+	@echo "  web       to make files usable by Sphinx.web"

+	@echo "  htmlhelp  to make HTML files and a HTML help project"

+	@echo "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"

+	@echo "  changes   to make an overview over all changed/added/deprecated items"

+	@echo "  linkcheck to check all external links for integrity"

+

+clean:

+	-rm -rf .build/*

+

+html:

+	mkdir -p ./html .build/doctrees

+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) ./html

+	@echo

+	@echo "Build finished. The HTML pages are in ./html."

+

+web:

+	mkdir -p .build/web .build/doctrees

+	$(SPHINXBUILD) -b web $(ALLSPHINXOPTS) .build/web

+	@echo

+	@echo "Build finished; now you can run"

+	@echo "  python -m sphinx.web .build/web"

+	@echo "to start the server."

+

+htmlhelp:

+	mkdir -p .build/htmlhelp .build/doctrees

+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) .build/htmlhelp

+	@echo

+	@echo "Build finished; now you can run HTML Help Workshop with the" \

+	      ".hhp project file in .build/htmlhelp."

+

+latex:

+	mkdir -p .build/latex .build/doctrees

+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) .build/latex

+	@echo

+	@echo "Build finished; the LaTeX files are in .build/latex."

+	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \

+	      "run these through (pdf)latex."

+

+changes:

+	mkdir -p .build/changes .build/doctrees

+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) .build/changes

+	@echo

+	@echo "The overview file is in .build/changes."

+

+linkcheck:

+	mkdir -p .build/linkcheck .build/doctrees

+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) .build/linkcheck

+	@echo

+	@echo "Link check complete; look for any errors in the above output " \

+	      "or in .build/linkcheck/output.txt."

diff --git a/doc/conf.py b/doc/conf.py
new file mode 100755
index 0000000..b5622b4
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,132 @@
+# -*- coding: utf-8 -*-

+#

+# httplib2 documentation build configuration file, created by

+# sphinx-quickstart on Thu Mar 27 16:07:14 2008.

+#

+# This file is execfile()d with the current directory set to its containing dir.

+#

+# The contents of this file are pickled, so don't put values in the namespace

+# that aren't pickleable (module imports are okay, they're removed automatically).

+#

+# All configuration values have a default value; values that are commented out

+# serve to show the default value.

+

+import sys

+

+# If your extensions are in another directory, add it here.

+#sys.path.append('some/directory')

+

+# General configuration

+# ---------------------

+

+# Add any Sphinx extension module names here, as strings. They can be extensions

+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.

+#extensions = []

+

+# Add any paths that contain templates here, relative to this directory.

+templates_path = ['.templates']

+

+# The suffix of source filenames.

+source_suffix = '.rst'

+

+# The master toctree document.

+master_doc = 'index'

+

+# General substitutions.

+project = 'httplib2'

+copyright = '2008, Joe Gregorio'

+

+# The default replacements for |version| and |release|, also used in various

+# other places throughout the built documents.

+#

+# The short X.Y version.

+version = '0.4'

+# The full version, including alpha/beta/rc tags.

+release = '0.4'

+

+# There are two options for replacing |today|: either, you set today to some

+# non-false value, then it is used:

+#today = ''

+# Else, today_fmt is used as the format for a strftime call.

+today_fmt = '%B %d, %Y'

+

+# List of documents that shouldn't be included in the build.

+#unused_docs = []

+

+# If true, '()' will be appended to :func: etc. cross-reference text.

+#add_function_parentheses = True

+

+# If true, the current module name will be prepended to all description

+# unit titles (such as .. function::).

+#add_module_names = True

+

+# If true, sectionauthor and moduleauthor directives will be shown in the

+# output. They are ignored by default.

+#show_authors = False

+

+# The name of the Pygments (syntax highlighting) style to use.

+pygments_style = 'sphinx'

+

+

+# Options for HTML output

+# -----------------------

+

+# The style sheet to use for HTML and HTML Help pages. A file of that name

+# must exist either in Sphinx' static/ path, or in one of the custom paths

+# given in html_static_path.

+html_style = 'default.css'

+

+# Add any paths that contain custom static files (such as style sheets) here,

+# relative to this directory. They are copied after the builtin static files,

+# so a file named "default.css" will overwrite the builtin "default.css".

+html_static_path = ['.static']

+

+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,

+# using the given strftime format.

+html_last_updated_fmt = '%b %d, %Y'

+

+# If true, SmartyPants will be used to convert quotes and dashes to

+# typographically correct entities.

+#html_use_smartypants = True

+

+# Content template for the index page.

+#html_index = ''

+

+# Custom sidebar templates, maps document names to template names.

+#html_sidebars = {}

+

+# Additional templates that should be rendered to pages, maps page names to

+# template names.

+#html_additional_pages = {}

+

+# If false, no module index is generated.

+#html_use_modindex = True

+

+# If true, the reST sources are included in the HTML build as _sources/<name>.

+#html_copy_source = True

+

+# Output file base name for HTML help builder.

+htmlhelp_basename = 'httplib2doc'

+

+

+# Options for LaTeX output

+# ------------------------

+

+# The paper size ('letter' or 'a4').

+#latex_paper_size = 'letter'

+

+# The font size ('10pt', '11pt' or '12pt').

+#latex_font_size = '10pt'

+

+# Grouping the document tree into LaTeX files. List of tuples

+# (source start file, target name, title, author, document class [howto/manual]).

+#latex_documents = []

+

+# Additional stuff for the LaTeX preamble.

+#latex_preamble = ''

+

+# Documents to append as an appendix to all manuals.

+#latex_appendices = []

+

+# If false, no module index is generated.

+#latex_use_modindex = True

diff --git a/doc/html/_sources/index.txt b/doc/html/_sources/index.txt
new file mode 100755
index 0000000..c435cab
--- /dev/null
+++ b/doc/html/_sources/index.txt
@@ -0,0 +1,35 @@
+.. httplib2 documentation master file, created by sphinx-quickstart on Thu Mar 27 16:07:14 2008.

+   You can adapt this file completely to your liking, but it should at least

+   contain the root `toctree` directive.

+

+************************

+  The httplib2 Library  

+************************

+

+:Author: Joe Gregorio

+

+:Date: Mar 8, 2007

+

+.. |release| replace:: 0.4

+

+

+.. topic:: Abstract

+

+   The :mod:`httplib2` module is a comprehensive HTTP client library that handles

+   caching, keep-alive, compression, redirects and many kinds of authentication.

+

+

+Contents:

+

+.. toctree::

+   :maxdepth: 2

+

+   libhttplib2.rst

+

+Indices and tables

+==================

+

+* :ref:`genindex`

+* :ref:`modindex`

+* :ref:`search`

+

diff --git a/doc/html/_sources/libhttplib2.txt b/doc/html/_sources/libhttplib2.txt
new file mode 100644
index 0000000..7666fb5
--- /dev/null
+++ b/doc/html/_sources/libhttplib2.txt
@@ -0,0 +1,483 @@
+.. % Template for a library manual section.
+.. % PLEASE REMOVE THE COMMENTS AFTER USING THE TEMPLATE
+.. %
+.. % Complete documentation on the extended LaTeX markup used for Python
+.. % documentation is available in ``Documenting Python'', which is part
+.. % of the standard documentation for Python.  It may be found online
+.. % at:
+.. %
+.. % http://www.python.org/doc/current/doc/doc.html
+.. % ==== 0. ====
+.. % Copy this file to <mydir>/lib<mymodule>.tex, and edit that file
+.. % according to the instructions below.
+
+.. % ==== 1. ====
+.. % The section prologue.  Give the section a title and provide some
+.. % meta-information.  References to the module should use
+.. % \refbimodindex, \refstmodindex, \refexmodindex or \refmodindex, as
+.. % appropriate.
+
+
+:mod:`httplib2`  A comprehensive HTTP client library.
+=====================================================
+
+.. module:: httplib2
+.. moduleauthor:: Joe Gregorio <joe@bitworking.org>
+.. sectionauthor:: Joe Gregorio <joe@bitworking.org>
+
+
+.. % Choose one of these to specify the module module name.  If there's
+.. % an underscore in the name, use
+.. % \declaremodule[modname]{...}{mod_name} instead.
+.. %
+.. % not standard, in Python
+.. % Portability statement:  Uncomment and fill in the parameter to specify the
+.. % availability of the module.  The parameter can be Unix, IRIX, SunOS, Mac,
+.. % Windows, or lots of other stuff.  When ``Mac'' is specified, the availability
+.. % statement will say ``Macintosh'' and the Module Index may say ``Mac''.
+.. % Please use a name that has already been used whenever applicable.  If this
+.. % is omitted, no availability statement is produced or implied.
+.. %
+.. % \platform{Unix}
+.. % These apply to all modules, and may be given more than once:
+.. % Author of the module code;
+.. % omit if not known.
+.. % Author of the documentation,
+.. % even if not a module section.
+
+
+
+.. % Leave at least one blank line after this, to simplify ad-hoc tools
+.. % that are sometimes used to massage these files.
+
+The :mod:`httplib2` module is a comprehensive HTTP client library with the
+following features:
+
+.. % ==== 2. ====
+.. % Give a short overview of what the module does.
+.. % If it is platform specific, mention this.
+.. % Mention other important restrictions or general operating principles.
+.. % For example:
+
+.. describe:: HTTP and HTTPS
+
+   HTTPS support is only available if the socket module was compiled with SSL
+   support.
+
+.. describe:: Keep-Alive
+
+   Supports HTTP 1.1 Keep-Alive, keeping the socket open and performing multiple
+   requests over the same connection if possible.
+
+.. describe:: Authentication
+
+   The following three types of HTTP Authentication are supported. These can be
+   used over both HTTP and HTTPS.
+
+      * Digest
+      * Basic
+      * WSSE
+
+.. describe:: Caching
+
+   The module can optionally operate with a private cache that understands the
+   Cache-Control: header and uses both the ETag and Last-Modified cache validators.
+
+.. describe:: All Methods
+
+   The module can handle any HTTP request method, not just GET and POST.
+
+.. describe:: Redirects
+
+   Automatically follows 3XX redirects on GETs.
+
+.. describe:: Compression
+
+   Handles both ``deflate`` and ``gzip`` types of compression.
+
+.. describe:: Lost update support
+
+   Automatically adds back ETags into PUT requests to resources we have already
+   cached. This implements Section 3.2 of Detecting the Lost Update Problem Using
+   Unreserved Checkout
+
+The :mod:`httplib2` module defines the following variables:
+
+.. % ==== 3. ====
+.. % List the public functions defined by the module.  Begin with a
+.. % standard phrase.  You may also list the exceptions and other data
+.. % items defined in the module, insofar as they are important for the
+.. % user.
+.. % ---- 3.2. ----
+.. % Data items are described using a ``datadesc'' block.  This has only
+.. % one parameter: the item's name.
+
+
+.. data:: debuglevel
+
+   The amount of debugging information to print. The default is 0.
+
+
+.. data:: RETRIES
+
+   A request will be tried 'RETRIES' times if it fails at the socket/connection level.
+   The default is 2.
+
+The :mod:`httplib2` module may raise the following Exceptions. Note that  there
+is an option that turns exceptions into  normal responses with an HTTP status
+code indicating an error occured. See
+:attr:`Http.force_exception_to_status_code`
+
+.. % --- 3.3. ---
+.. % Exceptions are described using a ``excdesc'' block.  This has only
+.. % one parameter: the exception name.  Exceptions defined as classes in
+.. % the source code should be documented using this environment, but
+.. % constructor parameters must be omitted.
+
+
+.. exception:: HttpLib2Error
+
+   The Base Exception for all exceptions raised by httplib2.
+
+
+.. exception:: RedirectMissingLocation
+
+   A 3xx redirect response code was provided but no Location: header  was provided
+   to point to the new location.
+
+
+.. exception:: RedirectLimit
+
+   The maximum number of redirections was reached without coming to a final URI.
+
+
+.. exception:: ServerNotFoundError
+
+   Unable to resolve the host name given.
+
+
+.. exception:: RelativeURIError
+
+   A relative, as opposed to an absolute URI, was passed into request().
+
+
+.. exception:: FailedToDecompressContent
+
+   The headers claimed that the content of the response was compressed but the
+   decompression algorithm applied to the content failed.
+
+
+.. exception:: UnimplementedDigestAuthOptionError
+
+   The server requested a type of Digest authentication that we are unfamiliar
+   with.
+
+
+.. exception:: UnimplementedHmacDigestAuthOptionError
+
+   The server requested a type of HMACDigest authentication that we are unfamiliar
+   with.
+
+.. % ---- 3.4. ----
+.. % Other standard environments:
+.. %
+.. % classdesc  - Python classes; same arguments are funcdesc
+.. % methoddesc - methods, like funcdesc but has an optional parameter
+.. % to give the type name: \begin{methoddesc}[mytype]{name}{args}
+.. % By default, the type name will be the name of the
+.. % last class defined using classdesc.  The type name
+.. % is required if the type is implemented in C (because
+.. % there's no classdesc) or if the class isn't directly
+.. % documented (if it's private).
+.. % memberdesc - data members, like datadesc, but with an optional
+.. % type name like methoddesc.
+
+
+.. class:: Http([cache=None], [timeout=None], [proxy_info==ProxyInfo.from_environment], [ca_certs=None], [disable_ssl_certificate_validation=False])
+
+   The class that represents a client HTTP interface. The *cache* parameter is
+   either the name of a directory to be used as a flat file cache, or it must an
+   object that  implements the required caching interface. The *timeout* parameter
+   is the socket level timeout. The *ca_certs* parameter is the filename of the
+   CA certificates to use. If none is given a default set is used. The
+   *disable_ssl_certificate_validation* boolean flag determines if ssl certificate validation
+   is done. The *proxy_info* parameter is an object of type :class:`ProxyInfo`.
+
+
+.. class:: ProxyInfo(proxy_type, proxy_host, proxy_port, [proxy_rdns=None], [proxy_user=None], [proxy_pass=None])
+
+   Collect information required to use a proxy.
+   The parameter proxy_type must be set to one of socks.PROXY_TYPE_XXX
+   constants. For example: ::
+
+   p = ProxyInfo(proxy_type=socks.PROXY_TYPE_HTTP, proxy_host='localhost', proxy_port=8000)
+
+.. class:: Response(info)
+
+   Response is a subclass of :class:`dict` and instances of this  class are
+   returned from calls to Http.request. The *info* parameter is either  an
+   :class:`rfc822.Message` or an :class:`httplib.HTTPResponse` object.
+
+
+.. class:: FileCache(dir_name, [safe=safename])
+
+   FileCache implements a Cache as a directory of files. The *dir_name* parameter
+   is the name of the directory to use. If the directory does not exist then
+   FileCache attempts to create the directory. The optional *safe* parameter is a
+   funtion which generates the cache filename for each URI. A FileCache object is
+   constructed and used for caching when you pass a directory name into the
+   constructor of :class:`Http`.
+
+Http objects have the following methods:
+
+.. % If your module defines new object types (for a built-in module) or
+.. % classes (for a module written in Python), you should list the
+.. % methods and instance variables (if any) of each type or class in a
+.. % separate subsection.
+
+.. _http-objects:
+
+Http Objects
+---------------
+
+.. method:: Http.request(uri, [method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None])
+
+   Performs a single HTTP request. The *uri* is the URI of the HTTP resource and
+   can begin with either ``http`` or ``https``. The value of *uri* must be an
+   absolute URI.
+
+   The *method* is the HTTP method to perform, such as ``GET``, ``POST``,
+   ``DELETE``, etc. There is no restriction on the methods allowed.
+
+   The *body* is the entity body to be sent with the request. It is a string
+   object.
+
+   Any extra headers that are to be sent with the request should be provided in the
+   *headers* dictionary.
+
+   The maximum number of redirect to follow before raising an exception is
+   *redirections*. The default is 5.
+
+   The *connection_type* is the type of connection object to use. The supplied
+   class should implement the interface of httplib.HTTPConnection.
+
+   The return value is a tuple of (response, content), the first being an instance
+   of the :class:`Response` class, the second being a string that contains the
+   response entity body.
+
+
+.. method:: Http.add_credentials(name, password, [domain=None])
+
+   Adds a name and password that will be used when a request  requires
+   authentication. Supplying the optional *domain* name will restrict these
+   credentials to only be sent to the specified domain. If *domain* is not
+   specified then the given credentials will be used to try to satisfy every HTTP
+   401 challenge.
+
+
+.. method:: Http.add_certificate(key, cert, domain)
+
+   Add a *key* and *cert* that will be used for an SSL connection to the specified
+   domain. *keyfile* is the name of a PEM formatted  file that contains your
+   private key. *certfile* is a PEM formatted certificate chain file.
+
+
+.. method:: Http.clear_credentials()
+
+   Remove all the names and passwords used for authentication.
+
+
+.. attribute:: Http.follow_redirects
+
+   If ``True``, which is the default, safe redirects are followed, where safe means
+   that the client is only doing a ``GET`` or ``HEAD`` on the URI to which it is
+   being redirected. If ``False`` then no redirects are followed. Note that a False
+   'follow_redirects' takes precedence over a True 'follow_all_redirects'. Another
+   way of saying that is for 'follow_all_redirects' to have any affect,
+   'follow_redirects' must be True.
+
+
+.. attribute:: Http.follow_all_redirects
+
+   If ``False``, which is the default, only safe redirects are followed, where safe
+   means that the client is only doing a ``GET`` or ``HEAD`` on the URI to which it
+   is being redirected. If ``True`` then all redirects are followed. Note that a
+   False 'follow_redirects' takes precedence over a True 'follow_all_redirects'.
+   Another way of saying that is for 'follow_all_redirects' to have any affect,
+   'follow_redirects' must be True.
+
+
+.. attribute:: Http.forward_authorization_headers
+
+  If ``False``, which is the default, then Authorization: headers are
+  stripped from redirects. If ``True`` then Authorization: headers are left
+  in place when following redirects. This parameter only applies if following
+  redirects is turned on. Note that turning this on could cause your credentials
+  to leak, so carefully consider the consequences.
+
+
+.. attribute:: Http.force_exception_to_status_code
+
+   If ``True`` then no :mod:`httplib2` exceptions will be
+   thrown. Instead, those error conditions will be turned into :class:`Response`
+   objects that will be returned normally.
+
+   If ``False``, which is the default, then exceptions will be thrown.
+
+
+.. attribute:: Http.optimistic_concurrency_methods
+
+   By default a list that only contains "PUT", this attribute
+   controls which methods will get 'if-match' headers attached
+   to them from cached responses with etags. You can append
+   new items to this list to add new methods that should
+   get this support, such as "PATCH".
+
+.. attribute:: Http.ignore_etag
+
+   Defaults to ``False``. If ``True``, then any etags present in the cached
+   response are ignored when processing the current request, i.e. httplib2 does
+   **not** use 'if-match' for PUT or 'if-none-match' when GET or HEAD requests are
+   made. This is mainly to deal with broken servers which supply an etag, but
+   change it capriciously.
+
+If you wish to supply your own caching implementation then you will need to pass
+in an object that supports the  following methods. Note that the :mod:`memcache`
+module supports this interface natively.
+
+
+.. _cache-objects:
+
+Cache Objects
+--------------
+
+.. method:: Cache.get(key)
+
+   Takes a string *key* and returns the value as a string.
+
+
+.. method:: Cache.set(key, value)
+
+   Takes a string *key* and *value* and stores it in the cache.
+
+
+.. method:: Cache.delete(key)
+
+   Deletes the cached value stored at *key*. The value of *key* is a string.
+
+Response objects are derived from :class:`dict` and map header names (lower case
+with the trailing colon removed) to header values. In addition to the dict
+methods a Response object also has:
+
+
+.. _response-objects:
+
+Response Objects
+------------------
+
+
+.. attribute:: Response.fromcache
+
+   If ``true`` the response was returned from the cache.
+
+
+.. attribute:: Response.version
+
+   The version of HTTP that the server supports. A value of 11 means '1.1'.
+
+
+.. attribute:: Response.status
+
+   The numerical HTTP status code returned in the response.
+
+
+.. attribute:: Response.reason
+
+   The human readable component of the HTTP response status code.
+
+
+.. attribute:: Response.previous
+
+   If redirects are followed then the :class:`Response` object returned is just for
+   the very last HTTP request and *previous* points to the previous
+   :class:`Response` object. In this manner they form a chain going back through
+   the responses to the very first response. Will be ``None`` if there are no
+   previous responses.
+
+The Response object also populates the header ``content-location``, that
+contains the URI that was ultimately requested. This is useful if redirects were
+encountered, you can determine the ultimate URI that the request was sent to.
+All Response objects contain this key value, including ``previous`` responses so
+you can determine the entire chain of redirects. If
+:attr:`Http.force_exception_to_status_code` is ``True`` and the number of
+redirects has exceeded the number of allowed number  of redirects then the
+:class:`Response` object will report the error in the status code, but the
+complete chain of previous responses will still be in tact.
+
+To do a simple ``GET`` request just supply the absolute URI of the resource:
+
+.. % ==== 4. ====
+.. % Now is probably a good time for a complete example.  (Alternatively,
+.. % an example giving the flavor of the module may be given before the
+.. % detailed list of functions.)
+
+.. _httplib2-example:
+
+Examples
+---------
+
+::
+
+   import httplib2
+   h = httplib2.Http()
+   resp, content = h.request("http://bitworking.org/")
+   assert resp.status == 200
+   assert resp['content-type'] == 'text/html'
+
+Here is more complex example that does a PUT  of some text to a resource that
+requires authentication. The Http instance also uses a file cache in the
+directory ``.cache``.  ::
+
+   import httplib2
+   h = httplib2.Http(".cache")
+   h.add_credentials('name', 'password')
+   resp, content = h.request("https://example.org/chap/2",
+       "PUT", body="This is text",
+       headers={'content-type':'text/plain'} )
+
+Here is an example that connects to a server that  supports the Atom Publishing
+Protocol. ::
+
+   import httplib2
+   h = httplib2.Http()
+   h.add_credentials(myname, mypasswd)
+   h.follow_all_redirects = True
+   headers = {'Content-Type': 'application/atom+xml'}
+   body    = """<?xml version="1.0" ?>
+       <entry xmlns="http://www.w3.org/2005/Atom">
+         <title>Atom-Powered Robots Run Amok</title>
+         <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+         <updated>2003-12-13T18:30:02Z</updated>
+         <author><name>John Doe</name></author>
+         <content>Some text.</content>
+   </entry>
+   """
+   uri     = "http://www.example.com/collection/"
+   resp, content = h.request(uri, "POST", body=body, headers=headers)
+
+Here is an example of providing data to an HTML form processor. In this case we
+presume this is a POST form. We need to take our  data and format it as
+"application/x-www-form-urlencoded" data and use that as a  body for a POST
+request.
+
+
+::
+
+   >>> import httplib2
+   >>> import urllib
+   >>> data = {'name': 'fred', 'address': '123 shady lane'}
+   >>> body = urllib.urlencode(data)
+   >>> body
+   'name=fred&address=123+shady+lane'
+   >>> h = httplib2.Http()
+   >>> resp, content = h.request("http://example.com", method="POST", body=body)
diff --git a/doc/html/_static/basic.css b/doc/html/_static/basic.css
new file mode 100644
index 0000000..a04d654
--- /dev/null
+++ b/doc/html/_static/basic.css
@@ -0,0 +1,417 @@
+/**
+ * Sphinx stylesheet -- basic theme
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+    clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+    width: 100%;
+    font-size: 90%;
+}
+
+div.related h3 {
+    display: none;
+}
+
+div.related ul {
+    margin: 0;
+    padding: 0 0 0 10px;
+    list-style: none;
+}
+
+div.related li {
+    display: inline;
+}
+
+div.related li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+    padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+    float: left;
+    width: 230px;
+    margin-left: -100%;
+    font-size: 90%;
+}
+
+div.sphinxsidebar ul {
+    list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+    margin-left: 20px;
+    list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+    margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+img {
+    border: 0;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+    margin: 10px 0 0 20px;
+    padding: 0;
+}
+
+ul.search li {
+    padding: 5px 0 5px 20px;
+    background-image: url(file.png);
+    background-repeat: no-repeat;
+    background-position: 0 7px;
+}
+
+ul.search li a {
+    font-weight: bold;
+}
+
+ul.search li div.context {
+    color: #888;
+    margin: 2px 0 0 30px;
+    text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+    font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.3em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+    font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+a.headerlink {
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+div.body p.caption {
+    text-align: inherit;
+}
+
+div.body td {
+    text-align: left;
+}
+
+.field-list ul {
+    padding-left: 1em;
+}
+
+.first {
+    margin-top: 0 !important;
+}
+
+p.rubric {
+    margin-top: 30px;
+    font-weight: bold;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+    margin: 0 0 0.5em 1em;
+    border: 1px solid #ddb;
+    padding: 7px 7px 0 7px;
+    background-color: #ffe;
+    width: 40%;
+    float: right;
+}
+
+p.sidebar-title {
+    font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+    border: 1px solid #ccc;
+    padding: 7px 7px 0 7px;
+    margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+    font-size: 1.1em;
+    font-weight: bold;
+    margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    padding: 7px;
+}
+
+div.admonition dt {
+    font-weight: bold;
+}
+
+div.admonition dl {
+    margin-bottom: 0;
+}
+
+p.admonition-title {
+    margin: 0px 10px 5px 0px;
+    font-weight: bold;
+}
+
+div.body p.centered {
+    text-align: center;
+    margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+    border: 0;
+    border-collapse: collapse;
+}
+
+table.docutils td, table.docutils th {
+    padding: 1px 8px 1px 0;
+    border-top: 0;
+    border-left: 0;
+    border-right: 0;
+    border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+    border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+    border: 0 !important;
+}
+
+th {
+    text-align: left;
+    padding-right: 5px;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+dl {
+    margin-bottom: 15px;
+}
+
+dd p {
+    margin-top: 0px;
+}
+
+dd ul, dd table {
+    margin-bottom: 10px;
+}
+
+dd {
+    margin-top: 3px;
+    margin-bottom: 10px;
+    margin-left: 30px;
+}
+
+dt:target, .highlight {
+    background-color: #fbe54e;
+}
+
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.field-list ul {
+    margin: 0;
+    padding-left: 1em;
+}
+
+.field-list p {
+    margin: 0;
+}
+
+.refcount {
+    color: #060;
+}
+
+.optional {
+    font-size: 1.3em;
+}
+
+.versionmodified {
+    font-style: italic;
+}
+
+.system-message {
+    background-color: #fda;
+    padding: 5px;
+    border: 3px solid red;
+}
+
+.footnote:target  {
+    background-color: #ffa
+}
+
+.line-block {
+    display: block;
+    margin-top: 1em;
+    margin-bottom: 1em;
+}
+
+.line-block .line-block {
+    margin-top: 0;
+    margin-bottom: 0;
+    margin-left: 1.5em;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+    overflow: auto;
+}
+
+td.linenos pre {
+    padding: 5px 0px;
+    border: 0;
+    background-color: transparent;
+    color: #aaa;
+}
+
+table.highlighttable {
+    margin-left: 0.5em;
+}
+
+table.highlighttable td {
+    padding: 0 0.5em 0 0.5em;
+}
+
+tt.descname {
+    background-color: transparent;
+    font-weight: bold;
+    font-size: 1.2em;
+}
+
+tt.descclassname {
+    background-color: transparent;
+}
+
+tt.xref, a tt {
+    background-color: transparent;
+    font-weight: bold;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+    background-color: transparent;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+    vertical-align: middle;
+}
+
+div.body div.math p {
+    text-align: center;
+}
+
+span.eqno {
+    float: right;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+    div.document,
+    div.documentwrapper,
+    div.bodywrapper {
+        margin: 0 !important;
+        width: 100%;
+    }
+
+    div.sphinxsidebar,
+    div.related,
+    div.footer,
+    #top-link {
+        display: none;
+    }
+}
diff --git a/doc/html/_static/contents.png b/doc/html/_static/contents.png
new file mode 100755
index 0000000..7fb8215
--- /dev/null
+++ b/doc/html/_static/contents.png
Binary files differ
diff --git a/doc/html/_static/default.css b/doc/html/_static/default.css
new file mode 100644
index 0000000..42ed6ec
--- /dev/null
+++ b/doc/html/_static/default.css
@@ -0,0 +1,218 @@
+/**
+ * Sphinx stylesheet -- default theme
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+    font-family: sans-serif;
+    font-size: 100%;
+    background-color: #11303d;
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+div.document {
+    background-color: #1c4e63;
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+}
+
+div.bodywrapper {
+    margin: 0 0 0 230px;
+}
+
+div.body {
+    background-color: #ffffff;
+    color: #000000;
+    padding: 0 20px 30px 20px;
+}
+
+div.footer {
+    color: #ffffff;
+    width: 100%;
+    padding: 9px 0 9px 0;
+    text-align: center;
+    font-size: 75%;
+}
+
+div.footer a {
+    color: #ffffff;
+    text-decoration: underline;
+}
+
+div.related {
+    background-color: #133f52;
+    line-height: 30px;
+    color: #ffffff;
+}
+
+div.related a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar {
+}
+
+div.sphinxsidebar h3 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.4em;
+    font-weight: normal;
+    margin: 0;
+    padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+    color: #ffffff;
+}
+
+div.sphinxsidebar h4 {
+    font-family: 'Trebuchet MS', sans-serif;
+    color: #ffffff;
+    font-size: 1.3em;
+    font-weight: normal;
+    margin: 5px 0 0 0;
+    padding: 0;
+}
+
+div.sphinxsidebar p {
+    color: #ffffff;
+}
+
+div.sphinxsidebar p.topless {
+    margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+    margin: 10px;
+    padding: 0;
+    color: #ffffff;
+}
+
+div.sphinxsidebar a {
+    color: #98dbcc;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+a {
+    color: #355f7c;
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}
+
+div.body p, div.body dd, div.body li {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: 'Trebuchet MS', sans-serif;
+    background-color: #f2f2f2;
+    font-weight: normal;
+    color: #20435c;
+    border-bottom: 1px solid #ccc;
+    margin: 20px -20px 10px -20px;
+    padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+    color: #c60f0f;
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+}
+
+a.headerlink:hover {
+    background-color: #c60f0f;
+    color: white;
+}
+
+div.body p, div.body dd, div.body li {
+    text-align: justify;
+    line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+    display: inline;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+
+div.topic {
+    background-color: #eee;
+}
+
+div.warning {
+    background-color: #ffe4e4;
+    border: 1px solid #f66;
+}
+
+p.admonition-title {
+    display: inline;
+}
+
+p.admonition-title:after {
+    content: ":";
+}
+
+pre {
+    padding: 5px;
+    background-color: #eeffcc;
+    color: #333333;
+    line-height: 120%;
+    border: 1px solid #ac9;
+    border-left: none;
+    border-right: none;
+}
+
+tt {
+    background-color: #ecf0f3;
+    padding: 0 1px 0 1px;
+    font-size: 0.95em;
+}
+
+.warning tt {
+    background: #efc2c2;
+}
+
+.note tt {
+    background: #d6d6d6;
+}
\ No newline at end of file
diff --git a/doc/html/_static/doctools.js b/doc/html/_static/doctools.js
new file mode 100644
index 0000000..9447678
--- /dev/null
+++ b/doc/html/_static/doctools.js
@@ -0,0 +1,232 @@
+/// XXX: make it cross browser
+
+/**
+ * make the code below compatible with browsers without
+ * an installed firebug like debugger
+ */
+if (!window.console || !console.firebug) {
+  var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
+      "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
+  window.console = {};
+  for (var i = 0; i < names.length; ++i)
+    window.console[names[i]] = function() {}
+}
+
+/**
+ * small helper function to urldecode strings
+ */
+jQuery.urldecode = function(x) {
+  return decodeURIComponent(x).replace(/\+/g, ' ');
+}
+
+/**
+ * small helper function to urlencode strings
+ */
+jQuery.urlencode = encodeURIComponent;
+
+/**
+ * This function returns the parsed url parameters of the
+ * current request. Multiple values per key are supported,
+ * it will always return arrays of strings for the value parts.
+ */
+jQuery.getQueryParameters = function(s) {
+  if (typeof s == 'undefined')
+    s = document.location.search;
+  var parts = s.substr(s.indexOf('?') + 1).split('&');
+  var result = {};
+  for (var i = 0; i < parts.length; i++) {
+    var tmp = parts[i].split('=', 2);
+    var key = jQuery.urldecode(tmp[0]);
+    var value = jQuery.urldecode(tmp[1]);
+    if (key in result)
+      result[key].push(value);
+    else
+      result[key] = [value];
+  }
+  return result;
+}
+
+/**
+ * small function to check if an array contains
+ * a given item.
+ */
+jQuery.contains = function(arr, item) {
+  for (var i = 0; i < arr.length; i++) {
+    if (arr[i] == item)
+      return true;
+  }
+  return false;
+}
+
+/**
+ * highlight a given string on a jquery object by wrapping it in
+ * span elements with the given class name.
+ */
+jQuery.fn.highlightText = function(text, className) {
+  function highlight(node) {
+    if (node.nodeType == 3) {
+      var val = node.nodeValue;
+      var pos = val.toLowerCase().indexOf(text);
+      if (pos >= 0 && !jQuery.className.has(node.parentNode, className)) {
+        var span = document.createElement("span");
+        span.className = className;
+        span.appendChild(document.createTextNode(val.substr(pos, text.length)));
+        node.parentNode.insertBefore(span, node.parentNode.insertBefore(
+          document.createTextNode(val.substr(pos + text.length)),
+          node.nextSibling));
+        node.nodeValue = val.substr(0, pos);
+      }
+    }
+    else if (!jQuery(node).is("button, select, textarea")) {
+      jQuery.each(node.childNodes, function() {
+        highlight(this)
+      });
+    }
+  }
+  return this.each(function() {
+    highlight(this);
+  });
+}
+
+/**
+ * Small JavaScript module for the documentation.
+ */
+var Documentation = {
+
+  init : function() {
+    this.fixFirefoxAnchorBug();
+    this.highlightSearchWords();
+    this.initModIndex();
+  },
+
+  /**
+   * i18n support
+   */
+  TRANSLATIONS : {},
+  PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
+  LOCALE : 'unknown',
+
+  // gettext and ngettext don't access this so that the functions
+  // can savely bound to a different name (_ = Documentation.gettext)
+  gettext : function(string) {
+    var translated = Documentation.TRANSLATIONS[string];
+    if (typeof translated == 'undefined')
+      return string;
+    return (typeof translated == 'string') ? translated : translated[0];
+  },
+
+  ngettext : function(singular, plural, n) {
+    var translated = Documentation.TRANSLATIONS[singular];
+    if (typeof translated == 'undefined')
+      return (n == 1) ? singular : plural;
+    return translated[Documentation.PLURALEXPR(n)];
+  },
+
+  addTranslations : function(catalog) {
+    for (var key in catalog.messages)
+      this.TRANSLATIONS[key] = catalog.messages[key];
+    this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
+    this.LOCALE = catalog.locale;
+  },
+
+  /**
+   * add context elements like header anchor links
+   */
+  addContextElements : function() {
+    $('div[id] > :header:first').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this headline')).
+      appendTo(this);
+    });
+    $('dt[id]').each(function() {
+      $('<a class="headerlink">\u00B6</a>').
+      attr('href', '#' + this.id).
+      attr('title', _('Permalink to this definition')).
+      appendTo(this);
+    });
+  },
+
+  /**
+   * workaround a firefox stupidity
+   */
+  fixFirefoxAnchorBug : function() {
+    if (document.location.hash && $.browser.mozilla)
+      window.setTimeout(function() {
+        document.location.href += '';
+      }, 10);
+  },
+
+  /**
+   * highlight the search words provided in the url in the text
+   */
+  highlightSearchWords : function() {
+    var params = $.getQueryParameters();
+    var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
+    if (terms.length) {
+      var body = $('div.body');
+      window.setTimeout(function() {
+        $.each(terms, function() {
+          body.highlightText(this.toLowerCase(), 'highlight');
+        });
+      }, 10);
+      $('<li class="highlight-link"><a href="javascript:Documentation.' +
+        'hideSearchWords()">' + _('Hide Search Matches') + '</a></li>')
+          .appendTo($('.sidebar .this-page-menu'));
+    }
+  },
+
+  /**
+   * init the modindex toggle buttons
+   */
+  initModIndex : function() {
+    var togglers = $('img.toggler').click(function() {
+      var src = $(this).attr('src');
+      var idnum = $(this).attr('id').substr(7);
+      console.log($('tr.cg-' + idnum).toggle());
+      if (src.substr(-9) == 'minus.png')
+        $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
+      else
+        $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
+    }).css('display', '');
+    if (DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX) {
+        togglers.click();
+    }
+  },
+
+  /**
+   * helper function to hide the search marks again
+   */
+  hideSearchWords : function() {
+    $('.sidebar .this-page-menu li.highlight-link').fadeOut(300);
+    $('span.highlight').removeClass('highlight');
+  },
+
+  /**
+   * make the url absolute
+   */
+  makeURL : function(relativeURL) {
+    return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
+  },
+
+  /**
+   * get the current relative url
+   */
+  getCurrentURL : function() {
+    var path = document.location.pathname;
+    var parts = path.split(/\//);
+    $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
+      if (this == '..')
+        parts.pop();
+    });
+    var url = parts.join('/');
+    return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
+  }
+};
+
+// quick alias for translations
+_ = Documentation.gettext;
+
+$(document).ready(function() {
+  Documentation.init();
+});
diff --git a/doc/html/_static/file.png b/doc/html/_static/file.png
new file mode 100755
index 0000000..d18082e
--- /dev/null
+++ b/doc/html/_static/file.png
Binary files differ
diff --git a/doc/html/_static/interface.js b/doc/html/_static/interface.js
new file mode 100755
index 0000000..91a0d4f
--- /dev/null
+++ b/doc/html/_static/interface.js
@@ -0,0 +1,8 @@
+/*
+ * Interface elements for jQuery - http://interface.eyecon.ro
+ *
+ * Copyright (c) 2006 Stefan Petre
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ */
+ eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('k.1a={2R:u(e){D x=0;D y=0;D 5H=I;D es=e.18;if(k(e).B(\'19\')==\'1n\'){62=es.3j;9C=es.Y;es.3j=\'2O\';es.19=\'2E\';es.Y=\'1O\';5H=1b}D el=e;7o(el){x+=el.8n+(el.4Y&&!k.3h.7N?T(el.4Y.5a)||0:0);y+=el.8t+(el.4Y&&!k.3h.7N?T(el.4Y.4Z)||0:0);el=el.dr}el=e;7o(el&&el.4S&&el.4S.5Z()!=\'2e\'){x-=el.3g||0;y-=el.2V||0;el=el.3e}if(5H){es.19=\'1n\';es.Y=9C;es.3j=62}E{x:x,y:y}},bN:u(el){D x=0,y=0;7o(el){x+=el.8n||0;y+=el.8t||0;el=el.dr}E{x:x,y:y}},2p:u(e){D w=k.B(e,\'Z\');D h=k.B(e,\'V\');D 1D=0;D hb=0;D es=e.18;if(k(e).B(\'19\')!=\'1n\'){1D=e.4b;hb=e.63}P{62=es.3j;9C=es.Y;es.3j=\'2O\';es.19=\'2E\';es.Y=\'1O\';1D=e.4b;hb=e.63;es.19=\'1n\';es.Y=9C;es.3j=62}E{w:w,h:h,1D:1D,hb:hb}},82:u(el){E{1D:el.4b||0,hb:el.63||0}},bq:u(e){D h,w,de;if(e){w=e.8k;h=e.8z}P{de=1j.4J;w=1V.d0||9B.d0||(de&&de.8k)||1j.2e.8k;h=1V.d1||9B.d1||(de&&de.8z)||1j.2e.8z}E{w:w,h:h}},6W:u(e){D t,l,w,h,iw,ih;if(e&&e.9A.5Z()!=\'2e\'){t=e.2V;l=e.3g;w=e.cY;h=e.cW;iw=0;ih=0}P{if(1j.4J&&1j.4J.2V){t=1j.4J.2V;l=1j.4J.3g;w=1j.4J.cY;h=1j.4J.cW}P if(1j.2e){t=1j.2e.2V;l=1j.2e.3g;w=1j.2e.cY;h=1j.2e.cW}iw=9B.d0||1j.4J.8k||1j.2e.8k||0;ih=9B.d1||1j.4J.8z||1j.2e.8z||0}E{t:t,l:l,w:w,h:h,iw:iw,ih:ih}},c8:u(e,7C){D el=k(e);D t=el.B(\'5o\')||\'\';D r=el.B(\'5p\')||\'\';D b=el.B(\'5m\')||\'\';D l=el.B(\'5k\')||\'\';if(7C)E{t:T(t)||0,r:T(r)||0,b:T(b)||0,l:T(l)};P E{t:t,r:r,b:b,l:l}},aj:u(e,7C){D el=k(e);D t=el.B(\'66\')||\'\';D r=el.B(\'6j\')||\'\';D b=el.B(\'5M\')||\'\';D l=el.B(\'4X\')||\'\';if(7C)E{t:T(t)||0,r:T(r)||0,b:T(b)||0,l:T(l)};P E{t:t,r:r,b:b,l:l}},6h:u(e,7C){D el=k(e);D t=el.B(\'4Z\')||\'\';D r=el.B(\'6k\')||\'\';D b=el.B(\'6g\')||\'\';D l=el.B(\'5a\')||\'\';if(7C)E{t:T(t)||0,r:T(r)||0,b:T(b)||0,l:T(l)||0};P E{t:t,r:r,b:b,l:l}},44:u(2l){D x=2l.hI||(2l.hK+(1j.4J.3g||1j.2e.3g))||0;D y=2l.hL||(2l.hM+(1j.4J.2V||1j.2e.2V))||0;E{x:x,y:y}},cS:u(54,cT){cT(54);54=54.77;7o(54){k.1a.cS(54,cT);54=54.hU}},i1:u(54){k.1a.cS(54,u(el){1Y(D 1p in el){if(2h el[1p]===\'u\'){el[1p]=U}}})},i3:u(el,1N){D 5C=$.1a.6W();D d3=$.1a.2p(el);if(!1N||1N==\'4i\')$(el).B({Q:5C.t+((14.3v(5C.h,5C.ih)-5C.t-d3.hb)/2)+\'S\'});if(!1N||1N==\'4a\')$(el).B({O:5C.l+((14.3v(5C.w,5C.iw)-5C.l-d3.1D)/2)+\'S\'})},i0:u(el,dP){D 1Q=$(\'1U[@2M*="95"]\',el||1j),95;1Q.1B(u(){95=q.2M;q.2M=dP;q.18.69="aw:ax.ay.hZ(2M=\'"+95+"\')"})}};[].3F||(7b.hV.3F=u(v,n){n=(n==U)?0:n;D m=q.1h;1Y(D i=n;i<m;i++)if(q[i]==v)E i;E-1});k.4O=u(e){if(/^hW$|^hX$|^hY$|^6v$|^hH$|^hG$|^hp$|^hq$|^hs$|^2e$|^ht$|^ho$|^hn$|^hj$|^hi$|^hk$|^hl$/i.43(e.9A))E I;P E 1b};k.fx.9g=u(e,65){D c=e.77;D cs=c.18;cs.Y=65.Y;cs.5o=65.3A.t;cs.5k=65.3A.l;cs.5m=65.3A.b;cs.5p=65.3A.r;cs.Q=65.Q+\'S\';cs.O=65.O+\'S\';e.3e.dk(c,e);e.3e.hu(e)};k.fx.9h=u(e){if(!k.4O(e))E I;D t=k(e);D es=e.18;D 5H=I;D W={};W.Y=t.B(\'Y\');if(t.B(\'19\')==\'1n\'){62=t.B(\'3j\');es.3j=\'2O\';es.19=\'\';5H=1b}W.1q=k.1a.2p(e);W.3A=k.1a.c8(e);D d7=e.4Y?e.4Y.dM:t.B(\'hv\');W.Q=T(t.B(\'Q\'))||0;W.O=T(t.B(\'O\'))||0;D dC=\'hC\'+T(14.6w()*cd);D 6C=1j.3t(/^1U$|^br$|^hD$|^hr$|^8Z$|^hE$|^8i$|^3E$|^hF$|^hB$|^hA$|^aX$|^dl$|^hw$/i.43(e.9A)?\'26\':e.9A);k.1p(6C,\'id\',dC);6C.3b=\'hy\';D 3C=6C.18;D Q=0;D O=0;if(W.Y==\'2y\'||W.Y==\'1O\'){Q=W.Q;O=W.O}3C.19=\'1n\';3C.Q=Q+\'S\';3C.O=O+\'S\';3C.Y=W.Y!=\'2y\'&&W.Y!=\'1O\'?\'2y\':W.Y;3C.2Y=\'2O\';3C.V=W.1q.hb+\'S\';3C.Z=W.1q.1D+\'S\';3C.5o=W.3A.t;3C.5p=W.3A.r;3C.5m=W.3A.b;3C.5k=W.3A.l;if(k.3h.4I){3C.dM=d7}P{3C.i5=d7}e.3e.dk(6C,e);es.5o=\'3c\';es.5p=\'3c\';es.5m=\'3c\';es.5k=\'3c\';es.Y=\'1O\';es.dV=\'1n\';es.Q=\'3c\';es.O=\'3c\';if(5H){es.19=\'1n\';es.3j=62}6C.iK(e);3C.19=\'2E\';E{W:W,3o:k(6C)}};k.fx.8m={iM:[0,1X,1X],iI:[dJ,1X,1X],iH:[dG,dG,iD],iC:[0,0,0],iE:[0,0,1X],iF:[dE,42,42],iG:[0,1X,1X],iN:[0,0,7B],iO:[0,7B,7B],iV:[cn,cn,cn],iX:[0,2b,0],iY:[iU,iT,da],iP:[7B,0,7B],iQ:[85,da,47],iS:[1X,dI,0],iB:[iA,50,ig],ii:[7B,0,0],ij:[ik,fd,ie],ic:[i8,0,9y],i7:[1X,0,1X],i9:[1X,hh,0],ia:[0,6F,0],ib:[75,0,il],im:[dJ,dK,dI],iy:[iz,iu,dK],io:[dA,1X,1X],ip:[dL,iq,dL],iZ:[9y,9y,9y],gn:[1X,gr,gl],gq:[1X,1X,dA],gs:[0,1X,0],gj:[1X,0,1X],gh:[6F,0,0],gi:[0,0,6F],gd:[6F,6F,0],ge:[1X,dE,0],gf:[1X,9z,gk],gu:[6F,0,6F],gp:[1X,0,0],gv:[9z,9z,9z],gg:[1X,1X,1X],hg:[1X,1X,0]};k.fx.6H=u(4C,dH){if(k.fx.8m[4C])E{r:k.fx.8m[4C][0],g:k.fx.8m[4C][1],b:k.fx.8m[4C][2]};P if(2W=/^7K\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)$/.9D(4C))E{r:T(2W[1]),g:T(2W[2]),b:T(2W[3])};P if(2W=/7K\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)$/.9D(4C))E{r:2m(2W[1])*2.55,g:2m(2W[2])*2.55,b:2m(2W[3])*2.55};P if(2W=/^#([a-fA-7y-9])([a-fA-7y-9])([a-fA-7y-9])$/.9D(4C))E{r:T("7z"+2W[1]+2W[1]),g:T("7z"+2W[2]+2W[2]),b:T("7z"+2W[3]+2W[3])};P if(2W=/^#([a-fA-7y-9]{2})([a-fA-7y-9]{2})([a-fA-7y-9]{2})$/.9D(4C))E{r:T("7z"+2W[1]),g:T("7z"+2W[2]),b:T("7z"+2W[3])};P E dH==1b?I:{r:1X,g:1X,b:1X}};k.fx.d8={6g:1,5a:1,6k:1,4Z:1,4l:1,4w:1,V:1,O:1,cH:1,h3:1,5m:1,5k:1,5p:1,5o:1,8M:1,6q:1,8L:1,9s:1,1J:1,h0:1,gZ:1,5M:1,4X:1,6j:1,66:1,2N:1,gV:1,Q:1,Z:1,3B:1};k.fx.d9={7f:1,gW:1,gX:1,gY:1,h4:1,4C:1,h5:1};k.fx.8p=[\'gw\',\'hd\',\'he\',\'hf\'];k.fx.cw={\'cD\':[\'2B\',\'ds\'],\'9I\':[\'2B\',\'cq\'],\'6X\':[\'6X\',\'\'],\'92\':[\'92\',\'\']};k.fn.21({5K:u(5U,H,G,J){E q.1w(u(){D 9E=k.H(H,G,J);D e=11 k.dg(q,9E,5U)})},cK:u(H,J){E q.1w(u(){D 9E=k.H(H,J);D e=11 k.cK(q,9E)})},8v:u(2D){E q.1B(u(){if(q.5R)k.cv(q,2D)})},ha:u(2D){E q.1B(u(){if(q.5R)k.cv(q,2D);if(q.1w&&q.1w[\'fx\'])q.1w.fx=[]})}});k.21({cK:u(2i,M){D z=q,3u;z.2D=u(){if(k.eI(M.23))M.23.1F(2i)};z.2H=6I(u(){z.2D()},M.1m);2i.5R=z},G:{bV:u(p,n,1W,1I,1m){E((-14.5v(p*14.2Q)/2)+0.5)*1I+1W}},dg:u(2i,M,5U){D z=q,3u;D y=2i.18;D eH=k.B(2i,"2Y");D 7M=k.B(2i,"19");D 2k={};z.9x=(11 72()).71();M.G=M.G&&k.G[M.G]?M.G:\'bV\';z.9F=u(2z,49){if(k.fx.d8[2z]){if(49==\'22\'||49==\'2G\'||49==\'3Y\'){if(!2i.6u)2i.6u={};D r=2m(k.3M(2i,2z));2i.6u[2z]=r&&r>-cd?r:(2m(k.B(2i,2z))||0);49=49==\'3Y\'?(7M==\'1n\'?\'22\':\'2G\'):49;M[49]=1b;2k[2z]=49==\'22\'?[0,2i.6u[2z]]:[2i.6u[2z],0];if(2z!=\'1J\')y[2z]=2k[2z][0]+(2z!=\'3B\'&&2z!=\'8h\'?\'S\':\'\');P k.1p(y,"1J",2k[2z][0])}P{2k[2z]=[2m(k.3M(2i,2z)),2m(49)||0]}}P if(k.fx.d9[2z])2k[2z]=[k.fx.6H(k.3M(2i,2z)),k.fx.6H(49)];P if(/^6X$|92$|2B$|9I$|cD$/i.43(2z)){D m=49.4v(/\\s+/g,\' \').4v(/7K\\s*\\(\\s*/g,\'7K(\').4v(/\\s*,\\s*/g,\',\').4v(/\\s*\\)/g,\')\').bU(/([^\\s]+)/g);3m(2z){1e\'6X\':1e\'92\':1e\'cD\':1e\'9I\':m[3]=m[3]||m[1]||m[0];m[2]=m[2]||m[0];m[1]=m[1]||m[0];1Y(D i=0;i<k.fx.8p.1h;i++){D 5X=k.fx.cw[2z][0]+k.fx.8p[i]+k.fx.cw[2z][1];2k[5X]=2z==\'9I\'?[k.fx.6H(k.3M(2i,5X)),k.fx.6H(m[i])]:[2m(k.3M(2i,5X)),2m(m[i])]}1r;1e\'2B\':1Y(D i=0;i<m.1h;i++){D cC=2m(m[i]);D 9H=!h8(cC)?\'ds\':(!/b7|1n|2O|gT|gF|gG|gH|gE|gD|gz|gA/i.43(m[i])?\'cq\':I);if(9H){1Y(D j=0;j<k.fx.8p.1h;j++){5X=\'2B\'+k.fx.8p[j]+9H;2k[5X]=9H==\'cq\'?[k.fx.6H(k.3M(2i,5X)),k.fx.6H(m[i])]:[2m(k.3M(2i,5X)),cC]}}P{y[\'gQ\']=m[i]}}1r}}P{y[2z]=49}E I};1Y(p in 5U){if(p==\'18\'){D 5u=k.cu(5U[p]);1Y(7L in 5u){q.9F(7L,5u[7L])}}P if(p==\'3b\'){if(1j.9G)1Y(D i=0;i<1j.9G.1h;i++){D 7G=1j.9G[i].7G||1j.9G[i].gP||U;if(7G){1Y(D j=0;j<7G.1h;j++){if(7G[j].gO==\'.\'+5U[p]){D 7H=11 cp(\'\\.\'+5U[p]+\' {\');D 5S=7G[j].18.9T;D 5u=k.cu(5S.4v(7H,\'\').4v(/}/g,\'\'));1Y(7L in 5u){q.9F(7L,5u[7L])}}}}}}P{q.9F(p,5U[p])}}y.19=7M==\'1n\'?\'2E\':7M;y.2Y=\'2O\';z.2D=u(){D t=(11 72()).71();if(t>M.1m+z.9x){6c(z.2H);z.2H=U;1Y(p in 2k){if(p=="1J")k.1p(y,"1J",2k[p][1]);P if(2h 2k[p][1]==\'8i\')y[p]=\'7K(\'+2k[p][1].r+\',\'+2k[p][1].g+\',\'+2k[p][1].b+\')\';P y[p]=2k[p][1]+(p!=\'3B\'&&p!=\'8h\'?\'S\':\'\')}if(M.2G||M.22)1Y(D p in 2i.6u)if(p=="1J")k.1p(y,p,2i.6u[p]);P y[p]="";y.19=M.2G?\'1n\':(7M!=\'1n\'?7M:\'2E\');y.2Y=eH;2i.5R=U;if(k.eI(M.23))M.23.1F(2i)}P{D n=t-q.9x;D 8x=n/M.1m;1Y(p in 2k){if(2h 2k[p][1]==\'8i\'){y[p]=\'7K(\'+T(k.G[M.G](8x,n,2k[p][0].r,(2k[p][1].r-2k[p][0].r),M.1m))+\',\'+T(k.G[M.G](8x,n,2k[p][0].g,(2k[p][1].g-2k[p][0].g),M.1m))+\',\'+T(k.G[M.G](8x,n,2k[p][0].b,(2k[p][1].b-2k[p][0].b),M.1m))+\')\'}P{D cG=k.G[M.G](8x,n,2k[p][0],(2k[p][1]-2k[p][0]),M.1m);if(p=="1J")k.1p(y,"1J",cG);P y[p]=cG+(p!=\'3B\'&&p!=\'8h\'?\'S\':\'\')}}}};z.2H=6I(u(){z.2D()},13);2i.5R=z},cv:u(2i,2D){if(2D)2i.5R.9x-=kM;P{1V.6c(2i.5R.2H);2i.5R=U;k.2L(2i,"fx")}}});k.cu=u(5S){D 5u={};if(2h 5S==\'5g\'){5S=5S.5Z().7h(\';\');1Y(D i=0;i<5S.1h;i++){7H=5S[i].7h(\':\');if(7H.1h==2){5u[k.eP(7H[0].4v(/\\-(\\w)/g,u(m,c){E c.kn()}))]=k.eP(7H[1])}}}E 5u};k.12={1c:U,F:U,58:u(){E q.1B(u(){if(q.9q){q.A.5e.3p(\'5b\',k.12.cU);q.A=U;q.9q=I;if(k.3h.4I){q.d4="fQ"}P{q.18.kk=\'\';q.18.ej=\'\';q.18.e6=\'\'}}})},cU:u(e){if(k.12.F!=U){k.12.9w(e);E I}D C=q.3Z;k(1j).1H(\'3H\',k.12.d6).1H(\'61\',k.12.9w);C.A.1s=k.1a.44(e);C.A.4t=C.A.1s;C.A.7W=I;C.A.ki=q!=q.3Z;k.12.F=C;if(C.A.5i&&q!=q.3Z){ce=k.1a.2R(C.3e);cf=k.1a.2p(C);cg={x:T(k.B(C,\'O\'))||0,y:T(k.B(C,\'Q\'))||0};dx=C.A.4t.x-ce.x-cf.1D/2-cg.x;dy=C.A.4t.y-ce.y-cf.hb/2-cg.y;k.3d.59(C,[dx,dy])}E k.7Z||I},dT:u(e){D C=k.12.F;C.A.7W=1b;D 9p=C.18;C.A.7i=k.B(C,\'19\');C.A.4m=k.B(C,\'Y\');if(!C.A.c4)C.A.c4=C.A.4m;C.A.2c={x:T(k.B(C,\'O\'))||0,y:T(k.B(C,\'Q\'))||0};C.A.9l=0;C.A.9m=0;if(k.3h.4I){D cl=k.1a.6h(C,1b);C.A.9l=cl.l||0;C.A.9m=cl.t||0}C.A.1C=k.21(k.1a.2R(C),k.1a.2p(C));if(C.A.4m!=\'2y\'&&C.A.4m!=\'1O\'){9p.Y=\'2y\'}k.12.1c.5t();D 5s=C.dn(1b);k(5s).B({19:\'2E\',O:\'3c\',Q:\'3c\'});5s.18.5o=\'0\';5s.18.5p=\'0\';5s.18.5m=\'0\';5s.18.5k=\'0\';k.12.1c.1R(5s);D 3X=k.12.1c.K(0).18;if(C.A.cO){3X.Z=\'ao\';3X.V=\'ao\'}P{3X.V=C.A.1C.hb+\'S\';3X.Z=C.A.1C.1D+\'S\'}3X.19=\'2E\';3X.5o=\'3c\';3X.5p=\'3c\';3X.5m=\'3c\';3X.5k=\'3c\';k.21(C.A.1C,k.1a.2p(5s));if(C.A.2S){if(C.A.2S.O){C.A.2c.x+=C.A.1s.x-C.A.1C.x-C.A.2S.O;C.A.1C.x=C.A.1s.x-C.A.2S.O}if(C.A.2S.Q){C.A.2c.y+=C.A.1s.y-C.A.1C.y-C.A.2S.Q;C.A.1C.y=C.A.1s.y-C.A.2S.Q}if(C.A.2S.2N){C.A.2c.x+=C.A.1s.x-C.A.1C.x-C.A.1C.hb+C.A.2S.2N;C.A.1C.x=C.A.1s.x-C.A.1C.1D+C.A.2S.2N}if(C.A.2S.4l){C.A.2c.y+=C.A.1s.y-C.A.1C.y-C.A.1C.hb+C.A.2S.4l;C.A.1C.y=C.A.1s.y-C.A.1C.hb+C.A.2S.4l}}C.A.2x=C.A.2c.x;C.A.2r=C.A.2c.y;if(C.A.8g||C.A.2o==\'96\'){89=k.1a.6h(C.3e,1b);C.A.1C.x=C.8n+(k.3h.4I?0:k.3h.7N?-89.l:89.l);C.A.1C.y=C.8t+(k.3h.4I?0:k.3h.7N?-89.t:89.t);k(C.3e).1R(k.12.1c.K(0))}if(C.A.2o){k.12.bP(C);C.A.5J.2o=k.12.bH}if(C.A.5i){k.3d.bO(C)}3X.O=C.A.1C.x-C.A.9l+\'S\';3X.Q=C.A.1C.y-C.A.9m+\'S\';3X.Z=C.A.1C.1D+\'S\';3X.V=C.A.1C.hb+\'S\';k.12.F.A.9n=I;if(C.A.gx){C.A.5J.67=k.12.bI}if(C.A.3B!=I){k.12.1c.B(\'3B\',C.A.3B)}if(C.A.1J){k.12.1c.B(\'1J\',C.A.1J);if(1V.7a){k.12.1c.B(\'69\',\'9V(1J=\'+C.A.1J*2b+\')\')}}if(C.A.7w){k.12.1c.2Z(C.A.7w);k.12.1c.K(0).77.18.19=\'1n\'}if(C.A.4A)C.A.4A.1F(C,[5s,C.A.2c.x,C.A.2c.y]);if(k.1x&&k.1x.8W>0){k.1x.ea(C)}if(C.A.4j==I){9p.19=\'1n\'}E I},bP:u(C){if(C.A.2o.1K==b5){if(C.A.2o==\'96\'){C.A.24=k.21({x:0,y:0},k.1a.2p(C.3e));D 84=k.1a.6h(C.3e,1b);C.A.24.w=C.A.24.1D-84.l-84.r;C.A.24.h=C.A.24.hb-84.t-84.b}P if(C.A.2o==\'1j\'){D cM=k.1a.bq();C.A.24={x:0,y:0,w:cM.w,h:cM.h}}}P if(C.A.2o.1K==7b){C.A.24={x:T(C.A.2o[0])||0,y:T(C.A.2o[1])||0,w:T(C.A.2o[2])||0,h:T(C.A.2o[3])||0}}C.A.24.dx=C.A.24.x-C.A.1C.x;C.A.24.dy=C.A.24.y-C.A.1C.y},9o:u(F){if(F.A.8g||F.A.2o==\'96\'){k(\'2e\',1j).1R(k.12.1c.K(0))}k.12.1c.5t().2G().B(\'1J\',1);if(1V.7a){k.12.1c.B(\'69\',\'9V(1J=2b)\')}},9w:u(e){k(1j).3p(\'3H\',k.12.d6).3p(\'61\',k.12.9w);if(k.12.F==U){E}D F=k.12.F;k.12.F=U;if(F.A.7W==I){E I}if(F.A.48==1b){k(F).B(\'Y\',F.A.4m)}D 9p=F.18;if(F.5i){k.12.1c.B(\'94\',\'8C\')}if(F.A.7w){k.12.1c.4p(F.A.7w)}if(F.A.6o==I){if(F.A.fx>0){if(!F.A.1N||F.A.1N==\'4a\'){D x=11 k.fx(F,{1m:F.A.fx},\'O\');x.1L(F.A.2c.x,F.A.8c)}if(!F.A.1N||F.A.1N==\'4i\'){D y=11 k.fx(F,{1m:F.A.fx},\'Q\');y.1L(F.A.2c.y,F.A.8j)}}P{if(!F.A.1N||F.A.1N==\'4a\')F.18.O=F.A.8c+\'S\';if(!F.A.1N||F.A.1N==\'4i\')F.18.Q=F.A.8j+\'S\'}k.12.9o(F);if(F.A.4j==I){k(F).B(\'19\',F.A.7i)}}P if(F.A.fx>0){F.A.9n=1b;D dh=I;if(k.1x&&k.1t&&F.A.48){dh=k.1a.2R(k.1t.1c.K(0))}k.12.1c.5K({O:dh?dh.x:F.A.1C.x,Q:dh?dh.y:F.A.1C.y},F.A.fx,u(){F.A.9n=I;if(F.A.4j==I){F.18.19=F.A.7i}k.12.9o(F)})}P{k.12.9o(F);if(F.A.4j==I){k(F).B(\'19\',F.A.7i)}}if(k.1x&&k.1x.8W>0){k.1x.ed(F)}if(k.1t&&F.A.48){k.1t.dp(F)}if(F.A.2T&&(F.A.8c!=F.A.2c.x||F.A.8j!=F.A.2c.y)){F.A.2T.1F(F,F.A.bQ||[0,0,F.A.8c,F.A.8j])}if(F.A.3S)F.A.3S.1F(F);E I},bI:u(x,y,dx,dy){if(dx!=0)dx=T((dx+(q.A.gx*dx/14.3R(dx))/2)/q.A.gx)*q.A.gx;if(dy!=0)dy=T((dy+(q.A.gy*dy/14.3R(dy))/2)/q.A.gy)*q.A.gy;E{dx:dx,dy:dy,x:0,y:0}},bH:u(x,y,dx,dy){dx=14.3D(14.3v(dx,q.A.24.dx),q.A.24.w+q.A.24.dx-q.A.1C.1D);dy=14.3D(14.3v(dy,q.A.24.dy),q.A.24.h+q.A.24.dy-q.A.1C.hb);E{dx:dx,dy:dy,x:0,y:0}},d6:u(e){if(k.12.F==U||k.12.F.A.9n==1b){E}D F=k.12.F;F.A.4t=k.1a.44(e);if(F.A.7W==I){46=14.dm(14.5Y(F.A.1s.x-F.A.4t.x,2)+14.5Y(F.A.1s.y-F.A.4t.y,2));if(46<F.A.6m){E}P{k.12.dT(e)}}D dx=F.A.4t.x-F.A.1s.x;D dy=F.A.4t.y-F.A.1s.y;1Y(D i in F.A.5J){D 3q=F.A.5J[i].1F(F,[F.A.2c.x+dx,F.A.2c.y+dy,dx,dy]);if(3q&&3q.1K==7n){dx=i!=\'7l\'?3q.dx:(3q.x-F.A.2c.x);dy=i!=\'7l\'?3q.dy:(3q.y-F.A.2c.y)}}F.A.2x=F.A.1C.x+dx-F.A.9l;F.A.2r=F.A.1C.y+dy-F.A.9m;if(F.A.5i&&(F.A.3z||F.A.2T)){k.3d.3z(F,F.A.2x,F.A.2r)}if(F.A.4x)F.A.4x.1F(F,[F.A.2c.x+dx,F.A.2c.y+dy]);if(!F.A.1N||F.A.1N==\'4a\'){F.A.8c=F.A.2c.x+dx;k.12.1c.K(0).18.O=F.A.2x+\'S\'}if(!F.A.1N||F.A.1N==\'4i\'){F.A.8j=F.A.2c.y+dy;k.12.1c.K(0).18.Q=F.A.2r+\'S\'}if(k.1x&&k.1x.8W>0){k.1x.a3(F)}E I},2s:u(o){if(!k.12.1c){k(\'2e\',1j).1R(\'<26 id="dW"></26>\');k.12.1c=k(\'#dW\');D el=k.12.1c.K(0);D 4P=el.18;4P.Y=\'1O\';4P.19=\'1n\';4P.94=\'8C\';4P.dV=\'1n\';4P.2Y=\'2O\';if(1V.7a){el.d4="en"}P{4P.kh=\'1n\';4P.e6=\'1n\';4P.ej=\'1n\'}}if(!o){o={}}E q.1B(u(){if(q.9q||!k.1a)E;if(1V.7a){q.kf=u(){E I};q.kj=u(){E I}}D el=q;D 5e=o.3y?k(q).kp(o.3y):k(q);if(k.3h.4I){5e.1B(u(){q.d4="en"})}P{5e.B(\'-kE-7l-8Z\',\'1n\');5e.B(\'7l-8Z\',\'1n\');5e.B(\'-ko-7l-8Z\',\'1n\')}q.A={5e:5e,6o:o.6o?1b:I,4j:o.4j?1b:I,48:o.48?o.48:I,5i:o.5i?o.5i:I,8g:o.8g?o.8g:I,3B:o.3B?T(o.3B)||0:I,1J:o.1J?2m(o.1J):I,fx:T(o.fx)||U,6p:o.6p?o.6p:I,5J:{},1s:{},4A:o.4A&&o.4A.1K==2C?o.4A:I,3S:o.3S&&o.3S.1K==2C?o.3S:I,2T:o.2T&&o.2T.1K==2C?o.2T:I,1N:/4i|4a/.43(o.1N)?o.1N:I,6m:o.6m?T(o.6m)||0:0,2S:o.2S?o.2S:I,cO:o.cO?1b:I,7w:o.7w||I};if(o.5J&&o.5J.1K==2C)q.A.5J.7l=o.5J;if(o.4x&&o.4x.1K==2C)q.A.4x=o.4x;if(o.2o&&((o.2o.1K==b5&&(o.2o==\'96\'||o.2o==\'1j\'))||(o.2o.1K==7b&&o.2o.1h==4))){q.A.2o=o.2o}if(o.2K){q.A.2K=o.2K}if(o.67){if(2h o.67==\'kl\'){q.A.gx=T(o.67)||1;q.A.gy=T(o.67)||1}P if(o.67.1h==2){q.A.gx=T(o.67[0])||1;q.A.gy=T(o.67[1])||1}}if(o.3z&&o.3z.1K==2C){q.A.3z=o.3z}q.9q=1b;5e.1B(u(){q.3Z=el});5e.1H(\'5b\',k.12.cU)})}};k.fn.21({a4:k.12.58,6Y:k.12.2s});k.1x={ee:u(5r,5y,7j,7g){E 5r<=k.12.F.A.2x&&(5r+7j)>=(k.12.F.A.2x+k.12.F.A.1C.w)&&5y<=k.12.F.A.2r&&(5y+7g)>=(k.12.F.A.2r+k.12.F.A.1C.h)?1b:I},by:u(5r,5y,7j,7g){E!(5r>(k.12.F.A.2x+k.12.F.A.1C.w)||(5r+7j)<k.12.F.A.2x||5y>(k.12.F.A.2r+k.12.F.A.1C.h)||(5y+7g)<k.12.F.A.2r)?1b:I},1s:u(5r,5y,7j,7g){E 5r<k.12.F.A.4t.x&&(5r+7j)>k.12.F.A.4t.x&&5y<k.12.F.A.4t.y&&(5y+7g)>k.12.F.A.4t.y?1b:I},5l:I,3W:{},8W:0,3J:{},ea:u(C){if(k.12.F==U){E}D i;k.1x.3W={};D cZ=I;1Y(i in k.1x.3J){if(k.1x.3J[i]!=U){D 1k=k.1x.3J[i].K(0);if(k(k.12.F).is(\'.\'+1k.1i.a)){if(1k.1i.m==I){1k.1i.p=k.21(k.1a.2R(1k),k.1a.82(1k));1k.1i.m=1b}if(1k.1i.ac){k.1x.3J[i].2Z(1k.1i.ac)}k.1x.3W[i]=k.1x.3J[i];if(k.1t&&1k.1i.s&&k.12.F.A.48){1k.1i.el=k(\'.\'+1k.1i.a,1k);C.18.19=\'1n\';k.1t.c5(1k);1k.1i.9Z=k.1t.8o(k.1p(1k,\'id\')).7U;C.18.19=C.A.7i;cZ=1b}if(1k.1i.9v){1k.1i.9v.1F(k.1x.3J[i].K(0),[k.12.F])}}}}if(cZ){k.1t.28()}},ek:u(){k.1x.3W={};1Y(i in k.1x.3J){if(k.1x.3J[i]!=U){D 1k=k.1x.3J[i].K(0);if(k(k.12.F).is(\'.\'+1k.1i.a)){1k.1i.p=k.21(k.1a.2R(1k),k.1a.82(1k));if(1k.1i.ac){k.1x.3J[i].2Z(1k.1i.ac)}k.1x.3W[i]=k.1x.3J[i];if(k.1t&&1k.1i.s&&k.12.F.A.48){1k.1i.el=k(\'.\'+1k.1i.a,1k);C.18.19=\'1n\';k.1t.c5(1k);C.18.19=C.A.7i}}}}},a3:u(e){if(k.12.F==U){E}k.1x.5l=I;D i;D cb=I;D ec=0;1Y(i in k.1x.3W){D 1k=k.1x.3W[i].K(0);if(k.1x.5l==I&&k.1x[1k.1i.t](1k.1i.p.x,1k.1i.p.y,1k.1i.p.1D,1k.1i.p.hb)){if(1k.1i.hc&&1k.1i.h==I){k.1x.3W[i].2Z(1k.1i.hc)}if(1k.1i.h==I&&1k.1i.7T){cb=1b}1k.1i.h=1b;k.1x.5l=1k;if(k.1t&&1k.1i.s&&k.12.F.A.48){k.1t.1c.K(0).3b=1k.1i.eb;k.1t.a3(1k)}ec++}P if(1k.1i.h==1b){if(1k.1i.7Q){1k.1i.7Q.1F(1k,[e,k.12.1c.K(0).77,1k.1i.fx])}if(1k.1i.hc){k.1x.3W[i].4p(1k.1i.hc)}1k.1i.h=I}}if(k.1t&&!k.1x.5l&&k.12.F.48){k.1t.1c.K(0).18.19=\'1n\'}if(cb){k.1x.5l.1i.7T.1F(k.1x.5l,[e,k.12.1c.K(0).77])}},ed:u(e){D i;1Y(i in k.1x.3W){D 1k=k.1x.3W[i].K(0);if(1k.1i.ac){k.1x.3W[i].4p(1k.1i.ac)}if(1k.1i.hc){k.1x.3W[i].4p(1k.1i.hc)}if(1k.1i.s){k.1t.7V[k.1t.7V.1h]=i}if(1k.1i.9r&&1k.1i.h==1b){1k.1i.h=I;1k.1i.9r.1F(1k,[e,1k.1i.fx])}1k.1i.m=I;1k.1i.h=I}k.1x.3W={}},58:u(){E q.1B(u(){if(q.9u){if(q.1i.s){id=k.1p(q,\'id\');k.1t.5j[id]=U;k(\'.\'+q.1i.a,q).a4()}k.1x.3J[\'d\'+q.bn]=U;q.9u=I;q.f=U}})},2s:u(o){E q.1B(u(){if(q.9u==1b||!o.3P||!k.1a||!k.12){E}q.1i={a:o.3P,ac:o.a8||I,hc:o.a7||I,eb:o.4V||I,9r:o.kO||o.9r||I,7T:o.7T||o.dN||I,7Q:o.7Q||o.dz||I,9v:o.9v||I,t:o.6n&&(o.6n==\'ee\'||o.6n==\'by\')?o.6n:\'1s\',fx:o.fx?o.fx:I,m:I,h:I};if(o.bD==1b&&k.1t){id=k.1p(q,\'id\');k.1t.5j[id]=q.1i.a;q.1i.s=1b;if(o.2T){q.1i.2T=o.2T;q.1i.9Z=k.1t.8o(id).7U}}q.9u=1b;q.bn=T(14.6w()*cd);k.1x.3J[\'d\'+q.bn]=k(q);k.1x.8W++})}};k.fn.21({df:k.1x.58,dO:k.1x.2s});k.kH=k.1x.ek;k.R={1A:U,3Q:U,F:U,1s:U,1q:U,Y:U,7r:u(e){k.R.F=(q.a2)?q.a2:q;k.R.1s=k.1a.44(e);k.R.1q={Z:T(k(k.R.F).B(\'Z\'))||0,V:T(k(k.R.F).B(\'V\'))||0};k.R.Y={Q:T(k(k.R.F).B(\'Q\'))||0,O:T(k(k.R.F).B(\'O\'))||0};k(1j).1H(\'3H\',k.R.bj).1H(\'61\',k.R.bs);if(2h k.R.F.1g.ei===\'u\'){k.R.F.1g.ei.1F(k.R.F)}E I},bs:u(e){k(1j).3p(\'3H\',k.R.bj).3p(\'61\',k.R.bs);if(2h k.R.F.1g.e7===\'u\'){k.R.F.1g.e7.1F(k.R.F)}k.R.F=U},bj:u(e){if(!k.R.F){E}1s=k.1a.44(e);7u=k.R.Y.Q-k.R.1s.y+1s.y;7v=k.R.Y.O-k.R.1s.x+1s.x;7u=14.3v(14.3D(7u,k.R.F.1g.8U-k.R.1q.V),k.R.F.1g.7s);7v=14.3v(14.3D(7v,k.R.F.1g.8T-k.R.1q.Z),k.R.F.1g.7p);if(2h k.R.F.1g.4x===\'u\'){D 8J=k.R.F.1g.4x.1F(k.R.F,[7v,7u]);if(2h 8J==\'kc\'&&8J.1h==2){7v=8J[0];7u=8J[1]}}k.R.F.18.Q=7u+\'S\';k.R.F.18.O=7v+\'S\';E I},28:u(e){k(1j).1H(\'3H\',k.R.8C).1H(\'61\',k.R.8v);k.R.1A=q.1A;k.R.3Q=q.3Q;k.R.1s=k.1a.44(e);if(k.R.1A.1g.4A){k.R.1A.1g.4A.1F(k.R.1A,[q])}k.R.1q={Z:T(k(q.1A).B(\'Z\'))||0,V:T(k(q.1A).B(\'V\'))||0};k.R.Y={Q:T(k(q.1A).B(\'Q\'))||0,O:T(k(q.1A).B(\'O\'))||0};E I},8v:u(){k(1j).3p(\'3H\',k.R.8C).3p(\'61\',k.R.8v);if(k.R.1A.1g.3S){k.R.1A.1g.3S.1F(k.R.1A,[k.R.3Q])}k.R.1A=U;k.R.3Q=U},6V:u(dx,9t){E 14.3D(14.3v(k.R.1q.Z+dx*9t,k.R.1A.1g.9s),k.R.1A.1g.6q)},6Q:u(dy,9t){E 14.3D(14.3v(k.R.1q.V+dy*9t,k.R.1A.1g.8L),k.R.1A.1g.8M)},dX:u(V){E 14.3D(14.3v(V,k.R.1A.1g.8L),k.R.1A.1g.8M)},8C:u(e){if(k.R.1A==U){E}1s=k.1a.44(e);dx=1s.x-k.R.1s.x;dy=1s.y-k.R.1s.y;1E={Z:k.R.1q.Z,V:k.R.1q.V};2n={Q:k.R.Y.Q,O:k.R.Y.O};3m(k.R.3Q){1e\'e\':1E.Z=k.R.6V(dx,1);1r;1e\'eO\':1E.Z=k.R.6V(dx,1);1E.V=k.R.6Q(dy,1);1r;1e\'w\':1E.Z=k.R.6V(dx,-1);2n.O=k.R.Y.O-1E.Z+k.R.1q.Z;1r;1e\'5O\':1E.Z=k.R.6V(dx,-1);2n.O=k.R.Y.O-1E.Z+k.R.1q.Z;1E.V=k.R.6Q(dy,1);1r;1e\'7q\':1E.V=k.R.6Q(dy,-1);2n.Q=k.R.Y.Q-1E.V+k.R.1q.V;1E.Z=k.R.6V(dx,-1);2n.O=k.R.Y.O-1E.Z+k.R.1q.Z;1r;1e\'n\':1E.V=k.R.6Q(dy,-1);2n.Q=k.R.Y.Q-1E.V+k.R.1q.V;1r;1e\'9J\':1E.V=k.R.6Q(dy,-1);2n.Q=k.R.Y.Q-1E.V+k.R.1q.V;1E.Z=k.R.6V(dx,1);1r;1e\'s\':1E.V=k.R.6Q(dy,1);1r}if(k.R.1A.1g.4D){if(k.R.3Q==\'n\'||k.R.3Q==\'s\')4B=1E.V*k.R.1A.1g.4D;P 4B=1E.Z;5c=k.R.dX(4B*k.R.1A.1g.4D);4B=5c/k.R.1A.1g.4D;3m(k.R.3Q){1e\'n\':1e\'7q\':1e\'9J\':2n.Q+=1E.V-5c;1r}3m(k.R.3Q){1e\'7q\':1e\'w\':1e\'5O\':2n.O+=1E.Z-4B;1r}1E.V=5c;1E.Z=4B}if(2n.Q<k.R.1A.1g.7s){5c=1E.V+2n.Q-k.R.1A.1g.7s;2n.Q=k.R.1A.1g.7s;if(k.R.1A.1g.4D){4B=5c/k.R.1A.1g.4D;3m(k.R.3Q){1e\'7q\':1e\'w\':1e\'5O\':2n.O+=1E.Z-4B;1r}1E.Z=4B}1E.V=5c}if(2n.O<k.R.1A.1g.7p){4B=1E.Z+2n.O-k.R.1A.1g.7p;2n.O=k.R.1A.1g.7p;if(k.R.1A.1g.4D){5c=4B*k.R.1A.1g.4D;3m(k.R.3Q){1e\'n\':1e\'7q\':1e\'9J\':2n.Q+=1E.V-5c;1r}1E.V=5c}1E.Z=4B}if(2n.Q+1E.V>k.R.1A.1g.8U){1E.V=k.R.1A.1g.8U-2n.Q;if(k.R.1A.1g.4D){1E.Z=1E.V/k.R.1A.1g.4D}}if(2n.O+1E.Z>k.R.1A.1g.8T){1E.Z=k.R.1A.1g.8T-2n.O;if(k.R.1A.1g.4D){1E.V=1E.Z*k.R.1A.1g.4D}}D 6O=I;5L=k.R.1A.18;5L.O=2n.O+\'S\';5L.Q=2n.Q+\'S\';5L.Z=1E.Z+\'S\';5L.V=1E.V+\'S\';if(k.R.1A.1g.dY){6O=k.R.1A.1g.dY.1F(k.R.1A,[1E,2n]);if(6O){if(6O.1q){k.21(1E,6O.1q)}if(6O.Y){k.21(2n,6O.Y)}}}5L.O=2n.O+\'S\';5L.Q=2n.Q+\'S\';5L.Z=1E.Z+\'S\';5L.V=1E.V+\'S\';E I},2s:u(M){if(!M||!M.3U||M.3U.1K!=7n){E}E q.1B(u(){D el=q;el.1g=M;el.1g.9s=M.9s||10;el.1g.8L=M.8L||10;el.1g.6q=M.6q||6x;el.1g.8M=M.8M||6x;el.1g.7s=M.7s||-aF;el.1g.7p=M.7p||-aF;el.1g.8T=M.8T||6x;el.1g.8U=M.8U||6x;b3=k(el).B(\'Y\');if(!(b3==\'2y\'||b3==\'1O\')){el.18.Y=\'2y\'}eM=/n|9J|e|eO|s|5O|w|7q/g;1Y(i in el.1g.3U){if(i.5Z().bU(eM)!=U){if(el.1g.3U[i].1K==b5){3y=k(el.1g.3U[i]);if(3y.1P()>0){el.1g.3U[i]=3y.K(0)}}if(el.1g.3U[i].4S){el.1g.3U[i].1A=el;el.1g.3U[i].3Q=i;k(el.1g.3U[i]).1H(\'5b\',k.R.28)}}}if(el.1g.4N){if(2h el.1g.4N===\'5g\'){9K=k(el.1g.4N);if(9K.1P()>0){9K.1B(u(){q.a2=el});9K.1H(\'5b\',k.R.7r)}}P if(el.1g.4N.4S){el.1g.4N.a2=el;k(el.1g.4N).1H(\'5b\',k.R.7r)}P if(el.1g.4N==1b){k(q).1H(\'5b\',k.R.7r)}}})},58:u(){E q.1B(u(){D el=q;1Y(i in el.1g.3U){el.1g.3U[i].1A=U;el.1g.3U[i].3Q=U;k(el.1g.3U[i]).3p(\'5b\',k.R.28)}if(el.1g.4N){if(2h el.1g.4N===\'5g\'){3y=k(el.1g.4N);if(3y.1P()>0){3y.3p(\'5b\',k.R.7r)}}P if(el.1g.4N==1b){k(q).3p(\'5b\',k.R.7r)}}el.1g=U})}};k.fn.21({j5:k.R.2s,j4:k.R.58});k.2u=U;k.7Z=I;k.3n=U;k.81=[];k.a0=u(e){D 3O=e.7F||e.7A||-1;if(3O==17||3O==16){k.7Z=1b}};k.9Y=u(e){k.7Z=I};k.eW=u(e){q.f.1s=k.1a.44(e);q.f.1M=k.21(k.1a.2R(q),k.1a.2p(q));q.f.3a=k.1a.6W(q);q.f.1s.x-=q.f.1M.x;q.f.1s.y-=q.f.1M.y;if(q.f.hc)k.2u.2Z(q.f.hc);k.2u.B({19:\'2E\',Z:\'83\',V:\'83\'});if(q.f.o){k.2u.B(\'1J\',q.f.o)}k.3n=q;k.8K=I;k.81=[];q.f.el.1B(u(){q.1M={x:q.8n+(q.4Y&&!k.3h.7N?T(q.4Y.5a)||0:0)+(k.3n.3g||0),y:q.8t+(q.4Y&&!k.3h.7N?T(q.4Y.4Z)||0:0)+(k.3n.2V||0),1D:q.4b,hb:q.63};if(q.s==1b){if(k.7Z==I){q.s=I;k(q).4p(k.3n.f.7X)}P{k.8K=1b;k.81[k.81.1h]=k.1p(q,\'id\')}}});k(q).1R(k.2u.K(0));q.f.93=k.1a.6h(k.2u[0],1b);k.a1.1F(q,[e]);k(1j).1H(\'3H\',k.a1).1H(\'61\',k.bT);E I};k.a1=u(e){if(!k.3n)E;k.eU.1F(k.3n,[e])};k.eU=u(e){if(!k.3n)E;D 1s=k.1a.44(e);D 3a=k.1a.6W(k.3n);1s.x+=3a.l-q.f.3a.l-q.f.1M.x;1s.y+=3a.t-q.f.3a.t-q.f.1M.y;D 8D=14.3D(1s.x,q.f.1s.x);D 5O=14.3D(14.3R(1s.x-q.f.1s.x),14.3R(q.f.3a.w-8D));D 9f=14.3D(1s.y,q.f.1s.y);D 8R=14.3D(14.3R(1s.y-q.f.1s.y),14.3R(q.f.3a.h-9f));if(q.2V>0&&1s.y-20<q.2V){D 3T=14.3D(3a.t,10);9f-=3T;8R+=3T;q.2V-=3T}P if(q.2V+q.f.1M.h<q.f.3a.h&&1s.y+20>q.2V+q.f.1M.h){D 3T=14.3D(q.f.3a.h-q.2V,10);q.2V+=3T;if(q.2V!=3a.t)8R+=3T}if(q.3g>0&&1s.x-20<q.3g){D 3T=14.3D(3a.l,10);8D-=3T;5O+=3T;q.3g-=3T}P if(q.3g+q.f.1M.w<q.f.3a.w&&1s.x+20>q.3g+q.f.1M.w){D 3T=14.3D(q.f.3a.w-q.3g,10);q.3g+=3T;if(q.3g!=3a.l)5O+=3T}k.2u.B({O:8D+\'S\',Q:9f+\'S\',Z:5O-(q.f.93.l+q.f.93.r)+\'S\',V:8R-(q.f.93.t+q.f.93.b)+\'S\'});k.2u.l=8D+q.f.3a.l;k.2u.t=9f+q.f.3a.t;k.2u.r=k.2u.l+5O;k.2u.b=k.2u.t+8R;k.8K=I;q.f.el.1B(u(){9k=k.81.3F(k.1p(q,\'id\'));if(!(q.1M.x>k.2u.r||(q.1M.x+q.1M.1D)<k.2u.l||q.1M.y>k.2u.b||(q.1M.y+q.1M.hb)<k.2u.t)){k.8K=1b;if(q.s!=1b){q.s=1b;k(q).2Z(k.3n.f.7X)}if(9k!=-1){q.s=I;k(q).4p(k.3n.f.7X)}}P if((q.s==1b)&&(9k==-1)){q.s=I;k(q).4p(k.3n.f.7X)}P if((!q.s)&&(k.7Z==1b)&&(9k!=-1)){q.s=1b;k(q).2Z(k.3n.f.7X)}});E I};k.bT=u(e){if(!k.3n)E;k.ex.1F(k.3n,[e])};k.ex=u(e){k(1j).3p(\'3H\',k.a1).3p(\'61\',k.bT);if(!k.3n)E;k.2u.B(\'19\',\'1n\');if(q.f.hc)k.2u.4p(q.f.hc);k.3n=I;k(\'2e\').1R(k.2u.K(0));if(k.8K==1b){if(q.f.8Y)q.f.8Y(k.c2(k.1p(q,\'id\')))}P{if(q.f.8X)q.f.8X(k.c2(k.1p(q,\'id\')))}k.81=[]};k.c2=u(s){D h=\'\';D o=[];if(a=k(\'#\'+s)){a.K(0).f.el.1B(u(){if(q.s==1b){if(h.1h>0){h+=\'&\'}h+=s+\'[]=\'+k.1p(q,\'id\');o[o.1h]=k.1p(q,\'id\')}})}E{7U:h,o:o}};k.fn.jZ=u(o){if(!k.2u){k(\'2e\',1j).1R(\'<26 id="2u"></26>\').1H(\'7E\',k.a0).1H(\'6S\',k.9Y);k.2u=k(\'#2u\');k.2u.B({Y:\'1O\',19:\'1n\'});if(1V.2l){k(\'2e\',1j).1H(\'7E\',k.a0).1H(\'6S\',k.9Y)}P{k(1j).1H(\'7E\',k.a0).1H(\'6S\',k.9Y)}}if(!o){o={}}E q.1B(u(){if(q.eX)E;q.eX=1b;q.f={a:o.3P,o:o.1J?2m(o.1J):I,7X:o.eE?o.eE:I,hc:o.4V?o.4V:I,8Y:o.8Y?o.8Y:I,8X:o.8X?o.8X:I};q.f.el=k(\'.\'+o.3P);k(q).1H(\'5b\',k.eW)})};k.1t={7V:[],5j:{},1c:I,7Y:U,28:u(){if(k.12.F==U){E}D 4M,3A,c,cs;k.1t.1c.K(0).3b=k.12.F.A.6p;4M=k.1t.1c.K(0).18;4M.19=\'2E\';k.1t.1c.1C=k.21(k.1a.2R(k.1t.1c.K(0)),k.1a.2p(k.1t.1c.K(0)));4M.Z=k.12.F.A.1C.1D+\'S\';4M.V=k.12.F.A.1C.hb+\'S\';3A=k.1a.c8(k.12.F);4M.5o=3A.t;4M.5p=3A.r;4M.5m=3A.b;4M.5k=3A.l;if(k.12.F.A.4j==1b){c=k.12.F.dn(1b);cs=c.18;cs.5o=\'3c\';cs.5p=\'3c\';cs.5m=\'3c\';cs.5k=\'3c\';cs.19=\'2E\';k.1t.1c.5t().1R(c)}k(k.12.F).dj(k.1t.1c.K(0));k.12.F.18.19=\'1n\'},dp:u(e){if(!e.A.48&&k.1x.5l.bD){if(e.A.3S)e.A.3S.1F(F);k(e).B(\'Y\',e.A.c4||e.A.4m);k(e).a4();k(k.1x.5l).dd(e)}k.1t.1c.4p(e.A.6p).3w(\'&7J;\');k.1t.7Y=U;D 4M=k.1t.1c.K(0).18;4M.19=\'1n\';k.1t.1c.dj(e);if(e.A.fx>0){k(e).7m(e.A.fx)}k(\'2e\').1R(k.1t.1c.K(0));D 86=[];D 8d=I;1Y(D i=0;i<k.1t.7V.1h;i++){D 1k=k.1x.3J[k.1t.7V[i]].K(0);D id=k.1p(1k,\'id\');D 8I=k.1t.8o(id);if(1k.1i.9Z!=8I.7U){1k.1i.9Z=8I.7U;if(8d==I&&1k.1i.2T){8d=1k.1i.2T}8I.id=id;86[86.1h]=8I}}k.1t.7V=[];if(8d!=I&&86.1h>0){8d(86)}},a3:u(e,o){if(!k.12.F)E;D 6i=I;D i=0;if(e.1i.el.1P()>0){1Y(i=e.1i.el.1P();i>0;i--){if(e.1i.el.K(i-1)!=k.12.F){if(!e.5V.bM){if((e.1i.el.K(i-1).1M.y+e.1i.el.K(i-1).1M.hb/2)>k.12.F.A.2r){6i=e.1i.el.K(i-1)}P{1r}}P{if((e.1i.el.K(i-1).1M.x+e.1i.el.K(i-1).1M.1D/2)>k.12.F.A.2x&&(e.1i.el.K(i-1).1M.y+e.1i.el.K(i-1).1M.hb/2)>k.12.F.A.2r){6i=e.1i.el.K(i-1)}}}}}if(6i&&k.1t.7Y!=6i){k.1t.7Y=6i;k(6i).k6(k.1t.1c.K(0))}P if(!6i&&(k.1t.7Y!=U||k.1t.1c.K(0).3e!=e)){k.1t.7Y=U;k(e).1R(k.1t.1c.K(0))}k.1t.1c.K(0).18.19=\'2E\'},c5:u(e){if(k.12.F==U){E}e.1i.el.1B(u(){q.1M=k.21(k.1a.82(q),k.1a.2R(q))})},8o:u(s){D i;D h=\'\';D o={};if(s){if(k.1t.5j[s]){o[s]=[];k(\'#\'+s+\' .\'+k.1t.5j[s]).1B(u(){if(h.1h>0){h+=\'&\'}h+=s+\'[]=\'+k.1p(q,\'id\');o[s][o[s].1h]=k.1p(q,\'id\')})}P{1Y(a in s){if(k.1t.5j[s[a]]){o[s[a]]=[];k(\'#\'+s[a]+\' .\'+k.1t.5j[s[a]]).1B(u(){if(h.1h>0){h+=\'&\'}h+=s[a]+\'[]=\'+k.1p(q,\'id\');o[s[a]][o[s[a]].1h]=k.1p(q,\'id\')})}}}}P{1Y(i in k.1t.5j){o[i]=[];k(\'#\'+i+\' .\'+k.1t.5j[i]).1B(u(){if(h.1h>0){h+=\'&\'}h+=i+\'[]=\'+k.1p(q,\'id\');o[i][o[i].1h]=k.1p(q,\'id\')})}}E{7U:h,o:o}},dc:u(e){if(!e.jJ){E}E q.1B(u(){if(!q.5V||!k(e).is(\'.\'+q.5V.3P))k(e).2Z(q.5V.3P);k(e).6Y(q.5V.A)})},58:u(){E q.1B(u(){k(\'.\'+q.5V.3P).a4();k(q).df();q.5V=U;q.dD=U})},2s:u(o){if(o.3P&&k.1a&&k.12&&k.1x){if(!k.1t.1c){k(\'2e\',1j).1R(\'<26 id="dt">&7J;</26>\');k.1t.1c=k(\'#dt\');k.1t.1c.K(0).18.19=\'1n\'}q.dO({3P:o.3P,a8:o.a8?o.a8:I,a7:o.a7?o.a7:I,4V:o.4V?o.4V:I,7T:o.7T||o.dN,7Q:o.7Q||o.dz,bD:1b,2T:o.2T||o.jL,fx:o.fx?o.fx:I,4j:o.4j?1b:I,6n:o.6n?o.6n:\'by\'});E q.1B(u(){D A={6o:o.6o?1b:I,dF:6x,1J:o.1J?2m(o.1J):I,6p:o.4V?o.4V:I,fx:o.fx?o.fx:I,48:1b,4j:o.4j?1b:I,3y:o.3y?o.3y:U,2o:o.2o?o.2o:U,4A:o.4A&&o.4A.1K==2C?o.4A:I,4x:o.4x&&o.4x.1K==2C?o.4x:I,3S:o.3S&&o.3S.1K==2C?o.3S:I,1N:/4i|4a/.43(o.1N)?o.1N:I,6m:o.6m?T(o.6m)||0:I,2S:o.2S?o.2S:I};k(\'.\'+o.3P,q).6Y(A);q.dD=1b;q.5V={3P:o.3P,6o:o.6o?1b:I,dF:6x,1J:o.1J?2m(o.1J):I,6p:o.4V?o.4V:I,fx:o.fx?o.fx:I,48:1b,4j:o.4j?1b:I,3y:o.3y?o.3y:U,2o:o.2o?o.2o:U,bM:o.bM?1b:I,A:A}})}}};k.fn.21({jR:k.1t.2s,dd:k.1t.dc,jQ:k.1t.58});k.jN=k.1t.8o;k.3d={bG:1,f0:u(3u){D 3u=3u;E q.1B(u(){q.4r.6T.1B(u(a6){k.3d.59(q,3u[a6])})})},K:u(){D 3u=[];q.1B(u(bJ){if(q.bF){3u[bJ]=[];D C=q;D 1q=k.1a.2p(q);q.4r.6T.1B(u(a6){D x=q.8n;D y=q.8t;99=T(x*2b/(1q.w-q.4b));8a=T(y*2b/(1q.h-q.63));3u[bJ][a6]=[99||0,8a||0,x||0,y||0]})}});E 3u},bO:u(C){C.A.fK=C.A.24.w-C.A.1C.1D;C.A.fN=C.A.24.h-C.A.1C.hb;if(C.9P.4r.bE){a5=C.9P.4r.6T.K(C.bR+1);if(a5){C.A.24.w=(T(k(a5).B(\'O\'))||0)+C.A.1C.1D;C.A.24.h=(T(k(a5).B(\'Q\'))||0)+C.A.1C.hb}9X=C.9P.4r.6T.K(C.bR-1);if(9X){D bL=T(k(9X).B(\'O\'))||0;D bK=T(k(9X).B(\'O\'))||0;C.A.24.x+=bL;C.A.24.y+=bK;C.A.24.w-=bL;C.A.24.h-=bK}}C.A.fW=C.A.24.w-C.A.1C.1D;C.A.fV=C.A.24.h-C.A.1C.hb;if(C.A.2K){C.A.gx=((C.A.24.w-C.A.1C.1D)/C.A.2K)||1;C.A.gy=((C.A.24.h-C.A.1C.hb)/C.A.2K)||1;C.A.fY=C.A.fW/C.A.2K;C.A.fS=C.A.fV/C.A.2K}C.A.24.dx=C.A.24.x-C.A.2c.x;C.A.24.dy=C.A.24.y-C.A.2c.y;k.12.1c.B(\'94\',\'aG\')},3z:u(C,x,y){if(C.A.2K){fZ=T(x/C.A.fY);99=fZ*2b/C.A.2K;fL=T(y/C.A.fS);8a=fL*2b/C.A.2K}P{99=T(x*2b/C.A.fK);8a=T(y*2b/C.A.fN)}C.A.bQ=[99||0,8a||0,x||0,y||0];if(C.A.3z)C.A.3z.1F(C,C.A.bQ)},g4:u(2l){3O=2l.7F||2l.7A||-1;3m(3O){1e 35:k.3d.59(q.3Z,[9W,9W]);1r;1e 36:k.3d.59(q.3Z,[-9W,-9W]);1r;1e 37:k.3d.59(q.3Z,[-q.3Z.A.gx||-1,0]);1r;1e 38:k.3d.59(q.3Z,[0,-q.3Z.A.gy||-1]);1r;1e 39:k.3d.59(q.3Z,[q.3Z.A.gx||1,0]);1r;1e 40:k.12.59(q.3Z,[0,q.3Z.A.gy||1]);1r}},59:u(C,Y){if(!C.A){E}C.A.1C=k.21(k.1a.2R(C),k.1a.2p(C));C.A.2c={x:T(k.B(C,\'O\'))||0,y:T(k.B(C,\'Q\'))||0};C.A.4m=k.B(C,\'Y\');if(C.A.4m!=\'2y\'&&C.A.4m!=\'1O\'){C.18.Y=\'2y\'}k.12.bP(C);k.3d.bO(C);dx=T(Y[0])||0;dy=T(Y[1])||0;2x=C.A.2c.x+dx;2r=C.A.2c.y+dy;if(C.A.2K){3q=k.12.bI.1F(C,[2x,2r,dx,dy]);if(3q.1K==7n){dx=3q.dx;dy=3q.dy}2x=C.A.2c.x+dx;2r=C.A.2c.y+dy}3q=k.12.bH.1F(C,[2x,2r,dx,dy]);if(3q&&3q.1K==7n){dx=3q.dx;dy=3q.dy}2x=C.A.2c.x+dx;2r=C.A.2c.y+dy;if(C.A.5i&&(C.A.3z||C.A.2T)){k.3d.3z(C,2x,2r)}2x=!C.A.1N||C.A.1N==\'4a\'?2x:C.A.2c.x||0;2r=!C.A.1N||C.A.1N==\'4i\'?2r:C.A.2c.y||0;C.18.O=2x+\'S\';C.18.Q=2r+\'S\'},2s:u(o){E q.1B(u(){if(q.bF==1b||!o.3P||!k.1a||!k.12||!k.1x){E}5N=k(o.3P,q);if(5N.1P()==0){E}D 4K={2o:\'96\',5i:1b,3z:o.3z&&o.3z.1K==2C?o.3z:U,2T:o.2T&&o.2T.1K==2C?o.2T:U,3y:q,1J:o.1J||I};if(o.2K&&T(o.2K)){4K.2K=T(o.2K)||1;4K.2K=4K.2K>0?4K.2K:1}if(5N.1P()==1)5N.6Y(4K);P{k(5N.K(0)).6Y(4K);4K.3y=U;5N.6Y(4K)}5N.7E(k.3d.g4);5N.1p(\'bG\',k.3d.bG++);q.bF=1b;q.4r={};q.4r.g6=4K.g6;q.4r.2K=4K.2K;q.4r.6T=5N;q.4r.bE=o.bE?1b:I;bS=q;bS.4r.6T.1B(u(2I){q.bR=2I;q.9P=bS});if(o.3u&&o.3u.1K==7b){1Y(i=o.3u.1h-1;i>=0;i--){if(o.3u[i].1K==7b&&o.3u[i].1h==2){el=q.4r.6T.K(i);if(el.4S){k.3d.59(el,o.3u[i])}}}}})}};k.fn.21({jV:k.3d.2s,k9:k.3d.f0,kb:k.3d.K});k.2t={6J:U,7c:I,9O:U,6D:u(e){k.2t.7c=1b;k.2t.22(e,q,1b)},bx:u(e){if(k.2t.6J!=q)E;k.2t.7c=I;k.2t.2G(e,q)},22:u(e,el,7c){if(k.2t.6J!=U)E;if(!el){el=q}k.2t.6J=el;1M=k.21(k.1a.2R(el),k.1a.2p(el));8G=k(el);45=8G.1p(\'45\');3f=8G.1p(\'3f\');if(45){k.2t.9O=45;8G.1p(\'45\',\'\');k(\'#fF\').3w(45);if(3f)k(\'#c9\').3w(3f.4v(\'k4://\',\'\'));P k(\'#c9\').3w(\'\');1c=k(\'#8V\');if(el.4T.3b){1c.K(0).3b=el.4T.3b}P{1c.K(0).3b=\'\'}c7=k.1a.2p(1c.K(0));fj=7c&&el.4T.Y==\'c3\'?\'4l\':el.4T.Y;3m(fj){1e\'Q\':2r=1M.y-c7.hb;2x=1M.x;1r;1e\'O\':2r=1M.y;2x=1M.x-c7.1D;1r;1e\'2N\':2r=1M.y;2x=1M.x+1M.1D;1r;1e\'c3\':k(\'2e\').1H(\'3H\',k.2t.3H);1s=k.1a.44(e);2r=1s.y+15;2x=1s.x+15;1r;aG:2r=1M.y+1M.hb;2x=1M.x;1r}1c.B({Q:2r+\'S\',O:2x+\'S\'});if(el.4T.53==I){1c.22()}P{1c.7m(el.4T.53)}if(el.4T.2U)el.4T.2U.1F(el);8G.1H(\'8q\',k.2t.2G).1H(\'5I\',k.2t.bx)}},3H:u(e){if(k.2t.6J==U){k(\'2e\').3p(\'3H\',k.2t.3H);E}1s=k.1a.44(e);k(\'#8V\').B({Q:1s.y+15+\'S\',O:1s.x+15+\'S\'})},2G:u(e,el){if(!el){el=q}if(k.2t.7c!=1b&&k.2t.6J==el){k.2t.6J=U;k(\'#8V\').7k(1);k(el).1p(\'45\',k.2t.9O).3p(\'8q\',k.2t.2G).3p(\'5I\',k.2t.bx);if(el.4T.3i)el.4T.3i.1F(el);k.2t.9O=U}},2s:u(M){if(!k.2t.1c){k(\'2e\').1R(\'<26 id="8V"><26 id="fF"></26><26 id="c9"></26></26>\');k(\'#8V\').B({Y:\'1O\',3B:6x,19:\'1n\'});k.2t.1c=1b}E q.1B(u(){if(k.1p(q,\'45\')){q.4T={Y:/Q|4l|O|2N|c3/.43(M.Y)?M.Y:\'4l\',3b:M.3b?M.3b:I,53:M.53?M.53:I,2U:M.2U&&M.2U.1K==2C?M.2U:I,3i:M.3i&&M.3i.1K==2C?M.3i:I};D el=k(q);el.1H(\'aV\',k.2t.22);el.1H(\'6D\',k.2t.6D)}})}};k.fn.k0=k.2t.2s;k.21({G:{bV:u(p,n,1W,1I,1m){E((-14.5v(p*14.2Q)/2)+0.5)*1I+1W},k2:u(p,n,1W,1I,1m){E 1I*(n/=1m)*n*n+1W},fG:u(p,n,1W,1I,1m){E-1I*((n=n/1m-1)*n*n*n-1)+1W},k1:u(p,n,1W,1I,1m){if((n/=1m/2)<1)E 1I/2*n*n*n*n+1W;E-1I/2*((n-=2)*n*n*n-2)+1W},9c:u(p,n,1W,1I,1m){if((n/=1m)<(1/2.75)){E 1I*(7.9N*n*n)+1W}P if(n<(2/2.75)){E 1I*(7.9N*(n-=(1.5/2.75))*n+.75)+1W}P if(n<(2.5/2.75)){E 1I*(7.9N*(n-=(2.25/2.75))*n+.jC)+1W}P{E 1I*(7.9N*(n-=(2.jB/2.75))*n+.jd)+1W}},bY:u(p,n,1W,1I,1m){if(k.G.9c)E 1I-k.G.9c(p,1m-n,0,1I,1m)+1W;E 1W+1I},jc:u(p,n,1W,1I,1m){if(k.G.bY&&k.G.9c)if(n<1m/2)E k.G.bY(p,n*2,0,1I,1m)*.5+1W;E k.G.9c(p,n*2-1m,0,1I,1m)*.5+1I*.5+1W;E 1W+1I},jb:u(p,n,1W,1I,1m){D a,s;if(n==0)E 1W;if((n/=1m)==1)E 1W+1I;a=1I*0.3;p=1m*.3;if(a<14.3R(1I)){a=1I;s=p/4}P{s=p/(2*14.2Q)*14.c0(1I/a)}E-(a*14.5Y(2,10*(n-=1))*14.98((n*1m-s)*(2*14.2Q)/p))+1W},je:u(p,n,1W,1I,1m){D a,s;if(n==0)E 1W;if((n/=1m/2)==2)E 1W+1I;a=1I*0.3;p=1m*.3;if(a<14.3R(1I)){a=1I;s=p/4}P{s=p/(2*14.2Q)*14.c0(1I/a)}E a*14.5Y(2,-10*n)*14.98((n*1m-s)*(2*14.2Q)/p)+1I+1W},jf:u(p,n,1W,1I,1m){D a,s;if(n==0)E 1W;if((n/=1m/2)==2)E 1W+1I;a=1I*0.3;p=1m*.3;if(a<14.3R(1I)){a=1I;s=p/4}P{s=p/(2*14.2Q)*14.c0(1I/a)}if(n<1){E-.5*(a*14.5Y(2,10*(n-=1))*14.98((n*1m-s)*(2*14.2Q)/p))+1W}E a*14.5Y(2,-10*(n-=1))*14.98((n*1m-s)*(2*14.2Q)/p)*.5+1I+1W}}});k.fn.21({fz:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5W(q,H,J,\'4U\',G)})},fP:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5W(q,H,J,\'4y\',G)})},j9:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5W(q,H,J,\'f8\',G)})},j3:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5W(q,H,J,\'O\',G)})},j2:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5W(q,H,J,\'2N\',G)})},j1:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5W(q,H,J,\'fh\',G)})}});k.fx.5W=u(e,H,J,2P,G){if(!k.4O(e)){k.2L(e,\'1o\');E I}D z=q;z.el=k(e);z.1P=k.1a.2p(e);z.G=2h J==\'5g\'?J:G||U;if(!e.4s)e.4s=z.el.B(\'19\');if(2P==\'f8\'){2P=z.el.B(\'19\')==\'1n\'?\'4y\':\'4U\'}P if(2P==\'fh\'){2P=z.el.B(\'19\')==\'1n\'?\'2N\':\'O\'}z.el.22();z.H=H;z.J=2h J==\'u\'?J:U;z.fx=k.fx.9h(e);z.2P=2P;z.23=u(){if(z.J&&z.J.1K==2C){z.J.1F(z.el.K(0))}if(z.2P==\'4y\'||z.2P==\'2N\'){z.el.B(\'19\',z.el.K(0).4s==\'1n\'?\'2E\':z.el.K(0).4s)}P{z.el.2G()}k.fx.9g(z.fx.3o.K(0),z.fx.W);k.2L(z.el.K(0),\'1o\')};3m(z.2P){1e\'4U\':6d=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,z.23),\'V\');6d.1L(z.fx.W.1q.hb,0);1r;1e\'4y\':z.fx.3o.B(\'V\',\'83\');z.el.22();6d=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,z.23),\'V\');6d.1L(0,z.fx.W.1q.hb);1r;1e\'O\':6d=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,z.23),\'Z\');6d.1L(z.fx.W.1q.1D,0);1r;1e\'2N\':z.fx.3o.B(\'Z\',\'83\');z.el.22();6d=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,z.23),\'Z\');6d.1L(0,z.fx.W.1q.1D);1r}};k.fn.kd=u(5w,J){E q.1w(\'1o\',u(){if(!k.4O(q)){k.2L(q,\'1o\');E I}D e=11 k.fx.fa(q,5w,J);e.bc()})};k.fx.fa=u(e,5w,J){D z=q;z.el=k(e);z.el.22();z.J=J;z.5w=T(5w)||40;z.W={};z.W.Y=z.el.B(\'Y\');z.W.Q=T(z.el.B(\'Q\'))||0;z.W.O=T(z.el.B(\'O\'))||0;if(z.W.Y!=\'2y\'&&z.W.Y!=\'1O\'){z.el.B(\'Y\',\'2y\')}z.41=5;z.5D=1;z.bc=u(){z.5D++;z.e=11 k.fx(z.el.K(0),{1m:j6,23:u(){z.e=11 k.fx(z.el.K(0),{1m:80,23:u(){z.5w=T(z.5w/2);if(z.5D<=z.41)z.bc();P{z.el.B(\'Y\',z.W.Y).B(\'Q\',z.W.Q+\'S\').B(\'O\',z.W.O+\'S\');k.2L(z.el.K(0),\'1o\');if(z.J&&z.J.1K==2C){z.J.1F(z.el.K(0))}}}},\'Q\');z.e.1L(z.W.Q-z.5w,z.W.Q)}},\'Q\');z.e.1L(z.W.Q,z.W.Q-z.5w)}};k.fn.21({ji:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'4y\',\'4d\',G)})},jj:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'4y\',\'in\',G)})},jw:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'4y\',\'3Y\',G)})},jv:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'4U\',\'4d\',G)})},ju:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'4U\',\'in\',G)})},jx:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'4U\',\'3Y\',G)})},jy:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'O\',\'4d\',G)})},jz:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'O\',\'in\',G)})},jt:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'O\',\'3Y\',G)})},js:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'2N\',\'4d\',G)})},jm:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'2N\',\'in\',G)})},jl:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.4k(q,H,J,\'2N\',\'3Y\',G)})}});k.fx.4k=u(e,H,J,2P,1u,G){if(!k.4O(e)){k.2L(e,\'1o\');E I}D z=q;z.el=k(e);z.G=2h J==\'5g\'?J:G||U;z.W={};z.W.Y=z.el.B(\'Y\');z.W.Q=z.el.B(\'Q\');z.W.O=z.el.B(\'O\');if(!e.4s)e.4s=z.el.B(\'19\');if(1u==\'3Y\'){1u=z.el.B(\'19\')==\'1n\'?\'in\':\'4d\'}z.el.22();if(z.W.Y!=\'2y\'&&z.W.Y!=\'1O\'){z.el.B(\'Y\',\'2y\')}z.1u=1u;J=2h J==\'u\'?J:U;8y=1;3m(2P){1e\'4U\':z.e=11 k.fx(z.el.K(0),k.H(H-15,z.G,J),\'Q\');z.68=2m(z.W.Q)||0;z.9L=z.fM;8y=-1;1r;1e\'4y\':z.e=11 k.fx(z.el.K(0),k.H(H-15,z.G,J),\'Q\');z.68=2m(z.W.Q)||0;z.9L=z.fM;1r;1e\'2N\':z.e=11 k.fx(z.el.K(0),k.H(H-15,z.G,J),\'O\');z.68=2m(z.W.O)||0;z.9L=z.f4;1r;1e\'O\':z.e=11 k.fx(z.el.K(0),k.H(H-15,z.G,J),\'O\');z.68=2m(z.W.O)||0;z.9L=z.f4;8y=-1;1r}z.e2=11 k.fx(z.el.K(0),k.H(H,z.G,u(){z.el.B(z.W);if(z.1u==\'4d\'){z.el.B(\'19\',\'1n\')}P z.el.B(\'19\',z.el.K(0).4s==\'1n\'?\'2E\':z.el.K(0).4s);k.2L(z.el.K(0),\'1o\')}),\'1J\');if(1u==\'in\'){z.e.1L(z.68+2b*8y,z.68);z.e2.1L(0,1)}P{z.e.1L(z.68,z.68+2b*8y);z.e2.1L(1,0)}};k.fn.21({jn:u(H,V,J,G){E q.1w(\'1o\',u(){11 k.fx.9M(q,H,V,J,\'g7\',G)})},jo:u(H,V,J,G){E q.1w(\'1o\',u(){11 k.fx.9M(q,H,V,J,\'9Q\',G)})},jr:u(H,V,J,G){E q.1w(\'1o\',u(){11 k.fx.9M(q,H,V,J,\'3Y\',G)})}});k.fx.9M=u(e,H,V,J,1u,G){if(!k.4O(e)){k.2L(e,\'1o\');E I}D z=q;z.el=k(e);z.G=2h J==\'5g\'?J:G||U;z.J=2h J==\'u\'?J:U;if(1u==\'3Y\'){1u=z.el.B(\'19\')==\'1n\'?\'9Q\':\'g7\'}z.H=H;z.V=V&&V.1K==cR?V:20;z.fx=k.fx.9h(e);z.1u=1u;z.23=u(){if(z.J&&z.J.1K==2C){z.J.1F(z.el.K(0))}if(z.1u==\'9Q\'){z.el.22()}P{z.el.2G()}k.fx.9g(z.fx.3o.K(0),z.fx.W);k.2L(z.el.K(0),\'1o\')};if(z.1u==\'9Q\'){z.el.22();z.fx.3o.B(\'V\',z.V+\'S\').B(\'Z\',\'83\');z.ef=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,u(){z.ef=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,z.23),\'V\');z.ef.1L(z.V,z.fx.W.1q.hb)}),\'Z\');z.ef.1L(0,z.fx.W.1q.1D)}P{z.ef=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,u(){z.ef=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G,z.23),\'Z\');z.ef.1L(z.fx.W.1q.1D,0)}),\'V\');z.ef.1L(z.fx.W.1q.hb,z.V)}};k.fn.21({jq:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.6z(q,H,1,2b,1b,J,\'f1\',G)})},jp:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.6z(q,H,2b,1,1b,J,\'d2\',G)})},kt:u(H,J,G){E q.1w(\'1o\',u(){D G=G||\'fG\';11 k.fx.6z(q,H,2b,fd,1b,J,\'6l\',G)})},6z:u(H,5d,4L,6E,J,G){E q.1w(\'1o\',u(){11 k.fx.6z(q,H,5d,4L,6E,J,\'6z\',G)})}});k.fx.6z=u(e,H,5d,4L,6E,J,1u,G){if(!k.4O(e)){k.2L(e,\'1o\');E I}D z=q;z.el=k(e);z.5d=T(5d)||2b;z.4L=T(4L)||2b;z.G=2h J==\'5g\'?J:G||U;z.J=2h J==\'u\'?J:U;z.1m=k.H(H).1m;z.6E=6E||U;z.2f=k.1a.2p(e);z.W={Z:z.el.B(\'Z\'),V:z.el.B(\'V\'),4w:z.el.B(\'4w\')||\'2b%\',Y:z.el.B(\'Y\'),19:z.el.B(\'19\'),Q:z.el.B(\'Q\'),O:z.el.B(\'O\'),2Y:z.el.B(\'2Y\'),4Z:z.el.B(\'4Z\'),6k:z.el.B(\'6k\'),6g:z.el.B(\'6g\'),5a:z.el.B(\'5a\'),66:z.el.B(\'66\'),6j:z.el.B(\'6j\'),5M:z.el.B(\'5M\'),4X:z.el.B(\'4X\')};z.Z=T(z.W.Z)||e.4b||0;z.V=T(z.W.V)||e.63||0;z.Q=T(z.W.Q)||0;z.O=T(z.W.O)||0;1q=[\'em\',\'S\',\'kJ\',\'%\'];1Y(i in 1q){if(z.W.4w.3F(1q[i])>0){z.fi=1q[i];z.4w=2m(z.W.4w)}if(z.W.4Z.3F(1q[i])>0){z.fw=1q[i];z.bt=2m(z.W.4Z)||0}if(z.W.6k.3F(1q[i])>0){z.fB=1q[i];z.bg=2m(z.W.6k)||0}if(z.W.6g.3F(1q[i])>0){z.fE=1q[i];z.bf=2m(z.W.6g)||0}if(z.W.5a.3F(1q[i])>0){z.fv=1q[i];z.be=2m(z.W.5a)||0}if(z.W.66.3F(1q[i])>0){z.fk=1q[i];z.bb=2m(z.W.66)||0}if(z.W.6j.3F(1q[i])>0){z.fs=1q[i];z.ba=2m(z.W.6j)||0}if(z.W.5M.3F(1q[i])>0){z.fb=1q[i];z.cJ=2m(z.W.5M)||0}if(z.W.4X.3F(1q[i])>0){z.fq=1q[i];z.cX=2m(z.W.4X)||0}}if(z.W.Y!=\'2y\'&&z.W.Y!=\'1O\'){z.el.B(\'Y\',\'2y\')}z.el.B(\'2Y\',\'2O\');z.1u=1u;3m(z.1u){1e\'f1\':z.4f=z.Q+z.2f.h/2;z.57=z.Q;z.4c=z.O+z.2f.w/2;z.4W=z.O;1r;1e\'d2\':z.57=z.Q+z.2f.h/2;z.4f=z.Q;z.4W=z.O+z.2f.w/2;z.4c=z.O;1r;1e\'6l\':z.57=z.Q-z.2f.h/4;z.4f=z.Q;z.4W=z.O-z.2f.w/4;z.4c=z.O;1r}z.bo=I;z.t=(11 72).71();z.4u=u(){6c(z.2H);z.2H=U};z.2D=u(){if(z.bo==I){z.el.22();z.bo=1b}D t=(11 72).71();D n=t-z.t;D p=n/z.1m;if(t>=z.1m+z.t){b1(u(){o=1;if(z.1u){t=z.57;l=z.4W;if(z.1u==\'6l\')o=0}z.bv(z.4L,l,t,1b,o)},13);z.4u()}P{o=1;if(!k.G||!k.G[z.G]){s=((-14.5v(p*14.2Q)/2)+0.5)*(z.4L-z.5d)+z.5d}P{s=k.G[z.G](p,n,z.5d,(z.4L-z.5d),z.1m)}if(z.1u){if(!k.G||!k.G[z.G]){t=((-14.5v(p*14.2Q)/2)+0.5)*(z.57-z.4f)+z.4f;l=((-14.5v(p*14.2Q)/2)+0.5)*(z.4W-z.4c)+z.4c;if(z.1u==\'6l\')o=((-14.5v(p*14.2Q)/2)+0.5)*(-0.9R)+0.9R}P{t=k.G[z.G](p,n,z.4f,(z.57-z.4f),z.1m);l=k.G[z.G](p,n,z.4c,(z.4W-z.4c),z.1m);if(z.1u==\'6l\')o=k.G[z.G](p,n,0.9R,-0.9R,z.1m)}}z.bv(s,l,t,I,o)}};z.2H=6I(u(){z.2D()},13);z.bv=u(4z,O,Q,fp,1J){z.el.B(\'V\',z.V*4z/2b+\'S\').B(\'Z\',z.Z*4z/2b+\'S\').B(\'O\',O+\'S\').B(\'Q\',Q+\'S\').B(\'4w\',z.4w*4z/2b+z.fi);if(z.bt)z.el.B(\'4Z\',z.bt*4z/2b+z.fw);if(z.bg)z.el.B(\'6k\',z.bg*4z/2b+z.fB);if(z.bf)z.el.B(\'6g\',z.bf*4z/2b+z.fE);if(z.be)z.el.B(\'5a\',z.be*4z/2b+z.fv);if(z.bb)z.el.B(\'66\',z.bb*4z/2b+z.fk);if(z.ba)z.el.B(\'6j\',z.ba*4z/2b+z.fs);if(z.cJ)z.el.B(\'5M\',z.cJ*4z/2b+z.fb);if(z.cX)z.el.B(\'4X\',z.cX*4z/2b+z.fq);if(z.1u==\'6l\'){if(1V.7a)z.el.K(0).18.69="9V(1J="+1J*2b+")";z.el.K(0).18.1J=1J}if(fp){if(z.6E){z.el.B(z.W)}if(z.1u==\'d2\'||z.1u==\'6l\'){z.el.B(\'19\',\'1n\');if(z.1u==\'6l\'){if(1V.7a)z.el.K(0).18.69="9V(1J="+2b+")";z.el.K(0).18.1J=1}}P z.el.B(\'19\',\'2E\');if(z.J)z.J.1F(z.el.K(0));k.2L(z.el.K(0),\'1o\')}}};k.fn.kL=u(H,4C,J,G){E q.1w(\'f6\',u(){q.73=k(q).1p("18")||\'\';G=2h J==\'5g\'?J:G||U;J=2h J==\'u\'?J:U;D 9U=k(q).B(\'7f\');D 87=q.3e;7o(9U==\'b7\'&&87){9U=k(87).B(\'7f\');87=87.3e}k(q).B(\'7f\',4C);if(2h q.73==\'8i\')q.73=q.73["9T"];k(q).5K({\'7f\':9U},H,G,u(){k.2L(q,\'f6\');if(2h k(q).1p("18")==\'8i\'){k(q).1p("18")["9T"]="";k(q).1p("18")["9T"]=q.73}P{k(q).1p("18",q.73)}if(J)J.1F(q)})})};k.fn.21({kg:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5A(q,H,J,\'4i\',\'5P\',G)})},kq:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5A(q,H,J,\'4a\',\'5P\',G)})},kr:u(H,J,G){E q.1w(\'1o\',u(){if(k.B(q,\'19\')==\'1n\'){11 k.fx.5A(q,H,J,\'4a\',\'7e\',G)}P{11 k.fx.5A(q,H,J,\'4a\',\'5P\',G)}})},kz:u(H,J,G){E q.1w(\'1o\',u(){if(k.B(q,\'19\')==\'1n\'){11 k.fx.5A(q,H,J,\'4i\',\'7e\',G)}P{11 k.fx.5A(q,H,J,\'4i\',\'5P\',G)}})},ky:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5A(q,H,J,\'4i\',\'7e\',G)})},kx:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.5A(q,H,J,\'4a\',\'7e\',G)})}});k.fx.5A=u(e,H,J,2P,1u,G){if(!k.4O(e)){k.2L(e,\'1o\');E I}D z=q;D 5H=I;z.el=k(e);z.G=2h J==\'5g\'?J:G||U;z.J=2h J==\'u\'?J:U;z.1u=1u;z.H=H;z.2f=k.1a.2p(e);z.W={};z.W.Y=z.el.B(\'Y\');z.W.19=z.el.B(\'19\');if(z.W.19==\'1n\'){62=z.el.B(\'3j\');z.el.22();5H=1b}z.W.Q=z.el.B(\'Q\');z.W.O=z.el.B(\'O\');if(5H){z.el.2G();z.el.B(\'3j\',62)}z.W.Z=z.2f.w+\'S\';z.W.V=z.2f.h+\'S\';z.W.2Y=z.el.B(\'2Y\');z.2f.Q=T(z.W.Q)||0;z.2f.O=T(z.W.O)||0;if(z.W.Y!=\'2y\'&&z.W.Y!=\'1O\'){z.el.B(\'Y\',\'2y\')}z.el.B(\'2Y\',\'2O\').B(\'V\',1u==\'7e\'&&2P==\'4i\'?1:z.2f.h+\'S\').B(\'Z\',1u==\'7e\'&&2P==\'4a\'?1:z.2f.w+\'S\');z.23=u(){z.el.B(z.W);if(z.1u==\'5P\')z.el.2G();P z.el.22();k.2L(z.el.K(0),\'1o\')};3m(2P){1e\'4i\':z.eh=11 k.fx(z.el.K(0),k.H(H-15,z.G,J),\'V\');z.et=11 k.fx(z.el.K(0),k.H(z.H,z.G,z.23),\'Q\');if(z.1u==\'5P\'){z.eh.1L(z.2f.h,0);z.et.1L(z.2f.Q,z.2f.Q+z.2f.h/2)}P{z.eh.1L(0,z.2f.h);z.et.1L(z.2f.Q+z.2f.h/2,z.2f.Q)}1r;1e\'4a\':z.eh=11 k.fx(z.el.K(0),k.H(H-15,z.G,J),\'Z\');z.et=11 k.fx(z.el.K(0),k.H(z.H,z.G,z.23),\'O\');if(z.1u==\'5P\'){z.eh.1L(z.2f.w,0);z.et.1L(z.2f.O,z.2f.O+z.2f.w/2)}P{z.eh.1L(0,z.2f.w);z.et.1L(z.2f.O+z.2f.w/2,z.2f.O)}1r}};k.fn.cr=u(H,41,J){E q.1w(\'1o\',u(){if(!k.4O(q)){k.2L(q,\'1o\');E I}D fx=11 k.fx.cr(q,H,41,J);fx.cm()})};k.fx.cr=u(el,H,41,J){D z=q;z.41=41;z.5D=1;z.el=el;z.H=H;z.J=J;k(z.el).22();z.cm=u(){z.5D++;z.e=11 k.fx(z.el,k.H(z.H,u(){z.ef=11 k.fx(z.el,k.H(z.H,u(){if(z.5D<=z.41)z.cm();P{k.2L(z.el,\'1o\');if(z.J&&z.J.1K==2C){z.J.1F(z.el)}}}),\'1J\');z.ef.1L(0,1)}),\'1J\');z.e.1L(1,0)}};k.fn.21({9S:u(H,1N,G){o=k.H(H);E q.1w(\'1o\',u(){11 k.fx.9S(q,o,1N,G)})},ks:u(H,1N,G){E q.1B(u(){k(\'a[@3f*="#"]\',q).5G(u(e){g8=q.3f.7h(\'#\');k(\'#\'+g8[1]).9S(H,1N,G);E I})})}});k.fx.9S=u(e,o,1N,G){D z=q;z.o=o;z.e=e;z.1N=/g3|g0/.43(1N)?1N:I;z.G=G;p=k.1a.2R(e);s=k.1a.6W();z.4u=u(){6c(z.2H);z.2H=U;k.2L(z.e,\'1o\')};z.t=(11 72).71();s.h=s.h>s.ih?(s.h-s.ih):s.h;s.w=s.w>s.iw?(s.w-s.iw):s.w;z.57=p.y>s.h?s.h:p.y;z.4W=p.x>s.w?s.w:p.x;z.4f=s.t;z.4c=s.l;z.2D=u(){D t=(11 72).71();D n=t-z.t;D p=n/z.o.1m;if(t>=z.o.1m+z.t){z.4u();b1(u(){z.cE(z.57,z.4W)},13)}P{if(!z.1N||z.1N==\'g3\'){if(!k.G||!k.G[z.G]){aa=((-14.5v(p*14.2Q)/2)+0.5)*(z.57-z.4f)+z.4f}P{aa=k.G[z.G](p,n,z.4f,(z.57-z.4f),z.o.1m)}}P{aa=z.4f}if(!z.1N||z.1N==\'g0\'){if(!k.G||!k.G[z.G]){a9=((-14.5v(p*14.2Q)/2)+0.5)*(z.4W-z.4c)+z.4c}P{a9=k.G[z.G](p,n,z.4c,(z.4W-z.4c),z.o.1m)}}P{a9=z.4c}z.cE(aa,a9)}};z.cE=u(t,l){1V.gN(l,t)};z.2H=6I(u(){z.2D()},13)};k.fn.cy=u(41,J){E q.1w(\'1o\',u(){if(!k.4O(q)){k.2L(q,\'1o\');E I}D e=11 k.fx.cy(q,41,J);e.cx()})};k.fx.cy=u(e,41,J){D z=q;z.el=k(e);z.el.22();z.41=T(41)||3;z.J=J;z.5D=1;z.W={};z.W.Y=z.el.B(\'Y\');z.W.Q=T(z.el.B(\'Q\'))||0;z.W.O=T(z.el.B(\'O\'))||0;if(z.W.Y!=\'2y\'&&z.W.Y!=\'1O\'){z.el.B(\'Y\',\'2y\')}z.cx=u(){z.5D++;z.e=11 k.fx(z.el.K(0),{1m:60,23:u(){z.e=11 k.fx(z.el.K(0),{1m:60,23:u(){z.e=11 k.fx(e,{1m:60,23:u(){if(z.5D<=z.41)z.cx();P{z.el.B(\'Y\',z.W.Y).B(\'Q\',z.W.Q+\'S\').B(\'O\',z.W.O+\'S\');k.2L(z.el.K(0),\'1o\');if(z.J&&z.J.1K==2C){z.J.1F(z.el.K(0))}}}},\'O\');z.e.1L(z.W.O-20,z.W.O)}},\'O\');z.e.1L(z.W.O+20,z.W.O-20)}},\'O\');z.e.1L(z.W.O,z.W.O+20)}};k.fn.21({g9:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'4U\',\'in\',G)})},f3:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'4U\',\'4d\',G)})},gM:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'4U\',\'3Y\',G)})},gL:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'4y\',\'in\',G)})},gK:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'4y\',\'4d\',G)})},gS:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'4y\',\'3Y\',G)})},gR:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'O\',\'in\',G)})},gJ:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'O\',\'4d\',G)})},gI:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'O\',\'3Y\',G)})},gC:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'2N\',\'in\',G)})},gB:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'2N\',\'4d\',G)})},gU:u(H,J,G){E q.1w(\'1o\',u(){11 k.fx.1z(q,H,J,\'2N\',\'3Y\',G)})}});k.fx.1z=u(e,H,J,2P,1u,G){if(!k.4O(e)){k.2L(e,\'1o\');E I}D z=q;z.el=k(e);z.G=2h J==\'5g\'?J:G||U;z.J=2h J==\'u\'?J:U;if(1u==\'3Y\'){1u=z.el.B(\'19\')==\'1n\'?\'in\':\'4d\'}if(!e.4s)e.4s=z.el.B(\'19\');z.el.22();z.H=H;z.fx=k.fx.9h(e);z.1u=1u;z.2P=2P;z.23=u(){if(z.1u==\'4d\')z.el.B(\'3j\',\'2O\');k.fx.9g(z.fx.3o.K(0),z.fx.W);if(z.1u==\'in\'){z.el.B(\'19\',z.el.K(0).4s==\'1n\'?\'2E\':z.el.K(0).4s)}P{z.el.B(\'19\',\'1n\');z.el.B(\'3j\',\'dR\')}if(z.J&&z.J.1K==2C){z.J.1F(z.el.K(0))}k.2L(z.el.K(0),\'1o\')};3m(z.2P){1e\'4U\':z.ef=11 k.fx(z.el.K(0),k.H(z.H,z.G,z.23),\'Q\');z.7S=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G),\'V\');if(z.1u==\'in\'){z.ef.1L(-z.fx.W.1q.hb,0);z.7S.1L(0,z.fx.W.1q.hb)}P{z.ef.1L(0,-z.fx.W.1q.hb);z.7S.1L(z.fx.W.1q.hb,0)}1r;1e\'4y\':z.ef=11 k.fx(z.el.K(0),k.H(z.H,z.G,z.23),\'Q\');if(z.1u==\'in\'){z.ef.1L(z.fx.W.1q.hb,0)}P{z.ef.1L(0,z.fx.W.1q.hb)}1r;1e\'O\':z.ef=11 k.fx(z.el.K(0),k.H(z.H,z.G,z.23),\'O\');z.7S=11 k.fx(z.fx.3o.K(0),k.H(z.H,z.G),\'Z\');if(z.1u==\'in\'){z.ef.1L(-z.fx.W.1q.1D,0);z.7S.1L(0,z.fx.W.1q.1D)}P{z.ef.1L(0,-z.fx.W.1q.1D);z.7S.1L(z.fx.W.1q.1D,0)}1r;1e\'2N\':z.ef=11 k.fx(z.el.K(0),k.H(z.H,z.G,z.23),\'O\');if(z.1u==\'in\'){z.ef.1L(z.fx.W.1q.1D,0)}P{z.ef.1L(0,z.fx.W.1q.1D)}1r}};k.h2=U;k.fn.h1=u(o){E q.1B(u(){if(!o||!o.4L){E}D el=q;k(o.4L).1B(u(){11 k.fx.fu(el,q,o)})})};k.fx.fu=u(e,8s,o){D z=q;z.el=k(e);z.8s=8s;z.4e=1j.3t(\'26\');k(z.4e).B({Y:\'1O\'}).2Z(o.3b);if(!o.1m){o.1m=er}z.1m=o.1m;z.23=o.23;z.9i=0;z.9j=0;if(k.f5){z.9i=(T(k.3M(z.4e,\'5a\'))||0)+(T(k.3M(z.4e,\'6k\'))||0)+(T(k.3M(z.4e,\'4X\'))||0)+(T(k.3M(z.4e,\'6j\'))||0);z.9j=(T(k.3M(z.4e,\'4Z\'))||0)+(T(k.3M(z.4e,\'6g\'))||0)+(T(k.3M(z.4e,\'66\'))||0)+(T(k.3M(z.4e,\'5M\'))||0)}z.28=k.21(k.1a.2R(z.el.K(0)),k.1a.2p(z.el.K(0)));z.2X=k.21(k.1a.2R(z.8s),k.1a.2p(z.8s));z.28.1D-=z.9i;z.28.hb-=z.9j;z.2X.1D-=z.9i;z.2X.hb-=z.9j;z.J=o.23;k(\'2e\').1R(z.4e);k(z.4e).B(\'Z\',z.28.1D+\'S\').B(\'V\',z.28.hb+\'S\').B(\'Q\',z.28.y+\'S\').B(\'O\',z.28.x+\'S\').5K({Q:z.2X.y,O:z.2X.x,Z:z.2X.1D,V:z.2X.hb},z.1m,u(){k(z.4e).aB();if(z.23&&z.23.1K==2C){z.23.1F(z.el.K(0),[z.4L])}})};k.ak={2s:u(M){E q.1B(u(){D el=q;D 7x=2*14.2Q/eY;D aZ=2*14.2Q;if(k(el).B(\'Y\')!=\'2y\'&&k(el).B(\'Y\')!=\'1O\'){k(el).B(\'Y\',\'2y\')}el.1l={1S:k(M.1S,q),2F:M.2F,6M:M.6M,an:M.an,aZ:aZ,1P:k.1a.2p(q),Y:k.1a.2R(q),28:14.2Q/2,ct:M.ct,91:M.6R,6R:[],aY:I,7x:2*14.2Q/eY};el.1l.eZ=(el.1l.1P.w-el.1l.2F)/2;el.1l.7O=(el.1l.1P.h-el.1l.6M-el.1l.6M*el.1l.91)/2;el.1l.2D=2*14.2Q/el.1l.1S.1P();el.1l.cI=el.1l.1P.w/2;el.1l.cF=el.1l.1P.h/2-el.1l.6M*el.1l.91;D aS=1j.3t(\'26\');k(aS).B({Y:\'1O\',3B:1,Q:0,O:0});k(el).1R(aS);el.1l.1S.1B(u(2I){ab=k(\'1U\',q).K(0);V=T(el.1l.6M*el.1l.91);if(k.3h.4I){3N=1j.3t(\'1U\');k(3N).B(\'Y\',\'1O\');3N.2M=ab.2M;3N.18.69=\'iW aw:ax.ay.c1(1J=60, 18=1, iJ=0, i6=0, hz=0, hx=0)\'}P{3N=1j.3t(\'3N\');if(3N.ga){4H=3N.ga("2d");3N.18.Y=\'1O\';3N.18.V=V+\'S\';3N.18.Z=el.1l.2F+\'S\';3N.V=V;3N.Z=el.1l.2F;4H.i4();4H.i2(0,V);4H.hT(1,-1);4H.hJ(ab,0,0,el.1l.2F,V);4H.6E();4H.hN="hO-4d";D b0=4H.hQ(0,0,0,V);b0.g1(1,"fU(1X, 1X, 1X, 1)");b0.g1(0,"fU(1X, 1X, 1X, 0.6)");4H.hR=b0;if(iR.iv.3F(\'ix\')!=-1){4H.it()}P{4H.ir(0,0,el.1l.2F,V)}}}el.1l.6R[2I]=3N;k(aS).1R(3N)}).1H(\'aV\',u(e){el.1l.aY=1b;el.1l.H=el.1l.7x*0.1*el.1l.H/14.3R(el.1l.H);E I}).1H(\'8q\',u(e){el.1l.aY=I;E I});k.ak.7P(el);el.1l.H=el.1l.7x*0.2;el.1l.gm=1V.6I(u(){el.1l.28+=el.1l.H;if(el.1l.28>aZ)el.1l.28=0;k.ak.7P(el)},20);k(el).1H(\'8q\',u(){el.1l.H=el.1l.7x*0.2*el.1l.H/14.3R(el.1l.H)}).1H(\'3H\',u(e){if(el.1l.aY==I){1s=k.1a.44(e);fe=el.1l.1P.w-1s.x+el.1l.Y.x;el.1l.H=el.1l.ct*el.1l.7x*(el.1l.1P.w/2-fe)/(el.1l.1P.w/2)}})})},7P:u(el){el.1l.1S.1B(u(2I){ch=el.1l.28+2I*el.1l.2D;x=el.1l.eZ*14.5v(ch);y=el.1l.7O*14.98(ch);fm=T(2b*(el.1l.7O+y)/(2*el.1l.7O));fl=(el.1l.7O+y)/(2*el.1l.7O);Z=T((el.1l.2F-el.1l.an)*fl+el.1l.an);V=T(Z*el.1l.6M/el.1l.2F);q.18.Q=el.1l.cF+y-V/2+"S";q.18.O=el.1l.cI+x-Z/2+"S";q.18.Z=Z+"S";q.18.V=V+"S";q.18.3B=fm;el.1l.6R[2I].18.Q=T(el.1l.cF+y+V-1-V/2)+"S";el.1l.6R[2I].18.O=T(el.1l.cI+x-Z/2)+"S";el.1l.6R[2I].18.Z=Z+"S";el.1l.6R[2I].18.V=T(V*el.1l.91)+"S"})}};k.fn.h9=k.ak.2s;k.ff={2s:u(M){E q.1B(u(){if(!M.ae||!M.ad)E;D el=q;el.2j={ag:M.ag||bw,ae:M.ae,ad:M.ad,8r:M.8r||\'f7\',af:M.af||\'f7\',2U:M.2U&&2h M.2U==\'u\'?M.2U:I,3i:M.2U&&2h M.3i==\'u\'?M.3i:I,74:M.74&&2h M.74==\'u\'?M.74:I,ai:k(M.ae,q),8f:k(M.ad,q),H:M.H||8w,6e:M.6e||0};el.2j.8f.2G().B(\'V\',\'83\').eq(0).B({V:el.2j.ag+\'S\',19:\'2E\'}).2X();el.2j.ai.1B(u(2I){q.7d=2I}).h6(u(){k(q).2Z(el.2j.af)},u(){k(q).4p(el.2j.af)}).1H(\'5G\',u(e){if(el.2j.6e==q.7d)E;el.2j.ai.eq(el.2j.6e).4p(el.2j.8r).2X().eq(q.7d).2Z(el.2j.8r).2X();el.2j.8f.eq(el.2j.6e).5K({V:0},el.2j.H,u(){q.18.19=\'1n\';if(el.2j.3i){el.2j.3i.1F(el,[q])}}).2X().eq(q.7d).22().5K({V:el.2j.ag},el.2j.H,u(){q.18.19=\'2E\';if(el.2j.2U){el.2j.2U.1F(el,[q])}}).2X();if(el.2j.74){el.2j.74.1F(el,[q,el.2j.8f.K(q.7d),el.2j.ai.K(el.2j.6e),el.2j.8f.K(el.2j.6e)])}el.2j.6e=q.7d}).eq(0).2Z(el.2j.8r).2X();k(q).B(\'V\',k(q).B(\'V\')).B(\'2Y\',\'2O\')})}};k.fn.h7=k.ff.2s;k.3L={1c:U,8u:u(){31=q.2v;if(!31)E;18={fg:k(q).B(\'fg\')||\'\',4w:k(q).B(\'4w\')||\'\',8h:k(q).B(\'8h\')||\'\',fI:k(q).B(\'fI\')||\'\',fJ:k(q).B(\'fJ\')||\'\',fT:k(q).B(\'fT\')||\'\',cH:k(q).B(\'cH\')||\'\',fc:k(q).B(\'fc\')||\'\'};k.3L.1c.B(18);3w=k.3L.g2(31);3w=3w.4v(11 cp("\\\\n","g"),"<br />");k.3L.1c.3w(\'km\');ck=k.3L.1c.K(0).4b;k.3L.1c.3w(3w);Z=k.3L.1c.K(0).4b+ck;if(q.6t.2J&&Z>q.6t.2J[0]){Z=q.6t.2J[0]}q.18.Z=Z+\'S\';if(q.4S==\'cQ\'){V=k.3L.1c.K(0).63+ck;if(q.6t.2J&&V>q.6t.2J[1]){V=q.6t.2J[1]}q.18.V=V+\'S\'}},g2:u(31){co={\'&\':\'&j0;\',\'<\':\'&kB;\',\'>\':\'&gt;\',\'"\':\'&kw;\'};1Y(i in co){31=31.4v(11 cp(i,\'g\'),co[i])}E 31},2s:u(2J){if(k.3L.1c==U){k(\'2e\',1j).1R(\'<26 id="fH" 18="Y: 1O; Q: 0; O: 0; 3j: 2O;"></26>\');k.3L.1c=k(\'#fH\')}E q.1B(u(){if(/cQ|bz/.43(q.4S)){if(q.4S==\'bz\'){f9=q.5n(\'1u\');if(!/31|kv/.43(f9)){E}}if(2J&&(2J.1K==cR||(2J.1K==7b&&2J.1h==2))){if(2J.1K==cR)2J=[2J,2J];P{2J[0]=T(2J[0])||8w;2J[1]=T(2J[1])||8w}q.6t={2J:2J}}k(q).5I(k.3L.8u).6S(k.3L.8u).fX(k.3L.8u);k.3L.8u.1F(q)}})}};k.fn.ke=k.3L.2s;k.N={1c:U,8S:U,3E:U,2H:U,4o:U,bp:U,1d:U,2g:U,1S:U,5t:u(){k.N.8S.5t();if(k.N.3E){k.N.3E.2G()}},4u:u(){k.N.1S=U;k.N.2g=U;k.N.4o=k.N.1d.2v;if(k.N.1c.B(\'19\')==\'2E\'){if(k.N.1d.1f.fx){3m(k.N.1d.1f.fx.1u){1e\'bB\':k.N.1c.7k(k.N.1d.1f.fx.1m,k.N.5t);1r;1e\'1z\':k.N.1c.f3(k.N.1d.1f.fx.1m,k.N.5t);1r;1e\'aT\':k.N.1c.fz(k.N.1d.1f.fx.1m,k.N.5t);1r}}P{k.N.1c.2G()}if(k.N.1d.1f.3i)k.N.1d.1f.3i.1F(k.N.1d,[k.N.1c,k.N.3E])}P{k.N.5t()}1V.c6(k.N.2H)},fy:u(){D 1d=k.N.1d;D 4g=k.N.ap(1d);if(1d&&4g.3k!=k.N.4o&&4g.3k.1h>=1d.1f.aL){k.N.4o=4g.3k;k.N.bp=4g.3k;79={2q:k(1d).1p(\'kP\')||\'2q\',2v:4g.3k};k.kN({1u:\'kG\',79:k.kI(79),kF:u(ft){1d.1f.4h=k(\'3k\',ft);1P=1d.1f.4h.1P();if(1P>0){D 5x=\'\';1d.1f.4h.1B(u(2I){5x+=\'<90 4G="\'+k(\'2v\',q).31()+\'" 8O="\'+2I+\'" 18="94: aG;">\'+k(\'31\',q).31()+\'</90>\'});if(1d.1f.aR){D 3G=k(\'2v\',1d.1f.4h.K(0)).31();1d.2v=4g.3l+3G+1d.1f.3K+4g.5Q;k.N.6G(1d,4g.3k.1h!=3G.1h?(4g.3l.1h+4g.3k.1h):3G.1h,4g.3k.1h!=3G.1h?(4g.3l.1h+3G.1h):3G.1h)}if(1P>0){k.N.b4(1d,5x)}P{k.N.4u()}}P{k.N.4u()}},6b:1d.1f.aM})}},b4:u(1d,5x){k.N.8S.3w(5x);k.N.1S=k(\'90\',k.N.8S.K(0));k.N.1S.aV(k.N.f2).1H(\'5G\',k.N.fO);D Y=k.1a.2R(1d);D 1P=k.1a.2p(1d);k.N.1c.B(\'Q\',Y.y+1P.hb+\'S\').B(\'O\',Y.x+\'S\').2Z(1d.1f.aK);if(k.N.3E){k.N.3E.B(\'19\',\'2E\').B(\'Q\',Y.y+1P.hb+\'S\').B(\'O\',Y.x+\'S\').B(\'Z\',k.N.1c.B(\'Z\')).B(\'V\',k.N.1c.B(\'V\'))}k.N.2g=0;k.N.1S.K(0).3b=1d.1f.70;k.N.8P(1d,1d.1f.4h.K(0),\'6Z\');if(k.N.1c.B(\'19\')==\'1n\'){if(1d.1f.bA){D bm=k.1a.aj(1d,1b);D bl=k.1a.6h(1d,1b);k.N.1c.B(\'Z\',1d.4b-(k.f5?(bm.l+bm.r+bl.l+bl.r):0)+\'S\')}if(1d.1f.fx){3m(1d.1f.fx.1u){1e\'bB\':k.N.1c.7m(1d.1f.fx.1m);1r;1e\'1z\':k.N.1c.g9(1d.1f.fx.1m);1r;1e\'aT\':k.N.1c.fP(1d.1f.fx.1m);1r}}P{k.N.1c.22()}if(k.N.1d.1f.2U)k.N.1d.1f.2U.1F(k.N.1d,[k.N.1c,k.N.3E])}},fC:u(){D 1d=q;if(1d.1f.4h){k.N.4o=1d.2v;k.N.bp=1d.2v;D 5x=\'\';1d.1f.4h.1B(u(2I){2v=k(\'2v\',q).31().5Z();fR=1d.2v.5Z();if(2v.3F(fR)==0){5x+=\'<90 4G="\'+k(\'2v\',q).31()+\'" 8O="\'+2I+\'" 18="94: aG;">\'+k(\'31\',q).31()+\'</90>\'}});if(5x!=\'\'){k.N.b4(1d,5x);q.1f.aW=1b;E}}1d.1f.4h=U;q.1f.aW=I},6G:u(2q,28,2X){if(2q.aI){D 6K=2q.aI();6K.j8(1b);6K.fr("bW",28);6K.ja("bW",-2X+28);6K.8Z()}P if(2q.aU){2q.aU(28,2X)}P{if(2q.5B){2q.5B=28;2q.dq=2X}}2q.6D()},fD:u(2q){if(2q.5B)E 2q.5B;P if(2q.aI){D 6K=1j.6G.du();D fo=6K.jg();E 0-fo.fr(\'bW\',-jX)}},ap:u(2q){D 4F={2v:2q.2v,3l:\'\',5Q:\'\',3k:\'\'};if(2q.1f.aO){D 97=I;D 5B=k.N.fD(2q)||0;D 56=4F.2v.7h(2q.1f.3K);1Y(D i=0;i<56.1h;i++){if((4F.3l.1h+56[i].1h>=5B||5B==0)&&!97){if(4F.3l.1h<=5B)4F.3k=56[i];P 4F.5Q+=56[i]+(56[i]!=\'\'?2q.1f.3K:\'\');97=1b}P if(97){4F.5Q+=56[i]+(56[i]!=\'\'?2q.1f.3K:\'\')}if(!97){4F.3l+=56[i]+(56.1h>1?2q.1f.3K:\'\')}}}P{4F.3k=4F.2v}E 4F},bu:u(e){1V.c6(k.N.2H);D 1d=k.N.ap(q);D 3O=e.7F||e.7A||-1;if(/^13$|27$|35$|36$|38$|40$|^9$/.43(3O)&&k.N.1S){if(1V.2l){1V.2l.cj=1b;1V.2l.ci=I}P{e.al();e.am()}if(k.N.2g!=U)k.N.1S.K(k.N.2g||0).3b=\'\';P k.N.2g=-1;3m(3O){1e 9:1e 13:if(k.N.2g==-1)k.N.2g=0;D 2g=k.N.1S.K(k.N.2g||0);D 3G=2g.5n(\'4G\');q.2v=1d.3l+3G+q.1f.3K+1d.5Q;k.N.4o=1d.3k;k.N.6G(q,1d.3l.1h+3G.1h+q.1f.3K.1h,1d.3l.1h+3G.1h+q.1f.3K.1h);k.N.4u();if(q.1f.6a){4n=T(2g.5n(\'8O\'))||0;k.N.8P(q,q.1f.4h.K(4n),\'6a\')}if(q.76)q.76(I);E 3O!=13;1r;1e 27:q.2v=1d.3l+k.N.4o+q.1f.3K+1d.5Q;q.1f.4h=U;k.N.4u();if(q.76)q.76(I);E I;1r;1e 35:k.N.2g=k.N.1S.1P()-1;1r;1e 36:k.N.2g=0;1r;1e 38:k.N.2g--;if(k.N.2g<0)k.N.2g=k.N.1S.1P()-1;1r;1e 40:k.N.2g++;if(k.N.2g==k.N.1S.1P())k.N.2g=0;1r}k.N.8P(q,q.1f.4h.K(k.N.2g||0),\'6Z\');k.N.1S.K(k.N.2g||0).3b=q.1f.70;if(k.N.1S.K(k.N.2g||0).76)k.N.1S.K(k.N.2g||0).76(I);if(q.1f.aR){D aA=k.N.1S.K(k.N.2g||0).5n(\'4G\');q.2v=1d.3l+aA+q.1f.3K+1d.5Q;if(k.N.4o.1h!=aA.1h)k.N.6G(q,1d.3l.1h+k.N.4o.1h,1d.3l.1h+aA.1h)}E I}k.N.fC.1F(q);if(q.1f.aW==I){if(1d.3k!=k.N.4o&&1d.3k.1h>=q.1f.aL)k.N.2H=1V.b1(k.N.fy,q.1f.53);if(k.N.1S){k.N.4u()}}E 1b},8P:u(2q,3k,1u){if(2q.1f[1u]){D 79={};aE=3k.dU(\'*\');1Y(i=0;i<aE.1h;i++){79[aE[i].4S]=aE[i].77.k3}2q.1f[1u].1F(2q,[79])}},f2:u(e){if(k.N.1S){if(k.N.2g!=U)k.N.1S.K(k.N.2g||0).3b=\'\';k.N.1S.K(k.N.2g||0).3b=\'\';k.N.2g=T(q.5n(\'8O\'))||0;k.N.1S.K(k.N.2g||0).3b=k.N.1d.1f.70}},fO:u(2l){1V.c6(k.N.2H);2l=2l||k.2l.jH(1V.2l);2l.al();2l.am();D 1d=k.N.ap(k.N.1d);D 3G=q.5n(\'4G\');k.N.1d.2v=1d.3l+3G+k.N.1d.1f.3K+1d.5Q;k.N.4o=q.5n(\'4G\');k.N.6G(k.N.1d,1d.3l.1h+3G.1h+k.N.1d.1f.3K.1h,1d.3l.1h+3G.1h+k.N.1d.1f.3K.1h);k.N.4u();if(k.N.1d.1f.6a){4n=T(q.5n(\'8O\'))||0;k.N.8P(k.N.1d,k.N.1d.1f.4h.K(4n),\'6a\')}E I},gb:u(e){3O=e.7F||e.7A||-1;if(/13|27|35|36|38|40/.43(3O)&&k.N.1S){if(1V.2l){1V.2l.cj=1b;1V.2l.ci=I}P{e.al();e.am()}E I}},2s:u(M){if(!M.aM||!k.1a){E}if(!k.N.1c){if(k.3h.4I){k(\'2e\',1j).1R(\'<3E 18="19:1n;Y:1O;69:aw:ax.ay.c1(1J=0);" id="g5" 2M="ew:I;" ez="0" ey="bX"></3E>\');k.N.3E=k(\'#g5\')}k(\'2e\',1j).1R(\'<26 id="gc" 18="Y: 1O; Q: 0; O: 0; z-b2: jE; 19: 1n;"><aX 18="6X: 0;92: 0; jF-18: 1n; z-b2: jM;">&7J;</aX></26>\');k.N.1c=k(\'#gc\');k.N.8S=k(\'aX\',k.N.1c)}E q.1B(u(){if(q.4S!=\'bz\'&&q.5n(\'1u\')!=\'31\')E;q.1f={};q.1f.aM=M.aM;q.1f.aL=14.3R(T(M.aL)||1);q.1f.aK=M.aK?M.aK:\'\';q.1f.70=M.70?M.70:\'\';q.1f.6a=M.6a&&M.6a.1K==2C?M.6a:U;q.1f.2U=M.2U&&M.2U.1K==2C?M.2U:U;q.1f.3i=M.3i&&M.3i.1K==2C?M.3i:U;q.1f.6Z=M.6Z&&M.6Z.1K==2C?M.6Z:U;q.1f.bA=M.bA||I;q.1f.aO=M.aO||I;q.1f.3K=q.1f.aO?(M.3K||\', \'):\'\';q.1f.aR=M.aR?1b:I;q.1f.53=14.3R(T(M.53)||aF);if(M.fx&&M.fx.1K==7n){if(!M.fx.1u||!/bB|1z|aT/.43(M.fx.1u)){M.fx.1u=\'1z\'}if(M.fx.1u==\'1z\'&&!k.fx.1z)E;if(M.fx.1u==\'aT\'&&!k.fx.5W)E;M.fx.1m=14.3R(T(M.fx.1m)||8w);if(M.fx.1m>q.1f.53){M.fx.1m=q.1f.53-2b}q.1f.fx=M.fx}q.1f.4h=U;q.1f.aW=I;k(q).1p(\'bu\',\'fQ\').6D(u(){k.N.1d=q;k.N.4o=q.2v}).fX(k.N.gb).6S(k.N.bu).5I(u(){k.N.2H=1V.b1(k.N.4u,jP)})})}};k.fn.jO=k.N.2s;k.1y={2H:U,4E:U,29:U,2D:10,28:u(el,4P,2D,di){k.1y.4E=el;k.1y.29=4P;k.1y.2D=T(2D)||10;k.1y.2H=1V.6I(k.1y.db,T(di)||40)},db:u(){1Y(i=0;i<k.1y.29.1h;i++){if(!k.1y.29[i].30){k.1y.29[i].30=k.21(k.1a.bN(k.1y.29[i]),k.1a.82(k.1y.29[i]),k.1a.6W(k.1y.29[i]))}P{k.1y.29[i].30.t=k.1y.29[i].2V;k.1y.29[i].30.l=k.1y.29[i].3g}if(k.1y.4E.A&&k.1y.4E.A.7W==1b){6f={x:k.1y.4E.A.2x,y:k.1y.4E.A.2r,1D:k.1y.4E.A.1C.1D,hb:k.1y.4E.A.1C.hb}}P{6f=k.21(k.1a.bN(k.1y.4E),k.1a.82(k.1y.4E))}if(k.1y.29[i].30.t>0&&k.1y.29[i].30.y+k.1y.29[i].30.t>6f.y){k.1y.29[i].2V-=k.1y.2D}P if(k.1y.29[i].30.t<=k.1y.29[i].30.h&&k.1y.29[i].30.t+k.1y.29[i].30.hb<6f.y+6f.hb){k.1y.29[i].2V+=k.1y.2D}if(k.1y.29[i].30.l>0&&k.1y.29[i].30.x+k.1y.29[i].30.l>6f.x){k.1y.29[i].3g-=k.1y.2D}P if(k.1y.29[i].30.l<=k.1y.29[i].30.jT&&k.1y.29[i].30.l+k.1y.29[i].30.1D<6f.x+6f.1D){k.1y.29[i].3g+=k.1y.2D}}},8v:u(){1V.6c(k.1y.2H);k.1y.4E=U;k.1y.29=U;1Y(i in k.1y.29){k.1y.29[i].30=U}}};k.6y={2s:u(M){E q.1B(u(){D el=q;el.1G={1S:k(M.1S,q),1Z:k(M.1Z,q),1M:k.1a.2R(q),2F:M.2F,aN:M.aN,7R:M.7R,dw:M.dw,51:M.51,6q:M.6q};k.6y.aJ(el,0);k(1V).1H(\'jS\',u(){el.1G.1M=k.1a.2R(el);k.6y.aJ(el,0);k.6y.7P(el)});k.6y.7P(el);el.1G.1S.1H(\'aV\',u(){k(el.1G.aN,q).K(0).18.19=\'2E\'}).1H(\'8q\',u(){k(el.1G.aN,q).K(0).18.19=\'1n\'});k(1j).1H(\'3H\',u(e){D 1s=k.1a.44(e);D 5q=0;if(el.1G.51&&el.1G.51==\'b8\')D aQ=1s.x-el.1G.1M.x-(el.4b-el.1G.2F*el.1G.1S.1P())/2-el.1G.2F/2;P if(el.1G.51&&el.1G.51==\'2N\')D aQ=1s.x-el.1G.1M.x-el.4b+el.1G.2F*el.1G.1S.1P();P D aQ=1s.x-el.1G.1M.x;D dB=14.5Y(1s.y-el.1G.1M.y-el.63/2,2);el.1G.1S.1B(u(2I){46=14.dm(14.5Y(aQ-2I*el.1G.2F,2)+dB);46-=el.1G.2F/2;46=46<0?0:46;46=46>el.1G.7R?el.1G.7R:46;46=el.1G.7R-46;bC=el.1G.6q*46/el.1G.7R;q.18.Z=el.1G.2F+bC+\'S\';q.18.O=el.1G.2F*2I+5q+\'S\';5q+=bC});k.6y.aJ(el,5q)})})},aJ:u(el,5q){if(el.1G.51)if(el.1G.51==\'b8\')el.1G.1Z.K(0).18.O=(el.4b-el.1G.2F*el.1G.1S.1P())/2-5q/2+\'S\';P if(el.1G.51==\'O\')el.1G.1Z.K(0).18.O=-5q/el.1G.1S.1P()+\'S\';P if(el.1G.51==\'2N\')el.1G.1Z.K(0).18.O=(el.4b-el.1G.2F*el.1G.1S.1P())-5q/2+\'S\';el.1G.1Z.K(0).18.Z=el.1G.2F*el.1G.1S.1P()+5q+\'S\'},7P:u(el){el.1G.1S.1B(u(2I){q.18.Z=el.1G.2F+\'S\';q.18.O=el.1G.2F*2I+\'S\'})}};k.fn.jD=k.6y.2s;k.1v={M:{2B:10,eV:\'1Q/jG.eF\',eT:\'<1U 2M="1Q/5P.eC" />\',eN:0.8,e3:\'jK ab\',e5:\'5d\',3V:8w},jI:I,jU:I,6r:U,9d:I,9e:I,ca:u(2l){if(!k.1v.9e||k.1v.9d)E;D 3O=2l.7F||2l.7A||-1;3m(3O){1e 35:if(k.1v.6r)k.1v.28(U,k(\'a[@4G=\'+k.1v.6r+\']:k7\').K(0));1r;1e 36:if(k.1v.6r)k.1v.28(U,k(\'a[@4G=\'+k.1v.6r+\']:k5\').K(0));1r;1e 37:1e 8:1e 33:1e 80:1e k8:D ar=k(\'#9a\');if(ar.K(0).52!=U){ar.K(0).52.1F(ar.K(0))}1r;1e 38:1r;1e 39:1e 34:1e 32:1e ka:1e 78:D aD=k(\'#9b\');if(aD.K(0).52!=U){aD.K(0).52.1F(aD.K(0))}1r;1e 40:1r;1e 27:k.1v.ah();1r}},7W:u(M){if(M)k.21(k.1v.M,M);if(1V.2l){k(\'2e\',1j).1H(\'6S\',k.1v.ca)}P{k(1j).1H(\'6S\',k.1v.ca)}k(\'a\').1B(u(){el=k(q);dQ=el.1p(\'4G\')||\'\';eA=el.1p(\'3f\')||\'\';eu=/\\.eC|\\.jY|\\.95|\\.eF|\\.jW/g;if(eA.5Z().bU(eu)!=U&&dQ.5Z().3F(\'eJ\')==0){el.1H(\'5G\',k.1v.28)}});if(k.3h.4I){3E=1j.3t(\'3E\');k(3E).1p({id:\'b6\',2M:\'ew:I;\',ez:\'bX\',ey:\'bX\'}).B({19:\'1n\',Y:\'1O\',Q:\'0\',O:\'0\',69:\'aw:ax.ay.c1(1J=0)\'});k(\'2e\').1R(3E)}8Q=1j.3t(\'26\');k(8Q).1p(\'id\',\'bk\').B({Y:\'1O\',19:\'1n\',Q:\'0\',O:\'0\',1J:0}).1R(1j.8F(\' \')).1H(\'5G\',k.1v.ah);6L=1j.3t(\'26\');k(6L).1p(\'id\',\'dZ\').B({4X:k.1v.M.2B+\'S\'}).1R(1j.8F(\' \'));bZ=1j.3t(\'26\');k(bZ).1p(\'id\',\'e1\').B({4X:k.1v.M.2B+\'S\',5M:k.1v.M.2B+\'S\'}).1R(1j.8F(\' \'));cc=1j.3t(\'a\');k(cc).1p({id:\'jh\',3f:\'#\'}).B({Y:\'1O\',2N:k.1v.M.2B+\'S\',Q:\'0\'}).1R(k.1v.M.eT).1H(\'5G\',k.1v.ah);7t=1j.3t(\'26\');k(7t).1p(\'id\',\'bh\').B({Y:\'2y\',b9:\'O\',6X:\'0 ao\',3B:1}).1R(6L).1R(bZ).1R(cc);2a=1j.3t(\'1U\');2a.2M=k.1v.M.eV;k(2a).1p(\'id\',\'ep\').B({Y:\'1O\'});4R=1j.3t(\'a\');k(4R).1p({id:\'9a\',3f:\'#\'}).B({Y:\'1O\',19:\'1n\',2Y:\'2O\',eQ:\'1n\'}).1R(1j.8F(\' \'));4Q=1j.3t(\'a\');k(4Q).1p({id:\'9b\',3f:\'#\'}).B({Y:\'1O\',2Y:\'2O\',eQ:\'1n\'}).1R(1j.8F(\' \'));1Z=1j.3t(\'26\');k(1Z).1p(\'id\',\'e0\').B({19:\'1n\',Y:\'2y\',2Y:\'2O\',b9:\'O\',6X:\'0 ao\',Q:\'0\',O:\'0\',3B:2}).1R([2a,4R,4Q]);6N=1j.3t(\'26\');k(6N).1p(\'id\',\'aq\').B({19:\'1n\',Y:\'1O\',2Y:\'2O\',Q:\'0\',O:\'0\',b9:\'b8\',7f:\'b7\',j7:\'0\'}).1R([1Z,7t]);k(\'2e\').1R(8Q).1R(6N)},28:u(e,C){el=C?k(C):k(q);at=el.1p(\'4G\');D 6P,4n,4R,4Q;if(at!=\'eJ\'){k.1v.6r=at;8N=k(\'a[@4G=\'+at+\']\');6P=8N.1P();4n=8N.b2(C?C:q);4R=8N.K(4n-1);4Q=8N.K(4n+1)}8H=el.1p(\'3f\');6L=el.1p(\'45\');3I=k.1a.6W();8Q=k(\'#bk\');if(!k.1v.9e){k.1v.9e=1b;if(k.3h.4I){k(\'#b6\').B(\'V\',14.3v(3I.ih,3I.h)+\'S\').B(\'Z\',14.3v(3I.iw,3I.w)+\'S\').22()}8Q.B(\'V\',14.3v(3I.ih,3I.h)+\'S\').B(\'Z\',14.3v(3I.iw,3I.w)+\'S\').22().eo(bw,k.1v.M.eN,u(){k.1v.bd(8H,6L,3I,6P,4n,4R,4Q)});k(\'#aq\').B(\'Z\',14.3v(3I.iw,3I.w)+\'S\')}P{k(\'#9a\').K(0).52=U;k(\'#9b\').K(0).52=U;k.1v.bd(8H,6L,3I,6P,4n,4R,4Q)}E I},bd:u(8H,jA,3I,6P,4n,4R,4Q){k(\'#bi\').aB();aC=k(\'#9a\');aC.2G();as=k(\'#9b\');as.2G();2a=k(\'#ep\');1Z=k(\'#e0\');6N=k(\'#aq\');7t=k(\'#bh\').B(\'3j\',\'2O\');k(\'#dZ\').3w(6L);k.1v.9d=1b;if(6P)k(\'#e1\').3w(k.1v.M.e3+\' \'+(4n+1)+\' \'+k.1v.M.e5+\' \'+6P);if(4R){aC.K(0).52=u(){q.5I();k.1v.28(U,4R);E I}}if(4Q){as.K(0).52=u(){q.5I();k.1v.28(U,4Q);E I}}2a.22();8E=k.1a.2p(1Z.K(0));5f=14.3v(8E.1D,2a.K(0).Z+k.1v.M.2B*2);5T=14.3v(8E.hb,2a.K(0).V+k.1v.M.2B*2);2a.B({O:(5f-2a.K(0).Z)/2+\'S\',Q:(5T-2a.K(0).V)/2+\'S\'});1Z.B({Z:5f+\'S\',V:5T+\'S\'}).22();e4=k.1a.bq();6N.B(\'Q\',3I.t+(e4.h/15)+\'S\');if(6N.B(\'19\')==\'1n\'){6N.22().7m(k.1v.M.3V)}6U=11 aH;k(6U).1p(\'id\',\'bi\').1H(\'jk\',u(){5f=6U.Z+k.1v.M.2B*2;5T=6U.V+k.1v.M.2B*2;2a.2G();1Z.5K({V:5T},8E.hb!=5T?k.1v.M.3V:1,u(){1Z.5K({Z:5f},8E.1D!=5f?k.1v.M.3V:1,u(){1Z.cA(6U);k(6U).B({Y:\'1O\',O:k.1v.M.2B+\'S\',Q:k.1v.M.2B+\'S\'}).7m(k.1v.M.3V,u(){dS=k.1a.2p(7t.K(0));if(4R){aC.B({O:k.1v.M.2B+\'S\',Q:k.1v.M.2B+\'S\',Z:5f/2-k.1v.M.2B*3+\'S\',V:5T-k.1v.M.2B*2+\'S\'}).22()}if(4Q){as.B({O:5f/2+k.1v.M.2B*2+\'S\',Q:k.1v.M.2B+\'S\',Z:5f/2-k.1v.M.2B*3+\'S\',V:5T-k.1v.M.2B*2+\'S\'}).22()}7t.B({Z:5f+\'S\',Q:-dS.hb+\'S\',3j:\'dR\'}).5K({Q:-1},k.1v.M.3V,u(){k.1v.9d=I})})})})});6U.2M=8H},ah:u(){k(\'#bi\').aB();k(\'#aq\').2G();k(\'#bh\').B(\'3j\',\'2O\');k(\'#bk\').eo(bw,0,u(){k(q).2G();if(k.3h.4I){k(\'#b6\').2G()}});k(\'#9a\').K(0).52=U;k(\'#9b\').K(0).52=U;k.1v.6r=U;k.1v.9e=I;k.1v.9d=I;E I}};k.2A={5E:[],eS:u(){q.5I();X=q.3e;id=k.1p(X,\'id\');if(k.2A.5E[id]!=U){1V.6c(k.2A.5E[id])}1z=X.L.3x+1;if(X.L.1Q.1h<1z){1z=1}1Q=k(\'1U\',X.L.5F);X.L.3x=1z;if(1Q.1P()>0){1Q.7k(X.L.3V,k.2A.8B)}},eG:u(){q.5I();X=q.3e;id=k.1p(X,\'id\');if(k.2A.5E[id]!=U){1V.6c(k.2A.5E[id])}1z=X.L.3x-1;1Q=k(\'1U\',X.L.5F);if(1z<1){1z=X.L.1Q.1h}X.L.3x=1z;if(1Q.1P()>0){1Q.7k(X.L.3V,k.2A.8B)}},2H:u(c){X=1j.cP(c);if(X.L.6w){1z=X.L.3x;7o(1z==X.L.3x){1z=1+T(14.6w()*X.L.1Q.1h)}}P{1z=X.L.3x+1;if(X.L.1Q.1h<1z){1z=1}}1Q=k(\'1U\',X.L.5F);X.L.3x=1z;if(1Q.1P()>0){1Q.7k(X.L.3V,k.2A.8B)}},go:u(o){D X;if(o&&o.1K==7n){if(o.2a){X=1j.cP(o.2a.X);6b=1V.kK.3f.7h("#");o.2a.6B=U;if(6b.1h==2){1z=T(6b[1]);22=6b[1].4v(1z,\'\');if(k.1p(X,\'id\')!=22){1z=1}}P{1z=1}}if(o.8A){o.8A.5I();X=o.8A.3e.3e;id=k.1p(X,\'id\');if(k.2A.5E[id]!=U){1V.6c(k.2A.5E[id])}6b=o.8A.3f.7h("#");1z=T(6b[1]);22=6b[1].4v(1z,\'\');if(k.1p(X,\'id\')!=22){1z=1}}if(X.L.1Q.1h<1z||1z<1){1z=1}X.L.3x=1z;5h=k.1a.2p(X);e8=k.1a.aj(X);e9=k.1a.6h(X);if(X.L.3s){X.L.3s.o.B(\'19\',\'1n\')}if(X.L.3r){X.L.3r.o.B(\'19\',\'1n\')}if(X.L.2a){y=T(e8.t)+T(e9.t);if(X.L.1T){if(X.L.1T.5z==\'Q\'){y+=X.L.1T.4q.hb}P{5h.h-=X.L.1T.4q.hb}}if(X.L.2w){if(X.L.2w&&X.L.2w.6s==\'Q\'){y+=X.L.2w.4q.hb}P{5h.h-=X.L.2w.4q.hb}}if(!X.L.cV){X.L.eg=o.2a?o.2a.V:(T(X.L.2a.B(\'V\'))||0);X.L.cV=o.2a?o.2a.Z:(T(X.L.2a.B(\'Z\'))||0)}X.L.2a.B(\'Q\',y+(5h.h-X.L.eg)/2+\'S\');X.L.2a.B(\'O\',(5h.1D-X.L.cV)/2+\'S\');X.L.2a.B(\'19\',\'2E\')}1Q=k(\'1U\',X.L.5F);if(1Q.1P()>0){1Q.7k(X.L.3V,k.2A.8B)}P{aP=k(\'a\',X.L.1T.o).K(1z-1);k(aP).2Z(X.L.1T.64);D 1U=11 aH();1U.X=k.1p(X,\'id\');1U.1z=1z-1;1U.2M=X.L.1Q[X.L.3x-1].2M;if(1U.23){1U.6B=U;k.2A.19.1F(1U)}P{1U.6B=k.2A.19}if(X.L.2w){X.L.2w.o.3w(X.L.1Q[1z-1].6v)}}}},8B:u(){X=q.3e.3e;X.L.5F.B(\'19\',\'1n\');if(X.L.1T.64){aP=k(\'a\',X.L.1T.o).4p(X.L.1T.64).K(X.L.3x-1);k(aP).2Z(X.L.1T.64)}D 1U=11 aH();1U.X=k.1p(X,\'id\');1U.1z=X.L.3x-1;1U.2M=X.L.1Q[X.L.3x-1].2M;if(1U.23){1U.6B=U;k.2A.19.1F(1U)}P{1U.6B=k.2A.19}if(X.L.2w){X.L.2w.o.3w(X.L.1Q[X.L.3x-1].6v)}},19:u(){X=1j.cP(q.X);if(X.L.3s){X.L.3s.o.B(\'19\',\'1n\')}if(X.L.3r){X.L.3r.o.B(\'19\',\'1n\')}5h=k.1a.2p(X);y=0;if(X.L.1T){if(X.L.1T.5z==\'Q\'){y+=X.L.1T.4q.hb}P{5h.h-=X.L.1T.4q.hb}}if(X.L.2w){if(X.L.2w&&X.L.2w.6s==\'Q\'){y+=X.L.2w.4q.hb}P{5h.h-=X.L.2w.4q.hb}}kD=k(\'.cz\',X);y=y+(5h.h-q.V)/2;x=(5h.1D-q.Z)/2;X.L.5F.B(\'Q\',y+\'S\').B(\'O\',x+\'S\').3w(\'<1U 2M="\'+q.2M+\'" />\');X.L.5F.7m(X.L.3V);3r=X.L.3x+1;if(3r>X.L.1Q.1h){3r=1}3s=X.L.3x-1;if(3s<1){3s=X.L.1Q.1h}X.L.3r.o.B(\'19\',\'2E\').B(\'Q\',y+\'S\').B(\'O\',x+2*q.Z/3+\'S\').B(\'Z\',q.Z/3+\'S\').B(\'V\',q.V+\'S\').1p(\'45\',X.L.1Q[3r-1].6v);X.L.3r.o.K(0).3f=\'#\'+3r+k.1p(X,\'id\');X.L.3s.o.B(\'19\',\'2E\').B(\'Q\',y+\'S\').B(\'O\',x+\'S\').B(\'Z\',q.Z/3+\'S\').B(\'V\',q.V+\'S\').1p(\'45\',X.L.1Q[3s-1].6v);X.L.3s.o.K(0).3f=\'#\'+3s+k.1p(X,\'id\')},2s:u(o){if(!o||!o.1Z||k.2A.5E[o.1Z])E;D 1Z=k(\'#\'+o.1Z);D el=1Z.K(0);if(el.18.Y!=\'1O\'&&el.18.Y!=\'2y\'){el.18.Y=\'2y\'}el.18.2Y=\'2O\';if(1Z.1P()==0)E;el.L={};el.L.1Q=o.1Q?o.1Q:[];el.L.6w=o.6w&&o.6w==1b||I;8b=el.dU(\'kA\');1Y(i=0;i<8b.1h;i++){7I=el.L.1Q.1h;el.L.1Q[7I]={2M:8b[i].2M,6v:8b[i].45||8b[i].kC||\'\'}}if(el.L.1Q.1h==0){E}el.L.4m=k.21(k.1a.2R(el),k.1a.2p(el));el.L.d5=k.1a.aj(el);el.L.cL=k.1a.6h(el);t=T(el.L.d5.t)+T(el.L.cL.t);b=T(el.L.d5.b)+T(el.L.cL.b);k(\'1U\',el).aB();el.L.3V=o.3V?o.3V:er;if(o.5z||o.88||o.64){el.L.1T={};1Z.1R(\'<26 6A="eL"></26>\');el.L.1T.o=k(\'.eL\',el);if(o.88){el.L.1T.88=o.88;el.L.1T.o.2Z(o.88)}if(o.64){el.L.1T.64=o.64}el.L.1T.o.B(\'Y\',\'1O\').B(\'Z\',el.L.4m.w+\'S\');if(o.5z&&o.5z==\'Q\'){el.L.1T.5z=\'Q\';el.L.1T.o.B(\'Q\',t+\'S\')}P{el.L.1T.5z=\'4l\';el.L.1T.o.B(\'4l\',b+\'S\')}el.L.1T.au=o.au?o.au:\' \';1Y(D i=0;i<el.L.1Q.1h;i++){7I=T(i)+1;el.L.1T.o.1R(\'<a 3f="#\'+7I+o.1Z+\'" 6A="ku" 45="\'+el.L.1Q[i].6v+\'">\'+7I+\'</a>\'+(7I!=el.L.1Q.1h?el.L.1T.au:\'\'))}k(\'a\',el.L.1T.o).1H(\'5G\',u(){k.2A.go({8A:q})});el.L.1T.4q=k.1a.2p(el.L.1T.o.K(0))}if(o.6s||o.8l){el.L.2w={};1Z.1R(\'<26 6A="eK">&7J;</26>\');el.L.2w.o=k(\'.eK\',el);if(o.8l){el.L.2w.8l=o.8l;el.L.2w.o.2Z(o.8l)}el.L.2w.o.B(\'Y\',\'1O\').B(\'Z\',el.L.4m.w+\'S\');if(o.6s&&o.6s==\'Q\'){el.L.2w.6s=\'Q\';el.L.2w.o.B(\'Q\',(el.L.1T&&el.L.1T.5z==\'Q\'?el.L.1T.4q.hb+t:t)+\'S\')}P{el.L.2w.6s=\'4l\';el.L.2w.o.B(\'4l\',(el.L.1T&&el.L.1T.5z==\'4l\'?el.L.1T.4q.hb+b:b)+\'S\')}el.L.2w.4q=k.1a.2p(el.L.2w.o.K(0))}if(o.az){el.L.3r={az:o.az};1Z.1R(\'<a 3f="#2\'+o.1Z+\'" 6A="eR">&7J;</a>\');el.L.3r.o=k(\'.eR\',el);el.L.3r.o.B(\'Y\',\'1O\').B(\'19\',\'1n\').B(\'2Y\',\'2O\').B(\'4w\',\'eB\').2Z(el.L.3r.az);el.L.3r.o.1H(\'5G\',k.2A.eS)}if(o.av){el.L.3s={av:o.av};1Z.1R(\'<a 3f="#0\'+o.1Z+\'" 6A="ev">&7J;</a>\');el.L.3s.o=k(\'.ev\',el);el.L.3s.o.B(\'Y\',\'1O\').B(\'19\',\'1n\').B(\'2Y\',\'2O\').B(\'4w\',\'eB\').2Z(el.L.3s.av);el.L.3s.o.1H(\'5G\',k.2A.eG)}1Z.cA(\'<26 6A="cz"></26>\');el.L.5F=k(\'.cz\',el);el.L.5F.B(\'Y\',\'1O\').B(\'Q\',\'3c\').B(\'O\',\'3c\').B(\'19\',\'1n\');if(o.2a){1Z.cA(\'<26 6A="eD" 18="19: 1n;"><1U 2M="\'+o.2a+\'" /></26>\');el.L.2a=k(\'.eD\',el);el.L.2a.B(\'Y\',\'1O\');D 1U=11 aH();1U.X=o.1Z;1U.2M=o.2a;if(1U.23){1U.6B=U;k.2A.go({2a:1U})}P{1U.6B=u(){k.2A.go({2a:q})}}}P{k.2A.go({1Z:el})}if(o.cB){do=T(o.cB)*aF}k.2A.5E[o.1Z]=o.cB?1V.6I(\'k.2A.2H(\\\'\'+o.1Z+\'\\\')\',do):U}};k.X=k.2A.2s;k.8e={cN:u(e){3O=e.7F||e.7A||-1;if(3O==9){if(1V.2l){1V.2l.cj=1b;1V.2l.ci=I}P{e.al();e.am()}if(q.aI){1j.6G.du().31="\\t";q.dv=u(){q.6D();q.dv=U}}P if(q.aU){28=q.5B;2X=q.dq;q.2v=q.2v.iL(0,28)+"\\t"+q.2v.hm(2X);q.aU(28+1,28+1);q.6D()}E I}},58:u(){E q.1B(u(){if(q.7D&&q.7D==1b){k(q).3p(\'7E\',k.8e.cN);q.7D=I}})},2s:u(){E q.1B(u(){if(q.4S==\'cQ\'&&(!q.7D||q.7D==I)){k(q).1H(\'7E\',k.8e.cN);q.7D=1b}})}};k.fn.21({hS:k.8e.2s,hP:k.8e.58});',62,1292,'||||||||||||||||||||jQuery||||||this||||function||||||dragCfg|css|elm|var|return|dragged|easing|speed|false|callback|get|ss|options|iAuto|left|else|top|iResize|px|parseInt|null|height|oldStyle|slideshow|position|width||new|iDrag||Math||||style|display|iUtil|true|helper|subject|case|autoCFG|resizeOptions|length|dropCfg|document|iEL|carouselCfg|duration|none|interfaceFX|attr|sizes|break|pointer|iSort|type|ImageBox|queue|iDrop|iAutoscroller|slide|resizeElement|each|oC|wb|newSizes|apply|fisheyeCfg|bind|delta|opacity|constructor|custom|pos|axis|absolute|size|images|append|items|slideslinks|img|window|firstNum|255|for|container||extend|show|complete|cont||div||start|elsToScroll|loader|100|oR||body|oldP|selectedItem|typeof|elem|accordionCfg|props|event|parseFloat|newPosition|containment|getSize|field|ny|build|iTooltip|selectHelper|value|slideCaption|nx|relative|tp|islideshow|border|Function|step|block|itemWidth|hide|timer|nr|limit|fractions|dequeue|src|right|hidden|direction|PI|getPosition|cursorAt|onChange|onShow|scrollTop|result|end|overflow|addClass|parentData|text|||||||||scr|className|0px|iSlider|parentNode|href|scrollLeft|browser|onHide|visibility|item|pre|switch|selectdrug|wrapper|unbind|newCoords|nextslide|prevslide|createElement|values|max|html|currentslide|handle|onSlide|margins|zIndex|wrs|min|iframe|indexOf|valueToAdd|mousemove|pageSize|zones|multipleSeparator|iExpander|curCSS|canvas|pressedKey|accept|resizeDirection|abs|onStop|diff|handlers|fadeDuration|highlighted|dhs|toggle|dragElem||times||test|getPointer|title|distance||so|vp|horizontally|offsetWidth|startLeft|out|transferEl|startTop|subjectValue|lastSuggestion|vertically|ghosting|DropOutDirectiont|bottom|oP|iteration|lastValue|removeClass|dimm|slideCfg|ifxFirstDisplay|currentPointer|clear|replace|fontSize|onDrag|down|percent|onStart|nWidth|color|ratio|elToScroll|fieldData|rel|context|msie|documentElement|params|to|shs|dragHandle|fxCheckTag|els|nextImage|prevImage|tagName|tooltipCFG|up|helperclass|endLeft|paddingLeft|currentStyle|borderTopWidth||halign|onclick|delay|nodeEl||chunks|endTop|destroy|dragmoveBy|borderLeftWidth|mousedown|nHeight|from|dhe|containerW|string|slidePos|si|collected|marginLeft|overzone|marginBottom|getAttribute|marginTop|marginRight|toAdd|zonex|clonedEl|empty|newStyles|cos|hight|toWrite|zoney|linksPosition|OpenClose|selectionStart|clientScroll|cnt|slideshows|holder|click|restoreStyle|blur|onDragModifier|animate|elS|paddingBottom|toDrag|sw|close|post|animationHandler|styles|containerH|prop|sortCfg|BlindDirection|nmp|pow|toLowerCase||mouseup|oldVisibility|offsetHeight|activeLinkClass|old|paddingTop|grid|point|filter|onSelect|url|clearInterval|fxh|currentPanel|elementData|borderBottomWidth|getBorder|cur|paddingRight|borderRightWidth|puff|snapDistance|tolerance|revert|hpc|maxWidth|currentRel|captionPosition|Expander|orig|caption|random|3000|iFisheye|Scale|class|onload|wr|focus|restore|128|selection|parseColor|setInterval|current|selRange|captionText|itemHeight|outerContainer|newDimensions|totalImages|getHeight|reflections|keyup|sliders|imageEl|getWidth|getScroll|margin|Draggable|onHighlight|selectClass|getTime|Date|oldStyleAttr|onClick||scrollIntoView|firstChild||data|ActiveXObject|Array|focused|accordionPos|open|backgroundColor|zoneh|split|oD|zonew|fadeOut|user|fadeIn|Object|while|minLeft|nw|startDrag|minTop|captionEl|newTop|newLeft|frameClass|increment|F0|0x|keyCode|139|toInteger|hasTabsEnabled|keydown|charCode|cssRules|rule|indic|nbsp|rgb|np|oldDisplay|opera|radiusY|positionItems|onOut|proximity|efx|onHover|hash|changed|init|sc|inFrontOf|selectKeyHelper||selectCurrent|getSizeLite|1px|contBorders||ts|parentEl|linksClass|parentBorders|yproc|imgs|nRx|fnc|iTTabs|panels|insideParent|fontWeight|object|nRy|clientWidth|captionClass|namedColors|offsetLeft|serialize|cssSides|mouseout|activeClass|targetEl|offsetTop|expand|stop|400|pr|directionIncrement|clientHeight|link|showImage|move|sx|containerSize|createTextNode|jEl|imageSrc|ser|newPos|selectedone|minHeight|maxHeight|gallery|dir|applyOn|overlay|sh|content|maxRight|maxBottom|tooltipHelper|count|onselectstop|onselect|select|li|reflectionSize|padding|selectBorders|cursor|png|parent|finishedPre|sin|xproc|ImageBoxPrevImage|ImageBoxNextImage|bounceout|animationInProgress|opened|sy|destroyWrapper|buildWrapper|diffWidth|diffHeight|iIndex|diffX|diffY|prot|hidehelper|dEs|isDraggable|onDrop|minWidth|side|isDroppable|onActivate|dragstop|startTime|211|192|nodeName|self|oldPosition|exec|opt|getValues|styleSheets|sideEnd|borderColor|ne|handleEl|unit|DoFold|5625|oldTitle|SliderContainer|unfold|9999|ScrollTo|cssText|oldColor|alpha|2000|prev|selectKeyUp|os|selectKeyDown|selectcheck|dragEl|checkhover|DraggableDestroy|next|key|hoverclass|activeclass|sl|st|image||panelSelector|headerSelector|hoverClass|panelHeight|hideImage|headers|getPadding|iCarousel|preventDefault|stopPropagation|itemMinWidth|auto|getFieldValues|ImageBoxOuterContainer|prevEl|nextImageEl|linkRel|linksSeparator|prevslideClass|progid|DXImageTransform|Microsoft|nextslideClass|valToAdd|remove|prevImageEl|nextEl|childs|1000|default|Image|createTextRange|positionContainer|helperClass|minchars|source|itemsText|multiple|lnk|posx|autofill|reflexions|blind|setSelectionRange|mouseover|inCache|ul|protectRotation|maxRotation|gradient|setTimeout|index|elPosition|writeItems|String|ImageBoxIframe|transparent|center|textAlign|paddingRightSize|paddingTopSize|bounce|loadImage|borderLeftSize|borderBottomSize|borderRightSize|ImageBoxCaption|ImageBoxCurrentImage|moveDrag|ImageBoxOverlay|paddings|borders|idsa|firstStep|currentValue|getClient||stopDrag|borderTopSize|autocomplete|zoom|300|hidefocused|intersect|INPUT|inputWidth|fade|extraWidth|sortable|restricted|isSlider|tabindex|fitToContainer|snapToGrid|slider|prevTop|prevLeft|floats|getPositionLite|modifyContainer|getContainment|lastSi|SliderIteration|sliderEl|selectstop|match|linear|character|no|bouncein|captionImages|asin|Alpha|Selectserialize|mouse|initialPosition|measure|clearTimeout|helperSize|getMargins|tooltipURL|keyPressed|applyOnHover|closeEl|10000|parentPos|sliderSize|sliderPos|angle|returnValue|cancelBubble|spacer|oldBorder|pulse|169|entities|RegExp|Color|Pulsate||rotationSpeed|parseStyle|stopAnim|cssSidesEnd|shake|Shake|slideshowHolder|prepend|autoplay|floatVal|borderWidth|scroll|paddingY|pValue|letterSpacing|paddingX|paddingBottomSize|pause|oBor|clnt|doTab|autoSize|getElementById|TEXTAREA|Number|traverseDOM|func|draginit|loaderWidth|scrollHeight|paddingLeftSize|scrollWidth|oneIsSortable|innerWidth|innerHeight|shrink|windowSize|unselectable|oPad|dragmove|oldFloat|cssProps|colorCssProps|107|doScroll|addItem|SortableAddItem||DroppableDestroy|fxe||interval|after|insertBefore||sqrt|cloneNode|time|check|selectionEnd|offsetParent|Width|sortHelper|createRange|onblur|valign|||onout|224|posy|wid|isSortable|165|zindex|245|notColor|140|240|230|144|styleFloat|onhover|Droppable|emptyGIF|relAttr|visible|captionSize|dragstart|getElementsByTagName|listStyle|dragHelper|getHeightMinMax|onResize|ImageBoxCaptionText|ImageBoxContainer|ImageBoxCaptionImages||textImage|clientSize|textImageFrom|userSelect|onDragStop|slidePad|slideBor|highlight|shc|hlt|checkdrop|fit||loaderHeight||onDragStart|KhtmlUserSelect|remeasure|||on|fadeTo|ImageBoxLoader||500|||imageTypes|slideshowPrevslide|javascript|selectstopApply|scrolling|frameborder|hrefAttr|30px|jpg|slideshowLoader|selectedclass|gif|goprev|oldOverflow|isFunction|imagebox|slideshowCaption|slideshowLinks|directions|overlayOpacity|se|trim|textDecoration|slideshowNextSlide|gonext|closeHTML|selectcheckApply|loaderSRC|selectstart|isSelectable|360|radiusX|set|grow|hoverItem|SlideOutUp|leftUnit|boxModel|interfaceColorFX|fakeAccordionClass|togglever|elType|iBounce|paddingBottomUnit|wordSpacing|150|mousex|iAccordion|fontFamily|togglehor|fontUnit|filteredPosition|paddingTopUnit|parte|itemZIndex||selRange2|finish|paddingLeftUnit|moveStart|paddingRightUnit|xml|itransferTo|borderLeftUnit|borderTopUnit||update|BlindUp||borderRightUnit|checkCache|getSelectionStart|borderBottomUnit|tooltipTitle|easeout|expanderHelper|fontStyle|fontStretch|containerMaxx|yfrac|topUnit|containerMaxy|clickItem|BlindDown|off|inputValue|fracH|fontVariant|rgba|maxy|maxx|keypress|fracW|xfrac|horizontal|addColorStop|htmlEntities|vertical|dragmoveByKey|autocompleteIframe|onslide|fold|parts|SlideInUp|getContext|protect|autocompleteHelper|olive|orange|pink|white|maroon|navy|magenta|203|193|rotationTimer|lightpink||red|lightyellow|182|lime||purple|silver|Top|||inset|outset|SlideOutRight|SlideInRight|ridge|groove|dashed|solid|double|SlideToggleLeft|SlideOutLeft|SlideOutDown|SlideInDown|SlideToggleUp|scrollTo|selectorText|rules|borderStyle|SlideInLeft|SlideToggleDown|dotted|SlideToggleRight|textIndent|borderBottomColor|borderLeftColor|borderRightColor|outlineWidth|outlineOffset|TransferTo|transferHelper|lineHeight|borderTopColor|outlineColor|hover|Accordion|isNaN|Carousel|stopAll|||Right|Bottom|Left|yellow|215|option|frameset|optgroup|meta|substr|frame|script|col|colgroup||th|header|removeChild|float|ol|finishx|fxWrapper|starty|table|form|w_|input|textarea|button|tfoot|thead|pageX|drawImage|clientX|pageY|clientY|globalCompositeOperation|destination|DisableTabs|createLinearGradient|fillStyle|EnableTabs|scale|nextSibling|prototype|tr|td|tbody|AlphaImageLoader|fixPNG|purgeEvents|translate|centerEl|save|cssFloat|startx|fuchsia|148|gold|green|indigo|darkviolet||122||204||darkred|darksalmon|233|130|khaki||lightcyan|lightgreen|238|fillRect||fill|216|appVersion||WebKit|lightblue|173|153|darkorchid|black|220|blue|brown|cyan|beige|azure|finishOpacity|appendChild|substring|aqua|darkblue|darkcyan|darkmagenta|darkolivegreen|navigator|darkorange|183|189|darkgrey|flipv|darkgreen|darkkhaki|lightgrey|amp|BlindToggleHorizontally|BlindRight|BlindLeft|ResizableDestroy|Resizable|120|lineHeigt|collapse|BlindToggleVertically|moveEnd|elasticin|bounceboth|984375|elasticout|elasticboth|duplicate|ImageBoxClose|DropOutDown|DropInDown|load|DropToggleRight|DropInRight|Fold|UnFold|Shrink|Grow|FoldToggle|DropOutRight|DropToggleLeft|DropInUp|DropOutUp|DropToggleDown|DropToggleUp|DropOutLeft|DropInLeft|captiontext|625|9375|Fisheye|30001|list|loading|fix|imageLoaded|childNodes|Showing|onchange|30002|SortSerialize|Autocomplete|200|SortableDestroy|Sortable|resize|wh|firstResize|Slider|bmp|100000|jpeg|Selectable|ToolTip|easeboth|easein|nodeValue|http|first|before|last|112|SliderSetValues|110|SliderGetValues|array|Bounce|Autoexpand|onselectstart|CloseVertically|mozUserSelect|fromHandler|ondragstart|MozUserSelect|number|pW|toUpperCase|khtml|find|CloseHorizontally|SwitchHorizontally|ScrollToAnchors|Puff|slideshowLink|password|quot|OpenHorizontally|OpenVertically|SwitchVertically|IMG|lt|alt|par|moz|success|POST|recallDroppables|param|pt|location|Highlight|100000000|ajax|ondrop|name'.split('|'),0,{}))
diff --git a/doc/html/_static/jquery.js b/doc/html/_static/jquery.js
new file mode 100644
index 0000000..9263574
--- /dev/null
+++ b/doc/html/_static/jquery.js
@@ -0,0 +1,4376 @@
+/*!
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){
+
+var 
+	// Will speed up references to window, and allows munging its name.
+	window = this,
+	// Will speed up references to undefined, and allows munging its name.
+	undefined,
+	// Map over jQuery in case of overwrite
+	_jQuery = window.jQuery,
+	// Map over the $ in case of overwrite
+	_$ = window.$,
+
+	jQuery = window.jQuery = window.$ = function( selector, context ) {
+		// The jQuery object is actually just the init constructor 'enhanced'
+		return new jQuery.fn.init( selector, context );
+	},
+
+	// A simple way to check for HTML strings or ID strings
+	// (both of which we optimize for)
+	quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
+	// Is it a simple selector
+	isSimple = /^.[^:#\[\.,]*$/;
+
+jQuery.fn = jQuery.prototype = {
+	init: function( selector, context ) {
+		// Make sure that a selection was provided
+		selector = selector || document;
+
+		// Handle $(DOMElement)
+		if ( selector.nodeType ) {
+			this[0] = selector;
+			this.length = 1;
+			this.context = selector;
+			return this;
+		}
+		// Handle HTML strings
+		if ( typeof selector === "string" ) {
+			// Are we dealing with HTML string or an ID?
+			var match = quickExpr.exec( selector );
+
+			// Verify a match, and that no context was specified for #id
+			if ( match && (match[1] || !context) ) {
+
+				// HANDLE: $(html) -> $(array)
+				if ( match[1] )
+					selector = jQuery.clean( [ match[1] ], context );
+
+				// HANDLE: $("#id")
+				else {
+					var elem = document.getElementById( match[3] );
+
+					// Handle the case where IE and Opera return items
+					// by name instead of ID
+					if ( elem && elem.id != match[3] )
+						return jQuery().find( selector );
+
+					// Otherwise, we inject the element directly into the jQuery object
+					var ret = jQuery( elem || [] );
+					ret.context = document;
+					ret.selector = selector;
+					return ret;
+				}
+
+			// HANDLE: $(expr, [context])
+			// (which is just equivalent to: $(content).find(expr)
+			} else
+				return jQuery( context ).find( selector );
+
+		// HANDLE: $(function)
+		// Shortcut for document ready
+		} else if ( jQuery.isFunction( selector ) )
+			return jQuery( document ).ready( selector );
+
+		// Make sure that old selector state is passed along
+		if ( selector.selector && selector.context ) {
+			this.selector = selector.selector;
+			this.context = selector.context;
+		}
+
+		return this.setArray(jQuery.isArray( selector ) ?
+			selector :
+			jQuery.makeArray(selector));
+	},
+
+	// Start with an empty selector
+	selector: "",
+
+	// The current version of jQuery being used
+	jquery: "1.3.2",
+
+	// The number of elements contained in the matched element set
+	size: function() {
+		return this.length;
+	},
+
+	// Get the Nth element in the matched element set OR
+	// Get the whole matched element set as a clean array
+	get: function( num ) {
+		return num === undefined ?
+
+			// Return a 'clean' array
+			Array.prototype.slice.call( this ) :
+
+			// Return just the object
+			this[ num ];
+	},
+
+	// Take an array of elements and push it onto the stack
+	// (returning the new matched element set)
+	pushStack: function( elems, name, selector ) {
+		// Build a new jQuery matched element set
+		var ret = jQuery( elems );
+
+		// Add the old object onto the stack (as a reference)
+		ret.prevObject = this;
+
+		ret.context = this.context;
+
+		if ( name === "find" )
+			ret.selector = this.selector + (this.selector ? " " : "") + selector;
+		else if ( name )
+			ret.selector = this.selector + "." + name + "(" + selector + ")";
+
+		// Return the newly-formed element set
+		return ret;
+	},
+
+	// Force the current matched set of elements to become
+	// the specified array of elements (destroying the stack in the process)
+	// You should use pushStack() in order to do this, but maintain the stack
+	setArray: function( elems ) {
+		// Resetting the length to 0, then using the native Array push
+		// is a super-fast way to populate an object with array-like properties
+		this.length = 0;
+		Array.prototype.push.apply( this, elems );
+
+		return this;
+	},
+
+	// Execute a callback for every element in the matched set.
+	// (You can seed the arguments with an array of args, but this is
+	// only used internally.)
+	each: function( callback, args ) {
+		return jQuery.each( this, callback, args );
+	},
+
+	// Determine the position of an element within
+	// the matched set of elements
+	index: function( elem ) {
+		// Locate the position of the desired element
+		return jQuery.inArray(
+			// If it receives a jQuery object, the first element is used
+			elem && elem.jquery ? elem[0] : elem
+		, this );
+	},
+
+	attr: function( name, value, type ) {
+		var options = name;
+
+		// Look for the case where we're accessing a style value
+		if ( typeof name === "string" )
+			if ( value === undefined )
+				return this[0] && jQuery[ type || "attr" ]( this[0], name );
+
+			else {
+				options = {};
+				options[ name ] = value;
+			}
+
+		// Check to see if we're setting style values
+		return this.each(function(i){
+			// Set all the styles
+			for ( name in options )
+				jQuery.attr(
+					type ?
+						this.style :
+						this,
+					name, jQuery.prop( this, options[ name ], type, i, name )
+				);
+		});
+	},
+
+	css: function( key, value ) {
+		// ignore negative width and height values
+		if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
+			value = undefined;
+		return this.attr( key, value, "curCSS" );
+	},
+
+	text: function( text ) {
+		if ( typeof text !== "object" && text != null )
+			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+
+		var ret = "";
+
+		jQuery.each( text || this, function(){
+			jQuery.each( this.childNodes, function(){
+				if ( this.nodeType != 8 )
+					ret += this.nodeType != 1 ?
+						this.nodeValue :
+						jQuery.fn.text( [ this ] );
+			});
+		});
+
+		return ret;
+	},
+
+	wrapAll: function( html ) {
+		if ( this[0] ) {
+			// The elements to wrap the target around
+			var wrap = jQuery( html, this[0].ownerDocument ).clone();
+
+			if ( this[0].parentNode )
+				wrap.insertBefore( this[0] );
+
+			wrap.map(function(){
+				var elem = this;
+
+				while ( elem.firstChild )
+					elem = elem.firstChild;
+
+				return elem;
+			}).append(this);
+		}
+
+		return this;
+	},
+
+	wrapInner: function( html ) {
+		return this.each(function(){
+			jQuery( this ).contents().wrapAll( html );
+		});
+	},
+
+	wrap: function( html ) {
+		return this.each(function(){
+			jQuery( this ).wrapAll( html );
+		});
+	},
+
+	append: function() {
+		return this.domManip(arguments, true, function(elem){
+			if (this.nodeType == 1)
+				this.appendChild( elem );
+		});
+	},
+
+	prepend: function() {
+		return this.domManip(arguments, true, function(elem){
+			if (this.nodeType == 1)
+				this.insertBefore( elem, this.firstChild );
+		});
+	},
+
+	before: function() {
+		return this.domManip(arguments, false, function(elem){
+			this.parentNode.insertBefore( elem, this );
+		});
+	},
+
+	after: function() {
+		return this.domManip(arguments, false, function(elem){
+			this.parentNode.insertBefore( elem, this.nextSibling );
+		});
+	},
+
+	end: function() {
+		return this.prevObject || jQuery( [] );
+	},
+
+	// For internal use only.
+	// Behaves like an Array's method, not like a jQuery method.
+	push: [].push,
+	sort: [].sort,
+	splice: [].splice,
+
+	find: function( selector ) {
+		if ( this.length === 1 ) {
+			var ret = this.pushStack( [], "find", selector );
+			ret.length = 0;
+			jQuery.find( selector, this[0], ret );
+			return ret;
+		} else {
+			return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
+				return jQuery.find( selector, elem );
+			})), "find", selector );
+		}
+	},
+
+	clone: function( events ) {
+		// Do the clone
+		var ret = this.map(function(){
+			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
+				// IE copies events bound via attachEvent when
+				// using cloneNode. Calling detachEvent on the
+				// clone will also remove the events from the orignal
+				// In order to get around this, we use innerHTML.
+				// Unfortunately, this means some modifications to
+				// attributes in IE that are actually only stored
+				// as properties will not be copied (such as the
+				// the name attribute on an input).
+				var html = this.outerHTML;
+				if ( !html ) {
+					var div = this.ownerDocument.createElement("div");
+					div.appendChild( this.cloneNode(true) );
+					html = div.innerHTML;
+				}
+
+				return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
+			} else
+				return this.cloneNode(true);
+		});
+
+		// Copy the events from the original to the clone
+		if ( events === true ) {
+			var orig = this.find("*").andSelf(), i = 0;
+
+			ret.find("*").andSelf().each(function(){
+				if ( this.nodeName !== orig[i].nodeName )
+					return;
+
+				var events = jQuery.data( orig[i], "events" );
+
+				for ( var type in events ) {
+					for ( var handler in events[ type ] ) {
+						jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
+					}
+				}
+
+				i++;
+			});
+		}
+
+		// Return the cloned set
+		return ret;
+	},
+
+	filter: function( selector ) {
+		return this.pushStack(
+			jQuery.isFunction( selector ) &&
+			jQuery.grep(this, function(elem, i){
+				return selector.call( elem, i );
+			}) ||
+
+			jQuery.multiFilter( selector, jQuery.grep(this, function(elem){
+				return elem.nodeType === 1;
+			}) ), "filter", selector );
+	},
+
+	closest: function( selector ) {
+		var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
+			closer = 0;
+
+		return this.map(function(){
+			var cur = this;
+			while ( cur && cur.ownerDocument ) {
+				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
+					jQuery.data(cur, "closest", closer);
+					return cur;
+				}
+				cur = cur.parentNode;
+				closer++;
+			}
+		});
+	},
+
+	not: function( selector ) {
+		if ( typeof selector === "string" )
+			// test special case where just one selector is passed in
+			if ( isSimple.test( selector ) )
+				return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
+			else
+				selector = jQuery.multiFilter( selector, this );
+
+		var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
+		return this.filter(function() {
+			return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
+		});
+	},
+
+	add: function( selector ) {
+		return this.pushStack( jQuery.unique( jQuery.merge(
+			this.get(),
+			typeof selector === "string" ?
+				jQuery( selector ) :
+				jQuery.makeArray( selector )
+		)));
+	},
+
+	is: function( selector ) {
+		return !!selector && jQuery.multiFilter( selector, this ).length > 0;
+	},
+
+	hasClass: function( selector ) {
+		return !!selector && this.is( "." + selector );
+	},
+
+	val: function( value ) {
+		if ( value === undefined ) {			
+			var elem = this[0];
+
+			if ( elem ) {
+				if( jQuery.nodeName( elem, 'option' ) )
+					return (elem.attributes.value || {}).specified ? elem.value : elem.text;
+				
+				// We need to handle select boxes special
+				if ( jQuery.nodeName( elem, "select" ) ) {
+					var index = elem.selectedIndex,
+						values = [],
+						options = elem.options,
+						one = elem.type == "select-one";
+
+					// Nothing was selected
+					if ( index < 0 )
+						return null;
+
+					// Loop through all the selected options
+					for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+						var option = options[ i ];
+
+						if ( option.selected ) {
+							// Get the specifc value for the option
+							value = jQuery(option).val();
+
+							// We don't need an array for one selects
+							if ( one )
+								return value;
+
+							// Multi-Selects return an array
+							values.push( value );
+						}
+					}
+
+					return values;				
+				}
+
+				// Everything else, we just grab the value
+				return (elem.value || "").replace(/\r/g, "");
+
+			}
+
+			return undefined;
+		}
+
+		if ( typeof value === "number" )
+			value += '';
+
+		return this.each(function(){
+			if ( this.nodeType != 1 )
+				return;
+
+			if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) )
+				this.checked = (jQuery.inArray(this.value, value) >= 0 ||
+					jQuery.inArray(this.name, value) >= 0);
+
+			else if ( jQuery.nodeName( this, "select" ) ) {
+				var values = jQuery.makeArray(value);
+
+				jQuery( "option", this ).each(function(){
+					this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
+						jQuery.inArray( this.text, values ) >= 0);
+				});
+
+				if ( !values.length )
+					this.selectedIndex = -1;
+
+			} else
+				this.value = value;
+		});
+	},
+
+	html: function( value ) {
+		return value === undefined ?
+			(this[0] ?
+				this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
+				null) :
+			this.empty().append( value );
+	},
+
+	replaceWith: function( value ) {
+		return this.after( value ).remove();
+	},
+
+	eq: function( i ) {
+		return this.slice( i, +i + 1 );
+	},
+
+	slice: function() {
+		return this.pushStack( Array.prototype.slice.apply( this, arguments ),
+			"slice", Array.prototype.slice.call(arguments).join(",") );
+	},
+
+	map: function( callback ) {
+		return this.pushStack( jQuery.map(this, function(elem, i){
+			return callback.call( elem, i, elem );
+		}));
+	},
+
+	andSelf: function() {
+		return this.add( this.prevObject );
+	},
+
+	domManip: function( args, table, callback ) {
+		if ( this[0] ) {
+			var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
+				scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
+				first = fragment.firstChild;
+
+			if ( first )
+				for ( var i = 0, l = this.length; i < l; i++ )
+					callback.call( root(this[i], first), this.length > 1 || i > 0 ?
+							fragment.cloneNode(true) : fragment );
+		
+			if ( scripts )
+				jQuery.each( scripts, evalScript );
+		}
+
+		return this;
+		
+		function root( elem, cur ) {
+			return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
+				(elem.getElementsByTagName("tbody")[0] ||
+				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+				elem;
+		}
+	}
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+function evalScript( i, elem ) {
+	if ( elem.src )
+		jQuery.ajax({
+			url: elem.src,
+			async: false,
+			dataType: "script"
+		});
+
+	else
+		jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+
+	if ( elem.parentNode )
+		elem.parentNode.removeChild( elem );
+}
+
+function now(){
+	return +new Date;
+}
+
+jQuery.extend = jQuery.fn.extend = function() {
+	// copy reference to target object
+	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+	// Handle a deep copy situation
+	if ( typeof target === "boolean" ) {
+		deep = target;
+		target = arguments[1] || {};
+		// skip the boolean and the target
+		i = 2;
+	}
+
+	// Handle case when target is a string or something (possible in deep copy)
+	if ( typeof target !== "object" && !jQuery.isFunction(target) )
+		target = {};
+
+	// extend jQuery itself if only one argument is passed
+	if ( length == i ) {
+		target = this;
+		--i;
+	}
+
+	for ( ; i < length; i++ )
+		// Only deal with non-null/undefined values
+		if ( (options = arguments[ i ]) != null )
+			// Extend the base object
+			for ( var name in options ) {
+				var src = target[ name ], copy = options[ name ];
+
+				// Prevent never-ending loop
+				if ( target === copy )
+					continue;
+
+				// Recurse if we're merging object values
+				if ( deep && copy && typeof copy === "object" && !copy.nodeType )
+					target[ name ] = jQuery.extend( deep, 
+						// Never move original objects, clone them
+						src || ( copy.length != null ? [ ] : { } )
+					, copy );
+
+				// Don't bring in undefined values
+				else if ( copy !== undefined )
+					target[ name ] = copy;
+
+			}
+
+	// Return the modified object
+	return target;
+};
+
+// exclude the following css properties to add px
+var	exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+	// cache defaultView
+	defaultView = document.defaultView || {},
+	toString = Object.prototype.toString;
+
+jQuery.extend({
+	noConflict: function( deep ) {
+		window.$ = _$;
+
+		if ( deep )
+			window.jQuery = _jQuery;
+
+		return jQuery;
+	},
+
+	// See test/unit/core.js for details concerning isFunction.
+	// Since version 1.3, DOM methods and functions like alert
+	// aren't supported. They return false on IE (#2968).
+	isFunction: function( obj ) {
+		return toString.call(obj) === "[object Function]";
+	},
+
+	isArray: function( obj ) {
+		return toString.call(obj) === "[object Array]";
+	},
+
+	// check if an element is in a (or is an) XML document
+	isXMLDoc: function( elem ) {
+		return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+			!!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
+	},
+
+	// Evalulates a script in a global context
+	globalEval: function( data ) {
+		if ( data && /\S/.test(data) ) {
+			// Inspired by code by Andrea Giammarchi
+			// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
+			var head = document.getElementsByTagName("head")[0] || document.documentElement,
+				script = document.createElement("script");
+
+			script.type = "text/javascript";
+			if ( jQuery.support.scriptEval )
+				script.appendChild( document.createTextNode( data ) );
+			else
+				script.text = data;
+
+			// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+			// This arises when a base node is used (#2709).
+			head.insertBefore( script, head.firstChild );
+			head.removeChild( script );
+		}
+	},
+
+	nodeName: function( elem, name ) {
+		return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
+	},
+
+	// args is for internal usage only
+	each: function( object, callback, args ) {
+		var name, i = 0, length = object.length;
+
+		if ( args ) {
+			if ( length === undefined ) {
+				for ( name in object )
+					if ( callback.apply( object[ name ], args ) === false )
+						break;
+			} else
+				for ( ; i < length; )
+					if ( callback.apply( object[ i++ ], args ) === false )
+						break;
+
+		// A special, fast, case for the most common use of each
+		} else {
+			if ( length === undefined ) {
+				for ( name in object )
+					if ( callback.call( object[ name ], name, object[ name ] ) === false )
+						break;
+			} else
+				for ( var value = object[0];
+					i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
+		}
+
+		return object;
+	},
+
+	prop: function( elem, value, type, i, name ) {
+		// Handle executable functions
+		if ( jQuery.isFunction( value ) )
+			value = value.call( elem, i );
+
+		// Handle passing in a number to a CSS property
+		return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ?
+			value + "px" :
+			value;
+	},
+
+	className: {
+		// internal only, use addClass("class")
+		add: function( elem, classNames ) {
+			jQuery.each((classNames || "").split(/\s+/), function(i, className){
+				if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
+					elem.className += (elem.className ? " " : "") + className;
+			});
+		},
+
+		// internal only, use removeClass("class")
+		remove: function( elem, classNames ) {
+			if (elem.nodeType == 1)
+				elem.className = classNames !== undefined ?
+					jQuery.grep(elem.className.split(/\s+/), function(className){
+						return !jQuery.className.has( classNames, className );
+					}).join(" ") :
+					"";
+		},
+
+		// internal only, use hasClass("class")
+		has: function( elem, className ) {
+			return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
+		}
+	},
+
+	// A method for quickly swapping in/out CSS properties to get correct calculations
+	swap: function( elem, options, callback ) {
+		var old = {};
+		// Remember the old values, and insert the new ones
+		for ( var name in options ) {
+			old[ name ] = elem.style[ name ];
+			elem.style[ name ] = options[ name ];
+		}
+
+		callback.call( elem );
+
+		// Revert the old values
+		for ( var name in options )
+			elem.style[ name ] = old[ name ];
+	},
+
+	css: function( elem, name, force, extra ) {
+		if ( name == "width" || name == "height" ) {
+			var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
+
+			function getWH() {
+				val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
+
+				if ( extra === "border" )
+					return;
+
+				jQuery.each( which, function() {
+					if ( !extra )
+						val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+					if ( extra === "margin" )
+						val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
+					else
+						val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+				});
+			}
+
+			if ( elem.offsetWidth !== 0 )
+				getWH();
+			else
+				jQuery.swap( elem, props, getWH );
+
+			return Math.max(0, Math.round(val));
+		}
+
+		return jQuery.curCSS( elem, name, force );
+	},
+
+	curCSS: function( elem, name, force ) {
+		var ret, style = elem.style;
+
+		// We need to handle opacity special in IE
+		if ( name == "opacity" && !jQuery.support.opacity ) {
+			ret = jQuery.attr( style, "opacity" );
+
+			return ret == "" ?
+				"1" :
+				ret;
+		}
+
+		// Make sure we're using the right name for getting the float value
+		if ( name.match( /float/i ) )
+			name = styleFloat;
+
+		if ( !force && style && style[ name ] )
+			ret = style[ name ];
+
+		else if ( defaultView.getComputedStyle ) {
+
+			// Only "float" is needed here
+			if ( name.match( /float/i ) )
+				name = "float";
+
+			name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
+
+			var computedStyle = defaultView.getComputedStyle( elem, null );
+
+			if ( computedStyle )
+				ret = computedStyle.getPropertyValue( name );
+
+			// We should always get a number back from opacity
+			if ( name == "opacity" && ret == "" )
+				ret = "1";
+
+		} else if ( elem.currentStyle ) {
+			var camelCase = name.replace(/\-(\w)/g, function(all, letter){
+				return letter.toUpperCase();
+			});
+
+			ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+
+			// From the awesome hack by Dean Edwards
+			// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+			// If we're not dealing with a regular pixel number
+			// but a number that has a weird ending, we need to convert it to pixels
+			if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+				// Remember the original values
+				var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+				// Put in the new values to get a computed value out
+				elem.runtimeStyle.left = elem.currentStyle.left;
+				style.left = ret || 0;
+				ret = style.pixelLeft + "px";
+
+				// Revert the changed values
+				style.left = left;
+				elem.runtimeStyle.left = rsLeft;
+			}
+		}
+
+		return ret;
+	},
+
+	clean: function( elems, context, fragment ) {
+		context = context || document;
+
+		// !context.createElement fails in IE with an error but returns typeof 'object'
+		if ( typeof context.createElement === "undefined" )
+			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+
+		// If a single string is passed in and it's a single tag
+		// just do a createElement and skip the rest
+		if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
+			var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
+			if ( match )
+				return [ context.createElement( match[1] ) ];
+		}
+
+		var ret = [], scripts = [], div = context.createElement("div");
+
+		jQuery.each(elems, function(i, elem){
+			if ( typeof elem === "number" )
+				elem += '';
+
+			if ( !elem )
+				return;
+
+			// Convert html string into DOM nodes
+			if ( typeof elem === "string" ) {
+				// Fix "XHTML"-style tags in all browsers
+				elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
+					return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
+						all :
+						front + "></" + tag + ">";
+				});
+
+				// Trim whitespace, otherwise indexOf won't work as expected
+				var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
+
+				var wrap =
+					// option or optgroup
+					!tags.indexOf("<opt") &&
+					[ 1, "<select multiple='multiple'>", "</select>" ] ||
+
+					!tags.indexOf("<leg") &&
+					[ 1, "<fieldset>", "</fieldset>" ] ||
+
+					tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
+					[ 1, "<table>", "</table>" ] ||
+
+					!tags.indexOf("<tr") &&
+					[ 2, "<table><tbody>", "</tbody></table>" ] ||
+
+				 	// <thead> matched above
+					(!tags.indexOf("<td") || !tags.indexOf("<th")) &&
+					[ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
+
+					!tags.indexOf("<col") &&
+					[ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
+
+					// IE can't serialize <link> and <script> tags normally
+					!jQuery.support.htmlSerialize &&
+					[ 1, "div<div>", "</div>" ] ||
+
+					[ 0, "", "" ];
+
+				// Go to html and back, then peel off extra wrappers
+				div.innerHTML = wrap[1] + elem + wrap[2];
+
+				// Move to the right depth
+				while ( wrap[0]-- )
+					div = div.lastChild;
+
+				// Remove IE's autoinserted <tbody> from table fragments
+				if ( !jQuery.support.tbody ) {
+
+					// String was a <table>, *may* have spurious <tbody>
+					var hasBody = /<tbody/i.test(elem),
+						tbody = !tags.indexOf("<table") && !hasBody ?
+							div.firstChild && div.firstChild.childNodes :
+
+						// String was a bare <thead> or <tfoot>
+						wrap[1] == "<table>" && !hasBody ?
+							div.childNodes :
+							[];
+
+					for ( var j = tbody.length - 1; j >= 0 ; --j )
+						if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
+							tbody[ j ].parentNode.removeChild( tbody[ j ] );
+
+					}
+
+				// IE completely kills leading whitespace when innerHTML is used
+				if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
+					div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
+				
+				elem = jQuery.makeArray( div.childNodes );
+			}
+
+			if ( elem.nodeType )
+				ret.push( elem );
+			else
+				ret = jQuery.merge( ret, elem );
+
+		});
+
+		if ( fragment ) {
+			for ( var i = 0; ret[i]; i++ ) {
+				if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
+					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+				} else {
+					if ( ret[i].nodeType === 1 )
+						ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
+					fragment.appendChild( ret[i] );
+				}
+			}
+			
+			return scripts;
+		}
+
+		return ret;
+	},
+
+	attr: function( elem, name, value ) {
+		// don't set attributes on text and comment nodes
+		if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
+			return undefined;
+
+		var notxml = !jQuery.isXMLDoc( elem ),
+			// Whether we are setting (or getting)
+			set = value !== undefined;
+
+		// Try to normalize/fix the name
+		name = notxml && jQuery.props[ name ] || name;
+
+		// Only do all the following if this is a node (faster for style)
+		// IE elem.getAttribute passes even for style
+		if ( elem.tagName ) {
+
+			// These attributes require special treatment
+			var special = /href|src|style/.test( name );
+
+			// Safari mis-reports the default selected property of a hidden option
+			// Accessing the parent's selectedIndex property fixes it
+			if ( name == "selected" && elem.parentNode )
+				elem.parentNode.selectedIndex;
+
+			// If applicable, access the attribute via the DOM 0 way
+			if ( name in elem && notxml && !special ) {
+				if ( set ){
+					// We can't allow the type property to be changed (since it causes problems in IE)
+					if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
+						throw "type property can't be changed";
+
+					elem[ name ] = value;
+				}
+
+				// browsers index elements by id/name on forms, give priority to attributes.
+				if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
+					return elem.getAttributeNode( name ).nodeValue;
+
+				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+				if ( name == "tabIndex" ) {
+					var attributeNode = elem.getAttributeNode( "tabIndex" );
+					return attributeNode && attributeNode.specified
+						? attributeNode.value
+						: elem.nodeName.match(/(button|input|object|select|textarea)/i)
+							? 0
+							: elem.nodeName.match(/^(a|area)$/i) && elem.href
+								? 0
+								: undefined;
+				}
+
+				return elem[ name ];
+			}
+
+			if ( !jQuery.support.style && notxml &&  name == "style" )
+				return jQuery.attr( elem.style, "cssText", value );
+
+			if ( set )
+				// convert the value to a string (all browsers do this but IE) see #1070
+				elem.setAttribute( name, "" + value );
+
+			var attr = !jQuery.support.hrefNormalized && notxml && special
+					// Some attributes require a special call on IE
+					? elem.getAttribute( name, 2 )
+					: elem.getAttribute( name );
+
+			// Non-existent attributes return null, we normalize to undefined
+			return attr === null ? undefined : attr;
+		}
+
+		// elem is actually elem.style ... set the style
+
+		// IE uses filters for opacity
+		if ( !jQuery.support.opacity && name == "opacity" ) {
+			if ( set ) {
+				// IE has trouble with opacity if it does not have layout
+				// Force it by setting the zoom level
+				elem.zoom = 1;
+
+				// Set the alpha filter to set the opacity
+				elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
+					(parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
+			}
+
+			return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
+				(parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
+				"";
+		}
+
+		name = name.replace(/-([a-z])/ig, function(all, letter){
+			return letter.toUpperCase();
+		});
+
+		if ( set )
+			elem[ name ] = value;
+
+		return elem[ name ];
+	},
+
+	trim: function( text ) {
+		return (text || "").replace( /^\s+|\s+$/g, "" );
+	},
+
+	makeArray: function( array ) {
+		var ret = [];
+
+		if( array != null ){
+			var i = array.length;
+			// The window, strings (and functions) also have 'length'
+			if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
+				ret[0] = array;
+			else
+				while( i )
+					ret[--i] = array[i];
+		}
+
+		return ret;
+	},
+
+	inArray: function( elem, array ) {
+		for ( var i = 0, length = array.length; i < length; i++ )
+		// Use === because on IE, window == document
+			if ( array[ i ] === elem )
+				return i;
+
+		return -1;
+	},
+
+	merge: function( first, second ) {
+		// We have to loop this way because IE & Opera overwrite the length
+		// expando of getElementsByTagName
+		var i = 0, elem, pos = first.length;
+		// Also, we need to make sure that the correct elements are being returned
+		// (IE returns comment nodes in a '*' query)
+		if ( !jQuery.support.getAll ) {
+			while ( (elem = second[ i++ ]) != null )
+				if ( elem.nodeType != 8 )
+					first[ pos++ ] = elem;
+
+		} else
+			while ( (elem = second[ i++ ]) != null )
+				first[ pos++ ] = elem;
+
+		return first;
+	},
+
+	unique: function( array ) {
+		var ret = [], done = {};
+
+		try {
+
+			for ( var i = 0, length = array.length; i < length; i++ ) {
+				var id = jQuery.data( array[ i ] );
+
+				if ( !done[ id ] ) {
+					done[ id ] = true;
+					ret.push( array[ i ] );
+				}
+			}
+
+		} catch( e ) {
+			ret = array;
+		}
+
+		return ret;
+	},
+
+	grep: function( elems, callback, inv ) {
+		var ret = [];
+
+		// Go through the array, only saving the items
+		// that pass the validator function
+		for ( var i = 0, length = elems.length; i < length; i++ )
+			if ( !inv != !callback( elems[ i ], i ) )
+				ret.push( elems[ i ] );
+
+		return ret;
+	},
+
+	map: function( elems, callback ) {
+		var ret = [];
+
+		// Go through the array, translating each of the items to their
+		// new value (or values).
+		for ( var i = 0, length = elems.length; i < length; i++ ) {
+			var value = callback( elems[ i ], i );
+
+			if ( value != null )
+				ret[ ret.length ] = value;
+		}
+
+		return ret.concat.apply( [], ret );
+	}
+});
+
+// Use of jQuery.browser is deprecated.
+// It's included for backwards compatibility and plugins,
+// although they should work to migrate away.
+
+var userAgent = navigator.userAgent.toLowerCase();
+
+// Figure out what browser is being used
+jQuery.browser = {
+	version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
+	safari: /webkit/.test( userAgent ),
+	opera: /opera/.test( userAgent ),
+	msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
+	mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
+};
+
+jQuery.each({
+	parent: function(elem){return elem.parentNode;},
+	parents: function(elem){return jQuery.dir(elem,"parentNode");},
+	next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
+	prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
+	nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
+	prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
+	siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
+	children: function(elem){return jQuery.sibling(elem.firstChild);},
+	contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
+}, function(name, fn){
+	jQuery.fn[ name ] = function( selector ) {
+		var ret = jQuery.map( this, fn );
+
+		if ( selector && typeof selector == "string" )
+			ret = jQuery.multiFilter( selector, ret );
+
+		return this.pushStack( jQuery.unique( ret ), name, selector );
+	};
+});
+
+jQuery.each({
+	appendTo: "append",
+	prependTo: "prepend",
+	insertBefore: "before",
+	insertAfter: "after",
+	replaceAll: "replaceWith"
+}, function(name, original){
+	jQuery.fn[ name ] = function( selector ) {
+		var ret = [], insert = jQuery( selector );
+
+		for ( var i = 0, l = insert.length; i < l; i++ ) {
+			var elems = (i > 0 ? this.clone(true) : this).get();
+			jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
+			ret = ret.concat( elems );
+		}
+
+		return this.pushStack( ret, name, selector );
+	};
+});
+
+jQuery.each({
+	removeAttr: function( name ) {
+		jQuery.attr( this, name, "" );
+		if (this.nodeType == 1)
+			this.removeAttribute( name );
+	},
+
+	addClass: function( classNames ) {
+		jQuery.className.add( this, classNames );
+	},
+
+	removeClass: function( classNames ) {
+		jQuery.className.remove( this, classNames );
+	},
+
+	toggleClass: function( classNames, state ) {
+		if( typeof state !== "boolean" )
+			state = !jQuery.className.has( this, classNames );
+		jQuery.className[ state ? "add" : "remove" ]( this, classNames );
+	},
+
+	remove: function( selector ) {
+		if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
+			// Prevent memory leaks
+			jQuery( "*", this ).add([this]).each(function(){
+				jQuery.event.remove(this);
+				jQuery.removeData(this);
+			});
+			if (this.parentNode)
+				this.parentNode.removeChild( this );
+		}
+	},
+
+	empty: function() {
+		// Remove element nodes and prevent memory leaks
+		jQuery(this).children().remove();
+
+		// Remove any remaining nodes
+		while ( this.firstChild )
+			this.removeChild( this.firstChild );
+	}
+}, function(name, fn){
+	jQuery.fn[ name ] = function(){
+		return this.each( fn, arguments );
+	};
+});
+
+// Helper function used by the dimensions and offset modules
+function num(elem, prop) {
+	return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
+}
+var expando = "jQuery" + now(), uuid = 0, windowData = {};

+

+jQuery.extend({

+	cache: {},

+

+	data: function( elem, name, data ) {

+		elem = elem == window ?

+			windowData :

+			elem;

+

+		var id = elem[ expando ];

+

+		// Compute a unique ID for the element

+		if ( !id )

+			id = elem[ expando ] = ++uuid;

+

+		// Only generate the data cache if we're

+		// trying to access or manipulate it

+		if ( name && !jQuery.cache[ id ] )

+			jQuery.cache[ id ] = {};

+

+		// Prevent overriding the named cache with undefined values

+		if ( data !== undefined )

+			jQuery.cache[ id ][ name ] = data;

+

+		// Return the named cache data, or the ID for the element

+		return name ?

+			jQuery.cache[ id ][ name ] :

+			id;

+	},

+

+	removeData: function( elem, name ) {

+		elem = elem == window ?

+			windowData :

+			elem;

+

+		var id = elem[ expando ];

+

+		// If we want to remove a specific section of the element's data

+		if ( name ) {

+			if ( jQuery.cache[ id ] ) {

+				// Remove the section of cache data

+				delete jQuery.cache[ id ][ name ];

+

+				// If we've removed all the data, remove the element's cache

+				name = "";

+

+				for ( name in jQuery.cache[ id ] )

+					break;

+

+				if ( !name )

+					jQuery.removeData( elem );

+			}

+

+		// Otherwise, we want to remove all of the element's data

+		} else {

+			// Clean up the element expando

+			try {

+				delete elem[ expando ];

+			} catch(e){

+				// IE has trouble directly removing the expando

+				// but it's ok with using removeAttribute

+				if ( elem.removeAttribute )

+					elem.removeAttribute( expando );

+			}

+

+			// Completely remove the data cache

+			delete jQuery.cache[ id ];

+		}

+	},

+	queue: function( elem, type, data ) {

+		if ( elem ){

+	

+			type = (type || "fx") + "queue";

+	

+			var q = jQuery.data( elem, type );

+	

+			if ( !q || jQuery.isArray(data) )

+				q = jQuery.data( elem, type, jQuery.makeArray(data) );

+			else if( data )

+				q.push( data );

+	

+		}

+		return q;

+	},

+

+	dequeue: function( elem, type ){

+		var queue = jQuery.queue( elem, type ),

+			fn = queue.shift();

+		

+		if( !type || type === "fx" )

+			fn = queue[0];

+			

+		if( fn !== undefined )

+			fn.call(elem);

+	}

+});

+

+jQuery.fn.extend({

+	data: function( key, value ){

+		var parts = key.split(".");

+		parts[1] = parts[1] ? "." + parts[1] : "";

+

+		if ( value === undefined ) {

+			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);

+

+			if ( data === undefined && this.length )

+				data = jQuery.data( this[0], key );

+

+			return data === undefined && parts[1] ?

+				this.data( parts[0] ) :

+				data;

+		} else

+			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){

+				jQuery.data( this, key, value );

+			});

+	},

+

+	removeData: function( key ){

+		return this.each(function(){

+			jQuery.removeData( this, key );

+		});

+	},

+	queue: function(type, data){

+		if ( typeof type !== "string" ) {

+			data = type;

+			type = "fx";

+		}

+

+		if ( data === undefined )

+			return jQuery.queue( this[0], type );

+

+		return this.each(function(){

+			var queue = jQuery.queue( this, type, data );

+			

+			 if( type == "fx" && queue.length == 1 )

+				queue[0].call(this);

+		});

+	},

+	dequeue: function(type){

+		return this.each(function(){

+			jQuery.dequeue( this, type );

+		});

+	}

+});/*!
+ * Sizzle CSS Selector Engine - v0.9.3
+ *  Copyright 2009, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
+	done = 0,
+	toString = Object.prototype.toString;
+
+var Sizzle = function(selector, context, results, seed) {
+	results = results || [];
+	context = context || document;
+
+	if ( context.nodeType !== 1 && context.nodeType !== 9 )
+		return [];
+	
+	if ( !selector || typeof selector !== "string" ) {
+		return results;
+	}
+
+	var parts = [], m, set, checkSet, check, mode, extra, prune = true;
+	
+	// Reset the position of the chunker regexp (start from head)
+	chunker.lastIndex = 0;
+	
+	while ( (m = chunker.exec(selector)) !== null ) {
+		parts.push( m[1] );
+		
+		if ( m[2] ) {
+			extra = RegExp.rightContext;
+			break;
+		}
+	}
+
+	if ( parts.length > 1 && origPOS.exec( selector ) ) {
+		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+			set = posProcess( parts[0] + parts[1], context );
+		} else {
+			set = Expr.relative[ parts[0] ] ?
+				[ context ] :
+				Sizzle( parts.shift(), context );
+
+			while ( parts.length ) {
+				selector = parts.shift();
+
+				if ( Expr.relative[ selector ] )
+					selector += parts.shift();
+
+				set = posProcess( selector, set );
+			}
+		}
+	} else {
+		var ret = seed ?
+			{ expr: parts.pop(), set: makeArray(seed) } :
+			Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
+		set = Sizzle.filter( ret.expr, ret.set );
+
+		if ( parts.length > 0 ) {
+			checkSet = makeArray(set);
+		} else {
+			prune = false;
+		}
+
+		while ( parts.length ) {
+			var cur = parts.pop(), pop = cur;
+
+			if ( !Expr.relative[ cur ] ) {
+				cur = "";
+			} else {
+				pop = parts.pop();
+			}
+
+			if ( pop == null ) {
+				pop = context;
+			}
+
+			Expr.relative[ cur ]( checkSet, pop, isXML(context) );
+		}
+	}
+
+	if ( !checkSet ) {
+		checkSet = set;
+	}
+
+	if ( !checkSet ) {
+		throw "Syntax error, unrecognized expression: " + (cur || selector);
+	}
+
+	if ( toString.call(checkSet) === "[object Array]" ) {
+		if ( !prune ) {
+			results.push.apply( results, checkSet );
+		} else if ( context.nodeType === 1 ) {
+			for ( var i = 0; checkSet[i] != null; i++ ) {
+				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
+					results.push( set[i] );
+				}
+			}
+		} else {
+			for ( var i = 0; checkSet[i] != null; i++ ) {
+				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+					results.push( set[i] );
+				}
+			}
+		}
+	} else {
+		makeArray( checkSet, results );
+	}
+
+	if ( extra ) {
+		Sizzle( extra, context, results, seed );
+
+		if ( sortOrder ) {
+			hasDuplicate = false;
+			results.sort(sortOrder);
+
+			if ( hasDuplicate ) {
+				for ( var i = 1; i < results.length; i++ ) {
+					if ( results[i] === results[i-1] ) {
+						results.splice(i--, 1);
+					}
+				}
+			}
+		}
+	}
+
+	return results;
+};
+
+Sizzle.matches = function(expr, set){
+	return Sizzle(expr, null, null, set);
+};
+
+Sizzle.find = function(expr, context, isXML){
+	var set, match;
+
+	if ( !expr ) {
+		return [];
+	}
+
+	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+		var type = Expr.order[i], match;
+		
+		if ( (match = Expr.match[ type ].exec( expr )) ) {
+			var left = RegExp.leftContext;
+
+			if ( left.substr( left.length - 1 ) !== "\\" ) {
+				match[1] = (match[1] || "").replace(/\\/g, "");
+				set = Expr.find[ type ]( match, context, isXML );
+				if ( set != null ) {
+					expr = expr.replace( Expr.match[ type ], "" );
+					break;
+				}
+			}
+		}
+	}
+
+	if ( !set ) {
+		set = context.getElementsByTagName("*");
+	}
+
+	return {set: set, expr: expr};
+};
+
+Sizzle.filter = function(expr, set, inplace, not){
+	var old = expr, result = [], curLoop = set, match, anyFound,
+		isXMLFilter = set && set[0] && isXML(set[0]);
+
+	while ( expr && set.length ) {
+		for ( var type in Expr.filter ) {
+			if ( (match = Expr.match[ type ].exec( expr )) != null ) {
+				var filter = Expr.filter[ type ], found, item;
+				anyFound = false;
+
+				if ( curLoop == result ) {
+					result = [];
+				}
+
+				if ( Expr.preFilter[ type ] ) {
+					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+					if ( !match ) {
+						anyFound = found = true;
+					} else if ( match === true ) {
+						continue;
+					}
+				}
+
+				if ( match ) {
+					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+						if ( item ) {
+							found = filter( item, match, i, curLoop );
+							var pass = not ^ !!found;
+
+							if ( inplace && found != null ) {
+								if ( pass ) {
+									anyFound = true;
+								} else {
+									curLoop[i] = false;
+								}
+							} else if ( pass ) {
+								result.push( item );
+								anyFound = true;
+							}
+						}
+					}
+				}
+
+				if ( found !== undefined ) {
+					if ( !inplace ) {
+						curLoop = result;
+					}
+
+					expr = expr.replace( Expr.match[ type ], "" );
+
+					if ( !anyFound ) {
+						return [];
+					}
+
+					break;
+				}
+			}
+		}
+
+		// Improper expression
+		if ( expr == old ) {
+			if ( anyFound == null ) {
+				throw "Syntax error, unrecognized expression: " + expr;
+			} else {
+				break;
+			}
+		}
+
+		old = expr;
+	}
+
+	return curLoop;
+};
+
+var Expr = Sizzle.selectors = {
+	order: [ "ID", "NAME", "TAG" ],
+	match: {
+		ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
+		CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
+		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
+		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
+		TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
+		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
+		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
+		PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
+	},
+	attrMap: {
+		"class": "className",
+		"for": "htmlFor"
+	},
+	attrHandle: {
+		href: function(elem){
+			return elem.getAttribute("href");
+		}
+	},
+	relative: {
+		"+": function(checkSet, part, isXML){
+			var isPartStr = typeof part === "string",
+				isTag = isPartStr && !/\W/.test(part),
+				isPartStrNotTag = isPartStr && !isTag;
+
+			if ( isTag && !isXML ) {
+				part = part.toUpperCase();
+			}
+
+			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+				if ( (elem = checkSet[i]) ) {
+					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+					checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
+						elem || false :
+						elem === part;
+				}
+			}
+
+			if ( isPartStrNotTag ) {
+				Sizzle.filter( part, checkSet, true );
+			}
+		},
+		">": function(checkSet, part, isXML){
+			var isPartStr = typeof part === "string";
+
+			if ( isPartStr && !/\W/.test(part) ) {
+				part = isXML ? part : part.toUpperCase();
+
+				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+					var elem = checkSet[i];
+					if ( elem ) {
+						var parent = elem.parentNode;
+						checkSet[i] = parent.nodeName === part ? parent : false;
+					}
+				}
+			} else {
+				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+					var elem = checkSet[i];
+					if ( elem ) {
+						checkSet[i] = isPartStr ?
+							elem.parentNode :
+							elem.parentNode === part;
+					}
+				}
+
+				if ( isPartStr ) {
+					Sizzle.filter( part, checkSet, true );
+				}
+			}
+		},
+		"": function(checkSet, part, isXML){
+			var doneName = done++, checkFn = dirCheck;
+
+			if ( !part.match(/\W/) ) {
+				var nodeCheck = part = isXML ? part : part.toUpperCase();
+				checkFn = dirNodeCheck;
+			}
+
+			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
+		},
+		"~": function(checkSet, part, isXML){
+			var doneName = done++, checkFn = dirCheck;
+
+			if ( typeof part === "string" && !part.match(/\W/) ) {
+				var nodeCheck = part = isXML ? part : part.toUpperCase();
+				checkFn = dirNodeCheck;
+			}
+
+			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
+		}
+	},
+	find: {
+		ID: function(match, context, isXML){
+			if ( typeof context.getElementById !== "undefined" && !isXML ) {
+				var m = context.getElementById(match[1]);
+				return m ? [m] : [];
+			}
+		},
+		NAME: function(match, context, isXML){
+			if ( typeof context.getElementsByName !== "undefined" ) {
+				var ret = [], results = context.getElementsByName(match[1]);
+
+				for ( var i = 0, l = results.length; i < l; i++ ) {
+					if ( results[i].getAttribute("name") === match[1] ) {
+						ret.push( results[i] );
+					}
+				}
+
+				return ret.length === 0 ? null : ret;
+			}
+		},
+		TAG: function(match, context){
+			return context.getElementsByTagName(match[1]);
+		}
+	},
+	preFilter: {
+		CLASS: function(match, curLoop, inplace, result, not, isXML){
+			match = " " + match[1].replace(/\\/g, "") + " ";
+
+			if ( isXML ) {
+				return match;
+			}
+
+			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+				if ( elem ) {
+					if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
+						if ( !inplace )
+							result.push( elem );
+					} else if ( inplace ) {
+						curLoop[i] = false;
+					}
+				}
+			}
+
+			return false;
+		},
+		ID: function(match){
+			return match[1].replace(/\\/g, "");
+		},
+		TAG: function(match, curLoop){
+			for ( var i = 0; curLoop[i] === false; i++ ){}
+			return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
+		},
+		CHILD: function(match){
+			if ( match[1] == "nth" ) {
+				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+					match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
+					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+				// calculate the numbers (first)n+(last) including if they are negative
+				match[2] = (test[1] + (test[2] || 1)) - 0;
+				match[3] = test[3] - 0;
+			}
+
+			// TODO: Move to normal caching system
+			match[0] = done++;
+
+			return match;
+		},
+		ATTR: function(match, curLoop, inplace, result, not, isXML){
+			var name = match[1].replace(/\\/g, "");
+			
+			if ( !isXML && Expr.attrMap[name] ) {
+				match[1] = Expr.attrMap[name];
+			}
+
+			if ( match[2] === "~=" ) {
+				match[4] = " " + match[4] + " ";
+			}
+
+			return match;
+		},
+		PSEUDO: function(match, curLoop, inplace, result, not){
+			if ( match[1] === "not" ) {
+				// If we're dealing with a complex expression, or a simple one
+				if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
+					match[3] = Sizzle(match[3], null, null, curLoop);
+				} else {
+					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+					if ( !inplace ) {
+						result.push.apply( result, ret );
+					}
+					return false;
+				}
+			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+				return true;
+			}
+			
+			return match;
+		},
+		POS: function(match){
+			match.unshift( true );
+			return match;
+		}
+	},
+	filters: {
+		enabled: function(elem){
+			return elem.disabled === false && elem.type !== "hidden";
+		},
+		disabled: function(elem){
+			return elem.disabled === true;
+		},
+		checked: function(elem){
+			return elem.checked === true;
+		},
+		selected: function(elem){
+			// Accessing this property makes selected-by-default
+			// options in Safari work properly
+			elem.parentNode.selectedIndex;
+			return elem.selected === true;
+		},
+		parent: function(elem){
+			return !!elem.firstChild;
+		},
+		empty: function(elem){
+			return !elem.firstChild;
+		},
+		has: function(elem, i, match){
+			return !!Sizzle( match[3], elem ).length;
+		},
+		header: function(elem){
+			return /h\d/i.test( elem.nodeName );
+		},
+		text: function(elem){
+			return "text" === elem.type;
+		},
+		radio: function(elem){
+			return "radio" === elem.type;
+		},
+		checkbox: function(elem){
+			return "checkbox" === elem.type;
+		},
+		file: function(elem){
+			return "file" === elem.type;
+		},
+		password: function(elem){
+			return "password" === elem.type;
+		},
+		submit: function(elem){
+			return "submit" === elem.type;
+		},
+		image: function(elem){
+			return "image" === elem.type;
+		},
+		reset: function(elem){
+			return "reset" === elem.type;
+		},
+		button: function(elem){
+			return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
+		},
+		input: function(elem){
+			return /input|select|textarea|button/i.test(elem.nodeName);
+		}
+	},
+	setFilters: {
+		first: function(elem, i){
+			return i === 0;
+		},
+		last: function(elem, i, match, array){
+			return i === array.length - 1;
+		},
+		even: function(elem, i){
+			return i % 2 === 0;
+		},
+		odd: function(elem, i){
+			return i % 2 === 1;
+		},
+		lt: function(elem, i, match){
+			return i < match[3] - 0;
+		},
+		gt: function(elem, i, match){
+			return i > match[3] - 0;
+		},
+		nth: function(elem, i, match){
+			return match[3] - 0 == i;
+		},
+		eq: function(elem, i, match){
+			return match[3] - 0 == i;
+		}
+	},
+	filter: {
+		PSEUDO: function(elem, match, i, array){
+			var name = match[1], filter = Expr.filters[ name ];
+
+			if ( filter ) {
+				return filter( elem, i, match, array );
+			} else if ( name === "contains" ) {
+				return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
+			} else if ( name === "not" ) {
+				var not = match[3];
+
+				for ( var i = 0, l = not.length; i < l; i++ ) {
+					if ( not[i] === elem ) {
+						return false;
+					}
+				}
+
+				return true;
+			}
+		},
+		CHILD: function(elem, match){
+			var type = match[1], node = elem;
+			switch (type) {
+				case 'only':
+				case 'first':
+					while (node = node.previousSibling)  {
+						if ( node.nodeType === 1 ) return false;
+					}
+					if ( type == 'first') return true;
+					node = elem;
+				case 'last':
+					while (node = node.nextSibling)  {
+						if ( node.nodeType === 1 ) return false;
+					}
+					return true;
+				case 'nth':
+					var first = match[2], last = match[3];
+
+					if ( first == 1 && last == 0 ) {
+						return true;
+					}
+					
+					var doneName = match[0],
+						parent = elem.parentNode;
+	
+					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+						var count = 0;
+						for ( node = parent.firstChild; node; node = node.nextSibling ) {
+							if ( node.nodeType === 1 ) {
+								node.nodeIndex = ++count;
+							}
+						} 
+						parent.sizcache = doneName;
+					}
+					
+					var diff = elem.nodeIndex - last;
+					if ( first == 0 ) {
+						return diff == 0;
+					} else {
+						return ( diff % first == 0 && diff / first >= 0 );
+					}
+			}
+		},
+		ID: function(elem, match){
+			return elem.nodeType === 1 && elem.getAttribute("id") === match;
+		},
+		TAG: function(elem, match){
+			return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
+		},
+		CLASS: function(elem, match){
+			return (" " + (elem.className || elem.getAttribute("class")) + " ")
+				.indexOf( match ) > -1;
+		},
+		ATTR: function(elem, match){
+			var name = match[1],
+				result = Expr.attrHandle[ name ] ?
+					Expr.attrHandle[ name ]( elem ) :
+					elem[ name ] != null ?
+						elem[ name ] :
+						elem.getAttribute( name ),
+				value = result + "",
+				type = match[2],
+				check = match[4];
+
+			return result == null ?
+				type === "!=" :
+				type === "=" ?
+				value === check :
+				type === "*=" ?
+				value.indexOf(check) >= 0 :
+				type === "~=" ?
+				(" " + value + " ").indexOf(check) >= 0 :
+				!check ?
+				value && result !== false :
+				type === "!=" ?
+				value != check :
+				type === "^=" ?
+				value.indexOf(check) === 0 :
+				type === "$=" ?
+				value.substr(value.length - check.length) === check :
+				type === "|=" ?
+				value === check || value.substr(0, check.length + 1) === check + "-" :
+				false;
+		},
+		POS: function(elem, match, i, array){
+			var name = match[2], filter = Expr.setFilters[ name ];
+
+			if ( filter ) {
+				return filter( elem, i, match, array );
+			}
+		}
+	}
+};
+
+var origPOS = Expr.match.POS;
+
+for ( var type in Expr.match ) {
+	Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
+}
+
+var makeArray = function(array, results) {
+	array = Array.prototype.slice.call( array );
+
+	if ( results ) {
+		results.push.apply( results, array );
+		return results;
+	}
+	
+	return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+try {
+	Array.prototype.slice.call( document.documentElement.childNodes );
+
+// Provide a fallback method if it does not work
+} catch(e){
+	makeArray = function(array, results) {
+		var ret = results || [];
+
+		if ( toString.call(array) === "[object Array]" ) {
+			Array.prototype.push.apply( ret, array );
+		} else {
+			if ( typeof array.length === "number" ) {
+				for ( var i = 0, l = array.length; i < l; i++ ) {
+					ret.push( array[i] );
+				}
+			} else {
+				for ( var i = 0; array[i]; i++ ) {
+					ret.push( array[i] );
+				}
+			}
+		}
+
+		return ret;
+	};
+}
+
+var sortOrder;
+
+if ( document.documentElement.compareDocumentPosition ) {
+	sortOrder = function( a, b ) {
+		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
+		if ( ret === 0 ) {
+			hasDuplicate = true;
+		}
+		return ret;
+	};
+} else if ( "sourceIndex" in document.documentElement ) {
+	sortOrder = function( a, b ) {
+		var ret = a.sourceIndex - b.sourceIndex;
+		if ( ret === 0 ) {
+			hasDuplicate = true;
+		}
+		return ret;
+	};
+} else if ( document.createRange ) {
+	sortOrder = function( a, b ) {
+		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
+		aRange.selectNode(a);
+		aRange.collapse(true);
+		bRange.selectNode(b);
+		bRange.collapse(true);
+		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
+		if ( ret === 0 ) {
+			hasDuplicate = true;
+		}
+		return ret;
+	};
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+	// We're going to inject a fake input element with a specified name
+	var form = document.createElement("form"),
+		id = "script" + (new Date).getTime();
+	form.innerHTML = "<input name='" + id + "'/>";
+
+	// Inject it into the root element, check its status, and remove it quickly
+	var root = document.documentElement;
+	root.insertBefore( form, root.firstChild );
+
+	// The workaround has to do additional checks after a getElementById
+	// Which slows things down for other browsers (hence the branching)
+	if ( !!document.getElementById( id ) ) {
+		Expr.find.ID = function(match, context, isXML){
+			if ( typeof context.getElementById !== "undefined" && !isXML ) {
+				var m = context.getElementById(match[1]);
+				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
+			}
+		};
+
+		Expr.filter.ID = function(elem, match){
+			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+			return elem.nodeType === 1 && node && node.nodeValue === match;
+		};
+	}
+
+	root.removeChild( form );
+})();
+
+(function(){
+	// Check to see if the browser returns only elements
+	// when doing getElementsByTagName("*")
+
+	// Create a fake element
+	var div = document.createElement("div");
+	div.appendChild( document.createComment("") );
+
+	// Make sure no comments are found
+	if ( div.getElementsByTagName("*").length > 0 ) {
+		Expr.find.TAG = function(match, context){
+			var results = context.getElementsByTagName(match[1]);
+
+			// Filter out possible comments
+			if ( match[1] === "*" ) {
+				var tmp = [];
+
+				for ( var i = 0; results[i]; i++ ) {
+					if ( results[i].nodeType === 1 ) {
+						tmp.push( results[i] );
+					}
+				}
+
+				results = tmp;
+			}
+
+			return results;
+		};
+	}
+
+	// Check to see if an attribute returns normalized href attributes
+	div.innerHTML = "<a href='#'></a>";
+	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+			div.firstChild.getAttribute("href") !== "#" ) {
+		Expr.attrHandle.href = function(elem){
+			return elem.getAttribute("href", 2);
+		};
+	}
+})();
+
+if ( document.querySelectorAll ) (function(){
+	var oldSizzle = Sizzle, div = document.createElement("div");
+	div.innerHTML = "<p class='TEST'></p>";
+
+	// Safari can't handle uppercase or unicode characters when
+	// in quirks mode.
+	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+		return;
+	}
+	
+	Sizzle = function(query, context, extra, seed){
+		context = context || document;
+
+		// Only use querySelectorAll on non-XML documents
+		// (ID selectors don't work in non-HTML documents)
+		if ( !seed && context.nodeType === 9 && !isXML(context) ) {
+			try {
+				return makeArray( context.querySelectorAll(query), extra );
+			} catch(e){}
+		}
+		
+		return oldSizzle(query, context, extra, seed);
+	};
+
+	Sizzle.find = oldSizzle.find;
+	Sizzle.filter = oldSizzle.filter;
+	Sizzle.selectors = oldSizzle.selectors;
+	Sizzle.matches = oldSizzle.matches;
+})();
+
+if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
+	var div = document.createElement("div");
+	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+	// Opera can't find a second classname (in 9.6)
+	if ( div.getElementsByClassName("e").length === 0 )
+		return;
+
+	// Safari caches class attributes, doesn't catch changes (in 3.2)
+	div.lastChild.className = "e";
+
+	if ( div.getElementsByClassName("e").length === 1 )
+		return;
+
+	Expr.order.splice(1, 0, "CLASS");
+	Expr.find.CLASS = function(match, context, isXML) {
+		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+			return context.getElementsByClassName(match[1]);
+		}
+	};
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+	var sibDir = dir == "previousSibling" && !isXML;
+	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+		var elem = checkSet[i];
+		if ( elem ) {
+			if ( sibDir && elem.nodeType === 1 ){
+				elem.sizcache = doneName;
+				elem.sizset = i;
+			}
+			elem = elem[dir];
+			var match = false;
+
+			while ( elem ) {
+				if ( elem.sizcache === doneName ) {
+					match = checkSet[elem.sizset];
+					break;
+				}
+
+				if ( elem.nodeType === 1 && !isXML ){
+					elem.sizcache = doneName;
+					elem.sizset = i;
+				}
+
+				if ( elem.nodeName === cur ) {
+					match = elem;
+					break;
+				}
+
+				elem = elem[dir];
+			}
+
+			checkSet[i] = match;
+		}
+	}
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+	var sibDir = dir == "previousSibling" && !isXML;
+	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+		var elem = checkSet[i];
+		if ( elem ) {
+			if ( sibDir && elem.nodeType === 1 ) {
+				elem.sizcache = doneName;
+				elem.sizset = i;
+			}
+			elem = elem[dir];
+			var match = false;
+
+			while ( elem ) {
+				if ( elem.sizcache === doneName ) {
+					match = checkSet[elem.sizset];
+					break;
+				}
+
+				if ( elem.nodeType === 1 ) {
+					if ( !isXML ) {
+						elem.sizcache = doneName;
+						elem.sizset = i;
+					}
+					if ( typeof cur !== "string" ) {
+						if ( elem === cur ) {
+							match = true;
+							break;
+						}
+
+					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+						match = elem;
+						break;
+					}
+				}
+
+				elem = elem[dir];
+			}
+
+			checkSet[i] = match;
+		}
+	}
+}
+
+var contains = document.compareDocumentPosition ?  function(a, b){
+	return a.compareDocumentPosition(b) & 16;
+} : function(a, b){
+	return a !== b && (a.contains ? a.contains(b) : true);
+};
+
+var isXML = function(elem){
+	return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+		!!elem.ownerDocument && isXML( elem.ownerDocument );
+};
+
+var posProcess = function(selector, context){
+	var tmpSet = [], later = "", match,
+		root = context.nodeType ? [context] : context;
+
+	// Position selectors must be done after the filter
+	// And so must :not(positional) so we move all PSEUDOs to the end
+	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+		later += match[0];
+		selector = selector.replace( Expr.match.PSEUDO, "" );
+	}
+
+	selector = Expr.relative[selector] ? selector + "*" : selector;
+
+	for ( var i = 0, l = root.length; i < l; i++ ) {
+		Sizzle( selector, root[i], tmpSet );
+	}
+
+	return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+jQuery.find = Sizzle;
+jQuery.filter = Sizzle.filter;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+
+Sizzle.selectors.filters.hidden = function(elem){
+	return elem.offsetWidth === 0 || elem.offsetHeight === 0;
+};
+
+Sizzle.selectors.filters.visible = function(elem){
+	return elem.offsetWidth > 0 || elem.offsetHeight > 0;
+};
+
+Sizzle.selectors.filters.animated = function(elem){
+	return jQuery.grep(jQuery.timers, function(fn){
+		return elem === fn.elem;
+	}).length;
+};
+
+jQuery.multiFilter = function( expr, elems, not ) {
+	if ( not ) {
+		expr = ":not(" + expr + ")";
+	}
+
+	return Sizzle.matches(expr, elems);
+};
+
+jQuery.dir = function( elem, dir ){
+	var matched = [], cur = elem[dir];
+	while ( cur && cur != document ) {
+		if ( cur.nodeType == 1 )
+			matched.push( cur );
+		cur = cur[dir];
+	}
+	return matched;
+};
+
+jQuery.nth = function(cur, result, dir, elem){
+	result = result || 1;
+	var num = 0;
+
+	for ( ; cur; cur = cur[dir] )
+		if ( cur.nodeType == 1 && ++num == result )
+			break;
+
+	return cur;
+};
+
+jQuery.sibling = function(n, elem){
+	var r = [];
+
+	for ( ; n; n = n.nextSibling ) {
+		if ( n.nodeType == 1 && n != elem )
+			r.push( n );
+	}
+
+	return r;
+};
+
+return;
+
+window.Sizzle = Sizzle;
+
+})();
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code originated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+	// Bind an event to an element
+	// Original by Dean Edwards
+	add: function(elem, types, handler, data) {
+		if ( elem.nodeType == 3 || elem.nodeType == 8 )
+			return;
+
+		// For whatever reason, IE has trouble passing the window object
+		// around, causing it to be cloned in the process
+		if ( elem.setInterval && elem != window )
+			elem = window;
+
+		// Make sure that the function being executed has a unique ID
+		if ( !handler.guid )
+			handler.guid = this.guid++;
+
+		// if data is passed, bind to handler
+		if ( data !== undefined ) {
+			// Create temporary function pointer to original handler
+			var fn = handler;
+
+			// Create unique handler function, wrapped around original handler
+			handler = this.proxy( fn );
+
+			// Store data in unique handler
+			handler.data = data;
+		}
+
+		// Init the element's event structure
+		var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
+			handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
+				// Handle the second event of a trigger and when
+				// an event is called after a page has unloaded
+				return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
+					jQuery.event.handle.apply(arguments.callee.elem, arguments) :
+					undefined;
+			});
+		// Add elem as a property of the handle function
+		// This is to prevent a memory leak with non-native
+		// event in IE.
+		handle.elem = elem;
+
+		// Handle multiple events separated by a space
+		// jQuery(...).bind("mouseover mouseout", fn);
+		jQuery.each(types.split(/\s+/), function(index, type) {
+			// Namespaced event handlers
+			var namespaces = type.split(".");
+			type = namespaces.shift();
+			handler.type = namespaces.slice().sort().join(".");
+
+			// Get the current list of functions bound to this event
+			var handlers = events[type];
+			
+			if ( jQuery.event.specialAll[type] )
+				jQuery.event.specialAll[type].setup.call(elem, data, namespaces);
+
+			// Init the event handler queue
+			if (!handlers) {
+				handlers = events[type] = {};
+
+				// Check for a special event handler
+				// Only use addEventListener/attachEvent if the special
+				// events handler returns false
+				if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem, data, namespaces) === false ) {
+					// Bind the global event handler to the element
+					if (elem.addEventListener)
+						elem.addEventListener(type, handle, false);
+					else if (elem.attachEvent)
+						elem.attachEvent("on" + type, handle);
+				}
+			}
+
+			// Add the function to the element's handler list
+			handlers[handler.guid] = handler;
+
+			// Keep track of which events have been used, for global triggering
+			jQuery.event.global[type] = true;
+		});
+
+		// Nullify elem to prevent memory leaks in IE
+		elem = null;
+	},
+
+	guid: 1,
+	global: {},
+
+	// Detach an event or set of events from an element
+	remove: function(elem, types, handler) {
+		// don't do events on text and comment nodes
+		if ( elem.nodeType == 3 || elem.nodeType == 8 )
+			return;
+
+		var events = jQuery.data(elem, "events"), ret, index;
+
+		if ( events ) {
+			// Unbind all events for the element
+			if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") )
+				for ( var type in events )
+					this.remove( elem, type + (types || "") );
+			else {
+				// types is actually an event object here
+				if ( types.type ) {
+					handler = types.handler;
+					types = types.type;
+				}
+
+				// Handle multiple events seperated by a space
+				// jQuery(...).unbind("mouseover mouseout", fn);
+				jQuery.each(types.split(/\s+/), function(index, type){
+					// Namespaced event handlers
+					var namespaces = type.split(".");
+					type = namespaces.shift();
+					var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
+
+					if ( events[type] ) {
+						// remove the given handler for the given type
+						if ( handler )
+							delete events[type][handler.guid];
+
+						// remove all handlers for the given type
+						else
+							for ( var handle in events[type] )
+								// Handle the removal of namespaced events
+								if ( namespace.test(events[type][handle].type) )
+									delete events[type][handle];
+									
+						if ( jQuery.event.specialAll[type] )
+							jQuery.event.specialAll[type].teardown.call(elem, namespaces);
+
+						// remove generic event handler if no more handlers exist
+						for ( ret in events[type] ) break;
+						if ( !ret ) {
+							if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem, namespaces) === false ) {
+								if (elem.removeEventListener)
+									elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
+								else if (elem.detachEvent)
+									elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
+							}
+							ret = null;
+							delete events[type];
+						}
+					}
+				});
+			}
+
+			// Remove the expando if it's no longer used
+			for ( ret in events ) break;
+			if ( !ret ) {
+				var handle = jQuery.data( elem, "handle" );
+				if ( handle ) handle.elem = null;
+				jQuery.removeData( elem, "events" );
+				jQuery.removeData( elem, "handle" );
+			}
+		}
+	},
+
+	// bubbling is internal
+	trigger: function( event, data, elem, bubbling ) {
+		// Event object or event type
+		var type = event.type || event;
+
+		if( !bubbling ){
+			event = typeof event === "object" ?
+				// jQuery.Event object
+				event[expando] ? event :
+				// Object literal
+				jQuery.extend( jQuery.Event(type), event ) :
+				// Just the event type (string)
+				jQuery.Event(type);
+
+			if ( type.indexOf("!") >= 0 ) {
+				event.type = type = type.slice(0, -1);
+				event.exclusive = true;
+			}
+
+			// Handle a global trigger
+			if ( !elem ) {
+				// Don't bubble custom events when global (to avoid too much overhead)
+				event.stopPropagation();
+				// Only trigger if we've ever bound an event for it
+				if ( this.global[type] )
+					jQuery.each( jQuery.cache, function(){
+						if ( this.events && this.events[type] )
+							jQuery.event.trigger( event, data, this.handle.elem );
+					});
+			}
+
+			// Handle triggering a single element
+
+			// don't do events on text and comment nodes
+			if ( !elem || elem.nodeType == 3 || elem.nodeType == 8 )
+				return undefined;
+			
+			// Clean up in case it is reused
+			event.result = undefined;
+			event.target = elem;
+			
+			// Clone the incoming data, if any
+			data = jQuery.makeArray(data);
+			data.unshift( event );
+		}
+
+		event.currentTarget = elem;
+
+		// Trigger the event, it is assumed that "handle" is a function
+		var handle = jQuery.data(elem, "handle");
+		if ( handle )
+			handle.apply( elem, data );
+
+		// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
+		if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+			event.result = false;
+
+		// Trigger the native events (except for clicks on links)
+		if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
+			this.triggered = true;
+			try {
+				elem[ type ]();
+			// prevent IE from throwing an error for some hidden elements
+			} catch (e) {}
+		}
+
+		this.triggered = false;
+
+		if ( !event.isPropagationStopped() ) {
+			var parent = elem.parentNode || elem.ownerDocument;
+			if ( parent )
+				jQuery.event.trigger(event, data, parent, true);
+		}
+	},
+
+	handle: function(event) {
+		// returned undefined or false
+		var all, handlers;
+
+		event = arguments[0] = jQuery.event.fix( event || window.event );
+		event.currentTarget = this;
+		
+		// Namespaced event handlers
+		var namespaces = event.type.split(".");
+		event.type = namespaces.shift();
+
+		// Cache this now, all = true means, any handler
+		all = !namespaces.length && !event.exclusive;
+		
+		var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
+
+		handlers = ( jQuery.data(this, "events") || {} )[event.type];
+
+		for ( var j in handlers ) {
+			var handler = handlers[j];
+
+			// Filter the functions by class
+			if ( all || namespace.test(handler.type) ) {
+				// Pass in a reference to the handler function itself
+				// So that we can later remove it
+				event.handler = handler;
+				event.data = handler.data;
+
+				var ret = handler.apply(this, arguments);
+
+				if( ret !== undefined ){
+					event.result = ret;
+					if ( ret === false ) {
+						event.preventDefault();
+						event.stopPropagation();
+					}
+				}
+
+				if( event.isImmediatePropagationStopped() )
+					break;
+
+			}
+		}
+	},
+
+	props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+
+	fix: function(event) {
+		if ( event[expando] )
+			return event;
+
+		// store a copy of the original event object
+		// and "clone" to set read-only properties
+		var originalEvent = event;
+		event = jQuery.Event( originalEvent );
+
+		for ( var i = this.props.length, prop; i; ){
+			prop = this.props[ --i ];
+			event[ prop ] = originalEvent[ prop ];
+		}
+
+		// Fix target property, if necessary
+		if ( !event.target )
+			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+
+		// check if target is a textnode (safari)
+		if ( event.target.nodeType == 3 )
+			event.target = event.target.parentNode;
+
+		// Add relatedTarget, if necessary
+		if ( !event.relatedTarget && event.fromElement )
+			event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
+
+		// Calculate pageX/Y if missing and clientX/Y available
+		if ( event.pageX == null && event.clientX != null ) {
+			var doc = document.documentElement, body = document.body;
+			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
+			event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
+		}
+
+		// Add which for key events
+		if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
+			event.which = event.charCode || event.keyCode;
+
+		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+		if ( !event.metaKey && event.ctrlKey )
+			event.metaKey = event.ctrlKey;
+
+		// Add which for click: 1 == left; 2 == middle; 3 == right
+		// Note: button is not normalized, so don't use it
+		if ( !event.which && event.button )
+			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+
+		return event;
+	},
+
+	proxy: function( fn, proxy ){
+		proxy = proxy || function(){ return fn.apply(this, arguments); };
+		// Set the guid of unique handler to the same of original handler, so it can be removed
+		proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
+		// So proxy can be declared as an argument
+		return proxy;
+	},
+
+	special: {
+		ready: {
+			// Make sure the ready event is setup
+			setup: bindReady,
+			teardown: function() {}
+		}
+	},
+	
+	specialAll: {
+		live: {
+			setup: function( selector, namespaces ){
+				jQuery.event.add( this, namespaces[0], liveHandler );
+			},
+			teardown:  function( namespaces ){
+				if ( namespaces.length ) {
+					var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
+					
+					jQuery.each( (jQuery.data(this, "events").live || {}), function(){
+						if ( name.test(this.type) )
+							remove++;
+					});
+					
+					if ( remove < 1 )
+						jQuery.event.remove( this, namespaces[0], liveHandler );
+				}
+			}
+		}
+	}
+};
+
+jQuery.Event = function( src ){
+	// Allow instantiation without the 'new' keyword
+	if( !this.preventDefault )
+		return new jQuery.Event(src);
+	
+	// Event object
+	if( src && src.type ){
+		this.originalEvent = src;
+		this.type = src.type;
+	// Event type
+	}else
+		this.type = src;
+
+	// timeStamp is buggy for some events on Firefox(#3843)
+	// So we won't rely on the native value
+	this.timeStamp = now();
+	
+	// Mark it as fixed
+	this[expando] = true;
+};
+
+function returnFalse(){
+	return false;
+}
+function returnTrue(){
+	return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+	preventDefault: function() {
+		this.isDefaultPrevented = returnTrue;
+
+		var e = this.originalEvent;
+		if( !e )
+			return;
+		// if preventDefault exists run it on the original event
+		if (e.preventDefault)
+			e.preventDefault();
+		// otherwise set the returnValue property of the original event to false (IE)
+		e.returnValue = false;
+	},
+	stopPropagation: function() {
+		this.isPropagationStopped = returnTrue;
+
+		var e = this.originalEvent;
+		if( !e )
+			return;
+		// if stopPropagation exists run it on the original event
+		if (e.stopPropagation)
+			e.stopPropagation();
+		// otherwise set the cancelBubble property of the original event to true (IE)
+		e.cancelBubble = true;
+	},
+	stopImmediatePropagation:function(){
+		this.isImmediatePropagationStopped = returnTrue;
+		this.stopPropagation();
+	},
+	isDefaultPrevented: returnFalse,
+	isPropagationStopped: returnFalse,
+	isImmediatePropagationStopped: returnFalse
+};
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function(event) {
+	// Check if mouse(over|out) are still within the same parent element
+	var parent = event.relatedTarget;
+	// Traverse up the tree
+	while ( parent && parent != this )
+		try { parent = parent.parentNode; }
+		catch(e) { parent = this; }
+	
+	if( parent != this ){
+		// set the correct event type
+		event.type = event.data;
+		// handle event if we actually just moused on to a non sub-element
+		jQuery.event.handle.apply( this, arguments );
+	}
+};
+	
+jQuery.each({ 
+	mouseover: 'mouseenter', 
+	mouseout: 'mouseleave'
+}, function( orig, fix ){
+	jQuery.event.special[ fix ] = {
+		setup: function(){
+			jQuery.event.add( this, orig, withinElement, fix );
+		},
+		teardown: function(){
+			jQuery.event.remove( this, orig, withinElement );
+		}
+	};			   
+});
+
+jQuery.fn.extend({
+	bind: function( type, data, fn ) {
+		return type == "unload" ? this.one(type, data, fn) : this.each(function(){
+			jQuery.event.add( this, type, fn || data, fn && data );
+		});
+	},
+
+	one: function( type, data, fn ) {
+		var one = jQuery.event.proxy( fn || data, function(event) {
+			jQuery(this).unbind(event, one);
+			return (fn || data).apply( this, arguments );
+		});
+		return this.each(function(){
+			jQuery.event.add( this, type, one, fn && data);
+		});
+	},
+
+	unbind: function( type, fn ) {
+		return this.each(function(){
+			jQuery.event.remove( this, type, fn );
+		});
+	},
+
+	trigger: function( type, data ) {
+		return this.each(function(){
+			jQuery.event.trigger( type, data, this );
+		});
+	},
+
+	triggerHandler: function( type, data ) {
+		if( this[0] ){
+			var event = jQuery.Event(type);
+			event.preventDefault();
+			event.stopPropagation();
+			jQuery.event.trigger( event, data, this[0] );
+			return event.result;
+		}		
+	},
+
+	toggle: function( fn ) {
+		// Save reference to arguments for access in closure
+		var args = arguments, i = 1;
+
+		// link all the functions, so any of them can unbind this click handler
+		while( i < args.length )
+			jQuery.event.proxy( fn, args[i++] );
+
+		return this.click( jQuery.event.proxy( fn, function(event) {
+			// Figure out which function to execute
+			this.lastToggle = ( this.lastToggle || 0 ) % i;
+
+			// Make sure that clicks stop
+			event.preventDefault();
+
+			// and execute the function
+			return args[ this.lastToggle++ ].apply( this, arguments ) || false;
+		}));
+	},
+
+	hover: function(fnOver, fnOut) {
+		return this.mouseenter(fnOver).mouseleave(fnOut);
+	},
+
+	ready: function(fn) {
+		// Attach the listeners
+		bindReady();
+
+		// If the DOM is already ready
+		if ( jQuery.isReady )
+			// Execute the function immediately
+			fn.call( document, jQuery );
+
+		// Otherwise, remember the function for later
+		else
+			// Add the function to the wait list
+			jQuery.readyList.push( fn );
+
+		return this;
+	},
+	
+	live: function( type, fn ){
+		var proxy = jQuery.event.proxy( fn );
+		proxy.guid += this.selector + type;
+
+		jQuery(document).bind( liveConvert(type, this.selector), this.selector, proxy );
+
+		return this;
+	},
+	
+	die: function( type, fn ){
+		jQuery(document).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
+		return this;
+	}
+});
+
+function liveHandler( event ){
+	var check = RegExp("(^|\\.)" + event.type + "(\\.|$)"),
+		stop = true,
+		elems = [];
+
+	jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
+		if ( check.test(fn.type) ) {
+			var elem = jQuery(event.target).closest(fn.data)[0];
+			if ( elem )
+				elems.push({ elem: elem, fn: fn });
+		}
+	});
+
+	elems.sort(function(a,b) {
+		return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
+	});
+	
+	jQuery.each(elems, function(){
+		if ( this.fn.call(this.elem, event, this.fn.data) === false )
+			return (stop = false);
+	});
+
+	return stop;
+}
+
+function liveConvert(type, selector){
+	return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join(".");
+}
+
+jQuery.extend({
+	isReady: false,
+	readyList: [],
+	// Handle when the DOM is ready
+	ready: function() {
+		// Make sure that the DOM is not already loaded
+		if ( !jQuery.isReady ) {
+			// Remember that the DOM is ready
+			jQuery.isReady = true;
+
+			// If there are functions bound, to execute
+			if ( jQuery.readyList ) {
+				// Execute all of them
+				jQuery.each( jQuery.readyList, function(){
+					this.call( document, jQuery );
+				});
+
+				// Reset the list of functions
+				jQuery.readyList = null;
+			}
+
+			// Trigger any bound ready events
+			jQuery(document).triggerHandler("ready");
+		}
+	}
+});
+
+var readyBound = false;
+
+function bindReady(){
+	if ( readyBound ) return;
+	readyBound = true;
+
+	// Mozilla, Opera and webkit nightlies currently support this event
+	if ( document.addEventListener ) {
+		// Use the handy event callback
+		document.addEventListener( "DOMContentLoaded", function(){
+			document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
+			jQuery.ready();
+		}, false );
+
+	// If IE event model is used
+	} else if ( document.attachEvent ) {
+		// ensure firing before onload,
+		// maybe late but safe also for iframes
+		document.attachEvent("onreadystatechange", function(){
+			if ( document.readyState === "complete" ) {
+				document.detachEvent( "onreadystatechange", arguments.callee );
+				jQuery.ready();
+			}
+		});
+
+		// If IE and not an iframe
+		// continually check to see if the document is ready
+		if ( document.documentElement.doScroll && window == window.top ) (function(){
+			if ( jQuery.isReady ) return;
+
+			try {
+				// If IE is used, use the trick by Diego Perini
+				// http://javascript.nwbox.com/IEContentLoaded/
+				document.documentElement.doScroll("left");
+			} catch( error ) {
+				setTimeout( arguments.callee, 0 );
+				return;
+			}
+
+			// and execute any waiting functions
+			jQuery.ready();
+		})();
+	}
+
+	// A fallback to window.onload, that will always work
+	jQuery.event.add( window, "load", jQuery.ready );
+}
+
+jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
+	"mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave," +
+	"change,select,submit,keydown,keypress,keyup,error").split(","), function(i, name){
+
+	// Handle event binding
+	jQuery.fn[name] = function(fn){
+		return fn ? this.bind(name, fn) : this.trigger(name);
+	};
+});
+
+// Prevent memory leaks in IE
+// And prevent errors on refresh with events like mouseover in other browsers
+// Window isn't included so as not to unbind existing unload events
+jQuery( window ).bind( 'unload', function(){ 
+	for ( var id in jQuery.cache )
+		// Skip the window
+		if ( id != 1 && jQuery.cache[ id ].handle )
+			jQuery.event.remove( jQuery.cache[ id ].handle.elem );
+}); 
+(function(){
+
+	jQuery.support = {};
+
+	var root = document.documentElement,
+		script = document.createElement("script"),
+		div = document.createElement("div"),
+		id = "script" + (new Date).getTime();
+
+	div.style.display = "none";
+	div.innerHTML = '   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';
+
+	var all = div.getElementsByTagName("*"),
+		a = div.getElementsByTagName("a")[0];
+
+	// Can't get basic test support
+	if ( !all || !all.length || !a ) {
+		return;
+	}
+
+	jQuery.support = {
+		// IE strips leading whitespace when .innerHTML is used
+		leadingWhitespace: div.firstChild.nodeType == 3,
+		
+		// Make sure that tbody elements aren't automatically inserted
+		// IE will insert them into empty tables
+		tbody: !div.getElementsByTagName("tbody").length,
+		
+		// Make sure that you can get all elements in an <object> element
+		// IE 7 always returns no results
+		objectAll: !!div.getElementsByTagName("object")[0]
+			.getElementsByTagName("*").length,
+		
+		// Make sure that link elements get serialized correctly by innerHTML
+		// This requires a wrapper element in IE
+		htmlSerialize: !!div.getElementsByTagName("link").length,
+		
+		// Get the style information from getAttribute
+		// (IE uses .cssText insted)
+		style: /red/.test( a.getAttribute("style") ),
+		
+		// Make sure that URLs aren't manipulated
+		// (IE normalizes it by default)
+		hrefNormalized: a.getAttribute("href") === "/a",
+		
+		// Make sure that element opacity exists
+		// (IE uses filter instead)
+		opacity: a.style.opacity === "0.5",
+		
+		// Verify style float existence
+		// (IE uses styleFloat instead of cssFloat)
+		cssFloat: !!a.style.cssFloat,
+
+		// Will be defined later
+		scriptEval: false,
+		noCloneEvent: true,
+		boxModel: null
+	};
+	
+	script.type = "text/javascript";
+	try {
+		script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
+	} catch(e){}
+
+	root.insertBefore( script, root.firstChild );
+	
+	// Make sure that the execution of code works by injecting a script
+	// tag with appendChild/createTextNode
+	// (IE doesn't support this, fails, and uses .text instead)
+	if ( window[ id ] ) {
+		jQuery.support.scriptEval = true;
+		delete window[ id ];
+	}
+
+	root.removeChild( script );
+
+	if ( div.attachEvent && div.fireEvent ) {
+		div.attachEvent("onclick", function(){
+			// Cloning a node shouldn't copy over any
+			// bound event handlers (IE does this)
+			jQuery.support.noCloneEvent = false;
+			div.detachEvent("onclick", arguments.callee);
+		});
+		div.cloneNode(true).fireEvent("onclick");
+	}
+
+	// Figure out if the W3C box model works as expected
+	// document.body must exist before we can do this
+	jQuery(function(){
+		var div = document.createElement("div");
+		div.style.width = div.style.paddingLeft = "1px";
+
+		document.body.appendChild( div );
+		jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
+		document.body.removeChild( div ).style.display = 'none';
+	});
+})();
+
+var styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat";
+
+jQuery.props = {
+	"for": "htmlFor",
+	"class": "className",
+	"float": styleFloat,
+	cssFloat: styleFloat,
+	styleFloat: styleFloat,
+	readonly: "readOnly",
+	maxlength: "maxLength",
+	cellspacing: "cellSpacing",
+	rowspan: "rowSpan",
+	tabindex: "tabIndex"
+};
+jQuery.fn.extend({
+	// Keep a copy of the old load
+	_load: jQuery.fn.load,
+
+	load: function( url, params, callback ) {
+		if ( typeof url !== "string" )
+			return this._load( url );
+
+		var off = url.indexOf(" ");
+		if ( off >= 0 ) {
+			var selector = url.slice(off, url.length);
+			url = url.slice(0, off);
+		}
+
+		// Default to a GET request
+		var type = "GET";
+
+		// If the second parameter was provided
+		if ( params )
+			// If it's a function
+			if ( jQuery.isFunction( params ) ) {
+				// We assume that it's the callback
+				callback = params;
+				params = null;
+
+			// Otherwise, build a param string
+			} else if( typeof params === "object" ) {
+				params = jQuery.param( params );
+				type = "POST";
+			}
+
+		var self = this;
+
+		// Request the remote document
+		jQuery.ajax({
+			url: url,
+			type: type,
+			dataType: "html",
+			data: params,
+			complete: function(res, status){
+				// If successful, inject the HTML into all the matched elements
+				if ( status == "success" || status == "notmodified" )
+					// See if a selector was specified
+					self.html( selector ?
+						// Create a dummy div to hold the results
+						jQuery("<div/>")
+							// inject the contents of the document in, removing the scripts
+							// to avoid any 'Permission Denied' errors in IE
+							.append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
+
+							// Locate the specified elements
+							.find(selector) :
+
+						// If not, just inject the full result
+						res.responseText );
+
+				if( callback )
+					self.each( callback, [res.responseText, status, res] );
+			}
+		});
+		return this;
+	},
+
+	serialize: function() {
+		return jQuery.param(this.serializeArray());
+	},
+	serializeArray: function() {
+		return this.map(function(){
+			return this.elements ? jQuery.makeArray(this.elements) : this;
+		})
+		.filter(function(){
+			return this.name && !this.disabled &&
+				(this.checked || /select|textarea/i.test(this.nodeName) ||
+					/text|hidden|password|search/i.test(this.type));
+		})
+		.map(function(i, elem){
+			var val = jQuery(this).val();
+			return val == null ? null :
+				jQuery.isArray(val) ?
+					jQuery.map( val, function(val, i){
+						return {name: elem.name, value: val};
+					}) :
+					{name: elem.name, value: val};
+		}).get();
+	}
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
+	jQuery.fn[o] = function(f){
+		return this.bind(o, f);
+	};
+});
+
+var jsc = now();
+
+jQuery.extend({
+  
+	get: function( url, data, callback, type ) {
+		// shift arguments if data argument was ommited
+		if ( jQuery.isFunction( data ) ) {
+			callback = data;
+			data = null;
+		}
+
+		return jQuery.ajax({
+			type: "GET",
+			url: url,
+			data: data,
+			success: callback,
+			dataType: type
+		});
+	},
+
+	getScript: function( url, callback ) {
+		return jQuery.get(url, null, callback, "script");
+	},
+
+	getJSON: function( url, data, callback ) {
+		return jQuery.get(url, data, callback, "json");
+	},
+
+	post: function( url, data, callback, type ) {
+		if ( jQuery.isFunction( data ) ) {
+			callback = data;
+			data = {};
+		}
+
+		return jQuery.ajax({
+			type: "POST",
+			url: url,
+			data: data,
+			success: callback,
+			dataType: type
+		});
+	},
+
+	ajaxSetup: function( settings ) {
+		jQuery.extend( jQuery.ajaxSettings, settings );
+	},
+
+	ajaxSettings: {
+		url: location.href,
+		global: true,
+		type: "GET",
+		contentType: "application/x-www-form-urlencoded",
+		processData: true,
+		async: true,
+		/*
+		timeout: 0,
+		data: null,
+		username: null,
+		password: null,
+		*/
+		// Create the request object; Microsoft failed to properly
+		// implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
+		// This function can be overriden by calling jQuery.ajaxSetup
+		xhr:function(){
+			return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+		},
+		accepts: {
+			xml: "application/xml, text/xml",
+			html: "text/html",
+			script: "text/javascript, application/javascript",
+			json: "application/json, text/javascript",
+			text: "text/plain",
+			_default: "*/*"
+		}
+	},
+
+	// Last-Modified header cache for next request
+	lastModified: {},
+
+	ajax: function( s ) {
+		// Extend the settings, but re-extend 's' so that it can be
+		// checked again later (in the test suite, specifically)
+		s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
+
+		var jsonp, jsre = /=\?(&|$)/g, status, data,
+			type = s.type.toUpperCase();
+
+		// convert data if not already a string
+		if ( s.data && s.processData && typeof s.data !== "string" )
+			s.data = jQuery.param(s.data);
+
+		// Handle JSONP Parameter Callbacks
+		if ( s.dataType == "jsonp" ) {
+			if ( type == "GET" ) {
+				if ( !s.url.match(jsre) )
+					s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+			} else if ( !s.data || !s.data.match(jsre) )
+				s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+			s.dataType = "json";
+		}
+
+		// Build temporary JSONP function
+		if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
+			jsonp = "jsonp" + jsc++;
+
+			// Replace the =? sequence both in the query string and the data
+			if ( s.data )
+				s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+			s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+			// We need to make sure
+			// that a JSONP style response is executed properly
+			s.dataType = "script";
+
+			// Handle JSONP-style loading
+			window[ jsonp ] = function(tmp){
+				data = tmp;
+				success();
+				complete();
+				// Garbage collect
+				window[ jsonp ] = undefined;
+				try{ delete window[ jsonp ]; } catch(e){}
+				if ( head )
+					head.removeChild( script );
+			};
+		}
+
+		if ( s.dataType == "script" && s.cache == null )
+			s.cache = false;
+
+		if ( s.cache === false && type == "GET" ) {
+			var ts = now();
+			// try replacing _= if it is there
+			var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
+			// if nothing was replaced, add timestamp to the end
+			s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
+		}
+
+		// If data is available, append data to url for get requests
+		if ( s.data && type == "GET" ) {
+			s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
+
+			// IE likes to send both get and post data, prevent this
+			s.data = null;
+		}
+
+		// Watch for a new set of requests
+		if ( s.global && ! jQuery.active++ )
+			jQuery.event.trigger( "ajaxStart" );
+
+		// Matches an absolute URL, and saves the domain
+		var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec( s.url );
+
+		// If we're requesting a remote document
+		// and trying to load JSON or Script with a GET
+		if ( s.dataType == "script" && type == "GET" && parts
+			&& ( parts[1] && parts[1] != location.protocol || parts[2] != location.host )){
+
+			var head = document.getElementsByTagName("head")[0];
+			var script = document.createElement("script");
+			script.src = s.url;
+			if (s.scriptCharset)
+				script.charset = s.scriptCharset;
+
+			// Handle Script loading
+			if ( !jsonp ) {
+				var done = false;
+
+				// Attach handlers for all browsers
+				script.onload = script.onreadystatechange = function(){
+					if ( !done && (!this.readyState ||
+							this.readyState == "loaded" || this.readyState == "complete") ) {
+						done = true;
+						success();
+						complete();
+
+						// Handle memory leak in IE
+						script.onload = script.onreadystatechange = null;
+						head.removeChild( script );
+					}
+				};
+			}
+
+			head.appendChild(script);
+
+			// We handle everything using the script element injection
+			return undefined;
+		}
+
+		var requestDone = false;
+
+		// Create the request object
+		var xhr = s.xhr();
+
+		// Open the socket
+		// Passing null username, generates a login popup on Opera (#2865)
+		if( s.username )
+			xhr.open(type, s.url, s.async, s.username, s.password);
+		else
+			xhr.open(type, s.url, s.async);
+
+		// Need an extra try/catch for cross domain requests in Firefox 3
+		try {
+			// Set the correct header, if data is being sent
+			if ( s.data )
+				xhr.setRequestHeader("Content-Type", s.contentType);
+
+			// Set the If-Modified-Since header, if ifModified mode.
+			if ( s.ifModified )
+				xhr.setRequestHeader("If-Modified-Since",
+					jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+
+			// Set header so the called script knows that it's an XMLHttpRequest
+			xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+
+			// Set the Accepts header for the server, depending on the dataType
+			xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+				s.accepts[ s.dataType ] + ", */*" :
+				s.accepts._default );
+		} catch(e){}
+
+		// Allow custom headers/mimetypes and early abort
+		if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
+			// Handle the global AJAX counter
+			if ( s.global && ! --jQuery.active )
+				jQuery.event.trigger( "ajaxStop" );
+			// close opended socket
+			xhr.abort();
+			return false;
+		}
+
+		if ( s.global )
+			jQuery.event.trigger("ajaxSend", [xhr, s]);
+
+		// Wait for a response to come back
+		var onreadystatechange = function(isTimeout){
+			// The request was aborted, clear the interval and decrement jQuery.active
+			if (xhr.readyState == 0) {
+				if (ival) {
+					// clear poll interval
+					clearInterval(ival);
+					ival = null;
+					// Handle the global AJAX counter
+					if ( s.global && ! --jQuery.active )
+						jQuery.event.trigger( "ajaxStop" );
+				}
+			// The transfer is complete and the data is available, or the request timed out
+			} else if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
+				requestDone = true;
+
+				// clear poll interval
+				if (ival) {
+					clearInterval(ival);
+					ival = null;
+				}
+
+				status = isTimeout == "timeout" ? "timeout" :
+					!jQuery.httpSuccess( xhr ) ? "error" :
+					s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" :
+					"success";
+
+				if ( status == "success" ) {
+					// Watch for, and catch, XML document parse errors
+					try {
+						// process the data (runs the xml through httpData regardless of callback)
+						data = jQuery.httpData( xhr, s.dataType, s );
+					} catch(e) {
+						status = "parsererror";
+					}
+				}
+
+				// Make sure that the request was successful or notmodified
+				if ( status == "success" ) {
+					// Cache Last-Modified header, if ifModified mode.
+					var modRes;
+					try {
+						modRes = xhr.getResponseHeader("Last-Modified");
+					} catch(e) {} // swallow exception thrown by FF if header is not available
+
+					if ( s.ifModified && modRes )
+						jQuery.lastModified[s.url] = modRes;
+
+					// JSONP handles its own success callback
+					if ( !jsonp )
+						success();
+				} else
+					jQuery.handleError(s, xhr, status);
+
+				// Fire the complete handlers
+				complete();
+
+				if ( isTimeout )
+					xhr.abort();
+
+				// Stop memory leaks
+				if ( s.async )
+					xhr = null;
+			}
+		};
+
+		if ( s.async ) {
+			// don't attach the handler to the request, just poll it instead
+			var ival = setInterval(onreadystatechange, 13);
+
+			// Timeout checker
+			if ( s.timeout > 0 )
+				setTimeout(function(){
+					// Check to see if the request is still happening
+					if ( xhr && !requestDone )
+						onreadystatechange( "timeout" );
+				}, s.timeout);
+		}
+
+		// Send the data
+		try {
+			xhr.send(s.data);
+		} catch(e) {
+			jQuery.handleError(s, xhr, null, e);
+		}
+
+		// firefox 1.5 doesn't fire statechange for sync requests
+		if ( !s.async )
+			onreadystatechange();
+
+		function success(){
+			// If a local callback was specified, fire it and pass it the data
+			if ( s.success )
+				s.success( data, status );
+
+			// Fire the global callback
+			if ( s.global )
+				jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
+		}
+
+		function complete(){
+			// Process result
+			if ( s.complete )
+				s.complete(xhr, status);
+
+			// The request was completed
+			if ( s.global )
+				jQuery.event.trigger( "ajaxComplete", [xhr, s] );
+
+			// Handle the global AJAX counter
+			if ( s.global && ! --jQuery.active )
+				jQuery.event.trigger( "ajaxStop" );
+		}
+
+		// return XMLHttpRequest to allow aborting the request etc.
+		return xhr;
+	},
+
+	handleError: function( s, xhr, status, e ) {
+		// If a local callback was specified, fire it
+		if ( s.error ) s.error( xhr, status, e );
+
+		// Fire the global callback
+		if ( s.global )
+			jQuery.event.trigger( "ajaxError", [xhr, s, e] );
+	},
+
+	// Counter for holding the number of active queries
+	active: 0,
+
+	// Determines if an XMLHttpRequest was successful or not
+	httpSuccess: function( xhr ) {
+		try {
+			// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+			return !xhr.status && location.protocol == "file:" ||
+				( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223;
+		} catch(e){}
+		return false;
+	},
+
+	// Determines if an XMLHttpRequest returns NotModified
+	httpNotModified: function( xhr, url ) {
+		try {
+			var xhrRes = xhr.getResponseHeader("Last-Modified");
+
+			// Firefox always returns 200. check Last-Modified date
+			return xhr.status == 304 || xhrRes == jQuery.lastModified[url];
+		} catch(e){}
+		return false;
+	},
+
+	httpData: function( xhr, type, s ) {
+		var ct = xhr.getResponseHeader("content-type"),
+			xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
+			data = xml ? xhr.responseXML : xhr.responseText;
+
+		if ( xml && data.documentElement.tagName == "parsererror" )
+			throw "parsererror";
+			
+		// Allow a pre-filtering function to sanitize the response
+		// s != null is checked to keep backwards compatibility
+		if( s && s.dataFilter )
+			data = s.dataFilter( data, type );
+
+		// The filter can actually parse the response
+		if( typeof data === "string" ){
+
+			// If the type is "script", eval it in global context
+			if ( type == "script" )
+				jQuery.globalEval( data );
+
+			// Get the JavaScript object, if JSON is used.
+			if ( type == "json" )
+				data = window["eval"]("(" + data + ")");
+		}
+		
+		return data;
+	},
+
+	// Serialize an array of form elements or a set of
+	// key/values into a query string
+	param: function( a ) {
+		var s = [ ];
+
+		function add( key, value ){
+			s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
+		};
+
+		// If an array was passed in, assume that it is an array
+		// of form elements
+		if ( jQuery.isArray(a) || a.jquery )
+			// Serialize the form elements
+			jQuery.each( a, function(){
+				add( this.name, this.value );
+			});
+
+		// Otherwise, assume that it's an object of key/value pairs
+		else
+			// Serialize the key/values
+			for ( var j in a )
+				// If the value is an array then the key names need to be repeated
+				if ( jQuery.isArray(a[j]) )
+					jQuery.each( a[j], function(){
+						add( j, this );
+					});
+				else
+					add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
+
+		// Return the resulting serialization
+		return s.join("&").replace(/%20/g, "+");
+	}
+
+});
+var elemdisplay = {},
+	timerId,
+	fxAttrs = [
+		// height animations
+		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+		// width animations
+		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+		// opacity animations
+		[ "opacity" ]
+	];
+
+function genFx( type, num ){
+	var obj = {};
+	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
+		obj[ this ] = type;
+	});
+	return obj;
+}
+
+jQuery.fn.extend({
+	show: function(speed,callback){
+		if ( speed ) {
+			return this.animate( genFx("show", 3), speed, callback);
+		} else {
+			for ( var i = 0, l = this.length; i < l; i++ ){
+				var old = jQuery.data(this[i], "olddisplay");
+				
+				this[i].style.display = old || "";
+				
+				if ( jQuery.css(this[i], "display") === "none" ) {
+					var tagName = this[i].tagName, display;
+					
+					if ( elemdisplay[ tagName ] ) {
+						display = elemdisplay[ tagName ];
+					} else {
+						var elem = jQuery("<" + tagName + " />").appendTo("body");
+						
+						display = elem.css("display");
+						if ( display === "none" )
+							display = "block";
+						
+						elem.remove();
+						
+						elemdisplay[ tagName ] = display;
+					}
+					
+					jQuery.data(this[i], "olddisplay", display);
+				}
+			}
+
+			// Set the display of the elements in a second loop
+			// to avoid the constant reflow
+			for ( var i = 0, l = this.length; i < l; i++ ){
+				this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
+			}
+			
+			return this;
+		}
+	},
+
+	hide: function(speed,callback){
+		if ( speed ) {
+			return this.animate( genFx("hide", 3), speed, callback);
+		} else {
+			for ( var i = 0, l = this.length; i < l; i++ ){
+				var old = jQuery.data(this[i], "olddisplay");
+				if ( !old && old !== "none" )
+					jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
+			}
+
+			// Set the display of the elements in a second loop
+			// to avoid the constant reflow
+			for ( var i = 0, l = this.length; i < l; i++ ){
+				this[i].style.display = "none";
+			}
+
+			return this;
+		}
+	},
+
+	// Save the old toggle function
+	_toggle: jQuery.fn.toggle,
+
+	toggle: function( fn, fn2 ){
+		var bool = typeof fn === "boolean";
+
+		return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
+			this._toggle.apply( this, arguments ) :
+			fn == null || bool ?
+				this.each(function(){
+					var state = bool ? fn : jQuery(this).is(":hidden");
+					jQuery(this)[ state ? "show" : "hide" ]();
+				}) :
+				this.animate(genFx("toggle", 3), fn, fn2);
+	},
+
+	fadeTo: function(speed,to,callback){
+		return this.animate({opacity: to}, speed, callback);
+	},
+
+	animate: function( prop, speed, easing, callback ) {
+		var optall = jQuery.speed(speed, easing, callback);
+
+		return this[ optall.queue === false ? "each" : "queue" ](function(){
+		
+			var opt = jQuery.extend({}, optall), p,
+				hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),
+				self = this;
+	
+			for ( p in prop ) {
+				if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
+					return opt.complete.call(this);
+
+				if ( ( p == "height" || p == "width" ) && this.style ) {
+					// Store display property
+					opt.display = jQuery.css(this, "display");
+
+					// Make sure that nothing sneaks out
+					opt.overflow = this.style.overflow;
+				}
+			}
+
+			if ( opt.overflow != null )
+				this.style.overflow = "hidden";
+
+			opt.curAnim = jQuery.extend({}, prop);
+
+			jQuery.each( prop, function(name, val){
+				var e = new jQuery.fx( self, opt, name );
+
+				if ( /toggle|show|hide/.test(val) )
+					e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+				else {
+					var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
+						start = e.cur(true) || 0;
+
+					if ( parts ) {
+						var end = parseFloat(parts[2]),
+							unit = parts[3] || "px";
+
+						// We need to compute starting value
+						if ( unit != "px" ) {
+							self.style[ name ] = (end || 1) + unit;
+							start = ((end || 1) / e.cur(true)) * start;
+							self.style[ name ] = start + unit;
+						}
+
+						// If a +=/-= token was provided, we're doing a relative animation
+						if ( parts[1] )
+							end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
+
+						e.custom( start, end, unit );
+					} else
+						e.custom( start, val, "" );
+				}
+			});
+
+			// For JS strict compliance
+			return true;
+		});
+	},
+
+	stop: function(clearQueue, gotoEnd){
+		var timers = jQuery.timers;
+
+		if (clearQueue)
+			this.queue([]);
+
+		this.each(function(){
+			// go in reverse order so anything added to the queue during the loop is ignored
+			for ( var i = timers.length - 1; i >= 0; i-- )
+				if ( timers[i].elem == this ) {
+					if (gotoEnd)
+						// force the next step to be the last
+						timers[i](true);
+					timers.splice(i, 1);
+				}
+		});
+
+		// start the next in the queue if the last step wasn't forced
+		if (!gotoEnd)
+			this.dequeue();
+
+		return this;
+	}
+
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+	slideDown: genFx("show", 1),
+	slideUp: genFx("hide", 1),
+	slideToggle: genFx("toggle", 1),
+	fadeIn: { opacity: "show" },
+	fadeOut: { opacity: "hide" }
+}, function( name, props ){
+	jQuery.fn[ name ] = function( speed, callback ){
+		return this.animate( props, speed, callback );
+	};
+});
+
+jQuery.extend({
+
+	speed: function(speed, easing, fn) {
+		var opt = typeof speed === "object" ? speed : {
+			complete: fn || !fn && easing ||
+				jQuery.isFunction( speed ) && speed,
+			duration: speed,
+			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+		};
+
+		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+			jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
+
+		// Queueing
+		opt.old = opt.complete;
+		opt.complete = function(){
+			if ( opt.queue !== false )
+				jQuery(this).dequeue();
+			if ( jQuery.isFunction( opt.old ) )
+				opt.old.call( this );
+		};
+
+		return opt;
+	},
+
+	easing: {
+		linear: function( p, n, firstNum, diff ) {
+			return firstNum + diff * p;
+		},
+		swing: function( p, n, firstNum, diff ) {
+			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+		}
+	},
+
+	timers: [],
+
+	fx: function( elem, options, prop ){
+		this.options = options;
+		this.elem = elem;
+		this.prop = prop;
+
+		if ( !options.orig )
+			options.orig = {};
+	}
+
+});
+
+jQuery.fx.prototype = {
+
+	// Simple function for setting a style value
+	update: function(){
+		if ( this.options.step )
+			this.options.step.call( this.elem, this.now, this );
+
+		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+
+		// Set display property to block for height/width animations
+		if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style )
+			this.elem.style.display = "block";
+	},
+
+	// Get the current size
+	cur: function(force){
+		if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) )
+			return this.elem[ this.prop ];
+
+		var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+		return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+	},
+
+	// Start an animation from one number to another
+	custom: function(from, to, unit){
+		this.startTime = now();
+		this.start = from;
+		this.end = to;
+		this.unit = unit || this.unit || "px";
+		this.now = this.start;
+		this.pos = this.state = 0;
+
+		var self = this;
+		function t(gotoEnd){
+			return self.step(gotoEnd);
+		}
+
+		t.elem = this.elem;
+
+		if ( t() && jQuery.timers.push(t) && !timerId ) {
+			timerId = setInterval(function(){
+				var timers = jQuery.timers;
+
+				for ( var i = 0; i < timers.length; i++ )
+					if ( !timers[i]() )
+						timers.splice(i--, 1);
+
+				if ( !timers.length ) {
+					clearInterval( timerId );
+					timerId = undefined;
+				}
+			}, 13);
+		}
+	},
+
+	// Simple 'show' function
+	show: function(){
+		// Remember where we started, so that we can go back to it later
+		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+		this.options.show = true;
+
+		// Begin the animation
+		// Make sure that we start at a small width/height to avoid any
+		// flash of content
+		this.custom(this.prop == "width" || this.prop == "height" ? 1 : 0, this.cur());
+
+		// Start by showing the element
+		jQuery(this.elem).show();
+	},
+
+	// Simple 'hide' function
+	hide: function(){
+		// Remember where we started, so that we can go back to it later
+		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+		this.options.hide = true;
+
+		// Begin the animation
+		this.custom(this.cur(), 0);
+	},
+
+	// Each step of an animation
+	step: function(gotoEnd){
+		var t = now();
+
+		if ( gotoEnd || t >= this.options.duration + this.startTime ) {
+			this.now = this.end;
+			this.pos = this.state = 1;
+			this.update();
+
+			this.options.curAnim[ this.prop ] = true;
+
+			var done = true;
+			for ( var i in this.options.curAnim )
+				if ( this.options.curAnim[i] !== true )
+					done = false;
+
+			if ( done ) {
+				if ( this.options.display != null ) {
+					// Reset the overflow
+					this.elem.style.overflow = this.options.overflow;
+
+					// Reset the display
+					this.elem.style.display = this.options.display;
+					if ( jQuery.css(this.elem, "display") == "none" )
+						this.elem.style.display = "block";
+				}
+
+				// Hide the element if the "hide" operation was done
+				if ( this.options.hide )
+					jQuery(this.elem).hide();
+
+				// Reset the properties, if the item has been hidden or shown
+				if ( this.options.hide || this.options.show )
+					for ( var p in this.options.curAnim )
+						jQuery.attr(this.elem.style, p, this.options.orig[p]);
+					
+				// Execute the complete function
+				this.options.complete.call( this.elem );
+			}
+
+			return false;
+		} else {
+			var n = t - this.startTime;
+			this.state = n / this.options.duration;
+
+			// Perform the easing function, defaults to swing
+			this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
+			this.now = this.start + ((this.end - this.start) * this.pos);
+
+			// Perform the next step of the animation
+			this.update();
+		}
+
+		return true;
+	}
+
+};
+
+jQuery.extend( jQuery.fx, {
+	speeds:{
+		slow: 600,
+ 		fast: 200,
+ 		// Default speed
+ 		_default: 400
+	},
+	step: {
+
+		opacity: function(fx){
+			jQuery.attr(fx.elem.style, "opacity", fx.now);
+		},
+
+		_default: function(fx){
+			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
+				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+			else
+				fx.elem[ fx.prop ] = fx.now;
+		}
+	}
+});
+if ( document.documentElement["getBoundingClientRect"] )
+	jQuery.fn.offset = function() {
+		if ( !this[0] ) return { top: 0, left: 0 };
+		if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
+		var box  = this[0].getBoundingClientRect(), doc = this[0].ownerDocument, body = doc.body, docElem = doc.documentElement,
+			clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
+			top  = box.top  + (self.pageYOffset || jQuery.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
+			left = box.left + (self.pageXOffset || jQuery.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
+		return { top: top, left: left };
+	};
+else 
+	jQuery.fn.offset = function() {
+		if ( !this[0] ) return { top: 0, left: 0 };
+		if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
+		jQuery.offset.initialized || jQuery.offset.initialize();
+
+		var elem = this[0], offsetParent = elem.offsetParent, prevOffsetParent = elem,
+			doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
+			body = doc.body, defaultView = doc.defaultView,
+			prevComputedStyle = defaultView.getComputedStyle(elem, null),
+			top = elem.offsetTop, left = elem.offsetLeft;
+
+		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+			computedStyle = defaultView.getComputedStyle(elem, null);
+			top -= elem.scrollTop, left -= elem.scrollLeft;
+			if ( elem === offsetParent ) {
+				top += elem.offsetTop, left += elem.offsetLeft;
+				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.tagName)) )
+					top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
+					left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
+				prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
+			}
+			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" )
+				top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
+				left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
+			prevComputedStyle = computedStyle;
+		}
+
+		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" )
+			top  += body.offsetTop,
+			left += body.offsetLeft;
+
+		if ( prevComputedStyle.position === "fixed" )
+			top  += Math.max(docElem.scrollTop, body.scrollTop),
+			left += Math.max(docElem.scrollLeft, body.scrollLeft);
+
+		return { top: top, left: left };
+	};
+
+jQuery.offset = {
+	initialize: function() {
+		if ( this.initialized ) return;
+		var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
+			html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
+
+		rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
+		for ( prop in rules ) container.style[prop] = rules[prop];
+
+		container.innerHTML = html;
+		body.insertBefore(container, body.firstChild);
+		innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td = innerDiv.nextSibling.firstChild.firstChild;
+
+		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
+		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
+
+		innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
+		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+
+		body.style.marginTop = '1px';
+		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
+		body.style.marginTop = bodyMarginTop;
+
+		body.removeChild(container);
+		this.initialized = true;
+	},
+
+	bodyOffset: function(body) {
+		jQuery.offset.initialized || jQuery.offset.initialize();
+		var top = body.offsetTop, left = body.offsetLeft;
+		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset )
+			top  += parseInt( jQuery.curCSS(body, 'marginTop',  true), 10 ) || 0,
+			left += parseInt( jQuery.curCSS(body, 'marginLeft', true), 10 ) || 0;
+		return { top: top, left: left };
+	}
+};
+
+
+jQuery.fn.extend({
+	position: function() {
+		var left = 0, top = 0, results;
+
+		if ( this[0] ) {
+			// Get *real* offsetParent
+			var offsetParent = this.offsetParent(),
+
+			// Get correct offsets
+			offset       = this.offset(),
+			parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+			// Subtract element margins
+			// note: when an element has margin: auto the offsetLeft and marginLeft 
+			// are the same in Safari causing offset.left to incorrectly be 0
+			offset.top  -= num( this, 'marginTop'  );
+			offset.left -= num( this, 'marginLeft' );
+
+			// Add offsetParent borders
+			parentOffset.top  += num( offsetParent, 'borderTopWidth'  );
+			parentOffset.left += num( offsetParent, 'borderLeftWidth' );
+
+			// Subtract the two offsets
+			results = {
+				top:  offset.top  - parentOffset.top,
+				left: offset.left - parentOffset.left
+			};
+		}
+
+		return results;
+	},
+
+	offsetParent: function() {
+		var offsetParent = this[0].offsetParent || document.body;
+		while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
+			offsetParent = offsetParent.offsetParent;
+		return jQuery(offsetParent);
+	}
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ['Left', 'Top'], function(i, name) {
+	var method = 'scroll' + name;
+	
+	jQuery.fn[ method ] = function(val) {
+		if (!this[0]) return null;
+
+		return val !== undefined ?
+
+			// Set the scroll offset
+			this.each(function() {
+				this == window || this == document ?
+					window.scrollTo(
+						!i ? val : jQuery(window).scrollLeft(),
+						 i ? val : jQuery(window).scrollTop()
+					) :
+					this[ method ] = val;
+			}) :
+
+			// Return the scroll offset
+			this[0] == window || this[0] == document ?
+				self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
+					jQuery.boxModel && document.documentElement[ method ] ||
+					document.body[ method ] :
+				this[0][ method ];
+	};
+});
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function(i, name){
+
+	var tl = i ? "Left"  : "Top",  // top or left
+		br = i ? "Right" : "Bottom", // bottom or right
+		lower = name.toLowerCase();
+
+	// innerHeight and innerWidth
+	jQuery.fn["inner" + name] = function(){
+		return this[0] ?
+			jQuery.css( this[0], lower, false, "padding" ) :
+			null;
+	};
+
+	// outerHeight and outerWidth
+	jQuery.fn["outer" + name] = function(margin) {
+		return this[0] ?
+			jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
+			null;
+	};
+	
+	var type = name.toLowerCase();
+
+	jQuery.fn[ type ] = function( size ) {
+		// Get window width or height
+		return this[0] == window ?
+			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+			document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] ||
+			document.body[ "client" + name ] :
+
+			// Get document width or height
+			this[0] == document ?
+				// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+				Math.max(
+					document.documentElement["client" + name],
+					document.body["scroll" + name], document.documentElement["scroll" + name],
+					document.body["offset" + name], document.documentElement["offset" + name]
+				) :
+
+				// Get or set width or height on the element
+				size === undefined ?
+					// Get width or height on the element
+					(this.length ? jQuery.css( this[0], type ) : null) :
+
+					// Set the width or height on the element (default to pixels if value is unitless)
+					this.css( type, typeof size === "string" ? size : size + "px" );
+	};
+
+});
+})();
diff --git a/doc/html/_static/minus.png b/doc/html/_static/minus.png
new file mode 100755
index 0000000..da1c562
--- /dev/null
+++ b/doc/html/_static/minus.png
Binary files differ
diff --git a/doc/html/_static/navigation.png b/doc/html/_static/navigation.png
new file mode 100755
index 0000000..1081dc1
--- /dev/null
+++ b/doc/html/_static/navigation.png
Binary files differ
diff --git a/doc/html/_static/plus.png b/doc/html/_static/plus.png
new file mode 100755
index 0000000..b3cb374
--- /dev/null
+++ b/doc/html/_static/plus.png
Binary files differ
diff --git a/doc/html/_static/pygments.css b/doc/html/_static/pygments.css
new file mode 100644
index 0000000..1f2d2b6
--- /dev/null
+++ b/doc/html/_static/pygments.css
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #408090; font-style: italic } /* Comment */
+.err { border: 1px solid #FF0000 } /* Error */
+.k { color: #007020; font-weight: bold } /* Keyword */
+.o { color: #666666 } /* Operator */
+.cm { color: #408090; font-style: italic } /* Comment.Multiline */
+.cp { color: #007020 } /* Comment.Preproc */
+.c1 { color: #408090; font-style: italic } /* Comment.Single */
+.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
+.gd { color: #A00000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.gi { color: #00A000 } /* Generic.Inserted */
+.go { color: #303030 } /* Generic.Output */
+.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.gt { color: #0040D0 } /* Generic.Traceback */
+.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
+.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #007020 } /* Keyword.Pseudo */
+.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #902000 } /* Keyword.Type */
+.m { color: #208050 } /* Literal.Number */
+.s { color: #4070a0 } /* Literal.String */
+.na { color: #4070a0 } /* Name.Attribute */
+.nb { color: #007020 } /* Name.Builtin */
+.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
+.no { color: #60add5 } /* Name.Constant */
+.nd { color: #555555; font-weight: bold } /* Name.Decorator */
+.ni { color: #d55537; font-weight: bold } /* Name.Entity */
+.ne { color: #007020 } /* Name.Exception */
+.nf { color: #06287e } /* Name.Function */
+.nl { color: #002070; font-weight: bold } /* Name.Label */
+.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
+.nt { color: #062873; font-weight: bold } /* Name.Tag */
+.nv { color: #bb60d5 } /* Name.Variable */
+.ow { color: #007020; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #208050 } /* Literal.Number.Float */
+.mh { color: #208050 } /* Literal.Number.Hex */
+.mi { color: #208050 } /* Literal.Number.Integer */
+.mo { color: #208050 } /* Literal.Number.Oct */
+.sb { color: #4070a0 } /* Literal.String.Backtick */
+.sc { color: #4070a0 } /* Literal.String.Char */
+.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #4070a0 } /* Literal.String.Double */
+.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #4070a0 } /* Literal.String.Heredoc */
+.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
+.sx { color: #c65d09 } /* Literal.String.Other */
+.sr { color: #235388 } /* Literal.String.Regex */
+.s1 { color: #4070a0 } /* Literal.String.Single */
+.ss { color: #517918 } /* Literal.String.Symbol */
+.bp { color: #007020 } /* Name.Builtin.Pseudo */
+.vc { color: #bb60d5 } /* Name.Variable.Class */
+.vg { color: #bb60d5 } /* Name.Variable.Global */
+.vi { color: #bb60d5 } /* Name.Variable.Instance */
+.il { color: #208050 } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/doc/html/_static/rightsidebar.css b/doc/html/_static/rightsidebar.css
new file mode 100755
index 0000000..bc604a8
--- /dev/null
+++ b/doc/html/_static/rightsidebar.css
@@ -0,0 +1,16 @@
+/**
+ * Sphinx Doc Design -- Right Side Bar Overrides
+ */
+
+
+div.sphinxsidebar {
+    float: right;
+}
+
+div.bodywrapper {
+    margin: 0 230px 0 0;
+}
+
+div.inlinecomments {
+    right: 250px;
+}
diff --git a/doc/html/_static/searchtools.js b/doc/html/_static/searchtools.js
new file mode 100644
index 0000000..e022625
--- /dev/null
+++ b/doc/html/_static/searchtools.js
@@ -0,0 +1,467 @@
+/**
+ * helper function to return a node containing the
+ * search summary for a given text. keywords is a list
+ * of stemmed words, hlwords is the list of normal, unstemmed
+ * words. the first one is used to find the occurance, the
+ * latter for highlighting it.
+ */
+
+jQuery.makeSearchSummary = function(text, keywords, hlwords) {
+  var textLower = text.toLowerCase();
+  var start = 0;
+  $.each(keywords, function() {
+    var i = textLower.indexOf(this.toLowerCase());
+    if (i > -1)
+      start = i;
+  });
+  start = Math.max(start - 120, 0);
+  var excerpt = ((start > 0) ? '...' : '') +
+  $.trim(text.substr(start, 240)) +
+  ((start + 240 - text.length) ? '...' : '');
+  var rv = $('<div class="context"></div>').text(excerpt);
+  $.each(hlwords, function() {
+    rv = rv.highlightText(this, 'highlight');
+  });
+  return rv;
+}
+
+/**
+ * Porter Stemmer
+ */
+var PorterStemmer = function() {
+
+  var step2list = {
+    ational: 'ate',
+    tional: 'tion',
+    enci: 'ence',
+    anci: 'ance',
+    izer: 'ize',
+    bli: 'ble',
+    alli: 'al',
+    entli: 'ent',
+    eli: 'e',
+    ousli: 'ous',
+    ization: 'ize',
+    ation: 'ate',
+    ator: 'ate',
+    alism: 'al',
+    iveness: 'ive',
+    fulness: 'ful',
+    ousness: 'ous',
+    aliti: 'al',
+    iviti: 'ive',
+    biliti: 'ble',
+    logi: 'log'
+  };
+
+  var step3list = {
+    icate: 'ic',
+    ative: '',
+    alize: 'al',
+    iciti: 'ic',
+    ical: 'ic',
+    ful: '',
+    ness: ''
+  };
+
+  var c = "[^aeiou]";          // consonant
+  var v = "[aeiouy]";          // vowel
+  var C = c + "[^aeiouy]*";    // consonant sequence
+  var V = v + "[aeiou]*";      // vowel sequence
+
+  var mgr0 = "^(" + C + ")?" + V + C;                      // [C]VC... is m>0
+  var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$";    // [C]VC[V] is m=1
+  var mgr1 = "^(" + C + ")?" + V + C + V + C;              // [C]VCVC... is m>1
+  var s_v   = "^(" + C + ")?" + v;                         // vowel in stem
+
+  this.stemWord = function (w) {
+    var stem;
+    var suffix;
+    var firstch;
+    var origword = w;
+
+    if (w.length < 3)
+      return w;
+
+    var re;
+    var re2;
+    var re3;
+    var re4;
+
+    firstch = w.substr(0,1);
+    if (firstch == "y")
+      w = firstch.toUpperCase() + w.substr(1);
+
+    // Step 1a
+    re = /^(.+?)(ss|i)es$/;
+    re2 = /^(.+?)([^s])s$/;
+
+    if (re.test(w))
+      w = w.replace(re,"$1$2");
+    else if (re2.test(w))
+      w = w.replace(re2,"$1$2");
+
+    // Step 1b
+    re = /^(.+?)eed$/;
+    re2 = /^(.+?)(ed|ing)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      re = new RegExp(mgr0);
+      if (re.test(fp[1])) {
+        re = /.$/;
+        w = w.replace(re,"");
+      }
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1];
+      re2 = new RegExp(s_v);
+      if (re2.test(stem)) {
+        w = stem;
+        re2 = /(at|bl|iz)$/;
+        re3 = new RegExp("([^aeiouylsz])\\1$");
+        re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+        if (re2.test(w))
+          w = w + "e";
+        else if (re3.test(w)) {
+          re = /.$/;
+          w = w.replace(re,"");
+        }
+        else if (re4.test(w))
+          w = w + "e";
+      }
+    }
+
+    // Step 1c
+    re = /^(.+?)y$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(s_v);
+      if (re.test(stem))
+        w = stem + "i";
+    }
+
+    // Step 2
+    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step2list[suffix];
+    }
+
+    // Step 3
+    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      suffix = fp[2];
+      re = new RegExp(mgr0);
+      if (re.test(stem))
+        w = stem + step3list[suffix];
+    }
+
+    // Step 4
+    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
+    re2 = /^(.+?)(s|t)(ion)$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      if (re.test(stem))
+        w = stem;
+    }
+    else if (re2.test(w)) {
+      var fp = re2.exec(w);
+      stem = fp[1] + fp[2];
+      re2 = new RegExp(mgr1);
+      if (re2.test(stem))
+        w = stem;
+    }
+
+    // Step 5
+    re = /^(.+?)e$/;
+    if (re.test(w)) {
+      var fp = re.exec(w);
+      stem = fp[1];
+      re = new RegExp(mgr1);
+      re2 = new RegExp(meq1);
+      re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
+      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
+        w = stem;
+    }
+    re = /ll$/;
+    re2 = new RegExp(mgr1);
+    if (re.test(w) && re2.test(w)) {
+      re = /.$/;
+      w = w.replace(re,"");
+    }
+
+    // and turn initial Y back to y
+    if (firstch == "y")
+      w = firstch.toLowerCase() + w.substr(1);
+    return w;
+  }
+}
+
+
+/**
+ * Search Module
+ */
+var Search = {
+
+  _index : null,
+  _queued_query : null,
+  _pulse_status : -1,
+
+  init : function() {
+      var params = $.getQueryParameters();
+      if (params.q) {
+          var query = params.q[0];
+          $('input[name="q"]')[0].value = query;
+          this.performSearch(query);
+      }
+  },
+
+  /**
+   * Sets the index
+   */
+  setIndex : function(index) {
+    var q;
+    this._index = index;
+    if ((q = this._queued_query) !== null) {
+      this._queued_query = null;
+      Search.query(q);
+    }
+  },
+
+  hasIndex : function() {
+      return this._index !== null;
+  },
+
+  deferQuery : function(query) {
+      this._queued_query = query;
+  },
+
+  stopPulse : function() {
+      this._pulse_status = 0;
+  },
+
+  startPulse : function() {
+    if (this._pulse_status >= 0)
+        return;
+    function pulse() {
+      Search._pulse_status = (Search._pulse_status + 1) % 4;
+      var dotString = '';
+      for (var i = 0; i < Search._pulse_status; i++)
+        dotString += '.';
+      Search.dots.text(dotString);
+      if (Search._pulse_status > -1)
+        window.setTimeout(pulse, 500);
+    };
+    pulse();
+  },
+
+  /**
+   * perform a search for something
+   */
+  performSearch : function(query) {
+    // create the required interface elements
+    this.out = $('#search-results');
+    this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
+    this.dots = $('<span></span>').appendTo(this.title);
+    this.status = $('<p style="display: none"></p>').appendTo(this.out);
+    this.output = $('<ul class="search"/>').appendTo(this.out);
+
+    $('#search-progress').text(_('Preparing search...'));
+    this.startPulse();
+
+    // index already loaded, the browser was quick!
+    if (this.hasIndex())
+      this.query(query);
+    else
+      this.deferQuery(query);
+  },
+
+  query : function(query) {
+    // stem the searchterms and add them to the
+    // correct list
+    var stemmer = new PorterStemmer();
+    var searchterms = [];
+    var excluded = [];
+    var hlterms = [];
+    var tmp = query.split(/\s+/);
+    var object = (tmp.length == 1) ? tmp[0].toLowerCase() : null;
+    for (var i = 0; i < tmp.length; i++) {
+      // stem the word
+      var word = stemmer.stemWord(tmp[i]).toLowerCase();
+      // select the correct list
+      if (word[0] == '-') {
+        var toAppend = excluded;
+        word = word.substr(1);
+      }
+      else {
+        var toAppend = searchterms;
+        hlterms.push(tmp[i].toLowerCase());
+      }
+      // only add if not already in the list
+      if (!$.contains(toAppend, word))
+        toAppend.push(word);
+    };
+    var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
+
+    console.debug('SEARCH: searching for:');
+    console.info('required: ', searchterms);
+    console.info('excluded: ', excluded);
+
+    // prepare search
+    var filenames = this._index.filenames;
+    var titles = this._index.titles;
+    var terms = this._index.terms;
+    var descrefs = this._index.descrefs;
+    var modules = this._index.modules;
+    var desctypes = this._index.desctypes;
+    var fileMap = {};
+    var files = null;
+    var objectResults = [];
+    var regularResults = [];
+    $('#search-progress').empty();
+
+    // lookup as object
+    if (object != null) {
+      for (var module in modules) {
+        if (module.indexOf(object) > -1) {
+          fn = modules[module];
+          descr = _('module, in ') + titles[fn];
+          objectResults.push([filenames[fn], module, '#module-'+module, descr]);
+        }
+      }
+      for (var prefix in descrefs) {
+        for (var name in descrefs[prefix]) {
+          var fullname = (prefix ? prefix + '.' : '') + name;
+          if (fullname.toLowerCase().indexOf(object) > -1) {
+            match = descrefs[prefix][name];
+            descr = desctypes[match[1]] + _(', in ') + titles[match[0]];
+            objectResults.push([filenames[match[0]], fullname, '#'+fullname, descr]);
+          }
+        }
+      }
+    }
+
+    // sort results descending
+    objectResults.sort(function(a, b) {
+      return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
+    });
+
+
+    // perform the search on the required terms
+    for (var i = 0; i < searchterms.length; i++) {
+      var word = searchterms[i];
+      // no match but word was a required one
+      if ((files = terms[word]) == null)
+        break;
+      if (files.length == undefined) {
+        files = [files];
+      }
+      // create the mapping
+      for (var j = 0; j < files.length; j++) {
+        var file = files[j];
+        if (file in fileMap)
+          fileMap[file].push(word);
+        else
+          fileMap[file] = [word];
+      }
+    }
+
+    // now check if the files don't contain excluded terms
+    for (var file in fileMap) {
+      var valid = true;
+
+      // check if all requirements are matched
+      if (fileMap[file].length != searchterms.length)
+        continue;
+
+      // ensure that none of the excluded terms is in the
+      // search result.
+      for (var i = 0; i < excluded.length; i++) {
+        if (terms[excluded[i]] == file ||
+            $.contains(terms[excluded[i]] || [], file)) {
+          valid = false;
+          break;
+        }
+      }
+
+      // if we have still a valid result we can add it
+      // to the result list
+      if (valid)
+        regularResults.push([filenames[file], titles[file], '', null]);
+    }
+
+    // delete unused variables in order to not waste
+    // memory until list is retrieved completely
+    delete filenames, titles, terms;
+
+    // now sort the regular results descending by title
+    regularResults.sort(function(a, b) {
+      var left = a[1].toLowerCase();
+      var right = b[1].toLowerCase();
+      return (left > right) ? -1 : ((left < right) ? 1 : 0);
+    });
+
+    // combine both
+    var results = regularResults.concat(objectResults);
+
+    // print the results
+    var resultCount = results.length;
+    function displayNextItem() {
+      // results left, load the summary and display it
+      if (results.length) {
+        var item = results.pop();
+        var listItem = $('<li style="display:none"></li>');
+        listItem.append($('<a/>').attr(
+          'href',
+          item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
+          highlightstring + item[2]).html(item[1]));
+        if (item[3]) {
+          listItem.append($('<span> (' + item[3] + ')</span>'));
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
+          $.get('_sources/' + item[0] + '.txt', function(data) {
+            listItem.append($.makeSearchSummary(data, searchterms, hlterms));
+            Search.output.append(listItem);
+            listItem.slideDown(5, function() {
+              displayNextItem();
+            });
+          });
+        } else {
+          // no source available, just display title
+          Search.output.append(listItem);
+          listItem.slideDown(5, function() {
+            displayNextItem();
+          });
+        }
+      }
+      // search finished, update title and status message
+      else {
+        Search.stopPulse();
+        Search.title.text(_('Search Results'));
+        if (!resultCount)
+          Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
+        else
+            Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
+        Search.status.fadeIn(500);
+      }
+    }
+    displayNextItem();
+  }
+}
+
+$(document).ready(function() {
+  Search.init();
+});
diff --git a/doc/html/_static/sphinxdoc.css b/doc/html/_static/sphinxdoc.css
new file mode 100755
index 0000000..2c63178
--- /dev/null
+++ b/doc/html/_static/sphinxdoc.css
@@ -0,0 +1,504 @@
+/**
+ * Alternate Sphinx design
+ * Originally created by Armin Ronacher for Werkzeug, adapted by Georg Brandl.
+ */
+
+body {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif;
+    font-size: 14px;
+    letter-spacing: -0.01em;
+    line-height: 150%;
+    text-align: center;
+    /*background-color: #AFC1C4; */
+    background-color: #BFD1D4;
+    color: black;
+    padding: 0;
+    border: 1px solid #aaa;
+
+    margin: 0px 80px 0px 80px;
+    min-width: 740px;
+}
+
+a {
+    color: #CA7900;
+    text-decoration: none;
+}
+
+a:hover {
+    color: #2491CF;
+}
+
+pre {
+    font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.015em;
+    padding: 0.5em;
+    border: 1px solid #ccc;
+    background-color: #f8f8f8;
+}
+
+td.linenos pre {
+    padding: 0.5em 0;
+    border: 0;
+    background-color: transparent;
+    color: #aaa;
+}
+
+table.highlighttable {
+    margin-left: 0.5em;
+}
+
+table.highlighttable td {
+    padding: 0 0.5em 0 0.5em;
+}
+
+cite, code, tt {
+    font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.01em;
+}
+
+hr {
+    border: 1px solid #abc;
+    margin: 2em;
+}
+
+tt {
+    background-color: #f2f2f2;
+    border-bottom: 1px solid #ddd;
+    color: #333;
+}
+
+tt.descname {
+    background-color: transparent;
+    font-weight: bold;
+    font-size: 1.2em;
+    border: 0;
+}
+
+tt.descclassname {
+    background-color: transparent;
+    border: 0;
+}
+
+tt.xref {
+    background-color: transparent;
+    font-weight: bold;
+    border: 0;
+}
+
+a tt {
+    background-color: transparent;
+    font-weight: bold;
+    border: 0;
+    color: #CA7900;
+}
+
+a tt:hover {
+    color: #2491CF;
+}
+
+.field-list ul {
+    margin: 0;
+    padding-left: 1em;
+}
+
+.field-list p {
+    margin: 0;
+}
+
+dl {
+    margin-bottom: 15px;
+}
+
+dd p {
+    margin-top: 0px;
+}
+
+dd ul, dd table {
+    margin-bottom: 10px;
+}
+
+dd {
+    margin-top: 3px;
+    margin-bottom: 10px;
+    margin-left: 30px;
+}
+
+.refcount {
+    color: #060;
+}
+
+dt:target,
+.highlight {
+    background-color: #fbe54e;
+}
+
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+pre {
+    line-height: 120%;
+}
+
+pre a {
+    color: inherit;
+    text-decoration: underline;
+}
+
+.first {
+    margin-top: 0 !important;
+}
+
+div.document {
+    background-color: white;
+    text-align: left;
+    background-image: url(contents.png);
+    background-repeat: repeat-x;
+}
+
+/*
+div.documentwrapper {
+    width: 100%;
+}
+*/
+
+div.clearer {
+    clear: both;
+}
+
+div.related h3 {
+    display: none;
+}
+
+div.related ul {
+    background-image: url(navigation.png);
+    height: 2em;
+    list-style: none;
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 0;
+    padding-left: 10px;
+}
+
+div.related ul li {
+    margin: 0;
+    padding: 0;
+    height: 2em;
+    float: left;
+}
+
+div.related ul li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+div.related ul li a {
+    margin: 0;
+    padding: 0 5px 0 5px;
+    line-height: 1.75em;
+    color: #EE9816;
+}
+
+div.related ul li a:hover {
+    color: #3CA8E7;
+}
+
+div.body {
+    margin: 0;
+    padding: 0.5em 20px 20px 20px;
+}
+
+div.bodywrapper {
+    margin: 0 240px 0 0;
+    border-right: 1px solid #ccc;
+}
+
+div.body a {
+    text-decoration: underline;
+}
+
+div.sphinxsidebar {
+    margin: 0;
+    padding: 0.5em 15px 15px 0;
+    width: 210px;
+    float: right;
+    text-align: left;
+/*    margin-left: -100%; */
+}
+
+div.sphinxsidebar h4, div.sphinxsidebar h3 {
+    margin: 1em 0 0.5em 0;
+    font-size: 0.9em;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border: 1px solid #86989B;
+    background-color: #AFC1C4;
+}
+
+div.sphinxsidebar ul {
+    padding-left: 1.5em;
+    margin-top: 7px;
+    list-style: none;
+    padding: 0;
+    line-height: 130%;
+}
+
+div.sphinxsidebar ul ul {
+    list-style: square;
+    margin-left: 20px;
+}
+
+p {
+    margin: 0.8em 0 0.5em 0;
+}
+
+p.rubric {
+    font-weight: bold;
+}
+
+h1 {
+    margin: 0;
+    padding: 0.7em 0 0.3em 0;
+    font-size: 1.5em;
+    color: #11557C;
+}
+
+h2 {
+    margin: 1.3em 0 0.2em 0;
+    font-size: 1.35em;
+    padding: 0;
+}
+
+h3 {
+    margin: 1em 0 -0.3em 0;
+    font-size: 1.2em;
+}
+
+h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
+    color: black!important;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+    display: none;
+    margin: 0 0 0 0.3em;
+    padding: 0 0.2em 0 0.2em;
+    color: #aaa!important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+    display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+    color: #777;
+    background-color: #eee;
+}
+
+table {
+    border-collapse: collapse;
+    margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+    padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+div.footer {
+    background-color: #E3EFF1;
+    color: #86989B;
+    padding: 3px 8px 3px 0;
+    clear: both;
+    font-size: 0.8em;
+    text-align: right;
+}
+
+div.footer a {
+    color: #86989B;
+    text-decoration: underline;
+}
+
+div.pagination {
+    margin-top: 2em;
+    padding-top: 0.5em;
+    border-top: 1px solid black;
+    text-align: center;
+}
+
+div.sphinxsidebar ul.toc {
+    margin: 1em 0 1em 0;
+    padding: 0 0 0 0.5em;
+    list-style: none;
+}
+
+div.sphinxsidebar ul.toc li {
+    margin: 0.5em 0 0.5em 0;
+    font-size: 0.9em;
+    line-height: 130%;
+}
+
+div.sphinxsidebar ul.toc li p {
+    margin: 0;
+    padding: 0;
+}
+
+div.sphinxsidebar ul.toc ul {
+    margin: 0.2em 0 0.2em 0;
+    padding: 0 0 0 1.8em;
+}
+
+div.sphinxsidebar ul.toc ul li {
+    padding: 0;
+}
+
+div.admonition, div.warning {
+    font-size: 0.9em;
+    margin: 1em 0 0 0;
+    border: 1px solid #86989B;
+    background-color: #f7f7f7;
+}
+
+div.admonition p, div.warning p {
+    margin: 0.5em 1em 0.5em 1em;
+    padding: 0;
+}
+
+div.admonition pre, div.warning pre {
+    margin: 0.4em 1em 0.4em 1em;
+}
+
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+    margin: 0;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    border-bottom: 1px solid #86989B;
+    font-weight: bold;
+    background-color: #AFC1C4;
+}
+
+div.warning {
+    border: 1px solid #940000;
+}
+
+div.warning p.admonition-title {
+    background-color: #CF0000;
+    border-bottom-color: #940000;
+}
+
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
+    margin: 0.1em 0.5em 0.5em 3em;
+    padding: 0;
+}
+
+div.versioninfo {
+    margin: 1em 0 0 0;
+    border: 1px solid #ccc;
+    background-color: #DDEAF0;
+    padding: 8px;
+    line-height: 1.3em;
+    font-size: 0.9em;
+}
+
+
+a.headerlink {
+    color: #c60f0f!important;
+    font-size: 1em;
+    margin-left: 6px;
+    padding: 0 4px 0 4px;
+    text-decoration: none!important;
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+a.headerlink:hover {
+    background-color: #ccc;
+    color: white!important;
+}
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+form.pfform {
+    margin: 10px 0 20px 0;
+}
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.3em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+    font-size: 90%;
+}
+
+ul.search {
+    margin: 10px 0 0 20px;
+    padding: 0;
+}
+
+ul.search li {
+    padding: 5px 0 5px 20px;
+    background-image: url(file.png);
+    background-repeat: no-repeat;
+    background-position: 0 7px;
+}
+
+ul.search li a {
+    font-weight: bold;
+}
+
+ul.search li div.context {
+    color: #888;
+    margin: 2px 0 0 30px;
+    text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+    font-weight: bold;
+}
diff --git a/doc/html/_static/stickysidebar.css b/doc/html/_static/stickysidebar.css
new file mode 100755
index 0000000..dfc99c7
--- /dev/null
+++ b/doc/html/_static/stickysidebar.css
@@ -0,0 +1,19 @@
+/**
+ * Sphinx Doc Design -- Sticky sidebar Overrides
+ */
+
+div.sphinxsidebar {
+    top: 30px;
+    left: 0px;
+    position: fixed;
+    margin: 0;
+    float: none;
+}
+
+div.related {
+    position: fixed;
+}
+
+div.documentwrapper {
+    margin-top: 30px;
+}
diff --git a/doc/html/_static/traditional.css b/doc/html/_static/traditional.css
new file mode 100755
index 0000000..8c224c0
--- /dev/null
+++ b/doc/html/_static/traditional.css
@@ -0,0 +1,700 @@
+/**
+ * Sphinx Doc Design -- traditional python.org style
+ */
+
+body {
+    color: #000;
+    margin: 0;
+    padding: 0;
+}
+
+/* :::: LAYOUT :::: */
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+}
+
+div.bodywrapper {
+    margin: 0 230px 0 0;
+}
+
+div.body {
+    background-color: white;
+    padding: 0 20px 30px 20px;
+}
+
+div.sphinxsidebarwrapper {
+    border: 1px solid #99ccff;
+    padding: 10px;
+    margin: 10px 15px 10px 0;
+}
+
+div.sphinxsidebar {
+    float: right;
+    margin-left: -100%;
+    width: 230px;
+}
+
+div.clearer {
+    clear: both;
+}
+
+div.footer {
+    clear: both;
+    width: 100%;
+    background-color: #99ccff;
+    padding: 9px 0 9px 0;
+    text-align: center;
+}
+
+div.related {
+    background-color: #99ccff;
+    color: #333;
+    width: 100%;
+    height: 30px;
+    line-height: 30px;
+    border-bottom: 5px solid white;
+}
+
+div.related h3 {
+    display: none;
+}
+
+div.related ul {
+    margin: 0;
+    padding: 0 0 0 10px;
+    list-style: none;
+}
+
+div.related li {
+    display: inline;
+    font-weight: bold;
+}
+
+div.related li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+/* ::: SIDEBAR :::: */
+div.sphinxsidebar h3 {
+    margin: 0;
+}
+
+div.sphinxsidebar h4 {
+    margin: 5px 0 0 0;
+}
+
+div.sphinxsidebar p.topless {
+    margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+    margin: 10px;
+    margin-left: 15px;
+    padding: 0;
+}
+
+div.sphinxsidebar ul ul {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+    margin-top: 10px;
+}
+
+
+/* :::: SEARCH :::: */
+ul.search {
+    margin: 10px 0 0 20px;
+    padding: 0;
+}
+
+ul.search li {
+    padding: 5px 0 5px 20px;
+    background-image: url(file.png);
+    background-repeat: no-repeat;
+    background-position: 0 7px;
+}
+
+ul.search li a {
+    font-weight: bold;
+}
+
+ul.search li div.context {
+    color: #888;
+    margin: 2px 0 0 30px;
+    text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+    font-weight: bold;
+}
+
+/* :::: COMMON FORM STYLES :::: */
+
+div.actions {
+    border-top: 1px solid #aaa;
+    background-color: #ddd;
+    margin: 10px 0 0 -20px;
+    padding: 5px 0 5px 20px;
+}
+
+form dl {
+    color: #333;
+}
+
+form dt {
+    clear: both;
+    float: left;
+    min-width: 110px;
+    margin-right: 10px;
+    padding-top: 2px;
+}
+
+input#homepage {
+    display: none;
+}
+
+div.error {
+    margin: 5px 20px 0 0;
+    padding: 5px;
+    border: 1px solid #d00;
+    /*border: 2px solid #05171e;
+    background-color: #092835;
+    color: white;*/
+    font-weight: bold;
+}
+
+/* :::: INLINE COMMENTS :::: */
+
+div.inlinecommentswrapper {
+    float: right;
+    max-width: 40%;
+}
+
+div.commentmarker {
+    float: right;
+    background-image: url(style/comment.png);
+    background-repeat: no-repeat;
+    width: 25px;
+    height: 25px;
+    text-align: center;
+    padding-top: 3px;
+}
+
+div.nocommentmarker {
+    float: right;
+    background-image: url(style/nocomment.png);
+    background-repeat: no-repeat;
+    width: 25px;
+    height: 25px;
+}
+
+div.inlinecomments {
+    margin-left: 10px;
+    margin-bottom: 5px;
+    background-color: #eee;
+    border: 1px solid #ccc;
+    padding: 5px;
+}
+
+div.inlinecomment {
+    border-top: 1px solid #ccc;
+    padding-top: 5px;
+    margin-top: 5px;
+}
+
+.inlinecomments p {
+    margin: 5px 0 5px 0;
+}
+
+.inlinecomments .head {
+    font-weight: bold;
+}
+
+.inlinecomments .meta {
+    font-style: italic;
+}
+
+
+/* :::: COMMENTS :::: */
+
+div#comments h3 {
+    border-top: 1px solid #aaa;
+    padding: 5px 20px 5px 20px;
+    margin: 20px -20px 20px -20px;
+    background-color: #ddd;
+}
+
+/*
+div#comments {
+    background-color: #ccc;
+    margin: 40px -20px -30px -20px;
+    padding: 0 0 1px 0;
+}
+
+div#comments h4 {
+    margin: 30px 0 20px 0;
+    background-color: #aaa;
+    border-bottom: 1px solid #09232e;
+    color: #333;
+}
+
+div#comments form {
+    display: block;
+    margin: 0 0 0 20px;
+}
+
+div#comments textarea {
+    width: 98%;
+    height: 160px;
+}
+
+div#comments div.help {
+    margin: 20px 20px 10px 0;
+    background-color: #ccc;
+    color: #333;
+}
+
+div#comments div.help p {
+    margin: 0;
+    padding: 0 0 10px 0;
+}
+
+div#comments input, div#comments textarea {
+    font-family: 'Bitstream Vera Sans', 'Arial', sans-serif;
+    font-size: 13px;
+    color: black;
+    background-color: #aaa;
+    border: 1px solid #092835;
+}
+
+div#comments input[type="reset"],
+div#comments input[type="submit"] {
+    cursor: pointer;
+    font-weight: bold;
+    padding: 2px;
+    margin: 5px 5px 5px 0;
+    background-color: #666;
+    color: white;
+}
+
+div#comments div.comment {
+    margin: 10px 10px 10px 20px;
+    padding: 10px;
+    border: 1px solid #0f3646;
+    background-color: #aaa;
+    color: #333;
+}
+
+div#comments div.comment p {
+    margin: 5px 0 5px 0;
+}
+
+div#comments div.comment p.meta {
+    font-style: italic;
+    color: #444;
+    text-align: right;
+    margin: -5px 0 -5px 0;
+}
+
+div#comments div.comment h4 {
+    margin: -10px -10px 5px -10px;
+    padding: 3px;
+    font-size: 15px;
+    background-color: #888;
+    color: white;
+    border: 0;
+}
+
+div#comments div.comment pre,
+div#comments div.comment tt {
+    background-color: #ddd;
+    color: #111;
+    border: none;
+}
+
+div#comments div.comment a {
+    color: #fff;
+    text-decoration: underline;
+}
+
+div#comments div.comment blockquote {
+    margin: 10px;
+    padding: 10px;
+    border-left: 1px solid #0f3646;
+    /*border: 1px solid #0f3646;
+    background-color: #071c25;*/
+}
+
+div#comments em.important {
+    color: #d00;
+    font-weight: bold;
+    font-style: normal;
+}*/
+
+/* :::: SUGGEST CHANGES :::: */
+div#suggest-changes-box input, div#suggest-changes-box textarea {
+    border: 1px solid #ccc;
+    background-color: white;
+    color: black;
+}
+
+div#suggest-changes-box textarea {
+    width: 99%;
+    height: 400px;
+}
+
+
+/* :::: PREVIEW :::: */
+div.preview {
+    background-image: url(style/preview.png);
+    padding: 0 20px 20px 20px;
+    margin-bottom: 30px;
+}
+
+
+/* :::: INDEX PAGE :::: */
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.5em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+}
+
+/* :::: GENINDEX STYLES :::: */
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+/* :::: GLOBAL STYLES :::: */
+
+p.subhead {
+    font-weight: bold;
+    margin-top: 20px;
+}
+
+a:link:active           { color: #ff0000; }
+a:link:hover            { background-color: #bbeeff; }
+a:visited:hover         { background-color: #bbeeff; }
+a:visited               { color: #551a8b; }
+a:link                  { color: #0000bb; }
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+    font-family: avantgarde, sans-serif;
+    font-weight: bold;
+}
+
+div.body h1 { font-size: 180%; }
+div.body h2 { font-size: 150%; }
+div.body h3 { font-size: 120%; }
+div.body h4 { font-size: 120%; }
+
+a.headerlink,
+a.headerlink,
+a.headerlink,
+a.headerlink,
+a.headerlink,
+a.headerlink {
+    color: #c60f0f;
+    font-size: 0.8em;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+    visibility: hidden;
+}
+
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink,
+*:hover > a.headerlink {
+    visibility: visible;
+}
+
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover,
+a.headerlink:hover {
+    background-color: #c60f0f;
+    color: white;
+}
+
+div.body p, div.body dd, div.body li {
+    text-align: justify;
+}
+
+div.body td {
+    text-align: left;
+}
+
+ul.fakelist {
+    list-style: none;
+    margin: 10px 0 10px 20px;
+    padding: 0;
+}
+
+/* "Footnotes" heading */
+p.rubric {
+    margin-top: 30px;
+    font-weight: bold;
+}
+
+/* "Topics" */
+
+div.topic {
+    background-color: #eee;
+    border: 1px solid #ccc;
+    padding: 0 7px 0 7px;
+    margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+    font-size: 1.1em;
+    font-weight: bold;
+    margin-top: 10px;
+}
+
+/* Admonitions */
+
+div.admonition {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    padding: 7px;
+}
+
+div.admonition dt {
+    font-weight: bold;
+}
+
+div.admonition dd {
+    margin-bottom: 10px;
+}
+
+div.admonition dl {
+    margin-bottom: 0;
+}
+
+div.admonition p {
+    display: inline;
+}
+
+div.seealso {
+    background-color: #ffc;
+    border: 1px solid #ff6;
+}
+
+div.warning {
+    background-color: #ffe4e4;
+    border: 1px solid #f66;
+}
+
+div.note {
+    background-color: #eee;
+    border: 1px solid #ccc;
+}
+
+p.admonition-title {
+    margin: 0px 10px 5px 0px;
+    font-weight: bold;
+    display: inline;
+}
+
+p.admonition-title:after {
+    content: ":";
+}
+
+div.body p.centered {
+    text-align: center;
+    margin-top: 25px;
+}
+
+table.docutils {
+    border: 0;
+}
+
+table.docutils td, table.docutils th {
+    padding: 0 8px 2px 0;
+    border-top: 0;
+    border-left: 0;
+    border-right: 0;
+    border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+    border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+    border: 0 !important;
+}
+
+dl {
+    margin-bottom: 15px;
+    clear: both;
+}
+
+dd p {
+    margin-top: 0px;
+}
+
+dd ul, dd table {
+    margin-bottom: 10px;
+}
+
+dd {
+    margin-top: 3px;
+    margin-bottom: 10px;
+    margin-left: 30px;
+}
+
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.refcount {
+    color: #060;
+}
+
+th {
+    text-align: left;
+    padding-right: 5px;
+}
+
+pre {
+    font-family: monospace;
+    padding: 5px;
+    color: #00008b;
+    border-left: none;
+    border-right: none;
+}
+
+tt {
+    font-family: monospace;
+    background-color: #ecf0f3;
+    padding: 0 1px 0 1px;
+}
+
+tt.descname {
+    background-color: transparent;
+    font-weight: bold;
+    font-size: 1.2em;
+}
+
+tt.descclassname {
+    background-color: transparent;
+}
+
+tt.xref, a tt {
+    background-color: transparent;
+    font-weight: bold;
+}
+
+.footnote:target  { background-color: #ffa }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+    background-color: transparent;
+}
+
+.optional {
+    font-size: 1.3em;
+}
+
+.versionmodified {
+    font-style: italic;
+}
+
+form.comment {
+    margin: 0;
+    padding: 10px 30px 10px 30px;
+    background-color: #eee;
+}
+
+form.comment h3 {
+    background-color: #326591;
+    color: white;
+    margin: -10px -30px 10px -30px;
+    padding: 5px;
+    font-size: 1.4em;
+}
+
+form.comment input,
+form.comment textarea {
+    border: 1px solid #ccc;
+    padding: 2px;
+    font-family: sans-serif;
+    font-size: 13px;
+}
+
+form.comment input[type="text"] {
+    width: 240px;
+}
+
+form.comment textarea {
+    width: 100%;
+    height: 200px;
+    margin-bottom: 10px;
+}
+
+/* :::: PRINT :::: */
+@media print {
+    div.documentwrapper {
+        width: 100%;
+    }
+
+    div.body {
+        margin: 0;
+    }
+
+    div.sphinxsidebar,
+    div.related,
+    div.footer,
+    div#comments div.new-comment-box,
+    #top-link {
+        display: none;
+    }
+}
diff --git a/doc/html/genindex.html b/doc/html/genindex.html
new file mode 100644
index 0000000..0088470
--- /dev/null
+++ b/doc/html/genindex.html
@@ -0,0 +1,207 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+    <title>Index &mdash; httplib2 v0.4 documentation</title>
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    '#',
+        VERSION:     '0.4',
+        COLLAPSE_MODINDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="top" title="httplib2 v0.4 documentation" href="index.html" />
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="#" title="General Index"
+             accesskey="I">index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             accesskey="M">modules</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+
+
+   <h1 id="index">Index</h1>
+
+   <a href="#A"><strong>A</strong></a> | <a href="#C"><strong>C</strong></a> | <a href="#D"><strong>D</strong></a> | <a href="#F"><strong>F</strong></a> | <a href="#G"><strong>G</strong></a> | <a href="#H"><strong>H</strong></a> | <a href="#I"><strong>I</strong></a> | <a href="#O"><strong>O</strong></a> | <a href="#P"><strong>P</strong></a> | <a href="#R"><strong>R</strong></a> | <a href="#S"><strong>S</strong></a> | <a href="#U"><strong>U</strong></a> | <a href="#V"><strong>V</strong></a>
+
+   <hr />
+
+
+<h2 id="A">A</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Http.add_certificate">add_certificate() (httplib2.Http method)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Http.add_credentials">add_credentials() (httplib2.Http method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="C">C</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Http.clear_credentials">clear_credentials() (httplib2.Http method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="D">D</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.debuglevel">debuglevel (in module httplib2)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Cache.delete">delete() (httplib2.Cache method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="F">F</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.FailedToDecompressContent">FailedToDecompressContent</a></dt>
+<dt><a href="libhttplib2.html#httplib2.FileCache">FileCache (class in httplib2)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Http.follow_all_redirects">follow_all_redirects (httplib2.Http attribute)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Http.follow_redirects">follow_redirects (httplib2.Http attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="libhttplib2.html#httplib2.Http.force_exception_to_status_code">force_exception_to_status_code (httplib2.Http attribute)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Http.forward_authorization_headers">forward_authorization_headers (httplib2.Http attribute)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Response.fromcache">fromcache (httplib2.Response attribute)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="G">G</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Cache.get">get() (httplib2.Cache method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="H">H</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Http">Http (class in httplib2)</a></dt>
+<dt><a href="libhttplib2.html#module-httplib2">httplib2 (module)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="libhttplib2.html#httplib2.HttpLib2Error">HttpLib2Error</a></dt>
+</dl></td></tr></table>
+
+<h2 id="I">I</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Http.ignore_etag">ignore_etag (httplib2.Http attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="O">O</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Http.optimistic_concurrency_methods">optimistic_concurrency_methods (httplib2.Http attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="P">P</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Response.previous">previous (httplib2.Response attribute)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.ProxyInfo">ProxyInfo (class in httplib2)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="R">R</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Response.reason">reason (httplib2.Response attribute)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.RedirectLimit">RedirectLimit</a></dt>
+<dt><a href="libhttplib2.html#httplib2.RedirectMissingLocation">RedirectMissingLocation</a></dt>
+<dt><a href="libhttplib2.html#httplib2.RelativeURIError">RelativeURIError</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="libhttplib2.html#httplib2.Http.request">request() (httplib2.Http method)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Response">Response (class in httplib2)</a></dt>
+<dt><a href="libhttplib2.html#httplib2.RETRIES">RETRIES (in module httplib2)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="S">S</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.ServerNotFoundError">ServerNotFoundError</a></dt>
+<dt><a href="libhttplib2.html#httplib2.Cache.set">set() (httplib2.Cache method)</a></dt></dl></td><td width="33%" valign="top"><dl>
+<dt><a href="libhttplib2.html#httplib2.Response.status">status (httplib2.Response attribute)</a></dt>
+</dl></td></tr></table>
+
+<h2 id="U">U</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.UnimplementedDigestAuthOptionError">UnimplementedDigestAuthOptionError</a></dt>
+<dt><a href="libhttplib2.html#httplib2.UnimplementedHmacDigestAuthOptionError">UnimplementedHmacDigestAuthOptionError</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+<h2 id="V">V</h2>
+<table width="100%" class="indextable"><tr><td width="33%" valign="top">
+<dl>
+
+<dt><a href="libhttplib2.html#httplib2.Response.version">version (httplib2.Response attribute)</a></dt></dl></td><td width="33%" valign="top"><dl>
+</dl></td></tr></table>
+
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+
+
+
+          <div id="searchbox" style="display: none">
+            <h3>Quick search</h3>
+              <form class="search" action="search.html" method="get">
+                <input type="text" name="q" size="18" />
+                <input type="submit" value="Go" />
+                <input type="hidden" name="check_keywords" value="yes" />
+                <input type="hidden" name="area" value="default" />
+              </form>
+              <p class="searchtip" style="font-size: 90%">
+              Enter search terms or a module, class or function name.
+              </p>
+          </div>
+          <script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="#" title="General Index"
+             >index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             >modules</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+    <div class="footer">
+      &copy; Copyright 2008, Joe Gregorio.
+      Last updated on Aug 28, 2012.
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
+    </div>
+  </body>
+</html>
diff --git a/doc/html/index.html b/doc/html/index.html
new file mode 100644
index 0000000..adc081e
--- /dev/null
+++ b/doc/html/index.html
@@ -0,0 +1,144 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+    <title>The httplib2 Library &mdash; httplib2 v0.4 documentation</title>
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    '#',
+        VERSION:     '0.4',
+        COLLAPSE_MODINDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="top" title="httplib2 v0.4 documentation" href="#" />
+    <link rel="next" title="httplib2 A comprehensive HTTP client library." href="libhttplib2.html" />
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             accesskey="M">modules</a> |</li>
+        <li class="right" >
+          <a href="libhttplib2.html" title="httplib2 A comprehensive HTTP client library."
+             accesskey="N">next</a> |</li>
+        <li><a href="#">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+
+  <div class="section" id="the-httplib2-library">
+<h1>The httplib2 Library<a class="headerlink" href="#the-httplib2-library" title="Permalink to this headline">¶</a></h1>
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">Author:</th><td class="field-body">Joe Gregorio</td>
+</tr>
+<tr class="field"><th class="field-name">Date:</th><td class="field-body">Mar 8, 2007</td>
+</tr>
+</tbody>
+</table>
+<div class="topic">
+<p class="topic-title first">Abstract</p>
+<p>The <a title="" class="reference external" href="libhttplib2.html#module-httplib2"><tt class="xref docutils literal"><span class="pre">httplib2</span></tt></a> module is a comprehensive HTTP client library that handles
+caching, keep-alive, compression, redirects and many kinds of authentication.</p>
+</div>
+<p>Contents:</p>
+<ul>
+<li class="toctree-l1"><a class="reference external" href="libhttplib2.html"><tt class="docutils literal"><span class="pre">httplib2</span></tt>  A comprehensive HTTP client library.</a><ul>
+<li class="toctree-l2"><a class="reference external" href="libhttplib2.html#http-objects">Http Objects</a></li>
+<li class="toctree-l2"><a class="reference external" href="libhttplib2.html#cache-objects">Cache Objects</a></li>
+<li class="toctree-l2"><a class="reference external" href="libhttplib2.html#response-objects">Response Objects</a></li>
+<li class="toctree-l2"><a class="reference external" href="libhttplib2.html#examples">Examples</a></li>
+</ul>
+</li>
+</ul>
+<div class="section" id="indices-and-tables">
+<h2>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h2>
+<ul class="simple">
+<li><a class="reference external" href="genindex.html"><em>Index</em></a></li>
+<li><a class="reference external" href="modindex.html"><em>Module Index</em></a></li>
+<li><a class="reference external" href="search.html"><em>Search Page</em></a></li>
+</ul>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <h3><a href="#">Table Of Contents</a></h3>
+            <ul>
+<li><a class="reference external" href="#">The httplib2 Library</a><ul>
+<li><a class="reference external" href="#indices-and-tables">Indices and tables</a></li>
+</ul>
+</li>
+</ul>
+
+            <h4>Next topic</h4>
+            <p class="topless"><a href="libhttplib2.html"
+                                  title="next chapter"><tt class="docutils literal"><span class="pre">httplib2</span></tt>  A comprehensive HTTP client library.</a></p>
+            <h3>This Page</h3>
+            <ul class="this-page-menu">
+              <li><a href="_sources/index.txt"
+                     rel="nofollow">Show Source</a></li>
+            </ul>
+          <div id="searchbox" style="display: none">
+            <h3>Quick search</h3>
+              <form class="search" action="search.html" method="get">
+                <input type="text" name="q" size="18" />
+                <input type="submit" value="Go" />
+                <input type="hidden" name="check_keywords" value="yes" />
+                <input type="hidden" name="area" value="default" />
+              </form>
+              <p class="searchtip" style="font-size: 90%">
+              Enter search terms or a module, class or function name.
+              </p>
+          </div>
+          <script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             >modules</a> |</li>
+        <li class="right" >
+          <a href="libhttplib2.html" title="httplib2 A comprehensive HTTP client library."
+             >next</a> |</li>
+        <li><a href="#">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+    <div class="footer">
+      &copy; Copyright 2008, Joe Gregorio.
+      Last updated on Aug 28, 2012.
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
+    </div>
+  </body>
+</html>
diff --git a/doc/html/libhttplib2.html b/doc/html/libhttplib2.html
new file mode 100644
index 0000000..e908a46
--- /dev/null
+++ b/doc/html/libhttplib2.html
@@ -0,0 +1,490 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+    <title>httplib2 A comprehensive HTTP client library. &mdash; httplib2 v0.4 documentation</title>
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    '#',
+        VERSION:     '0.4',
+        COLLAPSE_MODINDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="top" title="httplib2 v0.4 documentation" href="index.html" />
+    <link rel="prev" title="The httplib2 Library" href="index.html" />
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             accesskey="M">modules</a> |</li>
+        <li class="right" >
+          <a href="index.html" title="The httplib2 Library"
+             accesskey="P">previous</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+
+  <div class="section" id="module-httplib2">
+<h1><tt class="xref docutils literal"><span class="pre">httplib2</span></tt>  A comprehensive HTTP client library.<a class="headerlink" href="#module-httplib2" title="Permalink to this headline">¶</a></h1>
+<p>The <tt class="xref docutils literal"><span class="pre">httplib2</span></tt> module is a comprehensive HTTP client library with the
+following features:</p>
+<dl class="describe">
+<dt>
+<tt class="descname">HTTP and HTTPS</tt></dt>
+<dd>HTTPS support is only available if the socket module was compiled with SSL
+support.</dd></dl>
+
+<dl class="describe">
+<dt>
+<tt class="descname">Keep-Alive</tt></dt>
+<dd>Supports HTTP 1.1 Keep-Alive, keeping the socket open and performing multiple
+requests over the same connection if possible.</dd></dl>
+
+<dl class="describe">
+<dt>
+<tt class="descname">Authentication</tt></dt>
+<dd><p>The following three types of HTTP Authentication are supported. These can be
+used over both HTTP and HTTPS.</p>
+<blockquote>
+<ul class="simple">
+<li>Digest</li>
+<li>Basic</li>
+<li>WSSE</li>
+</ul>
+</blockquote>
+</dd></dl>
+
+<dl class="describe">
+<dt>
+<tt class="descname">Caching</tt></dt>
+<dd>The module can optionally operate with a private cache that understands the
+Cache-Control: header and uses both the ETag and Last-Modified cache validators.</dd></dl>
+
+<dl class="describe">
+<dt>
+<tt class="descname">All Methods</tt></dt>
+<dd>The module can handle any HTTP request method, not just GET and POST.</dd></dl>
+
+<dl class="describe">
+<dt>
+<tt class="descname">Redirects</tt></dt>
+<dd>Automatically follows 3XX redirects on GETs.</dd></dl>
+
+<dl class="describe">
+<dt>
+<tt class="descname">Compression</tt></dt>
+<dd>Handles both <tt class="docutils literal"><span class="pre">deflate</span></tt> and <tt class="docutils literal"><span class="pre">gzip</span></tt> types of compression.</dd></dl>
+
+<dl class="describe">
+<dt>
+<tt class="descname">Lost update support</tt></dt>
+<dd>Automatically adds back ETags into PUT requests to resources we have already
+cached. This implements Section 3.2 of Detecting the Lost Update Problem Using
+Unreserved Checkout</dd></dl>
+
+<p>The <tt class="xref docutils literal"><span class="pre">httplib2</span></tt> module defines the following variables:</p>
+<dl class="data">
+<dt id="httplib2.debuglevel">
+<tt class="descclassname">httplib2.</tt><tt class="descname">debuglevel</tt><a class="headerlink" href="#httplib2.debuglevel" title="Permalink to this definition">¶</a></dt>
+<dd>The amount of debugging information to print. The default is 0.</dd></dl>
+
+<dl class="data">
+<dt id="httplib2.RETRIES">
+<tt class="descclassname">httplib2.</tt><tt class="descname">RETRIES</tt><a class="headerlink" href="#httplib2.RETRIES" title="Permalink to this definition">¶</a></dt>
+<dd>A request will be tried &#8216;RETRIES&#8217; times if it fails at the socket/connection level.
+The default is 2.</dd></dl>
+
+<p>The <tt class="xref docutils literal"><span class="pre">httplib2</span></tt> module may raise the following Exceptions. Note that  there
+is an option that turns exceptions into  normal responses with an HTTP status
+code indicating an error occured. See
+<a title="httplib2.Http.force_exception_to_status_code" class="reference internal" href="#httplib2.Http.force_exception_to_status_code"><tt class="xref docutils literal"><span class="pre">Http.force_exception_to_status_code</span></tt></a></p>
+<dl class="exception">
+<dt id="httplib2.HttpLib2Error">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">HttpLib2Error</tt><a class="headerlink" href="#httplib2.HttpLib2Error" title="Permalink to this definition">¶</a></dt>
+<dd>The Base Exception for all exceptions raised by httplib2.</dd></dl>
+
+<dl class="exception">
+<dt id="httplib2.RedirectMissingLocation">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">RedirectMissingLocation</tt><a class="headerlink" href="#httplib2.RedirectMissingLocation" title="Permalink to this definition">¶</a></dt>
+<dd>A 3xx redirect response code was provided but no Location: header  was provided
+to point to the new location.</dd></dl>
+
+<dl class="exception">
+<dt id="httplib2.RedirectLimit">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">RedirectLimit</tt><a class="headerlink" href="#httplib2.RedirectLimit" title="Permalink to this definition">¶</a></dt>
+<dd>The maximum number of redirections was reached without coming to a final URI.</dd></dl>
+
+<dl class="exception">
+<dt id="httplib2.ServerNotFoundError">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">ServerNotFoundError</tt><a class="headerlink" href="#httplib2.ServerNotFoundError" title="Permalink to this definition">¶</a></dt>
+<dd>Unable to resolve the host name given.</dd></dl>
+
+<dl class="exception">
+<dt id="httplib2.RelativeURIError">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">RelativeURIError</tt><a class="headerlink" href="#httplib2.RelativeURIError" title="Permalink to this definition">¶</a></dt>
+<dd>A relative, as opposed to an absolute URI, was passed into request().</dd></dl>
+
+<dl class="exception">
+<dt id="httplib2.FailedToDecompressContent">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">FailedToDecompressContent</tt><a class="headerlink" href="#httplib2.FailedToDecompressContent" title="Permalink to this definition">¶</a></dt>
+<dd>The headers claimed that the content of the response was compressed but the
+decompression algorithm applied to the content failed.</dd></dl>
+
+<dl class="exception">
+<dt id="httplib2.UnimplementedDigestAuthOptionError">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">UnimplementedDigestAuthOptionError</tt><a class="headerlink" href="#httplib2.UnimplementedDigestAuthOptionError" title="Permalink to this definition">¶</a></dt>
+<dd>The server requested a type of Digest authentication that we are unfamiliar
+with.</dd></dl>
+
+<dl class="exception">
+<dt id="httplib2.UnimplementedHmacDigestAuthOptionError">
+<em class="property">exception </em><tt class="descclassname">httplib2.</tt><tt class="descname">UnimplementedHmacDigestAuthOptionError</tt><a class="headerlink" href="#httplib2.UnimplementedHmacDigestAuthOptionError" title="Permalink to this definition">¶</a></dt>
+<dd>The server requested a type of HMACDigest authentication that we are unfamiliar
+with.</dd></dl>
+
+<dl class="class">
+<dt id="httplib2.Http">
+<em class="property">class </em><tt class="descclassname">httplib2.</tt><tt class="descname">Http</tt><big>(</big><span class="optional">[</span><em>cache=None</em><span class="optional">]</span><span class="optional">[</span>, <em>timeout=None</em><span class="optional">]</span><span class="optional">[</span>, <em>proxy_info==ProxyInfo.from_environment</em><span class="optional">]</span><span class="optional">[</span>, <em>ca_certs=None</em><span class="optional">]</span><span class="optional">[</span>, <em>disable_ssl_certificate_validation=False</em><span class="optional">]</span><big>)</big><a class="headerlink" href="#httplib2.Http" title="Permalink to this definition">¶</a></dt>
+<dd>The class that represents a client HTTP interface. The <em>cache</em> parameter is
+either the name of a directory to be used as a flat file cache, or it must an
+object that  implements the required caching interface. The <em>timeout</em> parameter
+is the socket level timeout. The <em>ca_certs</em> parameter is the filename of the
+CA certificates to use. If none is given a default set is used. The
+<em>disable_ssl_certificate_validation</em> boolean flag determines if ssl certificate validation
+is done. The <em>proxy_info</em> parameter is an object of type :class:ProxyInfo.</dd></dl>
+
+<dl class="class">
+<dt id="httplib2.ProxyInfo">
+<em class="property">class </em><tt class="descclassname">httplib2.</tt><tt class="descname">ProxyInfo</tt><big>(</big><em>proxy_type</em>, <em>proxy_host</em>, <em>proxy_port</em><span class="optional">[</span>, <em>proxy_rdns=None</em><span class="optional">]</span><span class="optional">[</span>, <em>proxy_user=None</em><span class="optional">]</span><span class="optional">[</span>, <em>proxy_pass=None</em><span class="optional">]</span><big>)</big><a class="headerlink" href="#httplib2.ProxyInfo" title="Permalink to this definition">¶</a></dt>
+<dd><p>Collect information required to use a proxy.
+The parameter proxy_type must be set to one of socks.PROXY_TYPE_XXX
+constants. For example:</p>
+<p>p = ProxyInfo(proxy_type=socks.PROXY_TYPE_HTTP, proxy_host=&#8217;localhost&#8217;, proxy_port=8000)</p>
+</dd></dl>
+
+<dl class="class">
+<dt id="httplib2.Response">
+<em class="property">class </em><tt class="descclassname">httplib2.</tt><tt class="descname">Response</tt><big>(</big><em>info</em><big>)</big><a class="headerlink" href="#httplib2.Response" title="Permalink to this definition">¶</a></dt>
+<dd>Response is a subclass of <tt class="xref docutils literal"><span class="pre">dict</span></tt> and instances of this  class are
+returned from calls to Http.request. The <em>info</em> parameter is either  an
+<tt class="xref docutils literal"><span class="pre">rfc822.Message</span></tt> or an <tt class="xref docutils literal"><span class="pre">httplib.HTTPResponse</span></tt> object.</dd></dl>
+
+<dl class="class">
+<dt id="httplib2.FileCache">
+<em class="property">class </em><tt class="descclassname">httplib2.</tt><tt class="descname">FileCache</tt><big>(</big><em>dir_name</em><span class="optional">[</span>, <em>safe=safename</em><span class="optional">]</span><big>)</big><a class="headerlink" href="#httplib2.FileCache" title="Permalink to this definition">¶</a></dt>
+<dd>FileCache implements a Cache as a directory of files. The <em>dir_name</em> parameter
+is the name of the directory to use. If the directory does not exist then
+FileCache attempts to create the directory. The optional <em>safe</em> parameter is a
+funtion which generates the cache filename for each URI. A FileCache object is
+constructed and used for caching when you pass a directory name into the
+constructor of <a title="httplib2.Http" class="reference internal" href="#httplib2.Http"><tt class="xref docutils literal"><span class="pre">Http</span></tt></a>.</dd></dl>
+
+<p>Http objects have the following methods:</p>
+<div class="section" id="http-objects">
+<span id="id1"></span><h2>Http Objects<a class="headerlink" href="#http-objects" title="Permalink to this headline">¶</a></h2>
+<dl class="method">
+<dt id="httplib2.Http.request">
+<tt class="descclassname">Http.</tt><tt class="descname">request</tt><big>(</big><em>uri</em><span class="optional">[</span>, <em>method=&quot;GET&quot;</em>, <em>body=None</em>, <em>headers=None</em>, <em>redirections=DEFAULT_MAX_REDIRECTS</em>, <em>connection_type=None</em><span class="optional">]</span><big>)</big><a class="headerlink" href="#httplib2.Http.request" title="Permalink to this definition">¶</a></dt>
+<dd><p>Performs a single HTTP request. The <em>uri</em> is the URI of the HTTP resource and
+can begin with either <tt class="docutils literal"><span class="pre">http</span></tt> or <tt class="docutils literal"><span class="pre">https</span></tt>. The value of <em>uri</em> must be an
+absolute URI.</p>
+<p>The <em>method</em> is the HTTP method to perform, such as <tt class="docutils literal"><span class="pre">GET</span></tt>, <tt class="docutils literal"><span class="pre">POST</span></tt>,
+<tt class="docutils literal"><span class="pre">DELETE</span></tt>, etc. There is no restriction on the methods allowed.</p>
+<p>The <em>body</em> is the entity body to be sent with the request. It is a string
+object.</p>
+<p>Any extra headers that are to be sent with the request should be provided in the
+<em>headers</em> dictionary.</p>
+<p>The maximum number of redirect to follow before raising an exception is
+<em>redirections</em>. The default is 5.</p>
+<p>The <em>connection_type</em> is the type of connection object to use. The supplied
+class should implement the interface of httplib.HTTPConnection.</p>
+<p>The return value is a tuple of (response, content), the first being and instance
+of the <a title="httplib2.Response" class="reference internal" href="#httplib2.Response"><tt class="xref docutils literal"><span class="pre">Response</span></tt></a> class, the second being a string that contains the
+response entity body.</p>
+</dd></dl>
+
+<dl class="method">
+<dt id="httplib2.Http.add_credentials">
+<tt class="descclassname">Http.</tt><tt class="descname">add_credentials</tt><big>(</big><em>name</em>, <em>password</em><span class="optional">[</span>, <em>domain=None</em><span class="optional">]</span><big>)</big><a class="headerlink" href="#httplib2.Http.add_credentials" title="Permalink to this definition">¶</a></dt>
+<dd>Adds a name and password that will be used when a request  requires
+authentication. Supplying the optional <em>domain</em> name will restrict these
+credentials to only be sent to the specified domain. If <em>domain</em> is not
+specified then the given credentials will be used to try to satisfy every HTTP
+401 challenge.</dd></dl>
+
+<dl class="method">
+<dt id="httplib2.Http.add_certificate">
+<tt class="descclassname">Http.</tt><tt class="descname">add_certificate</tt><big>(</big><em>key</em>, <em>cert</em>, <em>domain</em><big>)</big><a class="headerlink" href="#httplib2.Http.add_certificate" title="Permalink to this definition">¶</a></dt>
+<dd>Add a <em>key</em> and <em>cert</em> that will be used for an SSL connection to the specified
+domain. <em>keyfile</em> is the name of a PEM formatted  file that contains your
+private key. <em>certfile</em> is a PEM formatted certificate chain file.</dd></dl>
+
+<dl class="method">
+<dt id="httplib2.Http.clear_credentials">
+<tt class="descclassname">Http.</tt><tt class="descname">clear_credentials</tt><big>(</big><big>)</big><a class="headerlink" href="#httplib2.Http.clear_credentials" title="Permalink to this definition">¶</a></dt>
+<dd>Remove all the names and passwords used for authentication.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Http.follow_redirects">
+<tt class="descclassname">Http.</tt><tt class="descname">follow_redirects</tt><a class="headerlink" href="#httplib2.Http.follow_redirects" title="Permalink to this definition">¶</a></dt>
+<dd>If <tt class="xref docutils literal"><span class="pre">True</span></tt>, which is the default, safe redirects are followed, where safe means
+that the client is only doing a <tt class="docutils literal"><span class="pre">GET</span></tt> or <tt class="docutils literal"><span class="pre">HEAD</span></tt> on the URI to which it is
+being redirected. If <tt class="xref docutils literal"><span class="pre">False</span></tt> then no redirects are followed. Note that a False
+&#8216;follow_redirects&#8217; takes precedence over a True &#8216;follow_all_redirects&#8217;. Another
+way of saying that is for &#8216;follow_all_redirects&#8217; to have any affect,
+&#8216;follow_redirects&#8217; must be True.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Http.follow_all_redirects">
+<tt class="descclassname">Http.</tt><tt class="descname">follow_all_redirects</tt><a class="headerlink" href="#httplib2.Http.follow_all_redirects" title="Permalink to this definition">¶</a></dt>
+<dd>If <tt class="xref docutils literal"><span class="pre">False</span></tt>, which is the default, only safe redirects are followed, where safe
+means that the client is only doing a <tt class="docutils literal"><span class="pre">GET</span></tt> or <tt class="docutils literal"><span class="pre">HEAD</span></tt> on the URI to which it
+is being redirected. If <tt class="xref docutils literal"><span class="pre">True</span></tt> then all redirects are followed. Note that a
+False &#8216;follow_redirects&#8217; takes precedence over a True &#8216;follow_all_redirects&#8217;.
+Another way of saying that is for &#8216;follow_all_redirects&#8217; to have any affect,
+&#8216;follow_redirects&#8217; must be True.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Http.forward_authorization_headers">
+<tt class="descclassname">Http.</tt><tt class="descname">forward_authorization_headers</tt><a class="headerlink" href="#httplib2.Http.forward_authorization_headers" title="Permalink to this definition">¶</a></dt>
+<dd>If <tt class="xref docutils literal"><span class="pre">False</span></tt>, which is the default, then Authorization: headers are
+stripped from redirects. If <tt class="xref docutils literal"><span class="pre">True</span></tt> then Authorization: headers are left
+in place when following redirects. This parameter only applies if following
+redirects is turned on. Note that turning this on could cause your credentials
+to leak, so carefully consider the consequences.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Http.force_exception_to_status_code">
+<tt class="descclassname">Http.</tt><tt class="descname">force_exception_to_status_code</tt><a class="headerlink" href="#httplib2.Http.force_exception_to_status_code" title="Permalink to this definition">¶</a></dt>
+<dd><p>If <tt class="xref docutils literal"><span class="pre">True</span></tt> then no <tt class="xref docutils literal"><span class="pre">httplib2</span></tt> exceptions will be
+thrown. Instead, those error conditions will be turned into <a title="httplib2.Response" class="reference internal" href="#httplib2.Response"><tt class="xref docutils literal"><span class="pre">Response</span></tt></a>
+objects that will be returned normally.</p>
+<p>If <tt class="xref docutils literal"><span class="pre">False</span></tt>, which is the default, then exceptions will be thrown.</p>
+</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Http.optimistic_concurrency_methods">
+<tt class="descclassname">Http.</tt><tt class="descname">optimistic_concurrency_methods</tt><a class="headerlink" href="#httplib2.Http.optimistic_concurrency_methods" title="Permalink to this definition">¶</a></dt>
+<dd>By default a list that only contains &#8220;PUT&#8221;, this attribute
+controls which methods will get &#8216;if-match&#8217; headers attached
+to them from cached responses with etags. You can append
+new items to this list to add new methods that should
+get this support, such as &#8220;PATCH&#8221;.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Http.ignore_etag">
+<tt class="descclassname">Http.</tt><tt class="descname">ignore_etag</tt><a class="headerlink" href="#httplib2.Http.ignore_etag" title="Permalink to this definition">¶</a></dt>
+<dd>Defaults to <tt class="xref docutils literal"><span class="pre">False</span></tt>. If <tt class="xref docutils literal"><span class="pre">True</span></tt>, then any etags present in the cached
+response are ignored when processing the current request, i.e. httplib2 does
+<strong>not</strong> use &#8216;if-match&#8217; for PUT or &#8216;if-none-match&#8217; when GET or HEAD requests are
+made. This is mainly to deal with broken servers which supply an etag, but
+change it capriciously.</dd></dl>
+
+<p>If you wish to supply your own caching implementation then you will need to pass
+in an object that supports the  following methods. Note that the <tt class="xref docutils literal"><span class="pre">memcache</span></tt>
+module supports this interface natively.</p>
+</div>
+<div class="section" id="cache-objects">
+<span id="id2"></span><h2>Cache Objects<a class="headerlink" href="#cache-objects" title="Permalink to this headline">¶</a></h2>
+<dl class="method">
+<dt id="httplib2.Cache.get">
+<tt class="descclassname">Cache.</tt><tt class="descname">get</tt><big>(</big><em>key</em><big>)</big><a class="headerlink" href="#httplib2.Cache.get" title="Permalink to this definition">¶</a></dt>
+<dd>Takes a string <em>key</em> and returns the value as a string.</dd></dl>
+
+<dl class="method">
+<dt id="httplib2.Cache.set">
+<tt class="descclassname">Cache.</tt><tt class="descname">set</tt><big>(</big><em>key</em>, <em>value</em><big>)</big><a class="headerlink" href="#httplib2.Cache.set" title="Permalink to this definition">¶</a></dt>
+<dd>Takes a string <em>key</em> and <em>value</em> and stores it in the cache.</dd></dl>
+
+<dl class="method">
+<dt id="httplib2.Cache.delete">
+<tt class="descclassname">Cache.</tt><tt class="descname">delete</tt><big>(</big><em>key</em><big>)</big><a class="headerlink" href="#httplib2.Cache.delete" title="Permalink to this definition">¶</a></dt>
+<dd>Deletes the cached value stored at <em>key</em>. The value of <em>key</em> is a string.</dd></dl>
+
+<p>Response objects are derived from <tt class="xref docutils literal"><span class="pre">dict</span></tt> and map header names (lower case
+with the trailing colon removed) to header values. In addition to the dict
+methods a Response object also has:</p>
+</div>
+<div class="section" id="response-objects">
+<span id="id3"></span><h2>Response Objects<a class="headerlink" href="#response-objects" title="Permalink to this headline">¶</a></h2>
+<dl class="attribute">
+<dt id="httplib2.Response.fromcache">
+<tt class="descclassname">Response.</tt><tt class="descname">fromcache</tt><a class="headerlink" href="#httplib2.Response.fromcache" title="Permalink to this definition">¶</a></dt>
+<dd>If <tt class="docutils literal"><span class="pre">true</span></tt> the the response was returned from the cache.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Response.version">
+<tt class="descclassname">Response.</tt><tt class="descname">version</tt><a class="headerlink" href="#httplib2.Response.version" title="Permalink to this definition">¶</a></dt>
+<dd>The version of HTTP that the server supports. A value of 11 means &#8216;1.1&#8217;.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Response.status">
+<tt class="descclassname">Response.</tt><tt class="descname">status</tt><a class="headerlink" href="#httplib2.Response.status" title="Permalink to this definition">¶</a></dt>
+<dd>The numerical HTTP status code returned in the response.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Response.reason">
+<tt class="descclassname">Response.</tt><tt class="descname">reason</tt><a class="headerlink" href="#httplib2.Response.reason" title="Permalink to this definition">¶</a></dt>
+<dd>The human readable component of the HTTP response status code.</dd></dl>
+
+<dl class="attribute">
+<dt id="httplib2.Response.previous">
+<tt class="descclassname">Response.</tt><tt class="descname">previous</tt><a class="headerlink" href="#httplib2.Response.previous" title="Permalink to this definition">¶</a></dt>
+<dd>If redirects are followed then the <a title="httplib2.Response" class="reference internal" href="#httplib2.Response"><tt class="xref docutils literal"><span class="pre">Response</span></tt></a> object returned is just for
+the very last HTTP request and <em>previous</em> points to the previous
+<a title="httplib2.Response" class="reference internal" href="#httplib2.Response"><tt class="xref docutils literal"><span class="pre">Response</span></tt></a> object. In this manner they form a chain going back through
+the responses to the very first response. Will be <tt class="xref docutils literal"><span class="pre">None</span></tt> if there are no
+previous respones.</dd></dl>
+
+<p>The Response object also populates the header <tt class="docutils literal"><span class="pre">content-location</span></tt>, that
+contains the URI that was ultimately requested. This is useful if redirects were
+encountered, you can determine the ultimate URI that the request was sent to.
+All Response objects contain this key value, including <tt class="docutils literal"><span class="pre">previous</span></tt> responses so
+you can determine the entire chain of redirects. If
+<a title="httplib2.Http.force_exception_to_status_code" class="reference internal" href="#httplib2.Http.force_exception_to_status_code"><tt class="xref docutils literal"><span class="pre">Http.force_exception_to_status_code</span></tt></a> is <tt class="xref docutils literal"><span class="pre">True</span></tt> and the number of
+redirects has exceeded the number of allowed number  of redirects then the
+<a title="httplib2.Response" class="reference internal" href="#httplib2.Response"><tt class="xref docutils literal"><span class="pre">Response</span></tt></a> object will report the error in the status code, but the
+complete chain of previous responses will still be in tact.</p>
+<p>To do a simple <tt class="docutils literal"><span class="pre">GET</span></tt> request just supply the absolute URI of the resource:</p>
+</div>
+<div class="section" id="examples">
+<span id="httplib2-example"></span><h2>Examples<a class="headerlink" href="#examples" title="Permalink to this headline">¶</a></h2>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">httplib2</span>
+<span class="n">h</span> <span class="o">=</span> <span class="n">httplib2</span><span class="o">.</span><span class="n">Http</span><span class="p">()</span>
+<span class="n">resp</span><span class="p">,</span> <span class="n">content</span> <span class="o">=</span> <span class="n">h</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&quot;http://bitworking.org/&quot;</span><span class="p">)</span>
+<span class="k">assert</span> <span class="n">resp</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="mi">200</span>
+<span class="k">assert</span> <span class="n">resp</span><span class="p">[</span><span class="s">&#39;content-type&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&#39;text/html&#39;</span>
+</pre></div>
+</div>
+<p>Here is more complex example that does a PUT  of some text to a resource that
+requires authentication. The Http instance also uses a file cache in the
+directory <tt class="docutils literal"><span class="pre">.cache</span></tt>.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">httplib2</span>
+<span class="n">h</span> <span class="o">=</span> <span class="n">httplib2</span><span class="o">.</span><span class="n">Http</span><span class="p">(</span><span class="s">&quot;.cache&quot;</span><span class="p">)</span>
+<span class="n">h</span><span class="o">.</span><span class="n">add_credentials</span><span class="p">(</span><span class="s">&#39;name&#39;</span><span class="p">,</span> <span class="s">&#39;password&#39;</span><span class="p">)</span>
+<span class="n">resp</span><span class="p">,</span> <span class="n">content</span> <span class="o">=</span> <span class="n">h</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&quot;https://example.org/chap/2&quot;</span><span class="p">,</span>
+    <span class="s">&quot;PUT&quot;</span><span class="p">,</span> <span class="n">body</span><span class="o">=</span><span class="s">&quot;This is text&quot;</span><span class="p">,</span>
+    <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">&#39;content-type&#39;</span><span class="p">:</span><span class="s">&#39;text/plain&#39;</span><span class="p">}</span> <span class="p">)</span>
+</pre></div>
+</div>
+<p>Here is an example that connects to a server that  supports the Atom Publishing
+Protocol.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">httplib2</span>
+<span class="n">h</span> <span class="o">=</span> <span class="n">httplib2</span><span class="o">.</span><span class="n">Http</span><span class="p">()</span>
+<span class="n">h</span><span class="o">.</span><span class="n">add_credentials</span><span class="p">(</span><span class="n">myname</span><span class="p">,</span> <span class="n">mypasswd</span><span class="p">)</span>
+<span class="n">h</span><span class="o">.</span><span class="n">follow_all_redirects</span> <span class="o">=</span> <span class="bp">True</span>
+<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;Content-Type&#39;</span><span class="p">:</span> <span class="s">&#39;application/atom+xml&#39;</span><span class="p">}</span>
+<span class="n">body</span>    <span class="o">=</span> <span class="s">&quot;&quot;&quot;&lt;?xml version=&quot;1.0&quot; ?&gt;</span>
+<span class="s">    &lt;entry xmlns=&quot;http://www.w3.org/2005/Atom&quot;&gt;</span>
+<span class="s">      &lt;title&gt;Atom-Powered Robots Run Amok&lt;/title&gt;</span>
+<span class="s">      &lt;id&gt;urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a&lt;/id&gt;</span>
+<span class="s">      &lt;updated&gt;2003-12-13T18:30:02Z&lt;/updated&gt;</span>
+<span class="s">      &lt;author&gt;&lt;name&gt;John Doe&lt;/name&gt;&lt;/author&gt;</span>
+<span class="s">      &lt;content&gt;Some text.&lt;/content&gt;</span>
+<span class="s">&lt;/entry&gt;</span>
+<span class="s">&quot;&quot;&quot;</span>
+<span class="n">uri</span>     <span class="o">=</span> <span class="s">&quot;http://www.example.com/collection/&quot;</span>
+<span class="n">resp</span><span class="p">,</span> <span class="n">content</span> <span class="o">=</span> <span class="n">h</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="n">uri</span><span class="p">,</span> <span class="s">&quot;POST&quot;</span><span class="p">,</span> <span class="n">body</span><span class="o">=</span><span class="n">body</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
+</pre></div>
+</div>
+<p>Here is an example of providing data to an HTML form processor. In this case we
+presume this is a POST form. We need to take our  data and format it as
+&#8220;application/x-www-form-urlencoded&#8221; data and use that as a  body for a POST
+request.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">httplib2</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">urllib</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;name&#39;</span><span class="p">:</span> <span class="s">&#39;fred&#39;</span><span class="p">,</span> <span class="s">&#39;address&#39;</span><span class="p">:</span> <span class="s">&#39;123 shady lane&#39;</span><span class="p">}</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">body</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">body</span>
+<span class="go">&#39;name=fred&amp;address=123+shady+lane&#39;</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">h</span> <span class="o">=</span> <span class="n">httplib2</span><span class="o">.</span><span class="n">Http</span><span class="p">()</span>
+<span class="gp">&gt;&gt;&gt; </span><span class="n">resp</span><span class="p">,</span> <span class="n">content</span> <span class="o">=</span> <span class="n">h</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&quot;http://example.com&quot;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&quot;POST&quot;</span><span class="p">,</span> <span class="n">body</span><span class="o">=</span><span class="n">body</span><span class="p">)</span>
+</pre></div>
+</div>
+</div>
+</div>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+            <h3><a href="index.html">Table Of Contents</a></h3>
+            <ul>
+<li><a class="reference external" href="#"><tt class="docutils literal"><span class="pre">httplib2</span></tt>  A comprehensive HTTP client library.</a><ul>
+<li><a class="reference external" href="#http-objects">Http Objects</a></li>
+<li><a class="reference external" href="#cache-objects">Cache Objects</a></li>
+<li><a class="reference external" href="#response-objects">Response Objects</a></li>
+<li><a class="reference external" href="#examples">Examples</a></li>
+</ul>
+</li>
+</ul>
+
+            <h4>Previous topic</h4>
+            <p class="topless"><a href="index.html"
+                                  title="previous chapter">The httplib2 Library</a></p>
+            <h3>This Page</h3>
+            <ul class="this-page-menu">
+              <li><a href="_sources/libhttplib2.txt"
+                     rel="nofollow">Show Source</a></li>
+            </ul>
+          <div id="searchbox" style="display: none">
+            <h3>Quick search</h3>
+              <form class="search" action="search.html" method="get">
+                <input type="text" name="q" size="18" />
+                <input type="submit" value="Go" />
+                <input type="hidden" name="check_keywords" value="yes" />
+                <input type="hidden" name="area" value="default" />
+              </form>
+              <p class="searchtip" style="font-size: 90%">
+              Enter search terms or a module, class or function name.
+              </p>
+          </div>
+          <script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             >modules</a> |</li>
+        <li class="right" >
+          <a href="index.html" title="The httplib2 Library"
+             >previous</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+    <div class="footer">
+      &copy; Copyright 2008, Joe Gregorio.
+      Last updated on Aug 28, 2012.
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
+    </div>
+  </body>
+</html>
diff --git a/doc/html/modindex.html b/doc/html/modindex.html
new file mode 100644
index 0000000..6c086f9
--- /dev/null
+++ b/doc/html/modindex.html
@@ -0,0 +1,104 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+    <title>Global Module Index &mdash; httplib2 v0.4 documentation</title>
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    '#',
+        VERSION:     '0.4',
+        COLLAPSE_MODINDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <link rel="top" title="httplib2 v0.4 documentation" href="index.html" />
+
+
+    <script type="text/javascript">
+      DOCUMENTATION_OPTIONS.COLLAPSE_MODINDEX = true;
+    </script>
+
+
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li class="right" >
+          <a href="#" title="Global Module Index"
+             accesskey="M">modules</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+
+
+   <h1 id="global-module-index">Global Module Index</h1>
+   <a href="#cap-H"><strong>H</strong></a>
+   <hr/>
+
+   <table width="100%" class="indextable" cellspacing="0" cellpadding="2"><tr class="pcap"><td></td><td>&nbsp;</td><td></td></tr>
+   <tr class="cap"><td></td><td><a name="cap-H"><strong>H</strong></a></td><td></td></tr><tr>
+     <td></td>
+     <td>
+     <a href="libhttplib2.html#module-httplib2"><tt class="xref">httplib2</tt></a></td><td>
+     <em></em></td></tr>
+   </table>
+
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+          <div id="searchbox" style="display: none">
+            <h3>Quick search</h3>
+              <form class="search" action="search.html" method="get">
+                <input type="text" name="q" size="18" />
+                <input type="submit" value="Go" />
+                <input type="hidden" name="check_keywords" value="yes" />
+                <input type="hidden" name="area" value="default" />
+              </form>
+              <p class="searchtip" style="font-size: 90%">
+              Enter search terms or a module, class or function name.
+              </p>
+          </div>
+          <script type="text/javascript">$('#searchbox').show(0);</script>
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li class="right" >
+          <a href="#" title="Global Module Index"
+             >modules</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+    <div class="footer">
+      &copy; Copyright 2008, Joe Gregorio.
+      Last updated on Aug 28, 2012.
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
+    </div>
+  </body>
+</html>
diff --git a/doc/html/objects.inv b/doc/html/objects.inv
new file mode 100644
index 0000000..4f1fd85
--- /dev/null
+++ b/doc/html/objects.inv
@@ -0,0 +1,36 @@
+# Sphinx inventory version 1
+# Project: httplib2
+# Version: 0.4
+httplib2 mod libhttplib2.html
+httplib2.ProxyInfo class libhttplib2.html
+httplib2.Cache.set method libhttplib2.html
+httplib2.Http class libhttplib2.html
+httplib2.Cache.delete method libhttplib2.html
+httplib2.Http.follow_all_redirects attribute libhttplib2.html
+httplib2.RelativeURIError exception libhttplib2.html
+httplib2.Http.follow_redirects attribute libhttplib2.html
+httplib2.RETRIES data libhttplib2.html
+httplib2.debuglevel data libhttplib2.html
+httplib2.FileCache class libhttplib2.html
+httplib2.RedirectMissingLocation exception libhttplib2.html
+httplib2.Http.add_certificate method libhttplib2.html
+httplib2.Http.add_credentials method libhttplib2.html
+httplib2.Response.reason attribute libhttplib2.html
+httplib2.Http.clear_credentials method libhttplib2.html
+httplib2.Cache.get method libhttplib2.html
+httplib2.Http.forward_authorization_headers attribute libhttplib2.html
+httplib2.Http.optimistic_concurrency_methods attribute libhttplib2.html
+httplib2.RedirectLimit exception libhttplib2.html
+httplib2.ServerNotFoundError exception libhttplib2.html
+httplib2.Response class libhttplib2.html
+httplib2.Http.request method libhttplib2.html
+httplib2.Http.force_exception_to_status_code attribute libhttplib2.html
+httplib2.HttpLib2Error exception libhttplib2.html
+httplib2.Response.fromcache attribute libhttplib2.html
+httplib2.UnimplementedHmacDigestAuthOptionError exception libhttplib2.html
+httplib2.Http.ignore_etag attribute libhttplib2.html
+httplib2.UnimplementedDigestAuthOptionError exception libhttplib2.html
+httplib2.FailedToDecompressContent exception libhttplib2.html
+httplib2.Response.status attribute libhttplib2.html
+httplib2.Response.version attribute libhttplib2.html
+httplib2.Response.previous attribute libhttplib2.html
diff --git a/doc/html/search.html b/doc/html/search.html
new file mode 100644
index 0000000..4bb501f
--- /dev/null
+++ b/doc/html/search.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+
+    <title>Search &mdash; httplib2 v0.4 documentation</title>
+    <link rel="stylesheet" href="_static/default.css" type="text/css" />
+    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
+    <script type="text/javascript">
+      var DOCUMENTATION_OPTIONS = {
+        URL_ROOT:    '#',
+        VERSION:     '0.4',
+        COLLAPSE_MODINDEX: false,
+        FILE_SUFFIX: '.html',
+        HAS_SOURCE:  true
+      };
+    </script>
+    <script type="text/javascript" src="_static/jquery.js"></script>
+    <script type="text/javascript" src="_static/doctools.js"></script>
+    <script type="text/javascript" src="_static/searchtools.js"></script>
+    <link rel="top" title="httplib2 v0.4 documentation" href="index.html" />
+  </head>
+  <body>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             accesskey="I">index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             accesskey="M">modules</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+
+    <div class="document">
+      <div class="documentwrapper">
+        <div class="bodywrapper">
+          <div class="body">
+
+  <h1 id="search-documentation">Search</h1>
+  <div id="fallback" class="admonition warning">
+  <script type="text/javascript">$('#fallback').hide();</script>
+  <p>
+    Please activate JavaScript to enable the search
+    functionality.
+  </p>
+  </div>
+  <p>
+    From here you can search these documents. Enter your search
+    words into the box below and click "search". Note that the search
+    function will automatically search for all of the words. Pages
+    containing fewer words won't appear in the result list.
+  </p>
+  <form action="" method="get">
+    <input type="text" name="q" value="" />
+    <input type="submit" value="search" />
+    <span id="search-progress" style="padding-left: 10px"></span>
+  </form>
+
+  <div id="search-results">
+
+  </div>
+
+          </div>
+        </div>
+      </div>
+      <div class="sphinxsidebar">
+        <div class="sphinxsidebarwrapper">
+        </div>
+      </div>
+      <div class="clearer"></div>
+    </div>
+    <div class="related">
+      <h3>Navigation</h3>
+      <ul>
+        <li class="right" style="margin-right: 10px">
+          <a href="genindex.html" title="General Index"
+             >index</a></li>
+        <li class="right" >
+          <a href="modindex.html" title="Global Module Index"
+             >modules</a> |</li>
+        <li><a href="index.html">httplib2 v0.4 documentation</a> &raquo;</li>
+      </ul>
+    </div>
+
+    <div class="footer">
+      &copy; Copyright 2008, Joe Gregorio.
+      Last updated on Aug 28, 2012.
+      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.4.
+    </div>
+  <script type="text/javascript" src="searchindex.js"></script>
+
+  </body>
+</html>
diff --git a/doc/html/searchindex.js b/doc/html/searchindex.js
new file mode 100644
index 0000000..faf351f
--- /dev/null
+++ b/doc/html/searchindex.js
@@ -0,0 +1 @@
+Search.setIndex({desctypes:{"0":"class","1":"method","2":"attribute","3":"exception","4":"data"},terms:{all:1,code:1,chain:1,proxy_type_xxx:1,follow:1,privat:1,readabl:1,those:1,sent:1,liter:1,everi:1,string:1,fals:1,unfamiliar:1,proxy_typ:1,veri:1,affect:1,tri:1,force_exception_to_status_cod:1,level:1,list:1,"try":1,item:1,consequ:1,second:1,pass:1,"13t18":1,append:1,index:0,section:1,current:1,delet:1,version:1,"new":1,method:1,funtion:1,redirect:[0,1],deriv:1,gener:1,here:1,bodi:1,proxy_us:1,address:1,redirectmissingloc:1,ignore_etag:1,modifi:1,valu:1,search:0,respon:1,proxy_rdn:1,memcach:1,amount:1,implement:1,extra:1,appli:1,modul:[0,1],keyfil:1,filenam:1,"boolean":1,from:1,call:1,type:1,more:1,flat:1,trail:1,flag:1,cach:[0,1],must:1,none:1,hmacdigest:1,optimistic_concurrency_method:1,unimplementedhmacdigestauthoptionerror:1,can:1,aliv:[0,1],control:1,claim:1,process:1,challeng:1,indic:[0,1],aaaa:1,occur:1,multipl:1,anoth:1,instead:1,simpl:1,updat:1,follow_redirect:1,mar:0,resourc:1,proxy_info:1,tact:1,befor:1,date:0,httpconnect:1,data:1,unreserv:1,attempt:1,ssl:1,credenti:1,robot:1,caus:1,inform:1,preced:1,allow:1,shadi:1,over:1,"3xx":1,through:1,still:1,mainli:1,digest:1,paramet:1,uuid:1,complex:1,comprehens:[0,1],them:1,failedtodecompresscont:1,"return":1,thei:1,handl:[0,1],safe:1,httplib2:[0,1],gregorio:0,"80da344efa6a":1,httplib:1,name:1,authent:[0,1],timeout:1,each:1,debug:1,mean:1,compil:1,domain:1,map:1,connect:1,our:1,variabl:1,proxy_pass:1,urlencod:1,publish:1,content:[0,1],etag:1,rel:1,debuglevel:1,print:1,proxi:1,fred:1,reason:1,base:1,dictionari:1,put:1,org:1,thrown:1,could:1,keep:[0,1],turn:1,place:1,unabl:1,caprici:1,first:1,oper:1,certfil:1,number:1,restrict:1,mai:1,alreadi:1,done:1,messag:1,oppos:1,open:1,given:1,disable_ssl_certificate_valid:1,construct:1,attach:1,john:1,"final":1,store:1,xmln:1,option:1,specifi:1,cfb8:1,httplib2error:1,kind:0,provid:1,remov:1,proxy_type_http:1,were:1,pre:1,sai:1,ani:1,manner:1,have:1,tabl:0,mypasswd:1,note:1,also:1,client:[0,1],take:1,which:1,singl:1,begin:1,ca_cert:1,normal:1,object:[0,1],compress:[0,1],gzip:1,"class":1,urn:1,request:1,uri:1,doe:1,determin:1,carefulli:1,text:1,unimplementeddigestauthoptionerror:1,xml:1,absolut:1,onli:1,locat:1,should:1,dict:1,bitwork:1,get:1,filecach:1,nativ:1,report:1,requir:1,patch:1,contain:1,mynam:1,where:1,certif:1,set:1,see:1,respons:[0,1],fail:1,statu:1,detect:1,urllib:1,"import":1,"02z":1,attribut:1,kei:1,numer:1,proxy_port:1,entir:1,joe:0,come:1,addit:1,both:1,last:1,etc:1,instanc:1,mani:0,com:1,point:1,header:1,colon:1,suppli:1,ultim:1,three:1,compon:1,basic:1,popul:1,wish:1,assert:1,understand:1,present:1,"case":1,plain:1,defin:1,error:1,"4ebb":1,dir_nam:1,applic:1,need:1,follow_all_redirect:1,author:[0,1],perform:1,satisfi:1,cert:1,same:1,add_certif:1,html:1,complet:1,http:[0,1],rfc822:1,decompress:1,rais:1,chang:1,lower:1,entri:1,without:1,exampl:[0,1],add_credenti:1,thi:1,entiti:1,left:1,protocol:1,just:1,resp:1,human:1,password:1,proxy_host:1,except:1,proxyinfo:1,add:1,from_environ:1,match:1,connection_typ:1,format:1,safenam:1,httprespons:1,you:1,amok:1,redirectlimit:1,lost:1,servernotfounderror:1,docutil:1,resolv:1,server:1,collect:1,either:1,page:0,encount:1,exceed:1,deal:1,some:1,back:1,librari:[0,1],clear_credenti:1,leak:1,subclass:1,pem:1,retri:1,condit:1,localhost:1,previou:1,run:1,power:1,reach:1,broken:1,host:1,post:1,deflat:1,socket:1,default_max_redirect:1,fromcach:1,constructor:1,processor:1,own:1,www:1,automat:1,strip:1,your:1,span:1,wai:1,support:1,sock:1,avail:1,interfac:1,includ:1,head:1,form:1,tupl:1,atom:1,"true":1,info:1,made:1,possibl:1,"default":1,checkout:1,maximum:1,forward_authorization_head:1,problem:1,"1225c695":1,featur:1,constant:1,creat:1,"abstract":0,repres:1,chap:1,exist:1,file:1,relativeurierror:1,titl:1,when:1,valid:1,presum:1,consid:1,lane:1,algorithm:1,directori:1,wsse:1,ignor:1,time:1},titles:["The httplib2 Library","<tt class=\"docutils literal docutils literal\"><span class=\"pre\">httplib2</span></tt>  A comprehensive HTTP client library."],modules:{httplib2:1},descrefs:{"httplib2.Response":{status:[1,2],reason:[1,2],version:[1,2],previous:[1,2],fromcache:[1,2]},"httplib2.Cache":{get:[1,1],set:[1,1],"delete":[1,1]},"httplib2.Http":{forward_authorization_headers:[1,2],follow_redirects:[1,2],request:[1,1],force_exception_to_status_code:[1,2],clear_credentials:[1,1],optimistic_concurrency_methods:[1,2],follow_all_redirects:[1,2],add_certificate:[1,1],ignore_etag:[1,2],add_credentials:[1,1]},httplib2:{HttpLib2Error:[1,3],RETRIES:[1,4],Http:[1,0],FileCache:[1,0],UnimplementedHmacDigestAuthOptionError:[1,3],FailedToDecompressContent:[1,3],Response:[1,0],ServerNotFoundError:[1,3],RedirectMissingLocation:[1,3],debuglevel:[1,4],RedirectLimit:[1,3],RelativeURIError:[1,3],ProxyInfo:[1,0],UnimplementedDigestAuthOptionError:[1,3]}},filenames:["index","libhttplib2"]})
\ No newline at end of file
diff --git a/doc/html/searchindex.json b/doc/html/searchindex.json
new file mode 100755
index 0000000..4342f48
--- /dev/null
+++ b/doc/html/searchindex.json
@@ -0,0 +1 @@
+[["index","libhttplib2"],["The httplib2 Library","<tt class=\"docutils literal docutils literal\"><span class=\"pre\">httplib2</span></tt>  A comprehensive HTTP client library."],{"all":[1],"code":[1],"chain":[1],"suno":[1],"go":[1],"follow":[1],"privat":[1],"tt":[1],"readabl":[1],"to":[0,1],"those":[1],"sent":[1],"liter":[1],"everi":[1],"string":[1],"fals":[1],"unfamiliar":[1],"veri":[1],"affect":[1],"force_exception_to_status_cod":[1],"level":[1],"list":[1],"try":[1],"item":[1],"refer":[1],"pleas":[1],"impli":[1],"direct":[0],"tex":[1],"second":[1],"pass":[1],"13t18":[1],"append":[1],"even":[1],"index":[0,1],"what":[1],"section":[1],"current":[1],"delet":[1],"version":[1],"new":[1],"public":[1],"funtion":[1],"redirect":[0,1],"deriv":[1],"gener":[1],"here":[1],"bodi":[1],"address":[1],"redirectmissingloc":[1],"ignore_etag":[1],"standard":[1],"modifi":[1],"valu":[1],"refmodindex":[1],"search":[0],"respon":[1],"30":[1],"memcach":[1],"portabl":[1],"amount":[1],"excdesc":[1],"implement":[1],"macintosh":[1],"extra":[1],"appli":[1],"modul":[0,1],"keyfil":[1],"filenam":[1],"unix":[1],"kei":[1],"from":[1],"describ":[1],"0":[0,1],"mydir":[1],"by":[0,1],"massag":[1],"call":[1],"type":[1],"more":[1],"flat":[1],"python":[1],"trail":[1],"indic":[0,1],"known":[1],"cach":[0,1],"must":[1],"none":[1],"hmacdigest":[1],"optimistic_concurrency_method":[1],"unimplementedhmacdigestauthoptionerror":[1],"can":[0,1],"root":[0],"aliv":[0,1],"uncom":[1],"control":[1],"claim":[1],"quickstart":[0],"give":[1],"process":[1],"challeng":[1],"templat":[1],"aaaa":[1],"sourc":[1],"onlin":[1],"phrase":[1],"occur":[1],"multipl":[1],"hoc":[1],"anoth":[1],"1":[1],"instead":[1],"simpl":[1],"unabl":[1],"map":[1],"mar":[0],"resourc":[1],"after":[1],"tact":[1],"befor":[1],"mac":[1],"date":[0],"such":[1],"underscor":[1],"data":[1],"unreserv":[1],"a":[0,1],"short":[1],"attempt":[1],"ssl":[1],"credenti":[1],"robot":[1],"or":[1],"inform":[1],"preced":[1],"so":[1],"allow":[1],"shadi":[1],"over":[1],"becaus":[1],"3xx":[1],"through":[1],"still":[1],"mainli":[1],"digest":[1],"paramet":[1],"27":[0],"uuid":[1],"platform":[1],"window":[1],"html":[1],"401":[1],"comprehens":[0,1],"then":[1],"them":[1],"failedtodecompresscont":[1],"return":[1],"thei":[1],"handl":[0,1],"safe":[1],"mention":[1],"httplib2":[0,1],"not":[1],"now":[1],"gregorio":[0],"80da344efa6a":[1],"httplib":[1],"name":[1],"edit":[1],"authent":[0,1],"separ":[1],"timeout":[1],"each":[1],"debug":[1],"found":[1],"updat":[1],"mean":[1],"compil":[1],"domain":[1],"follow_redirect":[1],"meta":[1],"connect":[1],"our":[1],"variabl":[1],"urlencod":[1],"publish":[1],"content":[0,1],"method":[1],"etag":[1],"adapt":[0],"rel":[1],"debuglevel":[1],"print":[1],"fred":[1],"reason":[1],"base":[1],"dictionari":[1],"put":[1],"org":[1],"thrown":[1],"omit":[1],"keep":[0,1],"turn":[1],"isn":[1],"principl":[1],"caprici":[1],"first":[1],"oper":[1],"there":[1],"certfil":[1],"directli":[1],"onc":[1],"number":[1],"restrict":[1],"mai":[1],"instruct":[1],"alreadi":[1],"least":[0,1],"blank":[1],"oppos":[1],"open":[1],"given":[1],"sometim":[1],"messag":[1],"attach":[1],"2":[1],"master":[0],"statement":[1],"john":[1],"final":[1],"store":[1],"xmln":[1],"option":[1],"that":[0,1],"tool":[1],"copi":[1],"specifi":[1],"cfb8":[1],"part":[1],"checkout":[1],"than":[1],"httplib2error":[1],"kind":[0],"12":[1],"14":[0],"16":[0],"provid":[1],"remov":[1],"were":[1],"markup":[1],"pre":[1],"sai":[1],"arg":[1],"argument":[1],"manner":[1],"have":[1],"tabl":[0],"need":[1],"classdesc":[1],"built":[1],"lib":[1],"client":[0,1],"note":[1],"also":[1],"without":[1],"take":[1],"which":[1],"environ":[1],"singl":[1],"simplifi":[1],"begin":[1],"normal":[1],"object":[0,1],"reach":[1],"class":[1],"07":[0],"latex":[1],"doc":[1],"urn":[1],"request":[1],"uri":[1],"doe":[1],"determin":[1],"text":[1],"unimplementeddigestauthoptionerror":[1],"xml":[1],"absolut":[1],"onli":[1],"locat":[1],"modnam":[1],"with":[1],"written":[1],"should":[0,1],"dict":[1],"8":[0],"do":[1],"bitwork":[1],"get":[1],"filecach":[1],"nativ":[1],"123":[1],"report":[1],"requir":[1],"h":[1],"whenev":[1],"patch":[1],"stuff":[1],"contain":[0,1],"x":[1],"attribut":[1],"where":[1],"certif":[1],"set":[1],"we":[1],"see":[1],"w3":[1],"respons":[0,1],"fail":[1],"statu":[1],"detect":[1],"wa":[1],"urllib":[1],"3":[1],"import":[1],"entiti":[1],"mynam":[1],"altern":[1],"accord":[1],"extend":[1],"numer":[1],"entir":[1],"joe":[0],"come":[1],"addit":[1],"both":[1],"c":[1],"last":[1],"etc":[1],"s":[1],"instanc":[1],"mani":[0],"com":[1],"comment":[1],"and":[0,1],"point":[1],"overview":[1],"header":[1],"colon":[1],"prologu":[1],"ultim":[1],"three":[1],"been":[1],"compon":[1],"basic":[1],"popul":[1],"4":[0,1],"ani":[1],"assert":[1],"understand":[1],"an":[1],"present":[1],"case":[1],"these":[1],"plain":[1],"as":[1],"will":[1],"defin":[1],"error":[1],"02z":[1],"4ebb":[1],"subsect":[1],"dir_nam":[1],"fill":[1],"is":[0,1],"it":[0,1],"mypasswd":[1],"good":[1],"follow_all_redirect":[1],"in":[1],"id":[1],"if":[1],"author":[0,1],"perform":[1],"insofar":[1],"satisfi":[1],"cert":[1],"same":[1],"member":[1],"add_certif":[1],"complex":[1],"document":[0,1],"complet":[0,1],"http":[0,1],"rfc822":[1],"mytyp":[1],"decompress":[1],"rais":[1],"user":[1],"chang":[1],"lower":[1],"appropri":[1],"i":[1],"entri":[1],"thu":[0],"exampl":[0,1],"add_credenti":[1],"thi":[0,1],"choos":[1],"gzip":[1],"the":[0,1],"refstmodindex":[1],"construct":[1],"protocol":[1],"declaremodul":[1],"just":[1],"resp":[1],"human":[1],"flavor":[1],"httprespons":[1],"except":[1],"add":[1],"valid":[1],"funcdesc":[1],"match":[1],"applic":[1],"format":[1],"safenam":[1],"password":[1],"you":[0,1],"connection_typ":[1],"redirectlimit":[1],"like":[0,1],"specif":[1],"servernotfounderror":[1],"docutil":[1],"manual":[1],"resolv":[1],"server":[1],"collect":[1],"either":[1],"amok":[1],"page":[0],"encount":[1],"www":[1],"deal":[1],"200":[1],"suppli":[1],"some":[1],"back":[1],"mod_nam":[1],"toctre":[0],"datadesc":[1],"librari":[0,1],"clear_credenti":[1],"for":[1],"subclass":[1],"pem":[1],"leav":[1],"condit":[1],"t":[1],"be":[1],"previou":[1],"run":[1],"power":[1],"compress":[0,1],"broken":[1],"host":[1],"refbimodindex":[1],"post":[1],"refexmodindex":[1],"on":[0,1],"deflat":[1],"socket":[1],"of":[0,1],"irix":[1],"default_max_redirect":[1],"fromcach":[1],"constructor":[1],"produc":[1],"block":[1],"own":[1],"into":[1],"exceed":[1],"automat":[1],"your":[0,1],"processor":[1],"span":[1],"wai":[1],"support":[1],"memberdesc":[1],"avail":[1],"lost":[1],"interfac":[1],"includ":[1],"lot":[1],"function":[1],"head":[1],"form":[1],"tupl":[1],"but":[0,1],"atom":[1],"sphinx":[0],"line":[1],"ha":[1],"true":[1],"info":[1],"made":[1],"possibl":[1],"default":[1],"wish":[1],"maximum":[1],"us":[1],"below":[1],"problem":[1],"1225c695":[1],"httpconnect":[1],"featur":[1],"ad":[1],"creat":[0,1],"abstract":[0],"repres":[1],"chap":[1],"ar":[1],"exist":[1],"at":[0,1],"file":[0,1],"relativeurierror":[1],"methoddesc":[1],"probabl":[1],"11":[1],"no":[1],"titl":[1],"when":[1],"detail":[1],"other":[1],"5":[1],"presum":[1],"time":[1],"mymodul":[1],"lane":[1],"e":[1],"algorithm":[1],"directori":[1],"2003":[1],"wsse":[1],"ignor":[1],"2007":[0],"2005":[1],"2008":[0]}]
\ No newline at end of file
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100755
index 0000000..c435cab
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,35 @@
+.. httplib2 documentation master file, created by sphinx-quickstart on Thu Mar 27 16:07:14 2008.

+   You can adapt this file completely to your liking, but it should at least

+   contain the root `toctree` directive.

+

+************************

+  The httplib2 Library  

+************************

+

+:Author: Joe Gregorio

+

+:Date: Mar 8, 2007

+

+.. |release| replace:: 0.4

+

+

+.. topic:: Abstract

+

+   The :mod:`httplib2` module is a comprehensive HTTP client library that handles

+   caching, keep-alive, compression, redirects and many kinds of authentication.

+

+

+Contents:

+

+.. toctree::

+   :maxdepth: 2

+

+   libhttplib2.rst

+

+Indices and tables

+==================

+

+* :ref:`genindex`

+* :ref:`modindex`

+* :ref:`search`

+

diff --git a/doc/libhttplib2.rst b/doc/libhttplib2.rst
new file mode 100644
index 0000000..a407bfe
--- /dev/null
+++ b/doc/libhttplib2.rst
@@ -0,0 +1,483 @@
+.. % Template for a library manual section.
+.. % PLEASE REMOVE THE COMMENTS AFTER USING THE TEMPLATE
+.. %
+.. % Complete documentation on the extended LaTeX markup used for Python
+.. % documentation is available in ``Documenting Python'', which is part
+.. % of the standard documentation for Python.  It may be found online
+.. % at:
+.. %
+.. % http://www.python.org/doc/current/doc/doc.html
+.. % ==== 0. ====
+.. % Copy this file to <mydir>/lib<mymodule>.tex, and edit that file
+.. % according to the instructions below.
+
+.. % ==== 1. ====
+.. % The section prologue.  Give the section a title and provide some
+.. % meta-information.  References to the module should use
+.. % \refbimodindex, \refstmodindex, \refexmodindex or \refmodindex, as
+.. % appropriate.
+
+
+:mod:`httplib2`  A comprehensive HTTP client library.
+=====================================================
+
+.. module:: httplib2
+.. moduleauthor:: Joe Gregorio <joe@bitworking.org>
+.. sectionauthor:: Joe Gregorio <joe@bitworking.org>
+
+
+.. % Choose one of these to specify the module module name.  If there's
+.. % an underscore in the name, use
+.. % \declaremodule[modname]{...}{mod_name} instead.
+.. %
+.. % not standard, in Python
+.. % Portability statement:  Uncomment and fill in the parameter to specify the
+.. % availability of the module.  The parameter can be Unix, IRIX, SunOS, Mac,
+.. % Windows, or lots of other stuff.  When ``Mac'' is specified, the availability
+.. % statement will say ``Macintosh'' and the Module Index may say ``Mac''.
+.. % Please use a name that has already been used whenever applicable.  If this
+.. % is omitted, no availability statement is produced or implied.
+.. %
+.. % \platform{Unix}
+.. % These apply to all modules, and may be given more than once:
+.. % Author of the module code;
+.. % omit if not known.
+.. % Author of the documentation,
+.. % even if not a module section.
+
+
+
+.. % Leave at least one blank line after this, to simplify ad-hoc tools
+.. % that are sometimes used to massage these files.
+
+The :mod:`httplib2` module is a comprehensive HTTP client library with the
+following features:
+
+.. % ==== 2. ====
+.. % Give a short overview of what the module does.
+.. % If it is platform specific, mention this.
+.. % Mention other important restrictions or general operating principles.
+.. % For example:
+
+.. describe:: HTTP and HTTPS
+
+   HTTPS support is only available if the socket module was compiled with SSL
+   support.
+
+.. describe:: Keep-Alive
+
+   Supports HTTP 1.1 Keep-Alive, keeping the socket open and performing multiple
+   requests over the same connection if possible.
+
+.. describe:: Authentication
+
+   The following three types of HTTP Authentication are supported. These can be
+   used over both HTTP and HTTPS.
+
+      * Digest
+      * Basic
+      * WSSE
+
+.. describe:: Caching
+
+   The module can optionally operate with a private cache that understands the
+   Cache-Control: header and uses both the ETag and Last-Modified cache validators.
+
+.. describe:: All Methods
+
+   The module can handle any HTTP request method, not just GET and POST.
+
+.. describe:: Redirects
+
+   Automatically follows 3XX redirects on GETs.
+
+.. describe:: Compression
+
+   Handles both ``deflate`` and ``gzip`` types of compression.
+
+.. describe:: Lost update support
+
+   Automatically adds back ETags into PUT requests to resources we have already
+   cached. This implements Section 3.2 of Detecting the Lost Update Problem Using
+   Unreserved Checkout
+
+The :mod:`httplib2` module defines the following variables:
+
+.. % ==== 3. ====
+.. % List the public functions defined by the module.  Begin with a
+.. % standard phrase.  You may also list the exceptions and other data
+.. % items defined in the module, insofar as they are important for the
+.. % user.
+.. % ---- 3.2. ----
+.. % Data items are described using a ``datadesc'' block.  This has only
+.. % one parameter: the item's name.
+
+
+.. data:: debuglevel
+
+   The amount of debugging information to print. The default is 0.
+
+
+.. data:: RETRIES
+
+   A request will be tried 'RETRIES' times if it fails at the socket/connection level.
+   The default is 2.
+
+The :mod:`httplib2` module may raise the following Exceptions. Note that  there
+is an option that turns exceptions into  normal responses with an HTTP status
+code indicating an error occured. See
+:attr:`Http.force_exception_to_status_code`
+
+.. % --- 3.3. ---
+.. % Exceptions are described using a ``excdesc'' block.  This has only
+.. % one parameter: the exception name.  Exceptions defined as classes in
+.. % the source code should be documented using this environment, but
+.. % constructor parameters must be omitted.
+
+
+.. exception:: HttpLib2Error
+
+   The Base Exception for all exceptions raised by httplib2.
+
+
+.. exception:: RedirectMissingLocation
+
+   A 3xx redirect response code was provided but no Location: header  was provided
+   to point to the new location.
+
+
+.. exception:: RedirectLimit
+
+   The maximum number of redirections was reached without coming to a final URI.
+
+
+.. exception:: ServerNotFoundError
+
+   Unable to resolve the host name given.
+
+
+.. exception:: RelativeURIError
+
+   A relative, as opposed to an absolute URI, was passed into request().
+
+
+.. exception:: FailedToDecompressContent
+
+   The headers claimed that the content of the response was compressed but the
+   decompression algorithm applied to the content failed.
+
+
+.. exception:: UnimplementedDigestAuthOptionError
+
+   The server requested a type of Digest authentication that we are unfamiliar
+   with.
+
+
+.. exception:: UnimplementedHmacDigestAuthOptionError
+
+   The server requested a type of HMACDigest authentication that we are unfamiliar
+   with.
+
+.. % ---- 3.4. ----
+.. % Other standard environments:
+.. %
+.. % classdesc  - Python classes; same arguments are funcdesc
+.. % methoddesc - methods, like funcdesc but has an optional parameter
+.. % to give the type name: \begin{methoddesc}[mytype]{name}{args}
+.. % By default, the type name will be the name of the
+.. % last class defined using classdesc.  The type name
+.. % is required if the type is implemented in C (because
+.. % there's no classdesc) or if the class isn't directly
+.. % documented (if it's private).
+.. % memberdesc - data members, like datadesc, but with an optional
+.. % type name like methoddesc.
+
+
+.. class:: Http([cache=None], [timeout=None], [proxy_info==ProxyInfo.from_environment], [ca_certs=None], [disable_ssl_certificate_validation=False])
+
+   The class that represents a client HTTP interface. The *cache* parameter is
+   either the name of a directory to be used as a flat file cache, or it must an
+   object that  implements the required caching interface. The *timeout* parameter
+   is the socket level timeout. The *ca_certs* parameter is the filename of the
+   CA certificates to use. If none is given a default set is used. The
+   *disable_ssl_certificate_validation* boolean flag determines if ssl certificate validation
+   is done. The *proxy_info* parameter is an object of type :class:ProxyInfo.
+
+
+.. class:: ProxyInfo(proxy_type, proxy_host, proxy_port, [proxy_rdns=None], [proxy_user=None], [proxy_pass=None])
+
+   Collect information required to use a proxy.
+   The parameter proxy_type must be set to one of socks.PROXY_TYPE_XXX
+   constants. For example: ::
+
+   p = ProxyInfo(proxy_type=socks.PROXY_TYPE_HTTP, proxy_host='localhost', proxy_port=8000)
+
+.. class:: Response(info)
+
+   Response is a subclass of :class:`dict` and instances of this  class are
+   returned from calls to Http.request. The *info* parameter is either  an
+   :class:`rfc822.Message` or an :class:`httplib.HTTPResponse` object.
+
+
+.. class:: FileCache(dir_name, [safe=safename])
+
+   FileCache implements a Cache as a directory of files. The *dir_name* parameter
+   is the name of the directory to use. If the directory does not exist then
+   FileCache attempts to create the directory. The optional *safe* parameter is a
+   funtion which generates the cache filename for each URI. A FileCache object is
+   constructed and used for caching when you pass a directory name into the
+   constructor of :class:`Http`.
+
+Http objects have the following methods:
+
+.. % If your module defines new object types (for a built-in module) or
+.. % classes (for a module written in Python), you should list the
+.. % methods and instance variables (if any) of each type or class in a
+.. % separate subsection.
+
+.. _http-objects:
+
+Http Objects
+---------------
+
+.. method:: Http.request(uri, [method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None])
+
+   Performs a single HTTP request. The *uri* is the URI of the HTTP resource and
+   can begin with either ``http`` or ``https``. The value of *uri* must be an
+   absolute URI.
+
+   The *method* is the HTTP method to perform, such as ``GET``, ``POST``,
+   ``DELETE``, etc. There is no restriction on the methods allowed.
+
+   The *body* is the entity body to be sent with the request. It is a string
+   object.
+
+   Any extra headers that are to be sent with the request should be provided in the
+   *headers* dictionary.
+
+   The maximum number of redirect to follow before raising an exception is
+   *redirections*. The default is 5.
+
+   The *connection_type* is the type of connection object to use. The supplied
+   class should implement the interface of httplib.HTTPConnection.
+
+   The return value is a tuple of (response, content), the first being and instance
+   of the :class:`Response` class, the second being a string that contains the
+   response entity body.
+
+
+.. method:: Http.add_credentials(name, password, [domain=None])
+
+   Adds a name and password that will be used when a request  requires
+   authentication. Supplying the optional *domain* name will restrict these
+   credentials to only be sent to the specified domain. If *domain* is not
+   specified then the given credentials will be used to try to satisfy every HTTP
+   401 challenge.
+
+
+.. method:: Http.add_certificate(key, cert, domain)
+
+   Add a *key* and *cert* that will be used for an SSL connection to the specified
+   domain. *keyfile* is the name of a PEM formatted  file that contains your
+   private key. *certfile* is a PEM formatted certificate chain file.
+
+
+.. method:: Http.clear_credentials()
+
+   Remove all the names and passwords used for authentication.
+
+
+.. attribute:: Http.follow_redirects
+
+   If ``True``, which is the default, safe redirects are followed, where safe means
+   that the client is only doing a ``GET`` or ``HEAD`` on the URI to which it is
+   being redirected. If ``False`` then no redirects are followed. Note that a False
+   'follow_redirects' takes precedence over a True 'follow_all_redirects'. Another
+   way of saying that is for 'follow_all_redirects' to have any affect,
+   'follow_redirects' must be True.
+
+
+.. attribute:: Http.follow_all_redirects
+
+   If ``False``, which is the default, only safe redirects are followed, where safe
+   means that the client is only doing a ``GET`` or ``HEAD`` on the URI to which it
+   is being redirected. If ``True`` then all redirects are followed. Note that a
+   False 'follow_redirects' takes precedence over a True 'follow_all_redirects'.
+   Another way of saying that is for 'follow_all_redirects' to have any affect,
+   'follow_redirects' must be True.
+
+
+.. attribute:: Http.forward_authorization_headers
+
+  If ``False``, which is the default, then Authorization: headers are
+  stripped from redirects. If ``True`` then Authorization: headers are left
+  in place when following redirects. This parameter only applies if following
+  redirects is turned on. Note that turning this on could cause your credentials
+  to leak, so carefully consider the consequences.
+
+
+.. attribute:: Http.force_exception_to_status_code
+
+   If ``True`` then no :mod:`httplib2` exceptions will be
+   thrown. Instead, those error conditions will be turned into :class:`Response`
+   objects that will be returned normally.
+
+   If ``False``, which is the default, then exceptions will be thrown.
+
+
+.. attribute:: Http.optimistic_concurrency_methods
+
+   By default a list that only contains "PUT", this attribute
+   controls which methods will get 'if-match' headers attached
+   to them from cached responses with etags. You can append
+   new items to this list to add new methods that should
+   get this support, such as "PATCH".
+
+.. attribute:: Http.ignore_etag
+
+   Defaults to ``False``. If ``True``, then any etags present in the cached
+   response are ignored when processing the current request, i.e. httplib2 does
+   **not** use 'if-match' for PUT or 'if-none-match' when GET or HEAD requests are
+   made. This is mainly to deal with broken servers which supply an etag, but
+   change it capriciously.
+
+If you wish to supply your own caching implementation then you will need to pass
+in an object that supports the  following methods. Note that the :mod:`memcache`
+module supports this interface natively.
+
+
+.. _cache-objects:
+
+Cache Objects
+--------------
+
+.. method:: Cache.get(key)
+
+   Takes a string *key* and returns the value as a string.
+
+
+.. method:: Cache.set(key, value)
+
+   Takes a string *key* and *value* and stores it in the cache.
+
+
+.. method:: Cache.delete(key)
+
+   Deletes the cached value stored at *key*. The value of *key* is a string.
+
+Response objects are derived from :class:`dict` and map header names (lower case
+with the trailing colon removed) to header values. In addition to the dict
+methods a Response object also has:
+
+
+.. _response-objects:
+
+Response Objects
+------------------
+
+
+.. attribute:: Response.fromcache
+
+   If ``true`` the the response was returned from the cache.
+
+
+.. attribute:: Response.version
+
+   The version of HTTP that the server supports. A value of 11 means '1.1'.
+
+
+.. attribute:: Response.status
+
+   The numerical HTTP status code returned in the response.
+
+
+.. attribute:: Response.reason
+
+   The human readable component of the HTTP response status code.
+
+
+.. attribute:: Response.previous
+
+   If redirects are followed then the :class:`Response` object returned is just for
+   the very last HTTP request and *previous* points to the previous
+   :class:`Response` object. In this manner they form a chain going back through
+   the responses to the very first response. Will be ``None`` if there are no
+   previous respones.
+
+The Response object also populates the header ``content-location``, that
+contains the URI that was ultimately requested. This is useful if redirects were
+encountered, you can determine the ultimate URI that the request was sent to.
+All Response objects contain this key value, including ``previous`` responses so
+you can determine the entire chain of redirects. If
+:attr:`Http.force_exception_to_status_code` is ``True`` and the number of
+redirects has exceeded the number of allowed number  of redirects then the
+:class:`Response` object will report the error in the status code, but the
+complete chain of previous responses will still be in tact.
+
+To do a simple ``GET`` request just supply the absolute URI of the resource:
+
+.. % ==== 4. ====
+.. % Now is probably a good time for a complete example.  (Alternatively,
+.. % an example giving the flavor of the module may be given before the
+.. % detailed list of functions.)
+
+.. _httplib2-example:
+
+Examples
+---------
+
+::
+
+   import httplib2
+   h = httplib2.Http()
+   resp, content = h.request("http://bitworking.org/")
+   assert resp.status == 200
+   assert resp['content-type'] == 'text/html'
+
+Here is more complex example that does a PUT  of some text to a resource that
+requires authentication. The Http instance also uses a file cache in the
+directory ``.cache``.  ::
+
+   import httplib2
+   h = httplib2.Http(".cache")
+   h.add_credentials('name', 'password')
+   resp, content = h.request("https://example.org/chap/2",
+       "PUT", body="This is text",
+       headers={'content-type':'text/plain'} )
+
+Here is an example that connects to a server that  supports the Atom Publishing
+Protocol. ::
+
+   import httplib2
+   h = httplib2.Http()
+   h.add_credentials(myname, mypasswd)
+   h.follow_all_redirects = True
+   headers = {'Content-Type': 'application/atom+xml'}
+   body    = """<?xml version="1.0" ?>
+       <entry xmlns="http://www.w3.org/2005/Atom">
+         <title>Atom-Powered Robots Run Amok</title>
+         <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+         <updated>2003-12-13T18:30:02Z</updated>
+         <author><name>John Doe</name></author>
+         <content>Some text.</content>
+   </entry>
+   """
+   uri     = "http://www.example.com/collection/"
+   resp, content = h.request(uri, "POST", body=body, headers=headers)
+
+Here is an example of providing data to an HTML form processor. In this case we
+presume this is a POST form. We need to take our  data and format it as
+"application/x-www-form-urlencoded" data and use that as a  body for a POST
+request.
+
+
+::
+
+   >>> import httplib2
+   >>> import urllib
+   >>> data = {'name': 'fred', 'address': '123 shady lane'}
+   >>> body = urllib.urlencode(data)
+   >>> body
+   'name=fred&address=123+shady+lane'
+   >>> h = httplib2.Http()
+   >>> resp, content = h.request("http://example.com", method="POST", body=body)
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..5a98539
--- /dev/null
+++ b/index.html
@@ -0,0 +1,207 @@
+<html>
+<head>
+     <!--#include virtual="header.html" -->
+    <title>Joe Gregorio | BitWorking | Projects | httplib2.py</title>
+</head>
+<body class='main' id="top" name="top" >
+    <div class="body">
+        <!--#include virtual="titlebar.html" -->
+
+        <div class="content">
+
+            <div>
+
+                <h2>Httplib2</h2>
+                <p>A comprehensive HTTP client library, <code>httplib2.py</code>
+                supports many features left out of other HTTP libraries.
+                </p>
+                <dl>
+                    <dt>HTTP and HTTPS</dt>
+                    <dd>HTTPS support is only available if the socket module was compiled with SSL support.
+                    </dd>
+
+                    <dt>Keep-Alive</dt>
+                    <dd>Supports HTTP 1.1 Keep-Alive, keeping the socket
+                    open and performing multiple requests over the same connection
+                    if possible.
+                    </dd>
+
+                    <dt>Authentication</dt>
+                    <dd>The following types of HTTP Authentication are supported.
+                    These can be used over both HTTP and HTTPS.
+                    <ul>
+                        <li><a href="http://www.faqs.org/rfcs/rfc2617.html">Digest</a></li>
+                        <li><a href="http://www.faqs.org/rfcs/rfc2617.html">Basic</a></li>
+                        <li><a href="http://www.xml.com/pub/a/2003/12/17/dive.html">WSSE</a></li>
+                        <li><a href="http://franklinmint.fm/2006/02/28/draft-sayre-http-hmac-digest.html">HMAC Digest</a></li>
+                        <li><a href="http://code.google.com/apis/accounts/AuthForInstalledApps.html">Google Account Authentication</a></li>
+                    </ul>
+                    </dd>
+
+                    <dt>Caching</dt>
+                    <dd>The module can optionally operate with a private
+                    cache that understands the Cache-Control: header and
+                    uses both the ETag and Last-Modified cache validators.
+                    </dd>
+
+                    <dt>All Methods</dt>
+                    <dd>The module can handle any HTTP request method, not just GET and POST.</dd>
+
+                    <dt>Redirects</dt>
+                    <dd>Automatically follows 3XX redirects on GETs.</dd>
+
+                    <dt>Compression</dt>
+                    <dd>Handles both 'deflate' and 'gzip' types of compression.</dd>
+
+                    <dt>Lost update support</dt>
+                    <dd>Automatically adds back ETags into PUT requests to resources
+                    we have already cached. This implements Section 3.2 of
+                    <a href="http://www.w3.org/1999/04/Editing/#Table">Detecting the Lost Update Problem Using Unreserved Checkout</a></dd>
+
+                    <dt>Unit Tested</dt>
+                    <dd>A large and growing set of unit tests.</dd>
+
+                </dl>
+
+<h3>Usage</h3>
+
+<p>A simple retrieval:</p>
+
+<pre><code>import httplib2
+h = httplib2.Http(".cache")
+resp, content = h.request("http://example.org/", "GET")
+</code></pre>
+
+<p>The 'content' is the content retrieved from the URL.
+The content is already decompressed or unzipped if necessary.
+The 'resp' contains all the response headers.
+</p>
+
+<p>To PUT some content to a server that uses SSL
+and Basic authentication:</p>
+
+<pre><code>import httplib2
+h = httplib2.Http(".cache")
+h.add_credentials('name', 'password')
+resp, content = h.request("https://example.org/chap/2",
+    "PUT", body="This is text",
+    headers={'content-type':'text/plain'} )
+</code></pre>
+
+<p>Use the Cache-Control: header to control
+   how the caching operates.</p>
+
+<pre><code>import httplib2
+h = httplib2.Http(".cache")
+resp, content = h.request("http://bitworking.org/")
+ ...
+resp, content = h.request("http://bitworking.org/",
+    headers={'cache-control':'no-cache'})
+</code></pre>
+
+<p>The first request will be cached and since this is a request to
+bitworking.org it will be set to be cached for two hours, because
+that is how I have my server configured.
+Any subsequent GET to that URI will return the value from the
+on-disk cache and no request will be made to the server.
+You can use the Cache-Control: header to change the caches behavior and
+in this example the second request adds the Cache-Control: header with a value
+of 'no-cache' which tells the library that the cached copy
+must not be used when handling this request.
+</p>
+
+<h3>Requirements</h3>
+
+<p>Requires Python 2.3 or later. Does not require
+any libraries beyond what is found in the core library.</p>
+
+<h3>Download/Installation</h3>
+
+<p>The latest release of httplib2 is 0.3.0 and
+can be <a href="dist">downloaded from the from
+    the dist directory</a>. See the
+<a href="CHANGELOG">CHANGELOG</a> for what's new in this
+version.</p>
+
+
+<p>The httplib2 module is shipped as a distutils package.  To install
+the library, first unpack the distribution archive, and issue the following
+command:</p>
+
+<pre><code>$ python setup.py install</code></pre>
+
+<p><a href="dist">Download the distribution archives from here</a>. </p>
+
+<p> <a href="test">The resources used in the unit test cases</a>
+  are available also. More documentation on them will be forthcoming.</p>
+
+<p>You can also get the sources directly from the SourceForge hosted
+  subversion repository.</p>
+
+<pre>svn co https://httplib2.svn.sourceforge.net/svnroot/httplib2/trunk httplib2</pre>
+
+
+<h3>Documentation</h3>
+
+<p>In addition to the <a href="ref/">Python library style documentation</a> there
+are also two articles on XML.com, <a href="http://www.xml.com/pub/a/2006/02/01/doing-http-caching-right-introducing-httplib2.html">
+    Doing HTTP Caching Right: Introducing httplib2</a> and
+<a href="http://www.xml.com/pub/a/2006/03/29/httplib2-http-persistence-and-authentication.html">
+httplib2: HTTP Persistence and Authentication </a>.
+
+</p>
+
+<h3>Feedback</h3>
+
+<p>Bugs and enhancement requests are handled through
+<a href="http://sourceforge.net/projects/httplib2/">SourceForge</a>, and anything is up for discussion
+on the <a href="http://sourceforge.net/mail/?group_id=161082">httplib2 mailing list</a>.
+</p>
+
+<h3>To Do</h3>
+
+<p>This module is not perfect and needs the following:</p>
+<ul>
+    <li>Support for Proxies</li>
+    <li>A pluggable store for the cache is in place, with plugins for
+    flat files and memcached.
+    I eventually want to have plugins that allow keeping the cache in Berkeley DB, MySQL, etc.</li>
+    <li>More unit tests</li>
+</ul>
+
+<h3>Project Goal</h3>
+
+<p>To become a worthy addition to the Python core library.</p>
+
+<h3>Additional Information</h3>
+
+<p>
+   <dl>
+       <dt>Author</dt>
+       <dd>Joe Gregorio</dd>
+
+       <dt>License</dt>
+       <dd>MIT</dd>
+
+       <dt>Contributors</dt>
+
+       <dd> Thomas Broyer (t.broyer@ltgt.net) </dd>
+       <dd> James Antill </dd>
+       <dd> Xavier Verges Farrero </dd>
+       <dd> Jonathan Feinberg </dd>
+       <dd> Blair Zajac </dd>
+       <dd> Sam Ruby</dd>
+       <dd> Louis Nyffenegger </dd>
+       <dd> (Your Name Here) </dd>
+   </dl>
+</p>
+
+  <p style="font-size: small">This page last updated on: $LastChangedDate$.</p>
+
+            </div>
+        </div>
+     <!--#include virtual="footer.html" -->
+    </div>
+</body>
+
+</html>
diff --git a/libhttplib2.tex b/libhttplib2.tex
new file mode 100644
index 0000000..0c958c3
--- /dev/null
+++ b/libhttplib2.tex
@@ -0,0 +1,454 @@
+% Template for a library manual section.
+% PLEASE REMOVE THE COMMENTS AFTER USING THE TEMPLATE
+%
+% Complete documentation on the extended LaTeX markup used for Python
+% documentation is available in ``Documenting Python'', which is part
+% of the standard documentation for Python.  It may be found online
+% at:
+%
+%     http://www.python.org/doc/current/doc/doc.html
+
+% ==== 0. ====
+% Copy this file to <mydir>/lib<mymodule>.tex, and edit that file
+% according to the instructions below.
+
+
+% ==== 1. ====
+% The section prologue.  Give the section a title and provide some
+% meta-information.  References to the module should use
+% \refbimodindex, \refstmodindex, \refexmodindex or \refmodindex, as
+% appropriate.
+
+
+\section{\module{httplib2}
+         A comprehensive HTTP client library.  }
+
+% Choose one of these to specify the module module name.  If there's
+% an underscore in the name, use
+% \declaremodule[modname]{...}{mod_name} instead.
+%
+\declaremodule{}{httplib2}                     % not standard, in Python
+
+% Portability statement:  Uncomment and fill in the parameter to specify the
+% availability of the module.  The parameter can be Unix, IRIX, SunOS, Mac,
+% Windows, or lots of other stuff.  When ``Mac'' is specified, the availability
+% statement will say ``Macintosh'' and the Module Index may say ``Mac''.
+% Please use a name that has already been used whenever applicable.  If this
+% is omitted, no availability statement is produced or implied.
+%
+%   \platform{Unix}
+
+% These apply to all modules, and may be given more than once:
+
+\moduleauthor{Joe Gregorio}{joe@bitworking.org}         % Author of the module code;
+                                        % omit if not known.
+\sectionauthor{Joe Gregorio}{joe@bitworking.org}                % Author of the documentation,
+                                        % even if not a module section.
+
+
+% Leave at least one blank line after this, to simplify ad-hoc tools
+% that are sometimes used to massage these files.
+\modulesynopsis{A comprehensive HTTP client library, \module{httplib2} supports many features left out of other HTTP libraries.}
+
+
+% ==== 2. ====
+% Give a short overview of what the module does.
+% If it is platform specific, mention this.
+% Mention other important restrictions or general operating principles.
+% For example:
+
+The \module{httplib2} module is a comprehensive HTTP client library with the following features:
+
+\begin{description}
+\item[HTTP and HTTPS]  HTTPS support is only available if the socket module was compiled with SSL support.
+\item[Keep-Alive]    Supports HTTP 1.1 Keep-Alive, keeping the socket open and performing multiple requests over the same connection if possible.
+\item[Authentication] The following three types of HTTP Authentication are supported. These can be used over both HTTP and HTTPS.
+    \begin{itemize}
+        \item Digest
+        \item Basic
+        \item WSSE
+    \end{itemize}
+\item[Caching]
+    The module can optionally operate with a private cache that understands the Cache-Control: header and uses both the ETag and Last-Modified cache validators.
+\item[All Methods]
+    The module can handle any HTTP request method, not just GET and POST.
+\item[Redirects]
+    Automatically follows 3XX redirects on GETs.
+\item[Compression]
+    Handles both 'deflate' and 'gzip' types of compression.
+\item[Proxies]
+    If the Socksipy module is installed then httplib2 can handle sock4, sock5 and http proxies.
+\item[Lost update support]
+    Automatically adds back ETags into PUT requests to resources we have already cached. This implements Section 3.2 of Detecting the Lost Update Problem Using Unreserved Checkout
+\end{description}
+
+% ==== 3. ====
+% List the public functions defined by the module.  Begin with a
+% standard phrase.  You may also list the exceptions and other data
+% items defined in the module, insofar as they are important for the
+% user.
+
+The \module{httplib2} module defines the following variables:
+% ---- 3.2. ----
+% Data items are described using a ``datadesc'' block.  This has only
+% one parameter: the item's name.
+
+\begin{datadesc}{debuglevel}
+The amount of debugging information to print. The default is 0.
+\end{datadesc}
+
+\begin{datadesc}{RETRIES}
+A request will be tried 'RETRIES' times if it fails at the socket/connection level.
+The default is 2.
+\end{datadesc}
+
+% --- 3.3. ---
+% Exceptions are described using a ``excdesc'' block.  This has only
+% one parameter: the exception name.  Exceptions defined as classes in
+% the source code should be documented using this environment, but
+% constructor parameters must be omitted.
+
+The \module{httplib2} module may raise the following Exceptions. Note that
+there is an option that turns exceptions into
+normal responses with an HTTP status code indicating
+an error occured. See \member{Http.force_exception_to_status_code}
+
+\begin{excdesc}{HttpLib2Error}
+The Base Exception for all exceptions raised by httplib2.
+\end{excdesc}
+
+\begin{excdesc}{RedirectMissingLocation}
+A 3xx redirect response code was provided but no Location: header
+was provided to point to the new location.
+\end{excdesc}
+
+\begin{excdesc}{RedirectLimit}
+The maximum number of redirections was reached without coming to a final URI.
+\end{excdesc}
+
+
+\begin{excdesc}{ServerNotFoundError}
+Unable to resolve the host name given.
+\end{excdesc}
+
+\begin{excdesc}{RelativeURIError}
+A relative, as opposed to an absolute URI, was passed into request().
+\end{excdesc}
+
+\begin{excdesc}{FailedToDecompressContent}
+The headers claimed that the content of the response was compressed but the
+decompression algorithm applied to the content failed.
+\end{excdesc}
+
+\begin{excdesc}{UnimplementedDigestAuthOptionError}
+The server requested a type of Digest authentication that we
+are unfamiliar with.
+\end{excdesc}
+
+\begin{excdesc}{UnimplementedHmacDigestAuthOptionError}
+The server requested a type of HMACDigest authentication that we
+are unfamiliar with.
+\end{excdesc}
+
+% ---- 3.4. ----
+% Other standard environments:
+%
+%  classdesc    - Python classes; same arguments are funcdesc
+%  methoddesc   - methods, like funcdesc but has an optional parameter
+%                 to give the type name: \begin{methoddesc}[mytype]{name}{args}
+%                 By default, the type name will be the name of the
+%                 last class defined using classdesc.  The type name
+%                 is required if the type is implemented in C (because
+%                 there's no classdesc) or if the class isn't directly
+%                 documented (if it's private).
+%  memberdesc   - data members, like datadesc, but with an optional
+%                 type name like methoddesc.
+
+\begin{classdesc}{Http}{\optional{cache=None}, \optional{timeout=None}, \optional{proxy_info=None}}
+The class that represents a client HTTP interface.
+The \var{cache} parameter is either the name of a directory
+to be used as a flat file cache, or it must an object that
+implements the required caching interface.
+The \var{timeout} parameter is the socket level timeout.
+The \var{proxy_info} is an instance of \class{ProxyInfo} and is supplied
+if a proxy is to be used. Note that the Socksipy module must be
+installed for proxy support to work.
+\end{classdesc}
+
+\begin{classdesc}{Response}{info}
+Response is a subclass of \class{dict} and instances of this
+class are returned from calls
+to Http.request. The \var{info} parameter is either
+an \class{rfc822.Message} or an \class{httplib.HTTPResponse} object.
+\end{classdesc}
+
+\begin{classdesc}{FileCache}{dir_name, \optional{safe=safename}}
+FileCache implements a Cache as a directory of files.
+The \var{dir_name} parameter is
+the name of the directory to use. If the directory does
+not exist then FileCache attempts to create the directory.
+The optional \var{safe} parameter is a funtion which generates
+the cache filename for each URI. A FileCache object is
+constructed and used for caching when you pass a directory name
+into the constructor of \class{Http}.
+\end{classdesc}
+
+\begin{classdesc}{ProxyInfo}{proxy_type, proxy_host, proxy_port, \optional{proxy_rdns=None}, \optional{proxy_user=None}, \optional{proxy_pass=None}}
+The parameter \var{proxy_type} must be set to one of socks.PROXY_TYPE_XXX
+constants. The \var{proxy_host} and \var{proxy_port} must be set to the location
+of the proxy. The optional \var{proxy_rdns} should be set to True if
+the DNS server on the proxy should be used. The \var{proxy_user} and
+\var{proxy_pass} are supplied when the proxy is protected by authentication.
+\end{classdesc}
+
+
+% If your module defines new object types (for a built-in module) or
+% classes (for a module written in Python), you should list the
+% methods and instance variables (if any) of each type or class in a
+% separate subsection.
+
+\subsection{Http Objects}
+\label{http-objects}
+% This label is generally useful for referencing this section, but is
+% also used to give a filename when generating HTML.
+
+Http objects have the following methods:
+
+\begin{methoddesc}[Http]{request}{uri, \optional{method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None}}
+Performs a single HTTP request.
+The \var{uri} is the URI of the HTTP resource and can begin with either \code{http} or \code{https}. The value of \var{uri} must be an absolute URI.
+
+The \var{method} is the HTTP method to perform, such as \code{GET}, \code{POST}, \code{DELETE}, etc. There is no restriction
+on the methods allowed.
+
+The \var{body} is the entity body to be sent with the request. It is a string
+object.
+
+Any extra headers that are to be sent with the request should be provided in the
+\var{headers} dictionary.
+
+The maximum number of redirect to follow before raising an exception is \var{redirections}. The default is 5.
+
+The \var{connection_type} is the type of connection object to use. The supplied class
+should implement the interface of httplib.HTTPConnection.
+
+The return value is a tuple of (response, content), the first being and instance of the
+\class{Response} class, the second being a string that contains the response entity body.
+\end{methoddesc}
+
+\begin{methoddesc}[Http]{add_credentials}{name, password, \optional{domain=None}}
+Adds a name and password that will be used when a request
+requires authentication. Supplying the optional \var{domain} name will
+restrict these credentials to only be sent to the specified
+domain. If \var{domain} is not specified then the given credentials will
+be used to try to satisfy every HTTP 401 challenge.
+\end{methoddesc}
+
+\begin{methoddesc}[Http]{add_certificate}{key, cert, domain}
+Add a \var{key} and \var{cert} that will be used for an SSL connection
+to the specified domain. \var{keyfile} is the name of a PEM formatted
+file that contains your private key. \var{certfile} is a PEM formatted certificate chain file.
+\end{methoddesc}
+
+\begin{methoddesc}[Http]{clear_credentials}{}
+Remove all the names and passwords used for authentication.
+\end{methoddesc}
+
+\begin{memberdesc}[Http]{follow_redirects}
+If \code{True}, which is the default, safe redirects are followed, where
+safe means that the client is only doing a \code{GET} or \code{HEAD} on the
+URI to which it is being redirected. If \code{False} then no redirects are followed.
+Note that a False 'follow_redirects' takes precedence over a True 'follow_all_redirects'.
+Another way of saying that is for 'follow_all_redirects' to have any affect, 'follow_redirects'
+must be True.
+\end{memberdesc}
+
+\begin{memberdesc}[Http]{forward_authorization_headers}
+If \code{False}, which is the default, then Authorization: headers are
+stripped from redirects. If \code{True} then Authorization: headers are left
+in place when following redirects. This parameter only applies if following
+redirects is turned on. Note that turning this on could cause your credentials
+to leak, so carefully consider the consequences.
+\end{memberdesc}
+
+\begin{memberdesc}[Http]{follow_all_redirects}
+If \code{False}, which is the default, only safe redirects are followed, where
+safe means that the client is only doing a \code{GET} or \code{HEAD} on the
+URI to which it is being redirected. If \code{True} then all redirects are followed.
+Note that a False 'follow_redirects' takes precedence over a True 'follow_all_redirects'.
+Another way of saying that is for 'follow_all_redirects' to have any affect, 'follow_redirects'
+must be True.
+\end{memberdesc}
+
+\begin{memberdesc}[Http]{force_exception_to_status_code}
+If \code{True}, which is the default, then no \module{httplib2} exceptions will be thrown. Instead,
+those error conditions will be turned into \class{Response} objects
+that will be returned normally.
+
+If \code{False}, then exceptions will be thrown.
+\end{memberdesc}
+
+\begin{memberdesc}[Http]{ignore_etag}
+Defaults to \code{False}. If \code{True}, then any etags present in the cached response
+are ignored when processing the current request, i.e. httplib2 does \strong{not} use
+'if-match' for PUT or 'if-none-match' when GET or HEAD requests are made. This
+is mainly to deal with broken servers which supply an etag, but change it capriciously.
+\end{memberdesc}
+
+\subsection{Cache Objects}
+\label{cache-objects}
+% This label is generally useful for referencing this section, but is
+% also used to give a filename when generating HTML.
+
+If you wish to supply your own caching implementation
+then you will need to pass in an object that supports the
+following methods. Note that the \module{memcache} module
+supports this interface natively.
+
+\begin{methoddesc}[Cache]{get}{key}
+Takes a string \var{key} and returns the value as a string.
+\end{methoddesc}
+
+\begin{methoddesc}[Cache]{set}{key, value}
+Takes a string \var{key} and \var{value} and stores it in the cache.
+\end{methoddesc}
+
+\begin{methoddesc}[Cache]{delete}{key}
+Deletes the cached value stored at \var{key}. The value
+of \var{key} is a string.
+\end{methoddesc}
+
+
+
+
+\subsection{Response Objects}
+\label{response-objects}
+% This label is generally useful for referencing this section, but is
+% also used to give a filename when generating HTML.
+
+Response objects are derived from \class{dict} and map
+header names (lower case with the trailing colon removed)
+to header values. In addition to the dict methods
+a Response object also has:
+
+\begin{memberdesc}[Response]{fromcache}
+If \code{true} the the response was returned from the cache.
+\end{memberdesc}
+
+\begin{memberdesc}[Response]{version}
+The version of HTTP that the server supports. A value
+of 11 means '1.1'.
+\end{memberdesc}
+
+\begin{memberdesc}[Response]{status}
+The numerical HTTP status code returned in the response.
+\end{memberdesc}
+
+\begin{memberdesc}[Response]{reason}
+The human readable component of the HTTP response status code.
+\end{memberdesc}
+
+\begin{memberdesc}[Response]{previous}
+If redirects are followed then the \class{Response} object returned
+is just for the very last HTTP request and \var{previous} points to
+the previous \class{Response} object. In this manner they form a chain
+going back through the responses to the very first response.
+Will be \code{None} if there are no previous respones.
+\end{memberdesc}
+
+The Response object also populates the header \code{content-location}, that
+contains the URI that was ultimately requested. This is useful if
+redirects were encountered, you can determine the ultimate URI that
+the request was sent to. All Response objects contain this key value,
+including \code{previous} responses so you can determine the entire
+chain of redirects. If \member{Http.force_exception_to_status_code} is \code{True}
+and the number of redirects has exceeded the number of allowed number
+of redirects then the \class{Response} object will report the error
+in the status code, but the complete chain of previous responses will
+still be in tact.
+
+
+% ==== 4. ====
+% Now is probably a good time for a complete example.  (Alternatively,
+% an example giving the flavor of the module may be given before the
+% detailed list of functions.)
+
+\subsection{Examples \label{httplib2-example}}
+
+To do a simple \code{GET} request just supply the absolute URI
+of the resource:
+
+\begin{verbatim}
+import httplib2
+h = httplib2.Http()
+resp, content = h.request("http://bitworking.org/")
+assert resp.status == 200
+assert resp['content-type'] == 'text/html'
+\end{verbatim}
+
+Here is more complex example that does a PUT
+of some text to a resource that requires authentication.
+The Http instance also uses a file cache
+in the directory \code{.cache}.
+
+\begin{verbatim}
+import httplib2
+h = httplib2.Http(".cache")
+h.add_credentials('name', 'password')
+resp, content = h.request("https://example.org/chap/2",
+    "PUT", body="This is text",
+    headers={'content-type':'text/plain'} )
+\end{verbatim}
+
+Here is an example that connects to a server that
+supports the Atom Publishing Protocol.
+
+\begin{verbatim}
+import httplib2
+h = httplib2.Http()
+h.add_credentials(myname, mypasswd)
+h.follow_all_redirects = True
+headers = {'Content-Type': 'application/atom+xml'}
+body    = """<?xml version="1.0" ?>
+    <entry xmlns="http://www.w3.org/2005/Atom">
+      <title>Atom-Powered Robots Run Amok</title>
+      <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+      <updated>2003-12-13T18:30:02Z</updated>
+      <author><name>John Doe</name></author>
+      <content>Some text.</content>
+</entry>
+"""
+uri     = "http://www.example.com/collection/"
+resp, content = h.request(uri, "POST", body=body, headers=headers)
+\end{verbatim}
+% Note that there is no trailing ">>> " prompt shown.
+
+Here is an example of providing data to an HTML form processor.
+In this case we presume this is a POST form. We need to take our
+data and format it as "application/x-www-form-urlencoded" data and use that as a
+body for a POST request.
+
+\begin{verbatim}
+>>> import httplib2
+>>> import urllib
+>>> data = {'name': 'fred', 'address': '123 shady lane'}
+>>> body = urllib.urlencode(data)
+>>> body
+'name=fred&address=123+shady+lane'
+>>> h = httplib2.Http()
+>>> resp, content = h.request("http://example.com", method="POST", body=body)
+\end{verbatim}
+% Note that there is no trailing ">>> " prompt shown.
+
+Here is an example of using a proxy server:
+\begin{verbatim}
+import httplib2
+import socks
+
+httplib2.debuglevel=4
+h = httplib2.Http(proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP, 'localhost', 8000))
+r,c = h.request("http://bitworking.org/news/")
+\end{verbatim}
+
+
+
diff --git a/python2/httplib2/__init__.py b/python2/httplib2/__init__.py
new file mode 100644
index 0000000..18b013d
--- /dev/null
+++ b/python2/httplib2/__init__.py
@@ -0,0 +1,1780 @@
+from __future__ import print_function
+"""
+httplib2
+
+A caching http interface that supports ETags and gzip
+to conserve bandwidth.
+
+Requires Python 2.3 or later
+
+Changelog:
+2007-08-18, Rick: Modified so it's able to use a socks proxy if needed.
+
+"""
+
+__author__ = "Joe Gregorio (joe@bitworking.org)"
+__copyright__ = "Copyright 2006, Joe Gregorio"
+__contributors__ = ["Thomas Broyer (t.broyer@ltgt.net)",
+                    "James Antill",
+                    "Xavier Verges Farrero",
+                    "Jonathan Feinberg",
+                    "Blair Zajac",
+                    "Sam Ruby",
+                    "Louis Nyffenegger",
+                    "Alex Yu"]
+__license__ = "MIT"
+__version__ = '0.11.3'
+
+import re
+import sys
+import email
+import email.Utils
+import email.Message
+import email.FeedParser
+import StringIO
+import gzip
+import zlib
+import httplib
+import urlparse
+import urllib
+import base64
+import os
+import copy
+import calendar
+import time
+import random
+import errno
+try:
+    from hashlib import sha1 as _sha, md5 as _md5
+except ImportError:
+    # prior to Python 2.5, these were separate modules
+    import sha
+    import md5
+    _sha = sha.new
+    _md5 = md5.new
+import hmac
+from gettext import gettext as _
+import socket
+
+try:
+    from httplib2 import socks
+except ImportError:
+    try:
+        import socks
+    except (ImportError, AttributeError):
+        socks = None
+
+# Build the appropriate socket wrapper for ssl
+ssl = None
+ssl_SSLError = None
+ssl_CertificateError = None
+try:
+    import ssl  # python 2.6
+except ImportError:
+    pass
+if ssl is not None:
+    ssl_SSLError = getattr(ssl, 'SSLError', None)
+    ssl_CertificateError = getattr(ssl, 'CertificateError', None)
+
+
+def _ssl_wrap_socket(sock, key_file, cert_file, disable_validation,
+                     ca_certs, ssl_version, hostname):
+    if disable_validation:
+        cert_reqs = ssl.CERT_NONE
+    else:
+        cert_reqs = ssl.CERT_REQUIRED
+    if ssl_version is None:
+        ssl_version = ssl.PROTOCOL_SSLv23
+
+    if hasattr(ssl, 'SSLContext'):  # Python 2.7.9
+        context = ssl.SSLContext(ssl_version)
+        context.verify_mode = cert_reqs
+        context.check_hostname = (cert_reqs != ssl.CERT_NONE)
+        if cert_file:
+            context.load_cert_chain(cert_file, key_file)
+        if ca_certs:
+            context.load_verify_locations(ca_certs)
+        return context.wrap_socket(sock, server_hostname=hostname)
+    else:
+        return ssl.wrap_socket(sock, keyfile=key_file, certfile=cert_file,
+                               cert_reqs=cert_reqs, ca_certs=ca_certs,
+                               ssl_version=ssl_version)
+
+
+def _ssl_wrap_socket_unsupported(sock, key_file, cert_file, disable_validation,
+                                 ca_certs, ssl_version, hostname):
+    if not disable_validation:
+        raise CertificateValidationUnsupported(
+                "SSL certificate validation is not supported without "
+                "the ssl module installed. To avoid this error, install "
+                "the ssl module, or explicity disable validation.")
+    ssl_sock = socket.ssl(sock, key_file, cert_file)
+    return httplib.FakeSocket(sock, ssl_sock)
+
+if ssl is None:
+    _ssl_wrap_socket = _ssl_wrap_socket_unsupported
+
+
+if sys.version_info >= (2,3):
+    from iri2uri import iri2uri
+else:
+    def iri2uri(uri):
+        return uri
+
+def has_timeout(timeout): # python 2.6
+    if hasattr(socket, '_GLOBAL_DEFAULT_TIMEOUT'):
+        return (timeout is not None and timeout is not socket._GLOBAL_DEFAULT_TIMEOUT)
+    return (timeout is not None)
+
+__all__ = [
+    'Http', 'Response', 'ProxyInfo', 'HttpLib2Error', 'RedirectMissingLocation',
+    'RedirectLimit', 'FailedToDecompressContent',
+    'UnimplementedDigestAuthOptionError',
+    'UnimplementedHmacDigestAuthOptionError',
+    'debuglevel', 'ProxiesUnavailableError']
+
+
+# The httplib debug level, set to a non-zero value to get debug output
+debuglevel = 0
+
+# A request will be tried 'RETRIES' times if it fails at the socket/connection level.
+RETRIES = 2
+
+# Python 2.3 support
+if sys.version_info < (2,4):
+    def sorted(seq):
+        seq.sort()
+        return seq
+
+
+# Python 2.3 support
+def HTTPResponse__getheaders(self):
+    """Return list of (header, value) tuples."""
+    if self.msg is None:
+        raise httplib.ResponseNotReady()
+    return self.msg.items()
+
+if not hasattr(httplib.HTTPResponse, 'getheaders'):
+    httplib.HTTPResponse.getheaders = HTTPResponse__getheaders
+
+# All exceptions raised here derive from HttpLib2Error
+class HttpLib2Error(Exception): pass
+
+# Some exceptions can be caught and optionally
+# be turned back into responses.
+class HttpLib2ErrorWithResponse(HttpLib2Error):
+    def __init__(self, desc, response, content):
+        self.response = response
+        self.content = content
+        HttpLib2Error.__init__(self, desc)
+
+class RedirectMissingLocation(HttpLib2ErrorWithResponse): pass
+class RedirectLimit(HttpLib2ErrorWithResponse): pass
+class FailedToDecompressContent(HttpLib2ErrorWithResponse): pass
+class UnimplementedDigestAuthOptionError(HttpLib2ErrorWithResponse): pass
+class UnimplementedHmacDigestAuthOptionError(HttpLib2ErrorWithResponse): pass
+
+class MalformedHeader(HttpLib2Error): pass
+class RelativeURIError(HttpLib2Error): pass
+class ServerNotFoundError(HttpLib2Error): pass
+class ProxiesUnavailableError(HttpLib2Error): pass
+class CertificateValidationUnsupported(HttpLib2Error): pass
+class SSLHandshakeError(HttpLib2Error): pass
+class NotSupportedOnThisPlatform(HttpLib2Error): pass
+class CertificateHostnameMismatch(SSLHandshakeError):
+    def __init__(self, desc, host, cert):
+        HttpLib2Error.__init__(self, desc)
+        self.host = host
+        self.cert = cert
+
+class NotRunningAppEngineEnvironment(HttpLib2Error): pass
+
+# Open Items:
+# -----------
+# Proxy support
+
+# Are we removing the cached content too soon on PUT (only delete on 200 Maybe?)
+
+# Pluggable cache storage (supports storing the cache in
+#   flat files by default. We need a plug-in architecture
+#   that can support Berkeley DB and Squid)
+
+# == Known Issues ==
+# Does not handle a resource that uses conneg and Last-Modified but no ETag as a cache validator.
+# Does not handle Cache-Control: max-stale
+# Does not use Age: headers when calculating cache freshness.
+
+
+# The number of redirections to follow before giving up.
+# Note that only GET redirects are automatically followed.
+# Will also honor 301 requests by saving that info and never
+# requesting that URI again.
+DEFAULT_MAX_REDIRECTS = 5
+
+try:
+    # Users can optionally provide a module that tells us where the CA_CERTS
+    # are located.
+    import ca_certs_locater
+    CA_CERTS = ca_certs_locater.get()
+except ImportError:
+    # Default CA certificates file bundled with httplib2.
+    CA_CERTS = os.path.join(
+        os.path.dirname(os.path.abspath(__file__ )), "cacerts.txt")
+
+# Which headers are hop-by-hop headers by default
+HOP_BY_HOP = ['connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'transfer-encoding', 'upgrade']
+
+
+def _get_end2end_headers(response):
+    hopbyhop = list(HOP_BY_HOP)
+    hopbyhop.extend([x.strip() for x in response.get('connection', '').split(',')])
+    return [header for header in response.keys() if header not in hopbyhop]
+
+URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?")
+
+
+def parse_uri(uri):
+    """Parses a URI using the regex given in Appendix B of RFC 3986.
+
+        (scheme, authority, path, query, fragment) = parse_uri(uri)
+    """
+    groups = URI.match(uri).groups()
+    return (groups[1], groups[3], groups[4], groups[6], groups[8])
+
+
+def urlnorm(uri):
+    (scheme, authority, path, query, fragment) = parse_uri(uri)
+    if not scheme or not authority:
+        raise RelativeURIError("Only absolute URIs are allowed. uri = %s" % uri)
+    authority = authority.lower()
+    scheme = scheme.lower()
+    if not path:
+        path = "/"
+    # Could do syntax based normalization of the URI before
+    # computing the digest. See Section 6.2.2 of Std 66.
+    request_uri = query and "?".join([path, query]) or path
+    scheme = scheme.lower()
+    defrag_uri = scheme + "://" + authority + request_uri
+    return scheme, authority, request_uri, defrag_uri
+
+
+# Cache filename construction (original borrowed from Venus http://intertwingly.net/code/venus/)
+re_url_scheme    = re.compile(r'^\w+://')
+re_slash         = re.compile(r'[?/:|]+')
+
+
+def safename(filename):
+    """Return a filename suitable for the cache.
+
+    Strips dangerous and common characters to create a filename we
+    can use to store the cache in.
+    """
+
+    try:
+        if re_url_scheme.match(filename):
+            if isinstance(filename,str):
+                filename = filename.decode('utf-8')
+                filename = filename.encode('idna')
+            else:
+                filename = filename.encode('idna')
+    except UnicodeError:
+        pass
+    if isinstance(filename,unicode):
+        filename=filename.encode('utf-8')
+    filemd5 = _md5(filename).hexdigest()
+    filename = re_url_scheme.sub("", filename)
+    filename = re_slash.sub(",", filename)
+
+    # limit length of filename
+    if len(filename)>200:
+        filename=filename[:200]
+    return ",".join((filename, filemd5))
+
+NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
+
+
+def _normalize_headers(headers):
+    return dict([ (key.lower(), NORMALIZE_SPACE.sub(value, ' ').strip())  for (key, value) in headers.iteritems()])
+
+
+def _parse_cache_control(headers):
+    retval = {}
+    if 'cache-control' in headers:
+        parts =  headers['cache-control'].split(',')
+        parts_with_args = [tuple([x.strip().lower() for x in part.split("=", 1)]) for part in parts if -1 != part.find("=")]
+        parts_wo_args = [(name.strip().lower(), 1) for name in parts if -1 == name.find("=")]
+        retval = dict(parts_with_args + parts_wo_args)
+    return retval
+
+# Whether to use a strict mode to parse WWW-Authenticate headers
+# Might lead to bad results in case of ill-formed header value,
+# so disabled by default, falling back to relaxed parsing.
+# Set to true to turn on, usefull for testing servers.
+USE_WWW_AUTH_STRICT_PARSING = 0
+
+# In regex below:
+#    [^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+             matches a "token" as defined by HTTP
+#    "(?:[^\0-\x08\x0A-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?"    matches a "quoted-string" as defined by HTTP, when LWS have already been replaced by a single space
+# Actually, as an auth-param value can be either a token or a quoted-string, they are combined in a single pattern which matches both:
+#    \"?((?<=\")(?:[^\0-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?(?=\")|(?<!\")[^\0-\x08\x0A-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+(?!\"))\"?
+WWW_AUTH_STRICT = re.compile(r"^(?:\s*(?:,\s*)?([^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+)\s*=\s*\"?((?<=\")(?:[^\0-\x08\x0A-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?(?=\")|(?<!\")[^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+(?!\"))\"?)(.*)$")
+WWW_AUTH_RELAXED = re.compile(r"^(?:\s*(?:,\s*)?([^ \t\r\n=]+)\s*=\s*\"?((?<=\")(?:[^\\\"]|\\.)*?(?=\")|(?<!\")[^ \t\r\n,]+(?!\"))\"?)(.*)$")
+UNQUOTE_PAIRS = re.compile(r'\\(.)')
+def _parse_www_authenticate(headers, headername='www-authenticate'):
+    """Returns a dictionary of dictionaries, one dict
+    per auth_scheme."""
+    retval = {}
+    if headername in headers:
+        try:
+
+            authenticate = headers[headername].strip()
+            www_auth = USE_WWW_AUTH_STRICT_PARSING and WWW_AUTH_STRICT or WWW_AUTH_RELAXED
+            while authenticate:
+                # Break off the scheme at the beginning of the line
+                if headername == 'authentication-info':
+                    (auth_scheme, the_rest) = ('digest', authenticate)
+                else:
+                    (auth_scheme, the_rest) = authenticate.split(" ", 1)
+                # Now loop over all the key value pairs that come after the scheme,
+                # being careful not to roll into the next scheme
+                match = www_auth.search(the_rest)
+                auth_params = {}
+                while match:
+                    if match and len(match.groups()) == 3:
+                        (key, value, the_rest) = match.groups()
+                        auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')])
+                    match = www_auth.search(the_rest)
+                retval[auth_scheme.lower()] = auth_params
+                authenticate = the_rest.strip()
+
+        except ValueError:
+            raise MalformedHeader("WWW-Authenticate")
+    return retval
+
+
+# TODO: add current time as _entry_disposition argument to avoid sleep in tests
+def _entry_disposition(response_headers, request_headers):
+    """Determine freshness from the Date, Expires and Cache-Control headers.
+
+    We don't handle the following:
+
+    1. Cache-Control: max-stale
+    2. Age: headers are not used in the calculations.
+
+    Not that this algorithm is simpler than you might think
+    because we are operating as a private (non-shared) cache.
+    This lets us ignore 's-maxage'. We can also ignore
+    'proxy-invalidate' since we aren't a proxy.
+    We will never return a stale document as
+    fresh as a design decision, and thus the non-implementation
+    of 'max-stale'. This also lets us safely ignore 'must-revalidate'
+    since we operate as if every server has sent 'must-revalidate'.
+    Since we are private we get to ignore both 'public' and
+    'private' parameters. We also ignore 'no-transform' since
+    we don't do any transformations.
+    The 'no-store' parameter is handled at a higher level.
+    So the only Cache-Control parameters we look at are:
+
+    no-cache
+    only-if-cached
+    max-age
+    min-fresh
+    """
+
+    retval = "STALE"
+    cc = _parse_cache_control(request_headers)
+    cc_response = _parse_cache_control(response_headers)
+
+    if 'pragma' in request_headers and request_headers['pragma'].lower().find('no-cache') != -1:
+        retval = "TRANSPARENT"
+        if 'cache-control' not in request_headers:
+            request_headers['cache-control'] = 'no-cache'
+    elif 'no-cache' in cc:
+        retval = "TRANSPARENT"
+    elif 'no-cache' in cc_response:
+        retval = "STALE"
+    elif 'only-if-cached' in cc:
+        retval = "FRESH"
+    elif 'date' in response_headers:
+        date = calendar.timegm(email.Utils.parsedate_tz(response_headers['date']))
+        now = time.time()
+        current_age = max(0, now - date)
+        if 'max-age' in cc_response:
+            try:
+                freshness_lifetime = int(cc_response['max-age'])
+            except ValueError:
+                freshness_lifetime = 0
+        elif 'expires' in response_headers:
+            expires = email.Utils.parsedate_tz(response_headers['expires'])
+            if None == expires:
+                freshness_lifetime = 0
+            else:
+                freshness_lifetime = max(0, calendar.timegm(expires) - date)
+        else:
+            freshness_lifetime = 0
+        if 'max-age' in cc:
+            try:
+                freshness_lifetime = int(cc['max-age'])
+            except ValueError:
+                freshness_lifetime = 0
+        if 'min-fresh' in cc:
+            try:
+                min_fresh = int(cc['min-fresh'])
+            except ValueError:
+                min_fresh = 0
+            current_age += min_fresh
+        if freshness_lifetime > current_age:
+            retval = "FRESH"
+    return retval
+
+
+def _decompressContent(response, new_content):
+    content = new_content
+    try:
+        encoding = response.get('content-encoding', None)
+        if encoding in ['gzip', 'deflate']:
+            if encoding == 'gzip':
+                content = gzip.GzipFile(fileobj=StringIO.StringIO(new_content)).read()
+            if encoding == 'deflate':
+                content = zlib.decompress(content, -zlib.MAX_WBITS)
+            response['content-length'] = str(len(content))
+            # Record the historical presence of the encoding in a way the won't interfere.
+            response['-content-encoding'] = response['content-encoding']
+            del response['content-encoding']
+    except (IOError, zlib.error):
+        content = ""
+        raise FailedToDecompressContent(_("Content purported to be compressed with %s but failed to decompress.") % response.get('content-encoding'), response, content)
+    return content
+
+
+def _updateCache(request_headers, response_headers, content, cache, cachekey):
+    if cachekey:
+        cc = _parse_cache_control(request_headers)
+        cc_response = _parse_cache_control(response_headers)
+        if 'no-store' in cc or 'no-store' in cc_response:
+            cache.delete(cachekey)
+        else:
+            info = email.Message.Message()
+            for key, value in response_headers.iteritems():
+                if key not in ['status','content-encoding','transfer-encoding']:
+                    info[key] = value
+
+            # Add annotations to the cache to indicate what headers
+            # are variant for this request.
+            vary = response_headers.get('vary', None)
+            if vary:
+                vary_headers = vary.lower().replace(' ', '').split(',')
+                for header in vary_headers:
+                    key = '-varied-%s' % header
+                    try:
+                        info[key] = request_headers[header]
+                    except KeyError:
+                        pass
+
+            status = response_headers.status
+            if status == 304:
+                status = 200
+
+            status_header = 'status: %d\r\n' % status
+
+            header_str = info.as_string()
+
+            header_str = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", header_str)
+            text = "".join([status_header, header_str, content])
+
+            cache.set(cachekey, text)
+
+def _cnonce():
+    dig = _md5("%s:%s" % (time.ctime(), ["0123456789"[random.randrange(0, 9)] for i in range(20)])).hexdigest()
+    return dig[:16]
+
+def _wsse_username_token(cnonce, iso_now, password):
+    return base64.b64encode(_sha("%s%s%s" % (cnonce, iso_now, password)).digest()).strip()
+
+
+# For credentials we need two things, first
+# a pool of credential to try (not necesarily tied to BAsic, Digest, etc.)
+# Then we also need a list of URIs that have already demanded authentication
+# That list is tricky since sub-URIs can take the same auth, or the
+# auth scheme may change as you descend the tree.
+# So we also need each Auth instance to be able to tell us
+# how close to the 'top' it is.
+
+class Authentication(object):
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
+        self.path = path
+        self.host = host
+        self.credentials = credentials
+        self.http = http
+
+    def depth(self, request_uri):
+        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
+        return request_uri[len(self.path):].count("/")
+
+    def inscope(self, host, request_uri):
+        # XXX Should we normalize the request_uri?
+        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
+        return (host == self.host) and path.startswith(self.path)
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header. Over-ride this in sub-classes."""
+        pass
+
+    def response(self, response, content):
+        """Gives us a chance to update with new nonces
+        or such returned from the last authorized response.
+        Over-rise this in sub-classes if necessary.
+
+        Return TRUE is the request is to be retried, for
+        example Digest may return stale=true.
+        """
+        return False
+
+
+class BasicAuthentication(Authentication):
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header."""
+        headers['authorization'] = 'Basic ' + base64.b64encode("%s:%s" % self.credentials).strip()
+
+
+class DigestAuthentication(Authentication):
+    """Only do qop='auth' and MD5, since that
+    is all Apache currently implements"""
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+        challenge = _parse_www_authenticate(response, 'www-authenticate')
+        self.challenge = challenge['digest']
+        qop = self.challenge.get('qop', 'auth')
+        self.challenge['qop'] = ('auth' in [x.strip() for x in qop.split()]) and 'auth' or None
+        if self.challenge['qop'] is None:
+            raise UnimplementedDigestAuthOptionError( _("Unsupported value for qop: %s." % qop))
+        self.challenge['algorithm'] = self.challenge.get('algorithm', 'MD5').upper()
+        if self.challenge['algorithm'] != 'MD5':
+            raise UnimplementedDigestAuthOptionError( _("Unsupported value for algorithm: %s." % self.challenge['algorithm']))
+        self.A1 = "".join([self.credentials[0], ":", self.challenge['realm'], ":", self.credentials[1]])
+        self.challenge['nc'] = 1
+
+    def request(self, method, request_uri, headers, content, cnonce = None):
+        """Modify the request headers"""
+        H = lambda x: _md5(x).hexdigest()
+        KD = lambda s, d: H("%s:%s" % (s, d))
+        A2 = "".join([method, ":", request_uri])
+        self.challenge['cnonce'] = cnonce or _cnonce()
+        request_digest  = '"%s"' % KD(H(self.A1), "%s:%s:%s:%s:%s" % (
+                self.challenge['nonce'],
+                '%08x' % self.challenge['nc'],
+                self.challenge['cnonce'],
+                self.challenge['qop'], H(A2)))
+        headers['authorization'] = 'Digest username="%s", realm="%s", nonce="%s", uri="%s", algorithm=%s, response=%s, qop=%s, nc=%08x, cnonce="%s"' % (
+                self.credentials[0],
+                self.challenge['realm'],
+                self.challenge['nonce'],
+                request_uri,
+                self.challenge['algorithm'],
+                request_digest,
+                self.challenge['qop'],
+                self.challenge['nc'],
+                self.challenge['cnonce'])
+        if self.challenge.get('opaque'):
+            headers['authorization'] += ', opaque="%s"' % self.challenge['opaque']
+        self.challenge['nc'] += 1
+
+    def response(self, response, content):
+        if 'authentication-info' not in response:
+            challenge = _parse_www_authenticate(response, 'www-authenticate').get('digest', {})
+            if 'true' == challenge.get('stale'):
+                self.challenge['nonce'] = challenge['nonce']
+                self.challenge['nc'] = 1
+                return True
+        else:
+            updated_challenge = _parse_www_authenticate(response, 'authentication-info').get('digest', {})
+
+            if 'nextnonce' in updated_challenge:
+                self.challenge['nonce'] = updated_challenge['nextnonce']
+                self.challenge['nc'] = 1
+        return False
+
+
+class HmacDigestAuthentication(Authentication):
+    """Adapted from Robert Sayre's code and DigestAuthentication above."""
+    __author__ = "Thomas Broyer (t.broyer@ltgt.net)"
+
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+        challenge = _parse_www_authenticate(response, 'www-authenticate')
+        self.challenge = challenge['hmacdigest']
+        # TODO: self.challenge['domain']
+        self.challenge['reason'] = self.challenge.get('reason', 'unauthorized')
+        if self.challenge['reason'] not in ['unauthorized', 'integrity']:
+            self.challenge['reason'] = 'unauthorized'
+        self.challenge['salt'] = self.challenge.get('salt', '')
+        if not self.challenge.get('snonce'):
+            raise UnimplementedHmacDigestAuthOptionError( _("The challenge doesn't contain a server nonce, or this one is empty."))
+        self.challenge['algorithm'] = self.challenge.get('algorithm', 'HMAC-SHA-1')
+        if self.challenge['algorithm'] not in ['HMAC-SHA-1', 'HMAC-MD5']:
+            raise UnimplementedHmacDigestAuthOptionError( _("Unsupported value for algorithm: %s." % self.challenge['algorithm']))
+        self.challenge['pw-algorithm'] = self.challenge.get('pw-algorithm', 'SHA-1')
+        if self.challenge['pw-algorithm'] not in ['SHA-1', 'MD5']:
+            raise UnimplementedHmacDigestAuthOptionError( _("Unsupported value for pw-algorithm: %s." % self.challenge['pw-algorithm']))
+        if self.challenge['algorithm'] == 'HMAC-MD5':
+            self.hashmod = _md5
+        else:
+            self.hashmod = _sha
+        if self.challenge['pw-algorithm'] == 'MD5':
+            self.pwhashmod = _md5
+        else:
+            self.pwhashmod = _sha
+        self.key = "".join([self.credentials[0], ":",
+                            self.pwhashmod.new("".join([self.credentials[1], self.challenge['salt']])).hexdigest().lower(),
+                            ":", self.challenge['realm']])
+        self.key = self.pwhashmod.new(self.key).hexdigest().lower()
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers"""
+        keys = _get_end2end_headers(headers)
+        keylist = "".join(["%s " % k for k in keys])
+        headers_val = "".join([headers[k] for k in keys])
+        created = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime())
+        cnonce = _cnonce()
+        request_digest = "%s:%s:%s:%s:%s" % (method, request_uri, cnonce, self.challenge['snonce'], headers_val)
+        request_digest  = hmac.new(self.key, request_digest, self.hashmod).hexdigest().lower()
+        headers['authorization'] = 'HMACDigest username="%s", realm="%s", snonce="%s", cnonce="%s", uri="%s", created="%s", response="%s", headers="%s"' % (
+                self.credentials[0],
+                self.challenge['realm'],
+                self.challenge['snonce'],
+                cnonce,
+                request_uri,
+                created,
+                request_digest,
+                keylist)
+
+    def response(self, response, content):
+        challenge = _parse_www_authenticate(response, 'www-authenticate').get('hmacdigest', {})
+        if challenge.get('reason') in ['integrity', 'stale']:
+            return True
+        return False
+
+
+class WsseAuthentication(Authentication):
+    """This is thinly tested and should not be relied upon.
+    At this time there isn't any third party server to test against.
+    Blogger and TypePad implemented this algorithm at one point
+    but Blogger has since switched to Basic over HTTPS and
+    TypePad has implemented it wrong, by never issuing a 401
+    challenge but instead requiring your client to telepathically know that
+    their endpoint is expecting WSSE profile="UsernameToken"."""
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header."""
+        headers['authorization'] = 'WSSE profile="UsernameToken"'
+        iso_now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
+        cnonce = _cnonce()
+        password_digest = _wsse_username_token(cnonce, iso_now, self.credentials[1])
+        headers['X-WSSE'] = 'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"' % (
+                self.credentials[0],
+                password_digest,
+                cnonce,
+                iso_now)
+
+
+class GoogleLoginAuthentication(Authentication):
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        from urllib import urlencode
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+        challenge = _parse_www_authenticate(response, 'www-authenticate')
+        service = challenge['googlelogin'].get('service', 'xapi')
+        # Bloggger actually returns the service in the challenge
+        # For the rest we guess based on the URI
+        if service == 'xapi' and  request_uri.find("calendar") > 0:
+            service = "cl"
+        # No point in guessing Base or Spreadsheet
+        #elif request_uri.find("spreadsheets") > 0:
+        #    service = "wise"
+
+        auth = dict(Email=credentials[0], Passwd=credentials[1], service=service, source=headers['user-agent'])
+        resp, content = self.http.request("https://www.google.com/accounts/ClientLogin", method="POST", body=urlencode(auth), headers={'Content-Type': 'application/x-www-form-urlencoded'})
+        lines = content.split('\n')
+        d = dict([tuple(line.split("=", 1)) for line in lines if line])
+        if resp.status == 403:
+            self.Auth = ""
+        else:
+            self.Auth = d['Auth']
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header."""
+        headers['authorization'] = 'GoogleLogin Auth=' + self.Auth
+
+
+AUTH_SCHEME_CLASSES = {
+    "basic": BasicAuthentication,
+    "wsse": WsseAuthentication,
+    "digest": DigestAuthentication,
+    "hmacdigest": HmacDigestAuthentication,
+    "googlelogin": GoogleLoginAuthentication
+}
+
+AUTH_SCHEME_ORDER = ["hmacdigest", "googlelogin", "digest", "wsse", "basic"]
+
+
+class FileCache(object):
+    """Uses a local directory as a store for cached files.
+    Not really safe to use if multiple threads or processes are going to
+    be running on the same cache.
+    """
+    def __init__(self, cache, safe=safename):  # use safe=lambda x: md5.new(x).hexdigest() for the old behavior
+        self.cache = cache
+        self.safe = safe
+        if not os.path.exists(cache):
+            os.makedirs(self.cache)
+
+    def get(self, key):
+        retval = None
+        cacheFullPath = os.path.join(self.cache, self.safe(key))
+        try:
+            f = file(cacheFullPath, "rb")
+            retval = f.read()
+            f.close()
+        except IOError:
+            pass
+        return retval
+
+    def set(self, key, value):
+        cacheFullPath = os.path.join(self.cache, self.safe(key))
+        f = file(cacheFullPath, "wb")
+        f.write(value)
+        f.close()
+
+    def delete(self, key):
+        cacheFullPath = os.path.join(self.cache, self.safe(key))
+        if os.path.exists(cacheFullPath):
+            os.remove(cacheFullPath)
+
+
+class Credentials(object):
+    def __init__(self):
+        self.credentials = []
+
+    def add(self, name, password, domain=""):
+        self.credentials.append((domain.lower(), name, password))
+
+    def clear(self):
+        self.credentials = []
+
+    def iter(self, domain):
+        for (cdomain, name, password) in self.credentials:
+            if cdomain == "" or domain == cdomain:
+                yield (name, password)
+
+
+class KeyCerts(Credentials):
+    """Identical to Credentials except that
+    name/password are mapped to key/cert."""
+    pass
+
+
+class AllHosts(object):
+    pass
+
+
+class ProxyInfo(object):
+    """Collect information required to use a proxy."""
+    bypass_hosts = ()
+
+    def __init__(self, proxy_type, proxy_host, proxy_port,
+                 proxy_rdns=True, proxy_user=None, proxy_pass=None, proxy_headers=None):
+        """
+        Args:
+          proxy_type: The type of proxy server.  This must be set to one of
+          socks.PROXY_TYPE_XXX constants.  For example:
+
+            p = ProxyInfo(proxy_type=socks.PROXY_TYPE_HTTP,
+              proxy_host='localhost', proxy_port=8000)
+
+          proxy_host: The hostname or IP address of the proxy server.
+
+          proxy_port: The port that the proxy server is running on.
+
+          proxy_rdns: If True (default), DNS queries will not be performed
+          locally, and instead, handed to the proxy to resolve.  This is useful
+          if the network does not allow resolution of non-local names.  In
+          httplib2 0.9 and earlier, this defaulted to False.
+
+          proxy_user: The username used to authenticate with the proxy server.
+
+          proxy_pass: The password used to authenticate with the proxy server.
+
+          proxy_headers: Additional or modified headers for the proxy connect request.
+        """
+        self.proxy_type = proxy_type
+        self.proxy_host = proxy_host
+        self.proxy_port = proxy_port
+        self.proxy_rdns = proxy_rdns
+        self.proxy_user = proxy_user
+        self.proxy_pass = proxy_pass
+        self.proxy_headers = proxy_headers
+
+    def astuple(self):
+        return (self.proxy_type, self.proxy_host, self.proxy_port,
+                self.proxy_rdns, self.proxy_user, self.proxy_pass, self.proxy_headers)
+
+    def isgood(self):
+        return (self.proxy_host != None) and (self.proxy_port != None)
+
+    def applies_to(self, hostname):
+        return not self.bypass_host(hostname)
+
+    def bypass_host(self, hostname):
+        """Has this host been excluded from the proxy config"""
+        if self.bypass_hosts is AllHosts:
+            return True
+
+        hostname = '.' + hostname.lstrip('.')
+        for skip_name in self.bypass_hosts:
+            # *.suffix
+            if skip_name.startswith('.') and hostname.endswith(skip_name):
+                return True
+            # exact match
+            if hostname == '.' + skip_name:
+                return True
+        return False
+
+    def __repr__(self):
+        return (
+            '<ProxyInfo type={p.proxy_type} host:port={p.proxy_host}:{p.proxy_port} rdns={p.proxy_rdns}' +
+            ' user={p.proxy_user} headers={p.proxy_headers}>').format(p=self)
+
+
+def proxy_info_from_environment(method='http'):
+    """
+    Read proxy info from the environment variables.
+    """
+    if method not in ['http', 'https']:
+        return
+
+    env_var = method + '_proxy'
+    url = os.environ.get(env_var, os.environ.get(env_var.upper()))
+    if not url:
+        return
+    return proxy_info_from_url(url, method, None)
+
+
+def proxy_info_from_url(url, method='http', noproxy=None):
+    """
+    Construct a ProxyInfo from a URL (such as http_proxy env var)
+    """
+    url = urlparse.urlparse(url)
+    username = None
+    password = None
+    port = None
+    if '@' in url[1]:
+        ident, host_port = url[1].split('@', 1)
+        if ':' in ident:
+            username, password = ident.split(':', 1)
+        else:
+            password = ident
+    else:
+        host_port = url[1]
+    if ':' in host_port:
+        host, port = host_port.split(':', 1)
+    else:
+        host = host_port
+
+    if port:
+        port = int(port)
+    else:
+        port = dict(https=443, http=80)[method]
+
+    proxy_type = 3  # socks.PROXY_TYPE_HTTP
+    pi = ProxyInfo(
+        proxy_type = proxy_type,
+        proxy_host = host,
+        proxy_port = port,
+        proxy_user = username or None,
+        proxy_pass = password or None,
+        proxy_headers = None,
+    )
+
+    bypass_hosts = []
+    # If not given an explicit noproxy value, respect values in env vars.
+    if noproxy is None:
+        noproxy = os.environ.get('no_proxy', os.environ.get('NO_PROXY', ''))
+    # Special case: A single '*' character means all hosts should be bypassed.
+    if noproxy == '*':
+        bypass_hosts = AllHosts
+    elif noproxy.strip():
+        bypass_hosts = noproxy.split(',')
+        bypass_hosts = filter(bool, bypass_hosts)  # To exclude empty string.
+
+    pi.bypass_hosts = bypass_hosts
+    return pi
+
+
+class HTTPConnectionWithTimeout(httplib.HTTPConnection):
+    """
+    HTTPConnection subclass that supports timeouts
+
+    All timeouts are in seconds. If None is passed for timeout then
+    Python's default timeout for sockets will be used. See for example
+    the docs of socket.setdefaulttimeout():
+    http://docs.python.org/library/socket.html#socket.setdefaulttimeout
+    """
+
+    def __init__(self, host, port=None, strict=None, timeout=None, proxy_info=None):
+        httplib.HTTPConnection.__init__(self, host, port, strict)
+        self.timeout = timeout
+        self.proxy_info = proxy_info
+
+    def connect(self):
+        """Connect to the host and port specified in __init__."""
+        # Mostly verbatim from httplib.py.
+        if self.proxy_info and socks is None:
+            raise ProxiesUnavailableError(
+                'Proxy support missing but proxy use was requested!')
+        msg = "getaddrinfo returns an empty list"
+        if self.proxy_info and self.proxy_info.isgood():
+            use_proxy = True
+            proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers = self.proxy_info.astuple()
+
+            host = proxy_host
+            port = proxy_port
+        else:
+            use_proxy = False
+
+            host = self.host
+            port = self.port
+
+        for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
+            af, socktype, proto, canonname, sa = res
+            try:
+                if use_proxy:
+                    self.sock = socks.socksocket(af, socktype, proto)
+                    self.sock.setproxy(proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers)
+                else:
+                    self.sock = socket.socket(af, socktype, proto)
+                    self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+                # Different from httplib: support timeouts.
+                if has_timeout(self.timeout):
+                    self.sock.settimeout(self.timeout)
+                    # End of difference from httplib.
+                if self.debuglevel > 0:
+                    print("connect: (%s, %s) ************" % (self.host, self.port))
+                    if use_proxy:
+                        print("proxy: %s ************" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers)))
+                if use_proxy:
+                    self.sock.connect((self.host, self.port) + sa[2:])
+                else:
+                    self.sock.connect(sa)
+            except socket.error as msg:
+                if self.debuglevel > 0:
+                    print("connect fail: (%s, %s)" % (self.host, self.port))
+                    if use_proxy:
+                        print("proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers)))
+                if self.sock:
+                    self.sock.close()
+                self.sock = None
+                continue
+            break
+        if not self.sock:
+            raise socket.error, msg
+
+
+class HTTPSConnectionWithTimeout(httplib.HTTPSConnection):
+    """
+    This class allows communication via SSL.
+
+    All timeouts are in seconds. If None is passed for timeout then
+    Python's default timeout for sockets will be used. See for example
+    the docs of socket.setdefaulttimeout():
+    http://docs.python.org/library/socket.html#socket.setdefaulttimeout
+    """
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=None, proxy_info=None,
+                 ca_certs=None, disable_ssl_certificate_validation=False,
+                 ssl_version=None):
+        httplib.HTTPSConnection.__init__(self, host, port=port,
+                                         key_file=key_file,
+                                         cert_file=cert_file, strict=strict)
+        self.timeout = timeout
+        self.proxy_info = proxy_info
+        if ca_certs is None:
+            ca_certs = CA_CERTS
+        self.ca_certs = ca_certs
+        self.disable_ssl_certificate_validation = \
+                disable_ssl_certificate_validation
+        self.ssl_version = ssl_version
+
+    # The following two methods were adapted from https_wrapper.py, released
+    # with the Google Appengine SDK at
+    # http://googleappengine.googlecode.com/svn-history/r136/trunk/python/google/appengine/tools/https_wrapper.py
+    # under the following license:
+    #
+    # Copyright 2007 Google Inc.
+    #
+    # Licensed under the Apache License, Version 2.0 (the "License");
+    # you may not use this file except in compliance with the License.
+    # You may obtain a copy of the License at
+    #
+    #     http://www.apache.org/licenses/LICENSE-2.0
+    #
+    # Unless required by applicable law or agreed to in writing, software
+    # distributed under the License is distributed on an "AS IS" BASIS,
+    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    # See the License for the specific language governing permissions and
+    # limitations under the License.
+    #
+
+    def _GetValidHostsForCert(self, cert):
+        """Returns a list of valid host globs for an SSL certificate.
+
+        Args:
+          cert: A dictionary representing an SSL certificate.
+        Returns:
+          list: A list of valid host globs.
+        """
+        if 'subjectAltName' in cert:
+            return [x[1] for x in cert['subjectAltName']
+                    if x[0].lower() == 'dns']
+        else:
+            return [x[0][1] for x in cert['subject']
+                    if x[0][0].lower() == 'commonname']
+
+    def _ValidateCertificateHostname(self, cert, hostname):
+        """Validates that a given hostname is valid for an SSL certificate.
+
+        Args:
+          cert: A dictionary representing an SSL certificate.
+          hostname: The hostname to test.
+        Returns:
+          bool: Whether or not the hostname is valid for this certificate.
+        """
+        hosts = self._GetValidHostsForCert(cert)
+        for host in hosts:
+            host_re = host.replace('.', '\.').replace('*', '[^.]*')
+            if re.search('^%s$' % (host_re,), hostname, re.I):
+                return True
+        return False
+
+    def connect(self):
+        "Connect to a host on a given (SSL) port."
+
+        msg = "getaddrinfo returns an empty list"
+        if self.proxy_info and self.proxy_info.isgood():
+            use_proxy = True
+            proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers = self.proxy_info.astuple()
+
+            host = proxy_host
+            port = proxy_port
+        else:
+            use_proxy = False
+
+            host = self.host
+            port = self.port
+
+        address_info = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)
+        for family, socktype, proto, canonname, sockaddr in address_info:
+            try:
+                if use_proxy:
+                    sock = socks.socksocket(family, socktype, proto)
+
+                    sock.setproxy(proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers)
+                else:
+                    sock = socket.socket(family, socktype, proto)
+                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+
+                if has_timeout(self.timeout):
+                    sock.settimeout(self.timeout)
+
+                if use_proxy:
+                    sock.connect((self.host, self.port) + sockaddr[:2])
+                else:
+                    sock.connect(sockaddr)
+                self.sock =_ssl_wrap_socket(
+                    sock, self.key_file, self.cert_file,
+                    self.disable_ssl_certificate_validation, self.ca_certs,
+                    self.ssl_version, self.host)
+                if self.debuglevel > 0:
+                    print("connect: (%s, %s)" % (self.host, self.port))
+                    if use_proxy:
+                        print("proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers)))
+                if not self.disable_ssl_certificate_validation:
+                    cert = self.sock.getpeercert()
+                    hostname = self.host.split(':', 0)[0]
+                    if not self._ValidateCertificateHostname(cert, hostname):
+                        raise CertificateHostnameMismatch(
+                            'Server presented certificate that does not match '
+                            'host %s: %s' % (hostname, cert), hostname, cert)
+            except (ssl_SSLError, ssl_CertificateError, CertificateHostnameMismatch) as e:
+                if sock:
+                    sock.close()
+                if self.sock:
+                    self.sock.close()
+                self.sock = None
+                # Unfortunately the ssl module doesn't seem to provide any way
+                # to get at more detailed error information, in particular
+                # whether the error is due to certificate validation or
+                # something else (such as SSL protocol mismatch).
+                if getattr(e, 'errno', None) == ssl.SSL_ERROR_SSL:
+                    raise SSLHandshakeError(e)
+                else:
+                    raise
+            except (socket.timeout, socket.gaierror):
+                raise
+            except socket.error as msg:
+                if self.debuglevel > 0:
+                    print("connect fail: (%s, %s)" % (self.host, self.port))
+                    if use_proxy:
+                        print("proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers)))
+                if self.sock:
+                    self.sock.close()
+                self.sock = None
+                continue
+            break
+        if not self.sock:
+            raise socket.error, msg
+
+SCHEME_TO_CONNECTION = {
+    'http': HTTPConnectionWithTimeout,
+    'https': HTTPSConnectionWithTimeout
+}
+
+
+def _new_fixed_fetch(validate_certificate):
+    def fixed_fetch(url, payload=None, method="GET", headers={},
+                    allow_truncated=False, follow_redirects=True,
+                    deadline=None):
+        if deadline is None:
+            deadline = socket.getdefaulttimeout()
+        return fetch(url, payload=payload, method=method, headers=headers,
+                     allow_truncated=allow_truncated,
+                     follow_redirects=follow_redirects, deadline=deadline,
+                     validate_certificate=validate_certificate)
+    return fixed_fetch
+
+
+class AppEngineHttpConnection(httplib.HTTPConnection):
+    """Use httplib on App Engine, but compensate for its weirdness.
+
+    The parameters key_file, cert_file, proxy_info, ca_certs,
+    disable_ssl_certificate_validation, and ssl_version are all dropped on
+    the ground.
+    """
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=None, proxy_info=None, ca_certs=None,
+                 disable_ssl_certificate_validation=False,
+                 ssl_version=None):
+        httplib.HTTPConnection.__init__(self, host, port=port,
+                                        strict=strict, timeout=timeout)
+
+
+class AppEngineHttpsConnection(httplib.HTTPSConnection):
+    """Same as AppEngineHttpConnection, but for HTTPS URIs.
+
+    The parameters proxy_info, ca_certs, disable_ssl_certificate_validation,
+    and ssl_version are all dropped on the ground.
+    """
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=None, proxy_info=None, ca_certs=None,
+                 disable_ssl_certificate_validation=False,
+                 ssl_version=None):
+        httplib.HTTPSConnection.__init__(self, host, port=port,
+                                         key_file=key_file,
+                                         cert_file=cert_file, strict=strict,
+                                         timeout=timeout)
+        self._fetch = _new_fixed_fetch(
+                not disable_ssl_certificate_validation)
+
+# Use a different connection object for Google App Engine
+try:
+    server_software = os.environ.get('SERVER_SOFTWARE')
+    if not server_software:
+        raise NotRunningAppEngineEnvironment()
+    elif not (server_software.startswith('Google App Engine/') or
+              server_software.startswith('Development/')):
+        raise NotRunningAppEngineEnvironment()
+
+    from google.appengine.api import apiproxy_stub_map
+    if apiproxy_stub_map.apiproxy.GetStub('urlfetch') is None:
+        raise ImportError  # Bail out; we're not actually running on App Engine.
+    from google.appengine.api.urlfetch import fetch
+    from google.appengine.api.urlfetch import InvalidURLError
+
+    # Update the connection classes to use the Googel App Engine specific ones.
+    SCHEME_TO_CONNECTION = {
+        'http': AppEngineHttpConnection,
+        'https': AppEngineHttpsConnection
+    }
+except (ImportError, AttributeError, NotRunningAppEngineEnvironment):
+    pass
+
+
+class Http(object):
+    """An HTTP client that handles:
+
+    - all methods
+    - caching
+    - ETags
+    - compression,
+    - HTTPS
+    - Basic
+    - Digest
+    - WSSE
+
+    and more.
+    """
+    def __init__(self, cache=None, timeout=None,
+                 proxy_info=proxy_info_from_environment,
+                 ca_certs=None, disable_ssl_certificate_validation=False,
+                 ssl_version=None):
+        """If 'cache' is a string then it is used as a directory name for
+        a disk cache. Otherwise it must be an object that supports the
+        same interface as FileCache.
+
+        All timeouts are in seconds. If None is passed for timeout
+        then Python's default timeout for sockets will be used. See
+        for example the docs of socket.setdefaulttimeout():
+        http://docs.python.org/library/socket.html#socket.setdefaulttimeout
+
+        `proxy_info` may be:
+          - a callable that takes the http scheme ('http' or 'https') and
+            returns a ProxyInfo instance per request. By default, uses
+            proxy_nfo_from_environment.
+          - a ProxyInfo instance (static proxy config).
+          - None (proxy disabled).
+
+        ca_certs is the path of a file containing root CA certificates for SSL
+        server certificate validation.  By default, a CA cert file bundled with
+        httplib2 is used.
+
+        If disable_ssl_certificate_validation is true, SSL cert validation will
+        not be performed.
+
+        By default, ssl.PROTOCOL_SSLv23 will be used for the ssl version.
+        """
+        self.proxy_info = proxy_info
+        self.ca_certs = ca_certs
+        self.disable_ssl_certificate_validation = \
+                disable_ssl_certificate_validation
+        self.ssl_version = ssl_version
+
+        # Map domain name to an httplib connection
+        self.connections = {}
+        # The location of the cache, for now a directory
+        # where cached responses are held.
+        if cache and isinstance(cache, basestring):
+            self.cache = FileCache(cache)
+        else:
+            self.cache = cache
+
+        # Name/password
+        self.credentials = Credentials()
+
+        # Key/cert
+        self.certificates = KeyCerts()
+
+        # authorization objects
+        self.authorizations = []
+
+        # If set to False then no redirects are followed, even safe ones.
+        self.follow_redirects = True
+
+        # Which HTTP methods do we apply optimistic concurrency to, i.e.
+        # which methods get an "if-match:" etag header added to them.
+        self.optimistic_concurrency_methods = ["PUT", "PATCH"]
+
+        # If 'follow_redirects' is True, and this is set to True then
+        # all redirecs are followed, including unsafe ones.
+        self.follow_all_redirects = False
+
+        self.ignore_etag = False
+
+        self.force_exception_to_status_code = False
+
+        self.timeout = timeout
+
+        # Keep Authorization: headers on a redirect.
+        self.forward_authorization_headers = False
+
+    def __getstate__(self):
+        state_dict = copy.copy(self.__dict__)
+        # In case request is augmented by some foreign object such as
+        # credentials which handle auth
+        if 'request' in state_dict:
+            del state_dict['request']
+        if 'connections' in state_dict:
+            del state_dict['connections']
+        return state_dict
+
+    def __setstate__(self, state):
+        self.__dict__.update(state)
+        self.connections = {}
+
+    def _auth_from_challenge(self, host, request_uri, headers, response, content):
+        """A generator that creates Authorization objects
+           that can be applied to requests.
+        """
+        challenges = _parse_www_authenticate(response, 'www-authenticate')
+        for cred in self.credentials.iter(host):
+            for scheme in AUTH_SCHEME_ORDER:
+                if scheme in challenges:
+                    yield AUTH_SCHEME_CLASSES[scheme](cred, host, request_uri, headers, response, content, self)
+
+    def add_credentials(self, name, password, domain=""):
+        """Add a name and password that will be used
+        any time a request requires authentication."""
+        self.credentials.add(name, password, domain)
+
+    def add_certificate(self, key, cert, domain):
+        """Add a key and cert that will be used
+        any time a request requires authentication."""
+        self.certificates.add(key, cert, domain)
+
+    def clear_credentials(self):
+        """Remove all the names and passwords
+        that are used for authentication"""
+        self.credentials.clear()
+        self.authorizations = []
+
+    def _conn_request(self, conn, request_uri, method, body, headers):
+        i = 0
+        seen_bad_status_line = False
+        while i < RETRIES:
+            i += 1
+            try:
+                if hasattr(conn, 'sock') and conn.sock is None:
+                    conn.connect()
+                conn.request(method, request_uri, body, headers)
+            except socket.timeout:
+                raise
+            except socket.gaierror:
+                conn.close()
+                raise ServerNotFoundError("Unable to find the server at %s" % conn.host)
+            except ssl_SSLError:
+                conn.close()
+                raise
+            except socket.error as e:
+                err = 0
+                if hasattr(e, 'args'):
+                    err = getattr(e, 'args')[0]
+                else:
+                    err = e.errno
+                if err == errno.ECONNREFUSED:  # Connection refused
+                    raise
+                if err in (errno.ENETUNREACH, errno.EADDRNOTAVAIL) and i < RETRIES:
+                    continue  # retry on potentially transient socket errors
+            except httplib.HTTPException:
+                # Just because the server closed the connection doesn't apparently mean
+                # that the server didn't send a response.
+                if hasattr(conn, 'sock') and conn.sock is None:
+                    if i < RETRIES-1:
+                        conn.close()
+                        conn.connect()
+                        continue
+                    else:
+                        conn.close()
+                        raise
+                if i < RETRIES-1:
+                    conn.close()
+                    conn.connect()
+                    continue
+            try:
+                response = conn.getresponse()
+            except httplib.BadStatusLine:
+                # If we get a BadStatusLine on the first try then that means
+                # the connection just went stale, so retry regardless of the
+                # number of RETRIES set.
+                if not seen_bad_status_line and i == 1:
+                    i = 0
+                    seen_bad_status_line = True
+                    conn.close()
+                    conn.connect()
+                    continue
+                else:
+                    conn.close()
+                    raise
+            except (socket.error, httplib.HTTPException):
+                if i < RETRIES-1:
+                    conn.close()
+                    conn.connect()
+                    continue
+                else:
+                    conn.close()
+                    raise
+            else:
+                content = ""
+                if method == "HEAD":
+                    conn.close()
+                else:
+                    content = response.read()
+                response = Response(response)
+                if method != "HEAD":
+                    content = _decompressContent(response, content)
+            break
+        return (response, content)
+
+
+    def _request(self, conn, host, absolute_uri, request_uri, method, body, headers, redirections, cachekey):
+        """Do the actual request using the connection object
+        and also follow one level of redirects if necessary"""
+
+        auths = [(auth.depth(request_uri), auth) for auth in self.authorizations if auth.inscope(host, request_uri)]
+        auth = auths and sorted(auths)[0][1] or None
+        if auth:
+            auth.request(method, request_uri, headers, body)
+
+        (response, content) = self._conn_request(conn, request_uri, method, body, headers)
+
+        if auth:
+            if auth.response(response, body):
+                auth.request(method, request_uri, headers, body)
+                (response, content) = self._conn_request(conn, request_uri, method, body, headers )
+                response._stale_digest = 1
+
+        if response.status == 401:
+            for authorization in self._auth_from_challenge(host, request_uri, headers, response, content):
+                authorization.request(method, request_uri, headers, body)
+                (response, content) = self._conn_request(conn, request_uri, method, body, headers, )
+                if response.status != 401:
+                    self.authorizations.append(authorization)
+                    authorization.response(response, body)
+                    break
+
+        if (self.follow_all_redirects or (method in ["GET", "HEAD"]) or response.status == 303):
+            if self.follow_redirects and response.status in [300, 301, 302, 303, 307]:
+                # Pick out the location header and basically start from the beginning
+                # remembering first to strip the ETag header and decrement our 'depth'
+                if redirections:
+                    if 'location' not in response and response.status != 300:
+                        raise RedirectMissingLocation( _("Redirected but the response is missing a Location: header."), response, content)
+                    # Fix-up relative redirects (which violate an RFC 2616 MUST)
+                    if 'location' in response:
+                        location = response['location']
+                        (scheme, authority, path, query, fragment) = parse_uri(location)
+                        if authority == None:
+                            response['location'] = urlparse.urljoin(absolute_uri, location)
+                    if response.status == 301 and method in ["GET", "HEAD"]:
+                        response['-x-permanent-redirect-url'] = response['location']
+                        if 'content-location' not in response:
+                            response['content-location'] = absolute_uri
+                        _updateCache(headers, response, content, self.cache, cachekey)
+                    if 'if-none-match' in headers:
+                        del headers['if-none-match']
+                    if 'if-modified-since' in headers:
+                        del headers['if-modified-since']
+                    if 'authorization' in headers and not self.forward_authorization_headers:
+                        del headers['authorization']
+                    if 'location' in response:
+                        location = response['location']
+                        old_response = copy.deepcopy(response)
+                        if 'content-location' not in old_response:
+                            old_response['content-location'] = absolute_uri
+                        redirect_method = method
+                        if response.status in [302, 303]:
+                            redirect_method = "GET"
+                            body = None
+                        (response, content) = self.request(
+                            location, method=redirect_method,
+                            body=body, headers=headers,
+                            redirections=redirections - 1)
+                        response.previous = old_response
+                else:
+                    raise RedirectLimit("Redirected more times than rediection_limit allows.", response, content)
+            elif response.status in [200, 203] and method in ["GET", "HEAD"]:
+                # Don't cache 206's since we aren't going to handle byte range requests
+                if 'content-location' not in response:
+                    response['content-location'] = absolute_uri
+                _updateCache(headers, response, content, self.cache, cachekey)
+
+        return (response, content)
+
+    def _normalize_headers(self, headers):
+        return _normalize_headers(headers)
+
+# Need to catch and rebrand some exceptions
+# Then need to optionally turn all exceptions into status codes
+# including all socket.* and httplib.* exceptions.
+
+
+    def request(self, uri, method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None):
+        """ Performs a single HTTP request.
+
+        The 'uri' is the URI of the HTTP resource and can begin with either
+        'http' or 'https'. The value of 'uri' must be an absolute URI.
+
+        The 'method' is the HTTP method to perform, such as GET, POST, DELETE,
+        etc. There is no restriction on the methods allowed.
+
+        The 'body' is the entity body to be sent with the request. It is a
+        string object.
+
+        Any extra headers that are to be sent with the request should be
+        provided in the 'headers' dictionary.
+
+        The maximum number of redirect to follow before raising an
+        exception is 'redirections. The default is 5.
+
+        The return value is a tuple of (response, content), the first
+        being and instance of the 'Response' class, the second being
+        a string that contains the response entity body.
+        """
+        try:
+            if headers is None:
+                headers = {}
+            else:
+                headers = self._normalize_headers(headers)
+
+            if 'user-agent' not in headers:
+                headers['user-agent'] = "Python-httplib2/%s (gzip)" % __version__
+
+            uri = iri2uri(uri)
+
+            (scheme, authority, request_uri, defrag_uri) = urlnorm(uri)
+            domain_port = authority.split(":")[0:2]
+            if len(domain_port) == 2 and domain_port[1] == '443' and scheme == 'http':
+                scheme = 'https'
+                authority = domain_port[0]
+
+            proxy_info = self._get_proxy_info(scheme, authority)
+
+            conn_key = scheme+":"+authority
+            if conn_key in self.connections:
+                conn = self.connections[conn_key]
+            else:
+                if not connection_type:
+                    connection_type = SCHEME_TO_CONNECTION[scheme]
+                certs = list(self.certificates.iter(authority))
+                if scheme == 'https':
+                    if certs:
+                        conn = self.connections[conn_key] = connection_type(
+                                authority, key_file=certs[0][0],
+                                cert_file=certs[0][1], timeout=self.timeout,
+                                proxy_info=proxy_info,
+                                ca_certs=self.ca_certs,
+                                disable_ssl_certificate_validation=
+                                        self.disable_ssl_certificate_validation,
+                                        ssl_version=self.ssl_version)
+                    else:
+                        conn = self.connections[conn_key] = connection_type(
+                                authority, timeout=self.timeout,
+                                proxy_info=proxy_info,
+                                ca_certs=self.ca_certs,
+                                disable_ssl_certificate_validation=
+                                        self.disable_ssl_certificate_validation,
+                                ssl_version=self.ssl_version)
+                else:
+                    conn = self.connections[conn_key] = connection_type(
+                            authority, timeout=self.timeout,
+                            proxy_info=proxy_info)
+                conn.set_debuglevel(debuglevel)
+
+            if 'range' not in headers and 'accept-encoding' not in headers:
+                headers['accept-encoding'] = 'gzip, deflate'
+
+            info = email.Message.Message()
+            cached_value = None
+            if self.cache:
+                cachekey = defrag_uri.encode('utf-8')
+                cached_value = self.cache.get(cachekey)
+                if cached_value:
+                    # info = email.message_from_string(cached_value)
+                    #
+                    # Need to replace the line above with the kludge below
+                    # to fix the non-existent bug not fixed in this
+                    # bug report: http://mail.python.org/pipermail/python-bugs-list/2005-September/030289.html
+                    try:
+                        info, content = cached_value.split('\r\n\r\n', 1)
+                        feedparser = email.FeedParser.FeedParser()
+                        feedparser.feed(info)
+                        info = feedparser.close()
+                        feedparser._parse = None
+                    except (IndexError, ValueError):
+                        self.cache.delete(cachekey)
+                        cachekey = None
+                        cached_value = None
+            else:
+                cachekey = None
+
+            if method in self.optimistic_concurrency_methods and self.cache and 'etag' in info and not self.ignore_etag and 'if-match' not in headers:
+                # http://www.w3.org/1999/04/Editing/
+                headers['if-match'] = info['etag']
+
+            if method not in ["GET", "HEAD"] and self.cache and cachekey:
+                # RFC 2616 Section 13.10
+                self.cache.delete(cachekey)
+
+            # Check the vary header in the cache to see if this request
+            # matches what varies in the cache.
+            if method in ['GET', 'HEAD'] and 'vary' in info:
+                vary = info['vary']
+                vary_headers = vary.lower().replace(' ', '').split(',')
+                for header in vary_headers:
+                    key = '-varied-%s' % header
+                    value = info[key]
+                    if headers.get(header, None) != value:
+                        cached_value = None
+                        break
+
+            if cached_value and method in ["GET", "HEAD"] and self.cache and 'range' not in headers:
+                if '-x-permanent-redirect-url' in info:
+                    # Should cached permanent redirects be counted in our redirection count? For now, yes.
+                    if redirections <= 0:
+                        raise RedirectLimit("Redirected more times than rediection_limit allows.", {}, "")
+                    (response, new_content) = self.request(
+                        info['-x-permanent-redirect-url'], method='GET',
+                        headers=headers, redirections=redirections - 1)
+                    response.previous = Response(info)
+                    response.previous.fromcache = True
+                else:
+                    # Determine our course of action:
+                    #   Is the cached entry fresh or stale?
+                    #   Has the client requested a non-cached response?
+                    #
+                    # There seems to be three possible answers:
+                    # 1. [FRESH] Return the cache entry w/o doing a GET
+                    # 2. [STALE] Do the GET (but add in cache validators if available)
+                    # 3. [TRANSPARENT] Do a GET w/o any cache validators (Cache-Control: no-cache) on the request
+                    entry_disposition = _entry_disposition(info, headers)
+
+                    if entry_disposition == "FRESH":
+                        if not cached_value:
+                            info['status'] = '504'
+                            content = ""
+                        response = Response(info)
+                        if cached_value:
+                            response.fromcache = True
+                        return (response, content)
+
+                    if entry_disposition == "STALE":
+                        if 'etag' in info and not self.ignore_etag and not 'if-none-match' in headers:
+                            headers['if-none-match'] = info['etag']
+                        if 'last-modified' in info and not 'last-modified' in headers:
+                            headers['if-modified-since'] = info['last-modified']
+                    elif entry_disposition == "TRANSPARENT":
+                        pass
+
+                    (response, new_content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
+
+                if response.status == 304 and method == "GET":
+                    # Rewrite the cache entry with the new end-to-end headers
+                    # Take all headers that are in response
+                    # and overwrite their values in info.
+                    # unless they are hop-by-hop, or are listed in the connection header.
+
+                    for key in _get_end2end_headers(response):
+                        info[key] = response[key]
+                    merged_response = Response(info)
+                    if hasattr(response, "_stale_digest"):
+                        merged_response._stale_digest = response._stale_digest
+                    _updateCache(headers, merged_response, content, self.cache, cachekey)
+                    response = merged_response
+                    response.status = 200
+                    response.fromcache = True
+
+                elif response.status == 200:
+                    content = new_content
+                else:
+                    self.cache.delete(cachekey)
+                    content = new_content
+            else:
+                cc = _parse_cache_control(headers)
+                if 'only-if-cached' in cc:
+                    info['status'] = '504'
+                    response = Response(info)
+                    content = ""
+                else:
+                    (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
+        except Exception as e:
+            if self.force_exception_to_status_code:
+                if isinstance(e, HttpLib2ErrorWithResponse):
+                    response = e.response
+                    content = e.content
+                    response.status = 500
+                    response.reason = str(e)
+                elif isinstance(e, socket.timeout):
+                    content = "Request Timeout"
+                    response = Response({
+                        "content-type": "text/plain",
+                        "status": "408",
+                        "content-length": len(content)
+                    })
+                    response.reason = "Request Timeout"
+                else:
+                    content = str(e)
+                    response = Response({
+                        "content-type": "text/plain",
+                        "status": "400",
+                        "content-length": len(content)
+                    })
+                    response.reason = "Bad Request"
+            else:
+                raise
+
+
+        return (response, content)
+
+    def _get_proxy_info(self, scheme, authority):
+        """Return a ProxyInfo instance (or None) based on the scheme
+        and authority.
+        """
+        hostname, port = urllib.splitport(authority)
+        proxy_info = self.proxy_info
+        if callable(proxy_info):
+            proxy_info = proxy_info(scheme)
+
+        if (hasattr(proxy_info, 'applies_to')
+            and not proxy_info.applies_to(hostname)):
+            proxy_info = None
+        return proxy_info
+
+
+class Response(dict):
+    """An object more like email.Message than httplib.HTTPResponse."""
+
+    """Is this response from our local cache"""
+    fromcache = False
+
+    """HTTP protocol version used by server. 10 for HTTP/1.0, 11 for HTTP/1.1. """
+    version = 11
+
+    "Status code returned by server. "
+    status = 200
+
+    """Reason phrase returned by server."""
+    reason = "Ok"
+
+    previous = None
+
+    def __init__(self, info):
+        # info is either an email.Message or
+        # an httplib.HTTPResponse object.
+        if isinstance(info, httplib.HTTPResponse):
+            for key, value in info.getheaders():
+                self[key.lower()] = value
+            self.status = info.status
+            self['status'] = str(self.status)
+            self.reason = info.reason
+            self.version = info.version
+        elif isinstance(info, email.Message.Message):
+            for key, value in info.items():
+                self[key.lower()] = value
+            self.status = int(self['status'])
+        else:
+            for key, value in info.iteritems():
+                self[key.lower()] = value
+            self.status = int(self.get('status', self.status))
+            self.reason = self.get('reason', self.reason)
+
+    def __getattr__(self, name):
+        if name == 'dict':
+            return self
+        else:
+            raise AttributeError(name)
diff --git a/python2/httplib2/cacerts.txt b/python2/httplib2/cacerts.txt
new file mode 100644
index 0000000..a2a9833
--- /dev/null
+++ b/python2/httplib2/cacerts.txt
@@ -0,0 +1,2196 @@
+# Issuer: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
+# Subject: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
+# Label: "GTE CyberTrust Global Root"
+# Serial: 421
+# MD5 Fingerprint: ca:3d:d3:68:f1:03:5c:d0:32:fa:b8:2b:59:e8:5a:db
+# SHA1 Fingerprint: 97:81:79:50:d8:1c:96:70:cc:34:d8:09:cf:79:44:31:36:7e:f4:74
+# SHA256 Fingerprint: a5:31:25:18:8d:21:10:aa:96:4b:02:c7:b7:c6:da:32:03:17:08:94:e5:fb:71:ff:fb:66:67:d5:e6:81:0a:36
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+# Issuer: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Subject: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Label: "Thawte Server CA"
+# Serial: 1
+# MD5 Fingerprint: c5:70:c4:a2:ed:53:78:0c:c8:10:53:81:64:cb:d0:1d
+# SHA1 Fingerprint: 23:e5:94:94:51:95:f2:41:48:03:b4:d5:64:d2:a3:a3:f5:d8:8b:8c
+# SHA256 Fingerprint: b4:41:0b:73:e2:e6:ea:ca:47:fb:c4:2f:8f:a4:01:8a:f4:38:1d:c5:4c:fa:a8:44:50:46:1e:ed:09:45:4d:e9
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Subject: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Label: "Thawte Premium Server CA"
+# Serial: 1
+# MD5 Fingerprint: 06:9f:69:79:16:66:90:02:1b:8c:8c:a2:c3:07:6f:3a
+# SHA1 Fingerprint: 62:7f:8d:78:27:65:63:99:d2:7d:7f:90:44:c9:fe:b3:f3:3e:fa:9a
+# SHA256 Fingerprint: ab:70:36:36:5c:71:54:aa:29:c2:c2:9f:5d:41:91:16:3b:16:2a:22:25:01:13:57:d5:6d:07:ff:a7:bc:1f:72
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+# Issuer: O=Equifax OU=Equifax Secure Certificate Authority
+# Subject: O=Equifax OU=Equifax Secure Certificate Authority
+# Label: "Equifax Secure CA"
+# Serial: 903804111
+# MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4
+# SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a
+# SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+
+# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
+# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
+# Label: "Verisign Class 3 Public Primary Certification Authority - G2"
+# Serial: 167285380242319648451154478808036881606
+# MD5 Fingerprint: a2:33:9b:4c:74:78:73:d4:6c:e7:c1:f3:8d:cb:5c:e9
+# SHA1 Fingerprint: 85:37:1c:a6:e5:50:14:3d:ce:28:03:47:1b:de:3a:09:e8:f8:77:0f
+# SHA256 Fingerprint: 83:ce:3c:12:29:68:8a:59:3d:48:5f:81:97:3c:0f:91:95:43:1e:da:37:cc:5e:36:43:0e:79:c7:a8:88:63:8b
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
+# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
+# Label: "GlobalSign Root CA"
+# Serial: 4835703278459707669005204
+# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
+# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
+# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
+# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
+# Label: "GlobalSign Root CA - R2"
+# Serial: 4835703278459682885658125
+# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30
+# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe
+# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
+# Label: "ValiCert Class 1 VA"
+# Serial: 1
+# MD5 Fingerprint: 65:58:ab:15:ad:57:6c:1e:a8:a7:b5:69:ac:bf:ff:eb
+# SHA1 Fingerprint: e5:df:74:3c:b6:01:c4:9b:98:43:dc:ab:8c:e8:6a:81:10:9f:e4:8e
+# SHA256 Fingerprint: f4:c1:49:55:1a:30:13:a3:5b:c7:bf:fe:17:a7:f3:44:9b:c1:ab:5b:5a:0a:e7:4b:06:c2:3b:90:00:4c:01:04
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
+# Label: "ValiCert Class 2 VA"
+# Serial: 1
+# MD5 Fingerprint: a9:23:75:9b:ba:49:36:6e:31:c2:db:f2:e7:66:ba:87
+# SHA1 Fingerprint: 31:7a:2a:d0:7f:2b:33:5e:f5:a1:c3:4e:4b:57:e8:b7:d8:f1:fc:a6
+# SHA256 Fingerprint: 58:d0:17:27:9c:d4:dc:63:ab:dd:b1:96:a6:c9:90:6c:30:c4:e0:87:83:ea:e8:c1:60:99:54:d6:93:55:59:6b
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
+# Label: "RSA Root Certificate 1"
+# Serial: 1
+# MD5 Fingerprint: a2:6f:53:b7:ee:40:db:4a:68:e7:fa:18:d9:10:4b:72
+# SHA1 Fingerprint: 69:bd:8c:f4:9c:d3:00:fb:59:2e:17:93:ca:55:6a:f3:ec:aa:35:fb
+# SHA256 Fingerprint: bc:23:f9:8a:31:3c:b9:2d:e3:bb:fc:3a:5a:9f:44:61:ac:39:49:4c:4a:e1:5a:9e:9d:f1:31:e9:9b:73:01:9a
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Label: "Verisign Class 3 Public Primary Certification Authority - G3"
+# Serial: 206684696279472310254277870180966723415
+# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09
+# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6
+# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Label: "Verisign Class 4 Public Primary Certification Authority - G3"
+# Serial: 314531972711909413743075096039378935511
+# MD5 Fingerprint: db:c8:f2:27:2e:b1:ea:6a:29:23:5d:fe:56:3e:33:df
+# SHA1 Fingerprint: c8:ec:8c:87:92:69:cb:4b:ab:39:e9:8d:7e:57:67:f3:14:95:73:9d
+# SHA256 Fingerprint: e3:89:36:0d:0f:db:ae:b3:d2:50:58:4b:47:30:31:4e:22:2f:39:c1:56:a0:20:14:4e:8d:96:05:61:79:15:06
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Subject: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Label: "Entrust.net Secure Server CA"
+# Serial: 927650371
+# MD5 Fingerprint: df:f2:80:73:cc:f1:e6:61:73:fc:f5:42:e9:c5:7c:ee
+# SHA1 Fingerprint: 99:a6:9b:e6:1a:fe:88:6b:4d:2b:82:00:7c:b8:54:fc:31:7e:15:39
+# SHA256 Fingerprint: 62:f2:40:27:8c:56:4c:4d:d8:bf:7d:9d:4f:6f:36:6e:a8:94:d2:2f:5f:34:d9:89:a9:83:ac:ec:2f:ff:ed:50
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Label: "Entrust.net Premium 2048 Secure Server CA"
+# Serial: 946059622
+# MD5 Fingerprint: ba:21:ea:20:d6:dd:db:8f:c1:57:8b:40:ad:a1:fc:fc
+# SHA1 Fingerprint: 80:1d:62:d0:7b:44:9d:5c:5c:03:5c:98:ea:61:fa:44:3c:2a:58:fe
+# SHA256 Fingerprint: d1:c3:39:ea:27:84:eb:87:0f:93:4f:c5:63:4e:4a:a9:ad:55:05:01:64:01:f2:64:65:d3:7a:57:46:63:35:9f
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
+MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
+vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
+CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
+WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
+h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
+f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
+B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
+vUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
+# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
+# Label: "Baltimore CyberTrust Root"
+# Serial: 33554617
+# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4
+# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74
+# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+# Issuer: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
+# Subject: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
+# Label: "Equifax Secure Global eBusiness CA"
+# Serial: 1
+# MD5 Fingerprint: 8f:5d:77:06:27:c4:98:3c:5b:93:78:e7:d7:7d:9b:cc
+# SHA1 Fingerprint: 7e:78:4a:10:1c:82:65:cc:2d:e1:f1:6d:47:b4:40:ca:d9:0a:19:45
+# SHA256 Fingerprint: 5f:0b:62:ea:b5:e3:53:ea:65:21:65:16:58:fb:b6:53:59:f4:43:28:0a:4a:fb:d1:04:d7:7d:10:f9:f0:4c:07
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+# Issuer: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
+# Subject: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
+# Label: "Equifax Secure eBusiness CA 1"
+# Serial: 4
+# MD5 Fingerprint: 64:9c:ef:2e:44:fc:c6:8f:52:07:d0:51:73:8f:cb:3d
+# SHA1 Fingerprint: da:40:18:8b:91:89:a3:ed:ee:ae:da:97:fe:2f:9d:f5:b7:d1:8a:41
+# SHA256 Fingerprint: cf:56:ff:46:a4:a1:86:10:9d:d9:65:84:b5:ee:b5:8a:51:0c:42:75:b0:e5:f9:4f:40:bb:ae:86:5e:19:f6:73
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+# Issuer: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
+# Subject: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
+# Label: "Equifax Secure eBusiness CA 2"
+# Serial: 930140085
+# MD5 Fingerprint: aa:bf:bf:64:97:da:98:1d:6f:c6:08:3a:95:70:33:ca
+# SHA1 Fingerprint: 39:4f:f6:85:0b:06:be:52:e5:18:56:cc:10:e1:80:e8:82:b3:85:cc
+# SHA256 Fingerprint: 2f:27:4e:48:ab:a4:ac:7b:76:59:33:10:17:75:50:6d:c3:0e:e3:8e:f6:ac:d5:c0:49:32:cf:e0:41:23:42:20
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Low-Value Services Root"
+# Serial: 1
+# MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc
+# SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d
+# SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
+MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
+VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
+CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
+tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
+dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
+PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
+BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
+ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
+7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
+43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
+pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
+WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
+# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
+# Label: "AddTrust External Root"
+# Serial: 1
+# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f
+# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68
+# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Public Services Root"
+# Serial: 1
+# MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f
+# SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5
+# SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
+MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
+ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
+BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
+6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
+GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
+dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
+1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
+62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
+BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
+MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
+cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
+b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
+IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
+iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
+4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
+XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Qualified Certificates Root"
+# Serial: 1
+# MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb
+# SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf
+# SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
+MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
+EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
+BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
+xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
+87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
+2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
+WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
+0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
+A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
+pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
+ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
+aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
+hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
+hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
+P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
+iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
+xqE=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
+# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
+# Label: "Entrust Root Certification Authority"
+# Serial: 1164660820
+# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4
+# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9
+# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
+Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
+KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
+NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
+NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
+ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
+BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
+Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
+4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
+KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
+rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
+94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
+sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
+gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
+kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
+vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
+O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
+AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
+9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
+eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
+0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.
+# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.
+# Label: "GeoTrust Global CA"
+# Serial: 144470
+# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5
+# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12
+# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
+# Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
+# Label: "GeoTrust Global CA 2"
+# Serial: 1
+# MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9
+# SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d
+# SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
+IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
+R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
+PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
+Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
+TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
+5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
+S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
+2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
+EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
+EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
+/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
+A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
+abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
+I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
+4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc.
+# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc.
+# Label: "GeoTrust Universal CA"
+# Serial: 1
+# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48
+# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79
+# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
+IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
+VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
+cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
+QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
+F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
+c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
+mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
+VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
+teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
+f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
+Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
+/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
+MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
+IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
+ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
+uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
+Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
+QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
+koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
+ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
+DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
+bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
+# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
+# Label: "GeoTrust Universal CA 2"
+# Serial: 1
+# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7
+# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79
+# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
+VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
+c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
+WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
+FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
+XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
+se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
+KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
+IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
+y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
+hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
+QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
+Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
+HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
+KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
+L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
+Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
+ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
+T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
+GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
+1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
+OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
+6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
+QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+# Issuer: CN=America Online Root Certification Authority 1 O=America Online Inc.
+# Subject: CN=America Online Root Certification Authority 1 O=America Online Inc.
+# Label: "America Online Root Certification Authority 1"
+# Serial: 1
+# MD5 Fingerprint: 14:f1:08:ad:9d:fa:64:e2:89:e7:1c:cf:a8:ad:7d:5e
+# SHA1 Fingerprint: 39:21:c1:15:c1:5d:0e:ca:5c:cb:5b:c4:f0:7d:21:d8:05:0b:56:6a
+# SHA256 Fingerprint: 77:40:73:12:c6:3a:15:3d:5b:c0:0b:4e:51:75:9c:df:da:c2:37:dc:2a:33:b6:79:46:e9:8e:9b:fa:68:0a:e3
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
+hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
+1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
+OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
+2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
+O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
+AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
+Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
+LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
+oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
+MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+
+# Issuer: CN=America Online Root Certification Authority 2 O=America Online Inc.
+# Subject: CN=America Online Root Certification Authority 2 O=America Online Inc.
+# Label: "America Online Root Certification Authority 2"
+# Serial: 1
+# MD5 Fingerprint: d6:ed:3c:ca:e2:66:0f:af:10:43:0d:77:9b:04:09:bf
+# SHA1 Fingerprint: 85:b5:ff:67:9b:0c:79:96:1f:c8:6e:44:22:00:46:13:db:17:92:84
+# SHA256 Fingerprint: 7d:3b:46:5a:60:14:e5:26:c0:af:fc:ee:21:27:d2:31:17:27:ad:81:1c:26:84:2d:00:6a:f3:73:06:cc:80:bd
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
+206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
+KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
+JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
+BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
+Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
+PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
+Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
+Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
+o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
+YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
+FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
+xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
+LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
+obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
+CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
+IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
+DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
+AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
+Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
+AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
+Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
+RY8mkaKO/qk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
+# Subject: CN=AAA Certificate Services O=Comodo CA Limited
+# Label: "Comodo AAA Services root"
+# Serial: 1
+# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
+# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
+# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Secure Certificate Services O=Comodo CA Limited
+# Subject: CN=Secure Certificate Services O=Comodo CA Limited
+# Label: "Comodo Secure Services root"
+# Serial: 1
+# MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd
+# SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1
+# SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Trusted Certificate Services O=Comodo CA Limited
+# Subject: CN=Trusted Certificate Services O=Comodo CA Limited
+# Label: "Comodo Trusted Services root"
+# Serial: 1
+# MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27
+# SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd
+# SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+# Issuer: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
+# Subject: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
+# Label: "UTN DATACorp SGC Root CA"
+# Serial: 91374294542884689855167577680241077609
+# MD5 Fingerprint: b3:a5:3e:77:21:6d:ac:4a:c0:c9:fb:d5:41:3d:ca:06
+# SHA1 Fingerprint: 58:11:9f:0e:12:82:87:ea:50:fd:d9:87:45:6f:4f:78:dc:fa:d6:d4
+# SHA256 Fingerprint: 85:fb:2f:91:dd:12:27:5a:01:45:b6:36:53:4f:84:02:4a:d6:8b:69:b8:ee:88:68:4f:f7:11:37:58:05:b3:48
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+# Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
+# Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
+# Label: "UTN USERFirst Hardware Root CA"
+# Serial: 91374294542884704022267039221184531197
+# MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39
+# SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7
+# SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
+# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
+# Label: "XRamp Global CA Root"
+# Serial: 107108908803651509692980124233745014957
+# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1
+# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6
+# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
+# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
+# Label: "Go Daddy Class 2 CA"
+# Serial: 0
+# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
+# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
+# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+
+# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
+# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
+# Label: "Starfield Class 2 CA"
+# Serial: 0
+# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
+# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
+# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Label: "StartCom Certification Authority"
+# Serial: 1
+# MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16
+# SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f
+# SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert Assured ID Root CA"
+# Serial: 17154717934120587862167794914071425081
+# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72
+# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43
+# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert Global Root CA"
+# Serial: 10944719598952040374951832963794454346
+# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e
+# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36
+# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert High Assurance EV Root CA"
+# Serial: 3553400076410547919724730734378100087
+# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a
+# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25
+# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
+# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
+# Label: "GeoTrust Primary Certification Authority"
+# Serial: 32798226551256963324313806436981982369
+# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf
+# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96
+# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
+R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
+MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
+AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
+ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
+7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
+kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
+mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
+KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
+6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
+4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
+oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
+UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
+AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA"
+# Serial: 69529181992039203566298953787712940909
+# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12
+# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81
+# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
+NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
+A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
+W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
+3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
+6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
+Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
+NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
+r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
+DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
+YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
+/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
+LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
+jVaMaA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Class 3 Public Primary Certification Authority - G5"
+# Serial: 33037644167568058970164719475676101450
+# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c
+# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5
+# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
+nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
+t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
+SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
+BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
+NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
+BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
+BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
+MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
+p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
+5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
+WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
+4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
+hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
+# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
+# Label: "COMODO Certification Authority"
+# Serial: 104350513648249232941998508985834464573
+# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75
+# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b
+# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
+YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
+RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
+UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
+2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
+Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
+nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
+/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
+PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
+SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
+IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
+zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
+BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
+ZQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
+# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
+# Label: "Network Solutions Certificate Authority"
+# Serial: 116697915152937497490437556386812487904
+# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e
+# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce
+# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
+MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp
+dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV
+UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO
+ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz
+c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP
+OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl
+mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF
+BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4
+qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw
+gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu
+bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp
+dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8
+6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/
+h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
+/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
+pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
+# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
+# Label: "COMODO ECC Certification Authority"
+# Serial: 41578283867086692638256921589707938090
+# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23
+# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11
+# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
+IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
+MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
+ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
+T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
+FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
+cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
+BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
+fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
+GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
+# Subject: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
+# Label: "TC TrustCenter Class 2 CA II"
+# Serial: 941389028203453866782103406992443
+# MD5 Fingerprint: ce:78:33:5c:59:78:01:6e:18:ea:b9:36:a0:b9:2e:23
+# SHA1 Fingerprint: ae:50:83:ed:7c:f4:5c:bc:8f:61:c6:21:fe:68:5d:79:42:21:15:6e
+# SHA256 Fingerprint: e6:b8:f8:76:64:85:f8:07:ae:7f:8d:ac:16:70:46:1f:07:c0:a1:3e:ef:3a:1f:f7:17:53:8d:7a:ba:d3:91:b4
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
+tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
+uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
+XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
+8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
+5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
+kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
+GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
+ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
+au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
+hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
+dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
+# Subject: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
+# Label: "TC TrustCenter Class 3 CA II"
+# Serial: 1506523511417715638772220530020799
+# MD5 Fingerprint: 56:5f:aa:80:61:12:17:f6:67:21:e6:2b:6d:61:56:8e
+# SHA1 Fingerprint: 80:25:ef:f4:6e:70:c8:d4:72:24:65:84:fe:40:3b:8a:8d:6a:db:f5
+# SHA256 Fingerprint: 8d:a0:84:fc:f9:9c:e0:77:22:f8:9b:32:05:93:98:06:fa:5c:b8:11:e1:c8:13:f6:a1:08:c7:d3:36:b3:40:8e
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
+Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
+Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
+1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
+ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
+Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
+XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
+irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
+TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
+g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
+95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
+S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Subject: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Label: "TC TrustCenter Universal CA I"
+# Serial: 601024842042189035295619584734726
+# MD5 Fingerprint: 45:e1:a5:72:c5:a9:36:64:40:9e:f5:e4:58:84:67:8c
+# SHA1 Fingerprint: 6b:2f:34:ad:89:58:be:62:fd:b0:6b:5c:ce:bb:9d:d9:4f:4e:39:f3
+# SHA256 Fingerprint: eb:f3:c0:2a:87:89:b1:fb:7d:51:19:95:d6:63:b7:29:06:d9:13:ce:0d:5e:10:56:8a:8a:77:e2:58:61:67:e7
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
+MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
+R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
+VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
+JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
+fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
+jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
+wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
+fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
+VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
+CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
+7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
+8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
+ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
+2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
+
+# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc
+# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc
+# Label: "Cybertrust Global Root"
+# Serial: 4835703278459682877484360
+# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1
+# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6
+# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG
+A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh
+bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE
+ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS
+b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5
+7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS
+J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y
+HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP
+t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz
+FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY
+XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
+MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw
+hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js
+MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA
+A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj
+Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx
+XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o
+omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc
+A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
+# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
+# Label: "GeoTrust Primary Certification Authority - G3"
+# Serial: 28809105769928564313984085209975885599
+# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05
+# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd
+# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
+mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
+MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
+BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
+BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
+hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
+5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
+JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
+DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
+huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
+AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
+zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
+kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
+SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
+spki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA - G2"
+# Serial: 71758320672825410020661621085256472406
+# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f
+# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12
+# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
+IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
+BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
+MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
+YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
+dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
+BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
+papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
+DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
+KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
+XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA - G3"
+# Serial: 127614157056681299805556476275995414779
+# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31
+# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2
+# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
+rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
+BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
+Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
+LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
+MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
+ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
+gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
+YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
+b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
+9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
+zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
+OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
+HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
+2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
+oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
+KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
+m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
+MdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
+# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
+# Label: "GeoTrust Primary Certification Authority - G2"
+# Serial: 80682863203381065782177908751794619243
+# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a
+# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0
+# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
+MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
+KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
+MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
+NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
+BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
+So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
+tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
+CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
+qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
+rD6ogRLQy7rQkgu2npaqBA+K
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Universal Root Certification Authority"
+# Serial: 85209574734084581917763752644031726877
+# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19
+# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54
+# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
+vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
+ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
+IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
+IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
+bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
+9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
+H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
+LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
+/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
+rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
+WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
+exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
+sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
+seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
+4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
+lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
+7M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Class 3 Public Primary Certification Authority - G4"
+# Serial: 63143484348153506665311985501458640051
+# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41
+# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a
+# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
+U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
+SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
+biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
+GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
+fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
+aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
+aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
+kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
+4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
+FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
+# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
+# Label: "GlobalSign Root CA - R3"
+# Serial: 4835703278459759426209954
+# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
+# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
+# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
+MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
+RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
+gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
+KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
+QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
+XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
+LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
+RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
+jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
+6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
+mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
+Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
+WD9f
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Subject: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Label: "TC TrustCenter Universal CA III"
+# Serial: 2010889993983507346460533407902964
+# MD5 Fingerprint: 9f:dd:db:ab:ff:8e:ff:45:21:5f:f0:6c:9d:8f:fe:2b
+# SHA1 Fingerprint: 96:56:cd:7b:57:96:98:95:d0:e1:41:46:68:06:fb:b8:c6:11:06:87
+# SHA256 Fingerprint: 30:9b:4a:87:f6:ca:56:c9:31:69:aa:a9:9c:6d:98:88:54:d7:89:2b:d5:43:7e:2d:07:b2:9c:be:da:55:d3:5d
+-----BEGIN CERTIFICATE-----
+MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy
+MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl
+ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm
+BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF
+5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv
+DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v
+zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT
+yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj
+dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh
+MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI
+4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz
+dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY
+aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G
+DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
+CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH
+LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
+# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
+# Label: "Go Daddy Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01
+# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b
+# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
+EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
+ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
+NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
+EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
+AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
+E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
+/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
+DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
+GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
+tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
+AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
+WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
+9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
+gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
+2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
+4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Label: "Starfield Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96
+# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e
+# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
+ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
+MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
+aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
+Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
+nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
+HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
+Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
+dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
+HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
+CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
+sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
+4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
+8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
+mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Label: "Starfield Services Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2
+# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f
+# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
+ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
+VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
+ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
+dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
+OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
+8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
+Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
+hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
+6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
+AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
+bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
+ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
+qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
+0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
+sSi6
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Commercial O=AffirmTrust
+# Subject: CN=AffirmTrust Commercial O=AffirmTrust
+# Label: "AffirmTrust Commercial"
+# Serial: 8608355977964138876
+# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7
+# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7
+# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
+Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
+ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
+MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
+yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
+VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
+nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
+XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
+vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
+Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
+N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
+nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Networking O=AffirmTrust
+# Subject: CN=AffirmTrust Networking O=AffirmTrust
+# Label: "AffirmTrust Networking"
+# Serial: 8957382827206547757
+# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f
+# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f
+# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
+YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
+kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
+QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
+6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
+yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
+QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
+tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
+QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
+Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
+olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
+x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Premium O=AffirmTrust
+# Subject: CN=AffirmTrust Premium O=AffirmTrust
+# Label: "AffirmTrust Premium"
+# Serial: 7893706540734352110
+# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57
+# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27
+# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
+dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
+A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
+cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
+qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
+JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
+s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
+HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
+70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
+V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
+qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
+5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
+C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
+OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
+FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
+KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
+8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
+MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
+0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
+u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
+u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
+YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
+GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
+RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
+KeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust
+# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust
+# Label: "AffirmTrust Premium ECC"
+# Serial: 8401224907861490260
+# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d
+# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb
+# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
+cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
+BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
+VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
+0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
+ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
+A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
+aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
+flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Label: "StartCom Certification Authority"
+# Serial: 45
+# MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16
+# SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0
+# SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
+ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
+ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
+aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
+YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
+c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
+d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
+CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
+wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
+Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
+0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
+pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
+CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
+P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
+1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
+KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
+8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
+fyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd.
+# Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd.
+# Label: "StartCom Certification Authority G2"
+# Serial: 59
+# MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64
+# SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17
+# SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
+OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
+A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
+JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
+vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
+D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
+Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
+RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
+HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
+nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
+0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
+UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
+Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
+TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
+BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
+UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
+6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
+9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
+HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
+wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
+XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
+IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
+hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
+so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+
+# Issuer: O=Digital Signature Trust Co., CN=DST Root CA X3
+# Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
+# Label: "IdenTrust DST Root CA X3"
+# Serial: 44AFB080D6A327BA893039862EF8406B
+# MD5 Fingerprint: 41:03:52:DC:0F:F7:50:1B:16:F0:02:8E:BA:6F:45:C5
+# SHA1 Fingerprint: DA:C9:02:4F:54:D8:F6:DF:94:93:5F:B1:73:26:38:CA:6A:D7:7C:13
+# SHA256 Fingerprint: 06:87:26:03:31:A7:24:03:D9:09:F1:05:E6:9B:CF:0D:32:E1:BD:24:93:FF:C6:D9:20:6D:11:BC:D6:77:07:39
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
+rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
+OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
+xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
+7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
+aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
+SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
+ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
+AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
+R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
+JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
+Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Global Root G2, OU=www.digicert.com, O=DigiCert Inc, C=US
+# Subject: CN=DigiCert Global Root G2, OU=www.digicert.com, O=DigiCert Inc, C=US
+# Serial: 33af1e6a711a9a0bb2864b11d09fae5
+# MD5 Fingerprint: E4:A6:8A:C8:54:AC:52:42:46:0A:FD:72:48:1B:2A:44
+# SHA1 Fingerprint: DF:3C:24:F9:BF:D6:66:76:1B:26:80:73:FE:06:D1:CC:8D:4F:82:A4
+# SHA256 Fingerprint: CB:3C:CB:B7:60:31:E5:E0:13:8F:8D:D3:9A:23:F9:DE:47:FF:C3:5E:43:C1:14:4C:EA:27:D4:6A:5A:B1:CB:5F
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
+MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
+2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
+1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
+q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
+tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
+vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
+5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
+1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
+NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
+Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
+8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
+pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
diff --git a/python2/httplib2/iri2uri.py b/python2/httplib2/iri2uri.py
new file mode 100644
index 0000000..d88c91f
--- /dev/null
+++ b/python2/httplib2/iri2uri.py
@@ -0,0 +1,110 @@
+"""
+iri2uri
+
+Converts an IRI to a URI.
+
+"""
+__author__ = "Joe Gregorio (joe@bitworking.org)"
+__copyright__ = "Copyright 2006, Joe Gregorio"
+__contributors__ = []
+__version__ = "1.0.0"
+__license__ = "MIT"
+__history__ = """
+"""
+
+import urlparse
+
+
+# Convert an IRI to a URI following the rules in RFC 3987
+#
+# The characters we need to enocde and escape are defined in the spec:
+#
+# iprivate =  %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD
+# ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
+#         / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
+#         / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
+#         / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
+#         / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
+#         / %xD0000-DFFFD / %xE1000-EFFFD
+
+escape_range = [
+    (0xA0, 0xD7FF),
+    (0xE000, 0xF8FF),
+    (0xF900, 0xFDCF),
+    (0xFDF0, 0xFFEF),
+    (0x10000, 0x1FFFD),
+    (0x20000, 0x2FFFD),
+    (0x30000, 0x3FFFD),
+    (0x40000, 0x4FFFD),
+    (0x50000, 0x5FFFD),
+    (0x60000, 0x6FFFD),
+    (0x70000, 0x7FFFD),
+    (0x80000, 0x8FFFD),
+    (0x90000, 0x9FFFD),
+    (0xA0000, 0xAFFFD),
+    (0xB0000, 0xBFFFD),
+    (0xC0000, 0xCFFFD),
+    (0xD0000, 0xDFFFD),
+    (0xE1000, 0xEFFFD),
+    (0xF0000, 0xFFFFD),
+    (0x100000, 0x10FFFD),
+]
+
+def encode(c):
+    retval = c
+    i = ord(c)
+    for low, high in escape_range:
+        if i < low:
+            break
+        if i >= low and i <= high:
+            retval = "".join(["%%%2X" % ord(o) for o in c.encode('utf-8')])
+            break
+    return retval
+
+
+def iri2uri(uri):
+    """Convert an IRI to a URI. Note that IRIs must be
+    passed in a unicode strings. That is, do not utf-8 encode
+    the IRI before passing it into the function."""
+    if isinstance(uri ,unicode):
+        (scheme, authority, path, query, fragment) = urlparse.urlsplit(uri)
+        authority = authority.encode('idna')
+        # For each character in 'ucschar' or 'iprivate'
+        #  1. encode as utf-8
+        #  2. then %-encode each octet of that utf-8
+        uri = urlparse.urlunsplit((scheme, authority, path, query, fragment))
+        uri = "".join([encode(c) for c in uri])
+    return uri
+
+if __name__ == "__main__":
+    import unittest
+
+    class Test(unittest.TestCase):
+
+        def test_uris(self):
+            """Test that URIs are invariant under the transformation."""
+            invariant = [
+                u"ftp://ftp.is.co.za/rfc/rfc1808.txt",
+                u"http://www.ietf.org/rfc/rfc2396.txt",
+                u"ldap://[2001:db8::7]/c=GB?objectClass?one",
+                u"mailto:John.Doe@example.com",
+                u"news:comp.infosystems.www.servers.unix",
+                u"tel:+1-816-555-1212",
+                u"telnet://192.0.2.16:80/",
+                u"urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ]
+            for uri in invariant:
+                self.assertEqual(uri, iri2uri(uri))
+
+        def test_iri(self):
+            """ Test that the right type of escaping is done for each part of the URI."""
+            self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri(u"http://\N{COMET}.com/\N{COMET}"))
+            self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri(u"http://bitworking.org/?fred=\N{COMET}"))
+            self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri(u"http://bitworking.org/#\N{COMET}"))
+            self.assertEqual("#%E2%98%84", iri2uri(u"#\N{COMET}"))
+            self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))
+            self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")))
+            self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(u"/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8')))
+
+    unittest.main()
+
+
diff --git a/python2/httplib2/socks.py b/python2/httplib2/socks.py
new file mode 100644
index 0000000..dbbe511
--- /dev/null
+++ b/python2/httplib2/socks.py
@@ -0,0 +1,448 @@
+"""SocksiPy - Python SOCKS module.
+Version 1.00
+
+Copyright 2006 Dan-Haim. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of Dan Haim nor the names of his contributors may be used
+   to endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY DAN HAIM "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 DAN HAIM OR HIS 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, 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 DAMANGE.
+
+
+This module provides a standard socket-like interface for Python
+for tunneling connections through SOCKS proxies.
+
+"""
+
+"""
+
+Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
+for use in PyLoris (http://pyloris.sourceforge.net/)
+
+Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
+mainly to merge bug fixes found in Sourceforge
+
+"""
+
+import base64
+import socket
+import struct
+import sys
+
+if getattr(socket, 'socket', None) is None:
+    raise ImportError('socket.socket missing, proxy support unusable')
+
+PROXY_TYPE_SOCKS4 = 1
+PROXY_TYPE_SOCKS5 = 2
+PROXY_TYPE_HTTP = 3
+PROXY_TYPE_HTTP_NO_TUNNEL = 4
+
+_defaultproxy = None
+_orgsocket = socket.socket
+
+class ProxyError(Exception): pass
+class GeneralProxyError(ProxyError): pass
+class Socks5AuthError(ProxyError): pass
+class Socks5Error(ProxyError): pass
+class Socks4Error(ProxyError): pass
+class HTTPError(ProxyError): pass
+
+_generalerrors = ("success",
+    "invalid data",
+    "not connected",
+    "not available",
+    "bad proxy type",
+    "bad input")
+
+_socks5errors = ("succeeded",
+    "general SOCKS server failure",
+    "connection not allowed by ruleset",
+    "Network unreachable",
+    "Host unreachable",
+    "Connection refused",
+    "TTL expired",
+    "Command not supported",
+    "Address type not supported",
+    "Unknown error")
+
+_socks5autherrors = ("succeeded",
+    "authentication is required",
+    "all offered authentication methods were rejected",
+    "unknown username or invalid password",
+    "unknown error")
+
+_socks4errors = ("request granted",
+    "request rejected or failed",
+    "request rejected because SOCKS server cannot connect to identd on the client",
+    "request rejected because the client program and identd report different user-ids",
+    "unknown error")
+
+def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
+    """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
+    Sets a default proxy which all further socksocket objects will use,
+    unless explicitly changed.
+    """
+    global _defaultproxy
+    _defaultproxy = (proxytype, addr, port, rdns, username, password)
+
+def wrapmodule(module):
+    """wrapmodule(module)
+    Attempts to replace a module's socket library with a SOCKS socket. Must set
+    a default proxy using setdefaultproxy(...) first.
+    This will only work on modules that import socket directly into the namespace;
+    most of the Python Standard Library falls into this category.
+    """
+    if _defaultproxy != None:
+        module.socket.socket = socksocket
+    else:
+        raise GeneralProxyError((4, "no proxy specified"))
+
+class socksocket(socket.socket):
+    """socksocket([family[, type[, proto]]]) -> socket object
+    Open a SOCKS enabled socket. The parameters are the same as
+    those of the standard socket init. In order for SOCKS to work,
+    you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
+    """
+
+    def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
+        _orgsocket.__init__(self, family, type, proto, _sock)
+        if _defaultproxy != None:
+            self.__proxy = _defaultproxy
+        else:
+            self.__proxy = (None, None, None, None, None, None)
+        self.__proxysockname = None
+        self.__proxypeername = None
+        self.__httptunnel = True
+
+    def __recvall(self, count):
+        """__recvall(count) -> data
+        Receive EXACTLY the number of bytes requested from the socket.
+        Blocks until the required number of bytes have been received.
+        """
+        data = self.recv(count)
+        while len(data) < count:
+            d = self.recv(count-len(data))
+            if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
+            data = data + d
+        return data
+
+    def sendall(self, content, *args):
+        """ override socket.socket.sendall method to rewrite the header
+        for non-tunneling proxies if needed
+        """
+        if not self.__httptunnel:
+            content = self.__rewriteproxy(content)
+        return super(socksocket, self).sendall(content, *args)
+
+    def __rewriteproxy(self, header):
+        """ rewrite HTTP request headers to support non-tunneling proxies
+        (i.e. those which do not support the CONNECT method).
+        This only works for HTTP (not HTTPS) since HTTPS requires tunneling.
+        """
+        host, endpt = None, None
+        hdrs = header.split("\r\n")
+        for hdr in hdrs:
+            if hdr.lower().startswith("host:"):
+                host = hdr
+            elif hdr.lower().startswith("get") or hdr.lower().startswith("post"):
+                endpt = hdr
+        if host and endpt:
+            hdrs.remove(host)
+            hdrs.remove(endpt)
+            host = host.split(" ")[1]
+            endpt = endpt.split(" ")
+            if (self.__proxy[4] != None and self.__proxy[5] != None):
+                hdrs.insert(0, self.__getauthheader())
+            hdrs.insert(0, "Host: %s" % host)
+            hdrs.insert(0, "%s http://%s%s %s" % (endpt[0], host, endpt[1], endpt[2]))
+        return "\r\n".join(hdrs)
+
+    def __getauthheader(self):
+        auth = self.__proxy[4] + ":" + self.__proxy[5]
+        return "Proxy-Authorization: Basic " + base64.b64encode(auth)
+
+    def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None, headers=None):
+        """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
+        Sets the proxy to be used.
+        proxytype -    The type of the proxy to be used. Three types
+                are supported: PROXY_TYPE_SOCKS4 (including socks4a),
+                PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
+        addr -        The address of the server (IP or DNS).
+        port -        The port of the server. Defaults to 1080 for SOCKS
+                servers and 8080 for HTTP proxy servers.
+        rdns -        Should DNS queries be preformed on the remote side
+                (rather than the local side). The default is True.
+                Note: This has no effect with SOCKS4 servers.
+        username -    Username to authenticate with to the server.
+                The default is no authentication.
+        password -    Password to authenticate with to the server.
+                Only relevant when username is also provided.
+        headers -     Additional or modified headers for the proxy connect request.
+        """
+        self.__proxy = (proxytype, addr, port, rdns, username, password, headers)
+
+    def __negotiatesocks5(self, destaddr, destport):
+        """__negotiatesocks5(self,destaddr,destport)
+        Negotiates a connection through a SOCKS5 server.
+        """
+        # First we'll send the authentication packages we support.
+        if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
+            # The username/password details were supplied to the
+            # setproxy method so we support the USERNAME/PASSWORD
+            # authentication (in addition to the standard none).
+            self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
+        else:
+            # No username/password were entered, therefore we
+            # only support connections with no authentication.
+            self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
+        # We'll receive the server's response to determine which
+        # method was selected
+        chosenauth = self.__recvall(2)
+        if chosenauth[0:1] != chr(0x05).encode():
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        # Check the chosen authentication method
+        if chosenauth[1:2] == chr(0x00).encode():
+            # No authentication is required
+            pass
+        elif chosenauth[1:2] == chr(0x02).encode():
+            # Okay, we need to perform a basic username/password
+            # authentication.
+            self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
+            authstat = self.__recvall(2)
+            if authstat[0:1] != chr(0x01).encode():
+                # Bad response
+                self.close()
+                raise GeneralProxyError((1, _generalerrors[1]))
+            if authstat[1:2] != chr(0x00).encode():
+                # Authentication failed
+                self.close()
+                raise Socks5AuthError((3, _socks5autherrors[3]))
+            # Authentication succeeded
+        else:
+            # Reaching here is always bad
+            self.close()
+            if chosenauth[1] == chr(0xFF).encode():
+                raise Socks5AuthError((2, _socks5autherrors[2]))
+            else:
+                raise GeneralProxyError((1, _generalerrors[1]))
+        # Now we can request the actual connection
+        req = struct.pack('BBB', 0x05, 0x01, 0x00)
+        # If the given destination address is an IP address, we'll
+        # use the IPv4 address request even if remote resolving was specified.
+        try:
+            ipaddr = socket.inet_aton(destaddr)
+            req = req + chr(0x01).encode() + ipaddr
+        except socket.error:
+            # Well it's not an IP number,  so it's probably a DNS name.
+            if self.__proxy[3]:
+                # Resolve remotely
+                ipaddr = None
+                req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr.encode()
+            else:
+                # Resolve locally
+                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
+                req = req + chr(0x01).encode() + ipaddr
+        req = req + struct.pack(">H", destport)
+        self.sendall(req)
+        # Get the response
+        resp = self.__recvall(4)
+        if resp[0:1] != chr(0x05).encode():
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        elif resp[1:2] != chr(0x00).encode():
+            # Connection failed
+            self.close()
+            if ord(resp[1:2])<=8:
+                raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
+            else:
+                raise Socks5Error((9, _socks5errors[9]))
+        # Get the bound address/port
+        elif resp[3:4] == chr(0x01).encode():
+            boundaddr = self.__recvall(4)
+        elif resp[3:4] == chr(0x03).encode():
+            resp = resp + self.recv(1)
+            boundaddr = self.__recvall(ord(resp[4:5]))
+        else:
+            self.close()
+            raise GeneralProxyError((1,_generalerrors[1]))
+        boundport = struct.unpack(">H", self.__recvall(2))[0]
+        self.__proxysockname = (boundaddr, boundport)
+        if ipaddr != None:
+            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
+        else:
+            self.__proxypeername = (destaddr, destport)
+
+    def getproxysockname(self):
+        """getsockname() -> address info
+        Returns the bound IP address and port number at the proxy.
+        """
+        return self.__proxysockname
+
+    def getproxypeername(self):
+        """getproxypeername() -> address info
+        Returns the IP and port number of the proxy.
+        """
+        return _orgsocket.getpeername(self)
+
+    def getpeername(self):
+        """getpeername() -> address info
+        Returns the IP address and port number of the destination
+        machine (note: getproxypeername returns the proxy)
+        """
+        return self.__proxypeername
+
+    def __negotiatesocks4(self,destaddr,destport):
+        """__negotiatesocks4(self,destaddr,destport)
+        Negotiates a connection through a SOCKS4 server.
+        """
+        # Check if the destination address provided is an IP address
+        rmtrslv = False
+        try:
+            ipaddr = socket.inet_aton(destaddr)
+        except socket.error:
+            # It's a DNS name. Check where it should be resolved.
+            if self.__proxy[3]:
+                ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
+                rmtrslv = True
+            else:
+                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
+        # Construct the request packet
+        req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
+        # The username parameter is considered userid for SOCKS4
+        if self.__proxy[4] != None:
+            req = req + self.__proxy[4]
+        req = req + chr(0x00).encode()
+        # DNS name if remote resolving is required
+        # NOTE: This is actually an extension to the SOCKS4 protocol
+        # called SOCKS4A and may not be supported in all cases.
+        if rmtrslv:
+            req = req + destaddr + chr(0x00).encode()
+        self.sendall(req)
+        # Get the response from the server
+        resp = self.__recvall(8)
+        if resp[0:1] != chr(0x00).encode():
+            # Bad data
+            self.close()
+            raise GeneralProxyError((1,_generalerrors[1]))
+        if resp[1:2] != chr(0x5A).encode():
+            # Server returned an error
+            self.close()
+            if ord(resp[1:2]) in (91, 92, 93):
+                self.close()
+                raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
+            else:
+                raise Socks4Error((94, _socks4errors[4]))
+        # Get the bound address/port
+        self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
+        if rmtrslv != None:
+            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
+        else:
+            self.__proxypeername = (destaddr, destport)
+
+    def __negotiatehttp(self, destaddr, destport):
+        """__negotiatehttp(self,destaddr,destport)
+        Negotiates a connection through an HTTP server.
+        """
+        # If we need to resolve locally, we do this now
+        if not self.__proxy[3]:
+            addr = socket.gethostbyname(destaddr)
+        else:
+            addr = destaddr
+        headers =  ["CONNECT ", addr, ":", str(destport), " HTTP/1.1\r\n"]
+        wrote_host_header = False
+        wrote_auth_header = False
+        if self.__proxy[6] != None:
+            for key, val in self.__proxy[6].iteritems():
+                headers += [key, ": ", val, "\r\n"]
+                wrote_host_header = (key.lower() == "host")
+                wrote_auth_header = (key.lower() == "proxy-authorization")
+        if not wrote_host_header:
+            headers += ["Host: ", destaddr, "\r\n"]
+        if not wrote_auth_header:
+            if (self.__proxy[4] != None and self.__proxy[5] != None):
+                headers += [self.__getauthheader(), "\r\n"]
+        headers.append("\r\n")
+        self.sendall("".join(headers).encode())
+        # We read the response until we get the string "\r\n\r\n"
+        resp = self.recv(1)
+        while resp.find("\r\n\r\n".encode()) == -1:
+            resp = resp + self.recv(1)
+        # We just need the first line to check if the connection
+        # was successful
+        statusline = resp.splitlines()[0].split(" ".encode(), 2)
+        if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        try:
+            statuscode = int(statusline[1])
+        except ValueError:
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        if statuscode != 200:
+            self.close()
+            raise HTTPError((statuscode, statusline[2]))
+        self.__proxysockname = ("0.0.0.0", 0)
+        self.__proxypeername = (addr, destport)
+
+    def connect(self, destpair):
+        """connect(self, despair)
+        Connects to the specified destination through a proxy.
+        destpar - A tuple of the IP/DNS address and the port number.
+        (identical to socket's connect).
+        To select the proxy server use setproxy().
+        """
+        # Do a minimal input check first
+        if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (not isinstance(destpair[0], basestring)) or (type(destpair[1]) != int):
+            raise GeneralProxyError((5, _generalerrors[5]))
+        if self.__proxy[0] == PROXY_TYPE_SOCKS5:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 1080
+            _orgsocket.connect(self, (self.__proxy[1], portnum))
+            self.__negotiatesocks5(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 1080
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
+            self.__negotiatesocks4(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_HTTP:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 8080
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
+            self.__negotiatehttp(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_HTTP_NO_TUNNEL:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 8080
+            _orgsocket.connect(self,(self.__proxy[1],portnum))
+            if destpair[1] == 443:
+                self.__negotiatehttp(destpair[0],destpair[1])
+            else:
+                self.__httptunnel = False
+        elif self.__proxy[0] == None:
+            _orgsocket.connect(self, (destpair[0], destpair[1]))
+        else:
+            raise GeneralProxyError((4, _generalerrors[4]))
diff --git a/python2/httplib2/test/__init__.py b/python2/httplib2/test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python2/httplib2/test/__init__.py
diff --git a/python2/httplib2/test/brokensocket/socket.py b/python2/httplib2/test/brokensocket/socket.py
new file mode 100644
index 0000000..ff7c0b7
--- /dev/null
+++ b/python2/httplib2/test/brokensocket/socket.py
@@ -0,0 +1 @@
+from realsocket import gaierror, error, getaddrinfo, SOCK_STREAM
diff --git a/python2/httplib2/test/functional/test_proxies.py b/python2/httplib2/test/functional/test_proxies.py
new file mode 100644
index 0000000..e11369d
--- /dev/null
+++ b/python2/httplib2/test/functional/test_proxies.py
@@ -0,0 +1,89 @@
+from __future__ import print_function
+import unittest
+import errno
+import os
+import signal
+import subprocess
+import tempfile
+
+import nose
+
+import httplib2
+from httplib2 import socks
+from httplib2.test import miniserver
+
+tinyproxy_cfg = """
+User "%(user)s"
+Port %(port)s
+Listen 127.0.0.1
+PidFile "%(pidfile)s"
+LogFile "%(logfile)s"
+MaxClients 2
+StartServers 1
+LogLevel Info
+"""
+
+
+class FunctionalProxyHttpTest(unittest.TestCase):
+    def setUp(self):
+        if not socks:
+            raise nose.SkipTest('socks module unavailable')
+        if not subprocess:
+            raise nose.SkipTest('subprocess module unavailable')
+
+        # start a short-lived miniserver so we can get a likely port
+        # for the proxy
+        self.httpd, self.proxyport = miniserver.start_server(
+            miniserver.ThisDirHandler)
+        self.httpd.shutdown()
+        self.httpd, self.port = miniserver.start_server(
+            miniserver.ThisDirHandler)
+
+        self.pidfile = tempfile.mktemp()
+        self.logfile = tempfile.mktemp()
+        fd, self.conffile = tempfile.mkstemp()
+        f = os.fdopen(fd, 'w')
+        our_cfg = tinyproxy_cfg % {'user': os.getlogin(),
+                                   'pidfile': self.pidfile,
+                                   'port': self.proxyport,
+                                   'logfile': self.logfile}
+        f.write(our_cfg)
+        f.close()
+        try:
+            # TODO use subprocess.check_call when 2.4 is dropped
+            ret = subprocess.call(['tinyproxy', '-c', self.conffile])
+            self.assertEqual(0, ret)
+        except OSError as e:
+            if e.errno == errno.ENOENT:
+                raise nose.SkipTest('tinyproxy not available')
+            raise
+
+    def tearDown(self):
+        self.httpd.shutdown()
+        try:
+            pid = int(open(self.pidfile).read())
+            os.kill(pid, signal.SIGTERM)
+        except OSError as e:
+            if e.errno == errno.ESRCH:
+                print('\n\n\nTinyProxy Failed to start, log follows:')
+                print(open(self.logfile).read())
+                print('end tinyproxy log\n\n\n')
+            raise
+        map(os.unlink, (self.pidfile,
+                        self.logfile,
+                        self.conffile))
+
+    def testSimpleProxy(self):
+        proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP,
+                                        'localhost', self.proxyport)
+        client = httplib2.Http(proxy_info=proxy_info)
+        src = 'miniserver.py'
+        response, body = client.request('http://localhost:%d/%s' %
+                                        (self.port, src))
+        self.assertEqual(response.status, 200)
+        self.assertEqual(body, open(os.path.join(miniserver.HERE, src)).read())
+        lf = open(self.logfile).read()
+        expect = ('Established connection to host "127.0.0.1" '
+                  'using file descriptor')
+        self.assertTrue(expect in lf,
+                        'tinyproxy did not proxy a request for miniserver')
diff --git a/python2/httplib2/test/miniserver.py b/python2/httplib2/test/miniserver.py
new file mode 100644
index 0000000..f72ecca
--- /dev/null
+++ b/python2/httplib2/test/miniserver.py
@@ -0,0 +1,113 @@
+import logging
+import os
+import select
+import SimpleHTTPServer
+import socket
+import SocketServer
+import threading
+
+HERE = os.path.dirname(__file__)
+logger = logging.getLogger(__name__)
+
+
+class ThisDirHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+    def translate_path(self, path):
+        path = path.split('?', 1)[0].split('#', 1)[0]
+        return os.path.join(HERE, *filter(None, path.split('/')))
+
+    def log_message(self, s, *args):
+        # output via logging so nose can catch it
+        logger.info(s, *args)
+
+
+class ShutdownServer(SocketServer.TCPServer):
+    """Mixin that allows serve_forever to be shut down.
+
+    The methods in this mixin are backported from SocketServer.py in the Python
+    2.6.4 standard library. The mixin is unnecessary in 2.6 and later, when
+    BaseServer supports the shutdown method directly.
+    """
+
+    def __init__(self, use_tls, *args, **kwargs):
+        self.__use_tls = use_tls
+        SocketServer.TCPServer.__init__(self, *args, **kwargs)
+        self.__is_shut_down = threading.Event()
+        self.__serving = False
+
+    def server_bind(self):
+        SocketServer.TCPServer.server_bind(self)
+        if self.__use_tls:
+            import ssl
+            self.socket = ssl.wrap_socket(self.socket,
+                    os.path.join(os.path.dirname(__file__), 'server.key'),
+                    os.path.join(os.path.dirname(__file__), 'server.pem'),
+                    True
+            )
+
+
+    def serve_forever(self, poll_interval=0.1):
+        """Handle one request at a time until shutdown.
+
+        Polls for shutdown every poll_interval seconds. Ignores
+        self.timeout. If you need to do periodic tasks, do them in
+        another thread.
+        """
+        self.__serving = True
+        self.__is_shut_down.clear()
+        while self.__serving:
+            r, w, e = select.select([self.socket], [], [], poll_interval)
+            if r:
+                self._handle_request_noblock()
+        self.__is_shut_down.set()
+
+    def shutdown(self):
+        """Stops the serve_forever loop.
+
+        Blocks until the loop has finished. This must be called while
+        serve_forever() is running in another thread, or it will deadlock.
+        """
+        self.__serving = False
+        self.__is_shut_down.wait()
+
+    def handle_request(self):
+        """Handle one request, possibly blocking.
+
+        Respects self.timeout.
+        """
+        # Support people who used socket.settimeout() to escape
+        # handle_request before self.timeout was available.
+        timeout = self.socket.gettimeout()
+        if timeout is None:
+            timeout = self.timeout
+        elif self.timeout is not None:
+            timeout = min(timeout, self.timeout)
+        fd_sets = select.select([self], [], [], timeout)
+        if not fd_sets[0]:
+            self.handle_timeout()
+            return
+        self._handle_request_noblock()
+
+    def _handle_request_noblock(self):
+        """Handle one request, without blocking.
+
+        I assume that select.select has returned that the socket is
+        readable before this function was called, so there should be
+        no risk of blocking in get_request().
+        """
+        try:
+            request, client_address = self.get_request()
+        except socket.error:
+            return
+        if self.verify_request(request, client_address):
+            try:
+                self.process_request(request, client_address)
+            except:
+                self.handle_error(request, client_address)
+                self.close_request(request)
+
+
+def start_server(handler, use_tls=False):
+    httpd = ShutdownServer(use_tls, ("", 0), handler)
+    threading.Thread(target=httpd.serve_forever).start()
+    _, port = httpd.socket.getsockname()
+    return httpd, port
diff --git a/python2/httplib2/test/other_cacerts.txt b/python2/httplib2/test/other_cacerts.txt
new file mode 100644
index 0000000..b2c2488
--- /dev/null
+++ b/python2/httplib2/test/other_cacerts.txt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAe+gAwIBAgIJAIw94zvO7fk1MA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV
+BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNjA2MDQwMjMxMTRaFw0yNjA2MDIwMjMx
+MTRaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAK3YNcDIwK/wlTa0/iBARvDFOncQ6Jkk+Ymql1HXny7v
+mWPFWeLXEW+Zw1NrQEx/SIUGvxpRA+QyhTOhu2Gcwvtqilix/dHgaKgqWEcRYu8m
+L70uVDPVgB/kfNI8bpXM1Mz8Crjo0tHw5oUSD3wny8SyT6CYlXVmF923L8c2zdN9
+n9blFgYwxBq2+q+mqOiDErMFbwHES8FNBSWGBXdE1xjBdITtlfeHezmJhj/ylPW1
+7v8HInsv/WqU9DcJYlFxSnK0SZCLFBM/31Ez8O1gCfMlDUFvJoo59GyFqukUjuO1
+uB85wpu27gtcLm/J9X1Md71IxbDupV7a0dDoTvbhO4kCAwEAAaNQME4wHQYDVR0O
+BBYEFIHgAmwppZSKLz2peyFSO2kwVobNMB8GA1UdIwQYMBaAFIHgAmwppZSKLz2p
+eyFSO2kwVobNMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAJxz+AU/
+Iq8fMEStJ0BgPP1N86W9Jpb7aPMFCYTEZ+nd8hFPhPs4//55J0yIve+1I43MNFFz
+yflwwCzrIIhZdkvbsyea6CmlTo4jBc4+ihaDGobYnoNzFhavC47n5kYqJ8Ikyb2W
+OMrmNRiaTeSBl0wQmftnnQCbonenjmE1LDuJtE6bCwfFjfLbMxwdWtp/ymOlXsb5
+80XcWwcqc12UHWexYwHFzEJmDfncak/8tjHBsLWMJg5p2sVTY9kVt7TYgSIl+mFb
+4WVGrqZd2uTlJkRQQ4pCl+D+PKwadHuV6YI7oxkeajjcHCgbK/ANwW28MXYho6t6
+aWVIN4bWHrZ38kE=
+-----END CERTIFICATE-----
diff --git a/python2/httplib2/test/server.key b/python2/httplib2/test/server.key
new file mode 100644
index 0000000..4c21fac
--- /dev/null
+++ b/python2/httplib2/test/server.key
@@ -0,0 +1,146 @@
+Private TLS server key file used for HTTPS-related unit tests
+-------------------------------------------------------------
+
+Public Key Info:
+        Public Key Algorithm: RSA
+        Key Security Level: Medium (2048 bits)
+
+modulus:
+        00:cc:fb:f1:c5:de:29:29:40:3f:c4:9f:af:da:f6:be
+        27:f4:6a:00:ae:5a:f2:99:c3:5f:7a:e6:9b:cf:d9:08
+        34:01:9b:ea:fb:da:b5:d0:b5:b2:4e:60:b4:0d:8d:05
+        57:e4:2e:04:d4:57:1a:58:3c:0b:3a:ed:67:a3:13:31
+        58:0a:c2:eb:fd:d6:27:ee:07:95:30:35:b5:98:91:c7
+        a5:9b:be:a9:7e:ae:fd:73:c3:6b:21:bc:52:f8:ef:71
+        db:d3:b1:cd:51:df:b3:37:b3:fd:7d:ae:7e:02:38:be
+        8e:6f:45:55:e5:6d:8a:02:cb:36:c4:17:7a:ea:24:9a
+        72:8d:1e:75:03:3a:6f:c4:cb:a0:3a:50:56:32:bb:4c
+        e2:ea:74:f0:96:31:74:b2:c1:03:e8:c3:d4:a3:59:fc
+        7a:cc:68:35:c4:97:eb:aa:46:fa:64:c3:f9:55:59:22
+        b5:2b:3c:96:84:c6:d2:7d:b4:9f:b9:9c:af:d1:20:30
+        7c:e8:60:4e:ee:0a:60:a0:9d:4e:8a:d8:34:74:bd:f2
+        40:bc:d7:c2:b3:1a:b2:bb:d7:a5:4a:4c:65:94:43:82
+        16:9a:8f:76:2a:05:b0:9e:3d:a7:fb:e2:c7:78:25:f7
+        df:ca:08:ee:ec:4f:cd:1a:3c:03:41:ec:91:c5:50:70
+        4b:
+
+public exponent:
+        01:00:01:
+
+private exponent:
+        00:ad:01:83:b8:7d:dd:fd:ab:f5:66:2d:64:ce:08:ec
+        cb:6a:15:41:87:e6:c8:d5:10:39:78:d0:43:f7:73:f4
+        e1:77:ee:31:b0:e9:92:04:9a:25:e8:d2:e3:84:80:5e
+        5f:24:fd:d6:23:a5:74:5d:be:27:b8:4f:80:e5:f9:1f
+        ef:6f:fd:be:12:1a:7a:cf:02:65:5f:30:25:99:a4:88
+        7d:74:ea:c1:c1:63:4e:15:33:7d:2b:16:f8:6c:94:23
+        63:e6:d3:2d:38:89:f6:87:f0:08:e5:d7:ad:10:90:f5
+        fb:df:5c:04:b8:43:f0:74:95:31:1e:e5:b6:5f:02:0f
+        bb:55:cb:e1:b5:48:9f:1f:d3:1b:55:a7:bc:39:2b:8e
+        6d:14:64:3b:bf:e8:ca:6b:af:a9:f3:13:9a:c6:df:15
+        ef:6d:17:4e:8e:67:6c:41:20:dc:6b:08:0d:b9:14:cd
+        83:10:62:15:e6:b0:89:5d:37:fb:f6:fd:f0:bf:3b:9c
+        0b:e9:fd:b8:de:e4:64:90:bf:81:d5:59:2c:30:43:07
+        b9:60:8c:d0:ac:4f:95:87:aa:38:62:bd:c7:06:a7:c4
+        2d:08:c1:3c:86:10:c7:8e:1e:df:58:bf:95:ad:39:84
+        a0:2b:13:e2:18:e6:4a:80:f0:bc:04:50:bd:7d:cf:23
+        a1:
+
+prime1:
+        00:f0:8f:ad:2f:c9:64:f3:0d:2c:aa:06:17:05:8f:2f
+        d5:cb:92:22:90:05:66:3c:78:75:9d:7b:4c:6a:af:a9
+        1e:d6:28:4f:13:0e:3a:e7:31:49:3d:87:ef:2c:17:70
+        be:69:b3:42:82:6d:9c:b4:13:0a:e4:bc:8c:0f:1a:bd
+        04:b6:a0:be:ba:12:15:bf:04:db:91:1c:26:91:d6:d7
+        f2:ff:2f:0e:5f:96:a1:7c:4b:90:a8:2f:07:2a:cb:dc
+        40:a0:0b:1d:2a:1d:48:98:bd:4a:6b:9d:5c:69:b0:2b
+        6e:9b:2c:b2:a9:cb:28:fe:fa:7f:93:eb:20:c8:59:d0
+        11:
+
+prime2:
+        00:da:23:c0:3e:82:4c:88:7c:d4:fb:de:24:45:eb:9c
+        ae:2c:80:2d:52:a6:95:05:33:b9:d8:c1:7b:52:01:62
+        11:e6:b6:c6:0d:56:a3:68:39:26:9a:90:08:95:12:a9
+        1c:59:f6:0b:1d:af:6d:c0:c6:9b:2e:7a:62:98:21:36
+        e1:15:4c:e6:6d:a4:08:ac:90:af:57:86:71:78:2e:0e
+        cf:59:0f:35:79:cb:6a:a2:e2:30:2a:a8:f2:84:68:bc
+        8a:f2:48:3b:07:d5:a5:34:f3:d3:ec:25:61:38:f1:0a
+        07:f7:7e:29:61:e4:15:01:80:e3:7b:bd:63:9c:2e:16
+        9b:
+
+coefficient:
+        00:cb:b4:d2:9f:b4:04:db:8c:54:e6:ae:a9:28:a0:c9
+        70:ad:7a:94:72:5e:86:33:91:d9:43:61:2b:4d:55:e8
+        b7:25:d2:cd:db:1e:c4:56:95:68:85:e2:9b:4f:31:24
+        3a:40:06:41:1c:aa:7a:31:13:fa:07:e0:a6:59:c3:d1
+        d2:c5:2c:6a:82:98:bb:a1:59:c0:6f:ad:d7:2e:ed:5a
+        64:5f:e6:ea:4a:ee:45:29:d9:0f:96:b3:39:f7:ab:57
+        97:aa:c9:f7:b6:9c:c0:51:5d:9f:01:2c:ec:58:8d:06
+        6a:19:d0:33:74:11:6a:25:7c:8f:b7:31:d2:97:05:02
+        6f:
+
+exp1:
+        00:87:60:43:95:1d:e0:0a:8b:82:74:18:43:42:64:a7
+        05:c8:ae:ef:76:5f:23:7e:aa:47:7e:1d:52:0e:c3:d6
+        07:bd:7b:27:ac:d0:98:43:5c:d0:1b:a9:70:e6:3e:36
+        bb:61:5e:78:f2:4f:5f:1d:53:8e:10:d5:2e:78:9d:92
+        7b:a1:8e:ea:66:6a:21:04:c3:66:10:ce:67:c2:30:c6
+        8c:40:21:2a:14:8e:ff:47:a4:7a:be:ba:e0:6c:ac:16
+        c1:e3:8e:fd:95:a2:af:25:0d:79:61:00:48:6e:4d:ae
+        d3:6a:ce:07:a9:57:e4:35:41:a1:24:0b:f1:01:ee:d1
+        11:
+
+exp2:
+        00:ca:ca:bd:a7:de:fe:43:4c:b9:bb:c4:d2:37:e6:47
+        ec:6c:16:65:0c:17:2d:26:7e:e5:e1:2a:4d:f8:f8:ac
+        31:34:28:ea:89:ef:e7:4d:b7:03:ba:60:f8:79:8d:b5
+        85:53:e4:b6:84:cc:57:de:05:44:b2:ba:b7:f9:f1:b6
+        d1:1d:3a:36:65:eb:3e:dd:1e:4c:c3:b3:8a:bd:4d:24
+        1b:83:11:ee:86:e1:a2:aa:f6:58:0c:f0:af:34:85:21
+        f2:92:36:b0:1a:22:75:c9:7a:7b:a3:67:44:b0:e8:f4
+        88:5f:7e:fb:fd:b3:4a:0b:f1:c4:89:7e:91:a1:d9:fe
+        cd:
+
+
+Public Key ID: 92:D5:B4:2A:B6:A8:64:67:2C:2A:08:DB:51:B8:97:86:5E:44:CD:6C
+Public key's random art:
++--[ RSA 2048]----+
+|     +    .      |
+|    . E  o .     |
+|   o .  . o      |
+|  . o  o .       |
+|   = .= S        |
+|. +.=o +         |
+|o++== .          |
+|++o=             |
+|o .              |
++-----------------+
+
+
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpgIBAAKCAQEAzPvxxd4pKUA/xJ+v2va+J/RqAK5a8pnDX3rmm8/ZCDQBm+r7
+2rXQtbJOYLQNjQVX5C4E1FcaWDwLOu1noxMxWArC6/3WJ+4HlTA1tZiRx6Wbvql+
+rv1zw2shvFL473Hb07HNUd+zN7P9fa5+Aji+jm9FVeVtigLLNsQXeuokmnKNHnUD
+Om/Ey6A6UFYyu0zi6nTwljF0ssED6MPUo1n8esxoNcSX66pG+mTD+VVZIrUrPJaE
+xtJ9tJ+5nK/RIDB86GBO7gpgoJ1Oitg0dL3yQLzXwrMasrvXpUpMZZRDghaaj3Yq
+BbCePaf74sd4Jfffygju7E/NGjwDQeyRxVBwSwIDAQABAoIBAQCtAYO4fd39q/Vm
+LWTOCOzLahVBh+bI1RA5eNBD93P04XfuMbDpkgSaJejS44SAXl8k/dYjpXRdvie4
+T4Dl+R/vb/2+Ehp6zwJlXzAlmaSIfXTqwcFjThUzfSsW+GyUI2Pm0y04ifaH8Ajl
+160QkPX731wEuEPwdJUxHuW2XwIPu1XL4bVInx/TG1WnvDkrjm0UZDu/6Mprr6nz
+E5rG3xXvbRdOjmdsQSDcawgNuRTNgxBiFeawiV03+/b98L87nAvp/bje5GSQv4HV
+WSwwQwe5YIzQrE+Vh6o4Yr3HBqfELQjBPIYQx44e31i/la05hKArE+IY5kqA8LwE
+UL19zyOhAoGBAPCPrS/JZPMNLKoGFwWPL9XLkiKQBWY8eHWde0xqr6ke1ihPEw46
+5zFJPYfvLBdwvmmzQoJtnLQTCuS8jA8avQS2oL66EhW/BNuRHCaR1tfy/y8OX5ah
+fEuQqC8HKsvcQKALHSodSJi9SmudXGmwK26bLLKpyyj++n+T6yDIWdARAoGBANoj
+wD6CTIh81PveJEXrnK4sgC1SppUFM7nYwXtSAWIR5rbGDVajaDkmmpAIlRKpHFn2
+Cx2vbcDGmy56YpghNuEVTOZtpAiskK9XhnF4Lg7PWQ81ectqouIwKqjyhGi8ivJI
+OwfVpTTz0+wlYTjxCgf3filh5BUBgON7vWOcLhabAoGBAIdgQ5Ud4AqLgnQYQ0Jk
+pwXIru92XyN+qkd+HVIOw9YHvXsnrNCYQ1zQG6lw5j42u2FeePJPXx1TjhDVLnid
+knuhjupmaiEEw2YQzmfCMMaMQCEqFI7/R6R6vrrgbKwWweOO/ZWiryUNeWEASG5N
+rtNqzgepV+Q1QaEkC/EB7tERAoGBAMrKvafe/kNMubvE0jfmR+xsFmUMFy0mfuXh
+Kk34+KwxNCjqie/nTbcDumD4eY21hVPktoTMV94FRLK6t/nxttEdOjZl6z7dHkzD
+s4q9TSQbgxHuhuGiqvZYDPCvNIUh8pI2sBoidcl6e6NnRLDo9Ihffvv9s0oL8cSJ
+fpGh2f7NAoGBAMu00p+0BNuMVOauqSigyXCtepRyXoYzkdlDYStNVei3JdLN2x7E
+VpVoheKbTzEkOkAGQRyqejET+gfgplnD0dLFLGqCmLuhWcBvrdcu7VpkX+bqSu5F
+KdkPlrM596tXl6rJ97acwFFdnwEs7FiNBmoZ0DN0EWolfI+3MdKXBQJv
+-----END RSA PRIVATE KEY-----
diff --git a/python2/httplib2/test/server.pem b/python2/httplib2/test/server.pem
new file mode 100644
index 0000000..49b6efc
--- /dev/null
+++ b/python2/httplib2/test/server.pem
@@ -0,0 +1,50 @@
+Public, self-signed TLS server key file used for HTTPS-related unit tests
+-------------------------------------------------------------------------
+
+Public Key Information:
+        Public Key Algorithm: RSA
+        Algorithm Security Level: Medium (2048 bits)
+                Modulus (bits 2048):
+                        00:cc:fb:f1:c5:de:29:29:40:3f:c4:9f:af:da:f6:be
+                        27:f4:6a:00:ae:5a:f2:99:c3:5f:7a:e6:9b:cf:d9:08
+                        34:01:9b:ea:fb:da:b5:d0:b5:b2:4e:60:b4:0d:8d:05
+                        57:e4:2e:04:d4:57:1a:58:3c:0b:3a:ed:67:a3:13:31
+                        58:0a:c2:eb:fd:d6:27:ee:07:95:30:35:b5:98:91:c7
+                        a5:9b:be:a9:7e:ae:fd:73:c3:6b:21:bc:52:f8:ef:71
+                        db:d3:b1:cd:51:df:b3:37:b3:fd:7d:ae:7e:02:38:be
+                        8e:6f:45:55:e5:6d:8a:02:cb:36:c4:17:7a:ea:24:9a
+                        72:8d:1e:75:03:3a:6f:c4:cb:a0:3a:50:56:32:bb:4c
+                        e2:ea:74:f0:96:31:74:b2:c1:03:e8:c3:d4:a3:59:fc
+                        7a:cc:68:35:c4:97:eb:aa:46:fa:64:c3:f9:55:59:22
+                        b5:2b:3c:96:84:c6:d2:7d:b4:9f:b9:9c:af:d1:20:30
+                        7c:e8:60:4e:ee:0a:60:a0:9d:4e:8a:d8:34:74:bd:f2
+                        40:bc:d7:c2:b3:1a:b2:bb:d7:a5:4a:4c:65:94:43:82
+                        16:9a:8f:76:2a:05:b0:9e:3d:a7:fb:e2:c7:78:25:f7
+                        df:ca:08:ee:ec:4f:cd:1a:3c:03:41:ec:91:c5:50:70
+                        4b
+                Exponent (bits 24):
+                        01:00:01
+
+Public Key Usage:
+
+Public Key ID: 92d5b42ab6a864672c2a08db51b897865e44cd6c
+
+
+-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgIJAISbkoXpX75CMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
+BAMMCWxvY2FsaG9zdDAeFw0xNjA2MTcxNDA1NTlaFw0yNjA2MTUxNDA1NTlaMBQx
+EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMz78cXeKSlAP8Sfr9r2vif0agCuWvKZw1965pvP2Qg0AZvq+9q10LWyTmC0
+DY0FV+QuBNRXGlg8CzrtZ6MTMVgKwuv91ifuB5UwNbWYkcelm76pfq79c8NrIbxS
++O9x29OxzVHfszez/X2ufgI4vo5vRVXlbYoCyzbEF3rqJJpyjR51AzpvxMugOlBW
+MrtM4up08JYxdLLBA+jD1KNZ/HrMaDXEl+uqRvpkw/lVWSK1KzyWhMbSfbSfuZyv
+0SAwfOhgTu4KYKCdTorYNHS98kC818KzGrK716VKTGWUQ4IWmo92KgWwnj2n++LH
+eCX338oI7uxPzRo8A0HskcVQcEsCAwEAAaNQME4wHQYDVR0OBBYEFFdXD8Z8k0et
+ZNyM4e4WypNnGlcCMB8GA1UdIwQYMBaAFFdXD8Z8k0etZNyM4e4WypNnGlcCMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAC4FsnK1Ph/JpdoqSRTCJiVM
+MPFaaavKEEyYdAKPk/Acmb9vf07sqsT+OZg/0obsZG9LxJb7x0iAnhfM3aS+CmO9
+Ym2lXeFDaJ2bHooB9MsG2C3+n8lJUMwxm7Cqpff/lpCK6Z+6MGPx3GRs6HUEl34k
+BB5pue2vqhtFQ03UdHMpAK0M7n3TloAWbFb1a/JmqzTbsQ0oaMHGoECQEAbaBl+a
+/up6vA3iZHq+ZPYS1KIx+xuT/SapLcyUtjfhmq1bROVZP4+6EHMsBMnhJBYKxxHy
+0qKvqJL9X3NQLMgMKKUKzX+BuG2u5aRRyVIqewT/ORjaUr9Y8lU7WlXPf7Ljm6s=
+-----END CERTIFICATE-----
diff --git a/python2/httplib2/test/smoke_test.py b/python2/httplib2/test/smoke_test.py
new file mode 100644
index 0000000..9f1e6f0
--- /dev/null
+++ b/python2/httplib2/test/smoke_test.py
@@ -0,0 +1,23 @@
+import os
+import unittest
+
+import httplib2
+
+from httplib2.test import miniserver
+
+
+class HttpSmokeTest(unittest.TestCase):
+    def setUp(self):
+        self.httpd, self.port = miniserver.start_server(
+            miniserver.ThisDirHandler)
+
+    def tearDown(self):
+        self.httpd.shutdown()
+
+    def testGetFile(self):
+        client = httplib2.Http()
+        src = 'miniserver.py'
+        response, body = client.request('http://localhost:%d/%s' %
+                                        (self.port, src))
+        self.assertEqual(response.status, 200)
+        self.assertEqual(body, open(os.path.join(miniserver.HERE, src)).read())
diff --git a/python2/httplib2/test/test_no_socket.py b/python2/httplib2/test/test_no_socket.py
new file mode 100644
index 0000000..66ba056
--- /dev/null
+++ b/python2/httplib2/test/test_no_socket.py
@@ -0,0 +1,24 @@
+"""Tests for httplib2 when the socket module is missing.
+
+This helps ensure compatibility with environments such as AppEngine.
+"""
+import os
+import sys
+import unittest
+
+import httplib2
+
+class MissingSocketTest(unittest.TestCase):
+    def setUp(self):
+        self._oldsocks = httplib2.socks
+        httplib2.socks = None
+
+    def tearDown(self):
+        httplib2.socks = self._oldsocks
+
+    def testProxyDisabled(self):
+        proxy_info = httplib2.ProxyInfo('blah',
+                                        'localhost', 0)
+        client = httplib2.Http(proxy_info=proxy_info)
+        self.assertRaises(httplib2.ProxiesUnavailableError,
+                          client.request, 'http://localhost:-1/')
diff --git a/python2/httplib2/test/test_ssl_context.py b/python2/httplib2/test/test_ssl_context.py
new file mode 100644
index 0000000..5cf9efb
--- /dev/null
+++ b/python2/httplib2/test/test_ssl_context.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python2
+from __future__ import print_function
+import BaseHTTPServer
+import logging
+import os.path
+import ssl
+import sys
+import unittest
+
+import httplib2
+from httplib2.test import miniserver
+
+
+logger = logging.getLogger(__name__)
+
+
+class KeepAliveHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+    """
+    Request handler that keeps the HTTP connection open, so that the test can
+    inspect the resulting SSL connection object
+    """
+    def do_GET(self):
+        self.send_response(200)
+        self.send_header("Content-Length", "0")
+        self.send_header("Connection", "keep-alive")
+        self.end_headers()
+
+        self.close_connection = 0
+
+    def log_message(self, s, *args):
+        # output via logging so nose can catch it
+        logger.info(s, *args)
+
+
+class HttpsContextTest(unittest.TestCase):
+    def setUp(self):
+        if sys.version_info < (2, 7, 9):
+            if hasattr(self, "skipTest"):
+                self.skipTest("SSLContext requires Python 2.7.9")
+            else:
+                return
+
+        self.ca_certs_path = os.path.join(os.path.dirname(__file__), 'server.pem')
+        self.httpd, self.port = miniserver.start_server(KeepAliveHandler, True)
+
+    def tearDown(self):
+        self.httpd.shutdown()
+
+    def testHttpsContext(self):
+        client = httplib2.Http(ca_certs=self.ca_certs_path)
+
+        # Establish connection to local server
+        client.request('https://localhost:%d/' % (self.port))
+
+        # Verify that connection uses a TLS context with the correct hostname
+        conn = client.connections['https:localhost:%d' % self.port]
+
+        self.assertIsInstance(conn.sock, ssl.SSLSocket)
+        self.assertTrue(hasattr(conn.sock, 'context'))
+        self.assertIsInstance(conn.sock.context, ssl.SSLContext)
+        self.assertTrue(conn.sock.context.check_hostname)
+        self.assertEqual(conn.sock.server_hostname, 'localhost')
+        self.assertEqual(conn.sock.context.verify_mode, ssl.CERT_REQUIRED)
+        self.assertEqual(conn.sock.context.protocol, ssl.PROTOCOL_SSLv23)
+
+    def test_ssl_hostname_mismatch_repeat(self):
+        # https://github.com/httplib2/httplib2/issues/5
+
+        # FIXME(temoto): as of 2017-01-05 this is only a reference code, not useful test.
+        # Because it doesn't provoke described error on my machine.
+        # Instead `SSLContext.wrap_socket` raises `ssl.CertificateError`
+        # which was also added to original patch.
+
+        # url host is intentionally different, we provoke ssl hostname mismatch error
+        url = 'https://127.0.0.1:%d/' % (self.port,)
+        http = httplib2.Http(ca_certs=self.ca_certs_path, proxy_info=None)
+
+        def once():
+            try:
+                http.request(url)
+                assert False, 'expected certificate hostname mismatch error'
+            except Exception as e:
+                print('%s errno=%s' % (repr(e), getattr(e, 'errno', None)))
+
+        once()
+        once()
diff --git a/python2/httplib2test.py b/python2/httplib2test.py
new file mode 100755
index 0000000..82faabc
--- /dev/null
+++ b/python2/httplib2test.py
@@ -0,0 +1,1703 @@
+#!/usr/bin/env python2.4
+"""
+httplib2test
+
+A set of unit tests for httplib2.py.
+
+Requires Python 2.4 or later
+"""
+
+__author__ = "Joe Gregorio (joe@bitworking.org)"
+__copyright__ = "Copyright 2006, Joe Gregorio"
+__contributors__ = []
+__license__ = "MIT"
+__history__ = """ """
+__version__ = "0.1 ($Rev: 118 $)"
+
+
+import StringIO
+import base64
+import httplib
+import httplib2
+import os
+import pickle
+import socket
+import sys
+import time
+import unittest
+import urlparse
+
+try:
+    import ssl
+except ImportError:
+    pass
+
+# Python 2.3 support
+if not hasattr(unittest.TestCase, 'assertTrue'):
+    unittest.TestCase.assertTrue = unittest.TestCase.failUnless
+    unittest.TestCase.assertFalse = unittest.TestCase.failIf
+
+# The test resources base uri
+base = 'http://bitworking.org/projects/httplib2/test/'
+#base = 'http://localhost/projects/httplib2/test/'
+cacheDirName = ".cache"
+
+
+class CredentialsTest(unittest.TestCase):
+    def test(self):
+        c = httplib2.Credentials()
+        c.add("joe", "password")
+        self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
+        self.assertEqual(("joe", "password"), list(c.iter(""))[0])
+        c.add("fred", "password2", "wellformedweb.org")
+        self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])
+        self.assertEqual(1, len(list(c.iter("bitworking.org"))))
+        self.assertEqual(2, len(list(c.iter("wellformedweb.org"))))
+        self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
+        c.clear()
+        self.assertEqual(0, len(list(c.iter("bitworking.org"))))
+        c.add("fred", "password2", "wellformedweb.org")
+        self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))
+        self.assertEqual(0, len(list(c.iter("bitworking.org"))))
+        self.assertEqual(0, len(list(c.iter(""))))
+
+
+class ParserTest(unittest.TestCase):
+    def testFromStd66(self):
+        self.assertEqual( ('http', 'example.com', '', None, None ), httplib2.parse_uri("http://example.com"))
+        self.assertEqual( ('https', 'example.com', '', None, None ), httplib2.parse_uri("https://example.com"))
+        self.assertEqual( ('https', 'example.com:8080', '', None, None ), httplib2.parse_uri("https://example.com:8080"))
+        self.assertEqual( ('http', 'example.com', '/', None, None ), httplib2.parse_uri("http://example.com/"))
+        self.assertEqual( ('http', 'example.com', '/path', None, None ), httplib2.parse_uri("http://example.com/path"))
+        self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', None ), httplib2.parse_uri("http://example.com/path?a=1&b=2"))
+        self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
+        self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))
+
+
+class UrlNormTest(unittest.TestCase):
+    def test(self):
+        self.assertEqual( "http://example.org/", httplib2.urlnorm("http://example.org")[-1])
+        self.assertEqual( "http://example.org/", httplib2.urlnorm("http://EXAMple.org")[-1])
+        self.assertEqual( "http://example.org/?=b", httplib2.urlnorm("http://EXAMple.org?=b")[-1])
+        self.assertEqual( "http://example.org/mypath?a=b", httplib2.urlnorm("http://EXAMple.org/mypath?a=b")[-1])
+        self.assertEqual( "http://localhost:80/", httplib2.urlnorm("http://localhost:80")[-1])
+        self.assertEqual( httplib2.urlnorm("http://localhost:80/"), httplib2.urlnorm("HTTP://LOCALHOST:80"))
+        try:
+            httplib2.urlnorm("/")
+            self.fail("Non-absolute URIs should raise an exception")
+        except httplib2.RelativeURIError:
+            pass
+
+class UrlSafenameTest(unittest.TestCase):
+    def test(self):
+        # Test that different URIs end up generating different safe names
+        self.assertEqual( "example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f", httplib2.safename("http://example.org/fred/?a=b"))
+        self.assertEqual( "example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b", httplib2.safename("http://example.org/fred?/a=b"))
+        self.assertEqual( "www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968", httplib2.safename("http://www.example.org/fred?/a=b"))
+        self.assertEqual( httplib2.safename(httplib2.urlnorm("http://www")[-1]), httplib2.safename(httplib2.urlnorm("http://WWW")[-1]))
+        self.assertEqual( "www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d", httplib2.safename("https://www.example.org/fred?/a=b"))
+        self.assertNotEqual( httplib2.safename("http://www"), httplib2.safename("https://www"))
+        # Test the max length limits
+        uri = "http://" + ("w" * 200) + ".org"
+        uri2 = "http://" + ("w" * 201) + ".org"
+        self.assertNotEqual( httplib2.safename(uri2), httplib2.safename(uri))
+        # Max length should be 200 + 1 (",") + 32
+        self.assertEqual(233, len(httplib2.safename(uri2)))
+        self.assertEqual(233, len(httplib2.safename(uri)))
+        # Unicode
+        if sys.version_info >= (2,3):
+            self.assertEqual( "xn--http,-4y1d.org,fred,a=b,579924c35db315e5a32e3d9963388193", httplib2.safename(u"http://\u2304.org/fred/?a=b"))
+
+class _MyResponse(StringIO.StringIO):
+    def __init__(self, body, **kwargs):
+        StringIO.StringIO.__init__(self, body)
+        self.headers = kwargs
+
+    def iteritems(self):
+        return self.headers.iteritems()
+
+
+class _MyHTTPConnection(object):
+    "This class is just a mock of httplib.HTTPConnection used for testing"
+
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=None, proxy_info=None):
+        self.host = host
+        self.port = port
+        self.timeout = timeout
+        self.log = ""
+        self.sock = None
+
+    def set_debuglevel(self, level):
+        pass
+
+    def connect(self):
+        "Connect to a host on a given port."
+        pass
+
+    def close(self):
+        pass
+
+    def request(self, method, request_uri, body, headers):
+        pass
+
+    def getresponse(self):
+        return _MyResponse("the body", status="200")
+
+class _MyHTTPBadStatusConnection(object):
+    "Mock of httplib.HTTPConnection that raises BadStatusLine."
+
+    num_calls = 0
+
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=None, proxy_info=None):
+        self.host = host
+        self.port = port
+        self.timeout = timeout
+        self.log = ""
+        self.sock = None
+        _MyHTTPBadStatusConnection.num_calls = 0
+
+    def set_debuglevel(self, level):
+        pass
+
+    def connect(self):
+        pass
+
+    def close(self):
+        pass
+
+    def request(self, method, request_uri, body, headers):
+        pass
+
+    def getresponse(self):
+        _MyHTTPBadStatusConnection.num_calls += 1
+        raise httplib.BadStatusLine("")
+
+
+class HttpTest(unittest.TestCase):
+    def setUp(self):
+        if os.path.exists(cacheDirName):
+            [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]
+
+        if sys.version_info < (2, 6):
+            disable_cert_validation = True
+        else:
+            disable_cert_validation = False
+        self.http = httplib2.Http(
+                cacheDirName,
+                disable_ssl_certificate_validation=disable_cert_validation)
+        self.http.clear_credentials()
+
+    def testIPv6NoSSL(self):
+        try:
+          self.http.request("http://[::1]/")
+        except socket.gaierror:
+          self.fail("should get the address family right for IPv6")
+        except socket.error:
+          # Even if IPv6 isn't installed on a machine it should just raise socket.error
+          pass
+
+    def testIPv6SSL(self):
+        try:
+          self.http.request("https://[::1]/")
+        except socket.gaierror:
+          self.fail("should get the address family right for IPv6")
+        except httplib2.CertificateHostnameMismatch:
+          # We connected and verified that the certificate doesn't match
+          #  the name. Good enough.
+          pass
+        except socket.error:
+          # Even if IPv6 isn't installed on a machine it should just raise socket.error
+          pass
+
+    def testConnectionType(self):
+        self.http.force_exception_to_status_code = False
+        response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)
+        self.assertEqual(response['content-location'], "http://bitworking.org")
+        self.assertEqual(content, "the body")
+
+    def testBadStatusLineRetry(self):
+        old_retries = httplib2.RETRIES
+        httplib2.RETRIES = 1
+        self.http.force_exception_to_status_code = False
+        try:
+            response, content = self.http.request("http://bitworking.org",
+                connection_type=_MyHTTPBadStatusConnection)
+        except httplib.BadStatusLine:
+            self.assertEqual(2, _MyHTTPBadStatusConnection.num_calls)
+        httplib2.RETRIES = old_retries
+
+    def testGetUnknownServer(self):
+        self.http.force_exception_to_status_code = False
+        try:
+            self.http.request("http://fred.bitworking.org/")
+            self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")
+        except httplib2.ServerNotFoundError:
+            pass
+
+        # Now test with exceptions turned off
+        self.http.force_exception_to_status_code = True
+
+        (response, content) = self.http.request("http://fred.bitworking.org/")
+        self.assertEqual(response['content-type'], 'text/plain')
+        self.assertTrue(content.startswith("Unable to find"))
+        self.assertEqual(response.status, 400)
+
+    def testGetConnectionRefused(self):
+        self.http.force_exception_to_status_code = False
+        try:
+          self.http.request("http://localhost:7777/")
+          self.fail("An socket.error exception must be thrown on Connection Refused.")
+        except socket.error:
+            pass
+
+        # Now test with exceptions turned off
+        self.http.force_exception_to_status_code = True
+
+        (response, content) = self.http.request("http://localhost:7777/")
+        self.assertEqual(response['content-type'], 'text/plain')
+        self.assertTrue("Connection refused" in content
+            or "actively refused" in content,
+            "Unexpected status %(content)s" % vars())
+        self.assertEqual(response.status, 400)
+
+    def testGetIRI(self):
+        if sys.version_info >= (2,3):
+            uri = urlparse.urljoin(base, u"reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")
+            (response, content) = self.http.request(uri, "GET")
+            d = self.reflector(content)
+            self.assertTrue('QUERY_STRING' in d)
+            self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)
+
+    def testGetIsDefaultMethod(self):
+        # Test that GET is the default method
+        uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
+        (response, content) = self.http.request(uri)
+        self.assertEqual(response['x-method'], "GET")
+
+    def testDifferentMethods(self):
+        # Test that all methods can be used
+        uri = urlparse.urljoin(base, "methods/method_reflector.cgi")
+        for method in ["GET", "PUT", "DELETE", "POST"]:
+            (response, content) = self.http.request(uri, method, body=" ")
+            self.assertEqual(response['x-method'], method)
+
+    def testHeadRead(self):
+        # Test that we don't try to read the response of a HEAD request
+        # since httplib blocks response.read() for HEAD requests.
+        # Oddly enough this doesn't appear as a problem when doing HEAD requests
+        # against Apache servers.
+        uri = "http://www.google.com/"
+        (response, content) = self.http.request(uri, "HEAD")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(content, "")
+
+    def testGetNoCache(self):
+        # Test that can do a GET w/o the cache turned on.
+        http = httplib2.Http()
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+        (response, content) = http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.previous, None)
+
+    def testGetOnlyIfCachedCacheHit(self):
+        # Test that can do a GET with cache and 'only-if-cached'
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+        (response, content) = self.http.request(uri, "GET")
+        (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
+        self.assertEqual(response.fromcache, True)
+        self.assertEqual(response.status, 200)
+
+    def testGetOnlyIfCachedCacheMiss(self):
+        # Test that can do a GET with no cache with 'only-if-cached'
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+        (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
+        self.assertEqual(response.fromcache, False)
+        self.assertEqual(response.status, 504)
+
+    def testGetOnlyIfCachedNoCacheAtAll(self):
+        # Test that can do a GET with no cache with 'only-if-cached'
+        # Of course, there might be an intermediary beyond us
+        # that responds to the 'only-if-cached', so this
+        # test can't really be guaranteed to pass.
+        http = httplib2.Http()
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+        (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})
+        self.assertEqual(response.fromcache, False)
+        self.assertEqual(response.status, 504)
+
+    def testUserAgent(self):
+        # Test that we provide a default user-agent
+        uri = urlparse.urljoin(base, "user-agent/test.cgi")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertTrue(content.startswith("Python-httplib2/"))
+
+    def testUserAgentNonDefault(self):
+        # Test that the default user-agent can be over-ridden
+
+        uri = urlparse.urljoin(base, "user-agent/test.cgi")
+        (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})
+        self.assertEqual(response.status, 200)
+        self.assertTrue(content.startswith("fred/1.0"))
+
+    def testGet300WithLocation(self):
+        # Test the we automatically follow 300 redirects if a Location: header is provided
+        uri = urlparse.urljoin(base, "300/with-location-header.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 300)
+        self.assertEqual(response.previous.fromcache, False)
+
+        # Confirm that the intermediate 300 is not cached
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 300)
+        self.assertEqual(response.previous.fromcache, False)
+
+    def testGet300WithLocationNoRedirect(self):
+        # Test the we automatically follow 300 redirects if a Location: header is provided
+        self.http.follow_redirects = False
+        uri = urlparse.urljoin(base, "300/with-location-header.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 300)
+
+    def testGet300WithoutLocation(self):
+        # Not giving a Location: header in a 300 response is acceptable
+        # In which case we just return the 300 response
+        uri = urlparse.urljoin(base, "300/without-location-header.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 300)
+        self.assertTrue(response['content-type'].startswith("text/html"))
+        self.assertEqual(response.previous, None)
+
+    def testGet301(self):
+        # Test that we automatically follow 301 redirects
+        # and that we cache the 301 response
+        uri = urlparse.urljoin(base, "301/onestep.asis")
+        destination = urlparse.urljoin(base, "302/final-destination.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertTrue('content-location' in response)
+        self.assertEqual(response['content-location'], destination)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 301)
+        self.assertEqual(response.previous.fromcache, False)
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response['content-location'], destination)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 301)
+        self.assertEqual(response.previous.fromcache, True)
+
+    def testHead301(self):
+        # Test that we automatically follow 301 redirects
+        uri = urlparse.urljoin(base, "301/onestep.asis")
+        destination = urlparse.urljoin(base, "302/final-destination.txt")
+        (response, content) = self.http.request(uri, "HEAD")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.previous.status, 301)
+        self.assertEqual(response.previous.fromcache, False)
+
+    def testGet301NoRedirect(self):
+        # Test that we automatically follow 301 redirects
+        # and that we cache the 301 response
+        self.http.follow_redirects = False
+        uri = urlparse.urljoin(base, "301/onestep.asis")
+        destination = urlparse.urljoin(base, "302/final-destination.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 301)
+
+
+    def testGet302(self):
+        # Test that we automatically follow 302 redirects
+        # and that we DO NOT cache the 302 response
+        uri = urlparse.urljoin(base, "302/onestep.asis")
+        destination = urlparse.urljoin(base, "302/final-destination.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response['content-location'], destination)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 302)
+        self.assertEqual(response.previous.fromcache, False)
+
+        uri = urlparse.urljoin(base, "302/onestep.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+        self.assertEqual(response['content-location'], destination)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 302)
+        self.assertEqual(response.previous.fromcache, False)
+        self.assertEqual(response.previous['content-location'], uri)
+
+        uri = urlparse.urljoin(base, "302/twostep.asis")
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 302)
+        self.assertEqual(response.previous.fromcache, False)
+
+    def testGet302RedirectionLimit(self):
+        # Test that we can set a lower redirection limit
+        # and that we raise an exception when we exceed
+        # that limit.
+        self.http.force_exception_to_status_code = False
+
+        uri = urlparse.urljoin(base, "302/twostep.asis")
+        try:
+            (response, content) = self.http.request(uri, "GET", redirections = 1)
+            self.fail("This should not happen")
+        except httplib2.RedirectLimit:
+            pass
+        except Exception as e:
+            self.fail("Threw wrong kind of exception ")
+
+        # Re-run the test with out the exceptions
+        self.http.force_exception_to_status_code = True
+
+        (response, content) = self.http.request(uri, "GET", redirections = 1)
+        self.assertEqual(response.status, 500)
+        self.assertTrue(response.reason.startswith("Redirected more"))
+        self.assertEqual("302", response['status'])
+        self.assertTrue(content.startswith("<html>"))
+        self.assertTrue(response.previous != None)
+
+    def testGet302NoLocation(self):
+        # Test that we throw an exception when we get
+        # a 302 with no Location: header.
+        self.http.force_exception_to_status_code = False
+        uri = urlparse.urljoin(base, "302/no-location.asis")
+        try:
+            (response, content) = self.http.request(uri, "GET")
+            self.fail("Should never reach here")
+        except httplib2.RedirectMissingLocation:
+            pass
+        except Exception as e:
+            self.fail("Threw wrong kind of exception ")
+
+        # Re-run the test with out the exceptions
+        self.http.force_exception_to_status_code = True
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 500)
+        self.assertTrue(response.reason.startswith("Redirected but"))
+        self.assertEqual("302", response['status'])
+        self.assertTrue(content.startswith("This is content"))
+
+    def testGet301ViaHttps(self):
+        # Google always redirects to https://www.google.com
+        (response, content) = self.http.request("https://code.google.com/apis/", "GET")
+        self.assertEqual(200, response.status)
+        self.assertEqual(301, response.previous.status)
+
+    def testGetViaHttps(self):
+        # Test that we can handle HTTPS
+        (response, content) = self.http.request("https://www.google.com/adsense/", "GET")
+        self.assertEqual(200, response.status)
+
+    def testGetViaHttpsSpecViolationOnLocation(self):
+        # Test that we follow redirects through HTTPS
+        # even if they violate the spec by including
+        # a relative Location: header instead of an
+        # absolute one.
+        (response, content) = self.http.request("https://www.google.com/adsense", "GET")
+        self.assertEqual(200, response.status)
+        self.assertNotEqual(None, response.previous)
+
+    def testSslCertValidationDoubleDots(self):
+        pass
+        # No longer a valid test.
+        #if sys.version_info >= (2, 6):
+        # Test that we get match a double dot cert
+        #try:
+        #  self.http.request("https://www.appspot.com/", "GET")
+        #except httplib2.CertificateHostnameMismatch:
+        #  self.fail('cert with *.*.appspot.com should not raise an exception.')
+
+    def testSslHostnameValidation(self):
+      pass
+        # No longer a valid test.
+        #if sys.version_info >= (2, 6):
+            # The SSL server at google.com:443 returns a certificate for
+            # 'www.google.com', which results in a host name mismatch.
+            # Note that this test only works because the ssl module and httplib2
+            # do not support SNI; for requests specifying a server name of
+            # 'google.com' via SNI, a matching cert would be returned.
+        #    self.assertRaises(httplib2.CertificateHostnameMismatch,
+        #            self.http.request, "https://google.com/", "GET")
+
+    def testSslCertValidationWithoutSslModuleFails(self):
+        if sys.version_info < (2, 6):
+            http = httplib2.Http(disable_ssl_certificate_validation=False)
+            self.assertRaises(httplib2.CertificateValidationUnsupported,
+                    http.request, "https://www.google.com/", "GET")
+
+    def testGetViaHttpsKeyCert(self):
+        #  At this point I can only test
+        #  that the key and cert files are passed in
+        #  correctly to httplib. It would be nice to have
+        #  a real https endpoint to test against.
+
+        # bitworking.org presents an certificate for a non-matching host
+        # (*.webfaction.com), so we need to disable cert checking for this test.
+        http = httplib2.Http(timeout=2, disable_ssl_certificate_validation=True)
+
+        http.add_certificate("akeyfile", "acertfile", "bitworking.org")
+        try:
+            (response, content) = http.request("https://bitworking.org", "GET")
+        except:
+            pass
+        self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")
+        self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")
+
+        try:
+            (response, content) = http.request("https://notthere.bitworking.org", "GET")
+        except:
+            pass
+        self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)
+        self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)
+
+
+
+
+    def testGet303(self):
+        # Do a follow-up GET on a Location: header
+        # returned from a POST that gave a 303.
+        uri = urlparse.urljoin(base, "303/303.cgi")
+        (response, content) = self.http.request(uri, "POST", " ")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 303)
+
+    def testGet303NoRedirect(self):
+        # Do a follow-up GET on a Location: header
+        # returned from a POST that gave a 303.
+        self.http.follow_redirects = False
+        uri = urlparse.urljoin(base, "303/303.cgi")
+        (response, content) = self.http.request(uri, "POST", " ")
+        self.assertEqual(response.status, 303)
+
+    def test303ForDifferentMethods(self):
+        # Test that all methods can be used
+        uri = urlparse.urljoin(base, "303/redirect-to-reflector.cgi")
+        for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:
+            (response, content) = self.http.request(uri, method, body=" ")
+            self.assertEqual(response['x-method'], method_on_303)
+
+    def test303AndForwardAuthorizationHeader(self):
+        # Test that all methods can be used
+        uri = urlparse.urljoin(base, "303/redirect-to-header-reflector.cgi")
+        headers = {'authorization': 'Bearer foo'}
+        response, content = self.http.request(uri, 'GET', body=" ",
+            headers=headers)
+        # self.assertTrue('authorization' not in content)
+        self.http.follow_all_redirects = True
+        self.http.forward_authorization_headers = True
+        response, content = self.http.request(uri, 'GET', body=" ",
+            headers=headers)
+        # Oh, how I wish Apache didn't eat the Authorization header.
+        # self.assertTrue('authorization' in content)
+
+    def testGet304(self):
+        # Test that we use ETags properly to validate our cache
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+        (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
+        self.assertNotEqual(response['etag'], "")
+
+        (response, content) = self.http.request(uri, "GET")
+        (response, content) = self.http.request(uri, "GET", headers = {'cache-control': 'must-revalidate'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+
+        cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))
+        f = open(cache_file_name, "r")
+        status_line = f.readline()
+        f.close()
+
+        self.assertTrue(status_line.startswith("status:"))
+
+        (response, content) = self.http.request(uri, "HEAD")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+
+        (response, content) = self.http.request(uri, "GET", headers = {'range': 'bytes=0-0'})
+        self.assertEqual(response.status, 206)
+        self.assertEqual(response.fromcache, False)
+
+    def testGetIgnoreEtag(self):
+        # Test that we can forcibly ignore ETags
+        uri = urlparse.urljoin(base, "reflector/reflector.cgi")
+        (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
+        self.assertNotEqual(response['etag'], "")
+
+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})
+        d = self.reflector(content)
+        self.assertTrue('HTTP_IF_NONE_MATCH' in d)
+
+        self.http.ignore_etag = True
+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})
+        d = self.reflector(content)
+        self.assertEqual(response.fromcache, False)
+        self.assertFalse('HTTP_IF_NONE_MATCH' in d)
+
+    def testOverrideEtag(self):
+        # Test that we can forcibly ignore ETags
+        uri = urlparse.urljoin(base, "reflector/reflector.cgi")
+        (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
+        self.assertNotEqual(response['etag'], "")
+
+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})
+        d = self.reflector(content)
+        self.assertTrue('HTTP_IF_NONE_MATCH' in d)
+        self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")
+
+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0', 'if-none-match': 'fred'})
+        d = self.reflector(content)
+        self.assertTrue('HTTP_IF_NONE_MATCH' in d)
+        self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")
+
+#MAP-commented this out because it consistently fails
+#    def testGet304EndToEnd(self):
+#       # Test that end to end headers get overwritten in the cache
+#        uri = urlparse.urljoin(base, "304/end2end.cgi")
+#        (response, content) = self.http.request(uri, "GET")
+#        self.assertNotEqual(response['etag'], "")
+#        old_date = response['date']
+#        time.sleep(2)
+#
+#        (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})
+#        # The response should be from the cache, but the Date: header should be updated.
+#        new_date = response['date']
+#        self.assertNotEqual(new_date, old_date)
+#        self.assertEqual(response.status, 200)
+#        self.assertEqual(response.fromcache, True)
+
+    def testGet304LastModified(self):
+        # Test that we can still handle a 304
+        # by only using the last-modified cache validator.
+        uri = urlparse.urljoin(base, "304/last-modified-only/last-modified-only.txt")
+        (response, content) = self.http.request(uri, "GET")
+
+        self.assertNotEqual(response['last-modified'], "")
+        (response, content) = self.http.request(uri, "GET")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+
+    def testGet307(self):
+        # Test that we do follow 307 redirects but
+        # do not cache the 307
+        uri = urlparse.urljoin(base, "307/onestep.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 307)
+        self.assertEqual(response.previous.fromcache, False)
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+        self.assertEqual(content, "This is the final destination.\n")
+        self.assertEqual(response.previous.status, 307)
+        self.assertEqual(response.previous.fromcache, False)
+
+    def testGet410(self):
+        # Test that we pass 410's through
+        uri = urlparse.urljoin(base, "410/410.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 410)
+
+    def testVaryHeaderSimple(self):
+        """
+        RFC 2616 13.6
+        When the cache receives a subsequent request whose Request-URI
+        specifies one or more cache entries including a Vary header field,
+        the cache MUST NOT use such a cache entry to construct a response
+        to the new request unless all of the selecting request-headers
+        present in the new request match the corresponding stored
+        request-headers in the original request.
+        """
+        # test that the vary header is sent
+        uri = urlparse.urljoin(base, "vary/accept.asis")
+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+        self.assertEqual(response.status, 200)
+        self.assertTrue('vary' in response)
+
+        # get the resource again, from the cache since accept header in this
+        # request is the same as the request
+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+        # get the resource again, not from cache since Accept headers does not match
+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False, msg="Should not be from cache")
+
+        # get the resource again, without any Accept header, so again no match
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False, msg="Should not be from cache")
+
+    def testNoVary(self):
+        pass
+        # when there is no vary, a different Accept header (e.g.) should not
+        # impact if the cache is used
+        # test that the vary header is not sent
+        # uri = urlparse.urljoin(base, "vary/no-vary.asis")
+        # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+        # self.assertEqual(response.status, 200)
+        # self.assertFalse(response.has_key('vary'))
+
+        # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+        # self.assertEqual(response.status, 200)
+        # self.assertEqual(response.fromcache, True, msg="Should be from cache")
+        #
+        # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})
+        # self.assertEqual(response.status, 200)
+        # self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+    def testVaryHeaderDouble(self):
+        uri = urlparse.urljoin(base, "vary/accept-double.asis")
+        (response, content) = self.http.request(uri, "GET", headers={
+            'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
+        self.assertEqual(response.status, 200)
+        self.assertTrue('vary' in response)
+
+        # we are from cache
+        (response, content) = self.http.request(uri, "GET", headers={
+            'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
+        self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+        # get the resource again, not from cache, varied headers don't match exact
+        (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False, msg="Should not be from cache")
+
+    def testVaryUnusedHeader(self):
+        # A header's value is not considered to vary if it's not used at all.
+        uri = urlparse.urljoin(base, "vary/unused-header.asis")
+        (response, content) = self.http.request(uri, "GET", headers={
+            'Accept': 'text/plain'})
+        self.assertEqual(response.status, 200)
+        self.assertTrue('vary' in response)
+
+        # we are from cache
+        (response, content) = self.http.request(uri, "GET", headers={
+            'Accept': 'text/plain',})
+        self.assertEqual(response.fromcache, True, msg="Should be from cache")
+
+
+    def testHeadGZip(self):
+        # Test that we don't try to decompress a HEAD response
+        uri = urlparse.urljoin(base, "gzip/final-destination.txt")
+        (response, content) = self.http.request(uri, "HEAD")
+        self.assertEqual(response.status, 200)
+        self.assertNotEqual(int(response['content-length']), 0)
+        self.assertEqual(content, "")
+
+    def testGetGZip(self):
+        # Test that we support gzip compression
+        uri = urlparse.urljoin(base, "gzip/final-destination.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertFalse('content-encoding' in response)
+        self.assertTrue('-content-encoding' in response)
+        self.assertEqual(int(response['content-length']), len("This is the final destination.\n"))
+        self.assertEqual(content, "This is the final destination.\n")
+
+    def testPostAndGZipResponse(self):
+        uri = urlparse.urljoin(base, "gzip/post.cgi")
+        (response, content) = self.http.request(uri, "POST", body=" ")
+        self.assertEqual(response.status, 200)
+        self.assertFalse('content-encoding' in response)
+        self.assertTrue('-content-encoding' in response)
+
+    def testGetGZipFailure(self):
+        # Test that we raise a good exception when the gzip fails
+        self.http.force_exception_to_status_code = False
+        uri = urlparse.urljoin(base, "gzip/failed-compression.asis")
+        try:
+            (response, content) = self.http.request(uri, "GET")
+            self.fail("Should never reach here")
+        except httplib2.FailedToDecompressContent:
+            pass
+        except Exception:
+            self.fail("Threw wrong kind of exception")
+
+        # Re-run the test with out the exceptions
+        self.http.force_exception_to_status_code = True
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 500)
+        self.assertTrue(response.reason.startswith("Content purported"))
+
+    def testTimeout(self):
+        self.http.force_exception_to_status_code = True
+        uri = urlparse.urljoin(base, "timeout/timeout.cgi")
+        try:
+            import socket
+            socket.setdefaulttimeout(1)
+        except:
+            # Don't run the test if we can't set the timeout
+            return
+        (response, content) = self.http.request(uri)
+        self.assertEqual(response.status, 408)
+        self.assertTrue(response.reason.startswith("Request Timeout"))
+        self.assertTrue(content.startswith("Request Timeout"))
+
+    def testIndividualTimeout(self):
+        uri = urlparse.urljoin(base, "timeout/timeout.cgi")
+        http = httplib2.Http(timeout=1)
+        http.force_exception_to_status_code = True
+
+        (response, content) = http.request(uri)
+        self.assertEqual(response.status, 408)
+        self.assertTrue(response.reason.startswith("Request Timeout"))
+        self.assertTrue(content.startswith("Request Timeout"))
+
+
+    def testHTTPSInitTimeout(self):
+        c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
+        self.assertEqual(47, c.timeout)
+
+    def testGetDeflate(self):
+        # Test that we support deflate compression
+        uri = urlparse.urljoin(base, "deflate/deflated.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertFalse('content-encoding' in response)
+        self.assertEqual(int(response['content-length']), len("This is the final destination."))
+        self.assertEqual(content, "This is the final destination.")
+
+    def testGetDeflateFailure(self):
+        # Test that we raise a good exception when the deflate fails
+        self.http.force_exception_to_status_code = False
+
+        uri = urlparse.urljoin(base, "deflate/failed-compression.asis")
+        try:
+            (response, content) = self.http.request(uri, "GET")
+            self.fail("Should never reach here")
+        except httplib2.FailedToDecompressContent:
+            pass
+        except Exception:
+            self.fail("Threw wrong kind of exception")
+
+        # Re-run the test with out the exceptions
+        self.http.force_exception_to_status_code = True
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 500)
+        self.assertTrue(response.reason.startswith("Content purported"))
+
+    def testGetDuplicateHeaders(self):
+        # Test that duplicate headers get concatenated via ','
+        uri = urlparse.urljoin(base, "duplicate-headers/multilink.asis")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(content, "This is content\n")
+        self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')
+
+    def testGetCacheControlNoCache(self):
+        # Test Cache-Control: no-cache on requests
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+        (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
+        self.assertNotEqual(response['etag'], "")
+        (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+
+        (response, content) = self.http.request(uri, "GET", headers={'accept-encoding': 'identity', 'Cache-Control': 'no-cache'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+    def testGetCacheControlPragmaNoCache(self):
+        # Test Pragma: no-cache on requests
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+        (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
+        self.assertNotEqual(response['etag'], "")
+        (response, content) = self.http.request(uri, "GET", headers= {'accept-encoding': 'identity'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+
+        (response, content) = self.http.request(uri, "GET", headers={'accept-encoding': 'identity', 'Pragma': 'no-cache'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+    def testGetCacheControlNoStoreRequest(self):
+        # A no-store request means that the response should not be stored.
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+
+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+    def testGetCacheControlNoStoreResponse(self):
+        # A no-store response means that the response should not be stored.
+        uri = urlparse.urljoin(base, "no-store/no-store.asis")
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+    def testGetCacheControlNoCacheNoStoreRequest(self):
+        # Test that a no-store, no-cache clears the entry from the cache
+        # even if it was cached previously.
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+
+        (response, content) = self.http.request(uri, "GET")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.fromcache, True)
+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+
+    def testUpdateInvalidatesCache(self):
+        # Test that calling PUT or DELETE on a
+        # URI that is cache invalidates that cache.
+        uri = urlparse.urljoin(base, "304/test_etag.txt")
+
+        (response, content) = self.http.request(uri, "GET")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.fromcache, True)
+        (response, content) = self.http.request(uri, "DELETE")
+        self.assertEqual(response.status, 405)
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.fromcache, False)
+
+    def testUpdateUsesCachedETag(self):
+        # Test that we natively support http://www.w3.org/1999/04/Editing/
+        uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+        (response, content) = self.http.request(uri, "PUT", body="foo")
+        self.assertEqual(response.status, 200)
+        (response, content) = self.http.request(uri, "PUT", body="foo")
+        self.assertEqual(response.status, 412)
+
+    def testUpdatePatchUsesCachedETag(self):
+        # Test that we natively support http://www.w3.org/1999/04/Editing/
+        uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+        (response, content) = self.http.request(uri, "PATCH", body="foo")
+        self.assertEqual(response.status, 200)
+        (response, content) = self.http.request(uri, "PATCH", body="foo")
+        self.assertEqual(response.status, 412)
+
+
+    def testUpdateUsesCachedETagAndOCMethod(self):
+        # Test that we natively support http://www.w3.org/1999/04/Editing/
+        uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+        self.http.optimistic_concurrency_methods.append("DELETE")
+        (response, content) = self.http.request(uri, "DELETE")
+        self.assertEqual(response.status, 200)
+
+
+    def testUpdateUsesCachedETagOverridden(self):
+        # Test that we natively support http://www.w3.org/1999/04/Editing/
+        uri = urlparse.urljoin(base, "conditional-updates/test.cgi")
+
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, False)
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+        self.assertEqual(response.fromcache, True)
+        (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})
+        self.assertEqual(response.status, 412)
+
+    def testBasicAuth(self):
+        # Test Basic Authentication
+        uri = urlparse.urljoin(base, "basic/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        uri = urlparse.urljoin(base, "basic/")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        self.http.add_credentials('joe', 'password')
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+        uri = urlparse.urljoin(base, "basic/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+    def testBasicAuthWithDomain(self):
+        # Test Basic Authentication
+        uri = urlparse.urljoin(base, "basic/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        uri = urlparse.urljoin(base, "basic/")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        self.http.add_credentials('joe', 'password', "example.org")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        uri = urlparse.urljoin(base, "basic/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        domain = urlparse.urlparse(base)[1]
+        self.http.add_credentials('joe', 'password', domain)
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+        uri = urlparse.urljoin(base, "basic/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+
+
+
+
+
+    def testBasicAuthTwoDifferentCredentials(self):
+        # Test Basic Authentication with multiple sets of credentials
+        uri = urlparse.urljoin(base, "basic2/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        uri = urlparse.urljoin(base, "basic2/")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        self.http.add_credentials('fred', 'barney')
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+        uri = urlparse.urljoin(base, "basic2/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+    def testBasicAuthNested(self):
+        # Test Basic Authentication with resources
+        # that are nested
+        uri = urlparse.urljoin(base, "basic-nested/")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        uri = urlparse.urljoin(base, "basic-nested/subdir")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        # Now add in credentials one at a time and test.
+        self.http.add_credentials('joe', 'password')
+
+        uri = urlparse.urljoin(base, "basic-nested/")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+        uri = urlparse.urljoin(base, "basic-nested/subdir")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        self.http.add_credentials('fred', 'barney')
+
+        uri = urlparse.urljoin(base, "basic-nested/")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+        uri = urlparse.urljoin(base, "basic-nested/subdir")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+    def testDigestAuth(self):
+        # Test that we support Digest Authentication
+        uri = urlparse.urljoin(base, "digest/")
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 401)
+
+        self.http.add_credentials('joe', 'password')
+        (response, content) = self.http.request(uri, "GET")
+        self.assertEqual(response.status, 200)
+
+        uri = urlparse.urljoin(base, "digest/file.txt")
+        (response, content) = self.http.request(uri, "GET")
+
+    def testDigestAuthNextNonceAndNC(self):
+        # Test that if the server sets nextnonce that we reset
+        # the nonce count back to 1
+        uri = urlparse.urljoin(base, "digest/file.txt")
+        self.http.add_credentials('joe', 'password')
+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
+        info = httplib2._parse_www_authenticate(response, 'authentication-info')
+        self.assertEqual(response.status, 200)
+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
+        info2 = httplib2._parse_www_authenticate(response, 'authentication-info')
+        self.assertEqual(response.status, 200)
+
+        if 'nextnonce' in info:
+            self.assertEqual(info2['nc'], 1)
+
+    def testDigestAuthStale(self):
+        # Test that we can handle a nonce becoming stale
+        uri = urlparse.urljoin(base, "digest-expire/file.txt")
+        self.http.add_credentials('joe', 'password')
+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
+        info = httplib2._parse_www_authenticate(response, 'authentication-info')
+        self.assertEqual(response.status, 200)
+
+        time.sleep(3)
+        # Sleep long enough that the nonce becomes stale
+
+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})
+        self.assertFalse(response.fromcache)
+        self.assertTrue(response._stale_digest)
+        info3 = httplib2._parse_www_authenticate(response, 'authentication-info')
+        self.assertEqual(response.status, 200)
+
+    def reflector(self, content):
+        return  dict( [tuple(x.split("=", 1)) for x in content.strip().split("\n")] )
+
+    def testReflector(self):
+        uri = urlparse.urljoin(base, "reflector/reflector.cgi")
+        (response, content) = self.http.request(uri, "GET")
+        d = self.reflector(content)
+        self.assertTrue('HTTP_USER_AGENT' in d)
+
+    def testConnectionClose(self):
+        uri = "http://www.google.com/"
+        (response, content) = self.http.request(uri, "GET")
+        for c in self.http.connections.values():
+            self.assertNotEqual(None, c.sock)
+        (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})
+        for c in self.http.connections.values():
+            self.assertEqual(None, c.sock)
+
+    def testPickleHttp(self):
+        pickled_http = pickle.dumps(self.http)
+        new_http = pickle.loads(pickled_http)
+
+        self.assertEqual(sorted(new_http.__dict__.keys()),
+                         sorted(self.http.__dict__.keys()))
+        for key in new_http.__dict__:
+            if key in ('certificates', 'credentials'):
+                self.assertEqual(new_http.__dict__[key].credentials,
+                                 self.http.__dict__[key].credentials)
+            elif key == 'cache':
+                self.assertEqual(new_http.__dict__[key].cache,
+                                 self.http.__dict__[key].cache)
+            else:
+                self.assertEqual(new_http.__dict__[key],
+                                 self.http.__dict__[key])
+
+    def testPickleHttpWithConnection(self):
+        self.http.request('http://bitworking.org',
+                          connection_type=_MyHTTPConnection)
+        pickled_http = pickle.dumps(self.http)
+        new_http = pickle.loads(pickled_http)
+
+        self.assertEqual(self.http.connections.keys(), ['http:bitworking.org'])
+        self.assertEqual(new_http.connections, {})
+
+    def testPickleCustomRequestHttp(self):
+        def dummy_request(*args, **kwargs):
+            return new_request(*args, **kwargs)
+        dummy_request.dummy_attr = 'dummy_value'
+
+        self.http.request = dummy_request
+        pickled_http = pickle.dumps(self.http)
+        self.assertFalse("S'request'" in pickled_http)
+
+try:
+    import memcache
+    class HttpTestMemCached(HttpTest):
+        def setUp(self):
+            self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)
+            #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)
+            self.http = httplib2.Http(self.cache)
+            self.cache.flush_all()
+            # Not exactly sure why the sleep is needed here, but
+            # if not present then some unit tests that rely on caching
+            # fail. Memcached seems to lose some sets immediately
+            # after a flush_all if the set is to a value that
+            # was previously cached. (Maybe the flush is handled async?)
+            time.sleep(1)
+            self.http.clear_credentials()
+except:
+    pass
+
+
+
+
+# ------------------------------------------------------------------------
+
+class HttpPrivateTest(unittest.TestCase):
+
+    def testParseCacheControl(self):
+        # Test that we can parse the Cache-Control header
+        self.assertEqual({}, httplib2._parse_cache_control({}))
+        self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))
+        cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})
+        self.assertEqual(cc['no-cache'], 1)
+        self.assertEqual(cc['max-age'], '7200')
+        cc = httplib2._parse_cache_control({'cache-control': ' , '})
+        self.assertEqual(cc[''], 1)
+
+        try:
+            cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})
+            self.assertTrue("max-age" in cc)
+        except:
+            self.fail("Should not throw exception")
+
+    def testNormalizeHeaders(self):
+        # Test that we normalize headers to lowercase
+        h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
+        self.assertTrue('cache-control' in h)
+        self.assertTrue('other' in h)
+        self.assertEqual('Stuff', h['other'])
+
+    def testExpirationModelTransparent(self):
+        # Test that no-cache makes our request TRANSPARENT
+        response_headers = {
+            'cache-control': 'max-age=7200'
+        }
+        request_headers = {
+            'cache-control': 'no-cache'
+        }
+        self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testMaxAgeNonNumeric(self):
+        # Test that no-cache makes our request TRANSPARENT
+        response_headers = {
+            'cache-control': 'max-age=fred, min-fresh=barney'
+        }
+        request_headers = {
+        }
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+
+    def testExpirationModelNoCacheResponse(self):
+        # The date and expires point to an entry that should be
+        # FRESH, but the no-cache over-rides that.
+        now = time.time()
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
+            'cache-control': 'no-cache'
+        }
+        request_headers = {
+        }
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationModelStaleRequestMustReval(self):
+        # must-revalidate forces STALE
+        self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))
+
+    def testExpirationModelStaleResponseMustReval(self):
+        # must-revalidate forces STALE
+        self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))
+
+    def testExpirationModelFresh(self):
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
+            'cache-control': 'max-age=2'
+        }
+        request_headers = {
+        }
+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
+        time.sleep(3)
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationMaxAge0(self):
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),
+            'cache-control': 'max-age=0'
+        }
+        request_headers = {
+        }
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationModelDateAndExpires(self):
+        now = time.time()
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
+        }
+        request_headers = {
+        }
+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
+        time.sleep(3)
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpiresZero(self):
+        now = time.time()
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
+            'expires': "0",
+        }
+        request_headers = {
+        }
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationModelDateOnly(self):
+        now = time.time()
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),
+        }
+        request_headers = {
+        }
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationModelOnlyIfCached(self):
+        response_headers = {
+        }
+        request_headers = {
+            'cache-control': 'only-if-cached',
+        }
+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationModelMaxAgeBoth(self):
+        now = time.time()
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
+            'cache-control': 'max-age=2'
+        }
+        request_headers = {
+            'cache-control': 'max-age=0'
+        }
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationModelDateAndExpiresMinFresh1(self):
+        now = time.time()
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),
+        }
+        request_headers = {
+            'cache-control': 'min-fresh=2'
+        }
+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testExpirationModelDateAndExpiresMinFresh2(self):
+        now = time.time()
+        response_headers = {
+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),
+        }
+        request_headers = {
+            'cache-control': 'min-fresh=2'
+        }
+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))
+
+    def testParseWWWAuthenticateEmpty(self):
+        res = httplib2._parse_www_authenticate({})
+        self.assertEqual(len(res.keys()), 0)
+
+    def testParseWWWAuthenticate(self):
+        # different uses of spaces around commas
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})
+        self.assertEqual(len(res.keys()), 1)
+        self.assertEqual(len(res['test'].keys()), 5)
+
+        # tokens with non-alphanum
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})
+        self.assertEqual(len(res.keys()), 1)
+        self.assertEqual(len(res['t*!%#st'].keys()), 2)
+
+        # quoted string with quoted pairs
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})
+        self.assertEqual(len(res.keys()), 1)
+        self.assertEqual(res['test']['realm'], 'a "test" realm')
+
+    def testParseWWWAuthenticateStrict(self):
+        httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;
+        self.testParseWWWAuthenticate();
+        httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;
+
+    def testParseWWWAuthenticateBasic(self):
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+        self.assertEqual('MD5', basic['algorithm'])
+
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+        self.assertEqual('MD5', basic['algorithm'])
+
+    def testParseWWWAuthenticateBasic2(self):
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+        self.assertEqual('fred', basic['other'])
+
+    def testParseWWWAuthenticateBasic3(self):
+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+
+
+    def testParseWWWAuthenticateDigest(self):
+        res = httplib2._parse_www_authenticate({ 'www-authenticate':
+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})
+        digest = res['digest']
+        self.assertEqual('testrealm@host.com', digest['realm'])
+        self.assertEqual('auth,auth-int', digest['qop'])
+
+
+    def testParseWWWAuthenticateMultiple(self):
+        res = httplib2._parse_www_authenticate({ 'www-authenticate':
+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})
+        digest = res['digest']
+        self.assertEqual('testrealm@host.com', digest['realm'])
+        self.assertEqual('auth,auth-int', digest['qop'])
+        self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
+        self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+
+    def testParseWWWAuthenticateMultiple2(self):
+        # Handle an added comma between challenges, which might get thrown in if the challenges were
+        # originally sent in separate www-authenticate headers.
+        res = httplib2._parse_www_authenticate({ 'www-authenticate':
+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})
+        digest = res['digest']
+        self.assertEqual('testrealm@host.com', digest['realm'])
+        self.assertEqual('auth,auth-int', digest['qop'])
+        self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
+        self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+
+    def testParseWWWAuthenticateMultiple3(self):
+        # Handle an added comma between challenges, which might get thrown in if the challenges were
+        # originally sent in separate www-authenticate headers.
+        res = httplib2._parse_www_authenticate({ 'www-authenticate':
+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
+        digest = res['digest']
+        self.assertEqual('testrealm@host.com', digest['realm'])
+        self.assertEqual('auth,auth-int', digest['qop'])
+        self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])
+        self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])
+        basic = res['basic']
+        self.assertEqual('me', basic['realm'])
+        wsse = res['wsse']
+        self.assertEqual('foo', wsse['realm'])
+        self.assertEqual('UsernameToken', wsse['profile'])
+
+    def testParseWWWAuthenticateMultiple4(self):
+        res = httplib2._parse_www_authenticate({ 'www-authenticate':
+                'Digest realm="test-real.m@host.com", qop \t=\t"\tauth,auth-int", nonce="(*)&^&$%#",opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})
+        digest = res['digest']
+        self.assertEqual('test-real.m@host.com', digest['realm'])
+        self.assertEqual('\tauth,auth-int', digest['qop'])
+        self.assertEqual('(*)&^&$%#', digest['nonce'])
+
+    def testParseWWWAuthenticateMoreQuoteCombos(self):
+        res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})
+        digest = res['digest']
+        self.assertEqual('myrealm', digest['realm'])
+
+    def testParseWWWAuthenticateMalformed(self):
+        try:
+          res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})
+          self.fail("should raise an exception")
+        except httplib2.MalformedHeader:
+          pass
+
+    def testDigestObject(self):
+        credentials = ('joe', 'password')
+        host = None
+        request_uri = '/projects/httplib2/test/digest/'
+        headers = {}
+        response = {
+            'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'
+        }
+        content = ""
+
+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+        d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
+        our_request = "authorization: %s" % headers['authorization']
+        working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46"'
+        self.assertEqual(our_request, working_request)
+
+    def testDigestObjectWithOpaque(self):
+        credentials = ('joe', 'password')
+        host = None
+        request_uri = '/projects/httplib2/test/digest/'
+        headers = {}
+        response = {
+            'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'
+        }
+        content = ""
+
+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+        d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")
+        our_request = "authorization: %s" % headers['authorization']
+        working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46", opaque="atestopaque"'
+        self.assertEqual(our_request, working_request)
+
+    def testDigestObjectStale(self):
+        credentials = ('joe', 'password')
+        host = None
+        request_uri = '/projects/httplib2/test/digest/'
+        headers = {}
+        response = httplib2.Response({ })
+        response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
+        response.status = 401
+        content = ""
+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+        # Returns true to force a retry
+        self.assertTrue( d.response(response, content) )
+
+    def testDigestObjectAuthInfo(self):
+        credentials = ('joe', 'password')
+        host = None
+        request_uri = '/projects/httplib2/test/digest/'
+        headers = {}
+        response = httplib2.Response({ })
+        response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'
+        response['authentication-info'] = 'nextnonce="fred"'
+        content = ""
+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+        # Returns true to force a retry
+        self.assertFalse( d.response(response, content) )
+        self.assertEqual('fred', d.challenge['nonce'])
+        self.assertEqual(1, d.challenge['nc'])
+
+    def testWsseAlgorithm(self):
+        digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")
+        expected = "quR/EWLAV4xLf9Zqyw4pDmfV9OY="
+        self.assertEqual(expected, digest)
+
+    def testEnd2End(self):
+        # one end to end header
+        response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
+        end2end = httplib2._get_end2end_headers(response)
+        self.assertTrue('content-type' in end2end)
+        self.assertTrue('te' not in end2end)
+        self.assertTrue('connection' not in end2end)
+
+        # one end to end header that gets eliminated
+        response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
+        end2end = httplib2._get_end2end_headers(response)
+        self.assertTrue('content-type' not in end2end)
+        self.assertTrue('te' not in end2end)
+        self.assertTrue('connection' not in end2end)
+
+        # Degenerate case of no headers
+        response = {}
+        end2end = httplib2._get_end2end_headers(response)
+        self.assertEquals(0, len(end2end))
+
+        # Degenerate case of connection referrring to a header not passed in
+        response = {'connection': 'content-type'}
+        end2end = httplib2._get_end2end_headers(response)
+        self.assertEquals(0, len(end2end))
+
+
+class TestProxyInfo(unittest.TestCase):
+    def setUp(self):
+        self.orig_env = dict(os.environ)
+
+    def tearDown(self):
+        os.environ.clear()
+        os.environ.update(self.orig_env)
+
+    def test_from_url(self):
+        pi = httplib2.proxy_info_from_url('http://myproxy.example.com')
+        self.assertEquals(pi.proxy_host, 'myproxy.example.com')
+        self.assertEquals(pi.proxy_port, 80)
+        self.assertEquals(pi.proxy_user, None)
+
+    def test_from_url_ident(self):
+        pi = httplib2.proxy_info_from_url('http://zoidberg:fish@someproxy:99')
+        self.assertEquals(pi.proxy_host, 'someproxy')
+        self.assertEquals(pi.proxy_port, 99)
+        self.assertEquals(pi.proxy_user, 'zoidberg')
+        self.assertEquals(pi.proxy_pass, 'fish')
+
+    def test_from_env(self):
+        os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
+        pi = httplib2.proxy_info_from_environment()
+        self.assertEquals(pi.proxy_host, 'myproxy.example.com')
+        self.assertEquals(pi.proxy_port, 8080)
+        self.assertEquals(pi.bypass_hosts, [])
+
+    def test_from_env_no_proxy(self):
+        os.environ['http_proxy'] = 'http://myproxy.example.com:80'
+        os.environ['https_proxy'] = 'http://myproxy.example.com:81'
+        os.environ['no_proxy'] = 'localhost,otherhost.domain.local'
+        pi = httplib2.proxy_info_from_environment('https')
+        self.assertEquals(pi.proxy_host, 'myproxy.example.com')
+        self.assertEquals(pi.proxy_port, 81)
+        self.assertEquals(pi.bypass_hosts, ['localhost',
+            'otherhost.domain.local'])
+
+    def test_from_env_none(self):
+        os.environ.clear()
+        pi = httplib2.proxy_info_from_environment()
+        self.assertEquals(pi, None)
+
+    def test_applies_to(self):
+        os.environ['http_proxy'] = 'http://myproxy.example.com:80'
+        os.environ['https_proxy'] = 'http://myproxy.example.com:81'
+        os.environ['no_proxy'] = 'localhost,otherhost.domain.local,example.com'
+        pi = httplib2.proxy_info_from_environment()
+        self.assertFalse(pi.applies_to('localhost'))
+        self.assertTrue(pi.applies_to('www.google.com'))
+        self.assertFalse(pi.applies_to('www.example.com'))
+
+    def test_no_proxy_star(self):
+        os.environ['http_proxy'] = 'http://myproxy.example.com:80'
+        os.environ['NO_PROXY'] = '*'
+        pi = httplib2.proxy_info_from_environment()
+        for host in ('localhost', '169.254.38.192', 'www.google.com'):
+            self.assertFalse(pi.applies_to(host))
+
+    def test_proxy_headers(self):
+        headers = {'key0': 'val0', 'key1': 'val1'}
+        pi = httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_HTTP, 'localhost', 1234, proxy_headers = headers)
+        self.assertEquals(pi.proxy_headers, headers)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/python2/httplib2test_appengine.py b/python2/httplib2test_appengine.py
new file mode 100755
index 0000000..9fad05a
--- /dev/null
+++ b/python2/httplib2test_appengine.py
@@ -0,0 +1,79 @@
+"""Tests for httplib2 on Google App Engine."""
+
+import mock
+import os
+import sys
+import unittest
+
+APP_ENGINE_PATH='/usr/local/google_appengine'
+
+sys.path.insert(0, APP_ENGINE_PATH)
+
+import dev_appserver
+dev_appserver.fix_sys_path()
+
+from google.appengine.ext import testbed
+
+# Ensure that we are not loading the httplib2 version included in the Google
+# App Engine SDK.
+sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
+
+
+class AberrationsTest(unittest.TestCase):
+
+  def setUp(self):
+    self.testbed = testbed.Testbed()
+    self.testbed.activate()
+    self.testbed.init_urlfetch_stub()
+
+  def tearDown(self):
+    self.testbed.deactivate()
+
+  @mock.patch.dict('os.environ', {'SERVER_SOFTWARE': ''})
+  def testConnectionInit(self):
+    global httplib2
+    import httplib2
+    self.assertNotEqual(
+      httplib2.SCHEME_TO_CONNECTION['https'], httplib2.AppEngineHttpsConnection)
+    self.assertNotEqual(
+      httplib2.SCHEME_TO_CONNECTION['http'], httplib2.AppEngineHttpConnection)
+    del globals()['httplib2']
+
+
+class AppEngineHttpTest(unittest.TestCase):
+
+  def setUp(self):
+    self.testbed = testbed.Testbed()
+    self.testbed.activate()
+    self.testbed.init_urlfetch_stub()
+    global httplib2
+    import httplib2
+    reload(httplib2)
+
+  def tearDown(self):
+    self.testbed.deactivate()
+    del globals()['httplib2']
+
+  def testConnectionInit(self):
+    self.assertEqual(
+      httplib2.SCHEME_TO_CONNECTION['https'], httplib2.AppEngineHttpsConnection)
+    self.assertEqual(
+      httplib2.SCHEME_TO_CONNECTION['http'], httplib2.AppEngineHttpConnection)
+
+  def testGet(self):
+    http = httplib2.Http()
+    response, content = http.request("http://www.google.com")
+    self.assertEqual(httplib2.SCHEME_TO_CONNECTION['https'],
+                     httplib2.AppEngineHttpsConnection)
+    self.assertEquals(1, len(http.connections))
+    self.assertEquals(response.status, 200)
+    self.assertEquals(response['status'], '200')
+
+  def testProxyInfoIgnored(self):
+    http = httplib2.Http(proxy_info=mock.MagicMock())
+    response, content = http.request("http://www.google.com")
+    self.assertEquals(response.status, 200)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/python2/ssl_protocol_test.py b/python2/ssl_protocol_test.py
new file mode 100755
index 0000000..bac84c0
--- /dev/null
+++ b/python2/ssl_protocol_test.py
@@ -0,0 +1,57 @@
+"""Tests for SSL handling in httplib2."""
+
+import httplib2
+import os
+import ssl
+import sys
+import unittest
+
+
+class TestSslProtocol(unittest.TestCase):
+
+  def testSslCertValidationWithInvalidCaCert(self):
+    if sys.version_info >= (2, 6):
+      http = httplib2.Http(ca_certs='/nosuchfile')
+      if sys.version_info >= (2, 7):
+        with self.assertRaises(IOError):
+          http.request('https://www.google.com/', 'GET')
+      else:
+        self.assertRaises(
+            ssl.SSLError, http.request, 'https://www.google.com/', 'GET')
+
+  def testSslCertValidationWithSelfSignedCaCert(self):
+    if sys.version_info >= (2, 7):
+      other_ca_certs = os.path.join(
+          os.path.dirname(os.path.abspath(httplib2.__file__ )), 'test',
+          'other_cacerts.txt')
+      http = httplib2.Http(ca_certs=other_ca_certs)
+      if sys.platform != 'darwin':
+        with self.assertRaises(httplib2.SSLHandshakeError):
+          http.request('https://www.google.com/', 'GET')
+
+  def testSslProtocolTlsV1AndShouldPass(self):
+    http = httplib2.Http(ssl_version=ssl.PROTOCOL_TLSv1)
+    urls = ['https://www.amazon.com',
+            'https://www.apple.com',
+            'https://www.twitter.com']
+    for url in urls:
+      if sys.version_info >= (2, 7):
+        self.assertIsNotNone(http.request(uri=url))
+
+  def testSslProtocolV3AndShouldFailDueToPoodle(self):
+    http = httplib2.Http(ssl_version=ssl.PROTOCOL_SSLv3)
+    urls = ['https://www.amazon.com',
+            'https://www.apple.com',
+            'https://www.twitter.com']
+    for url in urls:
+      if sys.version_info >= (2, 7):
+        with self.assertRaises(httplib2.SSLHandshakeError):
+          http.request(url)
+        try:
+          http.request(url)
+        except httplib2.SSLHandshakeError as e:
+          self.assertTrue('sslv3 alert handshake failure' in str(e))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/python3/README b/python3/README
new file mode 100755
index 0000000..f4b4409
--- /dev/null
+++ b/python3/README
@@ -0,0 +1,68 @@
+httplib2 for Python 3

+

+This directory contains a port of httplib2 to Python 3. As you may

+know, Python 3 is not backward-compatible with Python 2. The biggest

+change in Python 3 (that affects httplib2) is the distinction between

+bytes and strings.

+

+To successfully use http2lib for Python 3, you absolutely must

+understand the following sentence:

+

+** THE RESPONSE HEADERS ARE STRINGS, BUT THE CONTENT BODY IS BYTES **

+

+

+Example:

+

+>>> import httplib2, pprint

+>>> h = httplib2.Http(".cache")

+>>> (resp_headers, content) = h.request("http://example.org/", "GET")

+>>> pprint.pprint(resp_headers)

+{'accept-ranges': 'bytes',

+ 'connection': 'close',

+ 'content-length': '438',

+ 'content-location': 'http://example.org/',

+ 'content-type': 'text/html; charset=UTF-8',

+ 'date': 'Fri, 29 May 2009 03:57:29 GMT',

+ 'etag': '"b80f4-1b6-80bfd280"',

+ 'last-modified': 'Tue, 15 Nov 2005 13:24:10 GMT',

+ 'server': 'Apache/2.2.3 (CentOS)',

+ 'status': '200'}

+>>> type(content)

+<class 'bytes'>

+>>> content[:49]

+b'<HTML>\r\n<HEAD>\r\n  <TITLE>Example Web Page</TITLE>'

+

+

+Further reading:

+

+  * http://diveintopython3.org/strings.html

+  * http://docs.python.org/3.0/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit

+  * http://docs.python.org/3.0/howto/unicode.html

+

+

+--------------------------------------------------------------------

+Httplib2 Software License

+

+Copyright (c) 2006 by Joe Gregorio

+Copyright (c) 2009 by Mark Pilgrim

+

+Permission is hereby granted, free of charge, to any person 

+obtaining a copy of this software and associated documentation 

+files (the "Software"), to deal in the Software without restriction, 

+including without limitation the rights to use, copy, modify, merge, 

+publish, distribute, sublicense, and/or sell copies of the Software, 

+and to permit persons to whom the Software is furnished to do so, 

+subject to the following conditions:

+

+The above copyright notice and this permission notice shall be 

+included in all copies or substantial portions of the Software.

+

+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 

+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 

+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 

+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 

+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 

+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 

+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 

+SOFTWARE.

+

diff --git a/python3/httplib2/__init__.py b/python3/httplib2/__init__.py
new file mode 100644
index 0000000..5dae2a5
--- /dev/null
+++ b/python3/httplib2/__init__.py
@@ -0,0 +1,1591 @@
+"""
+httplib2
+
+A caching http interface that supports ETags and gzip
+to conserve bandwidth.
+
+Requires Python 3.0 or later
+
+Changelog:
+2009-05-28, Pilgrim: ported to Python 3
+2007-08-18, Rick: Modified so it's able to use a socks proxy if needed.
+
+"""
+
+__author__ = "Joe Gregorio (joe@bitworking.org)"
+__copyright__ = "Copyright 2006, Joe Gregorio"
+__contributors__ = ["Thomas Broyer (t.broyer@ltgt.net)",
+    "James Antill",
+    "Xavier Verges Farrero",
+    "Jonathan Feinberg",
+    "Blair Zajac",
+    "Sam Ruby",
+    "Louis Nyffenegger",
+    "Mark Pilgrim"]
+__license__ = "MIT"
+__version__ = '0.11.3'
+
+import re
+import sys
+import email
+import email.utils
+import email.message
+import email.feedparser
+import io
+import gzip
+import zlib
+import http.client
+import urllib.parse
+import base64
+import os
+import copy
+import calendar
+import time
+import random
+import errno
+from hashlib import sha1 as _sha, md5 as _md5
+import hmac
+from gettext import gettext as _
+import socket
+import ssl
+
+
+try:
+    import socks
+except ImportError:
+    # TODO: remove this fallback and copypasted socksipy module upon py2/3 merge,
+    # idea is to have soft-dependency on any compatible module called socks
+    from . import socks
+from .iri2uri import iri2uri
+
+def has_timeout(timeout):
+    if hasattr(socket, '_GLOBAL_DEFAULT_TIMEOUT'):
+        return (timeout is not None and timeout is not socket._GLOBAL_DEFAULT_TIMEOUT)
+    return (timeout is not None)
+
+__all__ = ['Http', 'Response', 'ProxyInfo', 'HttpLib2Error',
+           'RedirectMissingLocation', 'RedirectLimit',
+           'FailedToDecompressContent', 'UnimplementedDigestAuthOptionError',
+           'UnimplementedHmacDigestAuthOptionError',
+           'debuglevel', 'RETRIES']
+
+
+# The httplib debug level, set to a non-zero value to get debug output
+debuglevel = 0
+
+# A request will be tried 'RETRIES' times if it fails at the socket/connection level.
+RETRIES = 2
+
+# All exceptions raised here derive from HttpLib2Error
+class HttpLib2Error(Exception): pass
+
+# Some exceptions can be caught and optionally
+# be turned back into responses.
+class HttpLib2ErrorWithResponse(HttpLib2Error):
+    def __init__(self, desc, response, content):
+        self.response = response
+        self.content = content
+        HttpLib2Error.__init__(self, desc)
+
+class RedirectMissingLocation(HttpLib2ErrorWithResponse): pass
+class RedirectLimit(HttpLib2ErrorWithResponse): pass
+class FailedToDecompressContent(HttpLib2ErrorWithResponse): pass
+class UnimplementedDigestAuthOptionError(HttpLib2ErrorWithResponse): pass
+class UnimplementedHmacDigestAuthOptionError(HttpLib2ErrorWithResponse): pass
+
+class MalformedHeader(HttpLib2Error): pass
+class RelativeURIError(HttpLib2Error): pass
+class ServerNotFoundError(HttpLib2Error): pass
+
+class ProxiesUnavailableError(HttpLib2Error): pass
+
+
+# Open Items:
+# -----------
+
+# Are we removing the cached content too soon on PUT (only delete on 200 Maybe?)
+
+# Pluggable cache storage (supports storing the cache in
+#   flat files by default. We need a plug-in architecture
+#   that can support Berkeley DB and Squid)
+
+# == Known Issues ==
+# Does not handle a resource that uses conneg and Last-Modified but no ETag as a cache validator.
+# Does not handle Cache-Control: max-stale
+# Does not use Age: headers when calculating cache freshness.
+
+
+# The number of redirections to follow before giving up.
+# Note that only GET redirects are automatically followed.
+# Will also honor 301 requests by saving that info and never
+# requesting that URI again.
+DEFAULT_MAX_REDIRECTS = 5
+
+# Which headers are hop-by-hop headers by default
+HOP_BY_HOP = ['connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'transfer-encoding', 'upgrade']
+
+# Default CA certificates file bundled with httplib2.
+CA_CERTS = os.path.join(
+        os.path.dirname(os.path.abspath(__file__ )), "cacerts.txt")
+
+# PROTOCOL_TLS is python 3.5.3+. PROTOCOL_SSLv23 is deprecated.
+# Both PROTOCOL_TLS and PROTOCOL_SSLv23 are equivalent and means:
+# > Selects the highest protocol version that both the client and server support.
+# > Despite the name, this option can select “TLS” protocols as well as “SSL”.
+# source: https://docs.python.org/3.5/library/ssl.html#ssl.PROTOCOL_TLS
+DEFAULT_TLS_VERSION = getattr(ssl, 'PROTOCOL_TLS', None) or getattr(ssl, 'PROTOCOL_SSLv23')
+
+
+def _build_ssl_context(disable_ssl_certificate_validation, ca_certs, cert_file=None, key_file=None):
+    if not hasattr(ssl, 'SSLContext'):
+        raise RuntimeError("httplib2 requires Python 3.2+ for ssl.SSLContext")
+
+    context = ssl.SSLContext(DEFAULT_TLS_VERSION)
+    context.verify_mode = ssl.CERT_NONE if disable_ssl_certificate_validation else ssl.CERT_REQUIRED
+
+    # check_hostname requires python 3.4+
+    # we will perform the equivalent in HTTPSConnectionWithTimeout.connect() by calling ssl.match_hostname
+    # if check_hostname is not supported.
+    if hasattr(context, 'check_hostname'):
+        context.check_hostname = not disable_ssl_certificate_validation
+
+    context.load_verify_locations(ca_certs)
+
+    if cert_file:
+        context.load_cert_chain(cert_file, key_file)
+
+    return context
+
+def _get_end2end_headers(response):
+    hopbyhop = list(HOP_BY_HOP)
+    hopbyhop.extend([x.strip() for x in response.get('connection', '').split(',')])
+    return [header for header in list(response.keys()) if header not in hopbyhop]
+
+URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?")
+
+def parse_uri(uri):
+    """Parses a URI using the regex given in Appendix B of RFC 3986.
+
+        (scheme, authority, path, query, fragment) = parse_uri(uri)
+    """
+    groups = URI.match(uri).groups()
+    return (groups[1], groups[3], groups[4], groups[6], groups[8])
+
+def urlnorm(uri):
+    (scheme, authority, path, query, fragment) = parse_uri(uri)
+    if not scheme or not authority:
+        raise RelativeURIError("Only absolute URIs are allowed. uri = %s" % uri)
+    authority = authority.lower()
+    scheme = scheme.lower()
+    if not path:
+        path = "/"
+    # Could do syntax based normalization of the URI before
+    # computing the digest. See Section 6.2.2 of Std 66.
+    request_uri = query and "?".join([path, query]) or path
+    scheme = scheme.lower()
+    defrag_uri = scheme + "://" + authority + request_uri
+    return scheme, authority, request_uri, defrag_uri
+
+
+# Cache filename construction (original borrowed from Venus http://intertwingly.net/code/venus/)
+re_url_scheme    = re.compile(br'^\w+://')
+re_url_scheme_s  = re.compile(r'^\w+://')
+re_slash         = re.compile(br'[?/:|]+')
+
+def safename(filename):
+    """Return a filename suitable for the cache.
+
+    Strips dangerous and common characters to create a filename we
+    can use to store the cache in.
+    """
+
+    try:
+        if re_url_scheme_s.match(filename):
+            if isinstance(filename,bytes):
+                filename = filename.decode('utf-8')
+                filename = filename.encode('idna')
+            else:
+                filename = filename.encode('idna')
+    except UnicodeError:
+        pass
+    if isinstance(filename,str):
+        filename=filename.encode('utf-8')
+    filemd5 = _md5(filename).hexdigest().encode('utf-8')
+    filename = re_url_scheme.sub(b"", filename)
+    filename = re_slash.sub(b",", filename)
+
+    # limit length of filename
+    if len(filename)>200:
+        filename=filename[:200]
+    return b",".join((filename, filemd5)).decode('utf-8')
+
+NORMALIZE_SPACE = re.compile(r'(?:\r\n)?[ \t]+')
+def _normalize_headers(headers):
+    return dict([ (_convert_byte_str(key).lower(), NORMALIZE_SPACE.sub(_convert_byte_str(value), ' ').strip())  for (key, value) in headers.items()])
+
+def _convert_byte_str(s):
+    if not isinstance(s, str):
+        return str(s, 'utf-8')
+    return s
+
+def _parse_cache_control(headers):
+    retval = {}
+    if 'cache-control' in headers:
+        parts =  headers['cache-control'].split(',')
+        parts_with_args = [tuple([x.strip().lower() for x in part.split("=", 1)]) for part in parts if -1 != part.find("=")]
+        parts_wo_args = [(name.strip().lower(), 1) for name in parts if -1 == name.find("=")]
+        retval = dict(parts_with_args + parts_wo_args)
+    return retval
+
+# Whether to use a strict mode to parse WWW-Authenticate headers
+# Might lead to bad results in case of ill-formed header value,
+# so disabled by default, falling back to relaxed parsing.
+# Set to true to turn on, usefull for testing servers.
+USE_WWW_AUTH_STRICT_PARSING = 0
+
+# In regex below:
+#    [^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+             matches a "token" as defined by HTTP
+#    "(?:[^\0-\x08\x0A-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?"    matches a "quoted-string" as defined by HTTP, when LWS have already been replaced by a single space
+# Actually, as an auth-param value can be either a token or a quoted-string, they are combined in a single pattern which matches both:
+#    \"?((?<=\")(?:[^\0-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?(?=\")|(?<!\")[^\0-\x08\x0A-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+(?!\"))\"?
+WWW_AUTH_STRICT = re.compile(r"^(?:\s*(?:,\s*)?([^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+)\s*=\s*\"?((?<=\")(?:[^\0-\x08\x0A-\x1f\x7f-\xff\\\"]|\\[\0-\x7f])*?(?=\")|(?<!\")[^\0-\x1f\x7f-\xff()<>@,;:\\\"/[\]?={} \t]+(?!\"))\"?)(.*)$")
+WWW_AUTH_RELAXED = re.compile(r"^(?:\s*(?:,\s*)?([^ \t\r\n=]+)\s*=\s*\"?((?<=\")(?:[^\\\"]|\\.)*?(?=\")|(?<!\")[^ \t\r\n,]+(?!\"))\"?)(.*)$")
+UNQUOTE_PAIRS = re.compile(r'\\(.)')
+def _parse_www_authenticate(headers, headername='www-authenticate'):
+    """Returns a dictionary of dictionaries, one dict
+    per auth_scheme."""
+    retval = {}
+    if headername in headers:
+        try:
+            authenticate = headers[headername].strip()
+            www_auth = USE_WWW_AUTH_STRICT_PARSING and WWW_AUTH_STRICT or WWW_AUTH_RELAXED
+            while authenticate:
+                # Break off the scheme at the beginning of the line
+                if headername == 'authentication-info':
+                    (auth_scheme, the_rest) = ('digest', authenticate)
+                else:
+                    (auth_scheme, the_rest) = authenticate.split(" ", 1)
+                # Now loop over all the key value pairs that come after the scheme,
+                # being careful not to roll into the next scheme
+                match = www_auth.search(the_rest)
+                auth_params = {}
+                while match:
+                    if match and len(match.groups()) == 3:
+                        (key, value, the_rest) = match.groups()
+                        auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')])
+                    match = www_auth.search(the_rest)
+                retval[auth_scheme.lower()] = auth_params
+                authenticate = the_rest.strip()
+        except ValueError:
+            raise MalformedHeader("WWW-Authenticate")
+    return retval
+
+
+def _entry_disposition(response_headers, request_headers):
+    """Determine freshness from the Date, Expires and Cache-Control headers.
+
+    We don't handle the following:
+
+    1. Cache-Control: max-stale
+    2. Age: headers are not used in the calculations.
+
+    Not that this algorithm is simpler than you might think
+    because we are operating as a private (non-shared) cache.
+    This lets us ignore 's-maxage'. We can also ignore
+    'proxy-invalidate' since we aren't a proxy.
+    We will never return a stale document as
+    fresh as a design decision, and thus the non-implementation
+    of 'max-stale'. This also lets us safely ignore 'must-revalidate'
+    since we operate as if every server has sent 'must-revalidate'.
+    Since we are private we get to ignore both 'public' and
+    'private' parameters. We also ignore 'no-transform' since
+    we don't do any transformations.
+    The 'no-store' parameter is handled at a higher level.
+    So the only Cache-Control parameters we look at are:
+
+    no-cache
+    only-if-cached
+    max-age
+    min-fresh
+    """
+
+    retval = "STALE"
+    cc = _parse_cache_control(request_headers)
+    cc_response = _parse_cache_control(response_headers)
+
+    if 'pragma' in request_headers and request_headers['pragma'].lower().find('no-cache') != -1:
+        retval = "TRANSPARENT"
+        if 'cache-control' not in request_headers:
+            request_headers['cache-control'] = 'no-cache'
+    elif 'no-cache' in cc:
+        retval = "TRANSPARENT"
+    elif 'no-cache' in cc_response:
+        retval = "STALE"
+    elif 'only-if-cached' in cc:
+        retval = "FRESH"
+    elif 'date' in response_headers:
+        date = calendar.timegm(email.utils.parsedate_tz(response_headers['date']))
+        now = time.time()
+        current_age = max(0, now - date)
+        if 'max-age' in cc_response:
+            try:
+                freshness_lifetime = int(cc_response['max-age'])
+            except ValueError:
+                freshness_lifetime = 0
+        elif 'expires' in response_headers:
+            expires = email.utils.parsedate_tz(response_headers['expires'])
+            if None == expires:
+                freshness_lifetime = 0
+            else:
+                freshness_lifetime = max(0, calendar.timegm(expires) - date)
+        else:
+            freshness_lifetime = 0
+        if 'max-age' in cc:
+            try:
+                freshness_lifetime = int(cc['max-age'])
+            except ValueError:
+                freshness_lifetime = 0
+        if 'min-fresh' in cc:
+            try:
+                min_fresh = int(cc['min-fresh'])
+            except ValueError:
+                min_fresh = 0
+            current_age += min_fresh
+        if freshness_lifetime > current_age:
+            retval = "FRESH"
+    return retval
+
+def _decompressContent(response, new_content):
+    content = new_content
+    try:
+        encoding = response.get('content-encoding', None)
+        if encoding in ['gzip', 'deflate']:
+            if encoding == 'gzip':
+                content = gzip.GzipFile(fileobj=io.BytesIO(new_content)).read()
+            if encoding == 'deflate':
+                content = zlib.decompress(content, -zlib.MAX_WBITS)
+            response['content-length'] = str(len(content))
+            # Record the historical presence of the encoding in a way the won't interfere.
+            response['-content-encoding'] = response['content-encoding']
+            del response['content-encoding']
+    except (IOError, zlib.error):
+        content = ""
+        raise FailedToDecompressContent(_("Content purported to be compressed with %s but failed to decompress.") % response.get('content-encoding'), response, content)
+    return content
+
+def _bind_write_headers(msg):
+  from email.header import Header
+  def _write_headers(self):
+      # Self refers to the Generator object
+      for h, v in msg.items():
+          print('%s:' % h, end=' ', file=self._fp)
+          if isinstance(v, Header):
+              print(v.encode(maxlinelen=self._maxheaderlen), file=self._fp)
+          else:
+              # Header's got lots of smarts, so use it.
+              header = Header(v, maxlinelen=self._maxheaderlen, charset='utf-8',
+                              header_name=h)
+              print(header.encode(), file=self._fp)
+      # A blank line always separates headers from body
+      print(file=self._fp)
+  return _write_headers
+
+def _updateCache(request_headers, response_headers, content, cache, cachekey):
+    if cachekey:
+        cc = _parse_cache_control(request_headers)
+        cc_response = _parse_cache_control(response_headers)
+        if 'no-store' in cc or 'no-store' in cc_response:
+            cache.delete(cachekey)
+        else:
+            info = email.message.Message()
+            for key, value in response_headers.items():
+                if key not in ['status','content-encoding','transfer-encoding']:
+                    info[key] = value
+
+            # Add annotations to the cache to indicate what headers
+            # are variant for this request.
+            vary = response_headers.get('vary', None)
+            if vary:
+                vary_headers = vary.lower().replace(' ', '').split(',')
+                for header in vary_headers:
+                    key = '-varied-%s' % header
+                    try:
+                        info[key] = request_headers[header]
+                    except KeyError:
+                        pass
+
+            status = response_headers.status
+            if status == 304:
+                status = 200
+
+            status_header = 'status: %d\r\n' % status
+
+            try:
+                header_str = info.as_string()
+            except UnicodeEncodeError:
+                setattr(info, '_write_headers', _bind_write_headers(info))
+                header_str = info.as_string()
+
+            header_str = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", header_str)
+            text = b"".join([status_header.encode('utf-8'), header_str.encode('utf-8'), content])
+
+            cache.set(cachekey, text)
+
+def _cnonce():
+    dig = _md5(("%s:%s" % (time.ctime(), ["0123456789"[random.randrange(0, 9)] for i in range(20)])).encode('utf-8')).hexdigest()
+    return dig[:16]
+
+def _wsse_username_token(cnonce, iso_now, password):
+    return base64.b64encode(_sha(("%s%s%s" % (cnonce, iso_now, password)).encode('utf-8')).digest()).strip()
+
+
+# For credentials we need two things, first
+# a pool of credential to try (not necesarily tied to BAsic, Digest, etc.)
+# Then we also need a list of URIs that have already demanded authentication
+# That list is tricky since sub-URIs can take the same auth, or the
+# auth scheme may change as you descend the tree.
+# So we also need each Auth instance to be able to tell us
+# how close to the 'top' it is.
+
+class Authentication(object):
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
+        self.path = path
+        self.host = host
+        self.credentials = credentials
+        self.http = http
+
+    def depth(self, request_uri):
+        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
+        return request_uri[len(self.path):].count("/")
+
+    def inscope(self, host, request_uri):
+        # XXX Should we normalize the request_uri?
+        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
+        return (host == self.host) and path.startswith(self.path)
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header. Over-rise this in sub-classes."""
+        pass
+
+    def response(self, response, content):
+        """Gives us a chance to update with new nonces
+        or such returned from the last authorized response.
+        Over-rise this in sub-classes if necessary.
+
+        Return TRUE is the request is to be retried, for
+        example Digest may return stale=true.
+        """
+        return False
+
+    def __eq__(self, auth):
+        return False
+
+    def __ne__(self, auth):
+        return True
+
+    def __lt__(self, auth):
+        return True
+
+    def __gt__(self, auth):
+        return False
+
+    def __le__(self, auth):
+        return True
+
+    def __ge__(self, auth):
+        return False
+
+    def __bool__(self):
+        return True
+
+
+class BasicAuthentication(Authentication):
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header."""
+        headers['authorization'] = 'Basic ' + base64.b64encode(("%s:%s" % self.credentials).encode('utf-8')).strip().decode('utf-8')
+
+
+class DigestAuthentication(Authentication):
+    """Only do qop='auth' and MD5, since that
+    is all Apache currently implements"""
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+        challenge = _parse_www_authenticate(response, 'www-authenticate')
+        self.challenge = challenge['digest']
+        qop = self.challenge.get('qop', 'auth')
+        self.challenge['qop'] = ('auth' in [x.strip() for x in qop.split()]) and 'auth' or None
+        if self.challenge['qop'] is None:
+            raise UnimplementedDigestAuthOptionError( _("Unsupported value for qop: %s." % qop))
+        self.challenge['algorithm'] = self.challenge.get('algorithm', 'MD5').upper()
+        if self.challenge['algorithm'] != 'MD5':
+            raise UnimplementedDigestAuthOptionError( _("Unsupported value for algorithm: %s." % self.challenge['algorithm']))
+        self.A1 = "".join([self.credentials[0], ":", self.challenge['realm'], ":", self.credentials[1]])
+        self.challenge['nc'] = 1
+
+    def request(self, method, request_uri, headers, content, cnonce = None):
+        """Modify the request headers"""
+        H = lambda x: _md5(x.encode('utf-8')).hexdigest()
+        KD = lambda s, d: H("%s:%s" % (s, d))
+        A2 = "".join([method, ":", request_uri])
+        self.challenge['cnonce'] = cnonce or _cnonce()
+        request_digest  = '"%s"' % KD(H(self.A1), "%s:%s:%s:%s:%s" % (
+                self.challenge['nonce'],
+                '%08x' % self.challenge['nc'],
+                self.challenge['cnonce'],
+                self.challenge['qop'], H(A2)))
+        headers['authorization'] = 'Digest username="%s", realm="%s", nonce="%s", uri="%s", algorithm=%s, response=%s, qop=%s, nc=%08x, cnonce="%s"' % (
+                self.credentials[0],
+                self.challenge['realm'],
+                self.challenge['nonce'],
+                request_uri,
+                self.challenge['algorithm'],
+                request_digest,
+                self.challenge['qop'],
+                self.challenge['nc'],
+                self.challenge['cnonce'])
+        if self.challenge.get('opaque'):
+            headers['authorization'] += ', opaque="%s"' % self.challenge['opaque']
+        self.challenge['nc'] += 1
+
+    def response(self, response, content):
+        if 'authentication-info' not in response:
+            challenge = _parse_www_authenticate(response, 'www-authenticate').get('digest', {})
+            if 'true' == challenge.get('stale'):
+                self.challenge['nonce'] = challenge['nonce']
+                self.challenge['nc'] = 1
+                return True
+        else:
+            updated_challenge = _parse_www_authenticate(response, 'authentication-info').get('digest', {})
+
+            if 'nextnonce' in updated_challenge:
+                self.challenge['nonce'] = updated_challenge['nextnonce']
+                self.challenge['nc'] = 1
+        return False
+
+
+class HmacDigestAuthentication(Authentication):
+    """Adapted from Robert Sayre's code and DigestAuthentication above."""
+    __author__ = "Thomas Broyer (t.broyer@ltgt.net)"
+
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+        challenge = _parse_www_authenticate(response, 'www-authenticate')
+        self.challenge = challenge['hmacdigest']
+        # TODO: self.challenge['domain']
+        self.challenge['reason'] = self.challenge.get('reason', 'unauthorized')
+        if self.challenge['reason'] not in ['unauthorized', 'integrity']:
+            self.challenge['reason'] = 'unauthorized'
+        self.challenge['salt'] = self.challenge.get('salt', '')
+        if not self.challenge.get('snonce'):
+            raise UnimplementedHmacDigestAuthOptionError( _("The challenge doesn't contain a server nonce, or this one is empty."))
+        self.challenge['algorithm'] = self.challenge.get('algorithm', 'HMAC-SHA-1')
+        if self.challenge['algorithm'] not in ['HMAC-SHA-1', 'HMAC-MD5']:
+            raise UnimplementedHmacDigestAuthOptionError( _("Unsupported value for algorithm: %s." % self.challenge['algorithm']))
+        self.challenge['pw-algorithm'] = self.challenge.get('pw-algorithm', 'SHA-1')
+        if self.challenge['pw-algorithm'] not in ['SHA-1', 'MD5']:
+            raise UnimplementedHmacDigestAuthOptionError( _("Unsupported value for pw-algorithm: %s." % self.challenge['pw-algorithm']))
+        if self.challenge['algorithm'] == 'HMAC-MD5':
+            self.hashmod = _md5
+        else:
+            self.hashmod = _sha
+        if self.challenge['pw-algorithm'] == 'MD5':
+            self.pwhashmod = _md5
+        else:
+            self.pwhashmod = _sha
+        self.key = "".join([self.credentials[0], ":",
+                            self.pwhashmod.new("".join([self.credentials[1], self.challenge['salt']])).hexdigest().lower(),
+                            ":", self.challenge['realm']])
+        self.key = self.pwhashmod.new(self.key).hexdigest().lower()
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers"""
+        keys = _get_end2end_headers(headers)
+        keylist = "".join(["%s " % k for k in keys])
+        headers_val = "".join([headers[k] for k in keys])
+        created = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime())
+        cnonce = _cnonce()
+        request_digest = "%s:%s:%s:%s:%s" % (method, request_uri, cnonce, self.challenge['snonce'], headers_val)
+        request_digest  = hmac.new(self.key, request_digest, self.hashmod).hexdigest().lower()
+        headers['authorization'] = 'HMACDigest username="%s", realm="%s", snonce="%s", cnonce="%s", uri="%s", created="%s", response="%s", headers="%s"' % (
+                self.credentials[0],
+                self.challenge['realm'],
+                self.challenge['snonce'],
+                cnonce,
+                request_uri,
+                created,
+                request_digest,
+                keylist)
+
+    def response(self, response, content):
+        challenge = _parse_www_authenticate(response, 'www-authenticate').get('hmacdigest', {})
+        if challenge.get('reason') in ['integrity', 'stale']:
+            return True
+        return False
+
+
+class WsseAuthentication(Authentication):
+    """This is thinly tested and should not be relied upon.
+    At this time there isn't any third party server to test against.
+    Blogger and TypePad implemented this algorithm at one point
+    but Blogger has since switched to Basic over HTTPS and
+    TypePad has implemented it wrong, by never issuing a 401
+    challenge but instead requiring your client to telepathically know that
+    their endpoint is expecting WSSE profile="UsernameToken"."""
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header."""
+        headers['authorization'] = 'WSSE profile="UsernameToken"'
+        iso_now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
+        cnonce = _cnonce()
+        password_digest = _wsse_username_token(cnonce, iso_now, self.credentials[1])
+        headers['X-WSSE'] = 'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"' % (
+                self.credentials[0],
+                password_digest,
+                cnonce,
+                iso_now)
+
+class GoogleLoginAuthentication(Authentication):
+    def __init__(self, credentials, host, request_uri, headers, response, content, http):
+        from urllib.parse import urlencode
+        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
+        challenge = _parse_www_authenticate(response, 'www-authenticate')
+        service = challenge['googlelogin'].get('service', 'xapi')
+        # Bloggger actually returns the service in the challenge
+        # For the rest we guess based on the URI
+        if service == 'xapi' and  request_uri.find("calendar") > 0:
+            service = "cl"
+        # No point in guessing Base or Spreadsheet
+        #elif request_uri.find("spreadsheets") > 0:
+        #    service = "wise"
+
+        auth = dict(Email=credentials[0], Passwd=credentials[1], service=service, source=headers['user-agent'])
+        resp, content = self.http.request("https://www.google.com/accounts/ClientLogin", method="POST", body=urlencode(auth), headers={'Content-Type': 'application/x-www-form-urlencoded'})
+        lines = content.split('\n')
+        d = dict([tuple(line.split("=", 1)) for line in lines if line])
+        if resp.status == 403:
+            self.Auth = ""
+        else:
+            self.Auth = d['Auth']
+
+    def request(self, method, request_uri, headers, content):
+        """Modify the request headers to add the appropriate
+        Authorization header."""
+        headers['authorization'] = 'GoogleLogin Auth=' + self.Auth
+
+
+AUTH_SCHEME_CLASSES = {
+    "basic": BasicAuthentication,
+    "wsse": WsseAuthentication,
+    "digest": DigestAuthentication,
+    "hmacdigest": HmacDigestAuthentication,
+    "googlelogin": GoogleLoginAuthentication
+}
+
+AUTH_SCHEME_ORDER = ["hmacdigest", "googlelogin", "digest", "wsse", "basic"]
+
+class FileCache(object):
+    """Uses a local directory as a store for cached files.
+    Not really safe to use if multiple threads or processes are going to
+    be running on the same cache.
+    """
+    def __init__(self, cache, safe=safename): # use safe=lambda x: md5.new(x).hexdigest() for the old behavior
+        self.cache = cache
+        self.safe = safe
+        if not os.path.exists(cache):
+            os.makedirs(self.cache)
+
+    def get(self, key):
+        retval = None
+        cacheFullPath = os.path.join(self.cache, self.safe(key))
+        try:
+            f = open(cacheFullPath, "rb")
+            retval = f.read()
+            f.close()
+        except IOError:
+            pass
+        return retval
+
+    def set(self, key, value):
+        cacheFullPath = os.path.join(self.cache, self.safe(key))
+        f = open(cacheFullPath, "wb")
+        f.write(value)
+        f.close()
+
+    def delete(self, key):
+        cacheFullPath = os.path.join(self.cache, self.safe(key))
+        if os.path.exists(cacheFullPath):
+            os.remove(cacheFullPath)
+
+class Credentials(object):
+    def __init__(self):
+        self.credentials = []
+
+    def add(self, name, password, domain=""):
+        self.credentials.append((domain.lower(), name, password))
+
+    def clear(self):
+        self.credentials = []
+
+    def iter(self, domain):
+        for (cdomain, name, password) in self.credentials:
+            if cdomain == "" or domain == cdomain:
+                yield (name, password)
+
+class KeyCerts(Credentials):
+    """Identical to Credentials except that
+    name/password are mapped to key/cert."""
+    pass
+
+
+class AllHosts(object):
+    pass
+
+
+class ProxyInfo(object):
+  """Collect information required to use a proxy."""
+  bypass_hosts = ()
+
+  def __init__(self, proxy_type, proxy_host, proxy_port, proxy_rdns=True, proxy_user=None, proxy_pass=None, proxy_headers=None):
+      """
+        Args:
+          proxy_type: The type of proxy server.  This must be set to one of
+          socks.PROXY_TYPE_XXX constants.  For example:
+
+            p = ProxyInfo(proxy_type=socks.PROXY_TYPE_HTTP,
+              proxy_host='localhost', proxy_port=8000)
+
+          proxy_host: The hostname or IP address of the proxy server.
+
+          proxy_port: The port that the proxy server is running on.
+
+          proxy_rdns: If True (default), DNS queries will not be performed
+          locally, and instead, handed to the proxy to resolve.  This is useful
+          if the network does not allow resolution of non-local names.  In
+          httplib2 0.9 and earlier, this defaulted to False.
+
+          proxy_user: The username used to authenticate with the proxy server.
+
+          proxy_pass: The password used to authenticate with the proxy server.
+
+          proxy_headers: Additional or modified headers for the proxy connect request.
+      """
+      self.proxy_type, self.proxy_host, self.proxy_port, self.proxy_rdns, self.proxy_user, self.proxy_pass, self.proxy_headers = proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers
+
+  def astuple(self):
+    return (self.proxy_type, self.proxy_host, self.proxy_port, self.proxy_rdns,
+            self.proxy_user, self.proxy_pass, self.proxy_headers)
+
+  def isgood(self):
+    return socks and (self.proxy_host != None) and (self.proxy_port != None)
+
+  def applies_to(self, hostname):
+    return not self.bypass_host(hostname)
+
+  def bypass_host(self, hostname):
+    """Has this host been excluded from the proxy config"""
+    if self.bypass_hosts is AllHosts:
+      return True
+
+    hostname = '.' + hostname.lstrip('.')
+    for skip_name in self.bypass_hosts:
+      # *.suffix
+      if skip_name.startswith('.') and hostname.endswith(skip_name):
+        return True
+      # exact match
+      if hostname == '.' + skip_name:
+        return True
+    return False
+
+  def __repr__(self):
+    return (
+        '<ProxyInfo type={p.proxy_type} host:port={p.proxy_host}:{p.proxy_port} rdns={p.proxy_rdns}' +
+        ' user={p.proxy_user} headers={p.proxy_headers}>').format(p=self)
+
+
+def proxy_info_from_environment(method='http'):
+    """
+    Read proxy info from the environment variables.
+    """
+    if method not in ('http', 'https'):
+        return
+
+    env_var = method + '_proxy'
+    url = os.environ.get(env_var, os.environ.get(env_var.upper()))
+    if not url:
+        return
+    return proxy_info_from_url(url, method, noproxy=None)
+
+
+def proxy_info_from_url(url, method='http', noproxy=None):
+    """
+    Construct a ProxyInfo from a URL (such as http_proxy env var)
+    """
+    url = urllib.parse.urlparse(url)
+    username = None
+    password = None
+    port = None
+    if '@' in url[1]:
+        ident, host_port = url[1].split('@', 1)
+        if ':' in ident:
+            username, password = ident.split(':', 1)
+        else:
+            password = ident
+    else:
+        host_port = url[1]
+    if ':' in host_port:
+        host, port = host_port.split(':', 1)
+    else:
+        host = host_port
+
+    if port:
+        port = int(port)
+    else:
+        port = dict(https=443, http=80)[method]
+
+    proxy_type = 3  # socks.PROXY_TYPE_HTTP
+    pi = ProxyInfo(
+        proxy_type=proxy_type,
+        proxy_host=host,
+        proxy_port=port,
+        proxy_user=username or None,
+        proxy_pass=password or None,
+        proxy_headers=None,
+    )
+
+    bypass_hosts = []
+    # If not given an explicit noproxy value, respect values in env vars.
+    if noproxy is None:
+        noproxy = os.environ.get('no_proxy', os.environ.get('NO_PROXY', ''))
+    # Special case: A single '*' character means all hosts should be bypassed.
+    if noproxy == '*':
+        bypass_hosts = AllHosts
+    elif noproxy.strip():
+        bypass_hosts = noproxy.split(',')
+        bypass_hosts = tuple(filter(bool, bypass_hosts))  # To exclude empty string.
+
+    pi.bypass_hosts = bypass_hosts
+    return pi
+
+
+class HTTPConnectionWithTimeout(http.client.HTTPConnection):
+    """HTTPConnection subclass that supports timeouts
+
+    HTTPConnection subclass that supports timeouts
+
+    All timeouts are in seconds. If None is passed for timeout then
+    Python's default timeout for sockets will be used. See for example
+    the docs of socket.setdefaulttimeout():
+    http://docs.python.org/library/socket.html#socket.setdefaulttimeout
+    """
+
+    def __init__(self, host, port=None, timeout=None, proxy_info=None):
+        http.client.HTTPConnection.__init__(self, host, port=port,
+                                            timeout=timeout)
+
+        self.proxy_info = proxy_info
+        if proxy_info and not isinstance(proxy_info, ProxyInfo):
+            self.proxy_info = proxy_info('http')
+
+    def connect(self):
+        """Connect to the host and port specified in __init__."""
+        if self.proxy_info and socks is None:
+            raise ProxiesUnavailableError(
+                'Proxy support missing but proxy use was requested!')
+        if self.proxy_info and self.proxy_info.isgood():
+            use_proxy = True
+            proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers = self.proxy_info.astuple()
+
+            host = proxy_host
+            port = proxy_port
+        else:
+            use_proxy = False
+
+            host = self.host
+            port = self.port
+            proxy_type = None
+
+        socket_err = None
+
+        for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
+            af, socktype, proto, canonname, sa = res
+            try:
+                if use_proxy:
+                    self.sock = socks.socksocket(af, socktype, proto)
+                    self.sock.setproxy(proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass)
+                else:
+                    self.sock = socket.socket(af, socktype, proto)
+                    self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+                if has_timeout(self.timeout):
+                    self.sock.settimeout(self.timeout)
+                if self.debuglevel > 0:
+                    print(
+                        "connect: ({0}, {1}) ************".format(self.host, self.port))
+                    if use_proxy:
+                        print(
+                            "proxy: {0} ************".format(str(
+                                (proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers))))
+
+                self.sock.connect((self.host, self.port) + sa[2:])
+            except socket.error as e:
+                socket_err = e
+                if self.debuglevel > 0:
+                    print(
+                        "connect fail: ({0}, {1})".format(self.host, self.port))
+                    if use_proxy:
+                        print(
+                            "proxy: {0}".format(str(
+                                (proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers))))
+                if self.sock:
+                    self.sock.close()
+                self.sock = None
+                continue
+            break
+        if not self.sock:
+            raise socket_err
+
+
+class HTTPSConnectionWithTimeout(http.client.HTTPSConnection):
+    """
+    This class allows communication via SSL.
+
+    All timeouts are in seconds. If None is passed for timeout then
+    Python's default timeout for sockets will be used. See for example
+    the docs of socket.setdefaulttimeout():
+    http://docs.python.org/library/socket.html#socket.setdefaulttimeout
+    """
+
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 timeout=None, proxy_info=None,
+                 ca_certs=None, disable_ssl_certificate_validation=False):
+
+        self.disable_ssl_certificate_validation = disable_ssl_certificate_validation
+        self.ca_certs = ca_certs if ca_certs else CA_CERTS
+
+        self.proxy_info = proxy_info
+        if proxy_info and not isinstance(proxy_info, ProxyInfo):
+            self.proxy_info = proxy_info('https')
+
+        context = _build_ssl_context(self.disable_ssl_certificate_validation, self.ca_certs, cert_file, key_file)
+        super(HTTPSConnectionWithTimeout, self).__init__(host, port=port, key_file=key_file, cert_file=cert_file,
+                                                         timeout=timeout, context=context)
+
+    def connect(self):
+        """Connect to a host on a given (SSL) port."""
+        if self.proxy_info and self.proxy_info.isgood():
+            use_proxy = True
+            proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers = self.proxy_info.astuple()
+
+            host = proxy_host
+            port = proxy_port
+        else:
+            use_proxy = False
+
+            host = self.host
+            port = self.port
+            proxy_type = None
+            proxy_headers = None
+
+        socket_err = None
+
+        address_info = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)
+        for family, socktype, proto, canonname, sockaddr in address_info:
+            try:
+                if use_proxy:
+                    sock = socks.socksocket(family, socktype, proto)
+
+                    sock.setproxy(proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass)
+                else:
+                    sock = socket.socket(family, socktype, proto)
+                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+                if has_timeout(self.timeout):
+                    sock.settimeout(self.timeout)
+                sock.connect((self.host, self.port))
+
+                self.sock = self._context.wrap_socket(sock, server_hostname=self.host)
+
+                # Python 3.3 compatibility: emulate the check_hostname behavior
+                if not hasattr(self._context, 'check_hostname') and not self.disable_ssl_certificate_validation:
+                    try:
+                        ssl.match_hostname(self.sock.getpeercert(), self.host)
+                    except Exception:
+                        self.sock.shutdown(socket.SHUT_RDWR)
+                        self.sock.close()
+                        raise
+
+                if self.debuglevel > 0:
+                    print("connect: ({0}, {1})".format(self.host, self.port))
+                    if use_proxy:
+                        print("proxy: {0}".format(str(
+                            (proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers))))
+            except (ssl.SSLError, ssl.CertificateError) as e:
+                if sock:
+                    sock.close()
+                if self.sock:
+                    self.sock.close()
+                self.sock = None
+                raise
+            except (socket.timeout, socket.gaierror):
+                raise
+            except socket.error as e:
+                socket_err = e
+                if self.debuglevel > 0:
+                    print("connect fail: ({0}, {1})".format((self.host, self.port)))
+                    if use_proxy:
+                        print("proxy: {0}".format(str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers))))
+                if self.sock:
+                    self.sock.close()
+                self.sock = None
+                continue
+            break
+        if not self.sock:
+            raise socket_err
+
+
+SCHEME_TO_CONNECTION = {
+    'http': HTTPConnectionWithTimeout,
+    'https': HTTPSConnectionWithTimeout,
+}
+
+class Http(object):
+    """An HTTP client that handles:
+
+    - all methods
+    - caching
+    - ETags
+    - compression,
+    - HTTPS
+    - Basic
+    - Digest
+    - WSSE
+
+    and more.
+    """
+    def __init__(self, cache=None, timeout=None,
+                 proxy_info=proxy_info_from_environment,
+                 ca_certs=None, disable_ssl_certificate_validation=False):
+        """If 'cache' is a string then it is used as a directory name for
+        a disk cache. Otherwise it must be an object that supports the
+        same interface as FileCache.
+
+        All timeouts are in seconds. If None is passed for timeout
+        then Python's default timeout for sockets will be used. See
+        for example the docs of socket.setdefaulttimeout():
+        http://docs.python.org/library/socket.html#socket.setdefaulttimeout
+
+        `proxy_info` may be:
+          - a callable that takes the http scheme ('http' or 'https') and
+            returns a ProxyInfo instance per request. By default, uses
+            proxy_info_from_environment.
+          - a ProxyInfo instance (static proxy config).
+          - None (proxy disabled).
+
+        ca_certs is the path of a file containing root CA certificates for SSL
+        server certificate validation.  By default, a CA cert file bundled with
+        httplib2 is used.
+
+        If disable_ssl_certificate_validation is true, SSL cert validation will
+        not be performed.
+"""
+        self.proxy_info = proxy_info
+        self.ca_certs = ca_certs
+        self.disable_ssl_certificate_validation = \
+                disable_ssl_certificate_validation
+        # Map domain name to an httplib connection
+        self.connections = {}
+        # The location of the cache, for now a directory
+        # where cached responses are held.
+        if cache and isinstance(cache, str):
+            self.cache = FileCache(cache)
+        else:
+            self.cache = cache
+
+        # Name/password
+        self.credentials = Credentials()
+
+        # Key/cert
+        self.certificates = KeyCerts()
+
+        # authorization objects
+        self.authorizations = []
+
+        # If set to False then no redirects are followed, even safe ones.
+        self.follow_redirects = True
+
+        # Which HTTP methods do we apply optimistic concurrency to, i.e.
+        # which methods get an "if-match:" etag header added to them.
+        self.optimistic_concurrency_methods = ["PUT", "PATCH"]
+
+        # If 'follow_redirects' is True, and this is set to True then
+        # all redirecs are followed, including unsafe ones.
+        self.follow_all_redirects = False
+
+        self.ignore_etag = False
+
+        self.force_exception_to_status_code = False
+
+        self.timeout = timeout
+
+        # Keep Authorization: headers on a redirect.
+        self.forward_authorization_headers = False
+
+    def __getstate__(self):
+        state_dict = copy.copy(self.__dict__)
+        # In case request is augmented by some foreign object such as
+        # credentials which handle auth
+        if 'request' in state_dict:
+            del state_dict['request']
+        if 'connections' in state_dict:
+            del state_dict['connections']
+        return state_dict
+
+    def __setstate__(self, state):
+        self.__dict__.update(state)
+        self.connections = {}
+
+    def _auth_from_challenge(self, host, request_uri, headers, response, content):
+        """A generator that creates Authorization objects
+           that can be applied to requests.
+        """
+        challenges = _parse_www_authenticate(response, 'www-authenticate')
+        for cred in self.credentials.iter(host):
+            for scheme in AUTH_SCHEME_ORDER:
+                if scheme in challenges:
+                    yield AUTH_SCHEME_CLASSES[scheme](cred, host, request_uri, headers, response, content, self)
+
+    def add_credentials(self, name, password, domain=""):
+        """Add a name and password that will be used
+        any time a request requires authentication."""
+        self.credentials.add(name, password, domain)
+
+    def add_certificate(self, key, cert, domain):
+        """Add a key and cert that will be used
+        any time a request requires authentication."""
+        self.certificates.add(key, cert, domain)
+
+    def clear_credentials(self):
+        """Remove all the names and passwords
+        that are used for authentication"""
+        self.credentials.clear()
+        self.authorizations = []
+
+    def _conn_request(self, conn, request_uri, method, body, headers):
+        i = 0
+        seen_bad_status_line = False
+        while i < RETRIES:
+            i += 1
+            try:
+                if conn.sock is None:
+                    conn.connect()
+                conn.request(method, request_uri, body, headers)
+            except socket.timeout:
+                conn.close()
+                raise
+            except socket.gaierror:
+                conn.close()
+                raise ServerNotFoundError("Unable to find the server at %s" % conn.host)
+            except socket.error as e:
+                errno_ = (e.args[0].errno if isinstance(e.args[0], socket.error) else e.errno)
+                if errno_ in (errno.ENETUNREACH, errno.EADDRNOTAVAIL) and i < RETRIES:
+                    continue  # retry on potentially transient errors
+                raise
+            except http.client.HTTPException:
+                if conn.sock is None:
+                    if i < RETRIES-1:
+                        conn.close()
+                        conn.connect()
+                        continue
+                    else:
+                        conn.close()
+                        raise
+                if i < RETRIES-1:
+                    conn.close()
+                    conn.connect()
+                    continue
+                # Just because the server closed the connection doesn't apparently mean
+                # that the server didn't send a response.
+                pass
+            try:
+                response = conn.getresponse()
+            except (http.client.BadStatusLine, http.client.ResponseNotReady):
+                # If we get a BadStatusLine on the first try then that means
+                # the connection just went stale, so retry regardless of the
+                # number of RETRIES set.
+                if not seen_bad_status_line and i == 1:
+                    i = 0
+                    seen_bad_status_line = True
+                    conn.close()
+                    conn.connect()
+                    continue
+                else:
+                    conn.close()
+                    raise
+            except socket.timeout:
+                raise
+            except (socket.error, http.client.HTTPException):
+                conn.close()
+                if i == 0:
+                    conn.close()
+                    conn.connect()
+                    continue
+                else:
+                    raise
+            else:
+                content = b""
+                if method == "HEAD":
+                    conn.close()
+                else:
+                    content = response.read()
+                response = Response(response)
+                if method != "HEAD":
+                    content = _decompressContent(response, content)
+
+            break
+        return (response, content)
+
+
+    def _request(self, conn, host, absolute_uri, request_uri, method, body, headers, redirections, cachekey):
+        """Do the actual request using the connection object
+        and also follow one level of redirects if necessary"""
+
+        auths = [(auth.depth(request_uri), auth) for auth in self.authorizations if auth.inscope(host, request_uri)]
+        auth = auths and sorted(auths)[0][1] or None
+        if auth:
+            auth.request(method, request_uri, headers, body)
+
+        (response, content) = self._conn_request(conn, request_uri, method, body, headers)
+
+        if auth:
+            if auth.response(response, body):
+                auth.request(method, request_uri, headers, body)
+                (response, content) = self._conn_request(conn, request_uri, method, body, headers )
+                response._stale_digest = 1
+
+        if response.status == 401:
+            for authorization in self._auth_from_challenge(host, request_uri, headers, response, content):
+                authorization.request(method, request_uri, headers, body)
+                (response, content) = self._conn_request(conn, request_uri, method, body, headers, )
+                if response.status != 401:
+                    self.authorizations.append(authorization)
+                    authorization.response(response, body)
+                    break
+
+        if (self.follow_all_redirects or (method in ["GET", "HEAD"]) or response.status == 303):
+            if self.follow_redirects and response.status in [300, 301, 302, 303, 307]:
+                # Pick out the location header and basically start from the beginning
+                # remembering first to strip the ETag header and decrement our 'depth'
+                if redirections:
+                    if 'location' not in response and response.status != 300:
+                        raise RedirectMissingLocation( _("Redirected but the response is missing a Location: header."), response, content)
+                    # Fix-up relative redirects (which violate an RFC 2616 MUST)
+                    if 'location' in response:
+                        location = response['location']
+                        (scheme, authority, path, query, fragment) = parse_uri(location)
+                        if authority == None:
+                            response['location'] = urllib.parse.urljoin(absolute_uri, location)
+                    if response.status == 301 and method in ["GET", "HEAD"]:
+                        response['-x-permanent-redirect-url'] = response['location']
+                        if 'content-location' not in response:
+                            response['content-location'] = absolute_uri
+                        _updateCache(headers, response, content, self.cache, cachekey)
+                    if 'if-none-match' in headers:
+                        del headers['if-none-match']
+                    if 'if-modified-since' in headers:
+                        del headers['if-modified-since']
+                    if 'authorization' in headers and not self.forward_authorization_headers:
+                        del headers['authorization']
+                    if 'location' in response:
+                        location = response['location']
+                        old_response = copy.deepcopy(response)
+                        if 'content-location' not in old_response:
+                            old_response['content-location'] = absolute_uri
+                        redirect_method = method
+                        if response.status in [302, 303]:
+                          redirect_method = "GET"
+                          body = None
+                        (response, content) = self.request(
+                            location, method=redirect_method, body=body,
+                            headers=headers, redirections=redirections - 1)
+                        response.previous = old_response
+                else:
+                    raise RedirectLimit("Redirected more times than redirection_limit allows.", response, content)
+            elif response.status in [200, 203] and method in ["GET", "HEAD"]:
+                # Don't cache 206's since we aren't going to handle byte range requests
+                if 'content-location' not in response:
+                    response['content-location'] = absolute_uri
+                _updateCache(headers, response, content, self.cache, cachekey)
+
+        return (response, content)
+
+    def _normalize_headers(self, headers):
+        return _normalize_headers(headers)
+
+# Need to catch and rebrand some exceptions
+# Then need to optionally turn all exceptions into status codes
+# including all socket.* and httplib.* exceptions.
+
+
+    def request(self, uri, method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None):
+        """ Performs a single HTTP request.
+The 'uri' is the URI of the HTTP resource and can begin
+with either 'http' or 'https'. The value of 'uri' must be an absolute URI.
+
+The 'method' is the HTTP method to perform, such as GET, POST, DELETE, etc.
+There is no restriction on the methods allowed.
+
+The 'body' is the entity body to be sent with the request. It is a string
+object.
+
+Any extra headers that are to be sent with the request should be provided in the
+'headers' dictionary.
+
+The maximum number of redirect to follow before raising an
+exception is 'redirections. The default is 5.
+
+The return value is a tuple of (response, content), the first
+being and instance of the 'Response' class, the second being
+a string that contains the response entity body.
+        """
+        try:
+            if headers is None:
+                headers = {}
+            else:
+                headers = self._normalize_headers(headers)
+
+            if 'user-agent' not in headers:
+                headers['user-agent'] = "Python-httplib2/%s (gzip)" % __version__
+
+            uri = iri2uri(uri)
+
+            (scheme, authority, request_uri, defrag_uri) = urlnorm(uri)
+            domain_port = authority.split(":")[0:2]
+            if len(domain_port) == 2 and domain_port[1] == '443' and scheme == 'http':
+                scheme = 'https'
+                authority = domain_port[0]
+
+            conn_key = scheme+":"+authority
+            if conn_key in self.connections:
+                conn = self.connections[conn_key]
+            else:
+                if not connection_type:
+                    connection_type = SCHEME_TO_CONNECTION[scheme]
+                certs = list(self.certificates.iter(authority))
+                if issubclass(connection_type, HTTPSConnectionWithTimeout):
+                    if certs:
+                        conn = self.connections[conn_key] = connection_type(
+                                authority, key_file=certs[0][0],
+                                cert_file=certs[0][1], timeout=self.timeout,
+                                proxy_info=self.proxy_info,
+                                ca_certs=self.ca_certs,
+                                disable_ssl_certificate_validation=
+                                        self.disable_ssl_certificate_validation)
+                    else:
+                        conn = self.connections[conn_key] = connection_type(
+                                authority, timeout=self.timeout,
+                                proxy_info=self.proxy_info,
+                                ca_certs=self.ca_certs,
+                                disable_ssl_certificate_validation=
+                                        self.disable_ssl_certificate_validation)
+                else:
+                    conn = self.connections[conn_key] = connection_type(
+                            authority, timeout=self.timeout,
+                            proxy_info=self.proxy_info)
+                conn.set_debuglevel(debuglevel)
+
+            if 'range' not in headers and 'accept-encoding' not in headers:
+                headers['accept-encoding'] = 'gzip, deflate'
+
+            info = email.message.Message()
+            cached_value = None
+            if self.cache:
+                cachekey = defrag_uri
+                cached_value = self.cache.get(cachekey)
+                if cached_value:
+                    try:
+                        info, content = cached_value.split(b'\r\n\r\n', 1)
+                        info = email.message_from_bytes(info)
+                        for k, v in info.items():
+                          if v.startswith('=?') and v.endswith('?='):
+                            info.replace_header(k,
+                                                str(*email.header.decode_header(v)[0]))
+                    except (IndexError, ValueError):
+                        self.cache.delete(cachekey)
+                        cachekey = None
+                        cached_value = None
+            else:
+                cachekey = None
+
+            if method in self.optimistic_concurrency_methods and self.cache and 'etag' in info and not self.ignore_etag and 'if-match' not in headers:
+                # http://www.w3.org/1999/04/Editing/
+                headers['if-match'] = info['etag']
+
+            if method not in ["GET", "HEAD"] and self.cache and cachekey:
+                # RFC 2616 Section 13.10
+                self.cache.delete(cachekey)
+
+            # Check the vary header in the cache to see if this request
+            # matches what varies in the cache.
+            if method in ['GET', 'HEAD'] and 'vary' in info:
+                vary = info['vary']
+                vary_headers = vary.lower().replace(' ', '').split(',')
+                for header in vary_headers:
+                    key = '-varied-%s' % header
+                    value = info[key]
+                    if headers.get(header, None) != value:
+                            cached_value = None
+                            break
+
+            if cached_value and method in ["GET", "HEAD"] and self.cache and 'range' not in headers:
+                if '-x-permanent-redirect-url' in info:
+                    # Should cached permanent redirects be counted in our redirection count? For now, yes.
+                    if redirections <= 0:
+                        raise RedirectLimit("Redirected more times than redirection_limit allows.", {}, "")
+                    (response, new_content) = self.request(
+                        info['-x-permanent-redirect-url'], method='GET',
+                        headers=headers, redirections=redirections - 1)
+                    response.previous = Response(info)
+                    response.previous.fromcache = True
+                else:
+                    # Determine our course of action:
+                    #   Is the cached entry fresh or stale?
+                    #   Has the client requested a non-cached response?
+                    #
+                    # There seems to be three possible answers:
+                    # 1. [FRESH] Return the cache entry w/o doing a GET
+                    # 2. [STALE] Do the GET (but add in cache validators if available)
+                    # 3. [TRANSPARENT] Do a GET w/o any cache validators (Cache-Control: no-cache) on the request
+                    entry_disposition = _entry_disposition(info, headers)
+
+                    if entry_disposition == "FRESH":
+                        if not cached_value:
+                            info['status'] = '504'
+                            content = b""
+                        response = Response(info)
+                        if cached_value:
+                            response.fromcache = True
+                        return (response, content)
+
+                    if entry_disposition == "STALE":
+                        if 'etag' in info and not self.ignore_etag and not 'if-none-match' in headers:
+                            headers['if-none-match'] = info['etag']
+                        if 'last-modified' in info and not 'last-modified' in headers:
+                            headers['if-modified-since'] = info['last-modified']
+                    elif entry_disposition == "TRANSPARENT":
+                        pass
+
+                    (response, new_content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
+
+                if response.status == 304 and method == "GET":
+                    # Rewrite the cache entry with the new end-to-end headers
+                    # Take all headers that are in response
+                    # and overwrite their values in info.
+                    # unless they are hop-by-hop, or are listed in the connection header.
+
+                    for key in _get_end2end_headers(response):
+                        info[key] = response[key]
+                    merged_response = Response(info)
+                    if hasattr(response, "_stale_digest"):
+                        merged_response._stale_digest = response._stale_digest
+                    _updateCache(headers, merged_response, content, self.cache, cachekey)
+                    response = merged_response
+                    response.status = 200
+                    response.fromcache = True
+
+                elif response.status == 200:
+                    content = new_content
+                else:
+                    self.cache.delete(cachekey)
+                    content = new_content
+            else:
+                cc = _parse_cache_control(headers)
+                if 'only-if-cached'in cc:
+                    info['status'] = '504'
+                    response = Response(info)
+                    content = b""
+                else:
+                    (response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
+        except Exception as e:
+            if self.force_exception_to_status_code:
+                if isinstance(e, HttpLib2ErrorWithResponse):
+                    response = e.response
+                    content = e.content
+                    response.status = 500
+                    response.reason = str(e)
+                elif isinstance(e, socket.timeout):
+                    content = b"Request Timeout"
+                    response = Response({
+                        "content-type": "text/plain",
+                        "status": "408",
+                        "content-length": len(content)
+                    })
+                    response.reason = "Request Timeout"
+                else:
+                    content = str(e).encode('utf-8')
+                    response = Response({
+                        "content-type": "text/plain",
+                        "status": "400",
+                        "content-length": len(content)
+                    })
+                    response.reason = "Bad Request"
+            else:
+                raise
+
+
+        return (response, content)
+
+
+
+class Response(dict):
+    """An object more like email.message than httplib.HTTPResponse."""
+
+    """Is this response from our local cache"""
+    fromcache = False
+
+    """HTTP protocol version used by server. 10 for HTTP/1.0, 11 for HTTP/1.1. """
+    version = 11
+
+    "Status code returned by server. "
+    status = 200
+
+    """Reason phrase returned by server."""
+    reason = "Ok"
+
+    previous = None
+
+    def __init__(self, info):
+        # info is either an email.message or
+        # an httplib.HTTPResponse object.
+        if isinstance(info, http.client.HTTPResponse):
+            for key, value in info.getheaders():
+                key = key.lower()
+                prev = self.get(key)
+                if prev is not None:
+                    value = ', '.join((prev, value))
+                self[key] = value
+            self.status = info.status
+            self['status'] = str(self.status)
+            self.reason = info.reason
+            self.version = info.version
+        elif isinstance(info, email.message.Message):
+            for key, value in list(info.items()):
+                self[key.lower()] = value
+            self.status = int(self['status'])
+        else:
+            for key, value in info.items():
+                self[key.lower()] = value
+            self.status = int(self.get('status', self.status))
+
+
+    def __getattr__(self, name):
+        if name == 'dict':
+            return self
+        else:
+            raise AttributeError(name)
diff --git a/python3/httplib2/cacerts.txt b/python3/httplib2/cacerts.txt
new file mode 100644
index 0000000..8020c1b
--- /dev/null
+++ b/python3/httplib2/cacerts.txt
@@ -0,0 +1,2197 @@
+# Issuer: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
+# Subject: CN=GTE CyberTrust Global Root O=GTE Corporation OU=GTE CyberTrust Solutions, Inc.
+# Label: "GTE CyberTrust Global Root"
+# Serial: 421
+# MD5 Fingerprint: ca:3d:d3:68:f1:03:5c:d0:32:fa:b8:2b:59:e8:5a:db
+# SHA1 Fingerprint: 97:81:79:50:d8:1c:96:70:cc:34:d8:09:cf:79:44:31:36:7e:f4:74
+# SHA256 Fingerprint: a5:31:25:18:8d:21:10:aa:96:4b:02:c7:b7:c6:da:32:03:17:08:94:e5:fb:71:ff:fb:66:67:d5:e6:81:0a:36
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+# Issuer: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Subject: CN=Thawte Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Label: "Thawte Server CA"
+# Serial: 1
+# MD5 Fingerprint: c5:70:c4:a2:ed:53:78:0c:c8:10:53:81:64:cb:d0:1d
+# SHA1 Fingerprint: 23:e5:94:94:51:95:f2:41:48:03:b4:d5:64:d2:a3:a3:f5:d8:8b:8c
+# SHA256 Fingerprint: b4:41:0b:73:e2:e6:ea:ca:47:fb:c4:2f:8f:a4:01:8a:f4:38:1d:c5:4c:fa:a8:44:50:46:1e:ed:09:45:4d:e9
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Subject: CN=Thawte Premium Server CA O=Thawte Consulting cc OU=Certification Services Division
+# Label: "Thawte Premium Server CA"
+# Serial: 1
+# MD5 Fingerprint: 06:9f:69:79:16:66:90:02:1b:8c:8c:a2:c3:07:6f:3a
+# SHA1 Fingerprint: 62:7f:8d:78:27:65:63:99:d2:7d:7f:90:44:c9:fe:b3:f3:3e:fa:9a
+# SHA256 Fingerprint: ab:70:36:36:5c:71:54:aa:29:c2:c2:9f:5d:41:91:16:3b:16:2a:22:25:01:13:57:d5:6d:07:ff:a7:bc:1f:72
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+# Issuer: O=Equifax OU=Equifax Secure Certificate Authority
+# Subject: O=Equifax OU=Equifax Secure Certificate Authority
+# Label: "Equifax Secure CA"
+# Serial: 903804111
+# MD5 Fingerprint: 67:cb:9d:c0:13:24:8a:82:9b:b2:17:1e:d1:1b:ec:d4
+# SHA1 Fingerprint: d2:32:09:ad:23:d3:14:23:21:74:e4:0d:7f:9d:62:13:97:86:63:3a
+# SHA256 Fingerprint: 08:29:7a:40:47:db:a2:36:80:c7:31:db:6e:31:76:53:ca:78:48:e1:be:bd:3a:0b:01:79:a7:07:f9:2c:f1:78
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+
+# Issuer: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
+# Subject: O=VeriSign, Inc. OU=Class 3 Public Primary Certification Authority - G2/(c) 1998 VeriSign, Inc. - For authorized use only/VeriSign Trust Network
+# Label: "Verisign Class 3 Public Primary Certification Authority - G2"
+# Serial: 167285380242319648451154478808036881606
+# MD5 Fingerprint: a2:33:9b:4c:74:78:73:d4:6c:e7:c1:f3:8d:cb:5c:e9
+# SHA1 Fingerprint: 85:37:1c:a6:e5:50:14:3d:ce:28:03:47:1b:de:3a:09:e8:f8:77:0f
+# SHA256 Fingerprint: 83:ce:3c:12:29:68:8a:59:3d:48:5f:81:97:3c:0f:91:95:43:1e:da:37:cc:5e:36:43:0e:79:c7:a8:88:63:8b
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
+# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
+# Label: "GlobalSign Root CA"
+# Serial: 4835703278459707669005204
+# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
+# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
+# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
+# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2
+# Label: "GlobalSign Root CA - R2"
+# Serial: 4835703278459682885658125
+# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30
+# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe
+# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 1 Policy Validation Authority
+# Label: "ValiCert Class 1 VA"
+# Serial: 1
+# MD5 Fingerprint: 65:58:ab:15:ad:57:6c:1e:a8:a7:b5:69:ac:bf:ff:eb
+# SHA1 Fingerprint: e5:df:74:3c:b6:01:c4:9b:98:43:dc:ab:8c:e8:6a:81:10:9f:e4:8e
+# SHA256 Fingerprint: f4:c1:49:55:1a:30:13:a3:5b:c7:bf:fe:17:a7:f3:44:9b:c1:ab:5b:5a:0a:e7:4b:06:c2:3b:90:00:4c:01:04
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 2 Policy Validation Authority
+# Label: "ValiCert Class 2 VA"
+# Serial: 1
+# MD5 Fingerprint: a9:23:75:9b:ba:49:36:6e:31:c2:db:f2:e7:66:ba:87
+# SHA1 Fingerprint: 31:7a:2a:d0:7f:2b:33:5e:f5:a1:c3:4e:4b:57:e8:b7:d8:f1:fc:a6
+# SHA256 Fingerprint: 58:d0:17:27:9c:d4:dc:63:ab:dd:b1:96:a6:c9:90:6c:30:c4:e0:87:83:ea:e8:c1:60:99:54:d6:93:55:59:6b
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
+
+# Issuer: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
+# Subject: CN=http://www.valicert.com/ O=ValiCert, Inc. OU=ValiCert Class 3 Policy Validation Authority
+# Label: "RSA Root Certificate 1"
+# Serial: 1
+# MD5 Fingerprint: a2:6f:53:b7:ee:40:db:4a:68:e7:fa:18:d9:10:4b:72
+# SHA1 Fingerprint: 69:bd:8c:f4:9c:d3:00:fb:59:2e:17:93:ca:55:6a:f3:ec:aa:35:fb
+# SHA256 Fingerprint: bc:23:f9:8a:31:3c:b9:2d:e3:bb:fc:3a:5a:9f:44:61:ac:39:49:4c:4a:e1:5a:9e:9d:f1:31:e9:9b:73:01:9a
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Label: "Verisign Class 3 Public Primary Certification Authority - G3"
+# Serial: 206684696279472310254277870180966723415
+# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09
+# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6
+# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 4 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
+# Label: "Verisign Class 4 Public Primary Certification Authority - G3"
+# Serial: 314531972711909413743075096039378935511
+# MD5 Fingerprint: db:c8:f2:27:2e:b1:ea:6a:29:23:5d:fe:56:3e:33:df
+# SHA1 Fingerprint: c8:ec:8c:87:92:69:cb:4b:ab:39:e9:8d:7e:57:67:f3:14:95:73:9d
+# SHA256 Fingerprint: e3:89:36:0d:0f:db:ae:b3:d2:50:58:4b:47:30:31:4e:22:2f:39:c1:56:a0:20:14:4e:8d:96:05:61:79:15:06
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Subject: CN=Entrust.net Secure Server Certification Authority O=Entrust.net OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Label: "Entrust.net Secure Server CA"
+# Serial: 927650371
+# MD5 Fingerprint: df:f2:80:73:cc:f1:e6:61:73:fc:f5:42:e9:c5:7c:ee
+# SHA1 Fingerprint: 99:a6:9b:e6:1a:fe:88:6b:4d:2b:82:00:7c:b8:54:fc:31:7e:15:39
+# SHA256 Fingerprint: 62:f2:40:27:8c:56:4c:4d:d8:bf:7d:9d:4f:6f:36:6e:a8:94:d2:2f:5f:34:d9:89:a9:83:ac:ec:2f:ff:ed:50
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
+# Label: "Entrust.net Premium 2048 Secure Server CA"
+# Serial: 946059622
+# MD5 Fingerprint: ba:21:ea:20:d6:dd:db:8f:c1:57:8b:40:ad:a1:fc:fc
+# SHA1 Fingerprint: 80:1d:62:d0:7b:44:9d:5c:5c:03:5c:98:ea:61:fa:44:3c:2a:58:fe
+# SHA256 Fingerprint: d1:c3:39:ea:27:84:eb:87:0f:93:4f:c5:63:4e:4a:a9:ad:55:05:01:64:01:f2:64:65:d3:7a:57:46:63:35:9f
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
+MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
+vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
+CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
+WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
+h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
+f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
+B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
+vUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
+# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
+# Label: "Baltimore CyberTrust Root"
+# Serial: 33554617
+# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4
+# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74
+# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+# Issuer: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
+# Subject: CN=Equifax Secure Global eBusiness CA-1 O=Equifax Secure Inc.
+# Label: "Equifax Secure Global eBusiness CA"
+# Serial: 1
+# MD5 Fingerprint: 8f:5d:77:06:27:c4:98:3c:5b:93:78:e7:d7:7d:9b:cc
+# SHA1 Fingerprint: 7e:78:4a:10:1c:82:65:cc:2d:e1:f1:6d:47:b4:40:ca:d9:0a:19:45
+# SHA256 Fingerprint: 5f:0b:62:ea:b5:e3:53:ea:65:21:65:16:58:fb:b6:53:59:f4:43:28:0a:4a:fb:d1:04:d7:7d:10:f9:f0:4c:07
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+# Issuer: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
+# Subject: CN=Equifax Secure eBusiness CA-1 O=Equifax Secure Inc.
+# Label: "Equifax Secure eBusiness CA 1"
+# Serial: 4
+# MD5 Fingerprint: 64:9c:ef:2e:44:fc:c6:8f:52:07:d0:51:73:8f:cb:3d
+# SHA1 Fingerprint: da:40:18:8b:91:89:a3:ed:ee:ae:da:97:fe:2f:9d:f5:b7:d1:8a:41
+# SHA256 Fingerprint: cf:56:ff:46:a4:a1:86:10:9d:d9:65:84:b5:ee:b5:8a:51:0c:42:75:b0:e5:f9:4f:40:bb:ae:86:5e:19:f6:73
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+# Issuer: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
+# Subject: O=Equifax Secure OU=Equifax Secure eBusiness CA-2
+# Label: "Equifax Secure eBusiness CA 2"
+# Serial: 930140085
+# MD5 Fingerprint: aa:bf:bf:64:97:da:98:1d:6f:c6:08:3a:95:70:33:ca
+# SHA1 Fingerprint: 39:4f:f6:85:0b:06:be:52:e5:18:56:cc:10:e1:80:e8:82:b3:85:cc
+# SHA256 Fingerprint: 2f:27:4e:48:ab:a4:ac:7b:76:59:33:10:17:75:50:6d:c3:0e:e3:8e:f6:ac:d5:c0:49:32:cf:e0:41:23:42:20
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Class 1 CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Low-Value Services Root"
+# Serial: 1
+# MD5 Fingerprint: 1e:42:95:02:33:92:6b:b9:5f:c0:7f:da:d6:b2:4b:fc
+# SHA1 Fingerprint: cc:ab:0e:a0:4c:23:01:d6:69:7b:dd:37:9f:cd:12:eb:24:e3:94:9d
+# SHA256 Fingerprint: 8c:72:09:27:9a:c0:4e:27:5e:16:d0:7f:d3:b7:75:e8:01:54:b5:96:80:46:e3:1f:52:dd:25:76:63:24:e9:a7
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
+MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
+VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
+CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
+tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
+dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
+PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
+BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
+ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
+7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
+43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
+pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
+WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
+# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
+# Label: "AddTrust External Root"
+# Serial: 1
+# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f
+# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68
+# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Public CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Public Services Root"
+# Serial: 1
+# MD5 Fingerprint: c1:62:3e:23:c5:82:73:9c:03:59:4b:2b:e9:77:49:7f
+# SHA1 Fingerprint: 2a:b6:28:48:5e:78:fb:f3:ad:9e:79:10:dd:6b:df:99:72:2c:96:e5
+# SHA256 Fingerprint: 07:91:ca:07:49:b2:07:82:aa:d3:c7:d7:bd:0c:df:c9:48:58:35:84:3e:b2:d7:99:60:09:ce:43:ab:6c:69:27
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
+MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
+ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
+BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
+6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
+GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
+dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
+1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
+62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
+BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
+MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
+cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
+b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
+IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
+iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
+4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
+XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Subject: CN=AddTrust Qualified CA Root O=AddTrust AB OU=AddTrust TTP Network
+# Label: "AddTrust Qualified Certificates Root"
+# Serial: 1
+# MD5 Fingerprint: 27:ec:39:47:cd:da:5a:af:e2:9a:01:65:21:a9:4c:bb
+# SHA1 Fingerprint: 4d:23:78:ec:91:95:39:b5:00:7f:75:8f:03:3b:21:1e:c5:4d:8b:cf
+# SHA256 Fingerprint: 80:95:21:08:05:db:4b:bc:35:5e:44:28:d8:fd:6e:c2:cd:e3:ab:5f:b9:7a:99:42:98:8e:b8:f4:dc:d0:60:16
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
+MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
+EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
+BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
+xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
+87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
+2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
+WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
+0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
+A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
+pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
+ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
+aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
+hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
+hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
+P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
+iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
+xqE=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
+# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
+# Label: "Entrust Root Certification Authority"
+# Serial: 1164660820
+# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4
+# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9
+# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
+Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
+KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
+NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
+NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
+ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
+BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
+Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
+4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
+KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
+rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
+94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
+sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
+gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
+kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
+vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
+O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
+AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
+9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
+eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
+0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.
+# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.
+# Label: "GeoTrust Global CA"
+# Serial: 144470
+# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5
+# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12
+# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
+# Subject: CN=GeoTrust Global CA 2 O=GeoTrust Inc.
+# Label: "GeoTrust Global CA 2"
+# Serial: 1
+# MD5 Fingerprint: 0e:40:a7:6c:de:03:5d:8f:d1:0f:e4:d1:8d:f9:6c:a9
+# SHA1 Fingerprint: a9:e9:78:08:14:37:58:88:f2:05:19:b0:6d:2b:0d:2b:60:16:90:7d
+# SHA256 Fingerprint: ca:2d:82:a0:86:77:07:2f:8a:b6:76:4f:f0:35:67:6c:fe:3e:5e:32:5e:01:21:72:df:3f:92:09:6d:b7:9b:85
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
+IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
+R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
+PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
+Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
+TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
+5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
+S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
+2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
+EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
+EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
+/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
+A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
+abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
+I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
+4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc.
+# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc.
+# Label: "GeoTrust Universal CA"
+# Serial: 1
+# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48
+# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79
+# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
+IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
+VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
+cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
+QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
+F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
+c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
+mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
+VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
+teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
+f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
+Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
+/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
+MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
+IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
+ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
+uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
+Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
+QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
+koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
+ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
+DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
+bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
+# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
+# Label: "GeoTrust Universal CA 2"
+# Serial: 1
+# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7
+# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79
+# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
+VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
+c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
+WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
+FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
+XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
+se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
+KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
+IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
+y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
+hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
+QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
+Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
+HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
+KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
+L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
+Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
+ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
+T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
+GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
+1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
+OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
+6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
+QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+# Issuer: CN=America Online Root Certification Authority 1 O=America Online Inc.
+# Subject: CN=America Online Root Certification Authority 1 O=America Online Inc.
+# Label: "America Online Root Certification Authority 1"
+# Serial: 1
+# MD5 Fingerprint: 14:f1:08:ad:9d:fa:64:e2:89:e7:1c:cf:a8:ad:7d:5e
+# SHA1 Fingerprint: 39:21:c1:15:c1:5d:0e:ca:5c:cb:5b:c4:f0:7d:21:d8:05:0b:56:6a
+# SHA256 Fingerprint: 77:40:73:12:c6:3a:15:3d:5b:c0:0b:4e:51:75:9c:df:da:c2:37:dc:2a:33:b6:79:46:e9:8e:9b:fa:68:0a:e3
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
+hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
+1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
+OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
+2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
+O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
+AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
+Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
+LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
+oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
+MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+
+# Issuer: CN=America Online Root Certification Authority 2 O=America Online Inc.
+# Subject: CN=America Online Root Certification Authority 2 O=America Online Inc.
+# Label: "America Online Root Certification Authority 2"
+# Serial: 1
+# MD5 Fingerprint: d6:ed:3c:ca:e2:66:0f:af:10:43:0d:77:9b:04:09:bf
+# SHA1 Fingerprint: 85:b5:ff:67:9b:0c:79:96:1f:c8:6e:44:22:00:46:13:db:17:92:84
+# SHA256 Fingerprint: 7d:3b:46:5a:60:14:e5:26:c0:af:fc:ee:21:27:d2:31:17:27:ad:81:1c:26:84:2d:00:6a:f3:73:06:cc:80:bd
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
+206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
+KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
+JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
+BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
+Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
+PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
+Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
+Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
+o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
+YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
+FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
+xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
+LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
+obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
+CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
+IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
+DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
+AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
+Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
+AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
+Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
+RY8mkaKO/qk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
+# Subject: CN=AAA Certificate Services O=Comodo CA Limited
+# Label: "Comodo AAA Services root"
+# Serial: 1
+# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
+# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
+# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Secure Certificate Services O=Comodo CA Limited
+# Subject: CN=Secure Certificate Services O=Comodo CA Limited
+# Label: "Comodo Secure Services root"
+# Serial: 1
+# MD5 Fingerprint: d3:d9:bd:ae:9f:ac:67:24:b3:c8:1b:52:e1:b9:a9:bd
+# SHA1 Fingerprint: 4a:65:d5:f4:1d:ef:39:b8:b8:90:4a:4a:d3:64:81:33:cf:c7:a1:d1
+# SHA256 Fingerprint: bd:81:ce:3b:4f:65:91:d1:1a:67:b5:fc:7a:47:fd:ef:25:52:1b:f9:aa:4e:18:b9:e3:df:2e:34:a7:80:3b:e8
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Trusted Certificate Services O=Comodo CA Limited
+# Subject: CN=Trusted Certificate Services O=Comodo CA Limited
+# Label: "Comodo Trusted Services root"
+# Serial: 1
+# MD5 Fingerprint: 91:1b:3f:6e:cd:9e:ab:ee:07:fe:1f:71:d2:b3:61:27
+# SHA1 Fingerprint: e1:9f:e3:0e:8b:84:60:9e:80:9b:17:0d:72:a8:c5:ba:6e:14:09:bd
+# SHA256 Fingerprint: 3f:06:e5:56:81:d4:96:f5:be:16:9e:b5:38:9f:9f:2b:8f:f6:1e:17:08:df:68:81:72:48:49:cd:5d:27:cb:69
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+# Issuer: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
+# Subject: CN=UTN - DATACorp SGC O=The USERTRUST Network OU=http://www.usertrust.com
+# Label: "UTN DATACorp SGC Root CA"
+# Serial: 91374294542884689855167577680241077609
+# MD5 Fingerprint: b3:a5:3e:77:21:6d:ac:4a:c0:c9:fb:d5:41:3d:ca:06
+# SHA1 Fingerprint: 58:11:9f:0e:12:82:87:ea:50:fd:d9:87:45:6f:4f:78:dc:fa:d6:d4
+# SHA256 Fingerprint: 85:fb:2f:91:dd:12:27:5a:01:45:b6:36:53:4f:84:02:4a:d6:8b:69:b8:ee:88:68:4f:f7:11:37:58:05:b3:48
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+# Issuer: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
+# Subject: CN=UTN-USERFirst-Hardware O=The USERTRUST Network OU=http://www.usertrust.com
+# Label: "UTN USERFirst Hardware Root CA"
+# Serial: 91374294542884704022267039221184531197
+# MD5 Fingerprint: 4c:56:41:e5:0d:bb:2b:e8:ca:a3:ed:18:08:ad:43:39
+# SHA1 Fingerprint: 04:83:ed:33:99:ac:36:08:05:87:22:ed:bc:5e:46:00:e3:be:f9:d7
+# SHA256 Fingerprint: 6e:a5:47:41:d0:04:66:7e:ed:1b:48:16:63:4a:a3:a7:9e:6e:4b:96:95:0f:82:79:da:fc:8d:9b:d8:81:21:37
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
+# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
+# Label: "XRamp Global CA Root"
+# Serial: 107108908803651509692980124233745014957
+# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1
+# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6
+# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
+# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
+# Label: "Go Daddy Class 2 CA"
+# Serial: 0
+# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
+# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
+# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+
+# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
+# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
+# Label: "Starfield Class 2 CA"
+# Serial: 0
+# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
+# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
+# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Label: "StartCom Certification Authority"
+# Serial: 1
+# MD5 Fingerprint: 22:4d:8f:8a:fc:f7:35:c2:bb:57:34:90:7b:8b:22:16
+# SHA1 Fingerprint: 3e:2b:f7:f2:03:1b:96:f3:8c:e6:c4:d8:a8:5d:3e:2d:58:47:6a:0f
+# SHA256 Fingerprint: c7:66:a9:be:f2:d4:07:1c:86:3a:31:aa:49:20:e8:13:b2:d1:98:60:8c:b7:b7:cf:e2:11:43:b8:36:df:09:ea
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert Assured ID Root CA"
+# Serial: 17154717934120587862167794914071425081
+# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72
+# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43
+# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert Global Root CA"
+# Serial: 10944719598952040374951832963794454346
+# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e
+# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36
+# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
+# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
+# Label: "DigiCert High Assurance EV Root CA"
+# Serial: 3553400076410547919724730734378100087
+# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a
+# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25
+# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
+# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
+# Label: "GeoTrust Primary Certification Authority"
+# Serial: 32798226551256963324313806436981982369
+# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf
+# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96
+# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
+R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
+MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
+AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
+ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
+7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
+kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
+mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
+KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
+6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
+4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
+oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
+UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
+AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA"
+# Serial: 69529181992039203566298953787712940909
+# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12
+# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81
+# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
+NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
+A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
+W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
+3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
+6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
+Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
+NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
+r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
+DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
+YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
+/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
+LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
+jVaMaA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Class 3 Public Primary Certification Authority - G5"
+# Serial: 33037644167568058970164719475676101450
+# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c
+# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5
+# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
+nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
+t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
+SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
+BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
+NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
+BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
+BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
+MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
+p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
+5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
+WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
+4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
+hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+
+# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
+# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
+# Label: "COMODO Certification Authority"
+# Serial: 104350513648249232941998508985834464573
+# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75
+# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b
+# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
+YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
+RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
+UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
+2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
+Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
+nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
+/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
+PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
+SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
+IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
+zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
+BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
+ZQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
+# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C.
+# Label: "Network Solutions Certificate Authority"
+# Serial: 116697915152937497490437556386812487904
+# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e
+# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce
+# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
+MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp
+dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV
+UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO
+ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz
+c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP
+OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl
+mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF
+BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4
+qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw
+gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu
+bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp
+dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8
+6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/
+h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
+/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
+pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+
+# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
+# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
+# Label: "COMODO ECC Certification Authority"
+# Serial: 41578283867086692638256921589707938090
+# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23
+# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11
+# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7
+-----BEGIN CERTIFICATE-----
+MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
+IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
+MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
+ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
+T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
+FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
+cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
+BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
+fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
+GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
+# Subject: CN=TC TrustCenter Class 2 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 2 CA
+# Label: "TC TrustCenter Class 2 CA II"
+# Serial: 941389028203453866782103406992443
+# MD5 Fingerprint: ce:78:33:5c:59:78:01:6e:18:ea:b9:36:a0:b9:2e:23
+# SHA1 Fingerprint: ae:50:83:ed:7c:f4:5c:bc:8f:61:c6:21:fe:68:5d:79:42:21:15:6e
+# SHA256 Fingerprint: e6:b8:f8:76:64:85:f8:07:ae:7f:8d:ac:16:70:46:1f:07:c0:a1:3e:ef:3a:1f:f7:17:53:8d:7a:ba:d3:91:b4
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
+tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
+uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
+XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
+8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
+5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
+kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
+GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
+ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
+au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
+hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
+dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
+# Subject: CN=TC TrustCenter Class 3 CA II O=TC TrustCenter GmbH OU=TC TrustCenter Class 3 CA
+# Label: "TC TrustCenter Class 3 CA II"
+# Serial: 1506523511417715638772220530020799
+# MD5 Fingerprint: 56:5f:aa:80:61:12:17:f6:67:21:e6:2b:6d:61:56:8e
+# SHA1 Fingerprint: 80:25:ef:f4:6e:70:c8:d4:72:24:65:84:fe:40:3b:8a:8d:6a:db:f5
+# SHA256 Fingerprint: 8d:a0:84:fc:f9:9c:e0:77:22:f8:9b:32:05:93:98:06:fa:5c:b8:11:e1:c8:13:f6:a1:08:c7:d3:36:b3:40:8e
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
+Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
+Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
+1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
+ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
+Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
+XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
+irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
+TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
+g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
+95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
+S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Subject: CN=TC TrustCenter Universal CA I O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Label: "TC TrustCenter Universal CA I"
+# Serial: 601024842042189035295619584734726
+# MD5 Fingerprint: 45:e1:a5:72:c5:a9:36:64:40:9e:f5:e4:58:84:67:8c
+# SHA1 Fingerprint: 6b:2f:34:ad:89:58:be:62:fd:b0:6b:5c:ce:bb:9d:d9:4f:4e:39:f3
+# SHA256 Fingerprint: eb:f3:c0:2a:87:89:b1:fb:7d:51:19:95:d6:63:b7:29:06:d9:13:ce:0d:5e:10:56:8a:8a:77:e2:58:61:67:e7
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
+MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
+R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
+VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
+JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
+fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
+jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
+wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
+fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
+VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
+CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
+7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
+8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
+ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
+2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
+
+# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc
+# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc
+# Label: "Cybertrust Global Root"
+# Serial: 4835703278459682877484360
+# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1
+# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6
+# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG
+A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh
+bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE
+ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS
+b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5
+7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS
+J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y
+HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP
+t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz
+FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY
+XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
+MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw
+hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js
+MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA
+A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj
+Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx
+XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o
+omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc
+A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW
+WL1WMRJOEcgh4LMRkWXbtKaIOM5V
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
+# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
+# Label: "GeoTrust Primary Certification Authority - G3"
+# Serial: 28809105769928564313984085209975885599
+# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05
+# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd
+# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
+mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
+MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
+BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
+BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
+hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
+5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
+JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
+DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
+huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
+AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
+zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
+kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
+SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
+spki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA - G2"
+# Serial: 71758320672825410020661621085256472406
+# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f
+# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12
+# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
+IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
+BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
+MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
+YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
+dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
+BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
+papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
+DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
+KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
+XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
+# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
+# Label: "thawte Primary Root CA - G3"
+# Serial: 127614157056681299805556476275995414779
+# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31
+# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2
+# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
+rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
+BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
+Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
+LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
+MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
+ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
+gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
+YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
+b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
+9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
+zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
+OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
+HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
+2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
+oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
+KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
+m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
+MdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+
+# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
+# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
+# Label: "GeoTrust Primary Certification Authority - G2"
+# Serial: 80682863203381065782177908751794619243
+# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a
+# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0
+# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
+MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
+KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
+MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
+NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
+BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
+So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
+tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
+CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
+qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
+rD6ogRLQy7rQkgu2npaqBA+K
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Universal Root Certification Authority"
+# Serial: 85209574734084581917763752644031726877
+# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19
+# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54
+# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
+vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
+ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
+IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
+IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
+bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
+9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
+H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
+LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
+/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
+rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
+WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
+exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
+sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
+seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
+4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
+lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
+7M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
+# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
+# Label: "VeriSign Class 3 Public Primary Certification Authority - G4"
+# Serial: 63143484348153506665311985501458640051
+# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41
+# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a
+# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
+U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
+SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
+biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
+GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
+fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
+aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
+aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
+kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
+4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
+FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
+# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
+# Label: "GlobalSign Root CA - R3"
+# Serial: 4835703278459759426209954
+# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
+# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
+# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
+MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
+RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
+gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
+KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
+QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
+XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
+LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
+RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
+jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
+6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
+mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
+Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
+WD9f
+-----END CERTIFICATE-----
+
+# Issuer: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Subject: CN=TC TrustCenter Universal CA III O=TC TrustCenter GmbH OU=TC TrustCenter Universal CA
+# Label: "TC TrustCenter Universal CA III"
+# Serial: 2010889993983507346460533407902964
+# MD5 Fingerprint: 9f:dd:db:ab:ff:8e:ff:45:21:5f:f0:6c:9d:8f:fe:2b
+# SHA1 Fingerprint: 96:56:cd:7b:57:96:98:95:d0:e1:41:46:68:06:fb:b8:c6:11:06:87
+# SHA256 Fingerprint: 30:9b:4a:87:f6:ca:56:c9:31:69:aa:a9:9c:6d:98:88:54:d7:89:2b:d5:43:7e:2d:07:b2:9c:be:da:55:d3:5d
+-----BEGIN CERTIFICATE-----
+MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy
+MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl
+ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm
+BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF
+5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv
+DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v
+zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT
+yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj
+dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh
+MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI
+4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz
+dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY
+aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G
+DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
+CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH
+LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
+# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
+# Label: "Go Daddy Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01
+# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b
+# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
+EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
+ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
+NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
+EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
+AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
+E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
+/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
+DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
+GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
+tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
+AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
+WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
+9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
+gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
+2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
+4uJEvlz36hz1
+-----END CERTIFICATE-----
+
+# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Label: "Starfield Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96
+# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e
+# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
+ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
+MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
+aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
+Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
+nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
+HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
+Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
+dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
+HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
+CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
+sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
+4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
+8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
+mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+
+# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
+# Label: "Starfield Services Root Certificate Authority - G2"
+# Serial: 0
+# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2
+# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f
+# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
+ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
+VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
+ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
+dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
+OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
+8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
+Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
+hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
+6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
+AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
+bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
+ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
+qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
+0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
+sSi6
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Commercial O=AffirmTrust
+# Subject: CN=AffirmTrust Commercial O=AffirmTrust
+# Label: "AffirmTrust Commercial"
+# Serial: 8608355977964138876
+# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7
+# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7
+# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
+Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
+ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
+MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
+yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
+VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
+nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
+XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
+vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
+Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
+N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
+nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Networking O=AffirmTrust
+# Subject: CN=AffirmTrust Networking O=AffirmTrust
+# Label: "AffirmTrust Networking"
+# Serial: 8957382827206547757
+# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f
+# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f
+# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
+YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
+kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
+QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
+6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
+yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
+QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
+tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
+QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
+Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
+olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
+x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Premium O=AffirmTrust
+# Subject: CN=AffirmTrust Premium O=AffirmTrust
+# Label: "AffirmTrust Premium"
+# Serial: 7893706540734352110
+# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57
+# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27
+# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
+dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
+A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
+cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
+qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
+JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
+s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
+HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
+70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
+V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
+qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
+5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
+C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
+OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
+FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
+KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
+8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
+MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
+0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
+u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
+u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
+YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
+GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
+RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
+KeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust
+# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust
+# Label: "AffirmTrust Premium ECC"
+# Serial: 8401224907861490260
+# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d
+# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb
+# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
+cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
+BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
+VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
+0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
+ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
+A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
+aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
+flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Subject: CN=StartCom Certification Authority O=StartCom Ltd. OU=Secure Digital Certificate Signing
+# Label: "StartCom Certification Authority"
+# Serial: 45
+# MD5 Fingerprint: c9:3b:0d:84:41:fc:a4:76:79:23:08:57:de:10:19:16
+# SHA1 Fingerprint: a3:f1:33:3f:e2:42:bf:cf:c5:d1:4e:8f:39:42:98:40:68:10:d1:a0
+# SHA256 Fingerprint: e1:78:90:ee:09:a3:fb:f4:f4:8b:9c:41:4a:17:d6:37:b7:a5:06:47:e9:bc:75:23:22:72:7f:cc:17:42:a9:11
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
+ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
+ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
+aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
+YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
+c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
+d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
+CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
+wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
+Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
+0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
+pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
+CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
+P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
+1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
+KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
+8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
+fyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+
+# Issuer: CN=StartCom Certification Authority G2 O=StartCom Ltd.
+# Subject: CN=StartCom Certification Authority G2 O=StartCom Ltd.
+# Label: "StartCom Certification Authority G2"
+# Serial: 59
+# MD5 Fingerprint: 78:4b:fb:9e:64:82:0a:d3:b8:4c:62:f3:64:f2:90:64
+# SHA1 Fingerprint: 31:f1:fd:68:22:63:20:ee:c6:3b:3f:9d:ea:4a:3e:53:7c:7c:39:17
+# SHA256 Fingerprint: c7:ba:65:67:de:93:a7:98:ae:1f:aa:79:1e:71:2d:37:8f:ae:1f:93:c4:39:7f:ea:44:1b:b7:cb:e6:fd:59:95
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
+OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
+A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
+JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
+vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
+D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
+Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
+RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
+HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
+nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
+0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
+UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
+Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
+TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
+BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
+UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
+6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
+9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
+HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
+wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
+XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
+IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
+hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
+so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+
+# Issuer: O=Digital Signature Trust Co., CN=DST Root CA X3
+# Subject: O=Digital Signature Trust Co., CN=DST Root CA X3
+# Label: "IdenTrust DST Root CA X3"
+# Serial: 44AFB080D6A327BA893039862EF8406B
+# MD5 Fingerprint: 41:03:52:DC:0F:F7:50:1B:16:F0:02:8E:BA:6F:45:C5
+# SHA1 Fingerprint: DA:C9:02:4F:54:D8:F6:DF:94:93:5F:B1:73:26:38:CA:6A:D7:7C:13
+# SHA256 Fingerprint: 06:87:26:03:31:A7:24:03:D9:09:F1:05:E6:9B:CF:0D:32:E1:BD:24:93:FF:C6:D9:20:6D:11:BC:D6:77:07:39
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
+rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
+OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
+xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
+7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
+aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
+SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
+ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
+AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
+R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
+JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
+Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+
+# Issuer: CN=DigiCert Global Root G2, OU=www.digicert.com, O=DigiCert Inc, C=US
+# Subject: CN=DigiCert Global Root G2, OU=www.digicert.com, O=DigiCert Inc, C=US
+# Serial: 33af1e6a711a9a0bb2864b11d09fae5
+# MD5 Fingerprint: E4:A6:8A:C8:54:AC:52:42:46:0A:FD:72:48:1B:2A:44
+# SHA1 Fingerprint: DF:3C:24:F9:BF:D6:66:76:1B:26:80:73:FE:06:D1:CC:8D:4F:82:A4
+# SHA256 Fingerprint: CB:3C:CB:B7:60:31:E5:E0:13:8F:8D:D3:9A:23:F9:DE:47:FF:C3:5E:43:C1:14:4C:EA:27:D4:6A:5A:B1:CB:5F
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
+MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
+2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
+1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
+q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
+tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
+vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
+5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
+1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
+NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
+Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
+8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
+pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
+
diff --git a/python3/httplib2/iri2uri.py b/python3/httplib2/iri2uri.py
new file mode 100644
index 0000000..98985f8
--- /dev/null
+++ b/python3/httplib2/iri2uri.py
@@ -0,0 +1,110 @@
+"""

+iri2uri

+

+Converts an IRI to a URI.

+

+"""

+__author__ = "Joe Gregorio (joe@bitworking.org)"

+__copyright__ = "Copyright 2006, Joe Gregorio"

+__contributors__ = []

+__version__ = "1.0.0"

+__license__ = "MIT"

+__history__ = """

+"""

+

+import urllib.parse

+

+

+# Convert an IRI to a URI following the rules in RFC 3987

+#

+# The characters we need to enocde and escape are defined in the spec:

+#

+# iprivate =  %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD

+# ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF

+#         / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD

+#         / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD

+#         / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD

+#         / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD

+#         / %xD0000-DFFFD / %xE1000-EFFFD

+

+escape_range = [

+    (0xA0, 0xD7FF),

+    (0xE000, 0xF8FF),

+    (0xF900, 0xFDCF),

+    (0xFDF0, 0xFFEF),

+    (0x10000, 0x1FFFD),

+    (0x20000, 0x2FFFD),

+    (0x30000, 0x3FFFD),

+    (0x40000, 0x4FFFD),

+    (0x50000, 0x5FFFD),

+    (0x60000, 0x6FFFD),

+    (0x70000, 0x7FFFD),

+    (0x80000, 0x8FFFD),

+    (0x90000, 0x9FFFD),

+    (0xA0000, 0xAFFFD),

+    (0xB0000, 0xBFFFD),

+    (0xC0000, 0xCFFFD),

+    (0xD0000, 0xDFFFD),

+    (0xE1000, 0xEFFFD),

+    (0xF0000, 0xFFFFD),

+    (0x100000, 0x10FFFD),

+]

+

+def encode(c):

+    retval = c

+    i = ord(c)

+    for low, high in escape_range:

+        if i < low:

+            break

+        if i >= low and i <= high:

+            retval = "".join(["%%%2X" % o for o in c.encode('utf-8')])

+            break

+    return retval

+

+

+def iri2uri(uri):

+    """Convert an IRI to a URI. Note that IRIs must be

+    passed in a unicode strings. That is, do not utf-8 encode

+    the IRI before passing it into the function."""

+    if isinstance(uri ,str):

+        (scheme, authority, path, query, fragment) = urllib.parse.urlsplit(uri)

+        authority = authority.encode('idna').decode('utf-8')

+        # For each character in 'ucschar' or 'iprivate'

+        #  1. encode as utf-8

+        #  2. then %-encode each octet of that utf-8

+        uri = urllib.parse.urlunsplit((scheme, authority, path, query, fragment))

+        uri = "".join([encode(c) for c in uri])

+    return uri

+

+if __name__ == "__main__":

+    import unittest

+

+    class Test(unittest.TestCase):

+

+        def test_uris(self):

+            """Test that URIs are invariant under the transformation."""

+            invariant = [

+                "ftp://ftp.is.co.za/rfc/rfc1808.txt",

+                "http://www.ietf.org/rfc/rfc2396.txt",

+                "ldap://[2001:db8::7]/c=GB?objectClass?one",

+                "mailto:John.Doe@example.com",

+                "news:comp.infosystems.www.servers.unix",

+                "tel:+1-816-555-1212",

+                "telnet://192.0.2.16:80/",

+                "urn:oasis:names:specification:docbook:dtd:xml:4.1.2" ]

+            for uri in invariant:

+                self.assertEqual(uri, iri2uri(uri))

+

+        def test_iri(self):

+            """ Test that the right type of escaping is done for each part of the URI."""

+            self.assertEqual("http://xn--o3h.com/%E2%98%84", iri2uri("http://\N{COMET}.com/\N{COMET}"))

+            self.assertEqual("http://bitworking.org/?fred=%E2%98%84", iri2uri("http://bitworking.org/?fred=\N{COMET}"))

+            self.assertEqual("http://bitworking.org/#%E2%98%84", iri2uri("http://bitworking.org/#\N{COMET}"))

+            self.assertEqual("#%E2%98%84", iri2uri("#\N{COMET}"))

+            self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri("/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}"))

+            self.assertEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri(iri2uri("/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}")))

+            self.assertNotEqual("/fred?bar=%E2%98%9A#%E2%98%84", iri2uri("/fred?bar=\N{BLACK LEFT POINTING INDEX}#\N{COMET}".encode('utf-8')))

+

+    unittest.main()

+

+

diff --git a/python3/httplib2/socks.py b/python3/httplib2/socks.py
new file mode 100644
index 0000000..7fc0591
--- /dev/null
+++ b/python3/httplib2/socks.py
@@ -0,0 +1,448 @@
+"""SocksiPy - Python SOCKS module.
+Version 1.00
+
+Copyright 2006 Dan-Haim. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. 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.
+3. Neither the name of Dan Haim nor the names of his contributors may be used
+   to endorse or promote products derived from this software without specific
+   prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY DAN HAIM "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 DAN HAIM OR HIS 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, 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 DAMANGE.
+
+
+This module provides a standard socket-like interface for Python
+for tunneling connections through SOCKS proxies.
+
+"""
+
+"""
+
+Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
+for use in PyLoris (http://pyloris.sourceforge.net/)
+
+Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
+mainly to merge bug fixes found in Sourceforge
+
+"""
+
+import base64
+import socket
+import struct
+import sys
+
+if getattr(socket, 'socket', None) is None:
+    raise ImportError('socket.socket missing, proxy support unusable')
+
+PROXY_TYPE_SOCKS4 = 1
+PROXY_TYPE_SOCKS5 = 2
+PROXY_TYPE_HTTP = 3
+PROXY_TYPE_HTTP_NO_TUNNEL = 4
+
+_defaultproxy = None
+_orgsocket = socket.socket
+
+class ProxyError(Exception): pass
+class GeneralProxyError(ProxyError): pass
+class Socks5AuthError(ProxyError): pass
+class Socks5Error(ProxyError): pass
+class Socks4Error(ProxyError): pass
+class HTTPError(ProxyError): pass
+
+_generalerrors = ("success",
+    "invalid data",
+    "not connected",
+    "not available",
+    "bad proxy type",
+    "bad input")
+
+_socks5errors = ("succeeded",
+    "general SOCKS server failure",
+    "connection not allowed by ruleset",
+    "Network unreachable",
+    "Host unreachable",
+    "Connection refused",
+    "TTL expired",
+    "Command not supported",
+    "Address type not supported",
+    "Unknown error")
+
+_socks5autherrors = ("succeeded",
+    "authentication is required",
+    "all offered authentication methods were rejected",
+    "unknown username or invalid password",
+    "unknown error")
+
+_socks4errors = ("request granted",
+    "request rejected or failed",
+    "request rejected because SOCKS server cannot connect to identd on the client",
+    "request rejected because the client program and identd report different user-ids",
+    "unknown error")
+
+def setdefaultproxy(proxytype=None, addr=None, port=None, rdns=True, username=None, password=None):
+    """setdefaultproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
+    Sets a default proxy which all further socksocket objects will use,
+    unless explicitly changed.
+    """
+    global _defaultproxy
+    _defaultproxy = (proxytype, addr, port, rdns, username, password)
+
+def wrapmodule(module):
+    """wrapmodule(module)
+    Attempts to replace a module's socket library with a SOCKS socket. Must set
+    a default proxy using setdefaultproxy(...) first.
+    This will only work on modules that import socket directly into the namespace;
+    most of the Python Standard Library falls into this category.
+    """
+    if _defaultproxy != None:
+        module.socket.socket = socksocket
+    else:
+        raise GeneralProxyError((4, "no proxy specified"))
+
+class socksocket(socket.socket):
+    """socksocket([family[, type[, proto]]]) -> socket object
+    Open a SOCKS enabled socket. The parameters are the same as
+    those of the standard socket init. In order for SOCKS to work,
+    you must specify family=AF_INET, type=SOCK_STREAM and proto=0.
+    """
+
+    def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, _sock=None):
+        _orgsocket.__init__(self, family, type, proto, _sock)
+        if _defaultproxy != None:
+            self.__proxy = _defaultproxy
+        else:
+            self.__proxy = (None, None, None, None, None, None)
+        self.__proxysockname = None
+        self.__proxypeername = None
+        self.__httptunnel = True
+
+    def __recvall(self, count):
+        """__recvall(count) -> data
+        Receive EXACTLY the number of bytes requested from the socket.
+        Blocks until the required number of bytes have been received.
+        """
+        data = self.recv(count)
+        while len(data) < count:
+            d = self.recv(count-len(data))
+            if not d: raise GeneralProxyError((0, "connection closed unexpectedly"))
+            data = data + d
+        return data
+
+    def sendall(self, content, *args):
+        """ override socket.socket.sendall method to rewrite the header
+        for non-tunneling proxies if needed
+        """
+        if not self.__httptunnel:
+            content = self.__rewriteproxy(content)
+        return super(socksocket, self).sendall(content, *args)
+
+    def __rewriteproxy(self, header):
+        """ rewrite HTTP request headers to support non-tunneling proxies
+        (i.e. those which do not support the CONNECT method).
+        This only works for HTTP (not HTTPS) since HTTPS requires tunneling.
+        """
+        host, endpt = None, None
+        hdrs = header.split("\r\n")
+        for hdr in hdrs:
+            if hdr.lower().startswith("host:"):
+                host = hdr
+            elif hdr.lower().startswith("get") or hdr.lower().startswith("post"):
+                endpt = hdr
+        if host and endpt:
+            hdrs.remove(host)
+            hdrs.remove(endpt)
+            host = host.split(" ")[1]
+            endpt = endpt.split(" ")
+            if (self.__proxy[4] != None and self.__proxy[5] != None):
+                hdrs.insert(0, self.__getauthheader())
+            hdrs.insert(0, "Host: %s" % host)
+            hdrs.insert(0, "%s http://%s%s %s" % (endpt[0], host, endpt[1], endpt[2]))
+        return "\r\n".join(hdrs)
+
+    def __getauthheader(self):
+        auth = self.__proxy[4] + ":" + self.__proxy[5]
+        return "Proxy-Authorization: Basic " + base64.b64encode(auth)
+
+    def setproxy(self, proxytype=None, addr=None, port=None, rdns=True, username=None, password=None, headers=None):
+        """setproxy(proxytype, addr[, port[, rdns[, username[, password]]]])
+        Sets the proxy to be used.
+        proxytype -    The type of the proxy to be used. Three types
+                are supported: PROXY_TYPE_SOCKS4 (including socks4a),
+                PROXY_TYPE_SOCKS5 and PROXY_TYPE_HTTP
+        addr -        The address of the server (IP or DNS).
+        port -        The port of the server. Defaults to 1080 for SOCKS
+                servers and 8080 for HTTP proxy servers.
+        rdns -        Should DNS queries be preformed on the remote side
+                (rather than the local side). The default is True.
+                Note: This has no effect with SOCKS4 servers.
+        username -    Username to authenticate with to the server.
+                The default is no authentication.
+        password -    Password to authenticate with to the server.
+                Only relevant when username is also provided.
+        headers -     Additional or modified headers for the proxy connect request.
+        """
+        self.__proxy = (proxytype, addr, port, rdns, username, password, headers)
+
+    def __negotiatesocks5(self, destaddr, destport):
+        """__negotiatesocks5(self,destaddr,destport)
+        Negotiates a connection through a SOCKS5 server.
+        """
+        # First we'll send the authentication packages we support.
+        if (self.__proxy[4]!=None) and (self.__proxy[5]!=None):
+            # The username/password details were supplied to the
+            # setproxy method so we support the USERNAME/PASSWORD
+            # authentication (in addition to the standard none).
+            self.sendall(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02))
+        else:
+            # No username/password were entered, therefore we
+            # only support connections with no authentication.
+            self.sendall(struct.pack('BBB', 0x05, 0x01, 0x00))
+        # We'll receive the server's response to determine which
+        # method was selected
+        chosenauth = self.__recvall(2)
+        if chosenauth[0:1] != chr(0x05).encode():
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        # Check the chosen authentication method
+        if chosenauth[1:2] == chr(0x00).encode():
+            # No authentication is required
+            pass
+        elif chosenauth[1:2] == chr(0x02).encode():
+            # Okay, we need to perform a basic username/password
+            # authentication.
+            self.sendall(chr(0x01).encode() + chr(len(self.__proxy[4])) + self.__proxy[4] + chr(len(self.__proxy[5])) + self.__proxy[5])
+            authstat = self.__recvall(2)
+            if authstat[0:1] != chr(0x01).encode():
+                # Bad response
+                self.close()
+                raise GeneralProxyError((1, _generalerrors[1]))
+            if authstat[1:2] != chr(0x00).encode():
+                # Authentication failed
+                self.close()
+                raise Socks5AuthError((3, _socks5autherrors[3]))
+            # Authentication succeeded
+        else:
+            # Reaching here is always bad
+            self.close()
+            if chosenauth[1] == chr(0xFF).encode():
+                raise Socks5AuthError((2, _socks5autherrors[2]))
+            else:
+                raise GeneralProxyError((1, _generalerrors[1]))
+        # Now we can request the actual connection
+        req = struct.pack('BBB', 0x05, 0x01, 0x00)
+        # If the given destination address is an IP address, we'll
+        # use the IPv4 address request even if remote resolving was specified.
+        try:
+            ipaddr = socket.inet_aton(destaddr)
+            req = req + chr(0x01).encode() + ipaddr
+        except socket.error:
+            # Well it's not an IP number,  so it's probably a DNS name.
+            if self.__proxy[3]:
+                # Resolve remotely
+                ipaddr = None
+                req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr.encode()
+            else:
+                # Resolve locally
+                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
+                req = req + chr(0x01).encode() + ipaddr
+        req = req + struct.pack(">H", destport)
+        self.sendall(req)
+        # Get the response
+        resp = self.__recvall(4)
+        if resp[0:1] != chr(0x05).encode():
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        elif resp[1:2] != chr(0x00).encode():
+            # Connection failed
+            self.close()
+            if ord(resp[1:2])<=8:
+                raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])]))
+            else:
+                raise Socks5Error((9, _socks5errors[9]))
+        # Get the bound address/port
+        elif resp[3:4] == chr(0x01).encode():
+            boundaddr = self.__recvall(4)
+        elif resp[3:4] == chr(0x03).encode():
+            resp = resp + self.recv(1)
+            boundaddr = self.__recvall(ord(resp[4:5]))
+        else:
+            self.close()
+            raise GeneralProxyError((1,_generalerrors[1]))
+        boundport = struct.unpack(">H", self.__recvall(2))[0]
+        self.__proxysockname = (boundaddr, boundport)
+        if ipaddr != None:
+            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
+        else:
+            self.__proxypeername = (destaddr, destport)
+
+    def getproxysockname(self):
+        """getsockname() -> address info
+        Returns the bound IP address and port number at the proxy.
+        """
+        return self.__proxysockname
+
+    def getproxypeername(self):
+        """getproxypeername() -> address info
+        Returns the IP and port number of the proxy.
+        """
+        return _orgsocket.getpeername(self)
+
+    def getpeername(self):
+        """getpeername() -> address info
+        Returns the IP address and port number of the destination
+        machine (note: getproxypeername returns the proxy)
+        """
+        return self.__proxypeername
+
+    def __negotiatesocks4(self,destaddr,destport):
+        """__negotiatesocks4(self,destaddr,destport)
+        Negotiates a connection through a SOCKS4 server.
+        """
+        # Check if the destination address provided is an IP address
+        rmtrslv = False
+        try:
+            ipaddr = socket.inet_aton(destaddr)
+        except socket.error:
+            # It's a DNS name. Check where it should be resolved.
+            if self.__proxy[3]:
+                ipaddr = struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)
+                rmtrslv = True
+            else:
+                ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
+        # Construct the request packet
+        req = struct.pack(">BBH", 0x04, 0x01, destport) + ipaddr
+        # The username parameter is considered userid for SOCKS4
+        if self.__proxy[4] != None:
+            req = req + self.__proxy[4]
+        req = req + chr(0x00).encode()
+        # DNS name if remote resolving is required
+        # NOTE: This is actually an extension to the SOCKS4 protocol
+        # called SOCKS4A and may not be supported in all cases.
+        if rmtrslv:
+            req = req + destaddr + chr(0x00).encode()
+        self.sendall(req)
+        # Get the response from the server
+        resp = self.__recvall(8)
+        if resp[0:1] != chr(0x00).encode():
+            # Bad data
+            self.close()
+            raise GeneralProxyError((1,_generalerrors[1]))
+        if resp[1:2] != chr(0x5A).encode():
+            # Server returned an error
+            self.close()
+            if ord(resp[1:2]) in (91, 92, 93):
+                self.close()
+                raise Socks4Error((ord(resp[1:2]), _socks4errors[ord(resp[1:2]) - 90]))
+            else:
+                raise Socks4Error((94, _socks4errors[4]))
+        # Get the bound address/port
+        self.__proxysockname = (socket.inet_ntoa(resp[4:]), struct.unpack(">H", resp[2:4])[0])
+        if rmtrslv != None:
+            self.__proxypeername = (socket.inet_ntoa(ipaddr), destport)
+        else:
+            self.__proxypeername = (destaddr, destport)
+
+    def __negotiatehttp(self, destaddr, destport):
+        """__negotiatehttp(self,destaddr,destport)
+        Negotiates a connection through an HTTP server.
+        """
+        # If we need to resolve locally, we do this now
+        if not self.__proxy[3]:
+            addr = socket.gethostbyname(destaddr)
+        else:
+            addr = destaddr
+        headers =  ["CONNECT ", addr, ":", str(destport), " HTTP/1.1\r\n"]
+        wrote_host_header = False
+        wrote_auth_header = False
+        if self.__proxy[6] != None:
+            for key, val in self.__proxy[6].iteritems():
+                headers += [key, ": ", val, "\r\n"]
+                wrote_host_header = (key.lower() == "host")
+                wrote_auth_header = (key.lower() == "proxy-authorization")
+        if not wrote_host_header:
+            headers += ["Host: ", destaddr, "\r\n"]
+        if not wrote_auth_header:
+            if (self.__proxy[4] != None and self.__proxy[5] != None):
+                headers += [self.__getauthheader(), "\r\n"]
+        headers.append("\r\n")
+        self.sendall("".join(headers).encode())
+        # We read the response until we get the string "\r\n\r\n"
+        resp = self.recv(1)
+        while resp.find("\r\n\r\n".encode()) == -1:
+            resp = resp + self.recv(1)
+        # We just need the first line to check if the connection
+        # was successful
+        statusline = resp.splitlines()[0].split(" ".encode(), 2)
+        if statusline[0] not in ("HTTP/1.0".encode(), "HTTP/1.1".encode()):
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        try:
+            statuscode = int(statusline[1])
+        except ValueError:
+            self.close()
+            raise GeneralProxyError((1, _generalerrors[1]))
+        if statuscode != 200:
+            self.close()
+            raise HTTPError((statuscode, statusline[2]))
+        self.__proxysockname = ("0.0.0.0", 0)
+        self.__proxypeername = (addr, destport)
+
+    def connect(self, destpair):
+        """connect(self, despair)
+        Connects to the specified destination through a proxy.
+        destpar - A tuple of the IP/DNS address and the port number.
+        (identical to socket's connect).
+        To select the proxy server use setproxy().
+        """
+        # Do a minimal input check first
+        if (not type(destpair) in (list,tuple)) or (len(destpair) < 2) or (not isinstance(destpair[0], (str, bytes))) or (type(destpair[1]) != int):
+            raise GeneralProxyError((5, _generalerrors[5]))
+        if self.__proxy[0] == PROXY_TYPE_SOCKS5:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 1080
+            _orgsocket.connect(self, (self.__proxy[1], portnum))
+            self.__negotiatesocks5(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_SOCKS4:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 1080
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
+            self.__negotiatesocks4(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_HTTP:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 8080
+            _orgsocket.connect(self,(self.__proxy[1], portnum))
+            self.__negotiatehttp(destpair[0], destpair[1])
+        elif self.__proxy[0] == PROXY_TYPE_HTTP_NO_TUNNEL:
+            if self.__proxy[2] != None:
+                portnum = self.__proxy[2]
+            else:
+                portnum = 8080
+            _orgsocket.connect(self,(self.__proxy[1],portnum))
+            if destpair[1] == 443:
+                self.__negotiatehttp(destpair[0],destpair[1])
+            else:
+                self.__httptunnel = False
+        elif self.__proxy[0] == None:
+            _orgsocket.connect(self, (destpair[0], destpair[1]))
+        else:
+            raise GeneralProxyError((4, _generalerrors[4]))
diff --git a/python3/httplib2/test/other_cacerts.txt b/python3/httplib2/test/other_cacerts.txt
new file mode 100644
index 0000000..360954a
--- /dev/null
+++ b/python3/httplib2/test/other_cacerts.txt
@@ -0,0 +1,70 @@
+# Certifcate Authority certificates for validating SSL connections.
+#
+# This file contains PEM format certificates generated from
+# http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt
+#
+# ***** 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 Netscape security libraries.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1994-2000
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# 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 *****
+
+
+Comodo CA Limited, CN=Trusted Certificate Services
+==================================================
+
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
diff --git a/python3/httplib2test.py b/python3/httplib2test.py
new file mode 100755
index 0000000..a4afae9
--- /dev/null
+++ b/python3/httplib2test.py
@@ -0,0 +1,1640 @@
+#!/usr/bin/env python3

+"""

+httplib2test

+

+A set of unit tests for httplib2.py.

+

+Requires Python 3.0 or later

+"""

+

+__author__ = "Joe Gregorio (joe@bitworking.org)"

+__copyright__ = "Copyright 2006, Joe Gregorio"

+__contributors__ = ["Mark Pilgrim"]

+__license__ = "MIT"

+__history__ = """ """

+__version__ = "0.2 ($Rev: 118 $)"

+

+import base64

+import http.client

+import httplib2

+import io

+import os

+import pickle

+import socket

+import ssl

+import sys

+import time

+import unittest

+import urllib.parse

+

+# The test resources base uri

+base = 'http://bitworking.org/projects/httplib2/test/'

+#base = 'http://localhost/projects/httplib2/test/'

+cacheDirName = ".cache"

+

+

+class CredentialsTest(unittest.TestCase):

+    def test(self):

+        c = httplib2.Credentials()

+        c.add("joe", "password")

+        self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])

+        self.assertEqual(("joe", "password"), list(c.iter(""))[0])

+        c.add("fred", "password2", "wellformedweb.org")

+        self.assertEqual(("joe", "password"), list(c.iter("bitworking.org"))[0])

+        self.assertEqual(1, len(list(c.iter("bitworking.org"))))

+        self.assertEqual(2, len(list(c.iter("wellformedweb.org"))))

+        self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))

+        c.clear()

+        self.assertEqual(0, len(list(c.iter("bitworking.org"))))

+        c.add("fred", "password2", "wellformedweb.org")

+        self.assertTrue(("fred", "password2") in list(c.iter("wellformedweb.org")))

+        self.assertEqual(0, len(list(c.iter("bitworking.org"))))

+        self.assertEqual(0, len(list(c.iter(""))))

+

+

+class ParserTest(unittest.TestCase):

+    def testFromStd66(self):

+        self.assertEqual( ('http', 'example.com', '', None, None ), httplib2.parse_uri("http://example.com"))

+        self.assertEqual( ('https', 'example.com', '', None, None ), httplib2.parse_uri("https://example.com"))

+        self.assertEqual( ('https', 'example.com:8080', '', None, None ), httplib2.parse_uri("https://example.com:8080"))

+        self.assertEqual( ('http', 'example.com', '/', None, None ), httplib2.parse_uri("http://example.com/"))

+        self.assertEqual( ('http', 'example.com', '/path', None, None ), httplib2.parse_uri("http://example.com/path"))

+        self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', None ), httplib2.parse_uri("http://example.com/path?a=1&b=2"))

+        self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))

+        self.assertEqual( ('http', 'example.com', '/path', 'a=1&b=2', 'fred' ), httplib2.parse_uri("http://example.com/path?a=1&b=2#fred"))

+

+

+class UrlNormTest(unittest.TestCase):

+    def test(self):

+        self.assertEqual( "http://example.org/", httplib2.urlnorm("http://example.org")[-1])

+        self.assertEqual( "http://example.org/", httplib2.urlnorm("http://EXAMple.org")[-1])

+        self.assertEqual( "http://example.org/?=b", httplib2.urlnorm("http://EXAMple.org?=b")[-1])

+        self.assertEqual( "http://example.org/mypath?a=b", httplib2.urlnorm("http://EXAMple.org/mypath?a=b")[-1])

+        self.assertEqual( "http://localhost:80/", httplib2.urlnorm("http://localhost:80")[-1])

+        self.assertEqual( httplib2.urlnorm("http://localhost:80/"), httplib2.urlnorm("HTTP://LOCALHOST:80"))

+        try:

+            httplib2.urlnorm("/")

+            self.fail("Non-absolute URIs should raise an exception")

+        except httplib2.RelativeURIError:

+            pass

+

+class UrlSafenameTest(unittest.TestCase):

+    def test(self):

+        # Test that different URIs end up generating different safe names

+        self.assertEqual( "example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f", httplib2.safename("http://example.org/fred/?a=b"))

+        self.assertEqual( "example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b", httplib2.safename("http://example.org/fred?/a=b"))

+        self.assertEqual( "www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968", httplib2.safename("http://www.example.org/fred?/a=b"))

+        self.assertEqual( httplib2.safename(httplib2.urlnorm("http://www")[-1]), httplib2.safename(httplib2.urlnorm("http://WWW")[-1]))

+        self.assertEqual( "www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d", httplib2.safename("https://www.example.org/fred?/a=b"))

+        self.assertNotEqual( httplib2.safename("http://www"), httplib2.safename("https://www"))

+        # Test the max length limits

+        uri = "http://" + ("w" * 200) + ".org"

+        uri2 = "http://" + ("w" * 201) + ".org"

+        self.assertNotEqual( httplib2.safename(uri2), httplib2.safename(uri))

+        # Max length should be 200 + 1 (",") + 32

+        self.assertEqual(233, len(httplib2.safename(uri2)))

+        self.assertEqual(233, len(httplib2.safename(uri)))

+        # Unicode

+        if sys.version_info >= (2,3):

+            self.assertEqual( "xn--http,-4y1d.org,fred,a=b,579924c35db315e5a32e3d9963388193", httplib2.safename("http://\u2304.org/fred/?a=b"))

+

+class _MyResponse(io.BytesIO):

+    def __init__(self, body, **kwargs):

+        io.BytesIO.__init__(self, body)

+        self.headers = kwargs

+

+    def items(self):

+        return self.headers.items()

+

+    def iteritems(self):

+        return iter(self.headers.items())

+

+

+class _MyHTTPConnection(object):

+    "This class is just a mock of httplib.HTTPConnection used for testing"

+

+    def __init__(self, host, port=None, key_file=None, cert_file=None,

+                 strict=None, timeout=None, proxy_info=None):

+        self.host = host

+        self.port = port

+        self.timeout = timeout

+        self.log = ""

+        self.sock = None

+

+    def set_debuglevel(self, level):

+        pass

+

+    def connect(self):

+        "Connect to a host on a given port."

+        pass

+

+    def close(self):

+        pass

+

+    def request(self, method, request_uri, body, headers):

+        pass

+

+    def getresponse(self):

+        return _MyResponse(b"the body", status="200")

+

+

+class _MyHTTPBadStatusConnection(object):

+    "Mock of httplib.HTTPConnection that raises BadStatusLine."

+

+    num_calls = 0

+

+    def __init__(self, host, port=None, key_file=None, cert_file=None,

+                 strict=None, timeout=None, proxy_info=None):

+        self.host = host

+        self.port = port

+        self.timeout = timeout

+        self.log = ""

+        self.sock = None

+        _MyHTTPBadStatusConnection.num_calls = 0

+

+    def set_debuglevel(self, level):

+        pass

+

+    def connect(self):

+        pass

+

+    def close(self):

+        pass

+

+    def request(self, method, request_uri, body, headers):

+        pass

+

+    def getresponse(self):

+        _MyHTTPBadStatusConnection.num_calls += 1

+        raise http.client.BadStatusLine("")

+

+

+class HttpTest(unittest.TestCase):

+    def setUp(self):

+        if os.path.exists(cacheDirName):

+            [os.remove(os.path.join(cacheDirName, file)) for file in os.listdir(cacheDirName)]

+        self.http = httplib2.Http(cacheDirName)

+        self.http.clear_credentials()

+

+    def testIPv6NoSSL(self):

+        try:

+          self.http.request("http://[::1]/")

+        except socket.gaierror:

+          self.fail("should get the address family right for IPv6")

+        except socket.error:

+          # Even if IPv6 isn't installed on a machine it should just raise socket.error

+          pass

+

+    def testIPv6SSL(self):

+        try:

+          self.http.request("https://[::1]/")

+        except socket.gaierror:

+          self.fail("should get the address family right for IPv6")

+        except socket.error:

+          # Even if IPv6 isn't installed on a machine it should just raise socket.error

+          pass

+

+    def testConnectionType(self):

+        self.http.force_exception_to_status_code = False

+        response, content = self.http.request("http://bitworking.org", connection_type=_MyHTTPConnection)

+        self.assertEqual(response['content-location'], "http://bitworking.org")

+        self.assertEqual(content, b"the body")

+

+

+    def testBadStatusLineRetry(self):

+        old_retries = httplib2.RETRIES

+        httplib2.RETRIES = 1

+        self.http.force_exception_to_status_code = False

+        try:

+            response, content = self.http.request("http://bitworking.org",

+                connection_type=_MyHTTPBadStatusConnection)

+        except http.client.BadStatusLine:

+            self.assertEqual(2, _MyHTTPBadStatusConnection.num_calls)

+        httplib2.RETRIES = old_retries

+

+

+    def testGetUnknownServer(self):

+        self.http.force_exception_to_status_code = False

+        try:

+            self.http.request("http://fred.bitworking.org/")

+            self.fail("An httplib2.ServerNotFoundError Exception must be thrown on an unresolvable server.")

+        except httplib2.ServerNotFoundError:

+            pass

+

+        # Now test with exceptions turned off

+        self.http.force_exception_to_status_code = True

+

+        (response, content) = self.http.request("http://fred.bitworking.org/")

+        self.assertEqual(response['content-type'], 'text/plain')

+        self.assertTrue(content.startswith(b"Unable to find"))

+        self.assertEqual(response.status, 400)

+

+    def testGetConnectionRefused(self):

+        self.http.force_exception_to_status_code = False

+        try:

+            self.http.request("http://localhost:7777/")

+            self.fail("An socket.error exception must be thrown on Connection Refused.")

+        except socket.error:

+            pass

+

+        # Now test with exceptions turned off

+        self.http.force_exception_to_status_code = True

+

+        (response, content) = self.http.request("http://localhost:7777/")

+        self.assertEqual(response['content-type'], 'text/plain')

+        self.assertTrue(b"Connection refused" in content)

+        self.assertEqual(response.status, 400)

+

+    def testGetIRI(self):

+        if sys.version_info >= (2,3):

+            uri = urllib.parse.urljoin(base, "reflector/reflector.cgi?d=\N{CYRILLIC CAPITAL LETTER DJE}")

+            (response, content) = self.http.request(uri, "GET")

+            d = self.reflector(content)

+            self.assertTrue('QUERY_STRING' in d)

+            self.assertTrue(d['QUERY_STRING'].find('%D0%82') > 0)

+

+    def testGetIsDefaultMethod(self):

+        # Test that GET is the default method

+        uri = urllib.parse.urljoin(base, "methods/method_reflector.cgi")

+        (response, content) = self.http.request(uri)

+        self.assertEqual(response['x-method'], "GET")

+

+    def testDifferentMethods(self):

+        # Test that all methods can be used

+        uri = urllib.parse.urljoin(base, "methods/method_reflector.cgi")

+        for method in ["GET", "PUT", "DELETE", "POST"]:

+            (response, content) = self.http.request(uri, method, body=b" ")

+            self.assertEqual(response['x-method'], method)

+

+    def testHeadRead(self):

+        # Test that we don't try to read the response of a HEAD request

+        # since httplib blocks response.read() for HEAD requests.

+        # Oddly enough this doesn't appear as a problem when doing HEAD requests

+        # against Apache servers.

+        uri = "http://www.google.com/"

+        (response, content) = self.http.request(uri, "HEAD")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(content, b"")

+

+    def testGetNoCache(self):

+        # Test that can do a GET w/o the cache turned on.

+        http = httplib2.Http()

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+        (response, content) = http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.previous, None)

+

+    def testGetOnlyIfCachedCacheHit(self):

+        # Test that can do a GET with cache and 'only-if-cached'

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+        (response, content) = self.http.request(uri, "GET")

+        (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})

+        self.assertEqual(response.fromcache, True)

+        self.assertEqual(response.status, 200)

+

+    def testGetOnlyIfCachedCacheMiss(self):

+        # Test that can do a GET with no cache with 'only-if-cached'

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+        (response, content) = self.http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})

+        self.assertEqual(response.fromcache, False)

+        self.assertEqual(response.status, 504)

+

+    def testGetOnlyIfCachedNoCacheAtAll(self):

+        # Test that can do a GET with no cache with 'only-if-cached'

+        # Of course, there might be an intermediary beyond us

+        # that responds to the 'only-if-cached', so this

+        # test can't really be guaranteed to pass.

+        http = httplib2.Http()

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+        (response, content) = http.request(uri, "GET", headers={'cache-control': 'only-if-cached'})

+        self.assertEqual(response.fromcache, False)

+        self.assertEqual(response.status, 504)

+

+    def testUserAgent(self):

+        # Test that we provide a default user-agent

+        uri = urllib.parse.urljoin(base, "user-agent/test.cgi")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertTrue(content.startswith(b"Python-httplib2/"))

+

+    def testUserAgentNonDefault(self):

+        # Test that the default user-agent can be over-ridden

+

+        uri = urllib.parse.urljoin(base, "user-agent/test.cgi")

+        (response, content) = self.http.request(uri, "GET", headers={'User-Agent': 'fred/1.0'})

+        self.assertEqual(response.status, 200)

+        self.assertTrue(content.startswith(b"fred/1.0"))

+

+    def testGet300WithLocation(self):

+        # Test the we automatically follow 300 redirects if a Location: header is provided

+        uri = urllib.parse.urljoin(base, "300/with-location-header.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 300)

+        self.assertEqual(response.previous.fromcache, False)

+

+        # Confirm that the intermediate 300 is not cached

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 300)

+        self.assertEqual(response.previous.fromcache, False)

+

+    def testGet300WithLocationNoRedirect(self):

+        # Test the we automatically follow 300 redirects if a Location: header is provided

+        self.http.follow_redirects = False

+        uri = urllib.parse.urljoin(base, "300/with-location-header.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 300)

+

+    def testGet300WithoutLocation(self):

+        # Not giving a Location: header in a 300 response is acceptable

+        # In which case we just return the 300 response

+        uri = urllib.parse.urljoin(base, "300/without-location-header.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 300)

+        self.assertTrue(response['content-type'].startswith("text/html"))

+        self.assertEqual(response.previous, None)

+

+    def testGet301(self):

+        # Test that we automatically follow 301 redirects

+        # and that we cache the 301 response

+        uri = urllib.parse.urljoin(base, "301/onestep.asis")

+        destination = urllib.parse.urljoin(base, "302/final-destination.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertTrue('content-location' in response)

+        self.assertEqual(response['content-location'], destination)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 301)

+        self.assertEqual(response.previous.fromcache, False)

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response['content-location'], destination)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 301)

+        self.assertEqual(response.previous.fromcache, True)

+

+    def testHead301(self):

+        # Test that we automatically follow 301 redirects

+        uri = urllib.parse.urljoin(base, "301/onestep.asis")

+        (response, content) = self.http.request(uri, "HEAD")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.previous.status, 301)

+        self.assertEqual(response.previous.fromcache, False)

+

+    def testGet301NoRedirect(self):

+        # Test that we automatically follow 301 redirects

+        # and that we cache the 301 response

+        self.http.follow_redirects = False

+        uri = urllib.parse.urljoin(base, "301/onestep.asis")

+        destination = urllib.parse.urljoin(base, "302/final-destination.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 301)

+

+

+    def testGet302(self):

+        # Test that we automatically follow 302 redirects

+        # and that we DO NOT cache the 302 response

+        uri = urllib.parse.urljoin(base, "302/onestep.asis")

+        destination = urllib.parse.urljoin(base, "302/final-destination.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response['content-location'], destination)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 302)

+        self.assertEqual(response.previous.fromcache, False)

+

+        uri = urllib.parse.urljoin(base, "302/onestep.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+        self.assertEqual(response['content-location'], destination)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 302)

+        self.assertEqual(response.previous.fromcache, False)

+        self.assertEqual(response.previous['content-location'], uri)

+

+        uri = urllib.parse.urljoin(base, "302/twostep.asis")

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 302)

+        self.assertEqual(response.previous.fromcache, False)

+

+    def testGet302RedirectionLimit(self):

+        # Test that we can set a lower redirection limit

+        # and that we raise an exception when we exceed

+        # that limit.

+        self.http.force_exception_to_status_code = False

+

+        uri = urllib.parse.urljoin(base, "302/twostep.asis")

+        try:

+            (response, content) = self.http.request(uri, "GET", redirections = 1)

+            self.fail("This should not happen")

+        except httplib2.RedirectLimit:

+            pass

+        except Exception as e:

+            self.fail("Threw wrong kind of exception ")

+

+        # Re-run the test with out the exceptions

+        self.http.force_exception_to_status_code = True

+

+        (response, content) = self.http.request(uri, "GET", redirections = 1)

+        self.assertEqual(response.status, 500)

+        self.assertTrue(response.reason.startswith("Redirected more"))

+        self.assertEqual("302", response['status'])

+        self.assertTrue(content.startswith(b"<html>"))

+        self.assertTrue(response.previous != None)

+

+    def testGet302NoLocation(self):

+        # Test that we throw an exception when we get

+        # a 302 with no Location: header.

+        self.http.force_exception_to_status_code = False

+        uri = urllib.parse.urljoin(base, "302/no-location.asis")

+        try:

+            (response, content) = self.http.request(uri, "GET")

+            self.fail("Should never reach here")

+        except httplib2.RedirectMissingLocation:

+            pass

+        except Exception as e:

+            self.fail("Threw wrong kind of exception ")

+

+        # Re-run the test with out the exceptions

+        self.http.force_exception_to_status_code = True

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 500)

+        self.assertTrue(response.reason.startswith("Redirected but"))

+        self.assertEqual("302", response['status'])

+        self.assertTrue(content.startswith(b"This is content"))

+

+    def testGet301ViaHttps(self):

+        # Google always redirects to http://google.com

+        (response, content) = self.http.request("https://code.google.com/apis/", "GET")

+        self.assertEqual(200, response.status)

+        self.assertEqual(301, response.previous.status)

+

+    def testGetViaHttps(self):

+        # Test that we can handle HTTPS

+        (response, content) = self.http.request("https://google.com/adsense/", "GET")

+        self.assertEqual(200, response.status)

+

+    def testGetViaHttpsSpecViolationOnLocation(self):

+        # Test that we follow redirects through HTTPS

+        # even if they violate the spec by including

+        # a relative Location: header instead of an

+        # absolute one.

+        (response, content) = self.http.request("https://google.com/adsense", "GET")

+        self.assertEqual(200, response.status)

+        self.assertNotEqual(None, response.previous)

+

+

+    def testGetViaHttpsKeyCert(self):

+        #  At this point I can only test

+        #  that the key and cert files are passed in

+        #  correctly to httplib. It would be nice to have

+        #  a real https endpoint to test against.

+        http = httplib2.Http(timeout=2)

+

+        http.add_certificate("akeyfile", "acertfile", "bitworking.org")

+        try:

+          (response, content) = http.request("https://bitworking.org", "GET")

+        except AttributeError:

+          self.assertEqual(http.connections["https:bitworking.org"].key_file, "akeyfile")

+          self.assertEqual(http.connections["https:bitworking.org"].cert_file, "acertfile")

+        except IOError:

+          # Skip on 3.2

+          pass

+

+        try:

+            (response, content) = http.request("https://notthere.bitworking.org", "GET")

+        except httplib2.ServerNotFoundError:

+          self.assertEqual(http.connections["https:notthere.bitworking.org"].key_file, None)

+          self.assertEqual(http.connections["https:notthere.bitworking.org"].cert_file, None)

+        except IOError:

+          # Skip on 3.2

+          pass

+

+    def testSslCertValidation(self):

+          # Test that we get an ssl.SSLError when specifying a non-existent CA

+          # certs file.

+          http = httplib2.Http(ca_certs='/nosuchfile')

+          self.assertRaises(IOError,

+                  http.request, "https://www.google.com/", "GET")

+

+          # Test that we get a SSLHandshakeError if we try to access

+          # https://www.google.com, using a CA cert file that doesn't contain

+          # the CA Google uses (i.e., simulating a cert that's not signed by a

+          # trusted CA).

+          other_ca_certs = os.path.join(

+                  os.path.dirname(os.path.abspath(httplib2.__file__ )),

+                  "test", "other_cacerts.txt")

+          http = httplib2.Http(ca_certs=other_ca_certs)

+          self.assertRaises(ssl.SSLError,

+            http.request,"https://www.google.com/", "GET")

+

+    def testSniHostnameValidation(self):

+        self.http.request("https://google.com/", method="GET")

+

+    def testGet303(self):

+        # Do a follow-up GET on a Location: header

+        # returned from a POST that gave a 303.

+        uri = urllib.parse.urljoin(base, "303/303.cgi")

+        (response, content) = self.http.request(uri, "POST", " ")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 303)

+

+    def testGet303NoRedirect(self):

+        # Do a follow-up GET on a Location: header

+        # returned from a POST that gave a 303.

+        self.http.follow_redirects = False

+        uri = urllib.parse.urljoin(base, "303/303.cgi")

+        (response, content) = self.http.request(uri, "POST", " ")

+        self.assertEqual(response.status, 303)

+

+    def test303ForDifferentMethods(self):

+        # Test that all methods can be used

+        uri = urllib.parse.urljoin(base, "303/redirect-to-reflector.cgi")

+        for (method, method_on_303) in [("PUT", "GET"), ("DELETE", "GET"), ("POST", "GET"), ("GET", "GET"), ("HEAD", "GET")]:

+            (response, content) = self.http.request(uri, method, body=b" ")

+            self.assertEqual(response['x-method'], method_on_303)

+

+    def testGet304(self):

+        # Test that we use ETags properly to validate our cache

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        self.assertNotEqual(response['etag'], "")

+

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'must-revalidate'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+

+        cache_file_name = os.path.join(cacheDirName, httplib2.safename(httplib2.urlnorm(uri)[-1]))

+        f = open(cache_file_name, "r")

+        status_line = f.readline()

+        f.close()

+

+        self.assertTrue(status_line.startswith("status:"))

+

+        (response, content) = self.http.request(uri, "HEAD", headers = {'accept-encoding': 'identity'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'range': 'bytes=0-0'})

+        self.assertEqual(response.status, 206)

+        self.assertEqual(response.fromcache, False)

+

+    def testGetIgnoreEtag(self):

+        # Test that we can forcibly ignore ETags

+        uri = urllib.parse.urljoin(base, "reflector/reflector.cgi")

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        self.assertNotEqual(response['etag'], "")

+

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})

+        d = self.reflector(content)

+        self.assertTrue('HTTP_IF_NONE_MATCH' in d)

+

+        self.http.ignore_etag = True

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})

+        d = self.reflector(content)

+        self.assertEqual(response.fromcache, False)

+        self.assertFalse('HTTP_IF_NONE_MATCH' in d)

+

+    def testOverrideEtag(self):

+        # Test that we can forcibly ignore ETags

+        uri = urllib.parse.urljoin(base, "reflector/reflector.cgi")

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        self.assertNotEqual(response['etag'], "")

+

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0'})

+        d = self.reflector(content)

+        self.assertTrue('HTTP_IF_NONE_MATCH' in d)

+        self.assertNotEqual(d['HTTP_IF_NONE_MATCH'], "fred")

+

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'cache-control': 'max-age=0', 'if-none-match': 'fred'})

+        d = self.reflector(content)

+        self.assertTrue('HTTP_IF_NONE_MATCH' in d)

+        self.assertEqual(d['HTTP_IF_NONE_MATCH'], "fred")

+

+#MAP-commented this out because it consistently fails

+#    def testGet304EndToEnd(self):

+#       # Test that end to end headers get overwritten in the cache

+#        uri = urllib.parse.urljoin(base, "304/end2end.cgi")

+#        (response, content) = self.http.request(uri, "GET")

+#        self.assertNotEqual(response['etag'], "")

+#        old_date = response['date']

+#        time.sleep(2)

+#

+#        (response, content) = self.http.request(uri, "GET", headers = {'Cache-Control': 'max-age=0'})

+#        # The response should be from the cache, but the Date: header should be updated.

+#        new_date = response['date']

+#        self.assertNotEqual(new_date, old_date)

+#        self.assertEqual(response.status, 200)

+#        self.assertEqual(response.fromcache, True)

+

+    def testGet304LastModified(self):

+        # Test that we can still handle a 304

+        # by only using the last-modified cache validator.

+        uri = urllib.parse.urljoin(base, "304/last-modified-only/last-modified-only.txt")

+        (response, content) = self.http.request(uri, "GET")

+

+        self.assertNotEqual(response['last-modified'], "")

+        (response, content) = self.http.request(uri, "GET")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+

+    def testGet307(self):

+        # Test that we do follow 307 redirects but

+        # do not cache the 307

+        uri = urllib.parse.urljoin(base, "307/onestep.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 307)

+        self.assertEqual(response.previous.fromcache, False)

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+        self.assertEqual(content, b"This is the final destination.\n")

+        self.assertEqual(response.previous.status, 307)

+        self.assertEqual(response.previous.fromcache, False)

+

+    def testGet410(self):

+        # Test that we pass 410's through

+        uri = urllib.parse.urljoin(base, "410/410.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 410)

+

+    def testVaryHeaderSimple(self):

+        """

+        RFC 2616 13.6

+        When the cache receives a subsequent request whose Request-URI

+        specifies one or more cache entries including a Vary header field,

+        the cache MUST NOT use such a cache entry to construct a response

+        to the new request unless all of the selecting request-headers

+        present in the new request match the corresponding stored

+        request-headers in the original request.

+        """

+        # test that the vary header is sent

+        uri = urllib.parse.urljoin(base, "vary/accept.asis")

+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})

+        self.assertEqual(response.status, 200)

+        self.assertTrue('vary' in response)

+

+        # get the resource again, from the cache since accept header in this

+        # request is the same as the request

+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True, msg="Should be from cache")

+

+        # get the resource again, not from cache since Accept headers does not match

+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False, msg="Should not be from cache")

+

+        # get the resource again, without any Accept header, so again no match

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False, msg="Should not be from cache")

+

+    def testNoVary(self):

+        pass

+        # when there is no vary, a different Accept header (e.g.) should not

+        # impact if the cache is used

+        # test that the vary header is not sent

+        # uri = urllib.parse.urljoin(base, "vary/no-vary.asis")

+        # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})

+        # self.assertEqual(response.status, 200)

+        # self.assertFalse('vary' in response)

+        #

+        # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})

+        # self.assertEqual(response.status, 200)

+        # self.assertEqual(response.fromcache, True, msg="Should be from cache")

+        #

+        # (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/html'})

+        # self.assertEqual(response.status, 200)

+        # self.assertEqual(response.fromcache, True, msg="Should be from cache")

+

+    def testVaryHeaderDouble(self):

+        uri = urllib.parse.urljoin(base, "vary/accept-double.asis")

+        (response, content) = self.http.request(uri, "GET", headers={

+            'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})

+        self.assertEqual(response.status, 200)

+        self.assertTrue('vary' in response)

+

+        # we are from cache

+        (response, content) = self.http.request(uri, "GET", headers={

+            'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})

+        self.assertEqual(response.fromcache, True, msg="Should be from cache")

+

+        (response, content) = self.http.request(uri, "GET", headers={'Accept': 'text/plain'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+        # get the resource again, not from cache, varied headers don't match exact

+        (response, content) = self.http.request(uri, "GET", headers={'Accept-Language': 'da'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False, msg="Should not be from cache")

+

+    def testVaryUnusedHeader(self):

+        # A header's value is not considered to vary if it's not used at all.

+        uri = urllib.parse.urljoin(base, "vary/unused-header.asis")

+        (response, content) = self.http.request(uri, "GET", headers={

+            'Accept': 'text/plain'})

+        self.assertEqual(response.status, 200)

+        self.assertTrue('vary' in response)

+

+        # we are from cache

+        (response, content) = self.http.request(uri, "GET", headers={

+            'Accept': 'text/plain',})

+        self.assertEqual(response.fromcache, True, msg="Should be from cache")

+

+    def testHeadGZip(self):

+        # Test that we don't try to decompress a HEAD response

+        uri = urllib.parse.urljoin(base, "gzip/final-destination.txt")

+        (response, content) = self.http.request(uri, "HEAD")

+        self.assertEqual(response.status, 200)

+        self.assertNotEqual(int(response['content-length']), 0)

+        self.assertEqual(content, b"")

+

+    def testGetGZip(self):

+        # Test that we support gzip compression

+        uri = urllib.parse.urljoin(base, "gzip/final-destination.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertFalse('content-encoding' in response)

+        self.assertTrue('-content-encoding' in response)

+        self.assertEqual(int(response['content-length']), len(b"This is the final destination.\n"))

+        self.assertEqual(content, b"This is the final destination.\n")

+

+    def testPostAndGZipResponse(self):

+        uri = urllib.parse.urljoin(base, "gzip/post.cgi")

+        (response, content) = self.http.request(uri, "POST", body=" ")

+        self.assertEqual(response.status, 200)

+        self.assertFalse('content-encoding' in response)

+        self.assertTrue('-content-encoding' in response)

+

+    def testGetGZipFailure(self):

+        # Test that we raise a good exception when the gzip fails

+        self.http.force_exception_to_status_code = False

+        uri = urllib.parse.urljoin(base, "gzip/failed-compression.asis")

+        try:

+            (response, content) = self.http.request(uri, "GET")

+            self.fail("Should never reach here")

+        except httplib2.FailedToDecompressContent:

+            pass

+        except Exception:

+            self.fail("Threw wrong kind of exception")

+

+        # Re-run the test with out the exceptions

+        self.http.force_exception_to_status_code = True

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 500)

+        self.assertTrue(response.reason.startswith("Content purported"))

+

+    def testIndividualTimeout(self):

+        uri = urllib.parse.urljoin(base, "timeout/timeout.cgi")

+        http = httplib2.Http(timeout=1)

+        http.force_exception_to_status_code = True

+

+        (response, content) = http.request(uri)

+        self.assertEqual(response.status, 408)

+        self.assertTrue(response.reason.startswith("Request Timeout"))

+        self.assertTrue(content.startswith(b"Request Timeout"))

+

+

+    def testGetDeflate(self):

+        # Test that we support deflate compression

+        uri = urllib.parse.urljoin(base, "deflate/deflated.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertFalse('content-encoding' in response)

+        self.assertEqual(int(response['content-length']), len("This is the final destination."))

+        self.assertEqual(content, b"This is the final destination.")

+

+    def testGetDeflateFailure(self):

+        # Test that we raise a good exception when the deflate fails

+        self.http.force_exception_to_status_code = False

+

+        uri = urllib.parse.urljoin(base, "deflate/failed-compression.asis")

+        try:

+            (response, content) = self.http.request(uri, "GET")

+            self.fail("Should never reach here")

+        except httplib2.FailedToDecompressContent:

+            pass

+        except Exception:

+            self.fail("Threw wrong kind of exception")

+

+        # Re-run the test with out the exceptions

+        self.http.force_exception_to_status_code = True

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 500)

+        self.assertTrue(response.reason.startswith("Content purported"))

+

+    def testGetDuplicateHeaders(self):

+        # Test that duplicate headers get concatenated via ','

+        uri = urllib.parse.urljoin(base, "duplicate-headers/multilink.asis")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(content, b"This is content\n")

+        self.assertEqual(response['link'].split(",")[0], '<http://bitworking.org>; rel="home"; title="BitWorking"')

+

+    def testGetCacheControlNoCache(self):

+        # Test Cache-Control: no-cache on requests

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        self.assertNotEqual(response['etag'], "")

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'Cache-Control': 'no-cache'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+    def testGetCacheControlPragmaNoCache(self):

+        # Test Pragma: no-cache on requests

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        self.assertNotEqual(response['etag'], "")

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+

+        (response, content) = self.http.request(uri, "GET", headers = {'accept-encoding': 'identity', 'Pragma': 'no-cache'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+    def testGetCacheControlNoStoreRequest(self):

+        # A no-store request means that the response should not be stored.

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+

+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+    def testGetCacheControlNoStoreResponse(self):

+        # A no-store response means that the response should not be stored.

+        uri = urllib.parse.urljoin(base, "no-store/no-store.asis")

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+    def testGetCacheControlNoCacheNoStoreRequest(self):

+        # Test that a no-store, no-cache clears the entry from the cache

+        # even if it was cached previously.

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+

+        (response, content) = self.http.request(uri, "GET")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.fromcache, True)

+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})

+        (response, content) = self.http.request(uri, "GET", headers={'Cache-Control': 'no-store, no-cache'})

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+

+    def testUpdateInvalidatesCache(self):

+        # Test that calling PUT or DELETE on a

+        # URI that is cache invalidates that cache.

+        uri = urllib.parse.urljoin(base, "304/test_etag.txt")

+

+        (response, content) = self.http.request(uri, "GET")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.fromcache, True)

+        (response, content) = self.http.request(uri, "DELETE")

+        self.assertEqual(response.status, 405)

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.fromcache, False)

+

+    def testUpdateUsesCachedETag(self):

+        # Test that we natively support http://www.w3.org/1999/04/Editing/

+        uri = urllib.parse.urljoin(base, "conditional-updates/test.cgi")

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+        (response, content) = self.http.request(uri, "PUT", body="foo")

+        self.assertEqual(response.status, 200)

+        (response, content) = self.http.request(uri, "PUT", body="foo")

+        self.assertEqual(response.status, 412)

+

+

+    def testUpdatePatchUsesCachedETag(self):

+        # Test that we natively support http://www.w3.org/1999/04/Editing/

+        uri = urllib.parse.urljoin(base, "conditional-updates/test.cgi")

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+        (response, content) = self.http.request(uri, "PATCH", body="foo")

+        self.assertEqual(response.status, 200)

+        (response, content) = self.http.request(uri, "PATCH", body="foo")

+        self.assertEqual(response.status, 412)

+

+    def testUpdateUsesCachedETagAndOCMethod(self):

+        # Test that we natively support http://www.w3.org/1999/04/Editing/

+        uri = urllib.parse.urljoin(base, "conditional-updates/test.cgi")

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+        self.http.optimistic_concurrency_methods.append("DELETE")

+        (response, content) = self.http.request(uri, "DELETE")

+        self.assertEqual(response.status, 200)

+

+

+    def testUpdateUsesCachedETagOverridden(self):

+        # Test that we natively support http://www.w3.org/1999/04/Editing/

+        uri = urllib.parse.urljoin(base, "conditional-updates/test.cgi")

+

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, False)

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+        self.assertEqual(response.fromcache, True)

+        (response, content) = self.http.request(uri, "PUT", body="foo", headers={'if-match': 'fred'})

+        self.assertEqual(response.status, 412)

+

+    def testBasicAuth(self):

+        # Test Basic Authentication

+        uri = urllib.parse.urljoin(base, "basic/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        uri = urllib.parse.urljoin(base, "basic/")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        self.http.add_credentials('joe', 'password')

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+        uri = urllib.parse.urljoin(base, "basic/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+    def testBasicAuthWithDomain(self):

+        # Test Basic Authentication

+        uri = urllib.parse.urljoin(base, "basic/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        uri = urllib.parse.urljoin(base, "basic/")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        self.http.add_credentials('joe', 'password', "example.org")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        uri = urllib.parse.urljoin(base, "basic/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        domain = urllib.parse.urlparse(base)[1]

+        self.http.add_credentials('joe', 'password', domain)

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+        uri = urllib.parse.urljoin(base, "basic/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+

+

+

+

+

+    def testBasicAuthTwoDifferentCredentials(self):

+        # Test Basic Authentication with multiple sets of credentials

+        uri = urllib.parse.urljoin(base, "basic2/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        uri = urllib.parse.urljoin(base, "basic2/")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        self.http.add_credentials('fred', 'barney')

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+        uri = urllib.parse.urljoin(base, "basic2/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+    def testBasicAuthNested(self):

+        # Test Basic Authentication with resources

+        # that are nested

+        uri = urllib.parse.urljoin(base, "basic-nested/")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        uri = urllib.parse.urljoin(base, "basic-nested/subdir")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        # Now add in credentials one at a time and test.

+        self.http.add_credentials('joe', 'password')

+

+        uri = urllib.parse.urljoin(base, "basic-nested/")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+        uri = urllib.parse.urljoin(base, "basic-nested/subdir")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        self.http.add_credentials('fred', 'barney')

+

+        uri = urllib.parse.urljoin(base, "basic-nested/")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+        uri = urllib.parse.urljoin(base, "basic-nested/subdir")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+    def testDigestAuth(self):

+        # Test that we support Digest Authentication

+        uri = urllib.parse.urljoin(base, "digest/")

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 401)

+

+        self.http.add_credentials('joe', 'password')

+        (response, content) = self.http.request(uri, "GET")

+        self.assertEqual(response.status, 200)

+

+        uri = urllib.parse.urljoin(base, "digest/file.txt")

+        (response, content) = self.http.request(uri, "GET")

+

+    def testDigestAuthNextNonceAndNC(self):

+        # Test that if the server sets nextnonce that we reset

+        # the nonce count back to 1

+        uri = urllib.parse.urljoin(base, "digest/file.txt")

+        self.http.add_credentials('joe', 'password')

+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})

+        info = httplib2._parse_www_authenticate(response, 'authentication-info')

+        self.assertEqual(response.status, 200)

+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})

+        info2 = httplib2._parse_www_authenticate(response, 'authentication-info')

+        self.assertEqual(response.status, 200)

+

+        if 'nextnonce' in info:

+            self.assertEqual(info2['nc'], 1)

+

+    def testDigestAuthStale(self):

+        # Test that we can handle a nonce becoming stale

+        uri = urllib.parse.urljoin(base, "digest-expire/file.txt")

+        self.http.add_credentials('joe', 'password')

+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})

+        info = httplib2._parse_www_authenticate(response, 'authentication-info')

+        self.assertEqual(response.status, 200)

+

+        time.sleep(3)

+        # Sleep long enough that the nonce becomes stale

+

+        (response, content) = self.http.request(uri, "GET", headers = {"cache-control":"no-cache"})

+        self.assertFalse(response.fromcache)

+        self.assertTrue(response._stale_digest)

+        info3 = httplib2._parse_www_authenticate(response, 'authentication-info')

+        self.assertEqual(response.status, 200)

+

+    def reflector(self, content):

+        return  dict( [tuple(x.split("=", 1)) for x in content.decode('utf-8').strip().split("\n")] )

+

+    def testReflector(self):

+        uri = urllib.parse.urljoin(base, "reflector/reflector.cgi")

+        (response, content) = self.http.request(uri, "GET")

+        d = self.reflector(content)

+        self.assertTrue('HTTP_USER_AGENT' in d)

+

+

+    def testConnectionClose(self):

+        uri = "http://www.google.com/"

+        (response, content) = self.http.request(uri, "GET")

+        for c in self.http.connections.values():

+            self.assertNotEqual(None, c.sock)

+        (response, content) = self.http.request(uri, "GET", headers={"connection": "close"})

+        for c in self.http.connections.values():

+            self.assertEqual(None, c.sock)

+

+    def testPickleHttp(self):

+        pickled_http = pickle.dumps(self.http)

+        new_http = pickle.loads(pickled_http)

+

+        self.assertEqual(sorted(new_http.__dict__.keys()),

+                         sorted(self.http.__dict__.keys()))

+        for key in new_http.__dict__:

+            if key in ('certificates', 'credentials'):

+                self.assertEqual(new_http.__dict__[key].credentials,

+                                 self.http.__dict__[key].credentials)

+            elif key == 'cache':

+                self.assertEqual(new_http.__dict__[key].cache,

+                                 self.http.__dict__[key].cache)

+            else:

+                self.assertEqual(new_http.__dict__[key],

+                                 self.http.__dict__[key])

+

+    def testPickleHttpWithConnection(self):

+        self.http.request('http://bitworking.org',

+                          connection_type=_MyHTTPConnection)

+        pickled_http = pickle.dumps(self.http)

+        new_http = pickle.loads(pickled_http)

+

+        self.assertEqual(list(self.http.connections.keys()),

+                         ['http:bitworking.org'])

+        self.assertEqual(new_http.connections, {})

+

+    def testPickleCustomRequestHttp(self):

+        def dummy_request(*args, **kwargs):

+            return new_request(*args, **kwargs)

+        dummy_request.dummy_attr = 'dummy_value'

+

+        self.http.request = dummy_request

+        pickled_http = pickle.dumps(self.http)

+        self.assertFalse(b"S'request'" in pickled_http)

+

+try:

+    import memcache

+    class HttpTestMemCached(HttpTest):

+        def setUp(self):

+            self.cache = memcache.Client(['127.0.0.1:11211'], debug=0)

+            #self.cache = memcache.Client(['10.0.0.4:11211'], debug=1)

+            self.http = httplib2.Http(self.cache)

+            self.cache.flush_all()

+            # Not exactly sure why the sleep is needed here, but

+            # if not present then some unit tests that rely on caching

+            # fail. Memcached seems to lose some sets immediately

+            # after a flush_all if the set is to a value that

+            # was previously cached. (Maybe the flush is handled async?)

+            time.sleep(1)

+            self.http.clear_credentials()

+except:

+    pass

+

+

+

+# ------------------------------------------------------------------------

+

+class HttpPrivateTest(unittest.TestCase):

+

+    def testParseCacheControl(self):

+        # Test that we can parse the Cache-Control header

+        self.assertEqual({}, httplib2._parse_cache_control({}))

+        self.assertEqual({'no-cache': 1}, httplib2._parse_cache_control({'cache-control': ' no-cache'}))

+        cc = httplib2._parse_cache_control({'cache-control': ' no-cache, max-age = 7200'})

+        self.assertEqual(cc['no-cache'], 1)

+        self.assertEqual(cc['max-age'], '7200')

+        cc = httplib2._parse_cache_control({'cache-control': ' , '})

+        self.assertEqual(cc[''], 1)

+

+        try:

+            cc = httplib2._parse_cache_control({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'})

+            self.assertTrue("max-age" in cc)

+        except:

+            self.fail("Should not throw exception")

+

+

+

+

+    def testNormalizeHeaders(self):

+        # Test that we normalize headers to lowercase

+        h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})

+        self.assertTrue('cache-control' in h)

+        self.assertTrue('other' in h)

+        self.assertEqual('Stuff', h['other'])

+    

+    def testConvertByteStr(self):

+        with self.assertRaises(TypeError):

+            httplib2._convert_byte_str(4)

+        self.assertEqual('Hello World', httplib2._convert_byte_str(b'Hello World'))

+        self.assertEqual('Bye World', httplib2._convert_byte_str('Bye World'))

+

+    def testExpirationModelTransparent(self):

+        # Test that no-cache makes our request TRANSPARENT

+        response_headers = {

+            'cache-control': 'max-age=7200'

+        }

+        request_headers = {

+            'cache-control': 'no-cache'

+        }

+        self.assertEqual("TRANSPARENT", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testMaxAgeNonNumeric(self):

+        # Test that no-cache makes our request TRANSPARENT

+        response_headers = {

+            'cache-control': 'max-age=fred, min-fresh=barney'

+        }

+        request_headers = {

+        }

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+

+    def testExpirationModelNoCacheResponse(self):

+        # The date and expires point to an entry that should be

+        # FRESH, but the no-cache over-rides that.

+        now = time.time()

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),

+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),

+            'cache-control': 'no-cache'

+        }

+        request_headers = {

+        }

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationModelStaleRequestMustReval(self):

+        # must-revalidate forces STALE

+        self.assertEqual("STALE", httplib2._entry_disposition({}, {'cache-control': 'must-revalidate'}))

+

+    def testExpirationModelStaleResponseMustReval(self):

+        # must-revalidate forces STALE

+        self.assertEqual("STALE", httplib2._entry_disposition({'cache-control': 'must-revalidate'}, {}))

+

+    def testExpirationModelFresh(self):

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),

+            'cache-control': 'max-age=2'

+        }

+        request_headers = {

+        }

+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))

+        time.sleep(3)

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationMaxAge0(self):

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime()),

+            'cache-control': 'max-age=0'

+        }

+        request_headers = {

+        }

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationModelDateAndExpires(self):

+        now = time.time()

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),

+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),

+        }

+        request_headers = {

+        }

+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))

+        time.sleep(3)

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpiresZero(self):

+        now = time.time()

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),

+            'expires': "0",

+        }

+        request_headers = {

+        }

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationModelDateOnly(self):

+        now = time.time()

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+3)),

+        }

+        request_headers = {

+        }

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationModelOnlyIfCached(self):

+        response_headers = {

+        }

+        request_headers = {

+            'cache-control': 'only-if-cached',

+        }

+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationModelMaxAgeBoth(self):

+        now = time.time()

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),

+            'cache-control': 'max-age=2'

+        }

+        request_headers = {

+            'cache-control': 'max-age=0'

+        }

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationModelDateAndExpiresMinFresh1(self):

+        now = time.time()

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),

+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+2)),

+        }

+        request_headers = {

+            'cache-control': 'min-fresh=2'

+        }

+        self.assertEqual("STALE", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testExpirationModelDateAndExpiresMinFresh2(self):

+        now = time.time()

+        response_headers = {

+            'date': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),

+            'expires': time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now+4)),

+        }

+        request_headers = {

+            'cache-control': 'min-fresh=2'

+        }

+        self.assertEqual("FRESH", httplib2._entry_disposition(response_headers, request_headers))

+

+    def testParseWWWAuthenticateEmpty(self):

+        res = httplib2._parse_www_authenticate({})

+        self.assertEqual(len(list(res.keys())), 0)

+

+    def testParseWWWAuthenticate(self):

+        # different uses of spaces around commas

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'})

+        self.assertEqual(len(list(res.keys())), 1)

+        self.assertEqual(len(list(res['test'].keys())), 5)

+

+        # tokens with non-alphanum

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'})

+        self.assertEqual(len(list(res.keys())), 1)

+        self.assertEqual(len(list(res['t*!%#st'].keys())), 2)

+

+        # quoted string with quoted pairs

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Test realm="a \\"test\\" realm"'})

+        self.assertEqual(len(list(res.keys())), 1)

+        self.assertEqual(res['test']['realm'], 'a "test" realm')

+

+    def testParseWWWAuthenticateStrict(self):

+        httplib2.USE_WWW_AUTH_STRICT_PARSING = 1;

+        self.testParseWWWAuthenticate();

+        httplib2.USE_WWW_AUTH_STRICT_PARSING = 0;

+

+    def testParseWWWAuthenticateBasic(self):

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me"'})

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm="MD5"'})

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+        self.assertEqual('MD5', basic['algorithm'])

+

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me", algorithm=MD5'})

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+        self.assertEqual('MD5', basic['algorithm'])

+

+    def testParseWWWAuthenticateBasic2(self):

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic realm="me",other="fred" '})

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+        self.assertEqual('fred', basic['other'])

+

+    def testParseWWWAuthenticateBasic3(self):

+        res = httplib2._parse_www_authenticate({ 'www-authenticate': 'Basic REAlm="me" '})

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+

+

+    def testParseWWWAuthenticateDigest(self):

+        res = httplib2._parse_www_authenticate({ 'www-authenticate':

+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"'})

+        digest = res['digest']

+        self.assertEqual('testrealm@host.com', digest['realm'])

+        self.assertEqual('auth,auth-int', digest['qop'])

+

+

+    def testParseWWWAuthenticateMultiple(self):

+        res = httplib2._parse_www_authenticate({ 'www-authenticate':

+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41" Basic REAlm="me" '})

+        digest = res['digest']

+        self.assertEqual('testrealm@host.com', digest['realm'])

+        self.assertEqual('auth,auth-int', digest['qop'])

+        self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])

+        self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+

+    def testParseWWWAuthenticateMultiple2(self):

+        # Handle an added comma between challenges, which might get thrown in if the challenges were

+        # originally sent in separate www-authenticate headers.

+        res = httplib2._parse_www_authenticate({ 'www-authenticate':

+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me" '})

+        digest = res['digest']

+        self.assertEqual('testrealm@host.com', digest['realm'])

+        self.assertEqual('auth,auth-int', digest['qop'])

+        self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])

+        self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+

+    def testParseWWWAuthenticateMultiple3(self):

+        # Handle an added comma between challenges, which might get thrown in if the challenges were

+        # originally sent in separate www-authenticate headers.

+        res = httplib2._parse_www_authenticate({ 'www-authenticate':

+                'Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})

+        digest = res['digest']

+        self.assertEqual('testrealm@host.com', digest['realm'])

+        self.assertEqual('auth,auth-int', digest['qop'])

+        self.assertEqual('dcd98b7102dd2f0e8b11d0f600bfb0c093', digest['nonce'])

+        self.assertEqual('5ccc069c403ebaf9f0171e9517f40e41', digest['opaque'])

+        basic = res['basic']

+        self.assertEqual('me', basic['realm'])

+        wsse = res['wsse']

+        self.assertEqual('foo', wsse['realm'])

+        self.assertEqual('UsernameToken', wsse['profile'])

+

+    def testParseWWWAuthenticateMultiple4(self):

+        res = httplib2._parse_www_authenticate({ 'www-authenticate':

+                'Digest realm="test-real.m@host.com", qop \t=\t"\tauth,auth-int", nonce="(*)&^&$%#",opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic REAlm="me", WSSE realm="foo", profile="UsernameToken"'})

+        digest = res['digest']

+        self.assertEqual('test-real.m@host.com', digest['realm'])

+        self.assertEqual('\tauth,auth-int', digest['qop'])

+        self.assertEqual('(*)&^&$%#', digest['nonce'])

+

+    def testParseWWWAuthenticateMoreQuoteCombos(self):

+        res = httplib2._parse_www_authenticate({'www-authenticate':'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'})

+        digest = res['digest']

+        self.assertEqual('myrealm', digest['realm'])

+

+    def testParseWWWAuthenticateMalformed(self):

+        try:

+          res = httplib2._parse_www_authenticate({'www-authenticate':'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'})

+          self.fail("should raise an exception")

+        except httplib2.MalformedHeader:

+          pass

+

+    def testDigestObject(self):

+        credentials = ('joe', 'password')

+        host = None

+        request_uri = '/projects/httplib2/test/digest/'

+        headers = {}

+        response = {

+            'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth"'

+        }

+        content = b""

+

+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)

+        d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")

+        our_request = "authorization: %s" % headers['authorization']

+        working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46"'

+        self.assertEqual(our_request, working_request)

+

+    def testDigestObjectWithOpaque(self):

+        credentials = ('joe', 'password')

+        host = None

+        request_uri = '/projects/httplib2/test/digest/'

+        headers = {}

+        response = {

+            'www-authenticate': 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", opaque="atestopaque"'

+        }

+        content = ""

+

+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)

+        d.request("GET", request_uri, headers, content, cnonce="33033375ec278a46")

+        our_request = "authorization: %s" % headers['authorization']

+        working_request = 'authorization: Digest username="joe", realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", uri="/projects/httplib2/test/digest/", algorithm=MD5, response="97ed129401f7cdc60e5db58a80f3ea8b", qop=auth, nc=00000001, cnonce="33033375ec278a46", opaque="atestopaque"'

+        self.assertEqual(our_request, working_request)

+

+    def testDigestObjectStale(self):

+        credentials = ('joe', 'password')

+        host = None

+        request_uri = '/projects/httplib2/test/digest/'

+        headers = {}

+        response = httplib2.Response({ })

+        response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'

+        response.status = 401

+        content = b""

+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)

+        # Returns true to force a retry

+        self.assertTrue( d.response(response, content) )

+

+    def testDigestObjectAuthInfo(self):

+        credentials = ('joe', 'password')

+        host = None

+        request_uri = '/projects/httplib2/test/digest/'

+        headers = {}

+        response = httplib2.Response({ })

+        response['www-authenticate'] = 'Digest realm="myrealm", nonce="Ygk86AsKBAA=3516200d37f9a3230352fde99977bd6d472d4306", algorithm=MD5, qop="auth", stale=true'

+        response['authentication-info'] = 'nextnonce="fred"'

+        content = b""

+        d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)

+        # Returns true to force a retry

+        self.assertFalse( d.response(response, content) )

+        self.assertEqual('fred', d.challenge['nonce'])

+        self.assertEqual(1, d.challenge['nc'])

+

+    def testWsseAlgorithm(self):

+        digest = httplib2._wsse_username_token("d36e316282959a9ed4c89851497a717f", "2003-12-15T14:43:07Z", "taadtaadpstcsm")

+        expected = b"quR/EWLAV4xLf9Zqyw4pDmfV9OY="

+        self.assertEqual(expected, digest)

+

+    def testEnd2End(self):

+        # one end to end header

+        response = {'content-type': 'application/atom+xml', 'te': 'deflate'}

+        end2end = httplib2._get_end2end_headers(response)

+        self.assertTrue('content-type' in end2end)

+        self.assertTrue('te' not in end2end)

+        self.assertTrue('connection' not in end2end)

+

+        # one end to end header that gets eliminated

+        response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}

+        end2end = httplib2._get_end2end_headers(response)

+        self.assertTrue('content-type' not in end2end)

+        self.assertTrue('te' not in end2end)

+        self.assertTrue('connection' not in end2end)

+

+        # Degenerate case of no headers

+        response = {}

+        end2end = httplib2._get_end2end_headers(response)

+        self.assertEqual(0, len(end2end))

+

+        # Degenerate case of connection referrring to a header not passed in

+        response = {'connection': 'content-type'}

+        end2end = httplib2._get_end2end_headers(response)

+        self.assertEqual(0, len(end2end))

+

+

+class TestProxyInfo(unittest.TestCase):

+    def setUp(self):

+        self.orig_env = dict(os.environ)

+

+    def tearDown(self):

+        os.environ.clear()

+        os.environ.update(self.orig_env)

+

+    def test_from_url(self):

+        pi = httplib2.proxy_info_from_url('http://myproxy.example.com')

+        self.assertEqual(pi.proxy_host, 'myproxy.example.com')

+        self.assertEqual(pi.proxy_port, 80)

+        self.assertEqual(pi.proxy_user, None)

+

+    def test_from_url_ident(self):

+        pi = httplib2.proxy_info_from_url('http://zoidberg:fish@someproxy:99')

+        self.assertEqual(pi.proxy_host, 'someproxy')

+        self.assertEqual(pi.proxy_port, 99)

+        self.assertEqual(pi.proxy_user, 'zoidberg')

+        self.assertEqual(pi.proxy_pass, 'fish')

+

+    def test_from_env(self):

+        os.environ['http_proxy'] = 'http://myproxy.example.com:8080'

+        pi = httplib2.proxy_info_from_environment()

+        self.assertEqual(pi.proxy_host, 'myproxy.example.com')

+        self.assertEqual(pi.proxy_port, 8080)

+

+    def test_from_env_no_proxy(self):

+        os.environ['http_proxy'] = 'http://myproxy.example.com:80'

+        os.environ['https_proxy'] = 'http://myproxy.example.com:81'

+        pi = httplib2.proxy_info_from_environment('https')

+        self.assertEqual(pi.proxy_host, 'myproxy.example.com')

+        self.assertEqual(pi.proxy_port, 81)

+

+    def test_from_env_none(self):

+        os.environ.clear()

+        pi = httplib2.proxy_info_from_environment()

+        self.assertEqual(pi, None)

+

+    def test_proxy_headers(self):

+        headers = {'key0': 'val0', 'key1': 'val1'}

+        pi = httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_HTTP, 'localhost', 1234, proxy_headers = headers)

+        self.assertEqual(pi.proxy_headers, headers)

+

+    # regression: ensure that httplib2.HTTPConnectionWithTimeout initializes when proxy_info is not supplied

+    def test_proxy_init(self):

+        connection = httplib2.HTTPConnectionWithTimeout('www.google.com', 80)

+        connection.request('GET', '/')

+        connection.close()

+

+if __name__ == '__main__':

+    unittest.main()

diff --git a/ref.tex b/ref.tex
new file mode 100755
index 0000000..8093e3b
--- /dev/null
+++ b/ref.tex
@@ -0,0 +1,91 @@
+% Complete documentation on the extended LaTeX markup used for Python
+% documentation is available in ``Documenting Python'', which is part
+% of the standard documentation for Python.  It may be found online
+% at:
+%
+%     http://www.python.org/doc/current/doc/doc.html
+
+\documentclass{manual}
+
+\title{The httplib2 Library}
+
+\author{Joe Gregorio}
+
+% Please at least include a long-lived email address;
+% the rest is at your discretion.
+\authoraddress{
+%   Organization name, if applicable \\
+%   Street address, if you want to use it \\
+    Email: \email{joe@bitworking.org}
+}
+
+\date{Mar 8, 2007}       % update before release!
+
+\release{0.3}     % release version; this is used to define the
+                  % \version macro
+
+\makeindex          % tell \index to actually write the .idx file
+\makemodindex       % If this contains a lot of module sections.
+
+
+\begin{document}
+
+\maketitle
+
+% This makes the contents more accessible from the front page of the HTML.
+%\ifhtml
+%\chapter*{Front Matter\label{front}}
+%\fi
+
+%\input{copyright}
+
+\begin{abstract}
+\noindent
+
+The \module{httplib2} module is a comprehensive HTTP client library
+that handles caching, keep-alive, compression, redirects and
+many kinds of authentication.
+
+
+\end{abstract}
+
+\tableofcontents
+
+\chapter{Reference}
+
+\input{libhttplib2.tex}
+
+%\appendix
+%\chapter{...}
+
+%My appendix.
+
+%The \code{\e appendix} markup need not be repeated for additional
+%appendices.
+
+
+
+
+
+
+
+
+%
+%  The ugly "%begin{latexonly}" pseudo-environments are really just to
+%  keep LaTeX2HTML quiet during the \renewcommand{} macros; they're
+%  not really valuable.
+%
+%  If you don't want the Module Index, you can remove all of this up
+%  until the second \input line.
+%
+%begin{latexonly}
+\renewcommand{\indexname}{Module Index}
+%end{latexonly}
+\input{mod\jobname.ind}     % Module Index
+
+%begin{latexonly}
+\renewcommand{\indexname}{Index}
+%end{latexonly}
+\input{\jobname.ind}        % Index
+
+\end{document}
diff --git a/ref/about.html b/ref/about.html
new file mode 100755
index 0000000..b452de2
--- /dev/null
+++ b/ref/about.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="node2.html" />
+<link rel="parent" href="ref.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>About this document ...</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.4 Examples"
+  href="httplib2-example.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="The httplib2 Library"
+  href="ref.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="httplib2-example.html">1.1.4 Examples</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="ref.html">The httplib2 Library</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<h1><a name="SECTION003000000000000000000">
+About this document ...</a>
+</h1>
+ <strong>The httplib2 Library</strong>,
+Mar 8, 2007, Release 0.3
+<p> This document was generated using the <a
+    href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
+    <strong>LaTeX</strong>2<tt>HTML</tt></a> translator.
+</p>
+
+<p> <a
+    href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
+    <strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright &copy;
+  1993, 1994, 1995, 1996, 1997, <a
+    href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos
+    Drakos</a>, Computer Based Learning Unit, University of
+  Leeds, and Copyright &copy; 1997, 1998, <a
+    href="http://www.maths.mq.edu.au/~ross/">Ross
+    Moore</a>, Mathematics Department, Macquarie University,
+  Sydney.
+</p>
+
+<p> The application of <a
+    href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/">
+    <strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python
+  documentation has been heavily tailored by Fred L. Drake,
+  Jr.  Original navigation icons were contributed by Christopher
+  Petrilli.
+</p>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.4 Examples"
+  href="httplib2-example.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="The httplib2 Library"
+  href="ref.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="httplib2-example.html">1.1.4 Examples</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="ref.html">The httplib2 Library</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/blank.png b/ref/blank.png
new file mode 100755
index 0000000..2af5639
--- /dev/null
+++ b/ref/blank.png
Binary files differ
diff --git a/ref/cache-objects.html b/ref/cache-objects.html
new file mode 100644
index 0000000..9baa7c2
--- /dev/null
+++ b/ref/cache-objects.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="response-objects.html" />
+<link rel="prev" href="http-objects.html" />
+<link rel="parent" href="module-httplib2.html" />
+<link rel="next" href="response-objects.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>1.1.2 Cache Objects</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.1 http Objects"
+  href="http-objects.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.3 response Objects"
+  href="response-objects.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="http-objects.html">1.1.1 Http Objects</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="response-objects.html">1.1.3 Response Objects</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<h2><a name="SECTION002120000000000000000"></a>
+<a name="cache-objects"></a>
+<br>
+1.1.2 Cache Objects
+</h2>
+
+<p>
+If you wish to supply your own caching implementation
+then you will need to pass in an object that supports the
+following methods. Note that the <tt class="module">memcache</tt> module
+supports this interface natively.
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-23' xml:id='l2h-23' class="method">get</tt></b>(</nobr></td>
+  <td><var>key</var>)</td></tr></table></dt>
+<dd>
+Takes a string <var>key</var> and returns the value as a string.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-24' xml:id='l2h-24' class="method">set</tt></b>(</nobr></td>
+  <td><var>key, value</var>)</td></tr></table></dt>
+<dd>
+Takes a string <var>key</var> and <var>value</var> and stores it in the cache.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-25' xml:id='l2h-25' class="method">delete</tt></b>(</nobr></td>
+  <td><var>key</var>)</td></tr></table></dt>
+<dd>
+Deletes the cached value stored at <var>key</var>. The value
+of <var>key</var> is a string.
+</dl>
+
+<p>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.1 http Objects"
+  href="http-objects.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.3 response Objects"
+  href="response-objects.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="http-objects.html">1.1.1 Http Objects</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="response-objects.html">1.1.3 Response Objects</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/contents.html b/ref/contents.html
new file mode 100755
index 0000000..cfee565
--- /dev/null
+++ b/ref/contents.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="node2.html" />
+<link rel="prev" href="ref.html" />
+<link rel="parent" href="ref.html" />
+<link rel="next" href="node2.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>Contents</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="The httplib2 Library"
+  href="ref.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="The httplib2 Library"
+  href="ref.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1. Reference"
+  href="node2.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="ref.html">The httplib2 Library</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="ref.html">The httplib2 Library</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node2.html">1. Reference</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+<br><h2><a name="SECTION001000000000000000000">
+Contents</a>
+</h2>
+<!--Table of Contents-->
+
+<ul class="TofC">
+<li><a href="node2.html">1. Reference</a>
+<ul>
+<li><a href="module-httplib2.html">1.1 httplib2 A comprehensive HTTP client library.</a>
+<ul>
+<li><a href="http-objects.html">1.1.1 Http Objects</a>
+<li><a href="cache-objects.html">1.1.2 Cache Objects</a>
+<li><a href="response-objects.html">1.1.3 Response Objects</a>
+<li><a href="httplib2-example.html">1.1.4 Examples</a>
+</ul></ul></ul>
+<!--End of Table of Contents-->
+<p>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="The httplib2 Library"
+  href="ref.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="The httplib2 Library"
+  href="ref.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1. Reference"
+  href="node2.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="ref.html">The httplib2 Library</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="ref.html">The httplib2 Library</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="node2.html">1. Reference</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/contents.png b/ref/contents.png
new file mode 100755
index 0000000..3429be0
--- /dev/null
+++ b/ref/contents.png
Binary files differ
diff --git a/ref/http-objects.html b/ref/http-objects.html
new file mode 100644
index 0000000..603e52a
--- /dev/null
+++ b/ref/http-objects.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="cache-objects.html" />
+<link rel="prev" href="module-httplib2.html" />
+<link rel="parent" href="module-httplib2.html" />
+<link rel="next" href="cache-objects.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>1.1.1 Http Objects</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.2 cache Objects"
+  href="cache-objects.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="cache-objects.html">1.1.2 Cache Objects</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<h2><a name="SECTION002110000000000000000"></a>
+<a name="http-objects"></a>
+<br>
+1.1.1 Http Objects
+</h2>
+
+<p>
+Http objects have the following methods:
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-15' xml:id='l2h-15' class="method">request</tt></b>(</nobr></td>
+  <td><var>uri, </var><big>[</big><var>method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Performs a single HTTP request.
+The <var>uri</var> is the URI of the HTTP resource and can begin with either <code>http</code> or <code>https</code>. The value of <var>uri</var> must be an absolute URI.
+
+<p>
+The <var>method</var> is the HTTP method to perform, such as <code>GET</code>, <code>POST</code>, <code>DELETE</code>, etc. There is no restriction
+on the methods allowed.
+
+<p>
+The <var>body</var> is the entity body to be sent with the request. It is a string
+object.
+
+<p>
+Any extra headers that are to be sent with the request should be provided in the
+<var>headers</var> dictionary.
+
+<p>
+The maximum number of redirect to follow before raising an exception is <var>redirections</var>. The default is 5.
+
+<p>
+The <var>connection_type</var> is the type of connection object to use. The supplied class
+should implement the interface of httplib.HTTPConnection.
+
+<p>
+The return value is a tuple of (response, content), the first being and instance of the
+<tt class="class">Response</tt> class, the second being a string that contains the response entity body.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-16' xml:id='l2h-16' class="method">add_credentials</tt></b>(</nobr></td>
+  <td><var>name, password, </var><big>[</big><var>domain=None</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+Adds a name and password that will be used when a request
+requires authentication. Supplying the optional <var>domain</var> name will
+restrict these credentials to only be sent to the specified
+domain. If <var>domain</var> is not specified then the given credentials will
+be used to try to satisfy every HTTP 401 challenge.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-17' xml:id='l2h-17' class="method">add_certificate</tt></b>(</nobr></td>
+  <td><var>key, cert, domain</var>)</td></tr></table></dt>
+<dd>
+Add a <var>key</var> and <var>cert</var> that will be used for an SSL connection
+to the specified domain. <var>keyfile</var> is the name of a PEM formatted
+file that contains your private key. <var>certfile</var> is a PEM formatted certificate chain file.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><tt id='l2h-18' xml:id='l2h-18' class="method">clear_credentials</tt></b>(</nobr></td>
+  <td><var></var>)</td></tr></table></dt>
+<dd>
+Remove all the names and passwords used for authentication.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-19' xml:id='l2h-19' class="member">follow_redirects</tt></b></dt>
+<dd>
+If <code>True</code>, which is the default, safe redirects are followed, where
+safe means that the client is only doing a <code>GET</code> or <code>HEAD</code> on the
+URI to which it is being redirected. If <code>False</code> then no redirects are followed.
+Note that a False 'follow_redirects' takes precedence over a True 'follow_all_redirects'.
+Another way of saying that is for 'follow_all_redirects' to have any affect, 'follow_redirects'
+must be True.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-20' xml:id='l2h-20' class="member">follow_all_redirects</tt></b></dt>
+<dd>
+If <code>False</code>, which is the default, only safe redirects are followed, where
+safe means that the client is only doing a <code>GET</code> or <code>HEAD</code> on the
+URI to which it is being redirected. If <code>True</code> then all redirects are followed.
+Note that a False 'follow_redirects' takes precedence over a True 'follow_all_redirects'.
+Another way of saying that is for 'follow_all_redirects' to have any affect, 'follow_redirects'
+must be True.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-21' xml:id='l2h-21' class="member">force_exception_to_status_code</tt></b></dt>
+<dd>
+If <code>True</code>, which is the default, then no <tt class="module">httplib2</tt> exceptions will be thrown. Instead,
+those error conditions will be turned into <tt class="class">Response</tt> objects
+that will be returned normally.
+
+<p>
+If <code>False</code>, then exceptions will be thrown.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-22' xml:id='l2h-22' class="member">ignore_etag</tt></b></dt>
+<dd>
+Defaults to <code>False</code>. If <code>True</code>, then any etags present in the cached response
+are ignored when processing the current request, i.e. httplib2 does <strong>not</strong> use
+'if-match' for PUT or 'if-none-match' when GET or HEAD requests are made. This
+is mainly to deal with broken servers which supply an etag, but change it capriciously.
+</dl>
+
+<p>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.2 cache Objects"
+  href="cache-objects.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="cache-objects.html">1.1.2 Cache Objects</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/httplib2-example.html b/ref/httplib2-example.html
new file mode 100644
index 0000000..6607efe
--- /dev/null
+++ b/ref/httplib2-example.html
@@ -0,0 +1,188 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="response-objects.html" />
+<link rel="parent" href="module-httplib2.html" />
+<link rel="next" href="about.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>1.1.4 Examples </title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.3 response Objects"
+  href="response-objects.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="About this document ..."
+  href="about.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="response-objects.html">1.1.3 Response Objects</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="about.html">About this document ...</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<h2><a name="SECTION002140000000000000000"></a><a name="httplib2-example"></a>
+<br>
+1.1.4 Examples
+</h2>
+
+<p>
+To do a simple <code>GET</code> request just supply the absolute URI
+of the resource:
+
+<p>
+<div class="verbatim"><pre>
+import httplib2
+h = httplib2.Http()
+resp, content = h.request("http://bitworking.org/")
+assert resp.status == 200
+assert resp['content-type'] == 'text/html'
+</pre></div>
+
+<p>
+Here is more complex example that does a PUT
+of some text to a resource that requires authentication.
+The Http instance also uses a file cache
+in the directory <code>.cache</code>.
+
+<p>
+<div class="verbatim"><pre>
+import httplib2
+h = httplib2.Http(".cache")
+h.add_credentials('name', 'password')
+resp, content = h.request("https://example.org/chap/2",
+    "PUT", body="This is text",
+    headers={'content-type':'text/plain'} )
+</pre></div>
+
+<p>
+Here is an example that connects to a server that
+supports the Atom Publishing Protocol.
+
+<p>
+<div class="verbatim"><pre>
+import httplib2
+h = httplib2.Http()
+h.add_credentials(myname, mypasswd)
+h.follow_all_redirects = True
+headers = {'Content-Type': 'application/atom+xml'}
+body    = """&lt;?xml version="1.0" ?&gt;
+    &lt;entry xmlns="http://www.w3.org/2005/Atom"&gt;
+      &lt;title&gt;Atom-Powered Robots Run Amok&lt;/title&gt;
+      &lt;id&gt;urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a&lt;/id&gt;
+      &lt;updated&gt;2003-12-13T18:30:02Z&lt;/updated&gt;
+      &lt;author&gt;&lt;name&gt;John Doe&lt;/name&gt;&lt;/author&gt;
+      &lt;content&gt;Some text.&lt;/content&gt;
+&lt;/entry&gt;
+"""
+uri     = "http://www.example.com/collection/"
+resp, content = h.request(uri, "POST", body=body, headers=headers)
+</pre></div>
+
+<p>
+Here is an example of providing data to an HTML form processor.
+In this case we presume this is a POST form. We need to take our
+data and format it as "application/x-www-form-urlencoded" data and use that as a
+body for a POST request.
+
+<p>
+<div class="verbatim"><pre>
+&gt;&gt;&gt; import httplib2
+&gt;&gt;&gt; import urllib
+&gt;&gt;&gt; data = {'name': 'fred', 'address': '123 shady lane'}
+&gt;&gt;&gt; body = urllib.urlencode(data)
+&gt;&gt;&gt; body
+'name=fred&amp;address=123+shady+lane'
+&gt;&gt;&gt; h = httplib2.Http()
+&gt;&gt;&gt; resp, content = h.request("http://example.com", method="POST", body=body)
+</pre></div>
+
+<p>
+Here is an example of using a proxy server:
+<div class="verbatim"><pre>
+import httplib2
+import socks
+
+httplib2.debuglevel=4
+h = httplib2.Http(proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP, 'localhost', 8000))
+r,c = h.request("http://bitworking.org/news/")
+</pre></div>
+
+<p>
+
+<p>
+<IMG
+ WIDTH="556" HEIGHT="20" ALIGN="BOTTOM" BORDER="0"
+ SRC="img1.png"
+ ALT="\begin{center}\vbox{\input{modref.ind}
+}\end{center}">
+<p>
+
+<p>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.3 response Objects"
+  href="response-objects.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="About this document ..."
+  href="about.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="response-objects.html">1.1.3 Response Objects</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="about.html">About this document ...</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/images.idx b/ref/images.idx
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/ref/images.idx
diff --git a/ref/img1.old b/ref/img1.old
new file mode 100755
index 0000000..c9ce471
--- /dev/null
+++ b/ref/img1.old
Binary files differ
diff --git a/ref/img1.png b/ref/img1.png
new file mode 100755
index 0000000..c9ce471
--- /dev/null
+++ b/ref/img1.png
Binary files differ
diff --git a/ref/img2.old b/ref/img2.old
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/ref/img2.old
diff --git a/ref/img2.png b/ref/img2.png
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/ref/img2.png
diff --git a/ref/index.html b/ref/index.html
new file mode 100644
index 0000000..839d65e
--- /dev/null
+++ b/ref/index.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="contents.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>The httplib2 Library</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Contents"
+  href="contents.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="contents.html">Contents</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<p>
+
+<div class="titlepage">
+<div class='center'>
+<h1>The httplib2 Library</h1>
+<p><b><font size="+2">Joe Gregorio</font></b></p>
+<p>
+Email: <span class="email">joe@bitworking.org</span>
+</p>
+<p><strong>Release 0.3</strong><br />
+<strong>Mar 8, 2007</strong></p>
+<p></p>
+</div>
+</div>
+
+<p>
+
+<h3>Abstract:</h3>
+<div class="ABSTRACT">
+
+<p>
+The <tt class="module">httplib2</tt> module is a comprehensive HTTP client library
+that handles caching, keep-alive, compression, redirects and
+many kinds of authentication.
+
+<p>
+</div>
+<p>
+
+<p>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<a name="CHILD_LINKS"></a>
+
+<ul class="ChildLinks">
+<li><a href="contents.html">Contents</a>
+<li><a href="node2.html">1. Reference</a>
+<ul>
+<li><a href="module-httplib2.html">1.1 <tt class="module">httplib2</tt>
+A comprehensive HTTP client library.</a>
+<ul>
+<li><a href="http-objects.html">1.1.1 Http Objects</a>
+<li><a href="cache-objects.html">1.1.2 Cache Objects</a>
+<li><a href="response-objects.html">1.1.3 Response Objects</a>
+<li><a href="httplib2-example.html">1.1.4 Examples</a>
+</ul>
+</ul>
+<li><a href="about.html">About this document ...</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Contents"
+  href="contents.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="contents.html">Contents</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/index.png b/ref/index.png
new file mode 100755
index 0000000..cd918af
--- /dev/null
+++ b/ref/index.png
Binary files differ
diff --git a/ref/modimages.idx b/ref/modimages.idx
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/ref/modimages.idx
diff --git a/ref/module-httplib2.html b/ref/module-httplib2.html
new file mode 100644
index 0000000..155592b
--- /dev/null
+++ b/ref/module-httplib2.html
@@ -0,0 +1,280 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="prev" href="node2.html" />
+<link rel="parent" href="node2.html" />
+<link rel="next" href="http-objects.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>1.1 httplib2 A comprehensive HTTP client library. </title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1. Reference"
+  href="node2.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1. Reference"
+  href="node2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.1 http Objects"
+  href="http-objects.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node2.html">1. Reference</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node2.html">1. Reference</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="http-objects.html">1.1.1 Http Objects</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<h1><a name="SECTION002100000000000000000">
+1.1 <tt class="module">httplib2</tt>
+         A comprehensive HTTP client library.  </a>
+</h1>
+
+<p>
+<a name="module-httplib2"></a>
+<p>
+
+<p>
+
+<p>
+The <tt class="module">httplib2</tt> module is a comprehensive HTTP client library with the following features:
+
+<p>
+<dl>
+<dt><strong>HTTP and HTTPS</strong></dt>
+<dd>HTTPS support is only available if the socket module was compiled with SSL support.
+</dd>
+<dt><strong>Keep-Alive</strong></dt>
+<dd>Supports HTTP 1.1 Keep-Alive, keeping the socket open and performing multiple requests over the same connection if possible.
+</dd>
+<dt><strong>Authentication</strong></dt>
+<dd>The following three types of HTTP Authentication are supported. These can be used over both HTTP and HTTPS.
+
+<ul>
+<li>Digest
+</li>
+<li>Basic
+</li>
+<li>WSSE
+
+</li>
+</ul>
+</dd>
+<dt><strong>Caching</strong></dt>
+<dd>The module can optionally operate with a private cache that understands the Cache-Control: header and uses both the ETag and Last-Modified cache validators.
+</dd>
+<dt><strong>All Methods</strong></dt>
+<dd>The module can handle any HTTP request method, not just GET and POST.
+</dd>
+<dt><strong>Redirects</strong></dt>
+<dd>Automatically follows 3XX redirects on GETs.
+</dd>
+<dt><strong>Compression</strong></dt>
+<dd>Handles both 'deflate' and 'gzip' types of compression.
+</dd>
+<dt><strong>Proxies</strong></dt>
+<dd>If the Socksipy module is installed then httplib2 can handle sock4, sock5 and http proxies.
+</dd>
+<dt><strong>Lost update support</strong></dt>
+<dd>Automatically adds back ETags into PUT requests to resources we have already cached. This implements Section 3.2 of Detecting the Lost Update Problem Using Unreserved Checkout
+</dd>
+</dl>
+
+<p>
+The <tt class="module">httplib2</tt> module defines the following variables:
+
+<p>
+<dl><dt><b><tt id='l2h-2' xml:id='l2h-2'>debuglevel</tt></b></dt>
+<dd>
+The amount of debugging information to print. The default is 0.
+</dd></dl>
+
+<p>
+The <tt class="module">httplib2</tt> module may raise the following Exceptions. Note that
+there is an option that turns exceptions into
+normal responses with an HTTP status code indicating
+an error occured. See <tt class="member">Http.force_exception_to_status_code</tt>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-3' xml:id='l2h-3' class="exception">HttpLib2Error</tt></b></dt>
+<dd>
+The Base Exception for all exceptions raised by httplib2.
+</dd></dl>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-4' xml:id='l2h-4' class="exception">RedirectMissingLocation</tt></b></dt>
+<dd>
+A 3xx redirect response code was provided but no Location: header
+was provided to point to the new location.
+</dd></dl>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-5' xml:id='l2h-5' class="exception">RedirectLimit</tt></b></dt>
+<dd>
+The maximum number of redirections was reached without coming to a final URI.
+</dd></dl>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-6' xml:id='l2h-6' class="exception">ServerNotFoundError</tt></b></dt>
+<dd>
+Unable to resolve the host name given.
+</dd></dl>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-7' xml:id='l2h-7' class="exception">RelativeURIError</tt></b></dt>
+<dd>
+A relative, as opposed to an absolute URI, was passed into request().
+</dd></dl>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-8' xml:id='l2h-8' class="exception">FailedToDecompressContent</tt></b></dt>
+<dd>
+The headers claimed that the content of the response was compressed but the
+decompression algorithm applied to the content failed.
+</dd></dl>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-9' xml:id='l2h-9' class="exception">UnimplementedDigestAuthOptionError</tt></b></dt>
+<dd>
+The server requested a type of Digest authentication that we
+are unfamiliar with.
+</dd></dl>
+
+<p>
+<dl><dt><b><span class="typelabel">exception</span>&nbsp;<tt id='l2h-10' xml:id='l2h-10' class="exception">UnimplementedHmacDigestAuthOptionError</tt></b></dt>
+<dd>
+The server requested a type of HMACDigest authentication that we
+are unfamiliar with.
+</dd></dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><span class="typelabel">class</span>&nbsp;<tt id='l2h-11' xml:id='l2h-11' class="class">Http</tt></b>(</nobr></td>
+  <td><var></var><big>[</big><var>cache=None</var><big>]</big><var>, </var><big>[</big><var>timeout=None</var><big>]</big><var>, </var><big>[</big><var>proxy_info=None</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+The class that represents a client HTTP interface.
+The <var>cache</var> parameter is either the name of a directory
+to be used as a flat file cache, or it must an object that
+implements the required caching interface.
+The <var>timeout</var> parameter is the socket level timeout.
+The <var>proxy_info</var> is an instance of <tt class="class">ProxyInfo</tt> and is supplied
+if a proxy is to be used. Note that the Socksipy module must be
+installed for proxy support to work.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><span class="typelabel">class</span>&nbsp;<tt id='l2h-12' xml:id='l2h-12' class="class">Response</tt></b>(</nobr></td>
+  <td><var>info</var>)</td></tr></table></dt>
+<dd>
+Response is a subclass of <tt class="class">dict</tt> and instances of this
+class are returned from calls
+to Http.request. The <var>info</var> parameter is either
+an <tt class="class">rfc822.Message</tt> or an <tt class="class">httplib.HTTPResponse</tt> object.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><span class="typelabel">class</span>&nbsp;<tt id='l2h-13' xml:id='l2h-13' class="class">FileCache</tt></b>(</nobr></td>
+  <td><var>dir_name, </var><big>[</big><var>safe=safename</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+FileCache implements a Cache as a directory of files.
+The <var>dir_name</var> parameter is
+the name of the directory to use. If the directory does
+not exist then FileCache attempts to create the directory.
+The optional <var>safe</var> parameter is a funtion which generates
+the cache filename for each URI. A FileCache object is
+constructed and used for caching when you pass a directory name
+into the constructor of <tt class="class">Http</tt>.
+</dl>
+
+<p>
+<dl><dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">
+  <td><nobr><b><span class="typelabel">class</span>&nbsp;<tt id='l2h-14' xml:id='l2h-14' class="class">ProxyInfo</tt></b>(</nobr></td>
+  <td><var>proxy_type, proxy_host, proxy_port, </var><big>[</big><var>proxy_rdns=None</var><big>]</big><var>, </var><big>[</big><var>proxy_user=None</var><big>]</big><var>, </var><big>[</big><var>proxy_pass=None</var><big>]</big><var></var>)</td></tr></table></dt>
+<dd>
+The parameter <var>proxy_type</var> must be set to one of socks.PROXY_TYPE_XXX
+constants. The <var>proxy_host</var> and <var>proxy_port</var> must be set to the location
+of the proxy. The optional <var>proxy_rdns</var> should be set to True if
+the DNS server on the proxy should be used. The <var>proxy_user</var> and
+<var>proxy_pass</var> are supplied when the proxy is protected by authentication.
+</dl>
+
+<p>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<a name="CHILD_LINKS"><strong>Subsections</strong></a>
+
+<ul class="ChildLinks">
+<li><a href="http-objects.html">1.1.1 Http Objects</a>
+<li><a href="cache-objects.html">1.1.2 Cache Objects</a>
+<li><a href="response-objects.html">1.1.3 Response Objects</a>
+<li><a href="httplib2-example.html">1.1.4 Examples</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1. Reference"
+  href="node2.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1. Reference"
+  href="node2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.1 http Objects"
+  href="http-objects.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="node2.html">1. Reference</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="node2.html">1. Reference</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="http-objects.html">1.1.1 Http Objects</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/modules.png b/ref/modules.png
new file mode 100755
index 0000000..8fa8b75
--- /dev/null
+++ b/ref/modules.png
Binary files differ
diff --git a/ref/next.png b/ref/next.png
new file mode 100755
index 0000000..cfe5e51
--- /dev/null
+++ b/ref/next.png
Binary files differ
diff --git a/ref/node2.html b/ref/node2.html
new file mode 100644
index 0000000..408be41
--- /dev/null
+++ b/ref/node2.html
@@ -0,0 +1,115 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="about.html" />
+<link rel="prev" href="contents.html" />
+<link rel="parent" href="ref.html" />
+<link rel="next" href="module-httplib2.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>1. Reference</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Contents"
+  href="contents.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="The httplib2 Library"
+  href="ref.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="contents.html">Contents</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="ref.html">The httplib2 Library</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<h1><a name="SECTION002000000000000000000">
+1. Reference</a>
+</h1>
+
+<p>
+
+<p>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<a name="CHILD_LINKS"><strong>Subsections</strong></a>
+
+<ul class="ChildLinks">
+<li><a href="module-httplib2.html">1.1 <tt class="module">httplib2</tt>
+A comprehensive HTTP client library.</a>
+<ul>
+<li><a href="http-objects.html">1.1.1 Http Objects</a>
+<li><a href="cache-objects.html">1.1.2 Cache Objects</a>
+<li><a href="response-objects.html">1.1.3 Response Objects</a>
+<li><a href="httplib2-example.html">1.1.4 Examples</a>
+</ul></ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="Contents"
+  href="contents.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="The httplib2 Library"
+  href="ref.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="contents.html">Contents</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="ref.html">The httplib2 Library</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/previous.png b/ref/previous.png
new file mode 100755
index 0000000..497def4
--- /dev/null
+++ b/ref/previous.png
Binary files differ
diff --git a/ref/pyfav.png b/ref/pyfav.png
new file mode 100755
index 0000000..d2d8669
--- /dev/null
+++ b/ref/pyfav.png
Binary files differ
diff --git a/ref/ref.css b/ref/ref.css
new file mode 100755
index 0000000..06a613c
--- /dev/null
+++ b/ref/ref.css
@@ -0,0 +1,243 @@
+/*
+ * The first part of this is the standard CSS generated by LaTeX2HTML,
+ * with the "empty" declarations removed.
+ */
+
+/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */
+.math                   { font-family: "Century Schoolbook", serif; }
+.math i                 { font-family: "Century Schoolbook", serif;
+                          font-weight: bold }
+.boldmath               { font-family: "Century Schoolbook", serif;
+                          font-weight: bold }
+
+/*
+ * Implement both fixed-size and relative sizes.
+ *
+ * I think these can be safely removed, as it doesn't appear that
+ * LaTeX2HTML ever generates these, even though these are carried
+ * over from the LaTeX2HTML stylesheet.
+ */
+small.xtiny             { font-size : xx-small; }
+small.tiny              { font-size : x-small; }
+small.scriptsize        { font-size : smaller; }
+small.footnotesize      { font-size : small; }
+big.xlarge              { font-size : large; }
+big.xxlarge             { font-size : x-large; }
+big.huge                { font-size : larger; }
+big.xhuge               { font-size : xx-large; }
+
+/*
+ * Document-specific styles come next;
+ * these are added for the Python documentation.
+ *
+ * Note that the size specifications for the H* elements are because
+ * Netscape on Solaris otherwise doesn't get it right; they all end up
+ * the normal text size.
+ */
+
+body                    { color: #000000;
+                          background-color: #ffffff; }
+
+a:link:active           { color: #ff0000; }
+a:link:hover            { background-color: #bbeeff; }
+a:visited:hover         { background-color: #bbeeff; }
+a:visited               { color: #551a8b; }
+a:link                  { color: #0000bb; }
+
+h1, h2, h3, h4, h5, h6  { font-family: avantgarde, sans-serif;
+                          font-weight: bold; }
+h1                      { font-size: 180%; }
+h2                      { font-size: 150%; }
+h3, h4                  { font-size: 120%; }
+
+/* These are section titles used in navigation links, so make sure we
+ * match the section header font here, even it not the weight.
+ */
+.sectref                { font-family: avantgarde, sans-serif; }
+/* And the label before the titles in navigation: */
+.navlabel               { font-size: 85%; }
+
+
+/* LaTeX2HTML insists on inserting <br> elements into headers which
+ * are marked with \label.  This little bit of CSS magic ensures that
+ * these elements don't cause spurious whitespace to be added.
+ */
+h1>br, h2>br, h3>br,
+h4>br, h5>br, h6>br     { display: none; }
+
+code, tt                { font-family: "lucida typewriter", lucidatypewriter,
+                                       monospace; }
+var                     { font-family: times, serif;
+                          font-style: italic;
+                          font-weight: normal; }
+
+.Unix                   { font-variant: small-caps; }
+
+.typelabel              { font-family: lucida, sans-serif; }
+
+.navigation td          { background-color: #99ccff;
+                          font-weight: bold;
+                          font-family: avantgarde, sans-serif;
+                          font-size: 110%; }
+
+div.warning             { background-color: #fffaf0;
+                          border: thin solid black;
+                          padding: 1em;
+                          margin-left: 2em;
+                          margin-right: 2em; }
+
+div.warning .label      { font-family: sans-serif;
+                          font-size: 110%;
+                          margin-right: 0.5em; }
+
+div.note                { background-color: #fffaf0;
+                          border: thin solid black;
+                          padding: 1em;
+                          margin-left: 2em;
+                          margin-right: 2em; }
+
+div.note .label         { margin-right: 0.5em;
+                          font-family: sans-serif; }
+
+address                 { font-size: 80%; }
+.release-info           { font-style: italic;
+                          font-size: 80%; }
+
+.titlegraphic           { vertical-align: top; }
+
+.verbatim pre           { color: #00008b;
+                          font-family: "lucida typewriter", lucidatypewriter,
+                                       monospace;
+                          font-size: 90%; }
+.verbatim               { margin-left: 2em; }
+.verbatim .footer       { padding: 0.05in;
+                          font-size: 85%;
+                          background-color: #99ccff;
+                          margin-right: 0.5in; }
+
+.grammar                { background-color: #99ccff;
+                          margin-right: 0.5in;
+                          padding: 0.05in; }
+.grammar-footer         { padding: 0.05in;
+                          font-size: 85%; }
+.grammartoken           { font-family: "lucida typewriter", lucidatypewriter,
+                                       monospace; }
+
+.productions                  { background-color: #bbeeff; }
+.productions a:active         { color: #ff0000; }
+.productions a:link:hover     { background-color: #99ccff; }
+.productions a:visited:hover  { background-color: #99ccff; }
+.productions a:visited        { color: #551a8b; }
+.productions a:link           { color: #0000bb; }
+.productions table            { vertical-align: baseline;
+                                empty-cells: show; }
+.productions > table td,
+.productions > table th       { padding: 2px; }
+.productions > table td:first-child,
+.productions > table td:last-child {
+                                font-family: "lucida typewriter",
+                                             lucidatypewriter,
+                                             monospace;
+                                }
+/* same as the second selector above, but expressed differently for Opera */
+.productions > table td:first-child + td + td {
+                                font-family: "lucida typewriter",
+                                             lucidatypewriter,
+                                             monospace;
+                                vertical-align: baseline;
+                                }
+.productions > table td:first-child + td {
+                                padding-left: 1em;
+                                padding-right: 1em;
+                                }
+.productions > table tr       { vertical-align: baseline; }
+
+.email                  { font-family: avantgarde, sans-serif; }
+.mailheader             { font-family: avantgarde, sans-serif; }
+.mimetype               { font-family: avantgarde, sans-serif; }
+.newsgroup              { font-family: avantgarde, sans-serif; }
+.url                    { font-family: avantgarde, sans-serif; }
+.file                   { font-family: avantgarde, sans-serif; }
+.guilabel               { font-family: avantgarde, sans-serif; }
+
+.realtable              { border-collapse: collapse;
+                          border-color: black;
+                          border-style: solid;
+                          border-width: 0px 0px 2px 0px;
+                          empty-cells: show;
+                          margin-left: auto;
+                          margin-right: auto;
+                          padding-left: 0.4em;
+                          padding-right: 0.4em;
+                          }
+.realtable tbody        { vertical-align: baseline; }
+.realtable tfoot        { display: table-footer-group; }
+.realtable thead        { background-color: #99ccff;
+                          border-width: 0px 0px 2px 1px;
+                          display: table-header-group;
+                          font-family: avantgarde, sans-serif;
+                          font-weight: bold;
+                          vertical-align: baseline;
+                          }
+.realtable thead :first-child {
+                          border-width: 0px 0px 2px 0px;
+                          }
+.realtable thead th     { border-width: 0px 0px 2px 1px }
+.realtable td,
+.realtable th           { border-color: black;
+                          border-style: solid;
+                          border-width: 0px 0px 1px 1px;
+                          padding-left: 0.4em;
+                          padding-right: 0.4em;
+                          }
+.realtable td:first-child,
+.realtable th:first-child {
+                          border-left-width: 0px;
+                          vertical-align: baseline;
+                          }
+.center                 { text-align: center; }
+.left                   { text-align: left; }
+.right                  { text-align: right; }
+
+.refcount-info          { font-style: italic; }
+.refcount-info .value   { font-weight: bold;
+                          color: #006600; }
+
+/*
+ * Some decoration for the "See also:" blocks, in part inspired by some of
+ * the styling on Lars Marius Garshol's XSA pages.
+ * (The blue in the navigation bars is #99CCFF.)
+ */
+.seealso                { background-color: #fffaf0;
+                          border: thin solid black;
+                          padding: 0pt 1em 4pt 1em; }
+
+.seealso > .heading     { font-size: 110%;
+                          font-weight: bold; }
+
+/*
+ * Class 'availability' is used for module availability statements at
+ * the top of modules.
+ */
+.availability .platform { font-weight: bold; }
+
+
+/*
+ * Additional styles for the distutils package.
+ */
+.du-command             { font-family: monospace; }
+.du-option              { font-family: avantgarde, sans-serif; }
+.du-filevar             { font-family: avantgarde, sans-serif;
+                          font-style: italic; }
+.du-xxx:before          { content: "** ";
+                          font-weight: bold; }
+.du-xxx:after           { content: " **";
+                          font-weight: bold; }
+
+
+/*
+ * Some specialization for printed output.
+ */
+@media print {
+  .online-navigation    { display: none; }
+  }
diff --git a/ref/ref.html b/ref/ref.html
new file mode 100644
index 0000000..839d65e
--- /dev/null
+++ b/ref/ref.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="contents.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>The httplib2 Library</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Contents"
+  href="contents.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="contents.html">Contents</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<p>
+
+<div class="titlepage">
+<div class='center'>
+<h1>The httplib2 Library</h1>
+<p><b><font size="+2">Joe Gregorio</font></b></p>
+<p>
+Email: <span class="email">joe@bitworking.org</span>
+</p>
+<p><strong>Release 0.3</strong><br />
+<strong>Mar 8, 2007</strong></p>
+<p></p>
+</div>
+</div>
+
+<p>
+
+<h3>Abstract:</h3>
+<div class="ABSTRACT">
+
+<p>
+The <tt class="module">httplib2</tt> module is a comprehensive HTTP client library
+that handles caching, keep-alive, compression, redirects and
+many kinds of authentication.
+
+<p>
+</div>
+<p>
+
+<p>
+
+<p><br /></p><hr class='online-navigation' />
+<div class='online-navigation'>
+<!--Table of Child-Links-->
+<a name="CHILD_LINKS"></a>
+
+<ul class="ChildLinks">
+<li><a href="contents.html">Contents</a>
+<li><a href="node2.html">1. Reference</a>
+<ul>
+<li><a href="module-httplib2.html">1.1 <tt class="module">httplib2</tt>
+A comprehensive HTTP client library.</a>
+<ul>
+<li><a href="http-objects.html">1.1.1 Http Objects</a>
+<li><a href="cache-objects.html">1.1.2 Cache Objects</a>
+<li><a href="response-objects.html">1.1.3 Response Objects</a>
+<li><a href="httplib2-example.html">1.1.4 Examples</a>
+</ul>
+</ul>
+<li><a href="about.html">About this document ...</a>
+</ul>
+<!--End of Table of Child-Links-->
+</div>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></td>
+<td class='online-navigation'><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></td>
+<td class='online-navigation'><a rel="next" title="Contents"
+  href="contents.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="contents.html">Contents</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/response-objects.html b/ref/response-objects.html
new file mode 100644
index 0000000..74b79f5
--- /dev/null
+++ b/ref/response-objects.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<link rel="STYLESHEET" href="ref.css" type='text/css' />
+<link rel="first" href="ref.html" title='The httplib2 Library' />
+<link rel='contents' href='contents.html' title="Contents" />
+<link rel='last' href='about.html' title='About this document...' />
+<link rel='help' href='about.html' title='About this document...' />
+<link rel="next" href="httplib2-example.html" />
+<link rel="prev" href="cache-objects.html" />
+<link rel="parent" href="module-httplib2.html" />
+<link rel="next" href="httplib2-example.html" />
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name='aesop' content='information' />
+<title>1.1.3 Response Objects</title>
+</head>
+<body>
+<div class="navigation">
+<div id='top-navigation-panel' xml:id='top-navigation-panel'>
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.2 cache Objects"
+  href="cache-objects.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.4 Examples"
+  href="httplib2-example.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="cache-objects.html">1.1.2 Cache Objects</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="httplib2-example.html">1.1.4 Examples</a>
+</div>
+<hr /></div>
+</div>
+<!--End of Navigation Panel-->
+
+<h2><a name="SECTION002130000000000000000"></a>
+<a name="response-objects"></a>
+<br>
+1.1.3 Response Objects
+</h2>
+
+<p>
+Response objects are derived from <tt class="class">dict</tt> and map
+header names (lower case with the trailing colon removed)
+to header values. In addition to the dict methods
+a Response object also has:
+
+<p>
+<dl><dt><b><tt id='l2h-26' xml:id='l2h-26' class="member">fromcache</tt></b></dt>
+<dd>
+If <code>true</code> the the response was returned from the cache.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-27' xml:id='l2h-27' class="member">version</tt></b></dt>
+<dd>
+The version of HTTP that the server supports. A value
+of 11 means '1.1'.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-28' xml:id='l2h-28' class="member">status</tt></b></dt>
+<dd>
+The numerical HTTP status code returned in the response.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-29' xml:id='l2h-29' class="member">reason</tt></b></dt>
+<dd>
+The human readable component of the HTTP response status code.
+</dl>
+
+<p>
+<dl><dt><b><tt id='l2h-30' xml:id='l2h-30' class="member">previous</tt></b></dt>
+<dd>
+If redirects are followed then the <tt class="class">Response</tt> object returned
+is just for the very last HTTP request and <var>previous</var> points to
+the previous <tt class="class">Response</tt> object. In this manner they form a chain
+going back through the responses to the very first response.
+Will be <code>None</code> if there are no previous respones.
+</dl>
+
+<p>
+The Response object also populates the header <code>content-location</code>, that
+contains the URI that was ultimately requested. This is useful if
+redirects were encountered, you can determine the ultimate URI that
+the request was sent to. All Response objects contain this key value,
+including <code>previous</code> responses so you can determine the entire
+chain of redirects. If <tt class="member">Http.force_exception_to_status_code</tt> is <code>True</code>
+and the number of redirects has exceeded the number of allowed number
+of redirects then the <tt class="class">Response</tt> object will report the error
+in the status code, but the complete chain of previous responses will
+still be in tact.
+
+<p>
+
+<div class="navigation">
+<div class='online-navigation'>
+<p></p><hr />
+<table align="center" width="100%" cellpadding="0" cellspacing="2">
+<tr>
+<td class='online-navigation'><a rel="prev" title="1.1.2 cache Objects"
+  href="cache-objects.html"><img src='previous.png'
+  border='0' height='32'  alt='Previous Page' width='32' /></a></td>
+<td class='online-navigation'><a rel="parent" title="1.1 httplib2 A comprehensive"
+  href="module-httplib2.html"><img src='up.png'
+  border='0' height='32'  alt='Up one Level' width='32' /></a></td>
+<td class='online-navigation'><a rel="next" title="1.1.4 Examples"
+  href="httplib2-example.html"><img src='next.png'
+  border='0' height='32'  alt='Next Page' width='32' /></a></td>
+<td align="center" width="100%">The httplib2 Library</td>
+<td class='online-navigation'><a rel="contents" title="Table of Contents"
+  href="contents.html"><img src='contents.png'
+  border='0' height='32'  alt='Contents' width='32' /></a></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+<td class='online-navigation'><img src='blank.png'
+  border='0' height='32'  alt='' width='32' /></td>
+</tr></table>
+<div class='online-navigation'>
+<b class="navlabel">Previous:</b>
+<a class="sectref" rel="prev" href="cache-objects.html">1.1.2 Cache Objects</a>
+<b class="navlabel">Up:</b>
+<a class="sectref" rel="parent" href="module-httplib2.html">1.1 httplib2 A comprehensive</a>
+<b class="navlabel">Next:</b>
+<a class="sectref" rel="next" href="httplib2-example.html">1.1.4 Examples</a>
+</div>
+</div>
+<hr />
+<span class="release-info">Release 0.3, documentation updated on Mar 8, 2007.</span>
+</div>
+<!--End of Navigation Panel-->
+
+</body>
+</html>
diff --git a/ref/up.png b/ref/up.png
new file mode 100755
index 0000000..a90e028
--- /dev/null
+++ b/ref/up.png
Binary files differ
diff --git a/requirements-test.txt b/requirements-test.txt
new file mode 100644
index 0000000..674a214
--- /dev/null
+++ b/requirements-test.txt
@@ -0,0 +1,9 @@
+flake8==3.4.1
+mock==2.0.0
+pytest-cov==2.5.1
+pytest-forked==0.2
+pytest-randomly==1.2.1
+pytest-timeout==1.2.0
+pytest-xdist==1.20.0
+pytest==3.2.1
+six==1.10.0
diff --git a/script/release b/script/release
new file mode 100755
index 0000000..556fc84
--- /dev/null
+++ b/script/release
@@ -0,0 +1,244 @@
+#!/bin/bash
+set -eu
+cd "$( dirname "${BASH_SOURCE[0]}" )/.."
+
+version=
+version_next=
+
+main() {
+	local opt_auto=0
+	while [[ $# -gt 0 ]] ; do
+		case $1 in
+		-auto)
+			opt_auto=1
+			;;
+		*)
+			echo "Usage: $0 [-auto]" >&2
+			exit 0
+			;;
+		esac
+		shift
+	done
+	if [[ "$opt_auto" -eq 1 ]] ; then
+		auto_prepare_release
+	else
+		interactive
+	fi
+}
+
+auto_prepare_release() {
+	echo 'script/release: auto mode for CI, will check or modify version based on tag' >&2
+
+	assert_tree_clean
+
+	local is_tag=0
+	local version_tag=
+	if version_tag=$(git describe --candidates=0 --tags HEAD 2>/dev/null) ; then
+		is_tag=1
+		version_tag=${version_tag##v}
+		version_check "$version_tag"
+	fi
+
+	local last_tag=
+	local version_replace=
+	if [[ "$is_tag" -eq 0 ]] ; then
+		last_tag=$(git tag --sort=-version:refname |head -n1)
+		last_tag=${last_tag##v}
+		version_replace="${last_tag}.post$(date -u +%y%m%d%H%M)"
+		update_version "setup.py" "s/VERSION =.+/VERSION = '$version_replace'/"
+		update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_replace'/"
+		update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_replace'/"
+		version_check "$version_replace"
+	fi
+}
+
+interactive() {
+	echo 'script/release: interactive mode for creating new tagged releases with human assistance' >&2
+
+	local branch="${1-$(git symbolic-ref --short HEAD)}"
+	version="$(PYTHONPATH=$PWD/python3 python3 -c 'import httplib2; print(httplib2.__version__)')"
+	printf "\nbranch: %s httplib2.__version__: '%s'\n" $branch $version >&2
+
+	if [[ "$branch" != "master" ]] ; then
+		echo "Must be on master" >&2
+		exit 1
+	fi
+	assert_tree_clean
+
+	last_commit_message=$(git show --format="%s" --no-patch HEAD)
+	expect_commit_message="v$version release"
+	if [[ "$last_commit_message" != "$expect_commit_message" ]] ; then
+		printf "Last commit message: '%s' expected: '%s'\n" "$last_commit_message" "$expect_commit_message" >&2
+		if confirm "Create release commit? [yN] " ; then
+			create_commit
+		elif ! confirm "Continue without proper release commit? [yN] " ; then
+			exit 1
+		fi
+	fi
+	confirm "Continue? [yN] " || exit 1
+
+	echo "Creating tag v$version" >&2
+	if ! git tag "v$version" ; then
+		echo "git tag failed " >&2
+		confirm "Continue still? [yN] " || exit 1
+	fi
+
+    echo "Building package" >&2
+    find . -name '*.pyc' -o -name '*.pyo' -o -name '*.orig' -delete
+    rm -rf python{2,3}/.cache
+    rm -rf build dist
+    # TODO: sdist bdist_wheel
+    # but wheels don't roll well with our 2/3 split code base
+    local venv=./venv-release
+    if [[ ! -d "$venv" ]] ; then
+        virtualenv $venv
+        $venv/bin/pip install -U pip setuptools wheel twine
+    fi
+    $venv/bin/python setup.py sdist
+
+	if confirm "Upload to PyPI? Use in special situation, normally CI (Travis) will upload to PyPI. [yN] " ; then
+		$venv/bin/twine upload dist/* || exit 1
+	fi
+
+	git push --tags
+}
+
+create_commit() {
+	echo "" >&2
+	echo "Plan:" >&2
+	echo "1. bump version" >&2
+	echo "2. update CHANGELOG" >&2
+	echo "3. commit" >&2
+	echo "4. run bin/release again" >&2
+	echo "" >&2
+
+	bump_version
+	edit_news
+
+	git diff
+	confirm "Ready to commit? [Yn] " || exit 1
+	git commit -a -m "v$version_next release"
+
+	echo "Re-exec $0 to continue" >&2
+	exec $0
+}
+
+bump_version() {
+	local current=$version
+	echo "Current version: '$current'" >&2
+	echo -n "Enter next version (empty to abort): " >&2
+	read version_next
+	if [[ -z "$version_next" ]] ; then
+		exit 1
+	fi
+	echo "Next version:    '$version_next'" >&2
+
+	update_version "python3/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_next'/"
+	update_version "python2/httplib2/__init__.py" "s/__version__ =.+/__version__ = '$version_next'/"
+	update_version "setup.py" "s/VERSION =.+/VERSION = '$version_next'/"
+
+	confirm "Confirm changes? [yN] " || exit 1
+}
+
+update_version() {
+	local path="$1"
+	local sed_expr="$2"
+		# sed -E --in-place='' -e "s/VERSION =.+/VERSION = '$version_replace'/" setup.py
+		# sed -E --in-place='' -e "s/__version__ =.+/__version__ = '$version_replace'/" python2/httplib2/__init__.py python3/httplib2/__init__.py
+	echo "Updating file '$path'" >&2
+	if ! sed -E --in-place='' -e "$sed_expr" "$path" ; then
+		echo "sed error $?" >&2
+		exit 1
+	fi
+	assert_modified "$path"
+	echo "" >&2
+}
+
+edit_news() {
+	echo "Changes since last release:" >&2
+	git log --format='%h   %an   %s' "v$version"^.. -- || exit 1
+	echo "" >&2
+
+	patch -p1 <<EOT
+diff a/CHANGELOG b/CHANGELOG
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -0,0 +1,4 @@
++$version_next
++
++  EDIT HERE. Describe important changes and link to more information.
++
+EOT
+
+	local editor=$(which edit 2>/dev/null)
+	[[ -z "$editor" ]] && editor="$EDITOR"
+	if [[ -n "$editor" ]] ; then
+		if confirm "Open default editor for CHANGELOG? [Yn] " ; then
+			$editor CHANGELOG
+		else
+			confirm "Edit CHANGELOG manually and press any key"
+		fi
+	else
+		echo "Unable to determine default text editor." >&2
+		confirm "Edit CHANGELOG manually and press any key"
+	fi
+	echo "" >&2
+
+	assert_modified CHANGELOG
+
+	echo "" >&2
+	confirm "Confirm changes? [yN] " || exit 1
+}
+
+assert_modified() {
+	local path="$1"
+	if git diff --exit-code "$path" ; then
+		echo "File '$path' is not modified" >&2
+		exit 1
+	fi
+}
+
+assert_tree_clean() {
+	if [[ -n "$(git status --short -uall)" ]] ; then
+		echo "Tree must be clean. git status:" >&2
+		echo "" >&2
+		git status --short -uall
+		echo "" >&2
+		exit 1
+	fi
+}
+
+version_check() {
+	local need=$1
+	local version_setup=$(fgrep 'VERSION =' setup.py |tr -d " '" |cut -d\= -f2)
+	local version_py2=$(cd python2 ; python2 -Es -c 'import httplib2;print(httplib2.__version__)')
+	local version_py3=$(cd python3 ; python3 -Es -c 'import httplib2;print(httplib2.__version__)')
+	if [[ "$version_setup" != "$need" ]] ; then
+		echo "error: setup.py VERSION=$version_setup expected=$need" >&1
+		exit 1
+	fi
+	if [[ "$version_py2" != "$need" ]] ; then
+		echo "error: python2/httplib2/__init__.py:__version__=$version_py2 expected=$need" >&1
+		exit 1
+	fi
+	if [[ "$version_py3" != "$need" ]] ; then
+		echo "error: python3/httplib2/__init__.py:__version__=$version_py3 expected=$need" >&1
+		exit 1
+	fi
+}
+
+confirm() {
+	local reply
+	local prompt="$1"
+	read -n1 -p "$prompt" reply >&2
+	echo "" >&2
+	rc=0
+	local default_y=" \[Yn\] $"
+	if [[ -z "$reply" ]] && [[ "$prompt" =~ $default_y ]] ; then
+		reply="y"
+	fi
+	[[ "$reply" != "y" ]] && rc=1
+	return $rc
+}
+
+main "$@"
diff --git a/script/test b/script/test
new file mode 100755
index 0000000..a3dca92
--- /dev/null
+++ b/script/test
@@ -0,0 +1,76 @@
+#!/bin/bash
+set -eux
+# By default, run tests with pytest-forked plugin,
+# disable in terminal for debugging, you may add --forked
+flag_forked="--forked"
+if [[ -z "${CONTINUOUS_INTEGRATION-}" ]] && [[ -t 1 ]] ; then
+	flag_forked=""
+fi
+test_flags=(
+	$@
+	$flag_forked
+	tests/
+)
+
+main() {
+	cd "$( dirname "${BASH_SOURCE[0]}" )/.."
+	if [[ -n "${CONTINUOUS_INTEGRATION-}" ]] ; then
+		case "${test_group-}" in
+		pep8)
+			if [[ "${TRAVIS_PYTHON_VERSION}" = "2.7" ]] ; then
+				flake8 python2/
+			else
+				flake8 python3/ tests/
+			fi
+			;;
+		package)
+			# TODO: sdist bdist_wheel
+			# but wheels don't roll well with our 2/3 split code base
+			python setup.py sdist
+			install_check_version "pip"
+			;;
+		*)
+			pip install -e .
+			httplib2_test_still_run_skipped=1 pytest --fulltrace -k test_303 $@ tests/ || true
+			httplib2_test_still_run_skipped=1 pytest --fulltrace -k test_head_301 $@ tests/ || true
+			pytest --fulltrace ${test_flags[@]}
+			;;
+		esac
+	else
+		if [[ ! -d ./venv-27 ]] ; then
+			virtualenv --python=python2.7 ./venv-27
+		fi
+		if [[ ! -d ./venv-36 ]] ; then
+			virtualenv --python=python3.6 ./venv-36
+		fi
+
+		./venv-27/bin/pip install -e . -r requirements-test.txt
+		./venv-27/bin/pytest ${test_flags[@]}
+		./venv-36/bin/pip install -e . -r requirements-test.txt
+		./venv-36/bin/pytest ${test_flags[@]}
+
+		# FIXME: too many errors
+		# ./venv-27/bin/flake8 python2/
+		# ./venv-36/bin/flake8 python3/ tests/
+
+		# TODO: sdist bdist_wheel
+		# but wheels don't roll well with our 2/3 split code base
+		./venv-36/bin/python setup.py sdist
+		install_check_version "./venv-27/bin/pip"
+		install_check_version "./venv-36/bin/pip"
+	fi
+	rm -rf ./_httplib2_test_cache
+}
+
+install_check_version() {
+	local pip="$1"
+	$pip install dist/httplib2*
+	version_source=$(cd python3 ; python3 -Es -c 'import httplib2;print(httplib2.__version__)')
+	version_installed=$($pip show httplib2 |fgrep Version |cut -d' ' -f2)
+	if [[ "$version_source" != "$version_installed" ]] ; then
+		echo "error: installed package version=$version_installed does not match source=$version_source" >&2
+		exit 1
+	fi
+}
+
+main "$@"
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..432d065
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,22 @@
+[coverage:run]
+omit = */test/*
+
+[flake8]
+exclude = *.egg*,.env,.git,.tox,_*,build*,dist*,venv*,python2/,python3/
+ignore = E261,W503
+max-line-length = 121
+
+[tool:pytest]
+minversion = 3.2
+addopts =
+  # --fulltrace
+  # -n auto
+  --cov-config=setup.cfg
+  --cov=httplib2
+  --noconftest
+  --showlocals
+  --strict
+  --tb=short
+  --timeout=17
+  --verbose
+  -ra
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..0f3a516
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,79 @@
+import setuptools
+import sys
+
+pkgdir = {'': 'python%s' % sys.version_info[0]}
+VERSION = '0.11.3'
+
+setuptools.setup(
+    name='httplib2',
+    version=VERSION,
+    author='Joe Gregorio',
+    author_email='joe@bitworking.org',
+    url='https://github.com/httplib2/httplib2',
+    description='A comprehensive HTTP client library.',
+    license='MIT',
+    long_description="""
+
+A comprehensive HTTP client library, ``httplib2`` supports many features left out of other HTTP libraries.
+
+**HTTP and HTTPS**
+  HTTPS support is only available if the socket module was compiled with SSL support.
+
+
+**Keep-Alive**
+  Supports HTTP 1.1 Keep-Alive, keeping the socket open and performing multiple requests over the same connection if possible.
+
+
+**Authentication**
+  The following three types of HTTP Authentication are supported. These can be used over both HTTP and HTTPS.
+
+  * Digest
+  * Basic
+  * WSSE
+
+**Caching**
+  The module can optionally operate with a private cache that understands the Cache-Control:
+  header and uses both the ETag and Last-Modified cache validators. Both file system
+  and memcached based caches are supported.
+
+
+**All Methods**
+  The module can handle any HTTP request method, not just GET and POST.
+
+
+**Redirects**
+  Automatically follows 3XX redirects on GETs.
+
+
+**Compression**
+  Handles both 'deflate' and 'gzip' types of compression.
+
+
+**Lost update support**
+  Automatically adds back ETags into PUT requests to resources we have already cached. This implements Section 3.2 of Detecting the Lost Update Problem Using Unreserved Checkout
+
+
+**Unit Tested**
+  A large and growing set of unit tests.
+""",
+    package_dir=pkgdir,
+    packages=['httplib2'],
+    package_data={'httplib2': ['*.txt']},
+    classifiers=(
+        'Development Status :: 4 - Beta',
+        'Environment :: Web Environment',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: MIT License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.3',
+        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
+        'Topic :: Internet :: WWW/HTTP',
+        'Topic :: Software Development :: Libraries',
+    ),
+)
diff --git a/test/.htaccess b/test/.htaccess
new file mode 100755
index 0000000..863f8e4
--- /dev/null
+++ b/test/.htaccess
@@ -0,0 +1,8 @@
+AddHandler cgi-script .asis
+Options +ExecCGI +Indexes
+ExpiresActive On
+ExpiresDefault "access plus 2 hours"
+<IfModule mod_security.c>
+SecFilterEngine Off
+SecFilterScanPOST off
+</IfModule>
diff --git a/test/300/final-destination.txt b/test/300/final-destination.txt
new file mode 100755
index 0000000..4ffba65
--- /dev/null
+++ b/test/300/final-destination.txt
@@ -0,0 +1 @@
+This is the final destination.
diff --git a/test/300/with-location-header.asis b/test/300/with-location-header.asis
new file mode 100755
index 0000000..8f2e9c2
--- /dev/null
+++ b/test/300/with-location-header.asis
@@ -0,0 +1,5 @@
+#!/usr/bin/tail --lines=+2
+Status: 300 Mutliple Choices
+Location: http://bitworking.org/projects/httplib2/test/300/final-destination.txt
+
+
diff --git a/test/300/without-location-header.asis b/test/300/without-location-header.asis
new file mode 100755
index 0000000..dae3055
--- /dev/null
+++ b/test/300/without-location-header.asis
@@ -0,0 +1,12 @@
+#!/usr/bin/tail --lines=+2
+Status: 300 Mutliple Choices
+Content-Type: text/html
+
+<html>
+  <body>
+     <ol>
+        <li><a href="http://example.com/">Choice A</a></li>
+        <li><a href="http://example.org">Choice B</a></li>
+     </ol>
+  </body>
+</html>
diff --git a/test/301/final-destination.txt b/test/301/final-destination.txt
new file mode 100755
index 0000000..4ffba65
--- /dev/null
+++ b/test/301/final-destination.txt
@@ -0,0 +1 @@
+This is the final destination.
diff --git a/test/301/onestep.asis b/test/301/onestep.asis
new file mode 100755
index 0000000..9d8be49
--- /dev/null
+++ b/test/301/onestep.asis
@@ -0,0 +1,15 @@
+#!/usr/bin/tail --lines=+2
+Status: 301 Now where did I leave that URL
+Location: http://bitworking.org/projects/httplib2/test/302/final-destination.txt
+Content-type: text/html
+
+<html>
+<head>
+<title>Lame excuses'R'us</title>
+</head>
+<body>
+<h1>Fred's exceptionally wonderful page has moved to
+<a href="http://example.com/foo/bar.html">Joe's</a> site.
+</h1>
+</body>
+</html>
diff --git a/test/302/.myhtaccess b/test/302/.myhtaccess
new file mode 100644
index 0000000..844154f
--- /dev/null
+++ b/test/302/.myhtaccess
@@ -0,0 +1 @@
+Redirect temp onestep final-destination.txt
diff --git a/test/302/final-destination.txt b/test/302/final-destination.txt
new file mode 100755
index 0000000..4ffba65
--- /dev/null
+++ b/test/302/final-destination.txt
@@ -0,0 +1 @@
+This is the final destination.
diff --git a/test/302/no-location.asis b/test/302/no-location.asis
new file mode 100755
index 0000000..8ffaac3
--- /dev/null
+++ b/test/302/no-location.asis
@@ -0,0 +1,7 @@
+#!/usr/bin/tail --lines=+2
+Content-Type: text/plain
+Status: 302 Found
+
+This is content.
+Note there is no Location header given.
+This should err.
diff --git a/test/302/onestep.asis b/test/302/onestep.asis
new file mode 100755
index 0000000..e5ef865
--- /dev/null
+++ b/test/302/onestep.asis
@@ -0,0 +1,15 @@
+#!/usr/bin/tail --lines=+2
+Status: 302 Now where did I leave that URL
+Location: http://bitworking.org/projects/httplib2/test/302/final-destination.txt
+Content-type: text/html
+
+<html>
+<head>
+<title>Lame excuses'R'us</title>
+</head>
+<body>
+<h1>Fred's exceptionally wonderful page has moved to
+<a href="http://example.com/foo/bar.html">Joe's</a> site.
+</h1>
+</body>
+</html>
diff --git a/test/302/twostep.asis b/test/302/twostep.asis
new file mode 100755
index 0000000..62daab5
--- /dev/null
+++ b/test/302/twostep.asis
@@ -0,0 +1,15 @@
+#!/usr/bin/tail --lines=+2
+Status: 302 Now where did I leave that URL
+Location: http://bitworking.org/projects/httplib2/test/302/onestep.asis
+Content-type: text/html
+
+<html>
+<head>
+<title>Lame excuses'R'us</title>
+</head>
+<body>
+<h1>Fred's exceptionally wonderful page has moved to
+<a href="http://example.com/foo/bar.html">Joe's</a> site.
+</h1>
+</body>
+</html>
diff --git a/test/303/303.cgi b/test/303/303.cgi
new file mode 100755
index 0000000..c6500b8
--- /dev/null
+++ b/test/303/303.cgi
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+import os
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+
+print "Status: 303 See Other"
+print "Location: http://bitworking.org/projects/httplib2/test/303/final-destination.txt"
+print "X-Method: %s" % os.environ['REQUEST_METHOD']
+print ""
+
+
diff --git a/test/303/final-destination.txt b/test/303/final-destination.txt
new file mode 100755
index 0000000..4ffba65
--- /dev/null
+++ b/test/303/final-destination.txt
@@ -0,0 +1 @@
+This is the final destination.
diff --git a/test/303/redirect-to-header-reflector.cgi b/test/303/redirect-to-header-reflector.cgi
new file mode 100644
index 0000000..e06b166
--- /dev/null
+++ b/test/303/redirect-to-header-reflector.cgi
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+import os
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+
+print "Status: 303 See Other"
+print "Location: http://bitworking.org/projects/httplib2/test/reflector/reflector.cgi"
+print "X-Method: %s" % os.environ['REQUEST_METHOD']
+print ""
+
+
diff --git a/test/303/redirect-to-reflector.cgi b/test/303/redirect-to-reflector.cgi
new file mode 100755
index 0000000..b42100a
--- /dev/null
+++ b/test/303/redirect-to-reflector.cgi
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+import os
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+
+print "Status: 303 See Other"
+print "Location: http://bitworking.org/projects/httplib2/test/methods/method_reflector.cgi"
+print "X-Method: %s" % os.environ['REQUEST_METHOD']
+print ""
+
+
diff --git a/test/304/end2end.cgi b/test/304/end2end.cgi
new file mode 100755
index 0000000..f158f66
--- /dev/null
+++ b/test/304/end2end.cgi
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+import os
+
+
+etag = os.environ.get("HTTP_IF_NONE_MATCH", None)
+if etag:
+    print "Status: 304 Not Modified"
+else:
+    print "Status: 200 Ok"
+    print 'ETag: "123456779"'
+    print "Content-Type: text/html"
+    print ""
+    print "<html></html>"
diff --git a/test/304/last-modified-only/.htaccess b/test/304/last-modified-only/.htaccess
new file mode 100755
index 0000000..7ec3ed9
--- /dev/null
+++ b/test/304/last-modified-only/.htaccess
@@ -0,0 +1 @@
+FileETag None
diff --git a/test/304/last-modified-only/last-modified-only.txt b/test/304/last-modified-only/last-modified-only.txt
new file mode 100755
index 0000000..baad073
--- /dev/null
+++ b/test/304/last-modified-only/last-modified-only.txt
@@ -0,0 +1 @@
+This file should automatically get an ETag from Apache.
diff --git a/test/304/test_etag.txt b/test/304/test_etag.txt
new file mode 100755
index 0000000..baad073
--- /dev/null
+++ b/test/304/test_etag.txt
@@ -0,0 +1 @@
+This file should automatically get an ETag from Apache.
diff --git a/test/307/final-destination.txt b/test/307/final-destination.txt
new file mode 100755
index 0000000..4ffba65
--- /dev/null
+++ b/test/307/final-destination.txt
@@ -0,0 +1 @@
+This is the final destination.
diff --git a/test/307/onestep.asis b/test/307/onestep.asis
new file mode 100755
index 0000000..eb53858
--- /dev/null
+++ b/test/307/onestep.asis
@@ -0,0 +1,15 @@
+#!/usr/bin/tail --lines=+2
+Status: 307 Temporary Redirect
+Location: http://bitworking.org/projects/httplib2/test/307/final-destination.txt
+Content-type: text/html
+
+<html>
+<head>
+<title>Lame excuses'R'us</title>
+</head>
+<body>
+<h1>Fred's exceptionally wonderful page has moved to
+<a href="http://example.com/foo/bar.html">Joe's</a> site.
+</h1>
+</body>
+</html>
diff --git a/test/410/410.asis b/test/410/410.asis
new file mode 100755
index 0000000..d3827d2
--- /dev/null
+++ b/test/410/410.asis
@@ -0,0 +1,12 @@
+#!/usr/bin/tail --lines=+2
+Status: 410 Gone
+Content-type: text/html
+
+<html>
+<head>
+<title>Gone</title>
+</head>
+<body>
+<h1>Don't request me again.</h1>
+</body>
+</html>
diff --git a/test/basic-nested/.htaccess b/test/basic-nested/.htaccess
new file mode 100755
index 0000000..32b5252
--- /dev/null
+++ b/test/basic-nested/.htaccess
@@ -0,0 +1,4 @@
+AuthUserFile /home/jcgregorio/webapps/bitworking/projects/httplib2/test/basic/passwdfile 
+AuthName "a realm with spaces"
+AuthType Basic
+require valid-user
diff --git a/test/basic-nested/file.txt b/test/basic-nested/file.txt
new file mode 100755
index 0000000..395b52f
--- /dev/null
+++ b/test/basic-nested/file.txt
@@ -0,0 +1,2 @@
+This is the content.
+
diff --git a/test/basic-nested/passwdfile b/test/basic-nested/passwdfile
new file mode 100755
index 0000000..7de4f23
--- /dev/null
+++ b/test/basic-nested/passwdfile
@@ -0,0 +1 @@
+joe:J5h11U4s90MWc
diff --git a/test/basic-nested/subdir/.htaccess b/test/basic-nested/subdir/.htaccess
new file mode 100755
index 0000000..1bb62ed
--- /dev/null
+++ b/test/basic-nested/subdir/.htaccess
@@ -0,0 +1,4 @@
+AuthUserFile /home/jcgregorio/webapps/bitworking/projects/httplib2/test/basic2/passwdfile 
+AuthName "justarealm"
+AuthType Basic
+require valid-user
diff --git a/test/basic-nested/subdir/file.txt b/test/basic-nested/subdir/file.txt
new file mode 100755
index 0000000..395b52f
--- /dev/null
+++ b/test/basic-nested/subdir/file.txt
@@ -0,0 +1,2 @@
+This is the content.
+
diff --git a/test/basic-nested/subdir/passwdfile b/test/basic-nested/subdir/passwdfile
new file mode 100755
index 0000000..2ddbadc
--- /dev/null
+++ b/test/basic-nested/subdir/passwdfile
@@ -0,0 +1 @@
+fred:TBd7idzkX/v6Q
diff --git a/test/basic/.htaccess b/test/basic/.htaccess
new file mode 100755
index 0000000..32b5252
--- /dev/null
+++ b/test/basic/.htaccess
@@ -0,0 +1,4 @@
+AuthUserFile /home/jcgregorio/webapps/bitworking/projects/httplib2/test/basic/passwdfile 
+AuthName "a realm with spaces"
+AuthType Basic
+require valid-user
diff --git a/test/basic/file.txt b/test/basic/file.txt
new file mode 100755
index 0000000..395b52f
--- /dev/null
+++ b/test/basic/file.txt
@@ -0,0 +1,2 @@
+This is the content.
+
diff --git a/test/basic/passwdfile b/test/basic/passwdfile
new file mode 100755
index 0000000..7de4f23
--- /dev/null
+++ b/test/basic/passwdfile
@@ -0,0 +1 @@
+joe:J5h11U4s90MWc
diff --git a/test/basic2/.htaccess b/test/basic2/.htaccess
new file mode 100755
index 0000000..1bb62ed
--- /dev/null
+++ b/test/basic2/.htaccess
@@ -0,0 +1,4 @@
+AuthUserFile /home/jcgregorio/webapps/bitworking/projects/httplib2/test/basic2/passwdfile 
+AuthName "justarealm"
+AuthType Basic
+require valid-user
diff --git a/test/basic2/file.txt b/test/basic2/file.txt
new file mode 100755
index 0000000..395b52f
--- /dev/null
+++ b/test/basic2/file.txt
@@ -0,0 +1,2 @@
+This is the content.
+
diff --git a/test/basic2/passwdfile b/test/basic2/passwdfile
new file mode 100755
index 0000000..2ddbadc
--- /dev/null
+++ b/test/basic2/passwdfile
@@ -0,0 +1 @@
+fred:TBd7idzkX/v6Q
diff --git a/test/conditional-updates/test.cgi b/test/conditional-updates/test.cgi
new file mode 100755
index 0000000..45b2131
--- /dev/null
+++ b/test/conditional-updates/test.cgi
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+import os
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+
+method = os.environ['REQUEST_METHOD']
+if "GET" == method:
+    if "123456789" == os.environ.get('HTTP_IF_NONE_MATCH', ''):
+        print "Status: 304 Not Modified"
+    else:
+        print "Status: 200 Ok"
+        print "ETag: 123456789"
+        print ""
+elif method in ["PUT", "PATCH", "DELETE"]:
+    if "123456789" == os.environ.get('HTTP_IF_MATCH', ''):
+        print "Status: 200 Ok"
+        print ""
+    else:
+        print "Status: 412 Precondition Failed"
+        print ""
+else:
+    print "Status: 405 Method Not Allowed"
+    print ""
+
+
+
diff --git a/test/deflate/deflated-content b/test/deflate/deflated-content
new file mode 100644
index 0000000..4a548b4
--- /dev/null
+++ b/test/deflate/deflated-content
Binary files differ
diff --git a/test/deflate/deflated-headers.txt b/test/deflate/deflated-headers.txt
new file mode 100755
index 0000000..54409ad
--- /dev/null
+++ b/test/deflate/deflated-headers.txt
@@ -0,0 +1,3 @@
+Content-type: text/plain
+Content-Encoding: deflate
+
diff --git a/test/deflate/deflated.asis b/test/deflate/deflated.asis
new file mode 100755
index 0000000..607286a
--- /dev/null
+++ b/test/deflate/deflated.asis
Binary files differ
diff --git a/test/deflate/failed-compression.asis b/test/deflate/failed-compression.asis
new file mode 100755
index 0000000..4256c2e
--- /dev/null
+++ b/test/deflate/failed-compression.asis
@@ -0,0 +1,6 @@
+#!/usr/bin/tail --lines=+2
+Content-Encoding: gzip
+Content-Type: text/plain
+Status: 200 Ok
+
+This is obviously not compressed.
diff --git a/test/digest-expire/.htaccess b/test/digest-expire/.htaccess
new file mode 100755
index 0000000..fb62e51
--- /dev/null
+++ b/test/digest-expire/.htaccess
@@ -0,0 +1,5 @@
+AuthType Digest
+AuthDigestNonceLifetime 1 
+AuthName "myrealm"
+AuthUserFile /home/jcgregorio/webapps/bitworking/projects/httplib2/test/digest/digestpw 
+Require valid-user
diff --git a/test/digest-expire/digestpw b/test/digest-expire/digestpw
new file mode 100755
index 0000000..fcdc74f
--- /dev/null
+++ b/test/digest-expire/digestpw
@@ -0,0 +1 @@
+joe:myrealm:079c7228d541e1b282713f4c146de5e7
diff --git a/test/digest-expire/file.txt b/test/digest-expire/file.txt
new file mode 100755
index 0000000..d39bb09
--- /dev/null
+++ b/test/digest-expire/file.txt
@@ -0,0 +1 @@
+This is spinal tap.
diff --git a/test/digest/.htaccess b/test/digest/.htaccess
new file mode 100755
index 0000000..a3cf9c8
--- /dev/null
+++ b/test/digest/.htaccess
@@ -0,0 +1,4 @@
+AuthType Digest
+AuthName "myrealm"
+AuthUserFile /home/jcgregorio/webapps/bitworking/projects/httplib2/test/digest/digestpw 
+Require valid-user
diff --git a/test/digest/digestpw b/test/digest/digestpw
new file mode 100755
index 0000000..fcdc74f
--- /dev/null
+++ b/test/digest/digestpw
@@ -0,0 +1 @@
+joe:myrealm:079c7228d541e1b282713f4c146de5e7
diff --git a/test/digest/file.txt b/test/digest/file.txt
new file mode 100755
index 0000000..d39bb09
--- /dev/null
+++ b/test/digest/file.txt
@@ -0,0 +1 @@
+This is spinal tap.
diff --git a/test/duplicate-headers/multilink.asis b/test/duplicate-headers/multilink.asis
new file mode 100755
index 0000000..b729035
--- /dev/null
+++ b/test/duplicate-headers/multilink.asis
@@ -0,0 +1,7 @@
+#!/usr/bin/tail --lines=+2
+Link: <http://bitworking.org>; rel="home"; title="BitWorking"
+Link: <http://bitworking.org/index.rss>; rel="feed"; title="BitWorking"
+Content-Type: text/plain
+Status: 200 Ok
+
+This is content
diff --git a/test/gzip/.htaccess b/test/gzip/.htaccess
new file mode 100755
index 0000000..fedf381
--- /dev/null
+++ b/test/gzip/.htaccess
@@ -0,0 +1 @@
+AddOutputFilterByType DEFLATE text/html text/plain
diff --git a/test/gzip/failed-compression.asis b/test/gzip/failed-compression.asis
new file mode 100755
index 0000000..4256c2e
--- /dev/null
+++ b/test/gzip/failed-compression.asis
@@ -0,0 +1,6 @@
+#!/usr/bin/tail --lines=+2
+Content-Encoding: gzip
+Content-Type: text/plain
+Status: 200 Ok
+
+This is obviously not compressed.
diff --git a/test/gzip/final-destination.txt b/test/gzip/final-destination.txt
new file mode 100755
index 0000000..4ffba65
--- /dev/null
+++ b/test/gzip/final-destination.txt
@@ -0,0 +1 @@
+This is the final destination.
diff --git a/test/gzip/post.cgi b/test/gzip/post.cgi
new file mode 100755
index 0000000..8a03727
--- /dev/null
+++ b/test/gzip/post.cgi
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+import zlib
+import os
+from StringIO import StringIO
+
+# Always returns a gzipped response body
+print "Status: 200 Ok"
+print ""
+
+print(zlib.compress('This is a compressed string'))
+
+
diff --git a/test/methods/method_reflector.cgi b/test/methods/method_reflector.cgi
new file mode 100755
index 0000000..ae55af8
--- /dev/null
+++ b/test/methods/method_reflector.cgi
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+import os
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+
+print "Status: 200 Ok"
+print "X-Method: %s" % os.environ['REQUEST_METHOD']
+print ""
+
+
diff --git a/test/no-store/no-store.asis b/test/no-store/no-store.asis
new file mode 100755
index 0000000..f376778
--- /dev/null
+++ b/test/no-store/no-store.asis
@@ -0,0 +1,9 @@
+#!/usr/bin/tail --lines=+2
+Status: 200 Ok
+Last-Modified: Fri, 30 Dec 2005 21:57:33 GMT
+Etag: "11c415a-8826-eb9c2d40"
+Cache-Control: max-age=7200, no-store
+Expires: Mon, 02 Jan 2006 04:06:44 GMT
+Content-Type: text/plain
+
+fred
diff --git a/test/reflector/reflector.cgi b/test/reflector/reflector.cgi
new file mode 100755
index 0000000..10c24a5
--- /dev/null
+++ b/test/reflector/reflector.cgi
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+import os
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+
+print "Status: 200 Ok"
+print "Content-type: text/plain"
+print 'ETag: "alsjflaksjfasj"'
+print ""
+print "\n".join(["%s=%s" % (key, value) for key, value in  os.environ.iteritems()])
+
+
diff --git a/test/test.asis b/test/test.asis
new file mode 100755
index 0000000..5cdf331
--- /dev/null
+++ b/test/test.asis
@@ -0,0 +1,15 @@
+#!/usr/bin/tail --lines=+2
+Status: 301 Now where did I leave that URL
+Location: http://example.com/foo/bar.html
+Content-type: text/html
+
+<html>
+<head>
+<title>Lame excuses'R'us</title>
+</head>
+<body>
+<h1>Fred's exceptionally wonderful page has moved to
+<a href="http://example.com/foo/bar.html">Joe's</a> site.
+</h1>
+</body>
+</html>
diff --git a/test/timeout/timeout.cgi b/test/timeout/timeout.cgi
new file mode 100755
index 0000000..07e15c0
--- /dev/null
+++ b/test/timeout/timeout.cgi
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+import os
+import time
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+time.sleep(3)
+
+print "Status: 200 Ok"
+print "Content-type: text/plain"
+print ""
+print "3 seconds later"
+
+
diff --git a/test/user-agent/test.cgi b/test/user-agent/test.cgi
new file mode 100755
index 0000000..a7b5454
--- /dev/null
+++ b/test/user-agent/test.cgi
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+import os
+
+# Always returns an empty response body
+# and adds in the X-Method: header with the
+# method that was sent to the CGI
+
+print "Status: 200 Ok"
+print "Content-Type: text/plain"
+print ""
+print os.environ.get('HTTP_USER_AGENT', '')
+
diff --git a/test/vary/accept-double.asis b/test/vary/accept-double.asis
new file mode 100755
index 0000000..a2fc2fb
--- /dev/null
+++ b/test/vary/accept-double.asis
@@ -0,0 +1,7 @@
+#!/usr/bin/tail --lines=+2
+Content-Type: text/plain
+Vary: Accept, Accept-Language
+Status: 200 OK
+
+We could've been some HTML.
+And Danish!
diff --git a/test/vary/accept.asis b/test/vary/accept.asis
new file mode 100755
index 0000000..559945f
--- /dev/null
+++ b/test/vary/accept.asis
@@ -0,0 +1,6 @@
+#!/usr/bin/tail --lines=+2
+Content-Type: text/plain
+Vary: Accept
+Status: 200 OK
+
+We could've been some HTML.
diff --git a/test/vary/no-vary.asis b/test/vary/no-vary.asis
new file mode 100755
index 0000000..46dc9a1
--- /dev/null
+++ b/test/vary/no-vary.asis
@@ -0,0 +1,5 @@
+#!/usr/bin/tail --lines=+2
+Content-Type: text/plain
+Status: 200 OK
+
+We could've been some HTML.
diff --git a/test/vary/unused-header.asis b/test/vary/unused-header.asis
new file mode 100755
index 0000000..2002f48
--- /dev/null
+++ b/test/vary/unused-header.asis
@@ -0,0 +1,6 @@
+#!/usr/bin/tail --lines=+2
+Content-Type: text/plain
+Vary: X-No-Such-Header
+Status: 200 OK
+
+I've never heard of a header called X-No-Such-Header.
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..1af0720
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,620 @@
+from __future__ import print_function
+
+import base64
+import contextlib
+import copy
+import email.utils
+import functools
+import gzip
+import hashlib
+import httplib2
+import os
+import random
+import re
+import shutil
+import six
+import socket
+import struct
+import threading
+import time
+import traceback
+import zlib
+from six.moves import http_client, queue
+
+
+@contextlib.contextmanager
+def assert_raises(exc_type):
+    def _name(t):
+        return getattr(t, '__name__', None) or str(t)
+
+    if not isinstance(exc_type, tuple):
+        exc_type = (exc_type,)
+    names = ', '.join(map(_name, exc_type))
+
+    try:
+        yield
+    except exc_type:
+        pass
+    else:
+        assert False, 'Expected exception(s) {0}'.format(names)
+
+
+class BufferedReader(object):
+    '''io.BufferedReader with \r\n support
+    '''
+    def __init__(self, sock):
+        self._buf = b''
+        self._end = False
+        self._newline = b'\r\n'
+        self._sock = sock
+        if isinstance(sock, bytes):
+            self._sock = None
+            self._buf = sock
+
+    def _fill(self, target=1, more=None, untilend=False):
+        if more:
+            target = len(self._buf) + more
+        while untilend or (len(self._buf) < target):
+            # crutch to enable HttpRequest.from_bytes
+            if self._sock is None:
+                chunk = b''
+            else:
+                chunk = self._sock.recv(8 << 10)
+            # print('!!! recv', chunk)
+            if not chunk:
+                self._end = True
+                if untilend:
+                    return
+                else:
+                    raise EOFError
+            self._buf += chunk
+
+    def peek(self, size):
+        self._fill(target=size)
+        return self._buf[:size]
+
+    def read(self, size):
+        self._fill(target=size)
+        chunk, self._buf = self._buf[:size], self._buf[size:]
+        return chunk
+
+    def readall(self):
+        self._fill(untilend=True)
+        chunk, self._buf = self._buf, b''
+        return chunk
+
+    def readline(self):
+        while True:
+            i = self._buf.find(self._newline)
+            if i >= 0:
+                break
+            self._fill(more=1)
+        inext = i + len(self._newline)
+        line, self._buf = self._buf[:inext], self._buf[inext:]
+        return line
+
+
+def parse_http_message(kind, buf):
+    if buf._end:
+        return None
+    try:
+        start_line = buf.readline()
+    except EOFError:
+        return None
+    msg = kind()
+    msg.raw = start_line
+    if kind is HttpRequest:
+        assert re.match(br'.+ HTTP/\d\.\d\r\n$', start_line), 'Start line does not look like HTTP request: ' + repr(start_line)
+        msg.method, msg.uri, msg.proto = start_line.rstrip().decode().split(' ', 2)
+        assert msg.proto.startswith('HTTP/'), repr(start_line)
+    elif kind is HttpResponse:
+        assert re.match(br'^HTTP/\d\.\d \d+ .+\r\n$', start_line), 'Start line does not look like HTTP response: ' + repr(start_line)
+        msg.proto, msg.status, msg.reason = start_line.rstrip().decode().split(' ', 2)
+        msg.status = int(msg.status)
+        assert msg.proto.startswith('HTTP/'), repr(start_line)
+    else:
+        raise Exception('Use HttpRequest or HttpResponse .from_{bytes,buffered}')
+    msg.version = msg.proto[5:]
+
+    while True:
+        line = buf.readline()
+        msg.raw += line
+        line = line.rstrip()
+        if not line:
+            break
+        t = line.decode().split(':', 1)
+        msg.headers[t[0].lower()] = t[1].lstrip()
+
+    content_length_string = msg.headers.get('content-length', '')
+    if content_length_string.isdigit():
+        content_length = int(content_length_string)
+        msg.body = msg.body_raw = buf.read(content_length)
+    elif msg.headers.get('transfer-encoding') == 'chunked':
+        raise NotImplemented
+    elif msg.version == '1.0':
+        msg.body = msg.body_raw = buf.readall()
+    else:
+        msg.body = msg.body_raw = b''
+
+    msg.raw += msg.body_raw
+    return msg
+
+
+class HttpMessage(object):
+    def __init__(self):
+        self.headers = {}
+
+    @classmethod
+    def from_bytes(cls, bs):
+        buf = BufferedReader(bs)
+        return parse_http_message(cls, buf)
+
+    @classmethod
+    def from_buffered(cls, buf):
+        return parse_http_message(cls, buf)
+
+    def __repr__(self):
+        return '{} {}'.format(self.__class__, repr(vars(self)))
+
+
+class HttpRequest(HttpMessage):
+    pass
+
+
+class HttpResponse(HttpMessage):
+    pass
+
+
+class MockResponse(six.BytesIO):
+    def __init__(self, body, **kwargs):
+        six.BytesIO.__init__(self, body)
+        self.headers = kwargs
+
+    def items(self):
+        return self.headers.items()
+
+    def iteritems(self):
+        return six.iteritems(self.headers)
+
+
+class MockHTTPConnection(object):
+    '''This class is just a mock of httplib.HTTPConnection used for testing
+    '''
+
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=None, proxy_info=None):
+        self.host = host
+        self.port = port
+        self.timeout = timeout
+        self.log = ''
+        self.sock = None
+
+    def set_debuglevel(self, level):
+        pass
+
+    def connect(self):
+        'Connect to a host on a given port.'
+        pass
+
+    def close(self):
+        pass
+
+    def request(self, method, request_uri, body, headers):
+        pass
+
+    def getresponse(self):
+        return MockResponse(b'the body', status='200')
+
+
+class MockHTTPBadStatusConnection(object):
+    '''Mock of httplib.HTTPConnection that raises BadStatusLine.
+    '''
+
+    num_calls = 0
+
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 strict=None, timeout=None, proxy_info=None):
+        self.host = host
+        self.port = port
+        self.timeout = timeout
+        self.log = ''
+        self.sock = None
+        MockHTTPBadStatusConnection.num_calls = 0
+
+    def set_debuglevel(self, level):
+        pass
+
+    def connect(self):
+        pass
+
+    def close(self):
+        pass
+
+    def request(self, method, request_uri, body, headers):
+        pass
+
+    def getresponse(self):
+        MockHTTPBadStatusConnection.num_calls += 1
+        raise http_client.BadStatusLine('')
+
+
+@contextlib.contextmanager
+def server_socket(fun, request_count=1, timeout=5):
+    gresult = [None]
+    gcounter = [0]
+
+    def tick(request):
+        gcounter[0] += 1
+        keep = True
+        keep &= gcounter[0] < request_count
+        keep &= request.headers.get('connection', '').lower() != 'close'
+        return keep
+
+    def server_socket_thread(srv):
+        try:
+            while gcounter[0] < request_count:
+                client, _ = srv.accept()
+                try:
+                    client.settimeout(timeout)
+                    fun(client, tick)
+                finally:
+                    try:
+                        client.shutdown(socket.SHUT_RDWR)
+                    except (IOError, socket.error):
+                        pass
+                    # FIXME: client.close() introduces connection reset by peer
+                    # at least in other/connection_close test
+                    # should not be a problem since socket would close upon garbage collection
+            if gcounter[0] > request_count:
+                gresult[0] = Exception('Request count expected={0} actual={1}'.format(request_count, gcounter[0]))
+        except Exception as e:
+            traceback.print_exc()
+            gresult[0] = e
+
+    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    server.bind(('localhost', 0))
+    try:
+        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    except socket.error as ex:
+        print('non critical error on SO_REUSEADDR', ex)
+    server.listen(10)
+    server.settimeout(timeout)
+    t = threading.Thread(target=server_socket_thread, args=(server,))
+    t.daemon = True
+    t.start()
+    yield u'http://{0}:{1}/'.format(*server.getsockname())
+    server.close()
+    t.join()
+    if gresult[0] is not None:
+        raise gresult[0]
+
+
+def server_yield(fun, **kwargs):
+    q = queue.Queue(1)
+    g = fun(q.get)
+
+    def server_yield_socket_handler(sock, tick):
+        buf = BufferedReader(sock)
+        i = 0
+        while True:
+            request = HttpRequest.from_buffered(buf)
+            if request is None:
+                break
+            i += 1
+            request.client_addr = sock.getsockname()
+            request.number = i
+            q.put(request)
+            response = six.next(g)
+            sock.sendall(response)
+            if not tick(request):
+                break
+
+    return server_socket(server_yield_socket_handler, **kwargs)
+
+
+def server_request(request_handler, **kwargs):
+    def server_request_socket_handler(sock, tick):
+        buf = BufferedReader(sock)
+        i = 0
+        while True:
+            request = HttpRequest.from_buffered(buf)
+            if request is None:
+                break
+            i += 1
+            request.client_addr = sock.getsockname()
+            request.number = i
+            response = request_handler(request=request)
+            sock.sendall(response)
+            if not tick(request):
+                break
+
+    return server_socket(server_request_socket_handler, **kwargs)
+
+
+def server_const_bytes(response_content, **kwargs):
+    return server_request(lambda request: response_content, **kwargs)
+
+
+_http_kwargs = (
+    'proto', 'status', 'headers', 'body', 'add_content_length', 'add_date', 'add_etag', 'undefined_body_length',
+)
+
+
+def http_response_bytes(proto='HTTP/1.1', status='200 OK', headers=None, body=b'',
+                        add_content_length=True, add_date=False, add_etag=False,
+                        undefined_body_length=False,
+                        **kwargs):
+    if undefined_body_length:
+        add_content_length = False
+    if headers is None:
+        headers = {}
+    if add_content_length:
+        headers.setdefault('content-length', str(len(body)))
+    if add_date:
+        headers.setdefault('date', email.utils.formatdate())
+    if add_etag:
+        headers.setdefault('etag', '"{0}"'.format(hashlib.md5(body).hexdigest()))
+    header_string = ''.join('{0}: {1}\r\n'.format(k, v) for k, v in headers.items())
+    if not undefined_body_length and proto != 'HTTP/1.0' and 'content-length' not in headers:
+        raise Exception('httplib2.tests.http_response_bytes: client could not figure response body length')
+    if str(status).isdigit():
+        status = '{} {}'.format(status, http_client.responses[status])
+    response = '{proto} {status}\r\n{headers}\r\n'.format(
+        proto=proto,
+        status=status,
+        headers=header_string,
+    ).encode() + body
+    return response
+
+
+def make_http_reflect(**kwargs):
+    assert 'body' not in kwargs, 'make_http_reflect will overwrite response body'
+
+    def fun(request):
+        kw = copy.deepcopy(kwargs)
+        kw['body'] = request.raw
+        response = http_response_bytes(**kw)
+        return response
+
+    return fun
+
+
+def server_route(routes, **kwargs):
+    response_404 = http_response_bytes(status='404 Not Found')
+    response_wildcard = routes.get('')
+
+    def handler(request):
+        target = routes.get(request.uri, response_wildcard) or response_404
+        if callable(target):
+            response = target(request=request)
+        else:
+            response = target
+        return response
+
+    return server_request(handler, **kwargs)
+
+
+def server_const_http(**kwargs):
+    response_kwargs = {
+        k: kwargs.pop(k) for k in dict(kwargs)
+        if k in _http_kwargs
+    }
+    response = http_response_bytes(**response_kwargs)
+    return server_const_bytes(response, **kwargs)
+
+
+def server_list_http(responses, **kwargs):
+    i = iter(responses)
+
+    def handler(request):
+        return next(i)
+
+    kwargs.setdefault('request_count', len(responses))
+    return server_request(handler, **kwargs)
+
+
+def server_reflect(**kwargs):
+    response_kwargs = {
+        k: kwargs.pop(k) for k in dict(kwargs)
+        if k in _http_kwargs
+    }
+    http_handler = make_http_reflect(**response_kwargs)
+    return server_request(http_handler, **kwargs)
+
+
+def http_parse_auth(s):
+    '''https://tools.ietf.org/html/rfc7235#section-2.1
+    '''
+    scheme, rest = s.split(' ', 1)
+    result = {}
+    while True:
+        m = httplib2.WWW_AUTH_RELAXED.search(rest)
+        if not m:
+            break
+        if len(m.groups()) == 3:
+            key, value, rest = m.groups()
+            result[key.lower()] = httplib2.UNQUOTE_PAIRS.sub(r'\1', value)
+    return result
+
+
+def store_request_response(out):
+    def wrapper(fun):
+        @functools.wraps(fun)
+        def wrapped(request, *a, **kw):
+            response_bytes = fun(request, *a, **kw)
+            if out is not None:
+                response = HttpResponse.from_bytes(response_bytes)
+                out.append((request, response))
+            return response_bytes
+        return wrapped
+    return wrapper
+
+
+def http_reflect_with_auth(allow_scheme, allow_credentials, out_renew_nonce=None, out_requests=None):
+    '''
+    allow_scheme - 'basic', 'digest', etc
+    allow_credentials - sequence of ('name', 'password')
+    out_renew_nonce - None | [function]
+        Way to return nonce renew function to caller.
+        Kind of `out` parameter in some programming languages.
+        Allows to keep same signature for all handler builder functions.
+    out_requests - None | []
+        If set to list, every parsed request will be appended here.
+    '''
+    glastnc = [None]
+    gnextnonce = [None]
+    gserver_nonce = [gen_digest_nonce(salt=b'n')]
+    realm = 'httplib2 test'
+    server_opaque = gen_digest_nonce(salt=b'o')
+
+    def renew_nonce():
+        if gnextnonce[0]:
+            assert False, 'previous nextnonce was not used, probably bug in test code'
+        gnextnonce[0] = gen_digest_nonce()
+        return gserver_nonce[0], gnextnonce[0]
+
+    if out_renew_nonce:
+        out_renew_nonce[0] = renew_nonce
+
+    def deny(**kwargs):
+        nonce_stale = kwargs.pop('nonce_stale', False)
+        if nonce_stale:
+            kwargs.setdefault('body', b'nonce stale')
+        if allow_scheme == 'basic':
+            authenticate = 'basic realm="{realm}"'.format(realm=realm)
+        elif allow_scheme == 'digest':
+            authenticate = (
+                'digest realm="{realm}", qop="auth"'
+                + ', nonce="{nonce}", opaque="{opaque}"'
+                + (', stale=true' if nonce_stale else '')
+            ).format(realm=realm, nonce=gserver_nonce[0], opaque=server_opaque)
+        else:
+            raise Exception('unknown allow_scheme={0}'.format(allow_scheme))
+        deny_headers = {'www-authenticate': authenticate}
+        kwargs.setdefault('status', 401)
+        # supplied headers may overwrite generated ones
+        deny_headers.update(kwargs.get('headers', {}))
+        kwargs['headers'] = deny_headers
+        kwargs.setdefault('body', b'HTTP authorization required')
+        return http_response_bytes(**kwargs)
+
+    @store_request_response(out_requests)
+    def http_reflect_with_auth_handler(request):
+        auth_header = request.headers.get('authorization', '')
+        if not auth_header:
+            return deny()
+        if ' ' not in auth_header:
+            return http_response_bytes(status=400, body=b'authorization header syntax error')
+        scheme, data = auth_header.split(' ', 1)
+        scheme = scheme.lower()
+        if scheme != allow_scheme:
+            return deny(body=b'must use different auth scheme')
+        if scheme == 'basic':
+            decoded = base64.b64decode(data).decode()
+            username, password = decoded.split(':', 1)
+            if (username, password) in allow_credentials:
+                return make_http_reflect()(request)
+            else:
+                return deny(body=b'supplied credentials are not allowed')
+        elif scheme == 'digest':
+            server_nonce_old = gserver_nonce[0]
+            nextnonce = gnextnonce[0]
+            if nextnonce:
+                # server decided to change nonce, in this case, guided by caller test code
+                gserver_nonce[0] = nextnonce
+                gnextnonce[0] = None
+            server_nonce_current = gserver_nonce[0]
+            auth_info = http_parse_auth(data)
+            client_cnonce = auth_info.get('cnonce', '')
+            client_nc = auth_info.get('nc', '')
+            client_nonce = auth_info.get('nonce', '')
+            client_opaque = auth_info.get('opaque', '')
+            client_qop = auth_info.get('qop', 'auth').strip('"')
+
+            # TODO: auth_info.get('algorithm', 'md5')
+            hasher = hashlib.md5
+
+            # TODO: client_qop auth-int
+            ha2 = hasher(':'.join((request.method, request.uri)).encode()).hexdigest()
+
+            if client_nonce != server_nonce_current:
+                if client_nonce == server_nonce_old:
+                    return deny(nonce_stale=True)
+                return deny(body=b'invalid nonce')
+            if not client_nc:
+                return deny(body=b'auth-info nc missing')
+            if client_opaque != server_opaque:
+                return deny(body='auth-info opaque mismatch expected={} actual={}'
+                            .format(server_opaque, client_opaque).encode())
+            for allow_username, allow_password in allow_credentials:
+                ha1 = hasher(':'.join((allow_username, realm, allow_password)).encode()).hexdigest()
+                allow_response = hasher(':'.join((
+                    ha1, client_nonce, client_nc, client_cnonce, client_qop, ha2,
+                )).encode()).hexdigest()
+                rspauth_ha2 = hasher(':{}'.format(request.uri).encode()).hexdigest()
+                rspauth = hasher(':'.join((
+                    ha1, client_nonce, client_nc, client_cnonce, client_qop, rspauth_ha2,
+                )).encode()).hexdigest()
+                if auth_info.get('response', '') == allow_response:
+                    # TODO: fix or remove doubtful comment
+                    # do we need to save nc only on success?
+                    glastnc[0] = client_nc
+                    allow_headers = {
+                        'authentication-info': ' '.join((
+                            'nextnonce="{}"'.format(nextnonce) if nextnonce else '',
+                            'qop={}'.format(client_qop),
+                            'rspauth="{}"'.format(rspauth),
+                            'cnonce="{}"'.format(client_cnonce),
+                            'nc={}'.format(client_nc),
+                        )).strip(),
+                    }
+                    return make_http_reflect(headers=allow_headers)(request)
+            return deny(body=b'supplied credentials are not allowed')
+        else:
+            return http_response_bytes(
+                status=400,
+                body='unknown authorization scheme={0}'.format(scheme).encode(),
+            )
+
+    return http_reflect_with_auth_handler
+
+
+def get_cache_path():
+    default = './_httplib2_test_cache'
+    path = os.environ.get('httplib2_test_cache_path') or default
+    if os.path.exists(path):
+        shutil.rmtree(path)
+    return path
+
+
+def gen_digest_nonce(salt=b''):
+    t = struct.pack('>Q', int(time.time() * 1e9))
+    return base64.b64encode(t + b':' + hashlib.sha1(t + salt).digest()).decode()
+
+
+def gen_password():
+    length = random.randint(8, 64)
+    return ''.join(six.unichr(random.randint(0, 127)) for _ in range(length))
+
+
+def gzip_compress(bs):
+    # gzipobj = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)
+    # result = gzipobj.compress(text) + gzipobj.flush()
+    buf = six.BytesIO()
+    gf = gzip.GzipFile(fileobj=buf, mode='wb', compresslevel=6)
+    gf.write(bs)
+    gf.close()
+    return buf.getvalue()
+
+
+def gzip_decompress(bs):
+    return zlib.decompress(bs, zlib.MAX_WBITS | 16)
+
+
+def deflate_compress(bs):
+    do = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS)
+    return do.compress(bs) + do.flush()
+
+
+def deflate_decompress(bs):
+    return zlib.decompress(bs, -zlib.MAX_WBITS)
diff --git a/tests/test_auth.py b/tests/test_auth.py
new file mode 100644
index 0000000..3768f2b
--- /dev/null
+++ b/tests/test_auth.py
@@ -0,0 +1,284 @@
+import httplib2
+import pytest
+import tests
+from six.moves import urllib
+
+
+def test_credentials():
+    c = httplib2.Credentials()
+    c.add('joe', 'password')
+    assert tuple(c.iter('bitworking.org'))[0] == ('joe', 'password')
+    assert tuple(c.iter(''))[0] == ('joe', 'password')
+    c.add('fred', 'password2', 'wellformedweb.org')
+    assert tuple(c.iter('bitworking.org'))[0] == ('joe', 'password')
+    assert len(tuple(c.iter('bitworking.org'))) == 1
+    assert len(tuple(c.iter('wellformedweb.org'))) == 2
+    assert ('fred', 'password2') in tuple(c.iter('wellformedweb.org'))
+    c.clear()
+    assert len(tuple(c.iter('bitworking.org'))) == 0
+    c.add('fred', 'password2', 'wellformedweb.org')
+    assert ('fred', 'password2') in tuple(c.iter('wellformedweb.org'))
+    assert len(tuple(c.iter('bitworking.org'))) == 0
+    assert len(tuple(c.iter(''))) == 0
+
+
+def test_basic():
+    # Test Basic Authentication
+    http = httplib2.Http()
+    password = tests.gen_password()
+    handler = tests.http_reflect_with_auth(allow_scheme='basic', allow_credentials=(('joe', password),))
+    with tests.server_request(handler, request_count=3) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 401
+        http.add_credentials('joe', password)
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+
+
+def test_basic_for_domain():
+    # Test Basic Authentication
+    http = httplib2.Http()
+    password = tests.gen_password()
+    handler = tests.http_reflect_with_auth(allow_scheme='basic', allow_credentials=(('joe', password),))
+    with tests.server_request(handler, request_count=4) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 401
+        http.add_credentials('joe', password, 'example.org')
+        response, content = http.request(uri, 'GET')
+        assert response.status == 401
+        domain = urllib.parse.urlparse(uri)[1]
+        http.add_credentials('joe', password, domain)
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+
+
+def test_basic_two_credentials():
+    # Test Basic Authentication with multiple sets of credentials
+    http = httplib2.Http()
+    password1 = tests.gen_password()
+    password2 = tests.gen_password()
+    allowed = [('joe', password1)]  # exploit shared mutable list
+    handler = tests.http_reflect_with_auth(allow_scheme='basic', allow_credentials=allowed)
+    with tests.server_request(handler, request_count=7) as uri:
+        http.add_credentials('fred', password2)
+        response, content = http.request(uri, 'GET')
+        assert response.status == 401
+        http.add_credentials('joe', password1)
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        allowed[0] = ('fred', password2)
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+
+
+def test_digest():
+    # Test that we support Digest Authentication
+    http = httplib2.Http()
+    password = tests.gen_password()
+    handler = tests.http_reflect_with_auth(allow_scheme='digest', allow_credentials=(('joe', password),))
+    with tests.server_request(handler, request_count=3) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 401
+        http.add_credentials('joe', password)
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200, content.decode()
+
+
+def test_digest_next_nonce_nc():
+    # Test that if the server sets nextnonce that we reset
+    # the nonce count back to 1
+    http = httplib2.Http()
+    password = tests.gen_password()
+    grenew_nonce = [None]
+    handler = tests.http_reflect_with_auth(
+        allow_scheme='digest',
+        allow_credentials=(('joe', password),),
+        out_renew_nonce=grenew_nonce,
+    )
+    with tests.server_request(handler, request_count=5) as uri:
+        http.add_credentials('joe', password)
+        response1, _ = http.request(uri, 'GET')
+        info = httplib2._parse_www_authenticate(response1, 'authentication-info')
+        assert response1.status == 200
+        assert info.get('digest', {}).get('nc') == '00000001', info
+        assert not info.get('digest', {}).get('nextnonce'), info
+        response2, _ = http.request(uri, 'GET')
+        info2 = httplib2._parse_www_authenticate(response2, 'authentication-info')
+        assert info2.get('digest', {}).get('nc') == '00000002', info2
+        grenew_nonce[0]()
+        response3, content = http.request(uri, 'GET')
+        info3 = httplib2._parse_www_authenticate(response3, 'authentication-info')
+        assert response3.status == 200
+        assert info3.get('digest', {}).get('nc') == '00000001', info3
+
+
+def test_digest_auth_stale():
+    # Test that we can handle a nonce becoming stale
+    http = httplib2.Http()
+    password = tests.gen_password()
+    grenew_nonce = [None]
+    requests = []
+    handler = tests.http_reflect_with_auth(
+        allow_scheme='digest',
+        allow_credentials=(('joe', password),),
+        out_renew_nonce=grenew_nonce,
+        out_requests=requests,
+    )
+    with tests.server_request(handler, request_count=4) as uri:
+        http.add_credentials('joe', password)
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        info = httplib2._parse_www_authenticate(requests[0][1].headers, 'www-authenticate')
+        grenew_nonce[0]()
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        assert not response.fromcache
+        assert getattr(response, '_stale_digest', False)
+        info2 = httplib2._parse_www_authenticate(requests[2][1].headers, 'www-authenticate')
+        nonce1 = info.get('digest', {}).get('nonce', '')
+        nonce2 = info2.get('digest', {}).get('nonce', '')
+        assert nonce1 != ''
+        assert nonce2 != ''
+        assert nonce1 != nonce2, (nonce1, nonce2)
+
+
+@pytest.mark.parametrize(
+    'data', (
+        ({}, {}),
+        ({'www-authenticate': ''}, {}),
+        ({'www-authenticate': 'Test realm="test realm" , foo=foo ,bar="bar", baz=baz,qux=qux'},
+         {'test': {'realm': 'test realm', 'foo': 'foo', 'bar': 'bar', 'baz': 'baz', 'qux': 'qux'}}),
+        ({'www-authenticate': 'T*!%#st realm=to*!%#en, to*!%#en="quoted string"'},
+         {'t*!%#st': {'realm': 'to*!%#en', 'to*!%#en': 'quoted string'}}),
+        ({'www-authenticate': 'Test realm="a \\"test\\" realm"'},
+         {'test': {'realm': 'a "test" realm'}}),
+        ({'www-authenticate': 'Basic realm="me"'},
+         {'basic': {'realm': 'me'}}),
+        ({'www-authenticate': 'Basic realm="me", algorithm="MD5"'},
+         {'basic': {'realm': 'me', 'algorithm': 'MD5'}}),
+        ({'www-authenticate': 'Basic realm="me", algorithm=MD5'},
+         {'basic': {'realm': 'me', 'algorithm': 'MD5'}}),
+        ({'www-authenticate': 'Basic realm="me",other="fred" '},
+         {'basic': {'realm': 'me', 'other': 'fred'}}),
+        ({'www-authenticate': 'Basic REAlm="me" '},
+         {'basic': {'realm': 'me'}}),
+        ({'www-authenticate': 'Digest realm="digest1", qop="auth,auth-int", nonce="7102dd2", opaque="e9517f"'},
+         {'digest': {'realm': 'digest1', 'qop': 'auth,auth-int', 'nonce': '7102dd2', 'opaque': 'e9517f'}}),
+        # multiple schema choice
+        ({'www-authenticate': 'Digest realm="multi-d", nonce="8b11d0f6", opaque="cc069c" Basic realm="multi-b" '},
+         {'digest': {'realm': 'multi-d', 'nonce': '8b11d0f6', 'opaque': 'cc069c'},
+          'basic': {'realm': 'multi-b'}}),
+        # FIXME
+        # comma between schemas (glue for multiple headers with same name)
+        # ({'www-authenticate': 'Digest realm="2-comma-d", qop="auth-int", nonce="c0c8ff1", Basic realm="2-comma-b"'},
+        #  {'digest': {'realm': '2-comma-d', 'qop': 'auth-int', 'nonce': 'c0c8ff1'},
+        #   'basic': {'realm': '2-comma-b'}}),
+        # FIXME
+        # comma between schemas + WSSE (glue for multiple headers with same name)
+        # ({'www-authenticate': 'Digest realm="com3d", Basic realm="com3b", WSSE realm="com3w", profile="token"'},
+        #  {'digest': {'realm': 'com3d'}, 'basic': {'realm': 'com3b'}, 'wsse': {'realm': 'com3w', profile': 'token'}}),
+        # FIXME
+        # multiple syntax figures
+        # ({'www-authenticate':
+        #     'Digest realm="brig", qop \t=\t"\tauth,auth-int", nonce="(*)&^&$%#",opaque="5ccc"' +
+        #     ', Basic REAlm="zoo", WSSE realm="very", profile="UsernameToken"'},
+        #  {'digest': {'realm': 'brig', 'qop': 'auth,auth-int', 'nonce': '(*)&^&$%#', 'opaque': '5ccc'},
+        #   'basic': {'realm': 'zoo'},
+        #   'wsse': {'realm': 'very', 'profile': 'UsernameToken'}}),
+        # more quote combos
+        ({'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=3", algorithm=MD5, qop="auth", stale=true'},
+         {'digest': {'realm': 'myrealm', 'nonce': 'KBAA=3', 'algorithm': 'MD5', 'qop': 'auth', 'stale': 'true'}}),
+    ), ids=lambda data: str(data[0]))
+@pytest.mark.parametrize('strict', (True, False), ids=('strict', 'relax'))
+def test_parse_www_authenticate_correct(data, strict):
+    headers, info = data
+    # FIXME: move strict to parse argument
+    httplib2.USE_WWW_AUTH_STRICT_PARSING = strict
+    try:
+        assert httplib2._parse_www_authenticate(headers) == info
+    finally:
+        httplib2.USE_WWW_AUTH_STRICT_PARSING = 0
+
+
+def test_parse_www_authenticate_malformed():
+    # TODO: test (and fix) header value 'barbqwnbm-bb...:asd' leads to dead loop
+    with tests.assert_raises(httplib2.MalformedHeader):
+        httplib2._parse_www_authenticate(
+            {'www-authenticate': 'OAuth "Facebook Platform" "invalid_token" "Invalid OAuth access token."'}
+        )
+
+
+def test_digest_object():
+    credentials = ('joe', 'password')
+    host = None
+    request_uri = '/test/digest/'
+    headers = {}
+    response = {
+        'www-authenticate': 'Digest realm="myrealm", nonce="KBAA=35", algorithm=MD5, qop="auth"'
+    }
+    content = b''
+
+    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+    d.request('GET', request_uri, headers, content, cnonce="33033375ec278a46")
+    our_request = 'authorization: ' + headers['authorization']
+    working_request = (
+        'authorization: Digest username="joe", realm="myrealm", nonce="KBAA=35", uri="/test/digest/"' +
+        ', algorithm=MD5, response="de6d4a123b80801d0e94550411b6283f", qop=auth, nc=00000001, cnonce="33033375ec278a46"'
+    )
+    assert our_request == working_request
+
+
+def test_digest_object_with_opaque():
+    credentials = ('joe', 'password')
+    host = None
+    request_uri = '/digest/opaque/'
+    headers = {}
+    response = {
+        'www-authenticate': 'Digest realm="myrealm", nonce="30352fd", algorithm=MD5, qop="auth", opaque="atestopaque"',
+    }
+    content = ''
+
+    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+    d.request('GET', request_uri, headers, content, cnonce="5ec2")
+    our_request = 'authorization: ' + headers['authorization']
+    working_request = (
+        'authorization: Digest username="joe", realm="myrealm", nonce="30352fd", uri="/digest/opaque/", algorithm=MD5' +
+        ', response="a1fab43041f8f3789a447f48018bee48", qop=auth, nc=00000001, cnonce="5ec2", opaque="atestopaque"'
+    )
+    assert our_request == working_request
+
+
+def test_digest_object_stale():
+    credentials = ('joe', 'password')
+    host = None
+    request_uri = '/digest/stale/'
+    headers = {}
+    response = httplib2.Response({})
+    response['www-authenticate'] = 'Digest realm="myrealm", nonce="bd669f", algorithm=MD5, qop="auth", stale=true'
+    response.status = 401
+    content = b''
+    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+    # Returns true to force a retry
+    assert d.response(response, content)
+
+
+def test_digest_object_auth_info():
+    credentials = ('joe', 'password')
+    host = None
+    request_uri = '/digest/nextnonce/'
+    headers = {}
+    response = httplib2.Response({})
+    response['www-authenticate'] = 'Digest realm="myrealm", nonce="barney", algorithm=MD5, qop="auth", stale=true'
+    response['authentication-info'] = 'nextnonce="fred"'
+    content = b''
+    d = httplib2.DigestAuthentication(credentials, host, request_uri, headers, response, content, None)
+    # Returns true to force a retry
+    assert not d.response(response, content)
+    assert d.challenge['nonce'] == 'fred'
+    assert d.challenge['nc'] == 1
+
+
+def test_wsse_algorithm():
+    digest = httplib2._wsse_username_token('d36e316282959a9ed4c89851497a717f', '2003-12-15T14:43:07Z', 'taadtaadpstcsm')
+    expected = b'quR/EWLAV4xLf9Zqyw4pDmfV9OY='
+    assert expected == digest
diff --git a/tests/test_cache.py b/tests/test_cache.py
new file mode 100644
index 0000000..c2a2beb
--- /dev/null
+++ b/tests/test_cache.py
@@ -0,0 +1,390 @@
+import email.utils
+import httplib2
+import pytest
+import re
+import tests
+import time
+
+
+dummy_url = 'http://127.0.0.1:1'
+
+
+def test_get_only_if_cached_cache_hit():
+    # Test that can do a GET with cache and 'only-if-cached'
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_const_http(add_etag=True) as uri:
+        http.request(uri, 'GET')
+        response, content = http.request(uri, 'GET', headers={'cache-control': 'only-if-cached'})
+    assert response.fromcache
+    assert response.status == 200
+
+
+def test_get_only_if_cached_cache_miss():
+    # Test that can do a GET with no cache with 'only-if-cached'
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_const_http(request_count=0) as uri:
+        response, content = http.request(uri, 'GET', headers={'cache-control': 'only-if-cached'})
+    assert not response.fromcache
+    assert response.status == 504
+
+
+def test_get_only_if_cached_no_cache_at_all():
+    # Test that can do a GET with no cache with 'only-if-cached'
+    # Of course, there might be an intermediary beyond us
+    # that responds to the 'only-if-cached', so this
+    # test can't really be guaranteed to pass.
+    http = httplib2.Http()
+    with tests.server_const_http(request_count=0) as uri:
+        response, content = http.request(uri, 'GET', headers={'cache-control': 'only-if-cached'})
+    assert not response.fromcache
+    assert response.status == 504
+
+
+@pytest.mark.skip(reason='was commented in legacy code')
+def test_TODO_vary_no():
+    pass
+    # when there is no vary, a different Accept header (e.g.) should not
+    # impact if the cache is used
+    # test that the vary header is not sent
+    # uri = urllib.parse.urljoin(base, "vary/no-vary.asis")
+    # response, content = http.request(uri, 'GET', headers={'Accept': 'text/plain'})
+    # assert response.status == 200
+    # assert 'vary' not in response
+    #
+    # response, content = http.request(uri, 'GET', headers={'Accept': 'text/plain'})
+    # assert response.status == 200
+    # assert response.fromcache, "Should be from cache"
+    #
+    # response, content = http.request(uri, 'GET', headers={'Accept': 'text/html'})
+    # assert response.status == 200
+    # assert response.fromcache, "Should be from cache"
+
+
+def test_vary_header_simple():
+    """
+    RFC 2616 13.6
+    When the cache receives a subsequent request whose Request-URI
+    specifies one or more cache entries including a Vary header field,
+    the cache MUST NOT use such a cache entry to construct a response
+    to the new request unless all of the selecting request-headers
+    present in the new request match the corresponding stored
+    request-headers in the original request.
+    """
+    # test that the vary header is sent
+    http = httplib2.Http(cache=tests.get_cache_path())
+    response = tests.http_response_bytes(
+        headers={'vary': 'Accept', 'cache-control': 'max-age=300'},
+        add_date=True,
+    )
+    with tests.server_const_bytes(response, request_count=3) as uri:
+        response, content = http.request(uri, 'GET', headers={'accept': 'text/plain'})
+        assert response.status == 200
+        assert 'vary' in response
+
+        # get the resource again, from the cache since accept header in this
+        # request is the same as the request
+        response, content = http.request(uri, 'GET', headers={'Accept': 'text/plain'})
+        assert response.status == 200
+        assert response.fromcache, "Should be from cache"
+
+        # get the resource again, not from cache since Accept headers does not match
+        response, content = http.request(uri, 'GET', headers={'Accept': 'text/html'})
+        assert response.status == 200
+        assert not response.fromcache, "Should not be from cache"
+
+        # get the resource again, without any Accept header, so again no match
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        assert not response.fromcache, "Should not be from cache"
+
+
+def test_vary_header_double():
+    http = httplib2.Http(cache=tests.get_cache_path())
+    response = tests.http_response_bytes(
+        headers={'vary': 'Accept, Accept-Language', 'cache-control': 'max-age=300'},
+        add_date=True,
+    )
+    with tests.server_const_bytes(response, request_count=3) as uri:
+        response, content = http.request(uri, 'GET', headers={
+            'Accept': 'text/plain',
+            'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7',
+        })
+        assert response.status == 200
+        assert 'vary' in response
+
+        # we are from cache
+        response, content = http.request(uri, 'GET', headers={
+            'Accept': 'text/plain', 'Accept-Language': 'da, en-gb;q=0.8, en;q=0.7'})
+        assert response.fromcache, "Should be from cache"
+
+        response, content = http.request(uri, 'GET', headers={'Accept': 'text/plain'})
+        assert response.status == 200
+        assert not response.fromcache
+
+        # get the resource again, not from cache, varied headers don't match exact
+        response, content = http.request(uri, 'GET', headers={'Accept-Language': 'da'})
+        assert response.status == 200
+        assert not response.fromcache, "Should not be from cache"
+
+
+def test_vary_unused_header():
+    http = httplib2.Http(cache=tests.get_cache_path())
+    response = tests.http_response_bytes(
+        headers={'vary': 'X-No-Such-Header', 'cache-control': 'max-age=300'},
+        add_date=True,
+    )
+    with tests.server_const_bytes(response, request_count=1) as uri:
+        # A header's value is not considered to vary if it's not used at all.
+        response, content = http.request(uri, 'GET', headers={'Accept': 'text/plain'})
+        assert response.status == 200
+        assert 'vary' in response
+
+        # we are from cache
+        response, content = http.request(uri, 'GET', headers={'Accept': 'text/plain'})
+        assert response.fromcache, "Should be from cache"
+
+
+def test_get_cache_control_no_cache():
+    # Test Cache-Control: no-cache on requests
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_const_http(
+            add_date=True, add_etag=True,
+            headers={'cache-control': 'max-age=300'}, request_count=2) as uri:
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        assert response.status == 200
+        assert response['etag'] != ''
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        assert response.status == 200
+        assert response.fromcache
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity', 'Cache-Control': 'no-cache'})
+        assert response.status == 200
+        assert not response.fromcache
+
+
+def test_get_cache_control_pragma_no_cache():
+    # Test Pragma: no-cache on requests
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_const_http(
+            add_date=True, add_etag=True,
+            headers={'cache-control': 'max-age=300'}, request_count=2) as uri:
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        assert response['etag'] != ''
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        assert response.status == 200
+        assert response.fromcache
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity', 'Pragma': 'no-cache'})
+        assert response.status == 200
+        assert not response.fromcache
+
+
+def test_get_cache_control_no_store_request():
+    # A no-store request means that the response should not be stored.
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_const_http(
+            add_date=True, add_etag=True,
+            headers={'cache-control': 'max-age=300'}, request_count=2) as uri:
+        response, _ = http.request(uri, 'GET', headers={'Cache-Control': 'no-store'})
+        assert response.status == 200
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET', headers={'Cache-Control': 'no-store'})
+        assert response.status == 200
+        assert not response.fromcache
+
+
+def test_get_cache_control_no_store_response():
+    # A no-store response means that the response should not be stored.
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_const_http(
+            add_date=True, add_etag=True,
+            headers={'cache-control': 'max-age=300, no-store'}, request_count=2) as uri:
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        assert not response.fromcache
+
+
+def test_get_cache_control_no_cache_no_store_request():
+    # Test that a no-store, no-cache clears the entry from the cache
+    # even if it was cached previously.
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_const_http(
+            add_date=True, add_etag=True,
+            headers={'cache-control': 'max-age=300'}, request_count=3) as uri:
+        response, _ = http.request(uri, 'GET')
+        response, _ = http.request(uri, 'GET')
+        assert response.fromcache
+        response, _ = http.request(uri, 'GET', headers={'Cache-Control': 'no-store, no-cache'})
+        assert response.status == 200
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET', headers={'Cache-Control': 'no-store, no-cache'})
+        assert response.status == 200
+        assert not response.fromcache
+
+
+def test_update_invalidates_cache():
+    # Test that calling PUT or DELETE on a
+    # URI that is cache invalidates that cache.
+    http = httplib2.Http(cache=tests.get_cache_path())
+
+    def handler(request):
+        if request.method in ('PUT', 'PATCH', 'DELETE'):
+            return tests.http_response_bytes(status=405)
+        return tests.http_response_bytes(
+            add_date=True, add_etag=True, headers={'cache-control': 'max-age=300'})
+
+    with tests.server_request(handler, request_count=3) as uri:
+        response, _ = http.request(uri, 'GET')
+        response, _ = http.request(uri, 'GET')
+        assert response.fromcache
+        response, _ = http.request(uri, 'DELETE')
+        assert response.status == 405
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET')
+        assert not response.fromcache
+
+
+def handler_conditional_update(request):
+    respond = tests.http_response_bytes
+    if request.method == 'GET':
+        if request.headers.get('if-none-match', '') == '12345':
+            return respond(status=304)
+        return respond(add_date=True, headers={'etag': '12345', 'cache-control': 'max-age=300'})
+    elif request.method in ('PUT', 'PATCH', 'DELETE'):
+        if request.headers.get('if-match', '') == '12345':
+            return respond(status=200)
+        return respond(status=412)
+    return respond(status=405)
+
+
+@pytest.mark.parametrize('method', ('PUT', 'PATCH'))
+def test_update_uses_cached_etag(method):
+    # Test that we natively support http://www.w3.org/1999/04/Editing/
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_request(handler_conditional_update, request_count=3) as uri:
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        assert response.fromcache
+        response, _ = http.request(uri, method, body=b'foo')
+        assert response.status == 200
+        response, _ = http.request(uri, method, body=b'foo')
+        assert response.status == 412
+
+
+def test_update_uses_cached_etag_and_oc_method():
+    # Test that we natively support http://www.w3.org/1999/04/Editing/
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_request(handler_conditional_update, request_count=2) as uri:
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 200
+        assert response.fromcache
+        http.optimistic_concurrency_methods.append('DELETE')
+        response, _ = http.request(uri, 'DELETE')
+        assert response.status == 200
+
+
+def test_update_uses_cached_etag_overridden():
+    # Test that we natively support http://www.w3.org/1999/04/Editing/
+    http = httplib2.Http(cache=tests.get_cache_path())
+    with tests.server_request(handler_conditional_update, request_count=2) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        assert not response.fromcache
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        assert response.fromcache
+        response, content = http.request(uri, 'PUT', body=b'foo', headers={'if-match': 'fred'})
+        assert response.status == 412
+
+
+@pytest.mark.parametrize(
+    'data', (
+        ({}, {}),
+        ({'cache-control': ' no-cache'},
+         {'no-cache': 1}),
+        ({'cache-control': ' no-store, max-age = 7200'},
+         {'no-store': 1, 'max-age': '7200'}),
+        ({'cache-control': ' , '}, {'': 1}),  # FIXME
+        ({'cache-control': 'Max-age=3600;post-check=1800,pre-check=3600'},
+         {'max-age': '3600;post-check=1800', 'pre-check': '3600'}),
+    ), ids=lambda data: str(data[0]))
+def test_parse_cache_control(data):
+    header, expected = data
+    assert httplib2._parse_cache_control(header) == expected
+
+
+def test_normalize_headers():
+    # Test that we normalize headers to lowercase
+    h = httplib2._normalize_headers({'Cache-Control': 'no-cache', 'Other': 'Stuff'})
+    assert 'cache-control' in h
+    assert 'other' in h
+    assert h['other'] == 'Stuff'
+
+
+@pytest.mark.parametrize(
+    'data', (
+        ({'cache-control': 'no-cache'}, {'cache-control': 'max-age=7200'}, 'TRANSPARENT'),
+        ({}, {'cache-control': 'max-age=fred, min-fresh=barney'}, 'STALE'),
+        ({}, {'date': '{now}', 'expires': '{now+3}'}, 'FRESH'),
+        ({}, {'date': '{now}', 'expires': '{now+3}', 'cache-control': 'no-cache'}, 'STALE'),
+        ({'cache-control': 'must-revalidate'}, {}, 'STALE'),
+        ({}, {'cache-control': 'must-revalidate'}, 'STALE'),
+        ({}, {'date': '{now}', 'cache-control': 'max-age=0'}, 'STALE'),
+        ({'cache-control': 'only-if-cached'}, {}, 'FRESH'),
+        ({}, {'date': '{now}', 'expires': '0'}, 'STALE'),
+        ({}, {'data': '{now+3}'}, 'STALE'),
+        ({'cache-control': 'max-age=0'}, {'date': '{now}', 'cache-control': 'max-age=2'}, 'STALE'),
+        ({'cache-control': 'min-fresh=2'}, {'date': '{now}', 'expires': '{now+2}'}, 'STALE'),
+        ({'cache-control': 'min-fresh=2'}, {'date': '{now}', 'expires': '{now+4}'}, 'FRESH'),
+    ), ids=lambda data: str(data))
+def test_entry_disposition(data):
+    now = time.time()
+    nowre = re.compile(r'{now([\+\-]\d+)?}')
+
+    def render(s):
+        m = nowre.match(s)
+        if m:
+            offset = int(m.expand(r'\1')) if m.group(1) else 0
+            s = email.utils.formatdate(now + offset, usegmt=True)
+        return s
+
+    request, response, expected = data
+    request = {k: render(v) for k, v in request.items()}
+    response = {k: render(v) for k, v in response.items()}
+    assert httplib2._entry_disposition(response, request) == expected
+
+
+def test_expiration_model_fresh():
+    response_headers = {
+        'date': email.utils.formatdate(usegmt=True),
+        'cache-control': 'max-age=2'
+    }
+    assert httplib2._entry_disposition(response_headers, {}) == 'FRESH'
+    # TODO: add current time as _entry_disposition argument to avoid sleep in tests
+    time.sleep(3)
+    assert httplib2._entry_disposition(response_headers, {}) == 'STALE'
+
+
+def test_expiration_model_date_and_expires():
+    now = time.time()
+    response_headers = {
+        'date': email.utils.formatdate(now, usegmt=True),
+        'expires': email.utils.formatdate(now + 2, usegmt=True),
+    }
+    assert httplib2._entry_disposition(response_headers, {}) == 'FRESH'
+    time.sleep(3)
+    assert httplib2._entry_disposition(response_headers, {}) == 'STALE'
+
+
+# TODO: Repeat all cache tests with memcache. pytest.mark.parametrize
+# cache = memcache.Client(['127.0.0.1:11211'], debug=0)
+# #cache = memcache.Client(['10.0.0.4:11211'], debug=1)
+# http = httplib2.Http(cache)
diff --git a/tests/test_encoding.py b/tests/test_encoding.py
new file mode 100644
index 0000000..df991a1
--- /dev/null
+++ b/tests/test_encoding.py
@@ -0,0 +1,99 @@
+import httplib2
+import tests
+
+
+def test_gzip_head():
+    # Test that we don't try to decompress a HEAD response
+    http = httplib2.Http()
+    response = tests.http_response_bytes(
+        headers={'content-encoding': 'gzip', 'content-length': 42},
+    )
+    with tests.server_const_bytes(response) as uri:
+        response, content = http.request(uri, 'HEAD')
+        assert response.status == 200
+        assert int(response['content-length']) != 0
+        assert content == b''
+
+
+def test_gzip_get():
+    # Test that we support gzip compression
+    http = httplib2.Http()
+    response = tests.http_response_bytes(
+        headers={'content-encoding': 'gzip'},
+        body=tests.gzip_compress(b'properly compressed'),
+    )
+    with tests.server_const_bytes(response) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        assert 'content-encoding' not in response
+        assert '-content-encoding' in response
+        assert int(response['content-length']) == len(b'properly compressed')
+        assert content == b'properly compressed'
+
+
+def test_gzip_post_response():
+    http = httplib2.Http()
+    response = tests.http_response_bytes(
+        headers={'content-encoding': 'gzip'},
+        body=tests.gzip_compress(b'properly compressed'),
+    )
+    with tests.server_const_bytes(response) as uri:
+        response, content = http.request(uri, 'POST', body=b'')
+        assert response.status == 200
+        assert 'content-encoding' not in response
+        assert '-content-encoding' in response
+
+
+def test_gzip_malformed_response():
+    http = httplib2.Http()
+    # Test that we raise a good exception when the gzip fails
+    http.force_exception_to_status_code = False
+    response = tests.http_response_bytes(
+        headers={'content-encoding': 'gzip'},
+        body=b'obviously not compressed',
+    )
+    with tests.server_const_bytes(response, request_count=2) as uri:
+        with tests.assert_raises(httplib2.FailedToDecompressContent):
+            http.request(uri, 'GET')
+
+        # Re-run the test with out the exceptions
+        http.force_exception_to_status_code = True
+
+        response, content = http.request(uri, 'GET')
+        assert response.status == 500
+        assert response.reason.startswith('Content purported')
+
+
+def test_deflate_get():
+    # Test that we support deflate compression
+    http = httplib2.Http()
+    response = tests.http_response_bytes(
+        headers={'content-encoding': 'deflate'},
+        body=tests.deflate_compress(b'properly compressed'),
+    )
+    with tests.server_const_bytes(response) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        assert 'content-encoding' not in response
+        assert int(response['content-length']) == len(b'properly compressed')
+        assert content == b'properly compressed'
+
+
+def test_deflate_malformed_response():
+    # Test that we raise a good exception when the deflate fails
+    http = httplib2.Http()
+    http.force_exception_to_status_code = False
+    response = tests.http_response_bytes(
+        headers={'content-encoding': 'deflate'},
+        body=b'obviously not compressed',
+    )
+    with tests.server_const_bytes(response, request_count=2) as uri:
+        with tests.assert_raises(httplib2.FailedToDecompressContent):
+            http.request(uri, 'GET')
+
+        # Re-run the test with out the exceptions
+        http.force_exception_to_status_code = True
+
+        response, content = http.request(uri, 'GET')
+        assert response.status == 500
+        assert response.reason.startswith('Content purported')
diff --git a/tests/test_external.py b/tests/test_external.py
new file mode 100644
index 0000000..20652c9
--- /dev/null
+++ b/tests/test_external.py
@@ -0,0 +1,95 @@
+'''These tests rely on replies from public internet services
+
+TODO: reimplement with local stubs
+'''
+import httplib2
+import os
+import pytest
+import ssl
+import sys
+import tests
+
+
+def test_get_301_via_https():
+    # Google always redirects to http://google.com
+    http = httplib2.Http()
+    response, content = http.request('https://code.google.com/apis/', 'GET')
+    assert response.status == 200
+    assert response.previous.status == 301
+
+
+def test_get_via_https():
+    # Test that we can handle HTTPS
+    http = httplib2.Http()
+    response, content = http.request('https://google.com/adsense/', 'GET')
+    assert response.status == 200
+
+
+def test_get_via_https_spec_violation_on_location():
+    # Test that we follow redirects through HTTPS
+    # even if they violate the spec by including
+    # a relative Location: header instead of an
+    # absolute one.
+    http = httplib2.Http()
+    response, content = http.request('https://google.com/adsense', 'GET')
+    assert response.status == 200
+    assert response.previous is not None
+
+
+def test_get_via_https_key_cert():
+    #  At this point I can only test
+    #  that the key and cert files are passed in
+    #  correctly to httplib. It would be nice to have
+    #  a real https endpoint to test against.
+    http = httplib2.Http(timeout=2)
+    http.add_certificate('akeyfile', 'acertfile', 'bitworking.org')
+    try:
+        http.request('https://bitworking.org', 'GET')
+    except AttributeError:
+        assert http.connections['https:bitworking.org'].key_file == 'akeyfile'
+        assert http.connections['https:bitworking.org'].cert_file == 'acertfile'
+    except IOError:
+        # Skip on 3.2
+        pass
+
+    try:
+        http.request('https://notthere.bitworking.org', 'GET')
+    except httplib2.ServerNotFoundError:
+        assert http.connections['https:notthere.bitworking.org'].key_file is None
+        assert http.connections['https:notthere.bitworking.org'].cert_file is None
+    except IOError:
+        # Skip on 3.2
+        pass
+
+
+def test_ssl_invalid_ca_certs_path():
+    # Test that we get an ssl.SSLError when specifying a non-existent CA
+    # certs file.
+    http = httplib2.Http(ca_certs='/nosuchfile')
+    with tests.assert_raises(IOError):
+        http.request('https://www.google.com/', 'GET')
+
+
+@pytest.mark.xfail(
+    sys.version_info <= (3,),
+    reason='FIXME: for unknown reason Python 2.7.10 validates www.google.com against dummy CA www.example.com',
+)
+def test_ssl_wrong_ca():
+    # Test that we get a SSLHandshakeError if we try to access
+    # https://www.google.com, using a CA cert file that doesn't contain
+    # the CA Google uses (i.e., simulating a cert that's not signed by a
+    # trusted CA).
+    other_ca_certs = os.path.join(
+        os.path.dirname(os.path.abspath(httplib2.__file__)),
+        'test', 'other_cacerts.txt')
+    assert os.path.exists(other_ca_certs)
+    http = httplib2.Http(ca_certs=other_ca_certs)
+    http.follow_redirects = False
+    with tests.assert_raises(ssl.SSLError):
+        http.request('https://www.google.com/', 'GET')
+
+
+def test_sni_hostname_validation():
+    # TODO: make explicit test server with SNI validation
+    http = httplib2.Http()
+    http.request('https://google.com/', method='GET')
diff --git a/tests/test_http.py b/tests/test_http.py
new file mode 100644
index 0000000..29d67af
--- /dev/null
+++ b/tests/test_http.py
@@ -0,0 +1,592 @@
+import email.utils
+import httplib2
+import mock
+import os
+import pytest
+import socket
+import tests
+from six.moves import http_client, urllib
+
+
+dummy_url = 'http://127.0.0.1:1'
+
+
+def test_connection_type():
+    http = httplib2.Http()
+    http.force_exception_to_status_code = False
+    response, content = http.request(dummy_url, connection_type=tests.MockHTTPConnection)
+    assert response['content-location'] == dummy_url
+    assert content == b'the body'
+
+
+def test_bad_status_line_retry():
+    http = httplib2.Http()
+    old_retries = httplib2.RETRIES
+    httplib2.RETRIES = 1
+    http.force_exception_to_status_code = False
+    try:
+        response, content = http.request(dummy_url, connection_type=tests.MockHTTPBadStatusConnection)
+    except http_client.BadStatusLine:
+        assert tests.MockHTTPBadStatusConnection.num_calls == 2
+    httplib2.RETRIES = old_retries
+
+
+def test_unknown_server():
+    http = httplib2.Http()
+    http.force_exception_to_status_code = False
+    with tests.assert_raises(httplib2.ServerNotFoundError):
+        with mock.patch('socket.socket.connect', side_effect=socket.gaierror):
+            http.request("http://no-such-hostname./")
+
+    # Now test with exceptions turned off
+    http.force_exception_to_status_code = True
+    response, content = http.request("http://no-such-hostname./")
+    assert response['content-type'] == 'text/plain'
+    assert content.startswith(b"Unable to find")
+    assert response.status == 400
+
+
+def test_connection_refused():
+    http = httplib2.Http()
+    http.force_exception_to_status_code = False
+    with tests.assert_raises(socket.error):
+        http.request(dummy_url)
+
+    # Now test with exceptions turned off
+    http.force_exception_to_status_code = True
+    response, content = http.request(dummy_url)
+    assert response['content-type'] == 'text/plain'
+    assert (b"Connection refused" in content or b"actively refused" in content)
+    assert response.status == 400
+
+
+def test_get_iri():
+    http = httplib2.Http()
+    query = u'?a=\N{CYRILLIC CAPITAL LETTER DJE}'
+    with tests.server_reflect() as uri:
+        response, content = http.request(uri + query, 'GET')
+        assert response.status == 200
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert reflected.uri == '/?a=%D0%82'
+
+
+def test_get_is_default_method():
+    # Test that GET is the default method
+    http = httplib2.Http()
+    with tests.server_reflect() as uri:
+        response, content = http.request(uri)
+        assert response.status == 200
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert reflected.method == 'GET'
+
+
+def test_different_methods():
+    # Test that all methods can be used
+    http = httplib2.Http()
+    methods = ['GET', 'PUT', 'DELETE', 'POST', 'unknown']
+    with tests.server_reflect(request_count=len(methods)) as uri:
+        for method in methods:
+            response, content = http.request(uri, method, body=b" ")
+            assert response.status == 200
+            reflected = tests.HttpRequest.from_bytes(content)
+            assert reflected.method == method
+
+
+def test_head_read():
+    # Test that we don't try to read the response of a HEAD request
+    # since httplib blocks response.read() for HEAD requests.
+    http = httplib2.Http()
+    respond_with = b'HTTP/1.0 200 OK\r\ncontent-length: 14\r\n\r\nnon-empty-body'
+    with tests.server_const_bytes(respond_with) as uri:
+        response, content = http.request(uri, 'HEAD')
+    assert response.status == 200
+    assert content == b""
+
+
+def test_get_no_cache():
+    # Test that can do a GET w/o the cache turned on.
+    http = httplib2.Http()
+    with tests.server_const_http() as uri:
+        response, content = http.request(uri, 'GET')
+    assert response.status == 200
+    assert response.previous is None
+
+
+def test_user_agent():
+    # Test that we provide a default user-agent
+    http = httplib2.Http()
+    with tests.server_reflect() as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert reflected.headers.get('user-agent', '').startswith('Python-httplib2/')
+
+
+def test_user_agent_non_default():
+    # Test that the default user-agent can be over-ridden
+    http = httplib2.Http()
+    with tests.server_reflect() as uri:
+        response, content = http.request(uri, 'GET', headers={'User-Agent': 'fred/1.0'})
+        assert response.status == 200
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert reflected.headers.get('user-agent') == 'fred/1.0'
+
+
+def test_get_300_with_location():
+    # Test the we automatically follow 300 redirects if a Location: header is provided
+    http = httplib2.Http()
+    final_content = b'This is the final destination.\n'
+    routes = {
+        '/final': tests.http_response_bytes(body=final_content),
+        '': tests.http_response_bytes(status='300 Multiple Choices', headers={'location': '/final'}),
+    }
+    with tests.server_route(routes, request_count=2) as uri:
+        response, content = http.request(uri, 'GET')
+    assert response.status == 200
+    assert content == final_content
+    assert response.previous.status == 300
+    assert not response.previous.fromcache
+
+    # Confirm that the intermediate 300 is not cached
+    with tests.server_route(routes, request_count=2) as uri:
+        response, content = http.request(uri, 'GET')
+    assert response.status == 200
+    assert content == final_content
+    assert response.previous.status == 300
+    assert not response.previous.fromcache
+
+
+def test_get_300_with_location_noredirect():
+    # Test the we automatically follow 300 redirects if a Location: header is provided
+    http = httplib2.Http()
+    http.follow_redirects = False
+    response = tests.http_response_bytes(
+        status='300 Multiple Choices',
+        headers={'location': '/final'},
+        body=b'redirect body')
+    with tests.server_const_bytes(response) as uri:
+        response, content = http.request(uri, 'GET')
+    assert response.status == 300
+
+
+def test_get_300_without_location():
+    # Not giving a Location: header in a 300 response is acceptable
+    # In which case we just return the 300 response
+    http = httplib2.Http()
+    with tests.server_const_http(status='300 Multiple Choices', body=b'redirect body') as uri:
+        response, content = http.request(uri, 'GET')
+    assert response.status == 300
+    assert response.previous is None
+    assert content == b'redirect body'
+
+
+def test_get_301():
+    # Test that we automatically follow 301 redirects
+    # and that we cache the 301 response
+    http = httplib2.Http(cache=tests.get_cache_path())
+    destination = ''
+    routes = {
+        '/final': tests.http_response_bytes(body=b'This is the final destination.\n'),
+        '': tests.http_response_bytes(
+            status='301 Now where did I leave that URL', headers={'location': '/final'}, body=b'redirect body'),
+    }
+    with tests.server_route(routes, request_count=3) as uri:
+        destination = urllib.parse.urljoin(uri, '/final')
+        response1, content1 = http.request(uri, 'GET')
+        response2, content2 = http.request(uri, 'GET')
+    assert response1.status == 200
+    assert 'content-location' in response2
+    assert response1['content-location'] == destination
+    assert content1 == b'This is the final destination.\n'
+    assert response1.previous.status == 301
+    assert not response1.previous.fromcache
+
+    assert response2.status == 200
+    assert response2['content-location'] == destination
+    assert content2 == b'This is the final destination.\n'
+    assert response2.previous.status == 301
+    assert response2.previous.fromcache
+
+
+@pytest.mark.skip(
+    not os.environ.get('httplib2_test_still_run_skipped') and
+    os.environ.get('TRAVIS_PYTHON_VERSION') in ('2.7', 'pypy'),
+    reason='FIXME: timeout on Travis py27 and pypy, works elsewhere',
+)
+def test_head_301():
+    # Test that we automatically follow 301 redirects
+    http = httplib2.Http()
+    destination = ''
+    routes = {
+        '/final': tests.http_response_bytes(body=b'This is the final destination.\n'),
+        '': tests.http_response_bytes(
+            status='301 Now where did I leave that URL', headers={'location': '/final'}, body=b'redirect body'),
+    }
+    with tests.server_route(routes, request_count=2) as uri:
+        destination = urllib.parse.urljoin(uri, '/final')
+        response, content = http.request(uri, 'HEAD')
+    assert response.status == 200
+    assert response['content-location'] == destination
+    assert response.previous.status == 301
+    assert not response.previous.fromcache
+
+
+@pytest.mark.xfail(reason='FIXME: 301 cache works only with follow_redirects, should work regardless')
+def test_get_301_no_redirect():
+    # Test that we cache the 301 response
+    http = httplib2.Http(cache=tests.get_cache_path(), timeout=0.5)
+    http.follow_redirects = False
+    response = tests.http_response_bytes(
+        status='301 Now where did I leave that URL',
+        headers={'location': '/final', 'cache-control': 'max-age=300'},
+        body=b'redirect body',
+        add_date=True,
+    )
+    with tests.server_const_bytes(response) as uri:
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 301
+        assert not response.fromcache
+        response, _ = http.request(uri, 'GET')
+        assert response.status == 301
+        assert response.fromcache
+
+
+def test_get_302():
+    # Test that we automatically follow 302 redirects
+    # and that we DO NOT cache the 302 response
+    http = httplib2.Http(cache=tests.get_cache_path())
+    second_url, final_url = '', ''
+    routes = {
+        '/final': tests.http_response_bytes(body=b'This is the final destination.\n'),
+        '/second': tests.http_response_bytes(
+            status='302 Found', headers={'location': '/final'}, body=b'second redirect'),
+        '': tests.http_response_bytes(
+            status='302 Found', headers={'location': '/second'}, body=b'redirect body'),
+    }
+    with tests.server_route(routes, request_count=7) as uri:
+        second_url = urllib.parse.urljoin(uri, '/second')
+        final_url = urllib.parse.urljoin(uri, '/final')
+        response1, content1 = http.request(second_url, 'GET')
+        response2, content2 = http.request(second_url, 'GET')
+        response3, content3 = http.request(uri, 'GET')
+    assert response1.status == 200
+    assert response1['content-location'] == final_url
+    assert content1 == b'This is the final destination.\n'
+    assert response1.previous.status == 302
+    assert not response1.previous.fromcache
+
+    assert response2.status == 200
+    # FIXME:
+    # assert response2.fromcache
+    assert response2['content-location'] == final_url
+    assert content2 == b'This is the final destination.\n'
+    assert response2.previous.status == 302
+    assert not response2.previous.fromcache
+    assert response2.previous['content-location'] == second_url
+
+    assert response3.status == 200
+    # FIXME:
+    # assert response3.fromcache
+    assert content3 == b'This is the final destination.\n'
+    assert response3.previous.status == 302
+    assert not response3.previous.fromcache
+
+
+def test_get_302_redirection_limit():
+    # Test that we can set a lower redirection limit
+    # and that we raise an exception when we exceed
+    # that limit.
+    http = httplib2.Http()
+    http.force_exception_to_status_code = False
+    routes = {
+        '/second': tests.http_response_bytes(
+            status='302 Found', headers={'location': '/final'}, body=b'second redirect'),
+        '': tests.http_response_bytes(
+            status='302 Found', headers={'location': '/second'}, body=b'redirect body'),
+    }
+    with tests.server_route(routes, request_count=4) as uri:
+        try:
+            http.request(uri, 'GET', redirections=1)
+            assert False, 'This should not happen'
+        except httplib2.RedirectLimit:
+            pass
+        except Exception:
+            assert False, 'Threw wrong kind of exception '
+
+        # Re-run the test with out the exceptions
+        http.force_exception_to_status_code = True
+        response, content = http.request(uri, 'GET', redirections=1)
+
+    assert response.status == 500
+    assert response.reason.startswith('Redirected more')
+    assert response['status'] == '302'
+    assert content == b'second redirect'
+    assert response.previous is not None
+
+
+def test_get_302_no_location():
+    # Test that we throw an exception when we get
+    # a 302 with no Location: header.
+    http = httplib2.Http()
+    http.force_exception_to_status_code = False
+    with tests.server_const_http(status='302 Found', request_count=2) as uri:
+        try:
+            http.request(uri, 'GET')
+            assert False, 'Should never reach here'
+        except httplib2.RedirectMissingLocation:
+            pass
+        except Exception:
+            assert False, 'Threw wrong kind of exception '
+
+        # Re-run the test with out the exceptions
+        http.force_exception_to_status_code = True
+        response, content = http.request(uri, 'GET')
+
+    assert response.status == 500
+    assert response.reason.startswith('Redirected but')
+    assert '302' == response['status']
+    assert content == b''
+
+
+@pytest.mark.skip(
+    not os.environ.get('httplib2_test_still_run_skipped') and
+    os.environ.get('TRAVIS_PYTHON_VERSION') in ('2.7', 'pypy'),
+    reason='FIXME: timeout on Travis py27 and pypy, works elsewhere',
+)
+def test_303():
+    # Do a follow-up GET on a Location: header
+    # returned from a POST that gave a 303.
+    http = httplib2.Http()
+    routes = {
+        '/final': tests.make_http_reflect(),
+        '': tests.make_http_reflect(status='303 See Other', headers={'location': '/final'}),
+    }
+    with tests.server_route(routes, request_count=2) as uri:
+        response, content = http.request(uri, 'POST', " ")
+    assert response.status == 200
+    reflected = tests.HttpRequest.from_bytes(content)
+    assert reflected.uri == '/final'
+    assert response.previous.status == 303
+
+    # Skip follow-up GET
+    http = httplib2.Http()
+    http.follow_redirects = False
+    with tests.server_route(routes, request_count=1) as uri:
+        response, content = http.request(uri, 'POST', " ")
+    assert response.status == 303
+
+    # All methods can be used
+    http = httplib2.Http()
+    cases = 'DELETE GET HEAD POST PUT EVEN_NEW_ONES'.split(' ')
+    with tests.server_route(routes, request_count=len(cases) * 2) as uri:
+        for method in cases:
+            response, content = http.request(uri, method, body=b'q q')
+            assert response.status == 200
+            reflected = tests.HttpRequest.from_bytes(content)
+            assert reflected.method == 'GET'
+
+
+def test_etag_used():
+    # Test that we use ETags properly to validate our cache
+    cache_path = tests.get_cache_path()
+    http = httplib2.Http(cache=cache_path)
+    response_kwargs = dict(
+        add_date=True,
+        add_etag=True,
+        body=b'something',
+        headers={
+            'cache-control': 'public,max-age=300',
+        },
+    )
+
+    def handler(request):
+        if request.headers.get('range'):
+            return tests.http_response_bytes(status=206, **response_kwargs)
+        return tests.http_response_bytes(**response_kwargs)
+
+    with tests.server_request(handler, request_count=2) as uri:
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        assert response['etag'] == '"437b930db84b8079c2dd804a71936b5f"'
+
+        http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        response, _ = http.request(
+            uri, 'GET',
+            headers={'accept-encoding': 'identity', 'cache-control': 'must-revalidate'},
+        )
+        assert response.status == 200
+        assert response.fromcache
+
+        # TODO: API to read cache item, at least internal to tests
+        cache_file_name = os.path.join(cache_path, httplib2.safename(httplib2.urlnorm(uri)[-1]))
+        with open(cache_file_name, 'r') as f:
+            status_line = f.readline()
+        assert status_line.startswith("status:")
+
+        response, content = http.request(uri, 'HEAD', headers={'accept-encoding': 'identity'})
+        assert response.status == 200
+        assert response.fromcache
+
+        response, content = http.request(uri, 'GET', headers={'accept-encoding': 'identity', 'range': 'bytes=0-0'})
+        assert response.status == 206
+        assert not response.fromcache
+
+
+def test_etag_ignore():
+    # Test that we can forcibly ignore ETags
+    http = httplib2.Http(cache=tests.get_cache_path())
+    response_kwargs = dict(
+        add_date=True,
+        add_etag=True,
+    )
+    with tests.server_reflect(request_count=3, **response_kwargs) as uri:
+        response, content = http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        assert response.status == 200
+        assert response['etag'] != ""
+
+        response, content = http.request(
+            uri, 'GET',
+            headers={'accept-encoding': 'identity', 'cache-control': 'max-age=0'},
+        )
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert reflected.headers.get('if-none-match')
+
+        http.ignore_etag = True
+        response, content = http.request(
+            uri, 'GET',
+            headers={'accept-encoding': 'identity', 'cache-control': 'max-age=0'},
+        )
+        assert not response.fromcache
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert not reflected.headers.get('if-none-match')
+
+
+def test_etag_override():
+    # Test that we can forcibly ignore ETags
+    http = httplib2.Http(cache=tests.get_cache_path())
+    response_kwargs = dict(
+        add_date=True,
+        add_etag=True,
+    )
+    with tests.server_reflect(request_count=3, **response_kwargs) as uri:
+        response, _ = http.request(uri, 'GET', headers={'accept-encoding': 'identity'})
+        assert response.status == 200
+        assert response['etag'] != ''
+
+        response, content = http.request(
+            uri, 'GET',
+            headers={'accept-encoding': 'identity', 'cache-control': 'max-age=0'},
+        )
+        assert response.status == 200
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert reflected.headers.get('if-none-match')
+        assert reflected.headers.get('if-none-match') != 'fred'
+
+        response, content = http.request(
+            uri, 'GET',
+            headers={'accept-encoding': 'identity', 'cache-control': 'max-age=0', 'if-none-match': 'fred'},
+        )
+        assert response.status == 200
+        reflected = tests.HttpRequest.from_bytes(content)
+        assert reflected.headers.get('if-none-match') == 'fred'
+
+
+@pytest.mark.skip(reason='was commented in legacy code')
+def test_get_304_end_to_end():
+    pass
+    # Test that end to end headers get overwritten in the cache
+    # uri = urllib.parse.urljoin(base, "304/end2end.cgi")
+    # response, content = http.request(uri, 'GET')
+    # assertNotEqual(response['etag'], "")
+    # old_date = response['date']
+    # time.sleep(2)
+
+    # response, content = http.request(uri, 'GET', headers = {'Cache-Control': 'max-age=0'})
+    # # The response should be from the cache, but the Date: header should be updated.
+    # new_date = response['date']
+    # assert new_date != old_date
+    # assert response.status == 200
+    # assert response.fromcache == True
+
+
+def test_get_304_last_modified():
+    # Test that we can still handle a 304
+    # by only using the last-modified cache validator.
+    http = httplib2.Http(cache=tests.get_cache_path())
+    date = email.utils.formatdate()
+
+    def handler(read):
+        read()
+        yield tests.http_response_bytes(
+            status=200,
+            body=b'something',
+            headers={
+                'date': date,
+                'last-modified': date,
+            },
+        )
+
+        request2 = read()
+        assert request2.headers['if-modified-since'] == date
+        yield tests.http_response_bytes(status=304)
+
+    with tests.server_yield(handler, request_count=2) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.get('last-modified') == date
+
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        assert response.fromcache
+
+
+def test_get_307():
+    # Test that we do follow 307 redirects but
+    # do not cache the 307
+    http = httplib2.Http(cache=tests.get_cache_path(), timeout=1)
+    r307 = tests.http_response_bytes(
+        status=307,
+        headers={'location': '/final'},
+    )
+    r200 = tests.http_response_bytes(
+        status=200,
+        add_date=True,
+        body=b'final content\n',
+        headers={'cache-control': 'max-age=300'},
+    )
+
+    with tests.server_list_http([r307, r200, r307]) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.previous.status == 307
+        assert not response.previous.fromcache
+        assert response.status == 200
+        assert not response.fromcache
+        assert content == b'final content\n'
+
+        response, content = http.request(uri, 'GET')
+        assert response.previous.status == 307
+        assert not response.previous.fromcache
+        assert response.status == 200
+        assert response.fromcache
+        assert content == b'final content\n'
+
+
+def test_get_410():
+    # Test that we pass 410's through
+    http = httplib2.Http()
+    with tests.server_const_http(status=410) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 410
+
+
+def test_get_duplicate_headers():
+    # Test that duplicate headers get concatenated via ','
+    http = httplib2.Http()
+    response = b'''HTTP/1.0 200 OK\r\n\
+Link: link1\r\n\
+Content-Length: 7\r\n\
+Link: link2\r\n\r\n\
+content'''
+    with tests.server_const_bytes(response) as uri:
+        response, content = http.request(uri, 'GET')
+        assert response.status == 200
+        assert content == b"content"
+        assert response['link'], 'link1, link2'
diff --git a/tests/test_other.py b/tests/test_other.py
new file mode 100644
index 0000000..61b0d46
--- /dev/null
+++ b/tests/test_other.py
@@ -0,0 +1,180 @@
+import httplib2
+import mock
+import os
+import pickle
+import pytest
+import socket
+import sys
+import tests
+import time
+from six.moves import urllib
+
+
+@pytest.mark.skipif(
+    sys.version_info <= (3,),
+    reason='TODO: httplib2._convert_byte_str was defined only in python3 code version',
+)
+def test_convert_byte_str():
+    with tests.assert_raises(TypeError):
+        httplib2._convert_byte_str(4)
+    assert httplib2._convert_byte_str(b'Hello') == 'Hello'
+    assert httplib2._convert_byte_str('World') == 'World'
+
+
+def test_reflect():
+    http = httplib2.Http()
+    with tests.server_reflect() as uri:
+        response, content = http.request(uri + '?query', 'METHOD')
+    assert response.status == 200
+    host = urllib.parse.urlparse(uri).netloc
+    assert content.startswith('''\
+METHOD /?query HTTP/1.1\r\n\
+Host: {host}\r\n'''.format(host=host).encode()), content
+
+
+def test_pickle_http():
+    http = httplib2.Http(cache=tests.get_cache_path())
+    new_http = pickle.loads(pickle.dumps(http))
+
+    assert tuple(sorted(new_http.__dict__)) == tuple(sorted(http.__dict__))
+    assert new_http.credentials.credentials == http.credentials.credentials
+    assert new_http.certificates.credentials == http.certificates.credentials
+    assert new_http.cache.cache == http.cache.cache
+    for key in new_http.__dict__:
+        if key not in ('cache', 'certificates', 'credentials'):
+            assert getattr(new_http, key) == getattr(http, key)
+
+
+def test_pickle_http_with_connection():
+    http = httplib2.Http()
+    http.request('http://random-domain:81/', connection_type=tests.MockHTTPConnection)
+    new_http = pickle.loads(pickle.dumps(http))
+    assert tuple(http.connections) == ('http:random-domain:81',)
+    assert new_http.connections == {}
+
+
+def test_pickle_custom_request_http():
+    http = httplib2.Http()
+    http.request = lambda: None
+    http.request.dummy_attr = 'dummy_value'
+    new_http = pickle.loads(pickle.dumps(http))
+    assert getattr(new_http.request, 'dummy_attr', None) is None
+
+
+@pytest.mark.xfail(
+    sys.version_info >= (3,),
+    reason='FIXME: for unknown reason global timeout test fails in Python3 with response 200',
+)
+def test_timeout_global():
+    def handler(request):
+        time.sleep(0.5)
+        return tests.http_response_bytes()
+
+    try:
+        socket.setdefaulttimeout(0.1)
+    except Exception:
+        pytest.skip('cannot set global socket timeout')
+    try:
+        http = httplib2.Http()
+        http.force_exception_to_status_code = True
+        with tests.server_request(handler) as uri:
+            response, content = http.request(uri)
+            assert response.status == 408
+            assert response.reason.startswith("Request Timeout")
+    finally:
+        socket.setdefaulttimeout(None)
+
+
+def test_timeout_individual():
+    def handler(request):
+        time.sleep(0.5)
+        return tests.http_response_bytes()
+
+    http = httplib2.Http(timeout=0.1)
+    http.force_exception_to_status_code = True
+
+    with tests.server_request(handler) as uri:
+        response, content = http.request(uri)
+        assert response.status == 408
+        assert response.reason.startswith("Request Timeout")
+
+
+def test_timeout_https():
+    c = httplib2.HTTPSConnectionWithTimeout('localhost', 80, timeout=47)
+    assert 47 == c.timeout
+
+
+# @pytest.mark.xfail(
+#     sys.version_info >= (3,),
+#     reason='[py3] last request should open new connection, but client does not realize socket was closed by server',
+# )
+def test_connection_close():
+    http = httplib2.Http()
+    g = []
+
+    def handler(request):
+        g.append(request.number)
+        return tests.http_response_bytes(proto='HTTP/1.1')
+
+    with tests.server_request(handler, request_count=3) as uri:
+        http.request(uri, 'GET')  # conn1 req1
+        for c in http.connections.values():
+            assert c.sock is not None
+        http.request(uri, 'GET', headers={'connection': 'close'})
+        time.sleep(0.7)
+        http.request(uri, 'GET')  # conn2 req1
+    assert g == [1, 2, 1]
+
+
+def test_get_end2end_headers():
+    # one end to end header
+    response = {'content-type': 'application/atom+xml', 'te': 'deflate'}
+    end2end = httplib2._get_end2end_headers(response)
+    assert 'content-type' in end2end
+    assert 'te' not in end2end
+    assert 'connection' not in end2end
+
+    # one end to end header that gets eliminated
+    response = {'connection': 'content-type', 'content-type': 'application/atom+xml', 'te': 'deflate'}
+    end2end = httplib2._get_end2end_headers(response)
+    assert 'content-type' not in end2end
+    assert 'te' not in end2end
+    assert 'connection' not in end2end
+
+    # Degenerate case of no headers
+    response = {}
+    end2end = httplib2._get_end2end_headers(response)
+    assert len(end2end) == 0
+
+    # Degenerate case of connection referrring to a header not passed in
+    response = {'connection': 'content-type'}
+    end2end = httplib2._get_end2end_headers(response)
+    assert len(end2end) == 0
+
+
+@pytest.mark.xfail(
+    os.environ.get('TRAVIS_PYTHON_VERSION') in ('2.7', 'pypy'),
+    reason='FIXME: fail on Travis py27 and pypy, works elsewhere',
+)
+@pytest.mark.parametrize('scheme', ('http', 'https'))
+def test_ipv6(scheme):
+    # Even if IPv6 isn't installed on a machine it should just raise socket.error
+    uri = '{scheme}://[::1]:1/'.format(scheme=scheme)
+    try:
+        httplib2.Http(timeout=0.1).request(uri)
+    except socket.gaierror:
+        assert False, 'should get the address family right for IPv6'
+    except socket.error:
+        pass
+
+
+@pytest.mark.parametrize('conn_type', (httplib2.HTTPConnectionWithTimeout, httplib2.HTTPSConnectionWithTimeout))
+def test_connection_proxy_info_attribute_error(conn_type):
+    # HTTPConnectionWithTimeout did not initialize its .proxy_info attribute
+    # https://github.com/httplib2/httplib2/pull/97
+    # Thanks to Joseph Ryan https://github.com/germanjoey
+    conn = conn_type('no-such-hostname.', 80)
+    # TODO: replace mock with dummy local server
+    with tests.assert_raises(socket.gaierror):
+        with mock.patch('socket.socket.connect', side_effect=socket.gaierror):
+            conn.request('GET', '/')
diff --git a/tests/test_proxy.py b/tests/test_proxy.py
new file mode 100644
index 0000000..4007868
--- /dev/null
+++ b/tests/test_proxy.py
@@ -0,0 +1,92 @@
+'''Warning: these tests modify os.environ global state.
+Each test must be run in separate process.
+Must use pytest --forked or similar technique.
+'''
+import httplib2
+import mock
+import os
+import socket
+import tests
+
+
+def test_from_url():
+    pi = httplib2.proxy_info_from_url('http://myproxy.example.com')
+    assert pi.proxy_host == 'myproxy.example.com'
+    assert pi.proxy_port == 80
+    assert pi.proxy_user is None
+
+
+def test_from_url_ident():
+    pi = httplib2.proxy_info_from_url('http://zoidberg:fish@someproxy:99')
+    assert pi.proxy_host == 'someproxy'
+    assert pi.proxy_port == 99
+    assert pi.proxy_user == 'zoidberg'
+    assert pi.proxy_pass == 'fish'
+
+
+def test_from_env():
+    os.environ['http_proxy'] = 'http://myproxy.example.com:8080'
+    pi = httplib2.proxy_info_from_environment()
+    assert pi.proxy_host == 'myproxy.example.com'
+    assert pi.proxy_port == 8080
+
+
+def test_from_env_https():
+    os.environ['http_proxy'] = 'http://myproxy.example.com:80'
+    os.environ['https_proxy'] = 'http://myproxy.example.com:81'
+    pi = httplib2.proxy_info_from_environment('https')
+    assert pi.proxy_host == 'myproxy.example.com'
+    assert pi.proxy_port == 81
+
+
+def test_from_env_none():
+    os.environ.clear()
+    pi = httplib2.proxy_info_from_environment()
+    assert pi is None
+
+
+def test_applies_to():
+    os.environ['http_proxy'] = 'http://myproxy.example.com:80'
+    os.environ['https_proxy'] = 'http://myproxy.example.com:81'
+    os.environ['no_proxy'] = 'localhost,example.com,.wildcard'
+    pi = httplib2.proxy_info_from_environment()
+    assert not pi.applies_to('localhost')
+    assert pi.applies_to('www.google.com')
+    assert pi.applies_to('prefixlocalhost')
+    assert pi.applies_to('www.example.com')
+    assert pi.applies_to('sub.example.com')
+    assert not pi.applies_to('sub.wildcard')
+    assert not pi.applies_to('pub.sub.wildcard')
+
+
+def test_noproxy_trailing_comma():
+    os.environ['http_proxy'] = 'http://myproxy.example.com:80'
+    os.environ['no_proxy'] = 'localhost,other.host,'
+    pi = httplib2.proxy_info_from_environment()
+    assert not pi.applies_to('localhost')
+    assert not pi.applies_to('other.host')
+    assert pi.applies_to('example.domain')
+
+
+def test_noproxy_star():
+    os.environ['http_proxy'] = 'http://myproxy.example.com:80'
+    os.environ['NO_PROXY'] = '*'
+    pi = httplib2.proxy_info_from_environment()
+    for host in ('localhost', '169.254.38.192', 'www.google.com'):
+        assert not pi.applies_to(host)
+
+
+def test_headers():
+    headers = {'key0': 'val0', 'key1': 'val1'}
+    pi = httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_HTTP, 'localhost', 1234, proxy_headers=headers)
+    assert pi.proxy_headers == headers
+
+
+def test_github_100_socks_basestring():
+    # https://github.com/httplib2/httplib2/pull/100
+    # NameError: name 'basestring' is not defined
+    # TODO: replace invalid address with dummy local server
+    http = httplib2.Http(proxy_info=httplib2.ProxyInfo(httplib2.socks.PROXY_TYPE_HTTP, '255.255.255.255', 8001))
+    with tests.assert_raises(httplib2.ServerNotFoundError):
+        with mock.patch('socket.socket.connect', side_effect=socket.gaierror):
+            http.request('http://255.255.255.255/', 'GET')
diff --git a/tests/test_uri.py b/tests/test_uri.py
new file mode 100644
index 0000000..3ed3b74
--- /dev/null
+++ b/tests/test_uri.py
@@ -0,0 +1,78 @@
+import httplib2
+
+
+def test_from_std66():
+    cases = (
+        ('http://example.com',
+            ('http', 'example.com', '', None, None)),
+        ('https://example.com',
+            ('https', 'example.com', '', None, None)),
+        ('https://example.com:8080',
+            ('https', 'example.com:8080', '', None, None)),
+        ('http://example.com/',
+            ('http', 'example.com', '/', None, None)),
+        ('http://example.com/path',
+            ('http', 'example.com', '/path', None, None)),
+        ('http://example.com/path?a=1&b=2',
+            ('http', 'example.com', '/path', 'a=1&b=2', None)),
+        ('http://example.com/path?a=1&b=2#fred',
+            ('http', 'example.com', '/path', 'a=1&b=2', 'fred')),
+        ('http://example.com/path?a=1&b=2#fred',
+            ('http', 'example.com', '/path', 'a=1&b=2', 'fred')),
+    )
+    for a, b in cases:
+        assert httplib2.parse_uri(a) == b
+
+
+def test_norm():
+    cases = (
+        ('http://example.org',
+            'http://example.org/'),
+        ('http://EXAMple.org',
+            'http://example.org/'),
+        ('http://EXAMple.org?=b',
+            'http://example.org/?=b'),
+        ('http://EXAMple.org/mypath?a=b',
+            'http://example.org/mypath?a=b'),
+        ('http://localhost:80',
+            'http://localhost:80/'),
+    )
+    for a, b in cases:
+        assert httplib2.urlnorm(a)[-1] == b
+
+    assert httplib2.urlnorm('http://localhost:80/') == httplib2.urlnorm('HTTP://LOCALHOST:80')
+
+    try:
+        httplib2.urlnorm('/')
+        assert False, 'Non-absolute URIs should raise an exception'
+    except httplib2.RelativeURIError:
+        pass
+
+
+def test_safename():
+    cases = (
+        ('http://example.org/fred/?a=b',
+            'example.org,fred,a=b,58489f63a7a83c3b7794a6a398ee8b1f'),
+        ('http://example.org/fred?/a=b',
+            'example.org,fred,a=b,8c5946d56fec453071f43329ff0be46b'),
+        ('http://www.example.org/fred?/a=b',
+            'www.example.org,fred,a=b,499c44b8d844a011b67ea2c015116968'),
+        ('https://www.example.org/fred?/a=b',
+            'www.example.org,fred,a=b,692e843a333484ce0095b070497ab45d'),
+        (httplib2.urlnorm('http://WWW')[-1],
+            httplib2.safename(httplib2.urlnorm('http://www')[-1])),
+        (u'http://\u2304.org/fred/?a=b',
+            'xn--http,-4y1d.org,fred,a=b,579924c35db315e5a32e3d9963388193'),
+    )
+    for a, b in cases:
+        assert httplib2.safename(a) == b
+
+    assert httplib2.safename('http://www') != httplib2.safename('https://www')
+
+    # Test the max length limits
+    uri = 'http://' + ('w' * 200) + '.org'
+    uri2 = 'http://' + ('w' * 201) + '.org'
+    assert httplib2.safename(uri) != httplib2.safename(uri2)
+    # Max length should be 200 + 1 (',') + 32
+    assert len(httplib2.safename(uri2)) == 233
+    assert len(httplib2.safename(uri)) == 233