diff --git a/.gitignore b/.gitignore index d94e7a3..7ef79eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,5 @@ *.swp *.swo -*.pyc +browsermob_proxy.egg-info/ +browsermobproxy/ dist/ -build/ -*.egg-info/ -.cache/ -bmp.log -.idea/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bbf3b74..0000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: python - -jdk: - - oraclejdk8 - -addons: - apt: - packages: - - oracle-java8-installer - - oracle-java8-set-default - - google-chrome-stable - -sudo: false -python: - - 2.6 - - 2.7 - - 3.3 - - 3.4 - - 3.5 -before_script: - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start - - ./bootstrap.sh - - ./start-servers.sh - - sleep 5 -install: pip install pytest selenium -script: python setup.py develop && py.test test -sudo: false -dist: trusty diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 67054d2..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,35 +0,0 @@ -# How to Contribute - -Firstly, thanks for wanting to contribute back to this project. Below are -guidelines that should hopefully minimise the amount of backwards and forwards -in the review process. - -## Getting Started - -* Fork the repository on GitHub - well... duh :P -* Create a virtualenv: `virtualenv venv` -* Activate the virtualenv: `. venv/bin/activate` -* Install the package in develop mode: `python setup.py develop` -* Install requirements: `pip install -r requirements.txt` -* Run the tests to check that everything was successful: `py.test tests` - -## Making Changes - -* Create a topic branch from where you want to base your work. - * This is usually the master branch. - * Only target release branches if you are certain your fix must be on that - branch. - * To quickly create a topic branch based on master; `git checkout -b - /my_contribution master`. Please avoid working directly on the - `master` branch. -* Make commits of logical units. -* Check for unnecessary whitespace with `git diff --check` before committing. -* Make sure you have added the necessary tests for your changes. -* Run _all_ the tests to assure nothing else was accidentally broken. - -## Submitting Changes - -* Push your changes to a topic branch in your fork of the repository. -* Submit a pull request to the main repository -* After feedback has been given we expect responses within two weeks. After two - weeks will may close the pull request if it isn't showing any activity. diff --git a/History.md b/History.md deleted file mode 100644 index 0af158b..0000000 --- a/History.md +++ /dev/null @@ -1,123 +0,0 @@ - -0.8.0 / 2017-02-07 -================== - - * Adds rewrite rules clear api. Fixes content type for request/response intercept and adds doc links for writing intercept code. Adds comments clarifying intercept client test coverage. Augments human test for url rewrite and adds clear portion. Adds test for response intercept. Adds bootstrap script to download tools to test with. Refactors human tests so browser session are cleaned up when tests fail and tests run with chromium. Adds server start script for travis. Changes .travis.yml to use provided scripts and also run headless chrome. - * If the JSON doesn't load, it's likely because the user has another server running on the same port. Improve the error message here so can figure out what's going on more easily. - * Inherit from Exception as StandardError was removed in Python 3 - * Add ProxyServerError and raise it instead of Exception - * Fix docstring for limits() - * Fix path join issue: log_path_name would be /server.log - * Make default option values more robust - * Add retry sleep and count in options - * Reenabling timeout tests as they have been fixed in B6 of the server - * Removing duplicate method. Fixes #41 - * docstrings cleanup - * configurable log file - * added title options for new har and new har page - * replaced mutable default values with None - * Update Requests dependency version - * Updating supported Python versions - * Disabling a test due to BMP Server bug - * Bumping version number of BMP server used in testing - * Add bmp.log to .gitignore - * Add details on how to contribute - * Updating response URL endpoints to use filter - * Ignoring .cache directory - * Change remap_hosts to accept dictionary - * Make sure the process is still running while waiting for the server to start. - * Changed hostmap to be a named argument for compatibility - * Merge remote-tracking branch 'upstream/master' into patch-1 - * Add the ability to empty the DNS cache - * Correct function name - * Add the ability to return all active proxy ports from Browsermob - * switch to Travis container setup - * Update to latest browsermob proxy release for testing - * Correct exception typo - * Update remap_hosts test - * Fix whitespace - * Let remap_hosts accept a dictionary - * Upgrading Travis to it's container system - * bumping to 0.7.1 - -0.7.1 / 2015-07-09 -================== - - * Adding option of using existing proxy port. - * Allow use of a remote proxy server. - * improved directions on running tests - * fix broken test (test_new_page_defaults) - -0.7.0 / 2015-06-05 -================== - - * Updating travis ci to use browsermob proxy 2.0 - * Support to use httpsProxy and httpProxy at proxy creation time - * Adding Python 3 support - * add sslProxy to Client.add_to_capabilities with tests - * Correct docstring for `wait_for_traffic_to_stop` - * Removing unused :Args: items - * Updating docstrings - * Correcting args and params for documentation - * updated docstrings for easier formatting on things like RTDs - * updated new_har() docstrings - * updated client documentation - * Added client and server docs - * updating version in docs - -0.6.0 / 2014-01-21 -================== - - * Added support for parameters in har creation - * Bug fixes for tests that are out of date - * Setup server constructor to look on path for location of browsermob-proxy executable. As well as looking for a file. Also added example code for using browsermob-proxy with chrome - * Fix project name - * adding docs - -0.5.0 / 2013-05-23 -================== -* Allow proxying of ssl requests with selenium. -* Updating case for proxy type - - -0.4.0 / 2013-03-06 -================== - - * Allow setting basic authentication - * Adding the ability to remap hosts which is available from BrowserMob Proxy Beta 7 - * Merge pull request #6 from lukeis/patch-2 - * Update readme.md - * initial commit of event listener to auto do record - * server.create_proxy is a function, should be called :) - * forgot to add the port - -0.2.0 / 2012-06-18 -================== - - * pep8 --ignore=E501 - * DELETE /proxy/:port/ - * /proxy/:port/limits - * /proxy/:port/blacklist - * /proxy/:port/whitelist - * fixing /proxy/:port/har/pageRef - * fixing /proxy/:port/har/pageRef - * fixing passing in a page ref as the name for the page in /proxy/:port/har - * tests around /proxy/:port/har and some cleanup of the implementation - * make /proxy/:port/headers work - * wrapping selenium_proxy with webdriver_proxy since the project is more than just webdriver - * extending the client to play nice with remote webdriver instances - * create_proxy sounds and feels like a method to me, let's make it so - * ensure the self.process exist, to reduce possibilities of AttributeError - * check the path before attempting to start the server - * wait longer than 3 seconds for the server to come up - -0.1.0 / 2012-03-22 -================== - -* Removed httplib2 in preference for requests -* Added support for setting headers - -0.0.1 / 2012-01-16 -================== - -* Initial version diff --git a/bootstrap.sh b/bootstrap.sh deleted file mode 100755 index d6be4a9..0000000 --- a/bootstrap.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -if [ "$(uname)" == "Darwin" ]; then - echo "We're on a MAC!" - chromeDriver="chromedriver_mac64.zip" - geckoDriverVersion="v0.13.0" - geckoDriver="geckodriver-$geckoDriverVersion-macos.tar.gz" -else - echo "We're not on a MAC!" - chromeDriver="chromedriver_linux64.zip" - geckoDriverVersion="v0.14.0" - geckoDriver="geckodriver-$geckoDriverVersion-linux64.tar.gz" -fi -rm -rf tools -mkdir -p tools && \ -cd tools && \ -wget https://github.com/lightbody/browsermob-proxy/releases/download/browsermob-proxy-2.1.4/browsermob-proxy-2.1.4-bin.zip && \ -unzip -o browsermob-proxy-2.1.4-bin.zip && \ -rm -rf browsermob-proxy*.zip* && \ -wget http://selenium-release.storage.googleapis.com/3.0/selenium-server-standalone-3.0.1.jar && \ -wget https://github.com/mozilla/geckodriver/releases/download/${geckoDriverVersion}/${geckoDriver} && \ -tar zxf ${geckoDriver} && \ -rm -rf ${geckoDriver}* && \ -wget https://chromedriver.storage.googleapis.com/2.27/${chromeDriver} && \ -unzip ${chromeDriver} && \ -rm -rf ${chromeDriver}* && \ -cd .. diff --git a/browsermobproxy/__init__.py b/browsermobproxy/__init__.py deleted file mode 100644 index ea3d46f..0000000 --- a/browsermobproxy/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -__version__ = '0.5.0' - -from .server import RemoteServer, Server -from .client import Client - -__all__ = ['RemoteServer', 'Server', 'Client', 'browsermobproxy'] diff --git a/browsermobproxy/client.py b/browsermobproxy/client.py deleted file mode 100644 index 8a3dd3b..0000000 --- a/browsermobproxy/client.py +++ /dev/null @@ -1,359 +0,0 @@ -import requests - -try: - from urllib.parse import urlencode, unquote -except ImportError: - from urllib import urlencode, unquote -import json - - -class Client(object): - def __init__(self, url, params=None, options=None): - """ - Initialises a new Client object - - - :param url: This is where the BrowserMob Proxy lives - :param params: URL query (for example httpProxy and httpsProxy vars) - :param options: Dictionary that can contain the port of an existing - proxy to use (for example 'existing_proxy_port_to_use') - """ - params = params if params is not None else {} - options = options if options is not None else {} - self.host = "http://" + url - if params: - urlparams = "?" + unquote(urlencode(params)) - else: - urlparams = "" - if 'existing_proxy_port_to_use' in options: - self.port = options['existing_proxy_port_to_use'] - else: - resp = requests.post('%s/proxy' % self.host + urlparams) - content = resp.content.decode('utf-8') - try: - jcontent = json.loads(content) - except Exception as e: - raise Exception("Could not read Browsermob-Proxy json\n" - "Another server running on this port?\n%s..." % content[:512]) - self.port = jcontent['port'] - url_parts = self.host.split(":") - self.proxy = url_parts[1][2:] + ":" + str(self.port) - - def close(self): - """ - shuts down the proxy and closes the port - """ - r = requests.delete('%s/proxy/%s' % (self.host, self.port)) - return r.status_code - - # webdriver integration - # ...as a proxy object - def selenium_proxy(self): - """ - Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy - """ - from selenium import webdriver - return webdriver.Proxy({ - "httpProxy": self.proxy, - "sslProxy": self.proxy, - }) - - def webdriver_proxy(self): - """ - Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy - """ - return self.selenium_proxy() - - # ...as a capability - def add_to_capabilities(self, capabilities): - """ - Adds an 'proxy' entry to a desired capabilities dictionary with the - BrowserMob proxy information - - - :param capabilities: The Desired capabilities object from Selenium WebDriver - """ - capabilities['proxy'] = { - 'proxyType': "MANUAL", - 'httpProxy': self.proxy, - 'sslProxy': self.proxy - } - - def add_to_webdriver_capabilities(self, capabilities): - self.add_to_capabilities(capabilities) - - # browsermob proxy api - @property - def proxy_ports(self): - """ - Return a list of proxy ports available - """ - # r should look like {u'proxyList': [{u'port': 8081}]} - r = requests.get('%s/proxy' % self.host).json() - ports = [port['port'] for port in r['proxyList']] - - return ports - - @property - def har(self): - """ - Gets the HAR that has been recorded - """ - r = requests.get('%s/proxy/%s/har' % (self.host, self.port)) - - return r.json() - - def new_har(self, ref=None, options=None, title=None): - """ - This sets a new HAR to be recorded - - :param str ref: A reference for the HAR. Defaults to None - :param dict options: A dictionary that will be passed to BrowserMob - Proxy with specific keywords. Keywords are: - - - captureHeaders: Boolean, capture headers - - captureContent: Boolean, capture content bodies - - captureBinaryContent: Boolean, capture binary content - - :param str title: the title of first har page. Defaults to ref. - """ - options = options if options is not None else {} - payload = {"initialPageRef": ref} if ref is not None else {} - if title is not None: - payload.update({'initialPageTitle': title}) - - if options: - payload.update(options) - - r = requests.put('%s/proxy/%s/har' % (self.host, self.port), payload) - if r.status_code == 200: - return (r.status_code, r.json()) - else: - return (r.status_code, None) - - def new_page(self, ref=None, title=None): - """ - This sets a new page to be recorded - - :param str ref: A reference for the new page. Defaults to None - :param str title: the title of new har page. Defaults to ref. - """ - payload = {"pageRef": ref} if ref is not None else {} - if title is not None: - payload.update({'pageTitle': title}) - r = requests.put('%s/proxy/%s/har/pageRef' % (self.host, self.port), - payload) - return r.status_code - - def blacklist(self, regexp, status_code): - """ - Sets a list of URL patterns to blacklist - - :param str regex: a comma separated list of regular expressions - :param int status_code: the HTTP status code to return for URLs - that do not match the blacklist - """ - r = requests.put('%s/proxy/%s/blacklist' % (self.host, self.port), - {'regex': regexp, 'status': status_code}) - return r.status_code - - def whitelist(self, regexp, status_code): - """ - Sets a list of URL patterns to whitelist - - :param str regex: a comma separated list of regular expressions - :param int status_code: the HTTP status code to return for URLs - that do not match the whitelist - """ - r = requests.put('%s/proxy/%s/whitelist' % (self.host, self.port), - {'regex': regexp, 'status': status_code}) - return r.status_code - - def basic_authentication(self, domain, username, password): - """ - This add automatic basic authentication - - :param str domain: domain to set authentication credentials for - :param str username: valid username to use when authenticating - :param str password: valid password to use when authenticating - """ - r = requests.post(url='%s/proxy/%s/auth/basic/%s' % (self.host, self.port, domain), - data=json.dumps({'username': username, 'password': password}), - headers={'content-type': 'application/json'}) - return r.status_code - - def headers(self, headers): - """ - This sets the headers that will set by the proxy on all requests - - :param dict headers: this is a dictionary of the headers to be set - """ - if not isinstance(headers, dict): - raise TypeError("headers needs to be dictionary") - - r = requests.post(url='%s/proxy/%s/headers' % (self.host, self.port), - data=json.dumps(headers), - headers={'content-type': 'application/json'}) - return r.status_code - - def response_interceptor(self, js): - """ - Executes the java/js code against each response - `HttpRequest request `_, - `HttpMessageContents contents `_, - `HttpMessageInfo messageInfo `_ - are available objects to interact with. - :param str js: the js/java code to execute - """ - r = requests.post(url='%s/proxy/%s/filter/response' % (self.host, self.port), - data=js, - headers={'content-type': 'text/plain'}) - return r.status_code - - def request_interceptor(self, js): - """ - Executes the java/js code against each response - `HttpRequest request `_, - `HttpMessageContents contents `_, - `HttpMessageInfo messageInfo `_ - are available objects to interact with. - :param str js: the js/java code to execute - """ - r = requests.post(url='%s/proxy/%s/filter/request' % (self.host, self.port), - data=js, - headers={'content-type': 'text/plain'}) - return r.status_code - - LIMITS = { - 'upstream_kbps': 'upstreamKbps', - 'downstream_kbps': 'downstreamKbps', - 'latency': 'latency' - } - - def limits(self, options): - """ - Limit the bandwidth through the proxy. - - :param dict options: A dictionary with all the details you want to set. - downstream_kbps - Sets the downstream kbps - upstream_kbps - Sets the upstream kbps - latency - Add the given latency to each HTTP request - """ - params = {} - - for (k, v) in list(options.items()): - if k not in self.LIMITS: - raise KeyError('invalid key: %s' % k) - - params[self.LIMITS[k]] = int(v) - - if len(list(params.items())) == 0: - raise KeyError("You need to specify one of the valid Keys") - - r = requests.put('%s/proxy/%s/limit' % (self.host, self.port), - params) - return r.status_code - - TIMEOUTS = { - 'request': 'requestTimeout', - 'read': 'readTimeout', - 'connection': 'connectionTimeout', - 'dns': 'dnsCacheTimeout' - } - - def timeouts(self, options): - """ - Configure various timeouts in the proxy - - :param dict options: A dictionary with all the details you want to set. - request - request timeout (in seconds) - read - read timeout (in seconds) - connection - connection timeout (in seconds) - dns - dns lookup timeout (in seconds) - """ - params = {} - - for (k, v) in list(options.items()): - if k not in self.TIMEOUTS: - raise KeyError('invalid key: %s' % k) - - params[self.TIMEOUTS[k]] = int(v) - - if len(list(params.items())) == 0: - raise KeyError("You need to specify one of the valid Keys") - - r = requests.put('%s/proxy/%s/timeout' % (self.host, self.port), - params) - return r.status_code - - def remap_hosts(self, address=None, ip_address=None, hostmap=None): - """ - Remap the hosts for a specific URL - - :param str address: url that you wish to remap - :param str ip_address: IP Address that will handle all traffic for - the address passed in - :param **hostmap: Other hosts to be added as keyword arguments - """ - hostmap = hostmap if hostmap is not None else {} - if (address is not None and ip_address is not None): - hostmap[address] = ip_address - - r = requests.post('%s/proxy/%s/hosts' % (self.host, self.port), - json.dumps(hostmap), - headers={'content-type': 'application/json'}) - return r.status_code - - def wait_for_traffic_to_stop(self, quiet_period, timeout): - """ - Waits for the network to be quiet - - :param int quiet_period: number of milliseconds the network needs - to be quiet for - :param int timeout: max number of milliseconds to wait - """ - r = requests.put('%s/proxy/%s/wait' % (self.host, self.port), - {'quietPeriodInMs': quiet_period, 'timeoutInMs': timeout}) - return r.status_code - - def clear_dns_cache(self): - """ - Clears the DNS cache associated with the proxy instance - """ - r = requests.delete('%s/proxy/%s/dns/cache' % (self.host, self.port)) - return r.status_code - - def rewrite_url(self, match, replace): - """ - Rewrites the requested url. - - :param match: a regex to match requests with - :param replace: unicode \ - a string to replace the matches with - """ - params = { - "matchRegex": match, - "replace": replace - } - r = requests.put('%s/proxy/%s/rewrite' % (self.host, self.port), - params) - return r.status_code - - def clear_all_rewrite_url_rules(self): - """ - Clears all URL rewrite rules - :return: status code - """ - - r = requests.delete('%s/proxy/%s/rewrite' % (self.host, self.port)) - return r.status_code - - def retry(self, retry_count): - """ - Retries. No idea what its used for, but its in the API... - - :param int retry_count: the number of retries - """ - r = requests.put('%s/proxy/%s/retry' % (self.host, self.port), - {'retrycount': retry_count}) - return r.status_code diff --git a/browsermobproxy/exceptions.py b/browsermobproxy/exceptions.py deleted file mode 100644 index c2d6d8d..0000000 --- a/browsermobproxy/exceptions.py +++ /dev/null @@ -1,2 +0,0 @@ -class ProxyServerError(Exception): - pass diff --git a/browsermobproxy/server.py b/browsermobproxy/server.py deleted file mode 100644 index a61e1a0..0000000 --- a/browsermobproxy/server.py +++ /dev/null @@ -1,164 +0,0 @@ -import os -import platform -import signal -import socket -import subprocess -import time - -import sys - -from .client import Client -from .exceptions import ProxyServerError - - -class RemoteServer(object): - - def __init__(self, host, port): - """ - Initialises a RemoteServer object - - :param host: The host of the proxy server. - :param port: The port of the proxy server. - """ - self.host = host - self.port = port - - @property - def url(self): - """ - Gets the url that the proxy is running on. This is not the URL clients - should connect to. - """ - return "http://%s:%d" % (self.host, self.port) - - def create_proxy(self, params=None): - """ - Gets a client class that allow to set all the proxy details that you - may need to. - - :param dict params: Dictionary where you can specify params - like httpProxy and httpsProxy - """ - params = params if params is not None else {} - client = Client(self.url[7:], params) - return client - - def _is_listening(self): - try: - socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - socket_.settimeout(1) - socket_.connect((self.host, self.port)) - socket_.close() - return True - except socket.error: - return False - - -class Server(RemoteServer): - - def __init__(self, path='browsermob-proxy', options=None): - """ - Initialises a Server object - - :param str path: Path to the browsermob proxy batch file - :param dict options: Dictionary that can hold the port. - More items will be added in the future. - This defaults to an empty dictionary - """ - self.win_env = sys.platform == "win32" - - options = options if options is not None else {} - - path_var_sep = ':' - if platform.system() == 'Windows': - path_var_sep = ';' - if not path.endswith('.bat'): - path += '.bat' - - exec_not_on_path = True - for directory in os.environ['PATH'].split(path_var_sep): - if(os.path.isfile(os.path.join(directory, path))): - exec_not_on_path = False - break - - if not os.path.isfile(path) and exec_not_on_path: - raise ProxyServerError("Browsermob-Proxy binary couldn't be found " - "in path provided: %s" % path) - - self.path = path - self.host = options.get('host', 'localhost') - self.port = options.get('port', 8080) - self.process = None - - if platform.system() == 'Darwin': - self.command = ['sh'] - else: - self.command = [] - self.command += [path, '--port=%s' % self.port] - - def start(self, options=None): - """ - This will start the browsermob proxy and then wait until it can - interact with it - - :param dict options: Dictionary that can hold the path and filename - of the log file with resp. keys of `log_path` and `log_file` - """ - if options is None: - options = {} - log_path = options.get('log_path', os.getcwd()) - log_file = options.get('log_file', 'server.log') - retry_sleep = options.get('retry_sleep', 0.5) - retry_count = options.get('retry_count', 60) - log_path_name = os.path.join(log_path, log_file) - self.log_file = open(log_path_name, 'w') - - if self.win_env: - self.process = self._start_on_windows() - else: - self.process = self._start_on_unix() - - count = 0 - while not self._is_listening(): - if self.process.poll(): - message = ( - "The Browsermob-Proxy server process failed to start. " - "Check {0}" - "for a helpful error message.".format(self.log_file)) - - raise ProxyServerError(message) - time.sleep(retry_sleep) - count += 1 - if count == retry_count: - self.stop() - raise ProxyServerError("Can't connect to Browsermob-Proxy") - - def _start_on_windows(self): - return subprocess.Popen(self.command, - creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, - stdout=self.log_file, - stderr=subprocess.STDOUT) - - def _start_on_unix(self): - return subprocess.Popen(self.command, - preexec_fn=os.setsid, - stdout=self.log_file, - stderr=subprocess.STDOUT) - - def stop(self): - """ - This will stop the process running the proxy - """ - if self.process.poll() is not None: - return - - group_pid = os.getpgid(self.process.pid) if not self.win_env else self.process.pid - try: - self.process.kill() - self.process.wait() - os.killpg(group_pid, signal.SIGINT) - except AttributeError: - # kill may not be available under windows environment - pass - - self.log_file.close() diff --git a/browsermobproxy/webdriver_event_listener.py b/browsermobproxy/webdriver_event_listener.py deleted file mode 100644 index 2405ada..0000000 --- a/browsermobproxy/webdriver_event_listener.py +++ /dev/null @@ -1,35 +0,0 @@ -from selenium.webdriver.support.abstract_event_listener import AbstractEventListener - -class WebDriverEventListener(AbstractEventListener): - - def __init__(self, client, refs=None): - refs = refs if refs is not None else {} - self.client = client - self.hars = [] - self.refs = refs - - def before_navigate_to(self, url, driver): - if len(self.hars) != 0: - self.hars.append(self.client.har) - self.client.new_har("navigate-to-%s" % url, self.refs) - - def before_navigate_back(self, driver=None): - if driver: - name = "-from-%s" % driver.current_url - else: - name = "navigate-back" - self.client.new_page(name) - - def before_navigate_forward(self, driver=None): - if driver: - name = "-from-%s" % driver.current_url - else: - name = "navigate-forward" - self.client.new_page(name) - - def before_click(self, element, driver): - name = "click-element-%s" % element.id - self.client.new_page(name) - - def before_quit(self, driver): - self.hars.append(self.client.har) diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 554b2a7..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/BrowserMobProxy.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/BrowserMobProxy.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/BrowserMobProxy" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/BrowserMobProxy" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/_build/doctrees/client.doctree b/docs/_build/doctrees/client.doctree deleted file mode 100644 index 9cbc638..0000000 Binary files a/docs/_build/doctrees/client.doctree and /dev/null differ diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle deleted file mode 100644 index 93a39d3..0000000 Binary files a/docs/_build/doctrees/environment.pickle and /dev/null differ diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree deleted file mode 100644 index 52ae2bd..0000000 Binary files a/docs/_build/doctrees/index.doctree and /dev/null differ diff --git a/docs/_build/doctrees/server.doctree b/docs/_build/doctrees/server.doctree deleted file mode 100644 index 1e4b051..0000000 Binary files a/docs/_build/doctrees/server.doctree and /dev/null differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo deleted file mode 100644 index 9274f43..0000000 --- a/docs/_build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 22346719ac3713bfe792fb5638c0a301 -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/_modules/browsermobproxy.html b/docs/_build/html/_modules/browsermobproxy.html deleted file mode 100644 index d3b83c2..0000000 --- a/docs/_build/html/_modules/browsermobproxy.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - browsermobproxy — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - - -
-
-
-
- -

Source code for browsermobproxy

-__version__ = '0.5.0'
-
-from server import Server
-from client import Client
-
-__all__ = ['Server', 'Client', 'browsermobproxy']
-
- -
-
-
-
-
- - -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/_modules/index.html b/docs/_build/html/_modules/index.html deleted file mode 100644 index 5650bd3..0000000 --- a/docs/_build/html/_modules/index.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - Overview: module code — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - -
-
-
-
- -

All modules for which code is available

- - -
-
-
-
-
- - -
-
-
-
- - - - \ No newline at end of file diff --git a/docs/_build/html/_sources/client.txt b/docs/_build/html/_sources/client.txt deleted file mode 100644 index 95c74fa..0000000 --- a/docs/_build/html/_sources/client.txt +++ /dev/null @@ -1,8 +0,0 @@ -.. toctree:: - :maxdepth: 2 - -:mod:`client` Package ---------------------- -.. automodule:: browsermobproxy -.. autoclass:: Client - :members: diff --git a/docs/_build/html/_sources/index.txt b/docs/_build/html/_sources/index.txt deleted file mode 100644 index 0a568cf..0000000 --- a/docs/_build/html/_sources/index.txt +++ /dev/null @@ -1,72 +0,0 @@ -.. BrowserMob Proxy documentation master file, created by - sphinx-quickstart on Fri May 24 12:37:12 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. -.. highlightlang:: python - - - -Welcome to BrowserMob Proxy's documentation! -============================================ - -Python client for the BrowserMob Proxy 2.0 REST API. - -How to install --------------- - -BrowserMob Proxy is available on PyPI_, so you can install it with ``pip``:: - - $ pip install browsermob-proxy - -Or with `easy_install`:: - - $ easy_install browsermob-proxy - -Or by cloning the repo from GitHub_:: - - $ git clone git://github.com/AutomatedTester/browsermob-proxy-py.git - -Then install it by running:: - - $ python setup.py install - -How to use with selenium-webdriver ----------------------------------- - -Manually:: - - from browsermobproxy import Server - server = Server("path/to/browsermob-proxy") - server.start() - proxy = server.create_proxy() - - from selenium import webdriver - profile = webdriver.FirefoxProfile() - profile.set_proxy(proxy.selenium_proxy()) - driver = webdriver.Firefox(firefox_profile=profile) - - - proxy.new_har("google") - driver.get("http://www.google.co.uk") - proxy.har # returns a HAR JSON blob - - server.stop() - driver.quit() - -Contents: - -.. toctree:: - :maxdepth: 2 - - client.rst - server.rst - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. _GitHub: https://github.com/AutomatedTester/browsermob-proxy-py -.. _PyPI: http://pypi.python.org/pypi/browsermob-proxy diff --git a/docs/_build/html/_sources/server.txt b/docs/_build/html/_sources/server.txt deleted file mode 100644 index 8af94b7..0000000 --- a/docs/_build/html/_sources/server.txt +++ /dev/null @@ -1,8 +0,0 @@ -.. toctree:: - :maxdepth: 2 - -:mod:`server` Package ---------------------- -.. automodule:: browsermobproxy -.. autoclass:: Server - :members: \ No newline at end of file diff --git a/docs/_build/html/_static/ajax-loader.gif b/docs/_build/html/_static/ajax-loader.gif deleted file mode 100644 index 61faf8c..0000000 Binary files a/docs/_build/html/_static/ajax-loader.gif and /dev/null differ diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css deleted file mode 100644 index c959cf0..0000000 --- a/docs/_build/html/_static/basic.css +++ /dev/null @@ -1,537 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- 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; -} - -div.sphinxsidebar #searchbox input[type="text"] { - width: 170px; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - width: 30px; -} - -img { - border: 0; - max-width: 100%; -} - -/* -- 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 { - width: 100%; -} - -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; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- 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; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- 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 5px; - 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; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -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, .highlighted { - 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; -} - -.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; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -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; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- 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; - } -} \ No newline at end of file diff --git a/docs/_build/html/_static/comment-bright.png b/docs/_build/html/_static/comment-bright.png deleted file mode 100644 index 551517b..0000000 Binary files a/docs/_build/html/_static/comment-bright.png and /dev/null differ diff --git a/docs/_build/html/_static/comment-close.png b/docs/_build/html/_static/comment-close.png deleted file mode 100644 index 09b54be..0000000 Binary files a/docs/_build/html/_static/comment-close.png and /dev/null differ diff --git a/docs/_build/html/_static/comment.png b/docs/_build/html/_static/comment.png deleted file mode 100644 index 92feb52..0000000 Binary files a/docs/_build/html/_static/comment.png and /dev/null differ diff --git a/docs/_build/html/_static/default.css b/docs/_build/html/_static/default.css deleted file mode 100644 index e534a07..0000000 --- a/docs/_build/html/_static/default.css +++ /dev/null @@ -1,256 +0,0 @@ -/* - * default.css_t - * ~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- default theme. - * - * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@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; -} - - - -/* -- hyperlink styles ------------------------------------------------------ */ - -a { - color: #355f7c; - text-decoration: none; -} - -a:visited { - color: #355f7c; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - - - -/* -- body styles ----------------------------------------------------------- */ - -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.admonition p { - margin-bottom: 5px; -} - -div.admonition pre { - margin-bottom: 5px; -} - -div.admonition ul, div.admonition ol { - margin-bottom: 5px; -} - -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; -} - -th { - background-color: #ede; -} - -.warning tt { - background: #efc2c2; -} - -.note tt { - background: #d6d6d6; -} - -.viewcode-back { - font-family: sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} \ No newline at end of file diff --git a/docs/_build/html/_static/doctools.js b/docs/_build/html/_static/doctools.js deleted file mode 100644 index 2036e5f..0000000 --- a/docs/_build/html/_static/doctools.js +++ /dev/null @@ -1,238 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * 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; -}; - -/** - * 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(node.parentNode).hasClass(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.initIndexTable(); - }, - - /** - * 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 safely 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() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - 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'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('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_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * 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/docs/_build/html/_static/down-pressed.png b/docs/_build/html/_static/down-pressed.png deleted file mode 100644 index 6f7ad78..0000000 Binary files a/docs/_build/html/_static/down-pressed.png and /dev/null differ diff --git a/docs/_build/html/_static/down.png b/docs/_build/html/_static/down.png deleted file mode 100644 index 3003a88..0000000 Binary files a/docs/_build/html/_static/down.png and /dev/null differ diff --git a/docs/_build/html/_static/file.png b/docs/_build/html/_static/file.png deleted file mode 100644 index d18082e..0000000 Binary files a/docs/_build/html/_static/file.png and /dev/null differ diff --git a/docs/_build/html/_static/jquery.js b/docs/_build/html/_static/jquery.js deleted file mode 100644 index 3883779..0000000 --- a/docs/_build/html/_static/jquery.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v1.8.3 jquery.com | jquery.org/license */ -(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/docs/_build/html/_static/minus.png b/docs/_build/html/_static/minus.png deleted file mode 100644 index da1c562..0000000 Binary files a/docs/_build/html/_static/minus.png and /dev/null differ diff --git a/docs/_build/html/_static/plus.png b/docs/_build/html/_static/plus.png deleted file mode 100644 index b3cb374..0000000 Binary files a/docs/_build/html/_static/plus.png and /dev/null differ diff --git a/docs/_build/html/_static/pygments.css b/docs/_build/html/_static/pygments.css deleted file mode 100644 index d79caa1..0000000 --- a/docs/_build/html/_static/pygments.css +++ /dev/null @@ -1,62 +0,0 @@ -.highlight .hll { background-color: #ffffcc } -.highlight { background: #eeffcc; } -.highlight .c { color: #408090; font-style: italic } /* Comment */ -.highlight .err { border: 1px solid #FF0000 } /* Error */ -.highlight .k { color: #007020; font-weight: bold } /* Keyword */ -.highlight .o { color: #666666 } /* Operator */ -.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #007020 } /* Comment.Preproc */ -.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ -.highlight .gd { color: #A00000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #333333 } /* Generic.Output */ -.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #0044DD } /* Generic.Traceback */ -.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #007020 } /* Keyword.Pseudo */ -.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #902000 } /* Keyword.Type */ -.highlight .m { color: #208050 } /* Literal.Number */ -.highlight .s { color: #4070a0 } /* Literal.String */ -.highlight .na { color: #4070a0 } /* Name.Attribute */ -.highlight .nb { color: #007020 } /* Name.Builtin */ -.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ -.highlight .no { color: #60add5 } /* Name.Constant */ -.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ -.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #007020 } /* Name.Exception */ -.highlight .nf { color: #06287e } /* Name.Function */ -.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ -.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #bb60d5 } /* Name.Variable */ -.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mf { color: #208050 } /* Literal.Number.Float */ -.highlight .mh { color: #208050 } /* Literal.Number.Hex */ -.highlight .mi { color: #208050 } /* Literal.Number.Integer */ -.highlight .mo { color: #208050 } /* Literal.Number.Oct */ -.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ -.highlight .sc { color: #4070a0 } /* Literal.String.Char */ -.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ -.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ -.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ -.highlight .sx { color: #c65d09 } /* Literal.String.Other */ -.highlight .sr { color: #235388 } /* Literal.String.Regex */ -.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ -.highlight .ss { color: #517918 } /* Literal.String.Symbol */ -.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ -.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ -.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ -.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_build/html/_static/searchtools.js b/docs/_build/html/_static/searchtools.js deleted file mode 100644 index f5c7e5f..0000000 --- a/docs/_build/html/_static/searchtools.js +++ /dev/null @@ -1,622 +0,0 @@ -/* - * searchtools.js_t - * ~~~~~~~~~~~~~~~~ - * - * Sphinx JavaScript utilties for the full-text search. - * - * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - - -/** - * Porter Stemmer - */ -var Stemmer = 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; - } -} - - - -/** - * Simple result scoring code. - */ -var Scorer = { - // Implement the following function to further tweak the score for each result - // The function takes a result array [filename, title, anchor, descr, score] - // and returns the new score. - /* - score: function(result) { - return result[4]; - }, - */ - - // query matches the full name of an object - objNameMatch: 11, - // or matches in the last dotted part of the object name - objPartialMatch: 6, - // Additive scores depending on the priority of the object - objPrio: {0: 15, // used to be importantResults - 1: 5, // used to be objectResults - 2: -5}, // used to be unimportantResults - // Used when the priority is not in the mapping. - objPrioDefault: 0, - - // query found in title - title: 15, - // query found in terms - term: 5 -}; - - -/** - * 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); - } - }, - - loadIndex : function(url) { - $.ajax({type: "GET", url: url, data: null, - dataType: "script", cache: true, - complete: function(jqxhr, textstatus) { - if (textstatus != "success") { - document.getElementById("searchindexloader").src = url; - } - }}); - }, - - 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() { - var i; - Search._pulse_status = (Search._pulse_status + 1) % 4; - var dotString = ''; - for (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 (or wait until index is loaded) - */ - performSearch : function(query) { - // create the required interface elements - this.out = $('#search-results'); - this.title = $('

' + _('Searching') + '

').appendTo(this.out); - this.dots = $('').appendTo(this.title); - this.status = $('

').appendTo(this.out); - this.output = $('
'); - } - // Prettify the comment rating. - comment.pretty_rating = comment.rating + ' point' + - (comment.rating == 1 ? '' : 's'); - // Make a class (for displaying not yet moderated comments differently) - comment.css_class = comment.displayed ? '' : ' moderate'; - // Create a div for this comment. - var context = $.extend({}, opts, comment); - var div = $(renderTemplate(commentTemplate, context)); - - // If the user has voted on this comment, highlight the correct arrow. - if (comment.vote) { - var direction = (comment.vote == 1) ? 'u' : 'd'; - div.find('#' + direction + 'v' + comment.id).hide(); - div.find('#' + direction + 'u' + comment.id).show(); - } - - if (opts.moderator || comment.text != '[deleted]') { - div.find('a.reply').show(); - if (comment.proposal_diff) - div.find('#sp' + comment.id).show(); - if (opts.moderator && !comment.displayed) - div.find('#cm' + comment.id).show(); - if (opts.moderator || (opts.username == comment.username)) - div.find('#dc' + comment.id).show(); - } - return div; - } - - /** - * A simple template renderer. Placeholders such as <%id%> are replaced - * by context['id'] with items being escaped. Placeholders such as <#id#> - * are not escaped. - */ - function renderTemplate(template, context) { - var esc = $(document.createElement('div')); - - function handle(ph, escape) { - var cur = context; - $.each(ph.split('.'), function() { - cur = cur[this]; - }); - return escape ? esc.text(cur || "").html() : cur; - } - - return template.replace(/<([%#])([\w\.]*)\1>/g, function() { - return handle(arguments[2], arguments[1] == '%' ? true : false); - }); - } - - /** Flash an error message briefly. */ - function showError(message) { - $(document.createElement('div')).attr({'class': 'popup-error'}) - .append($(document.createElement('div')) - .attr({'class': 'error-message'}).text(message)) - .appendTo('body') - .fadeIn("slow") - .delay(2000) - .fadeOut("slow"); - } - - /** Add a link the user uses to open the comments popup. */ - $.fn.comment = function() { - return this.each(function() { - var id = $(this).attr('id').substring(1); - var count = COMMENT_METADATA[id]; - var title = count + ' comment' + (count == 1 ? '' : 's'); - var image = count > 0 ? opts.commentBrightImage : opts.commentImage; - var addcls = count == 0 ? ' nocomment' : ''; - $(this) - .append( - $(document.createElement('a')).attr({ - href: '#', - 'class': 'sphinx-comment-open' + addcls, - id: 'ao' + id - }) - .append($(document.createElement('img')).attr({ - src: image, - alt: 'comment', - title: title - })) - .click(function(event) { - event.preventDefault(); - show($(this).attr('id').substring(2)); - }) - ) - .append( - $(document.createElement('a')).attr({ - href: '#', - 'class': 'sphinx-comment-close hidden', - id: 'ah' + id - }) - .append($(document.createElement('img')).attr({ - src: opts.closeCommentImage, - alt: 'close', - title: 'close' - })) - .click(function(event) { - event.preventDefault(); - hide($(this).attr('id').substring(2)); - }) - ); - }); - }; - - var opts = { - processVoteURL: '/_process_vote', - addCommentURL: '/_add_comment', - getCommentsURL: '/_get_comments', - acceptCommentURL: '/_accept_comment', - deleteCommentURL: '/_delete_comment', - commentImage: '/static/_static/comment.png', - closeCommentImage: '/static/_static/comment-close.png', - loadingImage: '/static/_static/ajax-loader.gif', - commentBrightImage: '/static/_static/comment-bright.png', - upArrow: '/static/_static/up.png', - downArrow: '/static/_static/down.png', - upArrowPressed: '/static/_static/up-pressed.png', - downArrowPressed: '/static/_static/down-pressed.png', - voting: false, - moderator: false - }; - - if (typeof COMMENT_OPTIONS != "undefined") { - opts = jQuery.extend(opts, COMMENT_OPTIONS); - } - - var popupTemplate = '\ -
\ -

\ - Sort by:\ - best rated\ - newest\ - oldest\ -

\ -
Comments
\ -
\ - loading comments...
\ -
    \ -
    \ -

    Add a comment\ - (markup):

    \ -
    \ - reStructured text markup: *emph*, **strong**, \ - ``code``, \ - code blocks: :: and an indented block after blank line
    \ -
    \ - \ -

    \ - \ - Propose a change ▹\ - \ - \ - Propose a change ▿\ - \ -

    \ - \ - \ - \ - \ - \ -
    \ -
    '; - - var commentTemplate = '\ -
    \ -
    \ -
    \ - \ - \ - \ - \ - \ - \ -
    \ -
    \ - \ - \ - \ - \ - \ - \ -
    \ -
    \ -
    \ -

    \ - <%username%>\ - <%pretty_rating%>\ - <%time.delta%>\ -

    \ -
    <#text#>
    \ -

    \ - \ - reply ▿\ - proposal ▹\ - proposal ▿\ - \ - \ -

    \ -
    \
    -<#proposal_diff#>\
    -        
    \ -
      \ -
      \ -
      \ -
      \ - '; - - var replyTemplate = '\ -
    • \ -
      \ -
      \ - \ - \ - \ - \ - \ - \ -
      \ -
    • '; - - $(document).ready(function() { - init(); - }); -})(jQuery); - -$(document).ready(function() { - // add comment anchors for all paragraphs that are commentable - $('.sphinx-has-comment').comment(); - - // highlight search words in search results - $("div.context").each(function() { - var params = $.getQueryParameters(); - var terms = (params.q) ? params.q[0].split(/\s+/) : []; - var result = $(this); - $.each(terms, function() { - result.highlightText(this.toLowerCase(), 'highlighted'); - }); - }); - - // directly open comment window if requested - var anchor = document.location.hash; - if (anchor.substring(0, 9) == '#comment-') { - $('#ao' + anchor.substring(9)).click(); - document.location.hash = '#s' + anchor.substring(9); - } -}); diff --git a/docs/_build/html/client.html b/docs/_build/html/client.html deleted file mode 100644 index 8b5de14..0000000 --- a/docs/_build/html/client.html +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - - - client Package — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - - - -
      -
      -
      -
      - -
      -
        -
      -
      -
      -

      client Package

      -
      -
      -class browsermobproxy.Client(url)
      -

      Initialises a new Client object

      -
      --- - - - -
      Parameters:url – This is where the BrowserMob Proxy lives
      -
      -
      -add_to_capabilities(capabilities)
      -

      Adds an ‘proxy’ entry to a desired capabilities dictionary with the -BrowserMob proxy information

      - --- - - - -
      Parameters:capabilities – The Desired capabilities object from Selenium WebDriver
      -
      - -
      -
      -basic_authentication(domain, username, password)
      -

      This add automatic basic authentication

      - --- - - - -
      Parameters:
        -
      • domain – domain to set authentication credentials for
      • -
      • username – valid username to use when authenticating
      • -
      • password – valid password to use when authenticating
      • -
      -
      -
      - -
      -
      -blacklist(regexp, status_code)
      -

      Sets a list of URL patterns to blacklist

      - --- - - - -
      Parameters:
        -
      • regex – a comma separated list of regular expressions
      • -
      • status_code – the HTTP status code to return for URLs that do not match the blacklist
      • -
      -
      -
      - -
      -
      -clear_dns_cache()
      -

      Clears the DNS cache associated with the proxy instance

      -
      - -
      -
      -close()
      -

      shuts down the proxy and closes the port

      -
      - -
      -
      -har
      -

      Gets the HAR that has been recorded

      -
      - -
      -
      -headers(headers)
      -

      This sets the headers that will set by the proxy on all requests

      - --- - - - -
      Parameters:headers – this is a dictionary of the headers to be set
      -
      - -
      -
      -limits(options)
      -

      Limit the bandwidth through the proxy.

      - --- - - - -
      Parameters:options – A dictionary with all the details you want to set. downstreamKbps - Sets the downstream kbps upstreamKbps - Sets the upstream kbps latency - Add the given latency to each HTTP request
      -
      - -
      -
      -new_har(ref=None, options={})
      -

      This sets a new HAR to be recorded

      - --- - - - -
      Parameters:
        -
      • ref – A reference for the HAR. Defaults to None
      • -
      • options – A dictionary that will be passed to BrowserMob Proxy with specific keywords. Keywords are: captureHeaders - Boolean, capture headers captureContent - Boolean, capture content bodies captureBinaryContent - Boolean, capture binary content
      • -
      -
      -
      - -
      -
      -new_page(ref=None)
      -

      This sets a new page to be recorded

      - --- - - - -
      Parameters:ref – A reference for the new page. Defaults to None
      -
      - -
      -
      -remap_hosts(address, ip_address)
      -

      Remap the hosts for a specific URL

      - --- - - - -
      Parameters:
        -
      • address – url that you wish to remap
      • -
      • ip_address – IP Address that will handle all traffic for the address passed in
      • -
      -
      -
      - -
      -
      -request_interceptor(js)
      -

      Executes the javascript against each request

      - --- - - - -
      Parameters:js – the javascript to execute
      -
      - -
      -
      -response_interceptor(js)
      -

      Executes the javascript against each response

      - --- - - - -
      Parameters:js – the javascript to execute
      -
      - -
      -
      -retry(retry_count)
      -

      Retries. No idea what its used for, but its in the API...

      - --- - - - -
      Parameters:retry_count – the number of retries
      -
      - -
      -
      -rewrite_url(match, replace)
      -

      Rewrites the requested url.

      - --- - - - -
      Parameters:
        -
      • match – a regex to match requests with
      • -
      • replace – unicode a string to replace the matches with
      • -
      -
      -
      - -
      -
      -selenium_proxy()
      -

      Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy

      -
      - -
      -
      -timeouts(options)
      -

      Configure various timeouts in the proxy

      - --- - - - -
      Parameters:options – A dictionary with all the details you want to set. request - request timeout (in seconds) read - read timeout (in seconds) connection - connection timeout (in seconds) dns - dns lookup timeout (in seconds)
      -
      - -
      -
      -wait_for_traffic_to_stop(quiet_period, timeout)
      -

      Waits for the network to be quiet

      - --- - - - -
      Parameters:
        -
      • quiet_period – number of seconds the network needs to be quiet for
      • -
      • timeout – max number of seconds to wait
      • -
      -
      -
      - -
      -
      -webdriver_proxy()
      -

      Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy

      -
      - -
      -
      -whitelist(regexp, status_code)
      -

      Sets a list of URL patterns to whitelist

      - --- - - - -
      Parameters:
        -
      • regex – a comma separated list of regular expressions
      • -
      • status_code – the HTTP status code to return for URLs that do not match the whitelist
      • -
      -
      -
      - - - - - - - - - -
      -
      -

      Previous topic

      -

      Welcome to BrowserMob Proxy’s documentation!

      -

      Next topic

      -

      server Package

      -

      This Page

      - - - -
      -
      -
      - - - - - \ No newline at end of file diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html deleted file mode 100644 index 6976d22..0000000 --- a/docs/_build/html/genindex.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - - - - - Index — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - -
      -
      -
      -
      - - -

      Index

      - -
      - A - | B - | C - | H - | L - | N - | R - | S - | T - | U - | W - -
      -

      A

      - - -
      - -
      add_to_capabilities() (browsermobproxy.Client method) -
      - -
      - -

      B

      - - - -
      - -
      basic_authentication() (browsermobproxy.Client method) -
      - - -
      blacklist() (browsermobproxy.Client method) -
      - -
      - -
      browsermobproxy (module), [1] -
      - -
      - -

      C

      - - - -
      - -
      clear_dns_cache() (browsermobproxy.Client method) -
      - - -
      Client (class in browsermobproxy) -
      - -
      - -
      close() (browsermobproxy.Client method) -
      - - -
      create_proxy() (browsermobproxy.Server method) -
      - -
      - -

      H

      - - - -
      - -
      har (browsermobproxy.Client attribute) -
      - -
      - -
      headers() (browsermobproxy.Client method) -
      - -
      - -

      L

      - - -
      - -
      limits() (browsermobproxy.Client method) -
      - -
      - -

      N

      - - - -
      - -
      new_har() (browsermobproxy.Client method) -
      - -
      - -
      new_page() (browsermobproxy.Client method) -
      - -
      - -

      R

      - - - -
      - -
      remap_hosts() (browsermobproxy.Client method) -
      - - -
      request_interceptor() (browsermobproxy.Client method) -
      - - -
      response_interceptor() (browsermobproxy.Client method) -
      - -
      - -
      retry() (browsermobproxy.Client method) -
      - - -
      rewrite_url() (browsermobproxy.Client method) -
      - -
      - -

      S

      - - - -
      - -
      selenium_proxy() (browsermobproxy.Client method) -
      - - -
      Server (class in browsermobproxy) -
      - -
      - -
      start() (browsermobproxy.Server method) -
      - - -
      stop() (browsermobproxy.Server method) -
      - -
      - -

      T

      - - -
      - -
      timeouts() (browsermobproxy.Client method) -
      - -
      - -

      U

      - - -
      - -
      url (browsermobproxy.Server attribute) -
      - -
      - -

      W

      - - - -
      - -
      wait_for_traffic_to_stop() (browsermobproxy.Client method) -
      - - -
      webdriver_proxy() (browsermobproxy.Client method) -
      - -
      - -
      whitelist() (browsermobproxy.Client method) -
      - -
      - - - -
      -
      -
      -
      -
      - - - - - -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html deleted file mode 100644 index 59fa22e..0000000 --- a/docs/_build/html/index.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - Welcome to BrowserMob Proxy’s documentation! — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - - -
      -
      -
      -
      - -
      -

      Welcome to BrowserMob Proxy’s documentation!

      -

      Python client for the BrowserMob Proxy 2.0 REST API.

      -
      -

      How to install

      -

      BrowserMob Proxy is available on PyPI, so you can install it with pip:

      -
      $ pip install browsermob-proxy
      -
      -
      -

      Or with easy_install:

      -
      $ easy_install browsermob-proxy
      -
      -
      -

      Or by cloning the repo from GitHub:

      -
      $ git clone git://github.com/AutomatedTester/browsermob-proxy-py.git
      -
      -
      -

      Then install it by running:

      -
      $ python setup.py install
      -
      -
      -
      -
      -

      How to use with selenium-webdriver

      -

      Manually:

      -
      from browsermobproxy import Server
      -server = Server("path/to/browsermob-proxy")
      -server.start()
      -proxy = server.create_proxy()
      -
      -from selenium import webdriver
      -profile  = webdriver.FirefoxProfile()
      -profile.set_proxy(proxy.selenium_proxy())
      -driver = webdriver.Firefox(firefox_profile=profile)
      -
      -
      -proxy.new_har("google")
      -driver.get("http://www.google.co.uk")
      -proxy.har # returns a HAR JSON blob
      -
      -server.stop()
      -driver.quit()
      -
      -
      -

      Contents:

      - -
      -
      -
      -

      Indices and tables

      - -
      - - -
      -
      -
      -
      -
      -

      Table Of Contents

      - - -

      Next topic

      -

      client Package

      -

      This Page

      - - - -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/docs/_build/html/objects.inv b/docs/_build/html/objects.inv deleted file mode 100644 index 92c3c7b..0000000 --- a/docs/_build/html/objects.inv +++ /dev/null @@ -1,6 +0,0 @@ -# Sphinx inventory version 2 -# Project: BrowserMob Proxy -# Version: 0.6.0 -# The remainder of this file is compressed using zlib. -xڥT�n�0 ����kѸr�i�I����M ��4����� �ӀM�dǺ~���{ �Q�p_����}U���P��Dz�������˱��a��:!r� �m/smj��7���8 -r�M�qH�X�<�)��9�r�~��k���v�d�P�P��{�|bCm��V��m'�4 Y���,(Ů����xPej��M�WX/F� qc��O�1�#均�Fc���<)���XK�cK��DK���O�*��cJ"�kǨ|(S+���N��Ų�#'���� �7m�2����o�F 5��F�۔�dE���ŕCt�X"3�3�n��<�3sw4���_ �\�z���ߝ�iY��/��>se��q(���@E��K���^��z�/z�� \ No newline at end of file diff --git a/docs/_build/html/py-modindex.html b/docs/_build/html/py-modindex.html deleted file mode 100644 index 08a48fb..0000000 --- a/docs/_build/html/py-modindex.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - Python Module Index — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - - - - - - -
      -
      -
      -
      - - -

      Python Module Index

      - -
      - b -
      - - - - - - - -
       
      - b
      - browsermobproxy -
      - - -
      -
      -
      -
      -
      - - -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html deleted file mode 100644 index 9adb77d..0000000 --- a/docs/_build/html/search.html +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - Search — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - - - - - - - -
      -
      -
      -
      - -

      Search

      -
      - -

      - Please activate JavaScript to enable the search - functionality. -

      -
      -

      - 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. -

      -
      - - - -
      - -
      - -
      - -
      -
      -
      -
      -
      -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js deleted file mode 100644 index cf2f7d0..0000000 --- a/docs/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({envversion:42,terms:{all:[1,2],basic_authent:1,execut:1,whitelist:1,rest:0,bandwidth:1,code:1,comma:1,kbp:1,paramet:[1,2],profil:0,configur:1,param:[],should:2,quiet_period:1,add:1,latenc:1,dict:[],blob:0,har:[0,1],pass:1,match:1,"return":[0,1],string:1,variou:1,get:[0,1,2],read:1,browsermobproxi:[0,1,2],express:1,stop:[0,2],number:1,repo:0,capturecont:1,traffic:1,upstream:1,password:1,ip_address:1,specif:1,list:1,authent:1,server:[],separ:1,retry_count:1,api:[0,1],timeout:1,each:1,through:1,unicod:1,where:1,page:[0,1],www:0,set:[1,2],captur:1,manual:0,idea:1,second:1,remap:1,connect:[1,2],domain:1,arg:2,close:1,process:2,port:[1,2],index:0,statu:1,network:1,item:2,pattern:1,content:[0,1],rewrit:1,retri:1,max:1,"import":0,ref:1,refer:1,shut:1,run:[0,2],webdriver_proxi:1,javascript:1,bodi:1,host:1,dictionari:[1,2],address:1,path:[0,2],wait:[1,2],search:0,quiet:1,against:1,initialis:[1,2],instanc:1,request_interceptor:1,rewrite_url:1,com:0,firefox:0,status_cod:1,modul:0,easy_instal:0,automat:1,down:1,header:1,"boolean":1,empti:2,wait_for_traffic_to_stop:1,regexp:1,regex:1,quit:0,given:1,git:0,from:[0,1],interact:2,json:0,been:1,avail:0,start:[0,2],live:1,basic:1,upstreamkbp:1,until:2,more:2,automatedtest:0,desir:1,option:[1,2],python:0,blacklist:1,hold:2,capturebinarycont:1,cach:1,clear_dns_cach:1,none:1,keyword:1,"default":[1,2],wish:1,setup:0,batch:2,record:1,limit:1,can:[0,2],str:[],remap_host:1,firefoxprofil:0,new_har:[0,1],"int":[],request:1,selenium_proxi:[0,1],capturehead:1,downstreamkbp:1,need:[1,2],replac:1,file:2,pip:0,create_proxi:[0,2],mai:2,downstream:1,want:1,when:1,detail:[1,2],binari:1,valid:1,lookup:1,futur:2,"new":1,you:[0,1,2],respons:1,add_to_cap:1,http:[0,1],allow:2,usernam:1,pypi:0,clone:0,object:[1,2],driver:0,what:1,firefox_profil:0,capabl:1,regular:1,set_proxi:0,associ:1,"class":[1,2],googl:0,handl:1,github:0,response_interceptor:1,url:[1,2],entri:1,clear:1,credenti:1,inform:1,client:[],thi:[1,2],new_pag:1},objtypes:{"0":"py:module","1":"py:method","2":"py:attribute","3":"py:class"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","attribute","Python attribute"],"3":["py","class","Python class"]},filenames:["index","client","server"],titles:["Welcome to BrowserMob Proxy’s documentation!","client Package","server Package"],objects:{"":{browsermobproxy:[2,0,0,"-"]},browsermobproxy:{Client:[1,3,1,""],Server:[2,3,1,""]},"browsermobproxy.Server":{url:[2,2,1,""],start:[2,1,1,""],stop:[2,1,1,""],create_proxy:[2,1,1,""]},"browsermobproxy.Client":{remap_hosts:[1,1,1,""],blacklist:[1,1,1,""],selenium_proxy:[1,1,1,""],response_interceptor:[1,1,1,""],webdriver_proxy:[1,1,1,""],clear_dns_cache:[1,1,1,""],timeouts:[1,1,1,""],whitelist:[1,1,1,""],new_page:[1,1,1,""],basic_authentication:[1,1,1,""],retry:[1,1,1,""],request_interceptor:[1,1,1,""],limits:[1,1,1,""],wait_for_traffic_to_stop:[1,1,1,""],rewrite_url:[1,1,1,""],close:[1,1,1,""],har:[1,2,1,""],add_to_capabilities:[1,1,1,""],headers:[1,1,1,""],new_har:[1,1,1,""]}},titleterms:{welcom:0,packag:[1,2],browsermob:0,selenium:0,webdriv:0,server:2,how:0,client:1,indic:0,tabl:0,instal:0,document:0,proxi:0}}) \ No newline at end of file diff --git a/docs/_build/html/server.html b/docs/_build/html/server.html deleted file mode 100644 index 74146e4..0000000 --- a/docs/_build/html/server.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - server Package — BrowserMob Proxy 0.6.0 documentation - - - - - - - - - - - - - - -
      -
      -
      -
      - -
      -
        -
      -
      -
      -

      server Package

      -
      -
      -class browsermobproxy.Server(path='browsermob-proxy', options={})
      -

      Initialises a Server object

      - --- - - - - - -
      Args:
      Parameters:
        -
      • path – Path to the browsermob proxy batch file
      • -
      • options – Dictionary that can hold the port. More items will be added in the future. This defaults to an empty dictionary
      • -
      -
      -
      -
      -create_proxy()
      -

      Gets a client class that allow to set all the proxy details that you -may need to.

      -
      - -
      -
      -start()
      -

      This will start the browsermob proxy and then wait until it can -interact with it

      -
      - -
      -
      -stop()
      -

      This will stop the process running the proxy

      -
      - -
      -
      -url
      -

      Gets the url that the proxy is running on. This is not the URL clients -should connect to.

      -
      - -
      - -
      - - -
      -
      -
      -
      -
      -

      Previous topic

      -

      client Package

      -

      This Page

      - - - -
      -
      -
      -
      - - - - \ No newline at end of file diff --git a/docs/api-objects.txt b/docs/api-objects.txt new file mode 100644 index 0000000..521c89d --- /dev/null +++ b/docs/api-objects.txt @@ -0,0 +1,21 @@ +browsermobproxy browsermobproxy-module.html +browsermobproxy.client browsermobproxy.client-module.html +browsermobproxy.server browsermobproxy.server-module.html +browsermobproxy.client.Client browsermobproxy.client.Client-class.html +browsermobproxy.client.Client.new_har browsermobproxy.client.Client-class.html#new_har +browsermobproxy.client.Client.whitelist browsermobproxy.client.Client-class.html#whitelist +browsermobproxy.client.Client.close browsermobproxy.client.Client-class.html#close +browsermobproxy.client.Client.selenium_proxy browsermobproxy.client.Client-class.html#selenium_proxy +browsermobproxy.client.Client.__init__ browsermobproxy.client.Client-class.html#__init__ +browsermobproxy.client.Client.LIMITS browsermobproxy.client.Client-class.html#LIMITS +browsermobproxy.client.Client.har browsermobproxy.client.Client-class.html#har +browsermobproxy.client.Client.blacklist browsermobproxy.client.Client-class.html#blacklist +browsermobproxy.client.Client.new_page browsermobproxy.client.Client-class.html#new_page +browsermobproxy.client.Client.limits browsermobproxy.client.Client-class.html#limits +browsermobproxy.server.Server browsermobproxy.server.Server-class.html +browsermobproxy.server.Server.create_proxy browsermobproxy.server.Server-class.html#create_proxy +browsermobproxy.server.Server.url browsermobproxy.server.Server-class.html#url +browsermobproxy.server.Server._is_listening browsermobproxy.server.Server-class.html#_is_listening +browsermobproxy.server.Server.stop browsermobproxy.server.Server-class.html#stop +browsermobproxy.server.Server.start browsermobproxy.server.Server-class.html#start +browsermobproxy.server.Server.__init__ browsermobproxy.server.Server-class.html#__init__ diff --git a/docs/browsermobproxy-module.html b/docs/browsermobproxy-module.html new file mode 100644 index 0000000..696a83c --- /dev/null +++ b/docs/browsermobproxy-module.html @@ -0,0 +1,164 @@ + + + + + browsermobproxy + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      + +

      Package browsermobproxy

      source code

      +
      +

      Version: + 0.0.1 +

      +
      + + + + + + +
      + + + + + +
      Submodules[hide private]
      +
      +
      + +
      + + + + + + + + + + + + +
      + + + + + +
      Variables[hide private]
      +
      +   + + Server +
      +   + + Client +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/browsermobproxy-pysrc.html b/docs/browsermobproxy-pysrc.html new file mode 100644 index 0000000..4dbf9aa --- /dev/null +++ b/docs/browsermobproxy-pysrc.html @@ -0,0 +1,116 @@ + + + + + browsermobproxy + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      +

      Source Code for Package browsermobproxy

      +
      +1  __version__ = '0.0.1' 
      +2   
      +3  from server import Server 
      +4  from client import Client 
      +5   
      +6  __all__ = ['Server', 'Client', 'browsermobproxy'] 
      +7   
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/browsermobproxy.client-module.html b/docs/browsermobproxy.client-module.html new file mode 100644 index 0000000..217374f --- /dev/null +++ b/docs/browsermobproxy.client-module.html @@ -0,0 +1,129 @@ + + + + + browsermobproxy.client + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy :: + Module client + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      + +

      Module client

      source code

      + + + + + + + + + +
      + + + + + +
      Classes[hide private]
      +
      +   + + Client +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/browsermobproxy.client-pysrc.html b/docs/browsermobproxy.client-pysrc.html new file mode 100644 index 0000000..3f4c21b --- /dev/null +++ b/docs/browsermobproxy.client-pysrc.html @@ -0,0 +1,236 @@ + + + + + browsermobproxy.client + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy :: + Module client + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      +

      Source Code for Module browsermobproxy.client

      +
      +  1  from httplib2 import Http 
      +  2  from urllib import urlencode 
      +  3  import json 
      +
      4 + 5 -class Client(object): +
      6 +
      7 - def __init__(self, url): +
      8 """ + 9 Initialises a new Client object + 10 :Args: + 11 - url: This is where the BrowserMob Proxy lives + 12 """ + 13 self.host = url + 14 h = Http() + 15 resp, content = h.request('%s/proxy' % self.host, 'POST', urlencode('')) + 16 jcontent = json.loads(content) + 17 self.port = jcontent['port'] + 18 url_parts = self.host.split(":") + 19 self.proxy = url_parts[0] + ":" + url_parts[1] + ":" + str(self.port) +
      20 +
      21 - def new_har(self, ref=None): +
      22 """ + 23 This sets a new HAR to be recorded + 24 :Args: + 25 - ref: A reference for the HAR. Defaults to None + 26 """ + 27 h = Http() + 28 resp, content = h.request('%s/proxy/%s/har' % (self.host, self.port), + 29 'PUT', ref or '') +
      30 +
      31 - def new_page(self, ref): +
      32 """ + 33 This sets a new page to be recorded + 34 :Args: + 35 - ref: A reference for the new page. Defaults to None + 36 """ + 37 h = Http() + 38 resp, content = h.request('%s/proxy/%s/har/pageRef' % (self.host, self.port), + 39 'PUT', ref or '') + 40 if content: + 41 return json.loads(content) +
      42 + 43 @property +
      44 - def har(self): +
      45 """ + 46 Gets the HAR that has been recorded + 47 """ + 48 h = Http() + 49 resp, content = h.request('%s/proxy/%s/har' % (self.host, self.port), + 50 'GET') + 51 return json.loads(content) +
      52 +
      53 - def selenium_proxy(self): +
      54 """ + 55 Returns a Selenium WebDriver Proxy class with details of the HTTP Proxy + 56 """ + 57 from selenium import webdriver + 58 return webdriver.Proxy({"httpProxy":self.proxy}) +
      59 +
      60 - def whitelist(self, regexp, status_code): +
      61 """ + 62 Sets a list of URL patterns to whitelist + 63 :Args: + 64 - regex: a comma separated list of regular expressions + 65 - status_code: the HTTP status code to return for URLs that do not match the whitelist + 66 + 67 """ + 68 h = Http() + 69 resp, content = h.request('%s/proxy/%s/whitelist' % (self.host, self.port), + 70 'PUT', urlencode({ 'regex': regexp, 'status': status_code + 71 })) +
      72 + 73 +
      74 - def blacklist(self, regexp, status_code): +
      75 """ + 76 Sets a list of URL patterns to blacklist + 77 :Args: + 78 - regex: a comma separated list of regular expressions + 79 - status_code: the HTTP status code to return for URLs that do not match the blacklist + 80 + 81 """ + 82 + 83 h = Http() + 84 resp, content = h.request('%s/proxy/%s/blacklist' % (self.host, self.port), + 85 'PUT', urlencode({ 'regex': regexp, 'status': status_code + 86 })) +
      87 + 88 LIMITS = { + 89 'upstream_kbps' : 'upstreamKbps', + 90 'downstream_kbps' : 'downstreamKbps', + 91 'latency' : 'latency' + 92 } + 93 + 94 +
      95 - def limits(self, options): +
      96 """ + 97 Limit the bandwidth through the proxy. + 98 :Args: + 99 - options: A dictionary with all the details you want to set. +100 downstreamKbps - Sets the downstream kbps +101 upstreamKbps - Sets the upstream kbps +102 latency - Add the given latency to each HTTP request +103 """ +104 params = {} +105 +106 for (k, v) in options.items(): +107 if not self.LIMITS.has_key(k): +108 raise Exception('invalid key: %s' % k) +109 +110 params[self.LIMITS[k]] = int(v) +111 +112 if len(params.items()) == 0: +113 raise Exception("You need to specify one of the valid Keys") +114 +115 h = Http() +116 resp, content = h.request('%s/proxy/%s/limit' % (self.host, self.port), +117 'PUT', urlencode(params)) +
      118 +
      119 - def close(self): +
      120 """ +121 shuts down the proxy and closes the port +122 """ +123 h = Http() +124 resp, content = h.request('%s/proxy/%s' % (self.host, self.port), +125 'DELETE' ) +
      126 +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/browsermobproxy.client.Client-class.html b/docs/browsermobproxy.client.Client-class.html new file mode 100644 index 0000000..fc43b8e --- /dev/null +++ b/docs/browsermobproxy.client.Client-class.html @@ -0,0 +1,607 @@ + + + + + browsermobproxy.client.Client + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy :: + Module client :: + Class Client + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      + +

      Class Client

      source code

      +
      +object --+
      +         |
      +        Client
      +
      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + + +
      Instance Methods[hide private]
      +
      +   + + + + + + +
      __init__(self, + url)
      + Initialises a new Client object :Args:
      + source code + +
      + +
      +   + + + + + + +
      new_har(self, + ref=None)
      + This sets a new HAR to be recorded :Args:
      + source code + +
      + +
      +   + + + + + + +
      new_page(self, + ref)
      + This sets a new page to be recorded :Args:
      + source code + +
      + +
      +   + + + + + + +
      har(self)
      + Gets the HAR that has been recorded
      + source code + +
      + +
      +   + + + + + + +
      selenium_proxy(self)
      + Returns a Selenium WebDriver Proxy class with details of the HTTP + Proxy
      + source code + +
      + +
      +   + + + + + + +
      whitelist(self, + regexp, + status_code)
      + Sets a list of URL patterns to whitelist :Args:
      + source code + +
      + +
      +   + + + + + + +
      blacklist(self, + regexp, + status_code)
      + Sets a list of URL patterns to blacklist :Args:
      + source code + +
      + +
      +   + + + + + + +
      limits(self, + options)
      + Limit the bandwidth through the proxy.
      + source code + +
      + +
      +   + + + + + + +
      close(self)
      + shuts down the proxy and closes the port
      + source code + +
      + +
      +

      Inherited from object: + __delattr__, + __format__, + __getattribute__, + __hash__, + __new__, + __reduce__, + __reduce_ex__, + __repr__, + __setattr__, + __sizeof__, + __str__, + __subclasshook__ +

      +
      + + + + + + + + + +
      + + + + + +
      Class Variables[hide private]
      +
      +   + + LIMITS = {'upstream_kbps': 'upstreamKbps', 'downstream_kbps': ... +
      + + + + + + + + + +
      + + + + + +
      Properties[hide private]
      +
      +

      Inherited from object: + __class__ +

      +
      + + + + + + +
      + + + + + +
      Method Details[hide private]
      +
      + +
      + +
      + + +
      +

      __init__(self, + url) +
      (Constructor) +

      +
      source code  +
      + +

      Initialises a new Client object :Args:

      +
        +
      • + url: This is where the BrowserMob Proxy lives +
      • +
      +
      +
      Overrides: + object.__init__ +
      +
      +
      +
      + +
      + +
      + + +
      +

      new_har(self, + ref=None) +

      +
      source code  +
      + +

      This sets a new HAR to be recorded :Args:

      +
        +
      • + ref: A reference for the HAR. Defaults to None +
      • +
      +
      +
      +
      +
      + +
      + +
      + + +
      +

      new_page(self, + ref) +

      +
      source code  +
      + +

      This sets a new page to be recorded :Args:

      +
        +
      • + ref: A reference for the new page. Defaults to None +
      • +
      +
      +
      +
      +
      + +
      + +
      + + +
      +

      har(self) +

      +
      source code  +
      + +

      Gets the HAR that has been recorded

      +
      +
      Decorators:
      +
        +
      • @property
      • +
      +
      +
      +
      + +
      + +
      + + +
      +

      whitelist(self, + regexp, + status_code) +

      +
      source code  +
      + +

      Sets a list of URL patterns to whitelist :Args:

      +
        +
      • + regex: a comma separated list of regular expressions +
      • +
      • + status_code: the HTTP status code to return for URLs that do not + match the whitelist +
      • +
      +
      +
      +
      +
      + +
      + +
      + + +
      +

      blacklist(self, + regexp, + status_code) +

      +
      source code  +
      + +

      Sets a list of URL patterns to blacklist :Args:

      +
        +
      • + regex: a comma separated list of regular expressions +
      • +
      • + status_code: the HTTP status code to return for URLs that do not + match the blacklist +
      • +
      +
      +
      +
      +
      + +
      + +
      + + +
      +

      limits(self, + options) +

      +
      source code  +
      + +

      Limit the bandwidth through the proxy. :Args:

      +
        +
      • + options: A dictionary with all the details you want to set. + downstreamKbps - Sets the downstream kbps upstreamKbps - Sets the + upstream kbps latency - Add the given latency to each HTTP request +
      • +
      +
      +
      +
      +
      +
      + + + + + + +
      + + + + + +
      Class Variable Details[hide private]
      +
      + +
      + +
      +

      LIMITS

      + +
      +
      +
      +
      Value:
      +
      +{'upstream_kbps': 'upstreamKbps', 'downstream_kbps': 'downstreamKbps',\
      + 'latency': 'latency'}
      +
      +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/browsermobproxy.server-module.html b/docs/browsermobproxy.server-module.html new file mode 100644 index 0000000..8540363 --- /dev/null +++ b/docs/browsermobproxy.server-module.html @@ -0,0 +1,129 @@ + + + + + browsermobproxy.server + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy :: + Module server + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      + +

      Module server

      source code

      + + + + + + + + + +
      + + + + + +
      Classes[hide private]
      +
      +   + + Server +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/browsermobproxy.server-pysrc.html b/docs/browsermobproxy.server-pysrc.html new file mode 100644 index 0000000..9c8b043 --- /dev/null +++ b/docs/browsermobproxy.server-pysrc.html @@ -0,0 +1,181 @@ + + + + + browsermobproxy.server + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy :: + Module server + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      +

      Source Code for Module browsermobproxy.server

      +
      + 1  from subprocess import Popen, PIPE, STDOUT 
      + 2  import socket 
      + 3  import time 
      + 4   
      + 5  from client import Client 
      +
      6 + 7 + 8 -class Server(object): +
      9 +
      10 - def __init__(self, path, options={}): +
      11 """ +12 Initialises a Server object +13 +14 :Args: +15 - path : Path to the browsermob proxy batch file +16 - options : Dictionary that can hold the port. More items will be added in the future. +17 This defaults to an empty dictionary +18 """ +19 self.path = path +20 self.port = options['port'] if options.has_key('port') else 8080 +21 self.command = ['sh', path, '--port=%s' % self.port] +
      22 +
      23 - def start(self): +
      24 """ +25 This will start the browsermob proxy and then wait until it can interact with it +26 """ +27 self.process = Popen(self.command, stdout=PIPE, stderr=STDOUT) +28 count = 0 +29 while not self._is_listening(): +30 time.sleep(0.1) +31 count += 1 +32 if count == 30: +33 raise Exception("Can't connect to Browsermob-Proxy") +
      34 +
      35 - def stop(self): +
      36 """ +37 This will stop the process running the proxy +38 """ +39 try: +40 if self.process: +41 self.process.kill() +42 self.process.wait() +43 except AttributeError: +44 # kill may not be available under windows environment +45 pass +
      46 +47 @property +
      48 - def url(self): +
      49 """ +50 Gets the url that the proxy is running on. This is not the URL clients should connect to. +51 """ +52 return "http://localhost:%d" % self.port +
      53 +54 @property +
      55 - def create_proxy(self): +
      56 """ +57 Gets a client class that allow to set all the proxy details that you may need to. +58 """ +59 client = Client(self.url) +60 return client +
      61 +
      62 - def _is_listening(self): +
      63 try: +64 socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +65 socket_.settimeout(1) +66 socket_.connect(("localhost", self.port)) +67 socket_.close() +68 return True +69 except socket.error: +70 return False +
      71 +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/browsermobproxy.server.Server-class.html b/docs/browsermobproxy.server.Server-class.html new file mode 100644 index 0000000..54b3889 --- /dev/null +++ b/docs/browsermobproxy.server.Server-class.html @@ -0,0 +1,380 @@ + + + + + browsermobproxy.server.Server + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + Package browsermobproxy :: + Module server :: + Class Server + + + + + + +
      [hide private]
      [frames] | no frames]
      +
      + +

      Class Server

      source code

      +
      +object --+
      +         |
      +        Server
      +
      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + + +
      Instance Methods[hide private]
      +
      +   + + + + + + +
      __init__(self, + path, + options={})
      + Initialises a Server object
      + source code + +
      + +
      +   + + + + + + +
      start(self)
      + This will start the browsermob proxy and then wait until it can + interact with it
      + source code + +
      + +
      +   + + + + + + +
      stop(self)
      + This will stop the process running the proxy
      + source code + +
      + +
      +   + + + + + + +
      url(self)
      + Gets the url that the proxy is running on.
      + source code + +
      + +
      +   + + + + + + +
      create_proxy(self)
      + Gets a client class that allow to set all the proxy details that you + may need to.
      + source code + +
      + +
      +   + + + + + + +
      _is_listening(self) + source code + +
      + +
      +

      Inherited from object: + __delattr__, + __format__, + __getattribute__, + __hash__, + __new__, + __reduce__, + __reduce_ex__, + __repr__, + __setattr__, + __sizeof__, + __str__, + __subclasshook__ +

      +
      + + + + + + + + + +
      + + + + + +
      Properties[hide private]
      +
      +

      Inherited from object: + __class__ +

      +
      + + + + + + +
      + + + + + +
      Method Details[hide private]
      +
      + +
      + +
      + + +
      +

      __init__(self, + path, + options={}) +
      (Constructor) +

      +
      source code  +
      + +

      Initialises a Server object

      +

      :Args:

      +
        +
      • + path : Path to the browsermob proxy batch file +
      • +
      • + options : Dictionary that can hold the port. More items will be added + in the future. This defaults to an empty dictionary +
      • +
      +
      +
      Overrides: + object.__init__ +
      +
      +
      +
      + +
      + +
      + + +
      +

      url(self) +

      +
      source code  +
      + +

      Gets the url that the proxy is running on. This is not the URL clients + should connect to.

      +
      +
      Decorators:
      +
        +
      • @property
      • +
      +
      +
      +
      + +
      + +
      + + +
      +

      create_proxy(self) +

      +
      source code  +
      + +

      Gets a client class that allow to set all the proxy details that you + may need to.

      +
      +
      Decorators:
      +
        +
      • @property
      • +
      +
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/class-tree.html b/docs/class-tree.html new file mode 100644 index 0000000..57ef2e3 --- /dev/null +++ b/docs/class-tree.html @@ -0,0 +1,113 @@ + + + + + Class Hierarchy + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
      [hide private]
      [frames] | no frames]
      +
      +
      + [ Module Hierarchy + | Class Hierarchy ] +

      +

      Class Hierarchy

      + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/client.rst b/docs/client.rst deleted file mode 100644 index 95c74fa..0000000 --- a/docs/client.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. toctree:: - :maxdepth: 2 - -:mod:`client` Package ---------------------- -.. automodule:: browsermobproxy -.. autoclass:: Client - :members: diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 961c489..0000000 --- a/docs/conf.py +++ /dev/null @@ -1,243 +0,0 @@ -# -*- coding: utf-8 -*- -# -# BrowserMob Proxy documentation build configuration file, created by -# sphinx-quickstart on Fri May 24 12:37:12 2013. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc'] -autoclass_content = 'both' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'BrowserMob Proxy' -copyright = u'2014, David Burns' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.6.0' -# The full version, including alpha/beta/rc tags. -release = '0.6.0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# 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 patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# 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' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# 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 - -# 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_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'BrowserMobProxydoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'BrowserMobProxy.tex', u'BrowserMob Proxy Documentation', - u'David Burns', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'browsermobproxy', u'BrowserMob Proxy Documentation', - [u'David Burns'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'BrowserMobProxy', u'BrowserMob Proxy Documentation', - u'David Burns', 'BrowserMobProxy', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' diff --git a/docs/crarr.png b/docs/crarr.png new file mode 100644 index 0000000..26b43c5 Binary files /dev/null and b/docs/crarr.png differ diff --git a/docs/epydoc.css b/docs/epydoc.css new file mode 100644 index 0000000..86d4170 --- /dev/null +++ b/docs/epydoc.css @@ -0,0 +1,322 @@ + + +/* Epydoc CSS Stylesheet + * + * This stylesheet can be used to customize the appearance of epydoc's + * HTML output. + * + */ + +/* Default Colors & Styles + * - Set the default foreground & background color with 'body'; and + * link colors with 'a:link' and 'a:visited'. + * - Use bold for decision list terms. + * - The heading styles defined here are used for headings *within* + * docstring descriptions. All headings used by epydoc itself use + * either class='epydoc' or class='toc' (CSS styles for both + * defined below). + */ +body { background: #ffffff; color: #000000; } +p { margin-top: 0.5em; margin-bottom: 0.5em; } +a:link { color: #0000ff; } +a:visited { color: #204080; } +dt { font-weight: bold; } +h1 { font-size: +140%; font-style: italic; + font-weight: bold; } +h2 { font-size: +125%; font-style: italic; + font-weight: bold; } +h3 { font-size: +110%; font-style: italic; + font-weight: normal; } +code { font-size: 100%; } +/* N.B.: class, not pseudoclass */ +a.link { font-family: monospace; } + +/* Page Header & Footer + * - The standard page header consists of a navigation bar (with + * pointers to standard pages such as 'home' and 'trees'); a + * breadcrumbs list, which can be used to navigate to containing + * classes or modules; options links, to show/hide private + * variables and to show/hide frames; and a page title (using + *

      ). The page title may be followed by a link to the + * corresponding source code (using 'span.codelink'). + * - The footer consists of a navigation bar, a timestamp, and a + * pointer to epydoc's homepage. + */ +h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; } +h2.epydoc { font-size: +130%; font-weight: bold; } +h3.epydoc { font-size: +115%; font-weight: bold; + margin-top: 0.2em; } +td h3.epydoc { font-size: +115%; font-weight: bold; + margin-bottom: 0; } +table.navbar { background: #a0c0ff; color: #000000; + border: 2px groove #c0d0d0; } +table.navbar table { color: #000000; } +th.navbar-select { background: #70b0ff; + color: #000000; } +table.navbar a { text-decoration: none; } +table.navbar a:link { color: #0000ff; } +table.navbar a:visited { color: #204080; } +span.breadcrumbs { font-size: 85%; font-weight: bold; } +span.options { font-size: 70%; } +span.codelink { font-size: 85%; } +td.footer { font-size: 85%; } + +/* Table Headers + * - Each summary table and details section begins with a 'header' + * row. This row contains a section title (marked by + * 'span.table-header') as well as a show/hide private link + * (marked by 'span.options', defined above). + * - Summary tables that contain user-defined groups mark those + * groups using 'group header' rows. + */ +td.table-header { background: #70b0ff; color: #000000; + border: 1px solid #608090; } +td.table-header table { color: #000000; } +td.table-header table a:link { color: #0000ff; } +td.table-header table a:visited { color: #204080; } +span.table-header { font-size: 120%; font-weight: bold; } +th.group-header { background: #c0e0f8; color: #000000; + text-align: left; font-style: italic; + font-size: 115%; + border: 1px solid #608090; } + +/* Summary Tables (functions, variables, etc) + * - Each object is described by a single row of the table with + * two cells. The left cell gives the object's type, and is + * marked with 'code.summary-type'. The right cell gives the + * object's name and a summary description. + * - CSS styles for the table's header and group headers are + * defined above, under 'Table Headers' + */ +table.summary { border-collapse: collapse; + background: #e8f0f8; color: #000000; + border: 1px solid #608090; + margin-bottom: 0.5em; } +td.summary { border: 1px solid #608090; } +code.summary-type { font-size: 85%; } +table.summary a:link { color: #0000ff; } +table.summary a:visited { color: #204080; } + + +/* Details Tables (functions, variables, etc) + * - Each object is described in its own div. + * - A single-row summary table w/ table-header is used as + * a header for each details section (CSS style for table-header + * is defined above, under 'Table Headers'). + */ +table.details { border-collapse: collapse; + background: #e8f0f8; color: #000000; + border: 1px solid #608090; + margin: .2em 0 0 0; } +table.details table { color: #000000; } +table.details a:link { color: #0000ff; } +table.details a:visited { color: #204080; } + +/* Fields */ +dl.fields { margin-left: 2em; margin-top: 1em; + margin-bottom: 1em; } +dl.fields dd ul { margin-left: 0em; padding-left: 0em; } +dl.fields dd ul li ul { margin-left: 2em; padding-left: 0em; } +div.fields { margin-left: 2em; } +div.fields p { margin-bottom: 0.5em; } + +/* Index tables (identifier index, term index, etc) + * - link-index is used for indices containing lists of links + * (namely, the identifier index & term index). + * - index-where is used in link indices for the text indicating + * the container/source for each link. + * - metadata-index is used for indices containing metadata + * extracted from fields (namely, the bug index & todo index). + */ +table.link-index { border-collapse: collapse; + background: #e8f0f8; color: #000000; + border: 1px solid #608090; } +td.link-index { border-width: 0px; } +table.link-index a:link { color: #0000ff; } +table.link-index a:visited { color: #204080; } +span.index-where { font-size: 70%; } +table.metadata-index { border-collapse: collapse; + background: #e8f0f8; color: #000000; + border: 1px solid #608090; + margin: .2em 0 0 0; } +td.metadata-index { border-width: 1px; border-style: solid; } +table.metadata-index a:link { color: #0000ff; } +table.metadata-index a:visited { color: #204080; } + +/* Function signatures + * - sig* is used for the signature in the details section. + * - .summary-sig* is used for the signature in the summary + * table, and when listing property accessor functions. + * */ +.sig-name { color: #006080; } +.sig-arg { color: #008060; } +.sig-default { color: #602000; } +.summary-sig { font-family: monospace; } +.summary-sig-name { color: #006080; font-weight: bold; } +table.summary a.summary-sig-name:link + { color: #006080; font-weight: bold; } +table.summary a.summary-sig-name:visited + { color: #006080; font-weight: bold; } +.summary-sig-arg { color: #006040; } +.summary-sig-default { color: #501800; } + +/* Subclass list + */ +ul.subclass-list { display: inline; } +ul.subclass-list li { display: inline; } + +/* To render variables, classes etc. like functions */ +table.summary .summary-name { color: #006080; font-weight: bold; + font-family: monospace; } +table.summary + a.summary-name:link { color: #006080; font-weight: bold; + font-family: monospace; } +table.summary + a.summary-name:visited { color: #006080; font-weight: bold; + font-family: monospace; } + +/* Variable values + * - In the 'variable details' sections, each varaible's value is + * listed in a 'pre.variable' box. The width of this box is + * restricted to 80 chars; if the value's repr is longer than + * this it will be wrapped, using a backslash marked with + * class 'variable-linewrap'. If the value's repr is longer + * than 3 lines, the rest will be ellided; and an ellipsis + * marker ('...' marked with 'variable-ellipsis') will be used. + * - If the value is a string, its quote marks will be marked + * with 'variable-quote'. + * - If the variable is a regexp, it is syntax-highlighted using + * the re* CSS classes. + */ +pre.variable { padding: .5em; margin: 0; + background: #dce4ec; color: #000000; + border: 1px solid #708890; } +.variable-linewrap { color: #604000; font-weight: bold; } +.variable-ellipsis { color: #604000; font-weight: bold; } +.variable-quote { color: #604000; font-weight: bold; } +.variable-group { color: #008000; font-weight: bold; } +.variable-op { color: #604000; font-weight: bold; } +.variable-string { color: #006030; } +.variable-unknown { color: #a00000; font-weight: bold; } +.re { color: #000000; } +.re-char { color: #006030; } +.re-op { color: #600000; } +.re-group { color: #003060; } +.re-ref { color: #404040; } + +/* Base tree + * - Used by class pages to display the base class hierarchy. + */ +pre.base-tree { font-size: 80%; margin: 0; } + +/* Frames-based table of contents headers + * - Consists of two frames: one for selecting modules; and + * the other listing the contents of the selected module. + * - h1.toc is used for each frame's heading + * - h2.toc is used for subheadings within each frame. + */ +h1.toc { text-align: center; font-size: 105%; + margin: 0; font-weight: bold; + padding: 0; } +h2.toc { font-size: 100%; font-weight: bold; + margin: 0.5em 0 0 -0.3em; } + +/* Syntax Highlighting for Source Code + * - doctest examples are displayed in a 'pre.py-doctest' block. + * If the example is in a details table entry, then it will use + * the colors specified by the 'table pre.py-doctest' line. + * - Source code listings are displayed in a 'pre.py-src' block. + * Each line is marked with 'span.py-line' (used to draw a line + * down the left margin, separating the code from the line + * numbers). Line numbers are displayed with 'span.py-lineno'. + * The expand/collapse block toggle button is displayed with + * 'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not + * modify the font size of the text.) + * - If a source code page is opened with an anchor, then the + * corresponding code block will be highlighted. The code + * block's header is highlighted with 'py-highlight-hdr'; and + * the code block's body is highlighted with 'py-highlight'. + * - The remaining py-* classes are used to perform syntax + * highlighting (py-string for string literals, py-name for names, + * etc.) + */ +pre.py-doctest { padding: .5em; margin: 1em; + background: #e8f0f8; color: #000000; + border: 1px solid #708890; } +table pre.py-doctest { background: #dce4ec; + color: #000000; } +pre.py-src { border: 2px solid #000000; + background: #f0f0f0; color: #000000; } +.py-line { border-left: 2px solid #000000; + margin-left: .2em; padding-left: .4em; } +.py-lineno { font-style: italic; font-size: 90%; + padding-left: .5em; } +a.py-toggle { text-decoration: none; } +div.py-highlight-hdr { border-top: 2px solid #000000; + border-bottom: 2px solid #000000; + background: #d8e8e8; } +div.py-highlight { border-bottom: 2px solid #000000; + background: #d0e0e0; } +.py-prompt { color: #005050; font-weight: bold;} +.py-more { color: #005050; font-weight: bold;} +.py-string { color: #006030; } +.py-comment { color: #003060; } +.py-keyword { color: #600000; } +.py-output { color: #404040; } +.py-name { color: #000050; } +.py-name:link { color: #000050 !important; } +.py-name:visited { color: #000050 !important; } +.py-number { color: #005000; } +.py-defname { color: #000060; font-weight: bold; } +.py-def-name { color: #000060; font-weight: bold; } +.py-base-class { color: #000060; } +.py-param { color: #000060; } +.py-docstring { color: #006030; } +.py-decorator { color: #804020; } +/* Use this if you don't want links to names underlined: */ +/*a.py-name { text-decoration: none; }*/ + +/* Graphs & Diagrams + * - These CSS styles are used for graphs & diagrams generated using + * Graphviz dot. 'img.graph-without-title' is used for bare + * diagrams (to remove the border created by making the image + * clickable). + */ +img.graph-without-title { border: none; } +img.graph-with-title { border: 1px solid #000000; } +span.graph-title { font-weight: bold; } +span.graph-caption { } + +/* General-purpose classes + * - 'p.indent-wrapped-lines' defines a paragraph whose first line + * is not indented, but whose subsequent lines are. + * - The 'nomargin-top' class is used to remove the top margin (e.g. + * from lists). The 'nomargin' class is used to remove both the + * top and bottom margin (but not the left or right margin -- + * for lists, that would cause the bullets to disappear.) + */ +p.indent-wrapped-lines { padding: 0 0 0 7em; text-indent: -7em; + margin: 0; } +.nomargin-top { margin-top: 0; } +.nomargin { margin-top: 0; margin-bottom: 0; } + +/* HTML Log */ +div.log-block { padding: 0; margin: .5em 0 .5em 0; + background: #e8f0f8; color: #000000; + border: 1px solid #000000; } +div.log-error { padding: .1em .3em .1em .3em; margin: 4px; + background: #ffb0b0; color: #000000; + border: 1px solid #000000; } +div.log-warning { padding: .1em .3em .1em .3em; margin: 4px; + background: #ffffb0; color: #000000; + border: 1px solid #000000; } +div.log-info { padding: .1em .3em .1em .3em; margin: 4px; + background: #b0ffb0; color: #000000; + border: 1px solid #000000; } +h2.log-hdr { background: #70b0ff; color: #000000; + margin: 0; padding: 0em 0.5em 0em 0.5em; + border-bottom: 1px solid #000000; font-size: 110%; } +p.log { font-weight: bold; margin: .5em 0 .5em 0; } +tr.opt-changed { color: #000000; font-weight: bold; } +tr.opt-default { color: #606060; } +pre.log { margin: 0; padding: 0; padding-left: 1em; } diff --git a/docs/epydoc.js b/docs/epydoc.js new file mode 100644 index 0000000..e787dbc --- /dev/null +++ b/docs/epydoc.js @@ -0,0 +1,293 @@ +function toggle_private() { + // Search for any private/public links on this page. Store + // their old text in "cmd," so we will know what action to + // take; and change their text to the opposite action. + var cmd = "?"; + var elts = document.getElementsByTagName("a"); + for(var i=0; i...
      "; + elt.innerHTML = s; + } +} + +function toggle(id) { + elt = document.getElementById(id+"-toggle"); + if (elt.innerHTML == "-") + collapse(id); + else + expand(id); + return false; +} + +function highlight(id) { + var elt = document.getElementById(id+"-def"); + if (elt) elt.className = "py-highlight-hdr"; + var elt = document.getElementById(id+"-expanded"); + if (elt) elt.className = "py-highlight"; + var elt = document.getElementById(id+"-collapsed"); + if (elt) elt.className = "py-highlight"; +} + +function num_lines(s) { + var n = 1; + var pos = s.indexOf("\n"); + while ( pos > 0) { + n += 1; + pos = s.indexOf("\n", pos+1); + } + return n; +} + +// Collapse all blocks that mave more than `min_lines` lines. +function collapse_all(min_lines) { + var elts = document.getElementsByTagName("div"); + for (var i=0; i 0) + if (elt.id.substring(split, elt.id.length) == "-expanded") + if (num_lines(elt.innerHTML) > min_lines) + collapse(elt.id.substring(0, split)); + } +} + +function expandto(href) { + var start = href.indexOf("#")+1; + if (start != 0 && start != href.length) { + if (href.substring(start, href.length) != "-") { + collapse_all(4); + pos = href.indexOf(".", start); + while (pos != -1) { + var id = href.substring(start, pos); + expand(id); + pos = href.indexOf(".", pos+1); + } + var id = href.substring(start, href.length); + expand(id); + highlight(id); + } + } +} + +function kill_doclink(id) { + var parent = document.getElementById(id); + parent.removeChild(parent.childNodes.item(0)); +} +function auto_kill_doclink(ev) { + if (!ev) var ev = window.event; + if (!this.contains(ev.toElement)) { + var parent = document.getElementById(this.parentID); + parent.removeChild(parent.childNodes.item(0)); + } +} + +function doclink(id, name, targets_id) { + var elt = document.getElementById(id); + + // If we already opened the box, then destroy it. + // (This case should never occur, but leave it in just in case.) + if (elt.childNodes.length > 1) { + elt.removeChild(elt.childNodes.item(0)); + } + else { + // The outer box: relative + inline positioning. + var box1 = document.createElement("div"); + box1.style.position = "relative"; + box1.style.display = "inline"; + box1.style.top = 0; + box1.style.left = 0; + + // A shadow for fun + var shadow = document.createElement("div"); + shadow.style.position = "absolute"; + shadow.style.left = "-1.3em"; + shadow.style.top = "-1.3em"; + shadow.style.background = "#404040"; + + // The inner box: absolute positioning. + var box2 = document.createElement("div"); + box2.style.position = "relative"; + box2.style.border = "1px solid #a0a0a0"; + box2.style.left = "-.2em"; + box2.style.top = "-.2em"; + box2.style.background = "white"; + box2.style.padding = ".3em .4em .3em .4em"; + box2.style.fontStyle = "normal"; + box2.onmouseout=auto_kill_doclink; + box2.parentID = id; + + // Get the targets + var targets_elt = document.getElementById(targets_id); + var targets = targets_elt.getAttribute("targets"); + var links = ""; + target_list = targets.split(","); + for (var i=0; i" + + target[0] + ""; + } + + // Put it all together. + elt.insertBefore(box1, elt.childNodes.item(0)); + //box1.appendChild(box2); + box1.appendChild(shadow); + shadow.appendChild(box2); + box2.innerHTML = + "Which "+name+" do you want to see documentation for?" + + ""; + } + return false; +} + +function get_anchor() { + var href = location.href; + var start = href.indexOf("#")+1; + if ((start != 0) && (start != href.length)) + return href.substring(start, href.length); + } +function redirect_url(dottedName) { + // Scan through each element of the "pages" list, and check + // if "name" matches with any of them. + for (var i=0; i-m" or "-c"; + // extract the portion & compare it to dottedName. + var pagename = pages[i].substring(0, pages[i].length-2); + if (pagename == dottedName.substring(0,pagename.length)) { + + // We've found a page that matches `dottedName`; + // construct its URL, using leftover `dottedName` + // content to form an anchor. + var pagetype = pages[i].charAt(pages[i].length-1); + var url = pagename + ((pagetype=="m")?"-module.html": + "-class.html"); + if (dottedName.length > pagename.length) + url += "#" + dottedName.substring(pagename.length+1, + dottedName.length); + return url; + } + } + } diff --git a/docs/frames.html b/docs/frames.html new file mode 100644 index 0000000..2556081 --- /dev/null +++ b/docs/frames.html @@ -0,0 +1,17 @@ + + + + + API Documentation + + + + + + + + + diff --git a/docs/help.html b/docs/help.html new file mode 100644 index 0000000..b4ddb60 --- /dev/null +++ b/docs/help.html @@ -0,0 +1,268 @@ + + + + + Help + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
      [hide private]
      [frames] | no frames]
      +
      + +

      API Documentation

      + +

      This document contains the API (Application Programming Interface) +documentation for this project. Documentation for the Python +objects defined by the project is divided into separate pages for each +package, module, and class. The API documentation also includes two +pages containing information about the project as a whole: a trees +page, and an index page.

      + +

      Object Documentation

      + +

      Each Package Documentation page contains:

      +
        +
      • A description of the package.
      • +
      • A list of the modules and sub-packages contained by the + package.
      • +
      • A summary of the classes defined by the package.
      • +
      • A summary of the functions defined by the package.
      • +
      • A summary of the variables defined by the package.
      • +
      • A detailed description of each function defined by the + package.
      • +
      • A detailed description of each variable defined by the + package.
      • +
      + +

      Each Module Documentation page contains:

      +
        +
      • A description of the module.
      • +
      • A summary of the classes defined by the module.
      • +
      • A summary of the functions defined by the module.
      • +
      • A summary of the variables defined by the module.
      • +
      • A detailed description of each function defined by the + module.
      • +
      • A detailed description of each variable defined by the + module.
      • +
      + +

      Each Class Documentation page contains:

      +
        +
      • A class inheritance diagram.
      • +
      • A list of known subclasses.
      • +
      • A description of the class.
      • +
      • A summary of the methods defined by the class.
      • +
      • A summary of the instance variables defined by the class.
      • +
      • A summary of the class (static) variables defined by the + class.
      • +
      • A detailed description of each method defined by the + class.
      • +
      • A detailed description of each instance variable defined by the + class.
      • +
      • A detailed description of each class (static) variable defined + by the class.
      • +
      + +

      Project Documentation

      + +

      The Trees page contains the module and class hierarchies:

      +
        +
      • The module hierarchy lists every package and module, with + modules grouped into packages. At the top level, and within each + package, modules and sub-packages are listed alphabetically.
      • +
      • The class hierarchy lists every class, grouped by base + class. If a class has more than one base class, then it will be + listed under each base class. At the top level, and under each base + class, classes are listed alphabetically.
      • +
      + +

      The Index page contains indices of terms and + identifiers:

      +
        +
      • The term index lists every term indexed by any object's + documentation. For each term, the index provides links to each + place where the term is indexed.
      • +
      • The identifier index lists the (short) name of every package, + module, class, method, function, variable, and parameter. For each + identifier, the index provides a short description, and a link to + its documentation.
      • +
      + +

      The Table of Contents

      + +

      The table of contents occupies the two frames on the left side of +the window. The upper-left frame displays the project +contents, and the lower-left frame displays the module +contents:

      + + + + + + + + + +
      + Project
      Contents
      ...
      + API
      Documentation
      Frame


      +
      + Module
      Contents
       
      ...
        +

      + +

      The project contents frame contains a list of all packages +and modules that are defined by the project. Clicking on an entry +will display its contents in the module contents frame. Clicking on a +special entry, labeled "Everything," will display the contents of +the entire project.

      + +

      The module contents frame contains a list of every +submodule, class, type, exception, function, and variable defined by a +module or package. Clicking on an entry will display its +documentation in the API documentation frame. Clicking on the name of +the module, at the top of the frame, will display the documentation +for the module itself.

      + +

      The "frames" and "no frames" buttons below the top +navigation bar can be used to control whether the table of contents is +displayed or not.

      + +

      The Navigation Bar

      + +

      A navigation bar is located at the top and bottom of every page. +It indicates what type of page you are currently viewing, and allows +you to go to related pages. The following table describes the labels +on the navigation bar. Note that not some labels (such as +[Parent]) are not displayed on all pages.

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      LabelHighlighted when...Links to...
      [Parent](never highlighted) the parent of the current package
      [Package]viewing a packagethe package containing the current object +
      [Module]viewing a modulethe module containing the current object +
      [Class]viewing a class the class containing the current object
      [Trees]viewing the trees page the trees page
      [Index]viewing the index page the index page
      [Help]viewing the help page the help page
      + +

      The "show private" and "hide private" buttons below +the top navigation bar can be used to control whether documentation +for private objects is displayed. Private objects are usually defined +as objects whose (short) names begin with a single underscore, but do +not end with an underscore. For example, "_x", +"__pprint", and "epydoc.epytext._tokenize" +are private objects; but "re.sub", +"__init__", and "type_" are not. However, +if a module defines the "__all__" variable, then its +contents are used to decide which objects are private.

      + +

      A timestamp below the bottom navigation bar indicates when each +page was last updated.

      + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/identifier-index.html b/docs/identifier-index.html new file mode 100644 index 0000000..bc4bc78 --- /dev/null +++ b/docs/identifier-index.html @@ -0,0 +1,260 @@ + + + + + Identifier Index + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
      [hide private]
      [frames] | no frames]
      +
      + +
      +

      Identifier Index

      +
      +[ + A + B + C + D + E + F + G + H + I + J + K + L + M + N + O + P + Q + R + S + T + U + V + W + X + Y + Z + _ +] +
      + + + + + + + + + + + + + + + + + + + +

      B

      + + + + + + + + +

      C

      + + + + + + + + + + + + +

      H

      + + + + + + + + +

      L

      + + + + + + + + +

      N

      + + + + + + + + +

      S

      + + + + + + + + + + + + +

      U

      + + + + + + + + +

      W

      + + + + + + + + +

      _

      + + + + + + + + +
      +

      + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..2556081 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,17 @@ + + + + + API Documentation + + + + + + + + + diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 10a83ce..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,111 +0,0 @@ -.. BrowserMob Proxy documentation master file, created by - sphinx-quickstart on Fri May 24 12:37:12 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. -.. highlightlang:: python - - -============================================ -Welcome to BrowserMob Proxy's documentation! -============================================ - -Python client for the BrowserMob Proxy 2.0 REST API. - --------------- -How to install --------------- - -BrowserMob Proxy is available on PyPI_, so you can install it with ``pip``:: - - $ pip install browsermob-proxy - -Or with `easy_install`:: - - $ easy_install browsermob-proxy - -Or by cloning the repo from GitHub_:: - - $ git clone git://github.com/AutomatedTester/browsermob-proxy-py.git - -Then install it by running:: - - $ python setup.py install - ----------------------------------- -How to use with selenium-webdriver ----------------------------------- - -Manually:: - - from browsermobproxy import Server - server = Server("path/to/browsermob-proxy") - server.start() - proxy = server.create_proxy() - - from selenium import webdriver - profile = webdriver.FirefoxProfile() - profile.set_proxy(proxy.selenium_proxy()) - driver = webdriver.Firefox(firefox_profile=profile) - - - proxy.new_har("google") - driver.get("http://www.google.co.uk") - proxy.har # returns a HAR JSON blob - - server.stop() - driver.quit() - ------------------ -How to Contribute ------------------ - -Getting Started ---------------- - -* Fork the repository on GitHub - well... duh :P -* Create a virtualenv: `virtualenv venv` -* Activate the virtualenv: `. venv/bin/activate` -* Install the package in develop mode: `python setup.py develop` -* Install requirements: `pip install -r requirements.txt` -* Run the tests to check that everything was successful: `py.test tests - -Making Changes --------------- - -* Create a topic branch from where you want to base your work. - * This is usually the master branch. - * Only target release branches if you are certain your fix must be on that - branch. - * To quickly create a topic branch based on master; `git checkout -b - /my_contribution master`. Please avoid working directly on the - `master` branch. -* Make commits of logical units. -* Check for unnecessary whitespace with `git diff --check` before committing. -* Make sure you have added the necessary tests for your changes. -* Run _all_ the tests to assure nothing else was accidentally broken. - -Submitting Changes ------------------- - -* Push your changes to a topic branch in your fork of the repository. -* Submit a pull request to the main repository -* After feedback has been given we expect responses within two weeks. After two - weeks will may close the pull request if it isn't showing any activity - -Contents: - -.. toctree:: - :maxdepth: 2 - - client.rst - server.rst - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. _GitHub: https://github.com/AutomatedTester/browsermob-proxy-py -.. _PyPI: http://pypi.python.org/pypi/browsermob-proxy diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 567b0da..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,190 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -set I18NSPHINXOPTS=%SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\BrowserMobProxy.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\BrowserMobProxy.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/docs/module-tree.html b/docs/module-tree.html new file mode 100644 index 0000000..b1b3365 --- /dev/null +++ b/docs/module-tree.html @@ -0,0 +1,110 @@ + + + + + Module Hierarchy + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + +
      [hide private]
      [frames] | no frames]
      +
      +
      + [ Module Hierarchy + | Class Hierarchy ] +

      +

      Module Hierarchy

      + + + + + + + + + + + + + + + + + + + + + + + + +
      + + + + diff --git a/docs/redirect.html b/docs/redirect.html new file mode 100644 index 0000000..3674f1d --- /dev/null +++ b/docs/redirect.html @@ -0,0 +1,38 @@ +Epydoc Redirect Page + + + + + + + + +

      Epydoc Auto-redirect page

      + +

      When javascript is enabled, this page will redirect URLs of +the form redirect.html#dotted.name to the +documentation for the object with the given fully-qualified +dotted name.

      +

       

      + + + + + diff --git a/docs/server.rst b/docs/server.rst deleted file mode 100644 index 8af94b7..0000000 --- a/docs/server.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. toctree:: - :maxdepth: 2 - -:mod:`server` Package ---------------------- -.. automodule:: browsermobproxy -.. autoclass:: Server - :members: \ No newline at end of file diff --git a/docs/toc-browsermobproxy-module.html b/docs/toc-browsermobproxy-module.html new file mode 100644 index 0000000..ad8c4f8 --- /dev/null +++ b/docs/toc-browsermobproxy-module.html @@ -0,0 +1,32 @@ + + + + + browsermobproxy + + + + + +

      Module browsermobproxy

      +
      +

      Variables

      + Client
      Server

      +[hide private] + + + + diff --git a/docs/toc-browsermobproxy.client-module.html b/docs/toc-browsermobproxy.client-module.html new file mode 100644 index 0000000..82ea832 --- /dev/null +++ b/docs/toc-browsermobproxy.client-module.html @@ -0,0 +1,31 @@ + + + + + client + + + + + +

      Module client

      +
      +

      Classes

      + Client

      +[hide private] + + + + diff --git a/docs/toc-browsermobproxy.server-module.html b/docs/toc-browsermobproxy.server-module.html new file mode 100644 index 0000000..731a9e4 --- /dev/null +++ b/docs/toc-browsermobproxy.server-module.html @@ -0,0 +1,31 @@ + + + + + server + + + + + +

      Module server

      +
      +

      Classes

      + Server

      +[hide private] + + + + diff --git a/docs/toc-everything.html b/docs/toc-everything.html new file mode 100644 index 0000000..001f345 --- /dev/null +++ b/docs/toc-everything.html @@ -0,0 +1,35 @@ + + + + + Everything + + + + + +

      Everything

      +
      +

      All Classes

      + browsermobproxy.client.Client
      browsermobproxy.server.Server

      All Variables

      + browsermobproxy.Client
      browsermobproxy.Server

      +[hide private] + + + + diff --git a/docs/toc.html b/docs/toc.html new file mode 100644 index 0000000..8706e03 --- /dev/null +++ b/docs/toc.html @@ -0,0 +1,35 @@ + + + + + Table of Contents + + + + + +

      Table of Contents

      +
      + Everything +
      +

      Modules

      + browsermobproxy
      browsermobproxy.client
      browsermobproxy.server

      + [hide private] + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..78e8d1c --- /dev/null +++ b/index.html @@ -0,0 +1,114 @@ + + + + Python Browsermob Proxy Library + + + +
       
      +
      +

      Python Browsermob Proxy Library

      +

      + This is the Python Library for interaction with the Browsermob Proxy. It allows us to create a proxy, set references and generate HAR representations. For more details read the docs. Note that this will only work with Selenium 2.17 onwards. +

      +

      +

      Example

      +
      +            
      +                from browsermobproxy import Server
      +                server = Server("path/to/browsermob-proxy")
      +                server.start()
      +                proxy = server.create_proxy()
      +
      +                from selenium import webdriver
      +                profile  = webdriver.FirefoxProfile()
      +                profile.set_proxy(proxy.selenium_proxy())
      +                driver = webdriver.Firefox(firefox_profile=profile)
      +
      +                proxy.new_har("google")
      +                driver.get("http://www.google.co.uk")
      +                proxy.har # returns a HAR JSON blob
      +
      +                proxy.stop()
      +                driver.quit()
      +            
      +        
      +

      +

      +

      Releases

      + +

      0.7.0

      +
        +
      • Updating travis ci to use browsermob proxy 2.0 +
      • Support to use httpsProxy and httpProxy at proxy creation time +
      • Adding Python 3 support +
      • add sslProxy to Client.add_to_capabilities with tests +
      • Correct docstring for `wait_for_traffic_to_stop` +
      • Removing unused :Args: items +
      • Updating docstrings +
      • Correcting args and params for documentation +
      • updated docstrings for easier formatting on things like RTDs +
      • updated new_har() docstrings +
      • updated client documentation +
      • Added client and server docs +
      • updating version in docs +
      + + +

      0.6.0

      +
        +
      • Added support for parameters in har creation +
      • Bug fixes for tests that are out of date +
      • Setup server constructor to look on path for location of browsermob-proxy executable. As well as looking for a file. Also added example code for using browsermob-proxy with chrome +
      • Fix project name +
      • adding docs +
      + +

      0.5.0

      +
        +
      • Allow proxying of ssl requests with selenium. +
      • Updating case for proxy type +
      + +

      0.4.0

      +
        +
      • Allow setting basic authentication +
      • Adding the ability to remap hosts which is available from BrowserMob Proxy Beta 7 +
      • Merge pull request #6 from lukeis/patch-2 +
      • Update readme.md +
      • initial commit of event listener to auto do record +
      • server.create_proxy is a function, should be called :) +
      • forgot to add the port +
      +

      0.2.0

      +
        +
      • DELETE /proxy/:port/ +
      • /proxy/:port/limits +
      • /proxy/:port/blacklist +
      • /proxy/:port/whitelist +
      • fixing /proxy/:port/har/pageRef +
      • fixing /proxy/:port/har/pageRef +
      • fixing passing in a page ref as the name for the page in /proxy/:port/har +
      • tests around /proxy/:port/har and some cleanup of the implementation +
      • make /proxy/:port/headers work +
      • wrapping selenium_proxy with webdriver_proxy since the project is more than just webdriver +
      • extending the client to play nice with remote webdriver instances +
      • create_proxy sounds and feels like a method to me, let's make it so +
      • ensure the self.process exist, to reduce possibilities of AttributeError +
      • check the path before attempting to start the server +
      • wait longer than 3 seconds for the server to come up +
      +

      0.1.0

      +
        +
      • Remove HTTPLib2 and replace with Requests
      • +
      • Added support for setting headers in the proxy
      • +
      +

      0.0.1

      +
        +
      • Initial release
      • +
      +

      +
      + Fork me on GitHub + + diff --git a/readme.md b/readme.md deleted file mode 100644 index 0ebdefb..0000000 --- a/readme.md +++ /dev/null @@ -1,106 +0,0 @@ -browsermob-proxy-py -=================== - -Python client for the BrowserMob Proxy 2.0 REST API. - - - -How to use with selenium-webdriver ----------------------------------- - -Manually: - -``` python -from browsermobproxy import Server -server = Server("path/to/browsermob-proxy") -server.start() -proxy = server.create_proxy() - -from selenium import webdriver -profile = webdriver.FirefoxProfile() -profile.set_proxy(proxy.selenium_proxy()) -driver = webdriver.Firefox(firefox_profile=profile) - - -proxy.new_har("google") -driver.get("http://www.google.co.uk") -proxy.har # returns a HAR JSON blob - -server.stop() -driver.quit() - -``` - -for Chrome use - -``` -chrome_options = webdriver.ChromeOptions() -chrome_options.add_argument("--proxy-server={0}".format(proxy.proxy)) -browser = webdriver.Chrome(chrome_options = chrome_options) -``` - -Running Tests -------------- - -Install pytest if you don't have it already. - -```bash -$ pip install pytest -``` - -Start a browsermob instance. - -```bash -$ java -jar browsermob.jar --port 9090 -``` - -In a separate window: - -```bash -$ py.test -``` - -If you are going to watch the test, the 'human' ones should display an english -muffin instead of the american flag on the 'pick your version' page. Or at -least it does from Canada. - -To run the tests in a CI environment, disable the ones that require human -judgement by adding "-m "not human" test" to the py.test command. - -```bash -$ py.test -m "not human" test -``` - -See also --------- - -* http://proxy.browsermob.com/ -* https://github.com/webmetrics/browsermob-proxy - -Note on Patches/Pull Requests ------------------------------ - -* Fork the project. -* Make your feature addition or bug fix. -* Add tests for it. This is important so I don't break it in a - future version unintentionally. -* Send me a pull request. Bonus points for topic branches. - -Copyright ---------- - -Copyright 2011 David Burns - -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. - - diff --git a/setup.py b/setup.py deleted file mode 100644 index 5207d3d..0000000 --- a/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -from setuptools import setup, find_packages - -setup(name='browsermob-proxy', - version='0.8.0', - description='A library for interacting with the Browsermob Proxy', - author='David Burns', - author_email='david.burns@theautomatedtester.co.uk', - url='http://oss.theautomatedtester.co.uk/browsermob-proxy-py', - classifiers=['Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: POSIX', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: MacOS :: MacOS X', - 'Topic :: Software Development :: Testing', - 'Topic :: Software Development :: Libraries', - 'Programming Language :: Python'], - packages = find_packages(), - install_requires=['requests>=2.9.1'], - ) diff --git a/start-servers.sh b/start-servers.sh deleted file mode 100755 index 4fab677..0000000 --- a/start-servers.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -TOOLS=$(pwd)/tools -cd $TOOLS/browsermob-proxy-2.1.4/bin/ && \ -./browsermob-proxy --port 9090 & \ -cd $TOOLS && \ -java -Dwebdriver.chrome.driver=chromedriver -Dwebdriver.gecko.driver=geckodriver -jar selenium-server-standalone-3.0.1.jar & \ No newline at end of file diff --git a/stylesheets/style.css b/stylesheets/style.css new file mode 100644 index 0000000..bbc82d3 --- /dev/null +++ b/stylesheets/style.css @@ -0,0 +1,34 @@ +body { + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; + background: gray; + color: white; +} + +a { + color: #00B7FF; +} +.container { + margin: 0 auto; + width: 850px +} + +pre { + font: 12px monaco, monospace; + margin: 10px; + padding: 10px; + border: 1px solid #eee; + border-bottom-color: #ddd; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; + -webkit-box-shadow: inset 0 0 10px #eee; + -moz-box-shadow: inset 0 0 10px #eee; + overflow-x: auto; +} + +.background { + background: #CACACA url(data:image/jpg;base64,/9j/4QBeRXhpZgAATU0AKgAAAAgAAgExAAIAAAAGAAAAJodpAAQAAAABAAAALAAAAABTa2l0Y2gAA5AAAAcAAAAEMDIxMKACAAQAAAABAAAFLKADAAQAAAABAAAA9AAAAAD/4AAQSkZJRgABAQAAAQABAAD/4hn8SUNDX1BST0ZJTEUAAQEAABnsYXBwbAIQAABtbnRyUkdCIFhZWiAH3AABAAMACQAXAClhY3NwQVBQTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFkZXNjAAABUAAAAGJkc2NtAAABtAAAAkJjcHJ0AAAD+AAAANB3dHB0AAAEyAAAABRyWFlaAAAE3AAAABRnWFlaAAAE8AAAABRiWFlaAAAFBAAAABRyVFJDAAAFGAAACAxhYXJnAAANJAAAACB2Y2d0AAANRAAABhJuZGluAAATWAAABj5jaGFkAAAZmAAAACxtbW9kAAAZxAAAAChiVFJDAAAFGAAACAxnVFJDAAAFGAAACAxhYWJnAAANJAAAACBhYWdnAAANJAAAACBkZXNjAAAAAAAAAAhEaXNwbGF5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAAAAASAAAADG5sTkwAAAAWAAAA6GRhREsAAAAcAAAA/nBsUEwAAAASAAABGmVuVVMAAAASAAABLG5iTk8AAAASAAABPmZyRlIAAAAWAAABUHB0QlIAAAAYAAABZnB0UFQAAAAWAAABfnpoQ04AAAAMAAABlGVzRVMAAAASAAABoGphSlAAAAAOAAABsnJ1UlUAAAAkAAABwHN2U0UAAAAQAAAB5HpoVFcAAAAOAAAB9GRlREUAAAAQAAACAmZpRkkAAAAQAAACEml0SVQAAAAUAAACImtvS1IAAAAMAAACNgBLAGwAZQB1AHIAZQBuAC0ATABDAEQATABDAEQALQBmAGEAcgB2AGUAcwBrAOYAcgBtAEsAbwBsAG8AcgAgAEwAQwBEAEMAbwBsAG8AcgAgAEwAQwBEAEYAYQByAGcAZQAtAEwAQwBEAEwAQwBEACAAYwBvAHUAbABlAHUAcgBMAEMARAAgAEMAbwBsAG8AcgBpAGQAbwBMAEMARAAgAGEAIABDAG8AcgBlAHNfaYJyACAATABDAEQATABDAEQAIABjAG8AbABvAHIwqzDpMPwAIABMAEMARAQmBDIENQRCBD0EPgQ5ACAEFgQaAC0ENAQ4BEEEPwQ7BDUEOQBGAOQAcgBnAC0ATABDAERfaYJybbJmdphveTpWaABGAGEAcgBiAC0ATABDAEQAVgDkAHIAaQAtAEwAQwBEAEwAQwBEACAAYwBvAGwAbwByAGnO7LfsACAATABDAEQAAHRleHQAAAAAQ29weXJpZ2h0IEFwcGxlLCBJbmMuLCAyMDEyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAA81IAAQAAAAEWz1hZWiAAAAAAAABtgwAAOZQAAAJbWFlaIAAAAAAAAGPgAAC38QAACeZYWVogAAAAAAAAJXMAAA58AADG62N1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANgA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCjAKgArQCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//cGFyYQAAAAAAAwAAAAJmZgAA8qcAAA1ZAAAT0AAACg52Y2d0AAAAAAAAAAAAAwEAAAIAAAAGABwARACBANMBHgFdAakCAAJYArsDJwOaBBcEnAUsBccGbgcfB9MIlQlgCi4LBAveDPEODQ8zEFsRghKxE+cVHBZZF5cY3BolG3Acvh4PH2cgviIZI3IkvCX6JzYocCmnKtosBy0tLk4vZjB4MYEyhTOCNH01dDZnN1E4KjkEOd46uTuWPHU9VT43PxtAAkDsQddCxUO1RKdFnEaSR4pIgkl7SnRLbkxpTWVOZE9kUGRRaFJuU3RUfVWGVo5Xl1ifWadar1u2XLxdwl7GX8tgz2HTYtdj22TiZe5m/mgTaSxqSGtmbIhtrG7Qb/RxF3I4c1l0eHWMdpt3rHi+edJ66XwCfR5+PX9fgIOBqoLTg/6FHoYxh0OIV4ltioeLpIzHje+PHZBSkYySy5QPlVWWmZfcmRyaWpuXnNCeCJ9AoHihr6LopCKlXKZyp4CokKmiqrir0qzwrhOvO7BpsZuyz7QItTe2Vrd0uJC5q7rCu9W85b3xvvq//8EDwgTDBsQJxQrGB8b9x+zI0MmnynLLMcvnzJHNN83gzqvPddA/0QjR0tKb02TULtT51cXWktdh2DjZGtn92uHbxNyl3YbeZd9B4Bzg9OHK4p/jduRQ5S3mDebx59royem86rTrseyw7bPuru+o8K3xw/Lw9Dj1nPce+L36c/w+/hn//wAAAAUAGQA8AHEAuAEKAUQBiAHXAisCgwLlA08DwgQ9BL8FTAXlBokHNgfmCJ0JXAohCuwL6wzxDgAPDRAkETgSUhN0FJUVuhblGBIZQRp3G60c6B4lH2MgoSHQIvYkGiU7JlsncyiJKZkqoiujLJ4tky6CL2wwUjE0MhMy5zOzNH01RzYQNtk3ojhsOTY6ADrJO5I8XD0mPe8+uj+IQF1BOEIUQu9Dy0SnRYRGYkdASB1I/EnbSrpLmUx4TVpOP08mUA1Q9VHfUspTt1SjVZFWgVdyWGFZU1pEWzVcJV0WXgle/V/zYOth5GLgY91k22XbZtxn3Wjfad9q3WvbbNpt2m7bb91w4HHlcutz83T8dgZ3EngbeSF6J3sufDZ9P35Jf1WAY4F0goaDm4SyhcuG6YgOiTOKWYt9jKKNxo7qkBCRNpJdk4aUr5XXlu+YAJkSmiabPZxXnXSelp+9oOeiFaNHpHylqabIp+epBqomq0WsZK2DrqSvxrDpsg2zMrRStWm2fbeRuKS5trrHu9i86L35vwrAHMEuwjPDJcQTxQDF7MbXx8HIq8mUynzLZcxOzTjOKM8h0BzRGdIZ0xrUHtUj1ijXL9g12TraQNtG3E7dWt5r34PgouHK4v3kOeV95sfoGOlr6sHsJ+2h7zHw4vKz9Kf2vPju+zf9lP//AAAABAAUADAAWgCTANwBHQFWAZkB5AI0AooC6QNOA7oEMASuBTUFwgZYBvQHlAg7COgJpQp4C2AMTA04DiUPFxANEQcSARMDFAUVBhYPFxsYJhk1GkUbVhxpHWweYh9YIEshPCIoIw8j8CTLJaAmbic4J/kotSluKiUq1yt/LCAswC1hLgEupC9IL+wwkjE5MeEyizM3M+I0jzU+Nes2lzdCN+04mTlFOfA6mztHO/M8nz1MPfg+pD9SP/9AtkFyQjJC80O0RHVFNkX3RrdHeUg7SPtJvUp+S0BMAEzCTYROSE8NT9RQnFFnUjNTAlPRVKNVdVZJVx1X7li/WZBaY1s1XAhc3F2xXohfX2A4YRNh72LMY6xkkGV1ZllnPWghaQVp6WrNa7FslW15bl1vQnArcRlyB3L1c+J0z3W6dqN3i3hxeVV6OHsZfAF8+n4BfwmAEoEagiODK4QzhTqGQIdGiEuJUIpdi3KMiI2fjrOPxpDXkeWS75P3lPyV/pb+mAqZMJpZm4Scrp3XnwCgJ6FNonKjlqS4pdmm/6gxqWSql6vMrQCuNK9psJ6x07MHtDy1cbalt9e5Cbo6u2u8mr3IvvTAH8FIwnHDmMS/xeLHBcgpyU/KecuozN3OGs9e0KnR+9NS1MPWX9gY2frcKt6/4dHldOm37pPz9PnI//8AAG5kaW4AAAAAAAAGNgAAo6IAAFckAABSTQAApCwAACUyAAANvwAAUA0AAFQ5AAIZmQABwo8AAUeuAAMBAAACAAAADgAqAEoAbACPALIA1QD6AR4BRAFrAZMBswHVAfcCGgI/AmQCigKwAtgDAAMpA1MDfQOoA9QEAAQuBFwEigS6BOoFGwVNBYEFugX0BjAGbQasBu0HMAd2B78ICghZCKsJAglcCbsKHQqDCuwLWwvXDFUM1g1YDdwOYg7pD3EP+hCEEQ8RmxIoErYTRRPVFGgU/BWSFioWxBdfF/sYmBk3GdYadhsYG7ocXh0FHa0eWB8FH7QgZiEaIdEiiyNHJAUkxiWJJk8nFifbKJ8pYiokKuYrqCxqLSwt7i6yL3cwPzEJMdYypTN3NFM1NjYZNv434zjIOa06kjt3PFw9QD4lPwk/70DUQbpCtEO0RLVFt0a5R7lIuUm2SrFLqkyfTZNOhE90UGNRUFJAUzJUJlUeVhhXFlgWWRpaIFsoXDNdP15NX1tgamF6Yo1j0GUTZlZnmGjZahdrU2yMbcNu9nAncVZyhXOydN52KHd1eMZ6G3t0fNN+OH+kgReCkYQShZmHJYi2ikSL2I10jx2Q15KqlJ+Wu5kOm5WeOaBiopGkxqb/qT6rf63BsASyR7SJtp+4tbrNvOq/DcE3w2vFqcfyykXMoM7z0UPTi9XL2ALaLtxR3mzggeKS5KDmxujt6vbs4e6t8F3x9PN09N/2O/eM+NT6EftJ/H39qv7W//8AAAAQAC8AUwB4AJ8AxQDrARMBPAFmAZEBtAHZAf4CJQJMAnUCnwLJAvQDIQNOA3wDqwPbBAsEPQRvBKIE1gULBUEFeQW2BfUGNgZ5Br0HBQdPB5wH7AhBCJoI9wlZCcAKKwqbCw8LjQwUDJ4NKw28DlAO5w+BEB8QwRFlEg0StxNdFAEUpxVQFfwWqhdaGA0Ywxl7GjUa8xuzHHQdNR33HrsfgSBIIRAh2yKnI3QkQyUVJegmvieWKHMpUCouKw0r7SzOLa8ukS90MFkxPjIlMw4z+TTqNd420zfJOME5ujq1O7A8rD2pPqc/pkCmQadCr0O7RMhF10bnR/hJCkocSy9MQU1TTmZPeFCLUZ1SqFO0VMNV01bmV/pZEVopW0NcXV15XpZfs2DSYfFjIGRgZaBm4GggaV9qnGvYbRFuSG9+cLFx43MVdEV1gXbNeBp5anq8fBB9Zn6+gBeBcYLMhCeFg4bgiD2JqosijJyOGo+bkR+SppQwlb2XTJjdmm+cA52Yn2ChOaMWpPmm4KjNqr+stK6usKqyqLSmtoy4cLpSvDO+Er/wwc7DrcWNx2/JVcs+zSnPFND80t/UutaM2FTaEtvF3XDfE+Cw4knj3OVt5wXok+oW64zs9e5S753w2/IP8zf0UvVp9nP3evh6+XX6bftg/FL9P/4s/xX//wAAABQAOQBiAI0AuADkAREBQAFwAZ4BxwHxAh0CSwJ6AqoC2wMOA0EDdgOtA+QEHARWBJEEzQULBUkFjAXWBiIGcQbDBxkHcwfSCDcIowkWCZEKFQqfCzEL2AyEDTUN6A6fD1gQFBDSEZQSWBMhE/IUxxWhFn8XYxhKGTYaJhsbHBMc/R3mHtEfwSC0IasipiOkJKclrSa3J8Yo2CnrKv8sFC0pLj8vVTBsMYUynzO7NOA2CDcyOF85jjq+O/A9Iz5XP4xAwkH4QypEXkWWRtBIDUlOSpJL2U0jTm9Pv1ERUl1TplTzVkRXmFjxWlBbtF0fXo9gBWGBYu5kOGWDZtBoH2lxasVsG211btJwMnGVcvx0ZXXDdxp4c3nOey18kH34f2aA2oJUg9aFXobriH+J5YtCjKGOAY9kkMmSMJOblQmWepfvmWea45xineOfUqDAojCjoaUTpoen/al0qu2sZ63jr2Gw4bJis+W1bLb3uIO6EbujvTe+zsBpwgjDq8VRxvvIqMpYzArNxc+B0T/S/NS31m7YItnP23bdFt6x4Ebh1+Nk5O7mVeek6OvqIutM7Gntau5k70TwH/Di8aXyUPL58530MPTE9VX12PZa9t33VvfM+EL4t/kl+ZH5/fpo+tD7NfuZ+/38YvzB/R/9fv3d/jv+lf7w/0r/pP//AABzZjMyAAAAAAABDEIAAAXe///zJgAAB5IAAP2R///7ov///aMAAAPcAADAbG1tb2QAAAAAAAAGEAAAnKQAAAAAxkOEgAAAAAAAAAAAAAAAAAAAAAD/2wBDABEMDQ8NCxEPDg8TEhEUGiscGhgYGjUmKB8rPjdBQD03PDtFTWNURUldSjs8VnVXXWZpb3BvQ1N5gnhrgWNsb2r/2wBDARITExoXGjIcHDJqRzxHampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqamr/wAARCAD0BSwDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDuyQoJJwB3qM3EI6yL+dFz/wAe7/So5RN5h2FsHjp0oAebq3HWVPzpUuYZH2JKrN6A1VJuBnBk6Y5A/wAaeC3n2wYknLdf92gC3nFLWR4gMoGnCFwjteIATnHRuvrWbDql9Lf6cst0kaO08T4QBZGRsL17nFAHU0VydtrV0lnYia/gVppJklllUfJtPA6jn61d03WZZrBrq7liVltvNaFUII5YbvocDijpcDforIeOWPTrOzeRhPO67zuOc53tg/mPpVKTXLpNSaEGIFbxbcWxU72jP/LT+vpR1sB0lFc1Brl1IL+Iy2xuIULo2R5IGcDLZ4PsakGtG40GVo5yt8YZSnyDJKDkrjII96OlwOgzzilrjm1C8RmvYLuKZo9NSR2K5DHe2RgHA9DV5dbuzrUtu4gjhiYDYxw7rtzuUdSc+lAHR0VySeJZ2gvZEkikEcCTREgZwWwcgHt+lSXmtzzLLJa3aRQRXsUYlC8FCBnOe2T1oA6miubj1u5bUFiEkLE3RgNuF+cJjiTr07+nNVU1rVpII5BLbDzLSS4/1R42nGOvfNAHXUVzK+IJH1K1gV0AkZEkRgBgsm7K85PNU7fXNQj06033EbySzSxyyyADySudqt2GfeiwHY5x1pa47V9YuJbWaCaeCD/Ro3CplvOZjztb0GKml1e+tH1U+csphuEVI2Ufuozj5vpQB1dFcvc67d29jBO89ps3uJGjdWZlHQqM4J55ApLvWb21udQdJA6qsLRxOuCit95vXjvQB1NFc7FqmoTmyhjmtC08siGVfnG1RkHg4zUl1rQbUIIILuCC3cPunkXgupwUGcDNAG9RXNW+u3L30SSPD807xyW+0740UEhz+X05ovfEgie48iWJlKQvb5U5cMSGP06UAdJmlrmtP1B4teubR2CRSXL7XbnewVfkHp61rac7TzXdyWJRpTHGM8BU4/U7j+VAF+iiigAqsfvv9as1WP33+tABRS0YPoaAEooooAKKKKACiiigApB95qWkX7zUAIskb52urY64OcUqurruRgw9Qc1zUsfmy6ibGIlHtsfu4TFghj8vIG4kE81Yjhlm+2DTYhHaSsgCkGLgA7toI4zwM4oDqbwIIyCCPUUVn6CkkejWqSxeUypjbnoO1aFDAKKKKACiiigApP4z9KWk/jP0oAWiiigAoooyMkZ5HUUAFFFBIAyTgUAFFFFABSfxn6UtJ/GfpQAtFFGQO/WgAooooAKKKKACiiigAooooAKKKKACiiigAoPQ0UHoaAEX7o+lLSL90fSloAKKKKACiiigBokRmKq6kr1APSkEsbKWEiFR1IYYFY9sbeXV5pRbmAxB02iBgZf7zM2MHpwM1FYm2a2vbr7FgMg/0MW5UYHQEEYLHvigDd82Lbu8xNvTO4YpzdB9RXMX2mpa2VkpiTLyvJLtgLorMh/hHYHArd04Mul2aujIwjQFXOSOO9AFuiiigAooooARmVQWYhQO5OKaZYwoYyIFboSwwar6pKkNhLJJbG5Cj/VBN249uKyJorYaEYyQWkMhXNozBWPUKuMqPSgZ0BkRWCl1DHoCeTTq5678qU2VvPatE5iRnm8lnZMHhFYA4Oc81Yl+3yXpxcTpG115W1VGFj253dPXvTsI2aoTf8h+w/65yf0rPS6vVk07fJO5YBZIghBOWxuJxjgdRxWhN/yH7D/rnJ/Sqhv9/wCQ1ubFFMkkSJcuwA/nTY54pG2q3zehGD+tRYRLRRRQAUUUUANboPqKdTW6D6inUAFFFFABRRRQAUUUUANT7i/SnU1PuL9KdQAUUUUAFFFFABTR98/QU6mj75+goAdRRRQAUUUUAFFFFADW6r9f6U6mt1X6/wBKdQAUUUUAFFFFABRRRQA1PuL9KdTU+4v0p1ABRRRQAUUUUAFNXq31/pTqavVvr/SgB1FFFABRRRQAUUUUANbqv1/pTqa3Vfr/AEp1ABRRRQAUUUUAFNf7jfSnU1/uN9KAHUUUUAFFFFABRRRQAUUUUARXP/Hu/wBKytQnuPtJSZnhtem6MZz9TWrc/wDHtJ/u1mzXilmCzQlT/tL/AI1cJcrvYmSuiG8dI/KNtNIJQgCKozuHbNWbSSZ5rc3ChXy3A9NtVvtSr92SDOMDBUY/Wp7SVZbuHa6ORuztIOOKcp3VrCUbO5qkA9RnFJsXj5RwcjinUVmWV5bK3mnimkjBeEkp6c9eO9PlgimjMckashxkEdcVLRQBG8MbyxysgLx52k9s9adsXdu2jd645p1FADRGgBAReevHWgIoAAUDHTinUUANCIBgKoHpigopYMVGR3xTqKAGCNB0RfTpS7ExjauPTFOooAbsUNu2jPrjmjav90enSnUUAN8tM52Ln1xQY0IIKLg8kY606igBpjQ4yi8cDijYpJO0ZPB4606igBnlR4A2LgdOOlKUUnJUE4x0p1FADQirjaoGOmBQY0IwUUjr0p1FADdi7i20bj3xzR5af3F6Y6U6igBNq/3R1z0pkMMdvEsUShEUYAHapKKACiiigArO1LzvsN59mz52xtm3rnHb3rRqsfvv9aAOUuZNLGnXMdgiG4azkZ5F++MYyH75JPf0q1JaabcaS7wxWUpRwMwLkDJGa6GlzQBHDDFbxiKFFjjXoqjAFPoooAKKKKACiiigApB95qWkH3moAXNFZNuk0K26BWZT865H3TtOQaV5J3hwJZTlVZztwUbIyBx9aANWiqV/G01tEiMxJcEN+BwarhrjzHudjK7x4xjO0Aj/AOuaANWk3KRkMMdc5qgZpQwXzZPJ3kebt5xj6evtUIRzZ7drD/Rz/DznPSgDVR1dQyMGB7g0pIUEk4A7ms6TzYS6xZAygLbQDjB9qjuHmaBkkkb/AFQxsXIc557UAatJ/H+FLSfxn6UAc019eW8cim9OftciSPIVHkr8xXkg4BwOo+mKsvqN0tzbIZ4zFIqefIibliJ9D6N79K3aWhAYEFxONPvo3u3luTcNCgbGY9zYU8dsHP0omE9rf3T20vlxxJAuzYDuGWGMntj0rceNHKF1DFDuXPY4xn9TTqEDMC3uLs/uVvmaV714mLKrGNcMRgY9hjNQ3Fxevp8yXE/miW1lJHlhcFWAB49Qef0xXS0tACdqKKKACk/jP0paT+M/SgDLbZ5b5/4/fMOP72c8Y9sYpVMrzKhnbeJ2HIB2jFalFAGX9ruP3I3ouVzlsAMc89vT0xVy2aR3lZ3yocqq4AxirFFABRRRQAUUUUAFFFFABRRRQAUUUUAFB6Gig9DQAi/dH0paRfuj6UtABRRRQAUAgjIOabLt8tt+NuOcjIqpZMIkkyODJgFFwp+g7UAXc+9G4HvVFhie7EIw7IMYHVuaqhZPKVIVTPyHeI8Yb0PrQBsZA70jdB9RWTMgaGFRHtYM2/zFJ+bHU+taFtn7JBkMpwvDdaAJ6KKKACiiigAzjknFJuGM5HNRXTIkDNJH5gH8OM5qm8SCw25j3HcRlMgZ7CgDS3AcZorNlCSCGNo9jlFJkZclQOwPrUjm5ac4ldUMuzAUcDHWgC9VCb/kP2H/AFzk/pTUmnBty7OQeGUDBJz1PHSnTf8AIfsP+ucn9KuG/wB/5DQ7UpWScjodo2n271TiuHVgqkliRtHvmty4torlNsq5x0PcVFb6fb2770Ql+xY5xWiqJQtYxcG5XLdFFFYGoUUUUANboPqKdTW6D6inUAFFFFABRRRQAUUUUANT7i/SnU1PuL9KdQAUUUUAFFFFABTR98/QU6mj75+goAdRRRQAUUUUAFFFFADW6r9f6U6mt1X6/wBKdQAUUUUAFFFFABRRRQA1PuL9KdTU+4v0p1ABRRRQAUUUUAFNXq31/pTqavVvr/SgB1FFFABRRRQAUUUUANbqv1/pTqa3Vfr/AEp1ABRRRQAUUUUAFNf7jfSnU1/uN9KAHUUUUAFFFFABRRRQAUUUUAIdpBBwQag+x2n/ADwh/wC+RQ7BELHoKCZP+eDfmP8AGgA+x2n/AD7w/wDfIp8cEEJJijjQnuoAqIvKP+Xd/wDvpf8AGkEzeYqPCybs4JIP8jQBayPUUZHqKioyM7cjPpQBLkeooyPUVWnuIrcIZXC+Y4Rc92PQVJQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeoquSN7896fUDffb60ASZHqKMj1FRUUAS5HqKMj1FRUUAS5HqKMj1FRUUAS5HqKMj1FRUUAS5HqKaCNzcimUg6mgCbI9RRketUYr+0nMgiuI38rl8N9360+C6t7mIywTJJGOrKeBQBbyPUUZHqKrxSxzRrJE6ujDKspyCKfQBLkeooyPWoqKAJcj1FGR61FRQBLkeopuRv6jpTKT+L8KAJsj1FGR6ioqKAJcj1FGR6ioqKAJcj1FGR6ioqKAJcj1FGR6ioqKAJcj1FNyN55HSmUn8X4UATZHqKMj1FV45UlUtGwZQxUn3Bwf1FOBB6EHvQBNkeooyPUVFTPMTzBHuG8jdtzzj1oAsZHqKMj1FQI6yAmNgwBIJHqKdQBLkeooyPUVFTGlRXRCw3SZ2j1x1oAsZHqKMj1FRUUAS5HqKMj1FQ5x170tAEuR6ijI9RUVB4GTwKAJcj1FISMHkVHSHpQBKpG0cjpS5HqKhHQUtAEuR6ijI9RUVFAEuR6ijI9RUVFAEuR60ZHqKpR31rLM8MdxG0kedyg8jHWmJqVlJC8yXUTRx/fYNwv1oA0Nw9aaxHHPcVQ/tXT/JEv2yDyy23dvGM9cVaDBlVlIKnBBHegCfI9RRkeoqrJPFE8aSSKjSHCAn7x9BTTeWwuhamePzz/wAs8/N69KALmR6ijI9RVKO+tZZJEjuI2eIEuAfugdc01dRsngedLmJokOGcNwKAL+R6ijI9arQzRXESywuskbdGU5BplveW10zrbzxylPvBTnFAFzI9aMj1FV3lSNkV2wZG2r7nGf6U+gCXI9RVCUj+37Dn/lnJ/SrVUpP+Q7Y/9c5P5Crhv8n+Q0bWR6ijI9RUVFQIlyPUUZHqKiooAlyPUUZHqKiooAkYjA5HUUuR6ioW6D6iloAlyPUUZHqKiooAlyPUUZHqKiooAlyPUUZHqKiooAkQjYvI6UuR6ioV+4v0paAJcj1FGR6ioqKAJcj1FGR6ioqKAJcj1FICN55HQVHSD75+goAmyPUUZHqKiooAlyPUUZHqKiooAlyPUUZHqKiooAkYjK8jr/SlyPUVCeq/X+lLQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBIhGxeR0pcj1FQp9xfpS0AS5HqKMj1FRUUAS5HqKMj1FRUUAS5HqKRSMtyOv9KjpF6t9f6UATZHqKMj1FRUUAS5HqKMj1FRUUAS5HqKMj1FRUUASMRleR1/pS5HqKhbqv1/pS0AS5HqKMj1FRUUAS5HqKMj1FRUUAS5HqKRyNjcjpUdI/wBxvpQBNkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBLkeooyPUVFRQBHcf6h/pSzDMhCkbyOm/BP4Ulx/qH+lVpI28+TMIbc+4SFgMDH50m7CbJY+Czb1QAYJ37v/1UO264tsNu5bkf7tZwt5QhXY20AY5Xdwex6EfWp7UOslusgAO5zgADsfSpjJt6oSbYmvwzT2IS388uHDYh74zweRx9DWUum3D3onuYpYPMsPKMkcpxC4z1Oc9PrXUE4GTSAq6gggqR17EVZRzNnDfX+n2V3MTLI1zGxCn5RGgI3c+vX8afpsep2c081zFdXE4D7lDDy5fmyuCTwcewrpAAAAMY9qRHVwSpyASPxFAHPrb3f2i+NzFemZy3kzRSDaqEcADOM/hVb7NqR0YxNBcq6TEoFbLSKBxv+bIBPoa6lmCKWY4AGSaAQwBHQ0ARWQlFlAJ0CSiNd6g5wccjPepqKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqBvvt9anrP1KOSayu4oTiV42VecckUAC31ozOq3UBKAlwJB8oHUnnim/wBo2OAft1rg9D5y8/rWRdP52my2lrp8yf6I4OYGUq3ACjjBzz0z0q3IgudMdVjkdwy/ftzGeo6AgUAacckcqB4nWRD0ZSCD+Ip9IAFGFAA9BS0AFFFFABRRRQAUg6mlpB1NAGDcW11eSXrLDOFkg2AXG0cg52rg9OvX2qY2lzeyXUoX7NHOyAxzDlguc5we+R+Va4kRgCrqQ3AIPWnUAUdHhmt9Lt4bhVWRFwVUdKvU1nVACzBcnAye9G9d+zcN2M4zzigB1FFRiaMru3jGN3Xt60ASUUyOVJRlGzSuyopZjhRyTQA6k/i/ClpP4vwoAWiubaK7gjkSNrtVN25lIEjHYdxUrjkjOM7fxqw5vhcW+Hung2oLhghXJ7FR1H+1ihAbZ468UKwZQykEEZBB4NYUMbwWN3bE3AmnuWjUuWPDMeVJ4+7k8elWSHTVGWX7UsSqotxEG8vvndjj0+9QBq0Vzpe8+wSjddhkmBD7ZczDHTH3kHuOOK3rdme3jZ0MbFQSjHJU46E0ASUUUUAFJ/F+FLSfxfhQBzA+zbift0P72W4EgN0uAjb9vGfXB9eahhls7e3WRZlSRbFo8/aVO1wPTd37V1Cm2dyi+UXHUDGaf5Uf/PNP++RQBz2n3tqruzXOIiseVkulLGQNy33unTP06VaTVbJZb67N5b5QeXGPNXkAZyOe5P6Vr+VH/wA80/75FHlR/wDPNP8AvkUAc7cT2sUNrH9qSaFIiCsN0qsJD0J+Ye9CXqpfWrSXkUrCILK/nqEU7Tkr83Un1FdF5Uf/ADzT/vkUeVH/AM80/wC+RQBh6VqVvBCySzxsrS4DPOm8gjlm+Y/p+VVLMWQgt4HuY4xHJJ5h+1L82QcEHdnB49K6fyo/+eaf98ijyo/+eaf98igDmY7oC4tDPfqVWOMApOh2sD8275u/HPNMW+/eXLCaONnjbgXKlSwbIxlu4+ldT5Uf/PNP++RR5Uf/ADzT/vkUAczcXdvdyCeaVPLS6V1j+0oG2bAD0b196X7WPPkIvI/N/eb5DcpsdSPkCjPXp6V0vlR/880/75FHlR/880/75FAHNMYFLMmoqxWKNlzeLzJk7j19Me1RXNylxNdr50SiVJU4uV2tx8p+9/QV1XlR/wDPNP8AvkUeVH/zzT/vkUAczHcwrd27fbAkKrGIwJ0OzH3g2W7/AI1qaJMkqXHz+ZMH/eOJQ6tycYwTgY+laXlR/wDPNP8AvkUoVVB2qF+gxQAo6ClpB0FLQAUUUUAFFFFAGVCZ5tSeW4tJk8kOkHC7CvHOc5ycelMtGujHc3clnKL1kAEbhQvHRRg89eSa1t67tu4bsZxnnFMFxCQxEqYXrz0oAx72wmit7QRLNJIHd5niC79zIQTzx1NadhG8OnW0cqLG6RqpRei4HSpTcQhA5lQKehLcGn5BAIOQcUAUdU8zNqY7aWcpMHPlgHAAPqR60wpMurB7eOdVkIM5fHlkbe3fPQfnWnRQBkLHLNqU8rw3Pk+Q0Z8zb3PRMHv70tmbmG0nDR3flKQIQQvnAYGe+Ota1FAGbpaz29nHHLBJl5HJJxuAJJBb3PtRpaTxyzR7JktVA8sTY3Zyc4x/D0rRZgqlmIAHUmmNPEiqzSIFboSetAGMbe5bVEke3nZkuGbzd/7vy9pCgDPuB0quBeW8E900UsDRhZQrPlWYE5XqeoP8q6Fp4lYK0ihm6AnrTyARgjIoAwxb3iT2UhWaaU4aXJ/drubLdxyB0GCOlaEn/Idsf+ucn8hV2qUn/Idsf+ucn8hVw3fz/Ia3NN5FTGcknoB1NR/aF/uP+n+NQ3LbJju43AYP9Kg3r61zTqNOxlKdmXftC/3H/T/Gj7Qv9x/0/wAapb19aN6+tR7Zk+0Zd+0L/cf9P8aPtC/3H/T/ABqjvX1o3r60e2Ye0Zda4XA+R+o9P8aX7Qv9x/0/xqgzrxz3FLvX1p+2Y/aMvfaF/uP+n+NH2hf7j/p/jVHevrRvX1pe2YvaMvfaF/uP+n+NH2hf7j/p/jVHevrRvX1o9sw9oy99oX+4/wCn+NH2hf7j/p/jVHevrRvX1o9sw9oy6twu0fI/T2/xpftC/wBx/wBP8aoq67Rz2o3r60/bMftGXvtC/wBx/wBP8aPtC/3H/T/GqO9fWjevrS9sxe0Ze+0L/cf9P8aPtC/3H/T/ABqjvX1o3r60e2Ye0Ze+0L/cf9P8aQXC7j8j9B6f41S3r60gddx57Cn7Zj9oy/8AaF/uP+n+NH2hf7j/AKf41R3r60b19aXtmL2jL32hf7j/AKf40faF/uP+n+NUd6+tG9fWj2zD2jL32hf7j/p/jR9oX+4/6f41R3r60b19aPbMPaMum4XK/I/X29PrS/aF/uP+n+NUC65XnvS719aftmP2jL32hf7j/p/jR9oX+4/6f41R3r60b19aXtmL2jL32hf7j/p/jR9oX+4/6f41R3r60b19aPbMPaMvfaF/uP8Ap/jR9oX+4/6f41R3r60b19aPbMPaMurcLsX5H6e3+NL9oX+4/wCn+NUFddo57Uu9fWn7Zj9oy99oX+4/6f40faF/uP8Ap/jVHevrRvX1pe2YvaMvfaF/uP8Ap/jR9oX+4/6f41R3r60b19aPbMPaMvfaF/uP+n+NItwuW+R+vt6fWqW9fWkDrlue9P2zH7Rl/wC0L/cf9P8AGj7Qv9x/0/xqjvX1o3r60vbMXtGXvtC/3H/T/Gj7Qv8Acf8AT/GqO9fWjevrR7Zh7Rl77Qv9x/0/xo+0L/cf9P8AGqO9fWjevrR7Zh7Rl03C5X5H6+3p9aX7Qv8Acf8AT/GqBdcrz3pd6+tP2zH7Rl77Qv8Acf8AT/Gj7Qv9x/0/xqjvX1o3r60vbMXtGXvtC/3H/T/Gj7Qv9x/0/wAao719aN6+tHtmHtGXvtC/3H/T/Gka4XY3yP09v8apb19aRnXaee1P2zH7Rl/7Qv8Acf8AT/Gj7Qv9x/0/xqjvX1o3r60vbMXtGXvtC/3H/T/Gj7Qv9x/0/wAao719aN6+tHtmHtGXvtC/3H/T/Gj7Qv8Acf8AT/GqO9fWjzF9aPbMPaM0FnViAQy56ZFSVktLxsTlm4A9+1aw6VtCXMjSLuR3AJgcAEnHQVnS3MUjE+Tcgn0g/wDrVrbT6Uu1vSrKMTzowcrFdKfaDH9KntZDNdRkRzAJkkuhXtitTa3pSbW9KAK94SYCi/ekIQfj1/TNV5UkF4AiyNGV2kchV46jtWhtPpRtPpQBjxpNFHBCm9TKNjAk5XBySPwp8sVwAoXzFTfITtBJ5PB4rV2HOcc0bT6UAZkizGZ8CSQPGRyCADt7djmkeC4jRliMpXahOSSep3Y/TpWptPpRtPpQBlPHc7YQHm2AHkKcg54yM+nrQYXWO4AEyuZdwIDEMPw/pWrtPpRtPpQBHAWMCF12ttGVJzin0u0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACUUu0+lG0+lACVA332+tWNp9KgZTvbjvQA2il2n0o2n0oASil2n0o2n0oASil2n0o2n0oASil2n0o2n0oASkHU07afSkCnJ4oAzYbeaIQhFO0/MQf4Gwf501opXiI2zY2jeGJ5bI6frWrtPpRtPpQBTu4TPBHGobG4deo4PNV/KucvKVIldPmx25HA/DNam0+lG0+lAGcRJkfLP5G/7uTu6fnjNNEMptthR/8AUkY981p7T6UbT6UAZ80cw3iPfsyvckkc596jmjlaIqwmk/dgJgEc98//AF61Np9KNp9KAEpP4vwp20+lJtO7p2oAKKXafSjafSgBpAOMgHHSlpdp9KNp9KAEopdp9KNp9KAEopdp9KNp9KAEpP4vwp20+lJtO7p2oAz/ACJAskpDMys5RBweT1zRBHK7or+aEDMeSRkcYrR2n0o2n0oAzdtx5c6oJCTghjkE88gD6elPiikZ4gzSlBuJzlfoDV/afSjafSgBKKXafSjafSgBKKXafSjafSgBKKXafSjafSgBKKXafSjafSgBKKXafSjafSgBKTtTtp9KCpx0oAaOgpaApwOO1LtPpQAlFLtPpRtPpQAlFLtPpRtPpQBnfZ7gXDO20l0YFhnjpgf596W382NNp84IqAcqMhvb2rQ2n0o2n0oAy2il8mL5ZOHc7guWwQeSKu24ZbaJWXaQACPSp9p9KRlPHHegAopdp9KNp9KAEopdp9KNp9KAGSf6tsgtx0Azmqe6QWkUaxSAkbWOzJUfSr+0+lG0+lAFGUEiOARSeTtBJC5PHQe1I0Mjzli0oBlwcMQNuP8AGr+0+lG0+lAGcizK1uSJGI4YHOOvXP8AjT5P+Q7Y/wDXOT+Qq9tPpVGQH+3rHj/lnJ/IVcN/v/IaNN0SRdrqGHoai+x2/wDzyH5mrG0+lG0+lZ2Qiv8AY7f/AJ5D8zR9jtv+eQ/M1Y2n0o2n0oshWRX+x23/ADyH5mj7Hbf88h+ZqxtPpRtPpRZBZFZrO2wP3Q6juaX7Hbf88h+ZqdlOBx3FLtPpRZBZFf7Hbf8APIfmaPsdt/zyH5mrG0+lG0+lFkFkV/sdt/zyH5mj7Hbf88h+ZqxtPpRtPpRZBZFf7Hbf88h+Zo+x23/PIfmasbT6UbT6UWQWRWWztto/dDp6ml+x23/PIfmanVTsXjtS7T6UWQWRX+x23/PIfmaPsdt/zyH5mrG0+lG0+lFkFkV/sdt/zyH5mj7Hbf8APIfmasbT6UbT6UWQWRX+x23/ADyH5mkFnbbj+6HQdzVnafSkCneeOwosgsiD7Hbf88h+Zo+x23/PIfmasbT6UbT6UWQWRX+x23/PIfmaPsdt/wA8h+ZqxtPpRtPpRZBZFf7Hbf8APIfmaPsdt/zyH5mrG0+lG0+lFkFkVjZ2+V/dDr6n0pfsdt/zyH5mpypyvHf+lLtPpRZBZFf7Hbf88h+Zo+x23/PIfmasbT6UbT6UWQWRX+x23/PIfmaPsdt/zyH5mrG0+lG0+lFkFkV/sdt/zyH5mj7Hbf8APIfmasbT6UbT6UWQWRWWzt9i/uh09TS/Y7b/AJ5D8zU6Kdi8dqXafSiyCyK/2O2/55D8zR9jtv8AnkPzNWNp9KNp9KLILIr/AGO2/wCeQ/M0fY7b/nkPzNWNp9KNp9KLILIr/Y7b/nkPzNItnb5b90Ovqas7T6Uiqctx3/pRZBZEH2O2/wCeQ/M0fY7b/nkPzNWNp9KNp9KLILIr/Y7b/nkPzNH2O2/55D8zVjafSjafSiyCyK/2O2/55D8zR9jtv+eQ/M1Y2n0o2n0osgsisbO3yv7odfU+lL9jtv8AnkPzNTspyvHf+lLtPpRZBZFf7Hbf88h+Zo+x23/PIfmasbT6UbT6UWQWRX+x23/PIfmaPsdt/wA8h+ZqxtPpRtPpRZBZFf7Hbf8APIfmaRrO22N+6HT1NWdp9KR1OxuO1FkFkQfY7b/nkPzNH2O2/wCeQ/M1Y2n0o2n0osgsiv8AYrb/AJ5D8zR9itv+eQ/M1Y2n0o2n0osgsiv9itv+eQ/M0fYrb/nkPzNWNp9KNp9KLILIhjt4YjujjVT61LS7T6UbT6UxmLPeatJct5ChYw20KAPTqSanttVlFwlrcrGJW6NuwCfTpWVLrZVVW3jMj4ydqkniob22ubiKO+CFCXXMZ+8uTWlkdEoW0asdZ5k/ZIT/ANtD/hSLNKJkSRIwHzgq5PQZ9KqpJAAW89VwACU4P8uakR1ee2KNvGW5/CsrpnPculgvUgfWkDoxwGUnGeDVDWLBtQW0QBWSO4WSQE4yoB/xFYsXhq4ijTyTHBLtnRpFY5Ab7gHsOOO1MDqRIhGQ6nnHB70xrhFnSE7izgkEDIGPU9utc1H4euzBOQkNtIFjMEaOSvmJ/Gfr0q7DpN0sltK7I0myYzkHq746ewxj6AUAbYdDnDKccnnpUFzewWyxM7ZEsixKV55PSuZm0CW005tgSP8A0NI5dpZt7hgSDjkgjI/Gm2unz39rctDZxxxm7ikWIlkVlVQCASM/pQB1/mIF3F12nvnijevPzDj3rlk0C7RI2MEEsYllf7EZPkQMAFwcY4xnp3px0G9D2T/un+zIiyqXI+0AHPP+72znNAHTh1LFQwyOoz0oV1f7rBsehzXN22h3UOoTzSL5m8ykSLNtLBxwpGM8dueKk07TdTtNOmtFSCJZCUVg3zxrtI3EgDcc49KAN/zI8E71wOpz0pTIgxl1+bpz1rmm0WdtFFp9ghjmVkJaOb/WEZ+Zsrzz2NLPpGoyHTpFitvtECBXbjyl55wmP1BFAHTUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABVY/ff61ZqsxCtIzEAA5JPbigAoqiur2LrI4nOyNS7OY2C7R1IOMH8KG1iwRA7SuqnjJhf/AOJoAvUUyGZJ4hJGSUboSpH6Hmn0AFFFFABRRRQAUg+81LSD7zUAVF1S2JmD+ZF5Kb282Nk+X1GRyOKfDf280Msu5oxF/rBIpQr35B5rMk026uZL1zGsHnxBQGl8zcwOQenyj296l/s65u5Z552W2aVkPljEgwmcZ6Z5P6UB1NO2uI7q3jnhbdHINynGMipKp6TbTWemw29w4eRBgkDirlDAKKKKACiiigApP4z9KWk/jP0oAWikVg+dhDYJBwc8jqKdQAlFN8xNjPvUquckHgY60qMJI1kQ5VgCDjtQAtFLg+lJQAUUUUAFJ/GfpS0n8Z+lAEMV3DLG7hwqozK27jG0kE/TINOjureUqI542LLvADA5X1+lc3ss/MDnO95Z2lYwSHcrhto+705XiokMENqNtsBILJoCUhfIbHBHyd6BnWh1OcMpwcHmm+cn2gQZPmbd+Mds4/rXN2E9tDI0jW3lKUjTyhHIdxVslydnXn68datrqsKPfXOJzI2EiXyJOVA4P3fUn8qBGvHcRSx+YrjbuKgnjJFSblDBSwyegzzXM3ElqI7ZUi+0xxQmPypIZFAY/wAQ+U/40kUqRX1tIGeTZCsUsrwyEtgEfKNmVOT1zQB04ZWztYHHoagF9bs0QSVXEpIVlORwMnJrE0m9SxgMRjIjMnC+U5IXHJJCfMc1BarZJFBDNEBHDJIxxBJiTIIBI2/ofSgDqdy5A3DJ6c9aA6EkBlOOvPSuSQRpcWju0sixxxrxHIDGVPOMocg+2OlHmFpblyio0sbLlIZAGO7KkjZ+pzQB1ck8URUSSIhY7V3HGT6U7cuSNwyOoz0rlpZo7h/PnhV2FysoiaKQjaFCkZ2daTcnmvgkN+9P2jypd0oYEBSNvQf0oA6nzE/vr1x170jzRRq7PIiqgyxLfdHvXLtDYDeY1IbyYwh8iXiRSSW+71xjnrTLhhcXNyzogEqSR7lgkG4EfLkbOe3U0AdYJEYKVdTuGVwetLuB3AEEjqAelcmph+2QTFXCKI8KkbjydvUD5OQfbGa19CZfKuFEYDB8tLtYGXJJBO4A/wA6ANVfuj6UtIv3R9KWgAooooAKKKKAKqahA9y1viVZAGI3xMoYDrtJHP4UyPVLeRJSEnDRAFkMLB8HoQuMmoYIb06jLcXMEZADLAwl4Ve3y46nHJplnBqKQ3MssUYvpV4k83cuewAxwB+tAEv9t2Xlh/3/APrDHt8h924DJGMZ6VdSVJ4Y5YmDRvhlYdwelZN9pMptLOG3UyeSzGT975bMWUgndjrk5rStIpILG3ilKmRFVWKjAyPSgB091FbyQpIWDTNsTCkjPv6UwX0JvDagSmRcbiI2KrkZ5bGBxUWpx3Mn2f7NCkvlyiRt0mzoD7H1qN7Wc6sk8UQhXOZZBKT5o2427Prjn2oAnXUYGmliIljaNC53xsuVHUjI5/CiPUIpbZp0juCi448hgzZ9BjJ/CqsVpcHUZ7mS3CxtE0ZQzb/M547fKKLW2uoLW4XyPlcjyrf7QTsGAD8+PxoA0LW5ju4BNETtJI+ZSCCDggg9ORTLS9ivNxhWXC/xPGyg/Qkc/hVfTLe5s7SKFkQje5b58lFJJAzj5j70mm2s9vPOWjEFu2NkPmF8HJy2e2fSgC5LcxxSxRsfnlbaoHrgnn8qkDo3R1Pbg1ijTbkaksxghbbcNL9oL/OVKkBcY7ZA69qqtp95bwXFy8MUc67ZE8nkNIpPYDuDigDpN6ggFlyeAM1Rm/5D9h/1zk/pVFdLuIriyljRHkTmaWQg8lsthccHnqDV6b/kP2H/AFzk/pVw3+8a3NiiopZhGQMbmPOKi+2H+4P++v8A61ZuSW5LaRaoqp9sP9wf99f/AFqPth/uD/vr/wCtS549w5kW6KqfbD/cH/fX/wBaj7Yf7g/76/8ArUc8e4cyLLdB9RTqpteHA+QdR/F/9al+2H+4P++v/rUc8e4cyLdFVPth/uD/AL6/+tR9sP8AcH/fX/1qOePcOZFuiqn2w/3B/wB9f/Wo+2H+4P8Avr/61HPHuHMi3RVT7Yf7g/76/wDrUfbD/cH/AH1/9ajnj3DmRZT7i/SnVTW8O0fIOn97/wCtS/bD/cH/AH1/9ajnj3DmRboqp9sP9wf99f8A1qPth/uD/vr/AOtRzx7hzIt0VU+2H+4P++v/AK1H2w/3B/31/wDWo549w5kW6aPvn6Cq32w/3B/31/8AWpBeHcfkHQfxf/Wo549w5kXKKqfbD/cH/fX/ANaj7Yf7g/76/wDrUc8e4cyLdFVPth/uD/vr/wCtR9sP9wf99f8A1qOePcOZFuiqn2w/3B/31/8AWo+2H+4P++v/AK1HPHuHMiy3Vfr/AEp1UzeHK/IOv972+lL9sP8AcH/fX/1qOePcOZFuiqn2w/3B/wB9f/Wo+2H+4P8Avr/61HPHuHMi3RVT7Yf7g/76/wDrUfbD/cH/AH1/9ajnj3DmRboqp9sP9wf99f8A1qPth/uD/vr/AOtRzx7hzIsp9xfpTqpreHYPkHT+9/8AWpfth/uD/vr/AOtRzx7hzIt0VU+2H+4P++v/AK1H2w/3B/31/wDWo549w5kW6KqfbD/cH/fX/wBaj7Yf7g/76/8ArUc8e4cyLdNXq31/pVb7Yf7g/wC+v/rUgvDlvkHX+97fSjnj3DmRcoqp9sP9wf8AfX/1qPth/uD/AL6/+tRzx7hzIt0VU+2H+4P++v8A61H2w/3B/wB9f/Wo549w5kW6KqfbD/cH/fX/ANaj7Yf7g/76/wDrUc8e4cyLLdV+v9KdVM3hyvyDr/e9vpS/bD/cH/fX/wBajnj3DmRboqp9sP8AcH/fX/1qPth/uD/vr/61HPHuHMi3RVT7Yf7g/wC+v/rUfbD/AHB/31/9ajnj3DmRbpr/AHG+lVvth/uD/vr/AOtSNeHY3yDp/e/+tRzx7hzIuUVU+2H+4P8Avr/61H2w/wBwf99f/Wo549w5kW6KqfbD/cH/AH1/9aj7Yf7g/wC+v/rUc8e4cyLdFVPth/uD/vr/AOtR9sP9wf8AfX/1qOePcOZFuiq6XQJG5doPGQcirFNNPYd7nEWdjf6fDcTW0ObgEKpYkbxkZBB6EeorZiaZUK3LJ5r43ITkIB6nvW1OpaB1UZJHArLd7lzk2Fx+EgH9aLFSm5asgWEspQPGwAG1BITjB6g9R+tWrRXSe3WRtzbmPXPb171CftB/5cLj/v4P8anskne5RpLd4lTPLMDnjHrSUEtiFFI02YKpZjgAZJpFdWQOD8pGRnjiob0F4PKUH96wQ47Dv+marzW0jXwkSMFSu1mbBGMHp3FUMvK6uoZGDKehByKSOVZFJU8BivPqDishbOSMW8AUJ5gKSgd1Bznj16fjUs9jK4UFSyB5CVUjPJ4PPFAGnI6xozseFBJoVgyhh0IzWdJazGd2SP78ZUs5BP3cDB6imyafIEZYVCqVjyAfvEE56/h1oA1Mj1pFdGztYHBwcHoay5LGRlhG2QooI27lypJzn0/Klayby518jJeTeGUrz9c9fpQBq0VHAHWCMSBQ4UZC9AfapKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACs7UYGurO7t0YK0qMgJ6ZIrRqsfvv9aAMK7Go3dhLaLYNCv2V0OXTDPwFCkHp16gVbaOefTZIvJuEfcuBO6sTyD1BNaVFACnrSUUUAFFFFABRRRQAUg+81LSD7zUARx3EUioyPkOcDjv/AJFSM6qMswA9Saz47KWPydhCjH7wZ6NgjI/OmGykaIr5KrhACMg+YQQc/wA/zoA0ZZo4VDSNtBIUH3NAmjMxhDfOF3Ee1QXVv9ogjj2BV3DK+gwarfYrjazMQZHTDEHGTkcfkKANPIqEXURi8zJ27d3TtVQ20m4MIF8reT5G4YHGPpSCzlNvsZFz5BTGf4s5oAvxSiRc7WU9wwxiiWRYo2dvuqMmqU9pId4jUBMqQoxyADkc8d6jls5TGVEPmZjCrvYZQ5oA1KT+P8KWk/jP0oA5uTSZ0jkjjtW8v7U8kgQp+9Q7tuATjjI4OParD2F19ptpEilaGNUWZXkG6bHQnBxle/rW7RQtAMGKxa2s7q0W2MZurkrvXGGRmJJ4ORhc9cc1Za1cau80tq06EKIZFZcQ4zngkY+ozWrRQBzhsLo6dNCbSTAmDxriMtJwf9YN21hn3B6Vv2/mfZ4vOVVk2jcq9AccgVJRQAUUUUAFJ/GfpS0n8Z+lAEaXcTy+WrndkjkEZI681Ln3qh9jcRyvjfIWcorH5QCf8KbBZvvQSxARq7MASO4GOBQBo596M+9Zv2Sby50RNivgjJGW5yRn0+tSQ2f7yIvGdibjhiDgnHYcUAX8n1oyfWkooAXJ9aMn1pKKAFyfWjJ9aSigBcn1oyfWkooAXJ9aMn1pKKAFyfWkPQ0UHoaAEX7o+lLSL90fSloAKKKKAEdgiljnA9BmmxSpKCUz8pwQQQQfoaWUuImMQDPj5QTjJqC3WWOPJiJkZsuSw59//rUATedH5pi3fOF3EegpiXULqGUttJABKEZz9RUEVpLFc+YZPMUq24lcEkke/wDnFRm0lkiMYV44iy7VL5KjnODQBaa8gVQxckElQQpOSOtSbldEZTlWwQaoy287xxIY8+USMowXIxgEelW4UaO2iR8blABx0oAmooooAKKKKAGyOI13NnHsCT+lR/aotitkncSAApzkdeOtOuDKIW8hQZO2TVNrV9sTeU5K7ty+ZhiT3yDQBae6iQgMxGQD908D39PxqbI9azpbWZo1TL72jCO+4YP17042IabeyBgZckk9VxQBfyKoTf8AIfsP+ucn9KalrKjW5EYLR8EkggDP55+lOm/5D9h/1zk/pVw3+/8AIaLF6THIWbO1wMH+lVfOT1FbJAIwRke9M8iL/nkn/fIrnlSu73M3C7uZPnJ6ijzk9RWt5EX/ADyT/vkUeRF/zyT/AL5FT7HzJ9mZPnJ6j86POT1H51reRF/zyT/vkUeRF/zyT/vkUex8w9mZDTJxyOopfOT1H51qtDFgfuk6j+EUvkRf88k/75FHsfMPZmT5yeo/Ojzk9R+da3kRf88k/wC+RR5EX/PJP++RR7HzD2Zk+cnqPzo85PUfnWt5EX/PJP8AvkUeRF/zyT/vkUex8w9mZPnJ6j86POT1Fa3kRf8APJP++RR5EX/PJP8AvkUex8w9mZCzJtHI6UvnJ6j861Uhi2L+6Tp/dFL5EX/PJP8AvkUex8w9mZPnJ6j86POT1H51reRF/wA8k/75FHkRf88k/wC+RR7HzD2Zk+cnqPzo85PUfnWt5EX/ADyT/vkUeRF/zyT/AL5FHsfMPZmT5yeo/OkEybjyOgrX8iL/AJ5J/wB8ikEMW8/uk6D+EUex8w9mZXnJ6j86POT1H51reRF/zyT/AL5FHkRf88k/75FHsfMPZmT5yeo/Ojzk9R+da3kRf88k/wC+RR5EX/PJP++RR7HzD2Zk+cnqPzo85PUfnWt5EX/PJP8AvkUeRF/zyT/vkUex8w9mZBmTK8jrS+cnqPzrVaGLK/uk6/3R6UvkRf8APJP++RR7HzD2Zk+cnqPzo85PUfnWt5EX/PJP++RR5EX/ADyT/vkUex8w9mZPnJ6j86POT1H51reRF/zyT/vkUeRF/wA8k/75FHsfMPZmT5yeo/Ojzk9RWt5EX/PJP++RR5EX/PJP++RR7HzD2ZkLMm0cjpS+cnqPzrVSGLYv7pOn90UvkRf88k/75FHsfMPZmT5yeo/Ojzk9R+da3kRf88k/75FHkRf88k/75FHsfMPZmT5yeo/Ojzk9R+da3kRf88k/75FHkRf88k/75FHsfMPZmT5yeo/OkEyZbkda1/Ii/wCeSf8AfIpFhiy37pOv90elHsfMPZmV5yeo/Ojzk9R+da3kRf8APJP++RR5EX/PJP8AvkUex8w9mZPnJ6j86POT1H51reRF/wA8k/75FHkRf88k/wC+RR7HzD2Zk+cnqPzo85PUfnWt5EX/ADyT/vkUeRF/zyT/AL5FHsfMPZmQZkyvI60vnJ6j861Wgiyv7pOv90elL5EX/PJP++RR7HzD2Zk+cnqPzo85PUfnWt5EX/PJP++RR5EX/PJP++RR7HzD2Zk+cnqPzo85PUVreRF/zyT/AL5FHkRf88k/75FHsfMPZmT5yeopGmTaeR0rX8iL/nkn/fIpHgi2N+6Tp/dFHsfMPZmV5yeoo85PUVreRF/zyT/vkUeRF/zyT/vkUex8w9mZPnJ6ijzk9RWt5EX/ADyT/vkUeRF/zyT/AL5FHsfMPZmT5yeoo85PUVreRF/zyT/vkUeRF/zyT/vkUex8w9mZHmGVvLi5Z+OP51tDpSKiJ9xVXPoMU6tIR5UXGNhu8e9G8e9QSsUiZh1ApG3AkG4iBHUFP/r1ZRY3j3o3j3qqpdzhLmEn2jP/AMVSbpY5o1d0dXyOEIIwM+poAt7x70bx71UurkWwiyhbzJBH94DGe/J/lzTV1CzeVokuoWkTO5Q4yMdaALu8e9G8e9VPttrtLfaItoQSE7hwp6H6Uw6jZCFZjdwiJ87X3jBx1oAvbx70bx71VjureVVaOaNgzFFIbOWHUfWpJnMUTPsd9oztUZJ+lAE28e9G8e9UbO+ju7BbwK0cbAnD9QASDnH0pmn6j9vG9LeVIiNySMVww+gOR+IFAGjvHvRvHvWa2q266rHpwDtM6liQPlXAzgn1xU0t/ZwTCGa5ijkOPkZwDz0oAubx70bx71QGo28hgMEiTJM5QOjjAIBJ789O1PgvrW5cpBcxSuF3FUYE49aALm8e9G8e9Z41K3UTtO6wJDJ5ZZ3XBP4Hj6HmrSOsiK6MGVhkEdCKAJt496N496jooAk3j3o3j3qOigCTePejePeo6KAJN496N496jooAk3j3o3j3qOigCTePejePeo6KAJN496N496jooAk3j3quXG9/rUlQN99vrQA7ePejePemUUAP3j3o3j3plFAD9496N496ZRQA/ePejePemUUAP3j3pA43N1ptIOpoAk3j3o3j3rMOqpGbgXEEkPkJ5hyVbcMkcbSeeOhp8eox+VO08bwPBjfG+CRnpjBIOaANDePejePeqtncrd2sVwisqyLuAbqPrU9AD9496N496ZRQA/ePejePemUUAP3j3pN439+lNpP4vwoAk3j3o3j3plFAD9496N496ZRQA/ePejePemUUAP3j3o3j3plFAD9496TeN569KbSfxfhQBJvHvRvHvWdHqtqwl3ypG8ZfchYZwrEE49OKIdXsJ2VY7pCWj8wc4+X1oA0d496N496qR3trKGMdxE+1grYYHBPAFPE6m6+zgEsE3k9hzgD/AD6UAWN496N496ojUbXyEmllWJHYhC5A3fSpTdQCdYTMnmsNypnkj1oAs7x70bx71XhuYbhGeGVJFU4JU5ANVF1mydY5I5kaFyymQnAUgZ5zQBp7x70bx71VN5bBolM8e6UZjG7730pFvbV2kVbiMtF98Bvu/WgC3vHvRvHvVK41C0tWVZ50Qs4QZPfGcH0p/wBrtjK8Xnx+Ygyy7uVHvQBa3j3o3j3qkNSsSwUXcOSwQDeOp6CiXUbOLzt9xGDAu6RQclR9KALu8e9BcYPWqiX1q5iC3EZMwzGN3LD2p8c8MzSJFIjtGcOFOdp96AJ1cbR16Uu8e9RjoKWgB+8e9G8e9MooAfvHvRvHvTKKAH7x70bx71QW+P2v7PJbSxlgxjYlSH29cYPHXvimx6g7maM2c6zxKG8olCWB6YOcfrQBo7x70jOOOvUVkf20vlK32O43NK0QTKZyoJJzuxjg960IZkuLeKePOyRQy5GDg80AWN496N496qXN0LeSBTG7CZ9m5cYU47/lTFvd989qkEjeXjfJldoyM9M5/SgC9vHvRvHvWcNRAnmilt5IzHG0gJKnco+hOPxxTob6Sa0M62co6bULplh653YH4mgC/vHvRvHvVSzulu7YTKjJyylWxkEEg9OO1Nsrw3is4gkjT+FmKnd+RP60AXd496N496oy6hBHdxWodWmkbaUDDK8E5I/Cnx31pKxWO4iZg2zAYdfT9DQBb3j3qjKwOv2B/wCmcn8hUhvLYSrEZ4/MclVXdySOoqGT/kO2P/XOT+Qq4b/J/kNGzvHvRvHvUdFQIk3j3o3j3qOigCTePejePeo6KAHM4wOvUU7ePeom6D6iloAk3j3o3j3qOigCTePejePeo6KAJN496N496jooAcjjYvXpTt496iX7i/SloAk3j3o3j3qOigCTePejePeo6KAJN496aHG89egptIPvn6CgCXePejePeo6KAJN496N496jooAk3j3o3j3qOigBzOMr16/0p28e9RHqv1/pS0ASbx70bx71HRQBJvHvRvHvUdFAEm8e9G8e9R0UAORxsXr0p28e9RJ9xfpS0ASbx70bx71HRQBJvHvRvHvUdFAEm8e9NVxluvX+lNpF6t9f6UAS7x70bx71HRQBJvHvRvHvUdFAEm8e9G8e9R0UAOZxlevX+lO3j3qJuq/X+lLQBJvHvRvHvUdFAEm8e9G8e9R0UASbx7013GxuvSm0j/cb6UAS7x70bx71HRQBJvHvRvHvUdFAEm8e9G8e9R0UASbx70bx71HRQBHcf6h/pT503ZO/AH1/xplx/qH+lR3EpOVVmUjr8hINJ6LQaGho2cBnZ+B0yMenelfAubcDplv8A0Gq+1WddrEbQOShB496l3Zu4Pq38qmDk78w5KPQq61FNdT2EEUEjBLlJnk42qoznn1qhb6JdWtzZwFkkt4o5kEipgjcON3PJ5ro3cRoztwqjJpguIwCXPlgKGJcgYzVkmD/wjdxJbSRTXceTDHEhRCMbDkZ571ah0QLJbPIIf3U7TOoBYOSuM89881rCaIqWEiEAZJz0pBPCd2JUOz73zDj60AY9jpLLrN7cSB0ttxMMZ4G5hh2GPyrShsY7RJPsoYOw/wCWkjOP1JqYzwhA5lQI3RtwwaQ3EQYKHVmyAQCMigDPtdNu4dNjsXnhMY3CQqhyynJ49Dk1XsNEuLBt9vNbxyLEsQ2xHD4OSzDPJI4rYNzAN375PlGSN3QU+ORJUDxsGU9CKAMgaAItRiu4LqYFHkkZHbILMMf59qiutAlvGeW4mgaaTydzCPj5CSR9DW9RQBkR6M0dwkglQKt1JcbQuOGUjH4ZqO20Wawjga2lhEsFs0WfL4ZiQc4/CtuigDm4NKuLy3vGliEDzXRmjMmVZeMBhtPBretIpIbWKKaXzZEUBnxjcfWpqKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqrNIkQlkkYKiZZiewAq1VG+txd21zbltolUrn0yKAKv9rRiCSd7a6SFIzJvZAAwHpzmiXVBDF5kllequcH92vH/AI971WubTVLu1kt5Bboht2j+WQkOxxg428Dg9z1qwLWZ9PeAwxQMWBAWUuOoPUgelAF6GQyxhzG8ef4XGCKfRRQAUUUUAFFFFABSDqaWkHU0AZMmkyTPcuzRQmePYfKU8tnIY57j+tS/2YZpZZrqUiWRlb9ycAbc469epq3FdxTIrJnDNt+h680rXMCqzGVNqnBIOcUAR6baGxsYrZpDKUGNx71aqGa4jhjWRjlWIAI96PtEfntFnDIu4nsBQBNRUfnxbN/mpszjduGKi+2J5PmkEDZv6igCzRUEdyrRln2oAASSwI596Wa5ihj3l1PGQM/e+lAE1J/F+FLSfxfhQBGLiBmdRNGWj++A4yv19KBcwFGcTxFVOC28YB9DWFeafflbuaRY5N0MyDYxywYgr8oX2x196dPp9ws0cwtYMtNGBCjEoAqtyTt46+lCA1pL6FHVQfMDRNKGQgghcZwfxFTNPCsgjaWNZGGQhYAkfSsf+yLgwOuYlZ4Z12gnCmRgQBx0GP8A61Tiyuori7aJYG+0fMsrk7kO0DGMcjj1HU0MC41/ZoI2a6h2ytsQ7wQx9M0/7VCsZkkkWJdxTMjBckHHr7Vjw6VeKUkkSBnW4WbbvJB+TaedvHPPSpX025VlkVIJiGmHlyMQAHbIOcHkDjp3PNAGq00SOqNLGrt0UsAT9BUlYg0WQRkFo2cLAquc5Gw5P09q1g0527kjGQd2HJwe2OOe9AEtJ/F+FIhYopcAPgbgDkA/Wl/i/CgDA8lgUxZXYImmkYiJfm3hh/e7bh+VM2Xa2vliyuWYWhtv9WBnjg/e/OttbyMybSGUZI3NjBx1qTz4tobzUweh3DmgDFtGuYZfOfT5w3lJEFSJQAqknP3uvJqRbm6X7ZKNOvPOlOI/lXhQMDJ3epJrWE0R3YkQ7fvc9PrR50WFPmJhuh3daAMWQTKYWt7C5BjhMJWSJSMHuMNUcUU8E1uYbS8VIo1jc7BmVQCACN2O9dFRQBh2El3ZpsFndeXvBEewEIuOQMtnrUduksS26yWN0627uyfulyQwOP4uozXQUUAczFayRTRObG7kCxxoylAPuEkEYb370GG9dpWlgunZ42QMYhnrkcbsfhXTUUAc9i7MnntaXJl89ZgPKG0YXbj7360w285Hl/ZLoRq0jIREu7Lgjk7ugz/KukoosBzzQEhwun3S7oI4RiFeNpJ/vd8j8qjmhvJ5ZWkt7tg6yICYhkBunG7HH610tFAHOCGY3azyWF0+RHvXbgAp0I+b+daWjiaO3eGWF40RiULoFLAknnBPNaNJ2oAB0FLSDoKWgAooooAKKrLexkMSrBQCwJxyAcVJFMJdw2sjL1VuooAqwWlzHdzzyyQyM+QjYOUXso7Y9fWmW1jdQ2s6NNF9olHM6g5Lepz6dhVxJ95cLG+FJGeMEj05pou1BIdHRgQMHHfv1oAp3ekLNbWkEQi2W+fkkBIYFSvb65q7awtb2kMLyGVo1Clz/FjvTWvECqwSRgxIXAHOO/XpUyuJI0dejYIoAr31vNP5PktGvlyCQ7wecA8cfWo5bJ5dQiucQx+WclkB3vxjaT6c/pV+igDPjsZFv5LoiBd0ZQqgPz88Fqbb2EkEdztW3/fMCIQpEa8AHj3rSooAo2FpNZ26QiSMqHZioBwoOSFX2FFnZPb3U858pBKAPLiBC5GfmPuc1cdiq5Clj6DrUX2keVvEchwSGAxlcevNAFJdNnW5DCWLyluGnHynflgRj8M/lVabS7tbad2lE1wVXy2Uc71OQeeO/T0rVN3GscbsGHmY2rjmpGniUlWlQEdQWFFgM1NKkiNoYZVjaIASSc7n5ywPYg/1qzJ/yHbH/rnJ/IVZ86L5f3ifP93nr9KrSf8AIdsf+ucn8hVw3fzGjQlm2NtAycZOegqP7UfRf1pl4GRi4UsjAZx2Iqn549/yrkqTmnZG0IRauy/9qPov60faj6L+tUPPHv8AlR549/yrP2tQv2cC/wDaj6L+tH2o+i/rVDzx7/lR549/yo9rUD2cC610cDheo9ad9qPov61ntOOOvUdqXzx7/lR7WoHs4F/7UfRf1o+1H0X9aoeePf8AKjzx7/lR7WoHs4F/7UfRf1o+1H0X9aoeePf8qPPHv+VHtagezgX/ALUfRf1pPtR9F/WqPnj3/Kjzx7/lR7WoHs4F1bo7RwvT3p32o+i/rWes42jr09KXzx7/AJUe1qB7OBf+1H0X9aPtR9F/WqHnj3/Kjzx7/lR7WoHs4F/7UfRf1o+1H0X9aoeePf8AKjzx7/lR7WoHs4F/7UfRf1poujuPC9B61S88e/5UgnG49eg7Ue1qB7OBofaj6L+tH2o+i/rVDzx7/lR549/yo9rUD2cC/wDaj6L+tH2o+i/rVDzx7/lR549/yo9rUD2cC/8Aaj6L+tH2o+i/rVDzx7/lR549/wAqPa1A9nAum6OV4Xr7+lO+1H0X9azzOMr16+lL549/yo9rUD2cC/8Aaj6L+tH2o+i/rVDzx7/lR549/wAqPa1A9nAv/aj6L+tH2o+i/rVDzx7/AJUeePf8qPa1A9nAv/aj6L+tJ9qPov61R88e/wCVHnj3/Kj2tQPZwLq3R2LwvT3p32o+i/rWes42jr09KXzx7/lR7WoHs4F/7UfRf1o+1H0X9aoeePf8qPPHv+VHtagezgX/ALUfRf1o+1H0X9aoeePf8qPPHv8AlR7WoHs4F/7UfRf1poujluF6+9UvPHv+VIJxluvX0o9rUD2cDQ+1H0X9aPtR9F/WqHnj3/Kjzx7/AJUe1qB7OBf+1H0X9aPtR9F/WqHnj3/Kjzx7/lR7WoHs4F/7UfRf1o+1H0X9aoeePf8AKjzx7/lR7WoHs4F03RyvC9ff0p32o+i/rWeZxlevX0pfPHv+VHtagezgX/tR9F/Wj7UfRf1qh549/wAqPPHv+VHtagezgX/tR9F/Wj7UfRf1qh549/yo88e/5Ue1qB7OBf8AtR9F/WmtdHY3C9PeqXnj3/KkacbT16elHtagezgX/tR9F/Wl+1H0X9aoeePf8qPPHv8AlR7WoHs4F/7UfRf1o+1H0X9aoeePf8qPPHv+VHtagezgX/tR9F/Wj7UfRf1qh549D+VHnj0P5Ue1qB7OBoLc92A29yO1WKx1Mk7bI1bngnHAFbA4FdFOTktTGoknoMmUvE6r1I4qg8d85y1pak+8mf6Vq7PejZ71oZmObe9PWztf++//AK1TWsFyJ1eeOKNUzjY2c5GPStLZ70bPegCtdI0kQjUZDsA3svf/AA/Gq7xzTTTGLKD5BlhjdgnOP8a0dnvRs96AMxNPceVudQFP7wD+IZyP1pBZTmRmkMcgZWXkkZBOfTitTZ70bPegDOS1uFMUhdJJE3DDE4wffHWn/ZCF6qCZvMJ9Rmr2z3o2e9AGXDaSOo3qiKrSEcfMckjmrtujRwIj7dygD5elT7PejZ70AMop+z3o2e9ADKKfs96NnvQAyin7PejZ70AMop+z3o2e9ADKKfs96NnvQAyin7PejZ70AMop+z3o2e9ADKKfs96NnvQAyin7PejZ70AMop+z3o2e9ADKgb77fWrWz3quyfO3PegBlFO2e9Gz3oAbRTtnvRs96AG0U7Z70bPegBtFO2e9Gz3oAbSDqafs96QJ8zc0AUVsSpiIcDC4fHfggH9aQ2cjIATGCqBVxnnBB5/KtDZ70bPegCtPCZ40VscHLD8CP61X+wNswZAzFcFj3OR/hWjs96NnvQBRNtL5nnDy9+7O3nb0xSCzcRbCy58op+Oav7PejZ70AUprRnZmVgDuUgZI6Z/xqNrOTYyx+WA6BCCSdvPatHZ70bPegBtJ/F+FP2e9Js+fr2oASinbPejZ70ANop2z3o2e9ADaKds96NnvQA2inbPejZ70ANpP4vwp+z3pNnz9e1AFMWhVJCpUTMWKsecZNJDaukitJsIDFupJ5A9fpV7Z70bPegDPNnIySJuVVbBVQSQDnP4VJFalJEchRt3cZJ5PfJq5s96NnvQA2inbPejZ70ANop2z3o2e9ADaKds96NnvQA2inbPejZ70ANop2z3o2e9ADaTtT9nvQU460AMHQUtKqfKOe1Ls96AG0lP2e9Gz3oAz4rN0Lbgh3KQ3J+c+p9Kkggki3MCu52GQSTgfWrmz3o2e9AFRYHE7SqI0ypHy/wAR9TUX2N3h8uXYcsGdgTlq0NnvRs96AKEtpLIiIxjcITjdkZGMc4qxEhjhjRm3FQAT61Ps96Rk6c9xQAlFO2e9Gz3oAbRTtnvRs96AIZ1kaJliYK56E9qi+zsYEi+RV3fMAScj/wCvVvZ70bPegCncWnnNvV2VuB14wDn0o+y/vd52n97v5HOMYq5s96NnvQBQW0kQxbWUFOCwJ5Gc4xRJ/wAh2x/65yfyFX9nvVGVca9YjP8Ayzk/kKuG/wB/5DRqUU/Z70bPeoEMop+z3o2e9ADKKfs96NnvQBG3QfUUtKycDnuKds96AGUU/Z70bPegBlFP2e9Gz3oAZRT9nvRs96AI1+4v0paVU+Ree1O2e9ADKKfs96NnvQAyin7PejZ70AMpB98/QVJs96aE+c89hQAlFP2e9Gz3oAZRT9nvRs96AGUU/Z70bPegCM9V+v8ASlpWTlee/wDSnbPegBlFP2e9Gz3oAZRT9nvRs96AGUU/Z70bPegCNPuL9KWlRPkXntTtnvQAyin7PejZ70AMop+z3o2e9ADKRerfX+lSbPemqnLc9/6UAJRT9nvRs96AGUU/Z70bPegBlFP2e9Gz3oAjbqv1/pS0rJyvPf8ApTtnvQAyin7PejZ70AMop+z3o2e9ADKR/uN9Kk2e9NdPkbntQAlFP2e9Gz3oAZRT9nvRs96AGUU/Z70bPegBlFP2e9Gz3oASZikLspwQOKjYlSQZZhj0Qf4U+5/493+lNnjR8liePYf1FADASxwLicfVFH81pAzpcRL5zur5BDBfTPYVAjwGQLt35A+8F4zUuR9qtwAAMtwPpUxkpbDaa3HX939kFv8A6v8AezLF87EdfTAPP+c1DFrmnzS+XHMScMQdjYYL94g4wce1M1e0uL2aySJF8uG4SZ5C3YZ4xVKDw/NbXVqi3Jls4llQKwAMYccfXr1qhGkdYsFjMhnwoiWXJU/dbgfifSmNrunrCkpmbDuYwNjbt46rjGQfaqK+GFNvLDPeSS74kiU7ANgQ5Wrdto/kyW0jTIWglaT5IggYldvPP60AWYNUs7jYIpcl5GiA2kHcvUYqG513TrW5a3nn2SIwVvkOFJGRk4xzVaHRXGqahehzA0w2wlTu2Ejl8HgE8VJJoYldne5cs1xFOTtHVABj8cUASf29p3kRyiZyJCwVRGxf5fvZXGRipF1iwdZCs4IjCE4B6P8Adx65z2qm2gFZPNgvGim3yksUDArIckY/rTk8O28dzZTJLIFtYwmztJj7pP0yaAJv7btYoRJcyBN0zxIEDNuKk8dOvHSiTX9NjhjlM5KSR+YCqMcL6nA4Hbmki0ZY5IX89j5U8s33epfdx+G6sq/8O3K26RafIS5gMDuzBQyls8j8T0oA0Tr9tFfz29ywjRDGEfBOdwzk8cDJxzVldZsWuTbrMTIGKfcO0sOqg4wT7dapT+HzO8u68ZYZ/K86IIPm2AYwe3SnJoAS4VxdMYY5muI4ig+V2zznuMk8UwLK65pzRPKtxlEUFsKeMnAH+97daDrdgI4XErsZmZURY2Lkr94bQMjHeqI8MRfZ7iH7VIVnZZTlRxKOS/4+lPufD7XFklubmJCGZi6W4UgnHK88H3pAaV7qNtYIjXLlRISFAUkk4zjAqn/wkFjLBO9rMsjRQmb5gyqV9c4/PHSpP7LczpJJeSSLE2Y1ZR8o27cZ7+tVh4dQWgg+0vgWjWudo6E53UAWpNbsIrgW8s+2bKgqFJALdMnHFPuNQS2vlhlaNY/JaVmLHIC9eMYx+NV5dESR5289h50kTn5emzoPxqBdLvX1MSzyh0jgkiErgEtuOR8o4wB60AjVsr2G+g86Df5Z6F0K54zkZHI561YrP0jTP7MilQTGTzH34C7VT2UZOBWhQAUUUUAFFFFABRRRQAUUUUAFVj99/rVmqVzMltFPPKcJGCzH2AoAkorPfUpYrOS7msnSFIzIPnBY+2Oxol1GWO38/wCx7kBwdsynHIH9aANCimxs7IDJH5bd1znH406gAooooAKKKKACkX7zUtIPvNQBlf2w8bXizRRN9mQP+5l38kkBTkDB4qVNSZFuEuoQs8G0bIm3h933QDgc8elNbSWned7u58xpYvKBSMJtGc56nJzT49KjcySXrfaZpGBLgFMYGBgA8dT+dAdSxYXJvLGG5KeWZFDFc5x7ZqxVbT7NNPso7aMllQdT3qzQwCiiigAooooAKT+M/SlpP4z9KAFoqsdQtA8qNMFaFSz7lIwB1PI5/CmDVbExs4uV2q208HqenGOc/rQBcoqg2qwZUxESRtDJLvzgfIQCDnp1/SpzfWwuPIMo80DJUAnHGeSBgUAWKKoPrNigiPmsRLJ5QxG2Q2M8jGRUj6laxR75pAgLsgAyxO04PAHt+FAFuiqr6lZJKkTXCb3AKgZOQehz71aoAKT+M/SlpP4z9KAM2HWoG81ZNwkjeVdqoTnYTwDjGcDOKWDW7abb+7uEDQefueIgBfc1B9iuP3YNsxCSyyf61ed+7I/Dd+lRfYNQW28pYgxFs1ty6jIx8v0xQM0oNTtbgsImdiNvHlsMhjgEccj36VKtxuvWt1XISMOzZ6EngY/A/lWbbW+pQyGWSPzJiiRht6gBFOcY9Tk808JqCpeEWi+bcE7T5wwoxgDp9T+NAiddWgFvHNKGXzdzIqKXJUfxEAcCpl1C2ecQo5digkyqkqFOcEnoM4NUJrW+YxNbQmCSOPyt3mKwK/T196iXT7qO4tnitwiWyBFUOu4gDGC3ce2KANa1u4ryHzYN5TPBKEZ9xnqKorrsEiW8qxyrFKzId0bbsgZ4Hf8ACo7K1v7MNsiHzSB2CsqqRjoB2z14otrO8g8oGAusLOUHmKMBh0PrjPWgC7/atmWhUS5MwVlIUkAN0ye2fel/tK2EkqMzo0Q3NujYZGcZGRyM+lZaaXcRTQypaoSiIjeYytuC9CPQ80waVegy7lZvMRkyXXcMnIJPfBoA1bnVLe2kSNlldmlEWI0LYJGe3tSjU7QyvF5hyu7nadpx1APQkegrOFhf8yFSZzMs28uuAQoXGPTFIdNuiWQwsYBvMcfmL8rOCCc9+p/OkBdGt2DEASuc4P8Aq2xg9G6fd9+lPuNWtrfzw4l3QoXI8thuA67SeDVWSzuXEg+zEb4ki/1q8bSTn9arNpd680rsjFZBIMF1JAYdM+3amBqLqtoXiQs6tKFIDIRtz0DccE9s1NBdRXPmeSWYIdpbaQCe+D0PTtWQunXa3KXBt42kwgk3bDu29CP7pq/pdvcW0UkU3EQOYlJBKgkkjI69aALy/dH0paRfuj6UtABRRRQAUUUUAUVvLhdQFrLBEA6M8ZSUscAj7wwMZz70yC9u5JLiA20H2iFVYBZiUOexO3IP4U620+aC5uJjd7xOSTmIbh6DdnoOwpltpc0FjNatelhIpHmLEFbJ6sTnk0AVX1yeO1jme2gXzJXRWNwQhCqTu3bfY9q1oJfPtYZijR+YqttbquecGqt3pYnito4ZFhFsflzGHBG0rgg/WrNtbraWkFurMyxBVDN1OKAG3lzJbyW4WIOksgjZi2NuQTnGOelQrqDvqr2QSELHgktLhyCM5C45H41Jf2kt35PlXAh8p9/Me/JHTuPU0ktlJNeQzSzgxQtvSMR4IbGPvZ6cnigCFNTk+13MDxQt5MTSfupSx46BhgYJ/GltdQmudPe5VbQEdMXBKj13HbwfwNPjsZhetdSXKvJsaOPEQXaCc8889KSKwniW4cXSm5nYFpPKG3gAfdz6D1oAl067N7ZJcFApYsPlbcDgkZB4yDjNR6ZfPfI7skKKpwAku5gc9GGBg/nS2di9pEiJcE/O0knyABy2TwOwzS2tk8V3NdTTiWWVQnCbQFGcfU89aAGS6pEt7DbRAuzS+W7bTtX5ScZxjPHSnpqlq0vl7nR94TDxsvJzjqOnB5qEaU4uhILthCJmmEWwcMwOfm9MkmqzaJKlncRrcGWSRAqMV2kMDkMTk5IoA0E1K1knWCN2d2JHyoSBg4JJxwMg81HN/wAh+w/65yf0qM6OP9DCSiNLULjCfMcHP3s9D3FSTf8AIfsP+ucn9KuG/wB41ubFFV7icodqYyOST2qD7VJ/fH/fP/16xlUjF2ZSg3sX6Kz/ALVJ/fH/AHz/APXo+1Sf3x/3z/8AXqfbRH7KRoUVn/apP74/75/+vR9qk/vj/vn/AOvR7aIeykXm6D6inVnNdSYHzjqP4f8A69L9qk/vj/vn/wCvR7aIezkaFFZ/2qT++P8Avn/69H2qT++P++f/AK9Htoh7KRoUVn/apP74/wC+f/r0fapP74/75/8Ar0e2iHspGhRWf9qk/vj/AL5/+vR9qk/vj/vn/wCvR7aIeykXk+4v0p1Zy3Um0fOOn93/AOvS/apP74/75/8Ar0e2iHs5GhRWf9qk/vj/AL5/+vR9qk/vj/vn/wCvR7aIeykaFFZ/2qT++P8Avn/69H2qT++P++f/AK9Htoh7KRoU0ffP0FUftUn98f8AfP8A9ekF1JuPzjoP4f8A69Htoh7ORo0Vn/apP74/75/+vR9qk/vj/vn/AOvR7aIeykaFFZ/2qT++P++f/r0fapP74/75/wDr0e2iHspGhRWf9qk/vj/vn/69H2qT++P++f8A69Htoh7KRebqv1/pTqzjdSZX5x1/u/8A16X7VJ/fH/fP/wBej20Q9nI0KKz/ALVJ/fH/AHz/APXo+1Sf3x/3z/8AXo9tEPZSNCis/wC1Sf3x/wB8/wD16PtUn98f98//AF6PbRD2UjQorP8AtUn98f8AfP8A9ej7VJ/fH/fP/wBej20Q9lIvJ9xfpTqzlupNo+cdP7v/ANel+1Sf3x/3z/8AXo9tEPZyNCis/wC1Sf3x/wB8/wD16PtUn98f98//AF6PbRD2UjQorP8AtUn98f8AfP8A9ej7VJ/fH/fP/wBej20Q9lI0KavVvr/SqP2qT++P++f/AK9ILqTLfOOv93/69Htoh7ORo0Vn/apP74/75/8Ar0fapP74/wC+f/r0e2iHspGhRWf9qk/vj/vn/wCvR9qk/vj/AL5/+vR7aIeykaFFZ/2qT++P++f/AK9H2qT++P8Avn/69Htoh7KRebqv1/pTqzjdSZX5x1/u+31pftUn98f98/8A16PbRD2cjQorP+1Sf3x/3z/9ej7VJ/fH/fP/ANej20Q9lI0KKz/tUn98f98//Xo+1Sf3x/3z/wDXo9tEPZSNCmv9xvpVH7VJ/fH/AHz/APXpGupNh+cdP7v/ANej20Q9nI0aKz/tUn98f98//Xo+1Sf3x/3z/wDXo9tEPZSNCis/7VJ/fH/fP/16PtUn98f98/8A16PbRD2UjQorP+1Sf3x/3z/9ej7VJ/fH/fP/ANej20Q9lI0KKpJdsDlyCvfjBFXauMlLYhxa3Irn/j3k+lVLqZc7WZlI7hlGfzNXZU8yJkBwWGM1nm01A/8ALzb/APfo/wCNNq6swTsQl4Sy5YqFwQCy9unep42DXkGDkZb+VNNlfn/l5g/79H/GpbWznjnEk80b7c4CIR/WkopbA23uXJZBFE8jdEBJqIXIBIkUqVVWIGWIznjAHtTrmNpkVBjaXBb6Dn+lVpLaW4mmY5hB2gZ53YJ6gHpzVCJ1vLdkZhJwoBPB70G8gBcFyNg3HKkceo9fwqBNNCmHdJnyicgDAYZyAfoaRdOZXZjMH3KVO9M5BOeeeaALLXUKhCxYF/ursO4/hjNNN5EW2o24hwjZBGD+XWoo7BohEUn+ePIyVyMHtjP9al+yfIF39JfN6e+cUAIb+2+bDklQTgKecdcetTQyrPEsiZ2sMjIwaqQ2UhUedJ8qlyqAdNxPfvwatwRmKFI2YNtGM4xQBJRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAVRu4Euobi3kzslBU46jIq9VY/ff60AY82lXtzC8Nxexsht2hXbERnOPmb5sEjHbHWrQspnsnt5pIASwIMURUDBB6En0q9RQAUUUUAFFFFABRRRQAUg+81LSD7zUAVYL5JkQhSpLbSCfu8E5/SnNfQBC4ZiBjopyQTjI9RTRYJmI7jmNdp/wBoYx/WkNiWTa82SqhUO3GACDzzz0oAkurpbeFZSpZWYD0IHrSfbYxcSRHhY03F88fT9RUksHnIiu2dpyeOvBH9agGnIIwgduFxk8nOQc/pQBN9rh27t567cbTnP061D9u/0fzSoz5e/Az649KU2j7xL52Jt2d2zjpjGM0CxAi2eYT+6Mece/WgB0d0NhM2ARj7oPJPtjNE97FHCXVtx27lAB/X0pJrISszFuSVIyuQMZ/xpr2JKsqShA6BGCpwfpzx1oAuUn8f4UtJ/GfpQBhXej3ZS6kFws7vFKiqUIYhyCBktjjAHpipLjTbwzx3AkheczISRFhEVQ3Ubsnr2NbVFAGQdFZoXVrgb5IpkYhON0hBJAz0GOlTf2fcRy3Rt7lY47n5mzHl1baFyDnpwOorRooAxodGuItrG6jaRZlmB8s4JC7Tn5s85z161KdLmRxLb3EaygzAl49y7ZG3EYyORxzWpRQBlLoqpC0SzcFYVBK8/Ic/rWgqz/LukjPB3YQjJ7Y5471LRQAiBgihyC+BuIGAT9KP4z9KWk/jP0oAqrfZm2NHhcsAQ2T8vtipPtcGF+c/MdoG05z6Ypv2NRFKqtteQklwORk5xSQWfkyBjIDgk4C4649/agCQXUJRnDHavU7Tj8PX8KPtcHyjecuSANpzx14qE2AYShpB+8wcKuACDnOM1JDaiN0fK5UEYVcDn8aALFFFFABRRRQAUUUUAFFFFABRRRQAUHoaKD0NACL90fSlpF+6PpS0AFFFFACMSFJUZbsCcZqK3meUuHjCbDjIbIP6VKwJUgHBI6+lRJAYoUjjfG08nGd3rQAn2na84dNoiAbOc5HP+FQm/wBmPOjCZwfvZAB79KlNszSys8gKSLtK7ccc98+9R/YN+DLJvIwPu8YHagAkvjHGjmIAOTt3Pt4Azk8cVYV/MijfBXdg4Paq7WJZUUS5CElQybsAjGOvNTxxiGGOMEsFwMnvQBLRRRQAUUUUANkLhcooZvQnFVWvwqISqK7MV+Z8KMdeasXETTQtGshjLfxAVEbVtsZWRVePIBCcYPbGaACa5kijV1iVwwHSTuew45pzXkCOUZ8ODgjBPPpQlqqGH5iVhXAB7n1o+zDzN+//AJaeZjHtjFADluoWKBWJLjIwp6e/p+NVZv8AkP2H/XOT+lSCxwYsSY8vvt5POeuelRzf8h+w/wCucn9KuG/3/kNFu9hk3eZGu8EfMB1qlif/AJ4S/wDfNbVFc8qUZO5cajSsYuJ/+eEv/fNGJ/8AnhL/AN81tUVPsIle2Zi4n/54S/8AfNGJ/wDnhL/3zW1RR7CIe2ZiMJ8D9xL1H8NLif8A54S/981sN0H1FOo9hEPbMxcT/wDPCX/vmjE//PCX/vmtqij2EQ9szFxP/wA8Jf8AvmjE/wDzwl/75raoo9hEPbMxcT/88Jf++aMT/wDPCX/vmtqij2EQ9szEUT7R+4l6f3aXE/8Azwl/75rYT7i/SnUewiHtmYuJ/wDnhL/3zRif/nhL/wB81tUUewiHtmYuJ/8AnhL/AN80Yn/54S/981tUUewiHtmYuJ/+eEv/AHzSAT7j+4l6D+Gtumj75+go9hEPbMx8T/8APCX/AL5oxP8A88Jf++a2qKPYRD2zMXE//PCX/vmjE/8Azwl/75raoo9hEPbMxcT/APPCX/vmjE//ADwl/wC+a2qKPYRD2zMQifK/uJev92lxP/zwl/75rYbqv1/pTqPYRD2zMXE//PCX/vmjE/8Azwl/75raoo9hEPbMxcT/APPCX/vmjE//ADwl/wC+a2qKPYRD2zMXE/8Azwl/75oxP/zwl/75raoo9hEPbMxFE+0fuJen92lxP/zwl/75rYT7i/SnUewiHtmYuJ/+eEv/AHzRif8A54S/981tUUewiHtmYuJ/+eEv/fNGJ/8AnhL/AN81tUUewiHtmYuJ/wDnhL/3zSAT5b9xL1/u1t01erfX+lHsIh7ZmPif/nhL/wB80Yn/AOeEv/fNbVFHsIh7ZmLif/nhL/3zRif/AJ4S/wDfNbVFHsIh7ZmLif8A54S/980Yn/54S/8AfNbVFHsIh7ZmIRPlf3EvX+7S4n/54S/981sN1X6/0p1HsIh7ZmLif/nhL/3zRif/AJ4S/wDfNbVFHsIh7ZmLif8A54S/980Yn/54S/8AfNbVFHsIh7ZmLif/AJ4S/wDfNIwn2n9xL0/u1t01/uN9KPYRD2zMfE//ADwl/wC+aMT/APPCX/vmtqij2EQ9szFxP/zwl/75oxP/AM8Jf++a2qKPYRD2zMXE/wDzwl/75oxP/wA8Jf8Avmtqij2EQ9szGS3uJ3CmNkQ/eZuOK2BwKWitIQUVoZyk5bke8+lG8+lQzkiFyDg461KbdD3k/wC/jf41ZIu8+lG8+lRtbR+sv/f1v8ahZBFcQhGkwxYEM7EdPc0AWt59KN59Kp399HYRxNJHJJ5sgjVY1ySSDj+VUIvElo+C8NxCmx23yJxlPvDg9R+VAG3vPpRvPpWTFrccqS7ba4EkSLIY22g7D0bJOMfjmo49Z+0i2kgV40njldVkj5O3GDnPA5980AbW8+lG8+lYFlrFw5RplDqbJJyqAAlicHkkDFXE1WO50ie+h3IIlfIdc7Suc8A89OxoA0959KN59KxG8QRQRr5kM8pWGOaSSOMbVVu554+nP41KmuQSXCxpDO0bTeSs20bC+M4657elAGtvPpRvPpTaKAHbz6Ubz6U2igB28+lG8+lNooAdvPpRvPpTaKAHbz6Ubz6U2igB28+lG8+lNooAdvPpRvPpTaKAHbz6Ubz6U2igB28+lG8+lNooAdvPpRvPpTaKAHbz6VAzne3Hepagb77fWgBd59KN59KbRQA7efSjefSm0UAO3n0o3n0ptFADt59KN59KbRQA7efSkDnc3FJSDqaAH7z6Ubz6VhvqlxBJeo5jlMEYdQI2j5JIxyTkdORUv9oy25uILny5LiMoEKDYHLZwMEnGMHPPSgDX3n0o3n0qnply15p8FxJs3uuW2dAfarVADt59KN59KbRQA7efSjefSm0UAO3n0pN539O1JSfxfhQA/efSjefSm0UAO3n0o3n0ptFADt59KN59KbRQA7efSjefSm0UAO3n0pN53dO1JSfxfhQA/efSjefSsaLV2AkWS3lZhJMqMAArFCx2jJ64HXpToNYaRVeSyljQ232hm3KcD060Aa+8+lG8+lZ9vqIndkFtOjgK4VwASrHG7r7Hg88dKlWdmvpIRt8uKMM575J4/QGgC3vPpRvPpWWmpt5MTNbySSyq0gjjAyqA9Tk//r9Kki1SCa4SGJXcNEJd/AG05xwTk9OwoA0N59KN59Kp2F6l9b+dGjKucAMRk/kePoeaox6vNLHayi0lUSs6+WMMWwOoOcDp3xQBtbz6Ubz6Vlf23amSFAHzKqt2Gzd0yM5/LNPOqxJLNHJFIhiXd1U7hnHGD/PFAGlvPpRvPpWbc6n5M6RRW0kzGYRNtIGCV3Z5NH9rQ7zmOUR/MFlIG1yoyQOc9u9AGlvPpRvPpWT/AG1Hnm0ugMK5JUDCMcBjz6546+1OutWW3a4Q28heKNnX5lw+OvfI/EUAam8+lBc46VlDWYBNFDJHIkjhNwJU7C33QeefwzVu1uhdK7pG6xgkK7Yw/UEjnOOO+KALKudo47Uu8+lMHQUtADt59KN59KbRQA7efSjefSm0UAO3n0o3n0rNS4uhqZtjJDKhRmOxCDFz8u45Oc8+nSmW9xeSvdRedbsYgMTCIhA3dSN3OPrQBq7z6UjOeOO4rn5NWvYrOGZ2twJpHCP5LkFApIO0NnnHrWxaytPaQSuoVpEViAcgEj1oAs7z6Ubz6VSvZ5oJLby9mySUI+4HOCD0/Koftc41Y27skcJwIw0TZk+XJw+cZ68Y7UAae8+lG8+lZKXtyL+4tyY5dkLSIBEyHOeByTu+ootbu4nspXaaIToRkfZ3Bj6HBQtk/pQBrbz6Ubz6VR0u6e8sVmk2lizDKggHBIHB5HToelR6ZdT3DSrcPGJE6xCJkZOT1yTke4oA0t59KN59Ky5NRZryGGGJ/LM5ieUgbSQpJA5z1HXFKurxeaY3iljIdUJJUj5s4PBPHFAGnvPpVGVs69Yn/pnJ/IVHHq0MtxFDHHI3m7ircAYBxnk8/hmnyf8AIdsf+ucn8hVw3+8a3NfefSjefSm0VAh28+lG8+lNooAdvPpRvPpTaKAFZzgcdxS7z6Uxug+opaAHbz6Ubz6U2igB28+lG8+lNooAdvPpRvPpTaKAFVzsXjtS7z6UxfuL9KWgB28+lG8+lNooAdvPpRvPpTaKAHbz6Ugc7zx2FJSD75+goAfvPpRvPpTaKAHbz6Ubz6U2igB28+lG8+lNooAVnOV47/0pd59KYeq/X+lLQA7efSjefSm0UAO3n0o3n0ptFADt59KN59KbRQAqOdi8dqXefSmJ9xfpS0AO3n0o3n0ptFADt59KN59KbRQA7efSkVzluO/9KSkXq31/pQA/efSjefSm0UAO3n0o3n0ptFADt59KN59KbRQArOcrx3/pS7z6Uxuq/X+lLQA7efSjefSm0UAO3n0o3n0ptFADt59KR3OxuO1JSP8Acb6UAP3n0o3n0ptFADt59KN59KbRQA7efSjefSm0UAO3n0o3n0ptFAEdx/qH+lZl9bakbx3i1ZoY2OUjEYIA/KtO4/493+lDtk59KB3sZdut/cA7NWRsHbxEODVuOOeGa3S5nE0m5juC7eNvTFOUJEcoiqc54HekMhkvYCT/AHv5UCJrm1jujCZN37mQSrg45AI/rVMaHZbERldkXzOGbrv+9n86vzyCGF5DztBOPWoDd+WSJQSw2DCL3Of8KAKTeHbN7eWF5LlvNCqzmT5tq9F6dKsppcKtEzyzytErorOwzhsZHAHpUsd6kjbRHKDg4yByR1HWhb6NlyEctv2bBgknGfXHT3oAqPoNk8IiJlAWJIgQwyApyO3XIqC50IraSRWMz75PMBE0h2/OME4A5PcfjWgdRgUIWDAt2OMjnHPPrUsVwksskahsocE8Yz/OgDKHh9ZJm8+eQwGCKEojY37M/e46HimDQZRq6XKukdskxmEauxycY+7jAreooFYKKKKBhRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABVK8nW1gnuHBKxKWIHU4FXaqXESTpNDINySAqw9QRQBnTX19bWU13PDbBUiMioshLZHY8fypJL6+W0+0JHZuAcHDuO4Hp70NowlVkmvbiVTC0KghflVsd8cngdatfY2a2aGe5kmDEHcVUEYOewFAFiLzfLHnhBJ3CEkfrT6KKACiiigAooooAKQdTS0g6mgCj/ZULGUzyzXBkQx5kYfKp5wMAf5FSQ6fBGr+YDcs5BZ5wGJx07YpsF6ZFTeoRifmHtgkEflTmvlVNwjfOAQDgbgTjIoAltLWKztkt4F2xoOBU1Vru4aCFZFTJLAFT1x3pn20CdwR+6Vchh1J44/UUAXKKr/akzt2Sb842YGfX1xUP2x/s+/GW8ovjHvQBeoqot15akTElhgdACSc++KSW9XyWaFWY7N3ThfrQBcpP4vwpaT+L8KAM99WhiGJEkdy0gCxKW4RsE06PVYJY3eKOd9gVsBMFlPQjJ6U5NOiRywd8kSjt/y0YMf5VFJo8TJGqzSoY1jVSMH7gwOCMHrQA59YtVgSZRLIrRmXCJkqo7mnjVLU3gtQx8wkDPbcRnH1xWfc6NMlusNm7EmNomdpNvyknAIC84yfQ/nV+LTVhuzcRysNxDOm1SGYDGckZHAHQ0AxTfHfJhF2JMsQYnqT1/I8U1dXtS2G8xFwxDuuFO37wB9sU1rScRwQqsbDzfNlkLYOc54GOfzqKDR90YW8meVRvCx8bV3Zzg4z0Pf1oDqSx6zayqPLEryFgoiVQWORnOM9MVbtbhLq3SeLcEcZG4YNZ0umTRRRm3leWaNsoxZYyoxgjIU5/EVd063e0sIYJGDOi4JHrQBapP4vwpaT+L8KAMj7Be/J+7tCEd3GZX6vnP8AD/tGov7L1AQeUjW4xC0AJlY/KRwD8vOO1aCXjtOyFVZQWBCj5hj1+tSLeI23ajksxXAAPI/GgDOt9P1GAlt8DyEKu9pWyFU5C/d6dfzp/wBl1URXKg2W64Yktuf5eAMDj0FXheR+W8mGCocZOOT+f86FvI3KBFdi2eABxjr3oAz57DUJhHj7NE0abA0UrglfQ/LSHTb7zoHAtQtuMRRiRtq8YyPlz0962qKAMaCw1GAllaAu0gkZjK2WIGMHC9KILC/g27RakIzMgaVsLu6gfL0rZooAxE02+ikieH7PGY1CHbK3zgdAcr/LFRLot2gcDyNrqybfObABOePl9a6CigDDGl3wU/NB5hkEvmGZt24DGfu46Cj+y7zezFbYq27EfmvtUsMEgbetblFAGO9jfOGzHafNGsZ/ev0Ukj+H3NQf2Pd75G/0fEm/Kea2Pm+9/DW/RQBiJp2oRypKjwB1ADHzW/eAdN3y/wAsVc0y0ntFlWVl2McoiOWCdSQMgY6+9X6TtQADoKWkHQUtABRRSUALRVaOWZpZIyY2KrncAcA+h5p1tJJJvL7CAcAqDz60AQwaclvLM6T3GJmZmQsMZPfpn9abDpUUNm9p59w8Drs2sw4HfGB3qaKaR5ZEbYpGdqlSDjPB9x9Kia8eIOZNjKjAFlBx7j60APubCO5WEeZLEYTlGiYAjjHcHtU0EEdtbxwRDEcYCqPYVXmu5Y4o3IjXzCcZBOBjI6VZjcyQxuRgsAcUARXlmt55e6aaLy23DyyBz+INI1kr3STyTSvsO5IyRtU4xnGOtWqKAKiWCrO07TzySFSil2HyA+nH86SPTxHHKFuLjzZSC024b+OnbH6VcooAqwWMduiKkkvyszklvvsepb1pbezSCaSYySyyyAAtIQSAOgGAOOamk3bDsKg+rdKr+fKbXzcxjBOSQcMO2Oe9AEf9lQfafP8AMmxvMgj3/IGIIJxj3NQPokSWU0EEjnzIxGPMbhRnIxgdRVuSaeOONmEe5sApg5J9uae12iyFNkjENtyF4J9KAIW0uFxbKWkEdvtKRgjbleh6Zz+NLJ/yHbH/AK5yfyFSpdxu0aqrZcZHTgfnUUn/ACHbH/rnJ/IVcN38/wAhotXdyY2KqdoH3iOvPYVS+2yf35P++h/hVq/tJJT5kON2MFT3qh9ivP8AniP++hWkOS2pStYl+2yf35P++h/hR9tk/vyf99D/AAqL7Fe/88R/30KPsV7/AM8R/wB9Cq/dj90l+2yf35P++h/hR9tk/vyf99D/AAqL7Fe/88R/30KPsV7/AM8R/wB9Cj92HukjXsnHzydR/EP8KX7bJ/fk/wC+h/hULWV5x+5HUfxCl+xXv/PEf99Cj92Hukv22T+/J/30P8KPtsn9+T/vof4VF9ivf+eI/wC+hR9ivf8AniP++hR+7D3SX7bJ/fk/76H+FH22T+/J/wB9D/CovsV7/wA8R/30KPsV7/zxH/fQo/dh7pL9tk/vyf8AfQ/wo+2yf35P++h/hUX2K9/54j/voUfYr3/niP8AvoUfuw90kW9k2j55On94f4Uv22T+/J/30P8ACoVsrzaP3I6f3hS/Yr3/AJ4j/voUfuw90l+2yf35P++h/hR9tk/vyf8AfQ/wqL7Fe/8APEf99Cj7Fe/88R/30KP3Ye6S/bZP78n/AH0P8KPtsn9+T/vof4VF9ivf+eI/76FH2K9/54j/AL6FH7sPdJftsn9+T/vof4UgvZNx+eToP4h/hUf2K9/54j/voUgsrzcf3I6D+IUfuw90m+2yf35P++h/hR9tk/vyf99D/CovsV7/AM8R/wB9Cj7Fe/8APEf99Cj92Hukv22T+/J/30P8KPtsn9+T/vof4VF9ivf+eI/76FH2K9/54j/voUfuw90l+2yf35P++h/hR9tk/vyf99D/AAqL7Fe/88R/30KPsV7/AM8R/wB9Cj92HukhvZMr88nX+8P8KX7bJ/fk/wC+h/hUJsrzI/cjr/eFL9ivf+eI/wC+hR+7D3SX7bJ/fk/76H+FH22T+/J/30P8Ki+xXv8AzxH/AH0KPsV7/wA8R/30KP3Ye6S/bZP78n/fQ/wo+2yf35P++h/hUX2K9/54j/voUfYr3/niP++hR+7D3SX7bJ/fk/76H+FH22T+/J/30P8ACovsV7/zxH/fQo+xXv8AzxH/AH0KP3Ye6SLeybR88nT+8P8ACl+2yf35P++h/hUK2V5tH7kdP7wpfsV7/wA8R/30KP3Ye6S/bZP78n/fQ/wo+2yf35P++h/hUX2K9/54j/voUfYr3/niP++hR+7D3SX7bJ/fk/76H+FH22T+/J/30P8ACovsV7/zxH/fQo+xXv8AzxH/AH0KP3Ye6S/bZP78n/fQ/wAKQXsmW+eTr/eH+FR/Yr3/AJ4j/voUgsrzJ/cjr/eFH7sPdJvtsn9+T/vof4UfbZP78n/fQ/wqL7Fe/wDPEf8AfQo+xXv/ADxH/fQo/dh7pL9tk/vyf99D/Cj7bJ/fk/76H+FRfYr3/niP++hR9ivf+eI/76FH7sPdJftsn9+T/vof4UfbZP78n/fQ/wAKi+xXv/PEf99Cj7Fe/wDPEf8AfQo/dh7pIb2TK/PJ1/vD/Cl+2yf35P8Avof4VCbK8yP3I6/3hS/Yr3/niP8AvoUfuw90l+2yf35P++h/hR9tk/vyf99D/CovsV7/AM8R/wB9Cj7Fe/8APEf99Cj92Hukv22T+/J/30P8KPtsn9+T/vof4VF9ivf+eI/76FH2K9/54j/voUfuw90l+2yf35P++h/hSNeybT88nT+8P8Kj+xXv/PEf99CkayvNp/cjp/eFH7sPdJvtsn9+T/vof4UfbZP78n/fQ/wqL7Fe/wDPEf8AfQo+xXv/ADxH/fQo/dh7pL9tk/vyf99D/Cj7bJ/fk/76H+FRfYr3/niP++hR9ivf+eI/76FH7sPdJftsn9+T/vof4UfbZP78n/fQ/wAKi+xXv/PEf99Cj7Fe/wDPEf8AfQo/dh7pZivmUkszEDkhsHI+tanUViw6dcySDzgI4+/OSfatqsZ8t9CZW6DZEEkbITjIxmqZsJz/AMxCf/vhP8K0tgo2CoJMz+zpv+ghP/3yv+FSW1kYZfMe4kmI6BgBj8hV/YKNgoArzxGVVXOFDBj7gc4/PFNa2RpDIS24lT19On86tbBRsFAFN7OJ12ktj5u/97rUT2O1D5TMX3BgS23BxjjA9K0dgo2CgDPisQiR7nYSJnLLznJzjkVMtsq3BnLMz4IGccD8qtbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdFSbBRsFAEdQN99vrVvYKrlRvf60AR0VJsFGwUAR0VJsFGwUAR0VJsFGwUAR0VJsFGwUAR0g6mpdgpoUbmoAq/ZIv3fBJjG0H1HvSfY49u0u542gkj5R7cVd2CjYKAK7xK6oGJO05+tRfYoQgQAhQu0YPvmruwUbBQBTNopO7zJN+c78jPp6UC0jCbMtjZs69qubBRsFAFSS2RyxJYEkHI7EU17NHBzJIMrtbBA3D34q7sFGwUAR0n8X4VLsFN2jf8AhQA2ipNgo2CgCOipNgo2CgCOipNgo2CgCOipNgo2CgCOk/i/Cpdgpu0bz9KAK5tkMLxZba5JPPPNJFapG+4M7EEnnHf8ParewUbBQBSNnG28szMXABJxkY6dqkSAKysWZmUEAnHf6CrOwUbBQBHRUmwUbBQBHRUmwUbBQBHRUmwUbBQBHRUmwUbBQBHRUmwUbBQBHSdql2CkKDBoAjHQUtPVRtH0pdgoAjpKl2CjYKAKkVsIkKLJIVIPBI/PpTlhVY0jVmVUxjB6/WrOwUbBQBV+zguXZ3YkEDJHyg+lNS0RUVN7sqkEA44/SrmwUbBQBSNmmAFeRQpJXBHGfTipUjWKNI0+6uAKsbBTWUcfUUANoqTYKNgoAjoqTYKNgoArzRLNEY2LAHrtNN8hSqKzMwRtwzirWwUbBQBVe3DzCXzHVgMcEYx+IpfITfu5zv3/AI4xVnYKNgoAp/ZExGNz7UOQOOuc+lRSf8h2x/65yfyFaOwVQlUDX7D/AK5yfyFXDf7/AMho06Kk2CjYKgRHRUmwUbBQBHRUmwUbBQBE3QfUUtPZBgfUUuwUAR0VJsFGwUAR0VJsFGwUAR0VJsFGwUARL9xfpS09EGxfpS7BQBHRUmwUbBQBHRUmwUbBQBHSD75+gqXYKQIN5+goAZRUmwUbBQBHRUmwUbBQBHRUmwUbBQBEeq/X+lLT2QZX6/0pdgoAjoqTYKNgoAjoqTYKNgoAjoqTYKNgoAiT7i/Slp6INi/Sl2CgCOipNgo2CgCOipNgo2CgCOkXq31/pUuwUioMt9f6UAMoqTYKNgoAjoqTYKNgoAjoqTYKNgoAibqv1/pS09kGV+v9KXYKAI6Kk2CjYKAI6Kk2CjYKAI6R/uN9Kl2CkdBsb6UAMoqTYKNgoAjoqTYKNgoAjoqTYKNgoAjoqTYKNgoAbP8A6h/pSG3hPWJP++aKKAGta2//ADwj/wC+RUYhiiuYTHGqEkg7RjPFFFADdRu5LQW3lhT5s6xNuHQHPT3q5RRQBR1WWSIWnlOU33CK2O454q/RRR0DqFQTBzcQFZXRQTuUYw/HfIz+WKKKAJ6KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAquR87fWiigAxRiiigAxRiiigAxRiiigAxRiiigAxSAfM1FFAGRNPc2ZvP8ASXm223nJ5ir8pyemAOPrUkNxPFbX4eZpmtxlHcDJ+XPOABRRR0B7lnSpZLjTLaaZt0jxhmOAMn8Kt4oopvcEGKMUUUgDFGKKKADFJj5/woooAXFGKKKADFGKKKADFGKKKADFGKKKADFJj5/woooAqWsrmzmkZi7LJLjPoGbA/IUtpcvO0IYKN9uspx6n+lFFAFvFV97/ANoiLd+78otjHfI5oooW4BZO8tvvkbcSzdunNWMUUUAAHNZ8FzLO1m7Hb5hfcq9DgHFFFAGhijFFFAEFzM0MluqgESSBDn0wanxRRQAYqK7kMNrLKuCyIWGelFFAD0O6NWPUgGnEcGiigBFHyj6UuKKKADFGKKKADFGKKKAMxWnj1FUNzJJHMkjbWVcJgjGMAHv3zTImuRJc27XkzbY0dZCqblJzn+HH5iiijoBUa6vQvl/bZci4dPM2Ju2hCQPu46+1bNnI1xYW00n35ERjj1IoopgQ6hLLFcWYjkKq8u1wADuGD6j+VNjaaTVZgbmQRRlQIgq7Tlc8nGf1ooqRsjaS4gu5lNzJIpt3kUOq/IQeMYA/XNSWiTy2J33sxd8ESbUBXp0+XH5g0UUAS6ZJJLZ5lkMjq7puIAJwxAzjjtUelmaSIyzXEku/orKoC8npgD9c0UVQia6ZlltQrFQ0uGA7jaeKs4oopAwxVKVR/bdk3cRyf0ooq4b/AHjRq0UUVAgooooAKKKKAGt0H1FOoooAKKKKACiiigAooooARfuj6UtFFABRRRQAUUUUAFNH3z9BRRQA6iiigAooooAKKKKAGnqv1p1FFABRRRQAUUUUAFFFFACL9wfSloooAKKKKACiiigApo6t9f6UUUAOooooAKKKKACiiigBD1X6/wBKWiigAooooAKKKKACkb7h+lFFAC0UUUAFFFFABRRRQAUUUUAf/9k=); + display:block; + width:100%; + height:100px; + position: relative; + top:0px;} diff --git a/test/test_client.py b/test/test_client.py deleted file mode 100644 index 2c6ac0d..0000000 --- a/test/test_client.py +++ /dev/null @@ -1,272 +0,0 @@ -import os.path -import pytest -import sys - - -def setup_module(module): - sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -class TestClient(object): - def setup_method(self, method): - from browsermobproxy.client import Client - self.client = Client("localhost:9090") - - def teardown_method(self, method): - self.client.close() - - def test_we_can_get_list_of_ports(self): - """ - GET /proxy - get a list of ports attached to ProxyServer instances - managed by ProxyManager - """ - ports = self.client.proxy_ports - - assert(len(ports) == 1) - assert(9090 not in ports) - - def test_headers_type(self): - """ - /proxy/:port/headers needs to take a dictionary - """ - with pytest.raises(TypeError): - self.client.headers(['foo']) - - def test_headers_content(self): - """ - /proxy/:port/headers needs to take a dictionary - and returns 200 when its successful - """ - s = self.client.headers({'User-Agent': 'rubber ducks floating in a row'}) - assert(s == 200) - - def test_new_har(self): - """ - /proxy/:port/har - and returns 204 when creating a har with a particular name the first time - and returns 200 and the previous har when creating one with the same name - """ - status_code, har = self.client.new_har() - assert(status_code == 204) - assert(har is None) - status_code, har = self.client.new_har() - assert(status_code == 200) - assert('log' in har) - - def _test_new_har(self): - """ - /proxy/:port/har - and returns 204 when creating a har with a particular name the first time - and returns 200 and the previous har when creating one with the same name - """ - status_code, har = self.client.new_har("elephants") - assert(status_code == 204) - assert(har is None) - status_code, har = self.client.new_har("elephants") - assert(status_code == 200) - assert('elephants' == har["log"]["pages"][0]['id']) - - def test_new_page_defaults(self): - """ - /proxy/:port/pageRef - adds a new page of 'Page N' when no page name is given - """ - self.client.new_har() - self.client.new_page() - har = self.client.har - assert(len(har["log"]["pages"]) == 2) - assert(har["log"]["pages"][1]["id"] == "Page 1") - - def test_new_named_page(self): - """ - /proxy/:port/pageRef - adds a new page of 'buttress' - """ - self.client.new_har() - self.client.new_page('buttress') - har = self.client.har - assert(len(har["log"]["pages"]) == 2) - assert(har["log"]["pages"][1]["id"] == "buttress") - - def test_single_whitelist(self): - """ - /proxy/:port/whitelist - adds a whitelist - """ - status_code = self.client.whitelist("http://www\\.facebook\\.com/.*", 200) - assert(status_code == 200) - - def test_multiple_whitelists(self): - """ - /proxy/:port/whitelist - adds a whitelist - """ - status_code = self.client.whitelist("http://www\\.facebook\\.com/.*,http://cdn\\.twitter\\.com", 200) - assert(status_code == 200) - - def test_blacklist(self): - """ - /proxy/:port/blacklist - adds a blacklist - """ - status_code = self.client.blacklist("http://www\\.facebook\\.com/.*", 200) - assert(status_code == 200) - - def test_basic_authentication(self): - """ - /proxy/:port/auth/basic - adds automatic basic authentication - """ - status_code = self.client.basic_authentication("www.example.com", "myUsername", "myPassword") - assert(status_code == 200) - - def test_limits_invalid_key(self): - """ - /proxy/:port/limits - pre-sending checking that the parameter is correct - """ - with pytest.raises(KeyError): - self.client.limits({"hurray": "explosions"}) - - def test_limits_key_no_value(self): - """ - /proxy/:port/limits - pre-sending checking that a parameter exists - """ - with pytest.raises(KeyError): - self.client.limits({}) - - def test_limits_all_key_values(self): - """ - /proxy/:port/limits - can send all 3 at once based on the proxy implementation - """ - limits = {"upstream_kbps": 320, "downstream_kbps": 560, "latency": 30} - status_code = self.client.limits(limits) - assert(status_code == 200) - - def test_rewrite(self): - """ - /proxy/:port/rewrite - - """ - match = "/foo" - replace = "/bar" - status_code = self.client.rewrite_url(match, replace) - assert(status_code == 200) - - def test_close(self): - """ - /proxy/:port - close the proxy port - """ - status_code = self.client.close() - assert(status_code == 200) - status_code = self.client.close() - assert(status_code == 404) - - def test_response_interceptor_with_parsing_js(self): - """ - /proxy/:port/interceptor/response - This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS - Code only gets validated if the filter/interceptor is used. - """ - js = 'alert("foo")' - status_code = self.client.response_interceptor(js) - assert(status_code == 200) - - def test_response_interceptor_with_invalid_js(self): - """ - /proxy/:port/interceptor/response - This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS - Code only gets validated if the filter/interceptor is used. - """ - js = 'alert("foo"' - status_code = self.client.response_interceptor(js) - assert(status_code == 500) - - def test_request_interceptor_with_parsing_js(self): - """ - /proxy/:port/interceptor/request - This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS - Code only gets validated if the filter/interceptor is used. - """ - js = 'alert("foo")' - status_code = self.client.request_interceptor(js) - assert(status_code == 200) - - def test_request_interceptor_with_invalid_js(self): - """ - /proxy/:port/interceptor/request - This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS - Code only gets validated if the filter/interceptor is used. - """ - js = 'alert("foo"' - status_code = self.client.request_interceptor(js) - assert(status_code == 500) - - def test_timeouts_invalid_timeouts(self): - """ - /proxy/:port/timeout - pre-sending checking that the parameter is correct - """ - with pytest.raises(KeyError): - self.client.timeouts({"hurray": "explosions"}) - - def test_timeouts_key_no_value(self): - """ - /proxy/:port/timeout - pre-sending checking that a parameter exists - """ - with pytest.raises(KeyError): - self.client.timeouts({}) - - def test_timeouts_all_key_values(self): - """ - /proxy/:port/timeout - can send all 3 at once based on the proxy implementation - """ - timeouts = {"request": 2, "read": 2, "connection": 2, "dns": 3} - status_code = self.client.timeouts(timeouts) - assert(status_code == 200) - - def test_remap_hosts(self): - """ - /proxy/:port/hosts - """ - status_code = self.client.remap_hosts("example.com", "1.2.3.4") - assert(status_code == 200) - - def test_remap_hosts_with_hostmap(self): - """ - /proxy/:port/hosts - """ - status_code = self.client.remap_hosts(hostmap={"example.com": "1.2.3.4"}) - assert(status_code == 200) - - def test_wait_for_traffic_to_stop(self): - """ - /proxy/:port/wait - """ - status_code = self.client.wait_for_traffic_to_stop(2000, 10000) - assert(status_code == 200) - - def test_clear_dns_cache(self): - """ - /proxy/:port/dns/cache - """ - status_code = self.client.clear_dns_cache() - assert(status_code == 200) - - def test_rewrite_url(self): - """ - /proxy/:port/rewrite - """ - status_code = self.client.rewrite_url('http://www.facebook\.com', 'http://microsoft.com') - assert(status_code == 200) - - def test_retry(self): - """ - /proxy/:port/retry - """ - status_code = self.client.retry(4) - assert(status_code == 200) diff --git a/test/test_remote.py b/test/test_remote.py deleted file mode 100644 index c8cd5f1..0000000 --- a/test/test_remote.py +++ /dev/null @@ -1,55 +0,0 @@ -from os import environ - -from selenium import webdriver -import selenium.webdriver.common.desired_capabilities -import os -import sys -import pytest - - -def setup_module(module): - sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - - -class TestRemote(object): - def setup_method(self, method): - from browsermobproxy.client import Client - self.client = Client("localhost:9090") - chrome_binary = environ.get("CHROME_BIN", None) - self.desired_caps = selenium.webdriver.common.desired_capabilities.DesiredCapabilities.CHROME - if chrome_binary is not None: - self.desired_caps.update({ - "chromeOptions": { - "binary": chrome_binary, - "args": ['no-sandbox'] - } - }) - self.driver = webdriver.Remote( - desired_capabilities=self.desired_caps, - proxy=self.client) - - def teardown_method(self, method): - self.client.close() - self.driver.quit() - - @pytest.mark.human - def test_set_clear_url_rewrite_rule(self): - targetURL = "https://www.saucelabs.com/versions.js" - assert 200 == self.client.rewrite_url( - "https://www.saucelabs.com/versions.+", "https://www.saucelabs.com/versions.json" - ) - self.driver.get(targetURL) - assert "Sauce Connect" in self.driver.page_source - assert self.client.clear_all_rewrite_url_rules() == 200 - self.driver.get(targetURL) - assert "Sauce Connect" not in self.driver.page_source - - @pytest.mark.human - def test_response_interceptor(self): - content = "Response successfully intercepted" - targetURL = "https://saucelabs.com/versions.json?hello" - self.client.response_interceptor( - """if(messageInfo.getOriginalUrl().contains('?hello')){contents.setTextContents("%s");}""" % content - ) - self.driver.get(targetURL) - assert content in self.driver.page_source diff --git a/test/test_webdriver.py b/test/test_webdriver.py deleted file mode 100644 index ba47d92..0000000 --- a/test/test_webdriver.py +++ /dev/null @@ -1,75 +0,0 @@ -from os import environ - -from selenium import webdriver -import selenium.webdriver.common.desired_capabilities -from selenium.webdriver.common.proxy import Proxy -import os -import sys -import copy -import pytest - -def setup_module(module): - sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -class TestWebDriver(object): - def setup_method(self, method): - from browsermobproxy.client import Client - self.client = Client("localhost:9090") - self.driver = None - - def teardown_method(self, method): - self.client.close() - if self.driver is not None: - self.driver.quit() - - @pytest.mark.human - def test_i_want_my_by_capability(self): - capabilities = selenium.webdriver.common.desired_capabilities.DesiredCapabilities.CHROME - self.client.add_to_capabilities(capabilities) - # sets self.driver for proper clean up - self._create_webdriver(capabilites=capabilities) - - self._run_url_rewrite_test() - - @pytest.mark.human - def test_i_want_my_by_proxy_object(self): - self._create_webdriver(capabilites=selenium.webdriver.common.desired_capabilities.DesiredCapabilities.CHROME, - proxy=self.client) - - self._run_url_rewrite_test() - - def test_what_things_look_like(self): - bmp_capabilities = copy.deepcopy(selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX) - self.client.add_to_capabilities(bmp_capabilities) - - proxy_capabilities = copy.deepcopy(selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX) - proxy_addr = 'localhost:%d' % self.client.port - proxy = Proxy({'httpProxy': proxy_addr,'sslProxy': proxy_addr}) - proxy.add_to_capabilities(proxy_capabilities) - - assert bmp_capabilities == proxy_capabilities - - def _create_webdriver(self, capabilites, proxy=None): - chrome_binary = environ.get("CHROME_BIN", None) - if chrome_binary is not None: - capabilites.update({ - "chromeOptions": { - "binary": chrome_binary, - "args": ['no-sandbox'] - } - }) - if proxy is None: - self.driver = webdriver.Remote(desired_capabilities=capabilites) - else: - self.driver = webdriver.Remote(desired_capabilities=capabilites, proxy=proxy) - - def _run_url_rewrite_test(self): - targetURL = "https://www.saucelabs.com/versions.js" - assert 200 == self.client.rewrite_url( - "https://www.saucelabs.com/versions.+", "https://www.saucelabs.com/versions.json" - ) - self.driver.get(targetURL) - assert "Sauce Connect" in self.driver.page_source - assert self.client.clear_all_rewrite_url_rules() == 200 - self.driver.get(targetURL) - assert "Sauce Connect" not in self.driver.page_source