aboutsummaryrefslogtreecommitdiffstats
path: root/pathod/libpathod
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2016-02-15 14:58:49 +0100
committerMaximilian Hils <git@maximilianhils.com>2016-02-15 14:58:49 +0100
commit175ce43a30559115c08e41e5d87519e957ff96f6 (patch)
tree9231c6396d15b70601492458b33f44bfe579233b /pathod/libpathod
parent43c3e164ecf13b2d0909f748c2c61f39e197659e (diff)
parente8598f5f7a613d7d27130de970b4c0045b3ee0d1 (diff)
downloadmitmproxy-175ce43a30559115c08e41e5d87519e957ff96f6.tar.gz
mitmproxy-175ce43a30559115c08e41e5d87519e957ff96f6.tar.bz2
mitmproxy-175ce43a30559115c08e41e5d87519e957ff96f6.zip
add pathod
Diffstat (limited to 'pathod/libpathod')
-rw-r--r--pathod/libpathod/__init__.py0
-rw-r--r--pathod/libpathod/app.py179
-rw-r--r--pathod/libpathod/language/__init__.py113
-rw-r--r--pathod/libpathod/language/actions.py126
-rw-r--r--pathod/libpathod/language/base.py576
-rw-r--r--pathod/libpathod/language/exceptions.py22
-rw-r--r--pathod/libpathod/language/generators.py86
-rw-r--r--pathod/libpathod/language/http.py381
-rw-r--r--pathod/libpathod/language/http2.py299
-rw-r--r--pathod/libpathod/language/message.py96
-rw-r--r--pathod/libpathod/language/websockets.py241
-rw-r--r--pathod/libpathod/language/writer.py67
-rw-r--r--pathod/libpathod/log.py83
-rw-r--r--pathod/libpathod/pathoc.py534
-rw-r--r--pathod/libpathod/pathoc_cmdline.py226
-rw-r--r--pathod/libpathod/pathod.py503
-rw-r--r--pathod/libpathod/pathod_cmdline.py231
-rw-r--r--pathod/libpathod/protocols/__init__.py1
-rw-r--r--pathod/libpathod/protocols/http.py71
-rw-r--r--pathod/libpathod/protocols/http2.py20
-rw-r--r--pathod/libpathod/protocols/websockets.py56
-rw-r--r--pathod/libpathod/static/bootstrap.min.css9
-rw-r--r--pathod/libpathod/static/bootstrap.min.js6
-rw-r--r--pathod/libpathod/static/jquery-1.7.2.min.js4
-rw-r--r--pathod/libpathod/static/jquery.localscroll-min.js9
-rw-r--r--pathod/libpathod/static/jquery.scrollTo-min.js11
-rw-r--r--pathod/libpathod/static/pathod.css56
-rw-r--r--pathod/libpathod/static/start_quote.pngbin0 -> 376 bytes
-rw-r--r--pathod/libpathod/static/syntax.css120
-rw-r--r--pathod/libpathod/static/torture.pngbin0 -> 108327 bytes
-rw-r--r--pathod/libpathod/templates/about.html22
-rw-r--r--pathod/libpathod/templates/docframe.html26
-rw-r--r--pathod/libpathod/templates/docs_lang.html196
-rw-r--r--pathod/libpathod/templates/docs_lang_requests.html114
-rw-r--r--pathod/libpathod/templates/docs_lang_responses.html88
-rw-r--r--pathod/libpathod/templates/docs_lang_websockets.html115
-rw-r--r--pathod/libpathod/templates/docs_libpathod.html23
-rw-r--r--pathod/libpathod/templates/docs_pathoc.html211
-rw-r--r--pathod/libpathod/templates/docs_pathod.html172
-rw-r--r--pathod/libpathod/templates/docs_test.html50
-rw-r--r--pathod/libpathod/templates/download.html39
-rw-r--r--pathod/libpathod/templates/examples_context.html24
-rw-r--r--pathod/libpathod/templates/examples_setup.html32
-rw-r--r--pathod/libpathod/templates/examples_setupall.html40
-rw-r--r--pathod/libpathod/templates/frame.html7
-rw-r--r--pathod/libpathod/templates/index.html60
-rw-r--r--pathod/libpathod/templates/layout.html75
-rw-r--r--pathod/libpathod/templates/libpathod_pathoc.html8
-rw-r--r--pathod/libpathod/templates/log.html31
-rw-r--r--pathod/libpathod/templates/onelog.html8
-rw-r--r--pathod/libpathod/templates/request_preview.html44
-rw-r--r--pathod/libpathod/templates/request_previewform.html53
-rw-r--r--pathod/libpathod/templates/response_preview.html44
-rw-r--r--pathod/libpathod/templates/response_previewform.html87
-rw-r--r--pathod/libpathod/test.py103
-rw-r--r--pathod/libpathod/utils.py124
-rw-r--r--pathod/libpathod/version.py11
57 files changed, 5933 insertions, 0 deletions
diff --git a/pathod/libpathod/__init__.py b/pathod/libpathod/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/pathod/libpathod/__init__.py
diff --git a/pathod/libpathod/app.py b/pathod/libpathod/app.py
new file mode 100644
index 00000000..debebaf2
--- /dev/null
+++ b/pathod/libpathod/app.py
@@ -0,0 +1,179 @@
+import logging
+import pprint
+import cStringIO
+import copy
+from flask import Flask, jsonify, render_template, request, abort, make_response
+from . import version, language, utils
+from netlib.http import user_agents
+
+logging.basicConfig(level="DEBUG")
+EXAMPLE_HOST = "example.com"
+EXAMPLE_WEBSOCKET_KEY = "examplekey"
+
+# pylint: disable=unused-variable
+
+
+def make_app(noapi, debug):
+ app = Flask(__name__)
+ app.debug = debug
+
+ if not noapi:
+ @app.route('/api/info')
+ def api_info():
+ return jsonify(
+ version=version.IVERSION
+ )
+
+ @app.route('/api/log')
+ def api_log():
+ return jsonify(
+ log=app.config["pathod"].get_log()
+ )
+
+ @app.route('/api/clear_log')
+ def api_clear_log():
+ app.config["pathod"].clear_log()
+ return "OK"
+
+ def render(s, cacheable, **kwargs):
+ kwargs["noapi"] = app.config["pathod"].noapi
+ kwargs["nocraft"] = app.config["pathod"].nocraft
+ kwargs["craftanchor"] = app.config["pathod"].craftanchor
+ resp = make_response(render_template(s, **kwargs), 200)
+ if cacheable:
+ resp.headers["Cache-control"] = "public, max-age=4320"
+ return resp
+
+ @app.route('/')
+ @app.route('/index.html')
+ def index():
+ return render(
+ "index.html",
+ True,
+ section="main",
+ version=version.VERSION
+ )
+
+ @app.route('/download')
+ @app.route('/download.html')
+ def download():
+ return render(
+ "download.html", True, section="download", version=version.VERSION
+ )
+
+ @app.route('/about')
+ @app.route('/about.html')
+ def about():
+ return render("about.html", True, section="about")
+
+ @app.route('/docs/pathod')
+ def docs_pathod():
+ return render(
+ "docs_pathod.html", True, section="docs", subsection="pathod"
+ )
+
+ @app.route('/docs/language')
+ def docs_language():
+ return render(
+ "docs_lang.html", True,
+ section="docs", uastrings=user_agents.UASTRINGS,
+ subsection="lang"
+ )
+
+ @app.route('/docs/pathoc')
+ def docs_pathoc():
+ return render(
+ "docs_pathoc.html", True, section="docs", subsection="pathoc"
+ )
+
+ @app.route('/docs/libpathod')
+ def docs_libpathod():
+ return render(
+ "docs_libpathod.html", True, section="docs", subsection="libpathod"
+ )
+
+ @app.route('/docs/test')
+ def docs_test():
+ return render(
+ "docs_test.html", True, section="docs", subsection="test"
+ )
+
+ @app.route('/log')
+ def log():
+ if app.config["pathod"].noapi:
+ abort(404)
+ return render(
+ "log.html",
+ False,
+ section="log",
+ log=app.config["pathod"].get_log()
+ )
+
+ @app.route('/log/<int:lid>')
+ def onelog(lid):
+ item = app.config["pathod"].log_by_id(int(lid))
+ if not item:
+ abort(404)
+ l = pprint.pformat(item)
+ return render("onelog.html", False, section="log", alog=l, lid=lid)
+
+ def _preview(is_request):
+ if is_request:
+ template = "request_preview.html"
+ else:
+ template = "response_preview.html"
+
+ spec = request.args["spec"]
+
+ args = dict(
+ spec=spec,
+ section="main",
+ syntaxerror=None,
+ error=None,
+ )
+ if not spec.strip():
+ args["error"] = "Can't parse an empty spec."
+ return render(template, False, **args)
+
+ try:
+ if is_request:
+ r = language.parse_pathoc(spec).next()
+ else:
+ r = language.parse_pathod(spec).next()
+ except language.ParseException as v:
+ args["syntaxerror"] = str(v)
+ args["marked"] = v.marked()
+ return render(template, False, **args)
+
+ s = cStringIO.StringIO()
+
+ settings = copy.copy(app.config["pathod"].settings)
+ settings.request_host = EXAMPLE_HOST
+ settings.websocket_key = EXAMPLE_WEBSOCKET_KEY
+
+ safe = r.preview_safe()
+ err, safe = app.config["pathod"].check_policy(
+ safe,
+ settings
+ )
+ if err:
+ args["error"] = err
+ return render(template, False, **args)
+ if is_request:
+ settings.request_host = EXAMPLE_HOST
+ language.serve(safe, s, settings)
+ else:
+ settings.websocket_key = EXAMPLE_WEBSOCKET_KEY
+ language.serve(safe, s, settings)
+
+ args["output"] = utils.escape_unprintables(s.getvalue())
+ return render(template, False, **args)
+
+ @app.route('/response_preview')
+ def response_preview():
+ return _preview(False)
+
+ @app.route('/request_preview')
+ def request_preview():
+ return _preview(True)
+ return app
diff --git a/pathod/libpathod/language/__init__.py b/pathod/libpathod/language/__init__.py
new file mode 100644
index 00000000..32199e08
--- /dev/null
+++ b/pathod/libpathod/language/__init__.py
@@ -0,0 +1,113 @@
+import itertools
+import time
+
+import pyparsing as pp
+
+from . import http, http2, websockets, writer, exceptions
+
+from exceptions import *
+from base import Settings
+assert Settings # prevent pyflakes from messing with this
+
+
+def expand(msg):
+ times = getattr(msg, "times", None)
+ if times:
+ for j_ in xrange(int(times.value)):
+ yield msg.strike_token("times")
+ else:
+ yield msg
+
+
+def parse_pathod(s, use_http2=False):
+ """
+ May raise ParseException
+ """
+ try:
+ s = s.decode("ascii")
+ except UnicodeError:
+ raise exceptions.ParseException("Spec must be valid ASCII.", 0, 0)
+ try:
+ if use_http2:
+ expressions = [
+ # http2.Frame.expr(),
+ http2.Response.expr(),
+ ]
+ else:
+ expressions = [
+ websockets.WebsocketFrame.expr(),
+ http.Response.expr(),
+ ]
+ reqs = pp.Or(expressions).parseString(s, parseAll=True)
+ except pp.ParseException as v:
+ raise exceptions.ParseException(v.msg, v.line, v.col)
+ return itertools.chain(*[expand(i) for i in reqs])
+
+
+def parse_pathoc(s, use_http2=False):
+ try:
+ s = s.decode("ascii")
+ except UnicodeError:
+ raise exceptions.ParseException("Spec must be valid ASCII.", 0, 0)
+ try:
+ if use_http2:
+ expressions = [
+ # http2.Frame.expr(),
+ http2.Request.expr(),
+ ]
+ else:
+ expressions = [
+ websockets.WebsocketClientFrame.expr(),
+ http.Request.expr(),
+ ]
+ reqs = pp.OneOrMore(pp.Or(expressions)).parseString(s, parseAll=True)
+ except pp.ParseException as v:
+ raise exceptions.ParseException(v.msg, v.line, v.col)
+ return itertools.chain(*[expand(i) for i in reqs])
+
+
+def parse_websocket_frame(s):
+ """
+ May raise ParseException
+ """
+ try:
+ reqs = pp.OneOrMore(
+ websockets.WebsocketFrame.expr()
+ ).parseString(
+ s,
+ parseAll=True
+ )
+ except pp.ParseException as v:
+ raise exceptions.ParseException(v.msg, v.line, v.col)
+ return itertools.chain(*[expand(i) for i in reqs])
+
+
+def serve(msg, fp, settings):
+ """
+ fp: The file pointer to write to.
+
+ request_host: If this a request, this is the connecting host. If
+ None, we assume it's a response. Used to decide what standard
+ modifications to make if raw is not set.
+
+ Calling this function may modify the object.
+ """
+ msg = msg.resolve(settings)
+ started = time.time()
+
+ vals = msg.values(settings)
+ vals.reverse()
+
+ actions = sorted(msg.actions[:])
+ actions.reverse()
+ actions = [i.intermediate(settings) for i in actions]
+
+ disconnect = writer.write_values(fp, vals, actions[:])
+ duration = time.time() - started
+ ret = dict(
+ disconnect=disconnect,
+ started=started,
+ duration=duration,
+ )
+ ret.update(msg.log(settings))
+ return ret
diff --git a/pathod/libpathod/language/actions.py b/pathod/libpathod/language/actions.py
new file mode 100644
index 00000000..34a9bafb
--- /dev/null
+++ b/pathod/libpathod/language/actions.py
@@ -0,0 +1,126 @@
+import abc
+import copy
+import random
+
+import pyparsing as pp
+
+from . import base
+
+
+class _Action(base.Token):
+
+ """
+ An action that operates on the raw data stream of the message. All
+ actions have one thing in common: an offset that specifies where the
+ action should take place.
+ """
+
+ def __init__(self, offset):
+ self.offset = offset
+
+ def resolve(self, settings, msg):
+ """
+ Resolves offset specifications to a numeric offset. Returns a copy
+ of the action object.
+ """
+ c = copy.copy(self)
+ l = msg.length(settings)
+ if c.offset == "r":
+ c.offset = random.randrange(l)
+ elif c.offset == "a":
+ c.offset = l + 1
+ return c
+
+ def __cmp__(self, other):
+ return cmp(self.offset, other.offset)
+
+ def __repr__(self):
+ return self.spec()
+
+ @abc.abstractmethod
+ def spec(self): # pragma: no cover
+ pass
+
+ @abc.abstractmethod
+ def intermediate(self, settings): # pragma: no cover
+ pass
+
+
+class PauseAt(_Action):
+ unique_name = None
+
+ def __init__(self, offset, seconds):
+ _Action.__init__(self, offset)
+ self.seconds = seconds
+
+ @classmethod
+ def expr(cls):
+ e = pp.Literal("p").suppress()
+ e += base.TokOffset
+ e += pp.Literal(",").suppress()
+ e += pp.MatchFirst(
+ [
+ base.v_integer,
+ pp.Literal("f")
+ ]
+ )
+ return e.setParseAction(lambda x: cls(*x))
+
+ def spec(self):
+ return "p%s,%s" % (self.offset, self.seconds)
+
+ def intermediate(self, settings):
+ return (self.offset, "pause", self.seconds)
+
+ def freeze(self, settings_):
+ return self
+
+
+class DisconnectAt(_Action):
+
+ def __init__(self, offset):
+ _Action.__init__(self, offset)
+
+ @classmethod
+ def expr(cls):
+ e = pp.Literal("d").suppress()
+ e += base.TokOffset
+ return e.setParseAction(lambda x: cls(*x))
+
+ def spec(self):
+ return "d%s" % self.offset
+
+ def intermediate(self, settings):
+ return (self.offset, "disconnect")
+
+ def freeze(self, settings_):
+ return self
+
+
+class InjectAt(_Action):
+ unique_name = None
+
+ def __init__(self, offset, value):
+ _Action.__init__(self, offset)
+ self.value = value
+
+ @classmethod
+ def expr(cls):
+ e = pp.Literal("i").suppress()
+ e += base.TokOffset
+ e += pp.Literal(",").suppress()
+ e += base.TokValue
+ return e.setParseAction(lambda x: cls(*x))
+
+ def spec(self):
+ return "i%s,%s" % (self.offset, self.value.spec())
+
+ def intermediate(self, settings):
+ return (
+ self.offset,
+ "inject",
+ self.value.get_generator(settings)
+ )
+
+ def freeze(self, settings):
+ return InjectAt(self.offset, self.value.freeze(settings))
diff --git a/pathod/libpathod/language/base.py b/pathod/libpathod/language/base.py
new file mode 100644
index 00000000..a4302998
--- /dev/null
+++ b/pathod/libpathod/language/base.py
@@ -0,0 +1,576 @@
+import operator
+import os
+import abc
+import pyparsing as pp
+
+from .. import utils
+from . import generators, exceptions
+
+class Settings(object):
+
+ def __init__(
+ self,
+ is_client=False,
+ staticdir=None,
+ unconstrained_file_access=False,
+ request_host=None,
+ websocket_key=None,
+ protocol=None,
+ ):
+ self.is_client = is_client
+ self.staticdir = staticdir
+ self.unconstrained_file_access = unconstrained_file_access
+ self.request_host = request_host
+ self.websocket_key = websocket_key # TODO: refactor this into the protocol
+ self.protocol = protocol
+
+
+Sep = pp.Optional(pp.Literal(":")).suppress()
+
+
+v_integer = pp.Word(pp.nums)\
+ .setName("integer")\
+ .setParseAction(lambda toks: int(toks[0]))
+
+
+v_literal = pp.MatchFirst(
+ [
+ pp.QuotedString(
+ "\"",
+ unquoteResults=True,
+ multiline=True
+ ),
+ pp.QuotedString(
+ "'",
+ unquoteResults=True,
+ multiline=True
+ ),
+ ]
+)
+
+v_naked_literal = pp.MatchFirst(
+ [
+ v_literal,
+ pp.Word("".join(i for i in pp.printables if i not in ",:\n@\'\""))
+ ]
+)
+
+
+class Token(object):
+
+ """
+ A token in the specification language. Tokens are immutable. The token
+ classes have no meaning in and of themselves, and are combined into
+ Components and Actions to build the language.
+ """
+ __metaclass__ = abc.ABCMeta
+
+ @classmethod
+ def expr(cls): # pragma: no cover
+ """
+ A parse expression.
+ """
+ return None
+
+ @abc.abstractmethod
+ def spec(self): # pragma: no cover
+ """
+ A parseable specification for this token.
+ """
+ return None
+
+ @property
+ def unique_name(self):
+ """
+ Controls uniqueness constraints for tokens. No two tokens with the
+ same name will be allowed. If no uniquness should be applied, this
+ should be None.
+ """
+ return self.__class__.__name__.lower()
+
+ def resolve(self, settings_, msg_):
+ """
+ Resolves this token to ready it for transmission. This means that
+ the calculated offsets of actions are fixed.
+
+ settings: a language.Settings instance
+ msg: The containing message
+ """
+ return self
+
+ def __repr__(self):
+ return self.spec()
+
+
+class _TokValueLiteral(Token):
+
+ def __init__(self, val):
+ self.val = val.decode("string_escape")
+
+ def get_generator(self, settings_):
+ return self.val
+
+ def freeze(self, settings_):
+ return self
+
+
+class TokValueLiteral(_TokValueLiteral):
+
+ """
+ A literal with Python-style string escaping
+ """
+ @classmethod
+ def expr(cls):
+ e = v_literal.copy()
+ return e.setParseAction(cls.parseAction)
+
+ @classmethod
+ def parseAction(cls, x):
+ v = cls(*x)
+ return v
+
+ def spec(self):
+ inner = self.val.encode("string_escape")
+ inner = inner.replace(r"\'", r"\x27")
+ return "'" + inner + "'"
+
+
+class TokValueNakedLiteral(_TokValueLiteral):
+
+ @classmethod
+ def expr(cls):
+ e = v_naked_literal.copy()
+ return e.setParseAction(lambda x: cls(*x))
+
+ def spec(self):
+ return self.val.encode("string_escape")
+
+
+class TokValueGenerate(Token):
+
+ def __init__(self, usize, unit, datatype):
+ if not unit:
+ unit = "b"
+ self.usize, self.unit, self.datatype = usize, unit, datatype
+
+ def bytes(self):
+ return self.usize * utils.SIZE_UNITS[self.unit]
+
+ def get_generator(self, settings_):
+ return generators.RandomGenerator(self.datatype, self.bytes())
+
+ def freeze(self, settings):
+ g = self.get_generator(settings)
+ return TokValueLiteral(g[:].encode("string_escape"))
+
+ @classmethod
+ def expr(cls):
+ e = pp.Literal("@").suppress() + v_integer
+
+ u = reduce(
+ operator.or_,
+ [pp.Literal(i) for i in utils.SIZE_UNITS.keys()]
+ ).leaveWhitespace()
+ e = e + pp.Optional(u, default=None)
+
+ s = pp.Literal(",").suppress()
+ s += reduce(
+ operator.or_,
+ [pp.Literal(i) for i in generators.DATATYPES.keys()]
+ )
+ e += pp.Optional(s, default="bytes")
+ return e.setParseAction(lambda x: cls(*x))
+
+ def spec(self):
+ s = "@%s" % self.usize
+ if self.unit != "b":
+ s += self.unit
+ if self.datatype != "bytes":
+ s += ",%s" % self.datatype
+ return s
+
+
+class TokValueFile(Token):
+
+ def __init__(self, path):
+ self.path = str(path)
+
+ @classmethod
+ def expr(cls):
+ e = pp.Literal("<").suppress()
+ e = e + v_naked_literal
+ return e.setParseAction(lambda x: cls(*x))
+
+ def freeze(self, settings_):
+ return self
+
+ def get_generator(self, settings):
+ if not settings.staticdir:
+ raise exceptions.FileAccessDenied("File access disabled.")
+ s = os.path.expanduser(self.path)
+ s = os.path.normpath(
+ os.path.abspath(os.path.join(settings.staticdir, s))
+ )
+ uf = settings.unconstrained_file_access
+ if not uf and not s.startswith(settings.staticdir):
+ raise exceptions.FileAccessDenied(
+ "File access outside of configured directory"
+ )
+ if not os.path.isfile(s):
+ raise exceptions.FileAccessDenied("File not readable")
+ return generators.FileGenerator(s)
+
+ def spec(self):
+ return "<'%s'" % self.path.encode("string_escape")
+
+
+TokValue = pp.MatchFirst(
+ [
+ TokValueGenerate.expr(),
+ TokValueFile.expr(),
+ TokValueLiteral.expr()
+ ]
+)
+
+
+TokNakedValue = pp.MatchFirst(
+ [
+ TokValueGenerate.expr(),
+ TokValueFile.expr(),
+ TokValueLiteral.expr(),
+ TokValueNakedLiteral.expr(),
+ ]
+)
+
+
+TokOffset = pp.MatchFirst(
+ [
+ v_integer,
+ pp.Literal("r"),
+ pp.Literal("a")
+ ]
+)
+
+
+class _Component(Token):
+
+ """
+ A value component of the primary specification of an message.
+ Components produce byte values desribe the bytes of the message.
+ """
+
+ def values(self, settings): # pragma: no cover
+ """
+ A sequence of values, which can either be strings or generators.
+ """
+ pass
+
+ def string(self, settings=None):
+ """
+ A string representation of the object.
+ """
+ return "".join(i[:] for i in self.values(settings or {}))
+
+
+class KeyValue(_Component):
+
+ """
+ A key/value pair.
+ cls.preamble: leader
+ """
+
+ def __init__(self, key, value):
+ self.key, self.value = key, value
+
+ @classmethod
+ def expr(cls):
+ e = pp.Literal(cls.preamble).suppress()
+ e += TokValue
+ e += pp.Literal("=").suppress()
+ e += TokValue
+ return e.setParseAction(lambda x: cls(*x))
+
+ def spec(self):
+ return "%s%s=%s" % (self.preamble, self.key.spec(), self.value.spec())
+
+ def freeze(self, settings):
+ return self.__class__(
+ self.key.freeze(settings), self.value.freeze(settings)
+ )
+
+
+class CaselessLiteral(_Component):
+
+ """
+ A caseless token that can take only one value.
+ """
+
+ def __init__(self, value):
+ self.value = value
+
+ @classmethod
+ def expr(cls):
+ spec = pp.CaselessLiteral(cls.TOK)
+ spec = spec.setParseAction(lambda x: cls(*x))
+ return spec
+
+ def values(self, settings):
+ return self.TOK
+
+ def spec(self):
+ return self.TOK
+
+ def freeze(self, settings_):
+ return self
+
+
+class OptionsOrValue(_Component):
+
+ """
+ Can be any of a specified set of options, or a value specifier.
+ """
+ preamble = ""
+ options = []
+
+ def __init__(self, value):
+ # If it's a string, we were passed one of the options, so we lower-case
+ # it to be canonical. The user can specify a different case by using a
+ # string value literal.
+ self.option_used = False
+ if isinstance(value, basestring):
+ for i in self.options:
+ # Find the exact option value in a case-insensitive way
+ if i.lower() == value.lower():
+ self.option_used = True
+ value = TokValueLiteral(i)
+ break
+ self.value = value
+
+ @classmethod
+ def expr(cls):
+ parts = [pp.CaselessLiteral(i) for i in cls.options]
+ m = pp.MatchFirst(parts)
+ spec = m | TokValue.copy()
+ spec = spec.setParseAction(lambda x: cls(*x))
+ if cls.preamble:
+ spec = pp.Literal(cls.preamble).suppress() + spec
+ return spec
+
+ def values(self, settings):
+ return [
+ self.value.get_generator(settings)
+ ]
+
+ def spec(self):
+ s = self.value.spec()
+ if s[1:-1].lower() in self.options:
+ s = s[1:-1].lower()
+ return "%s%s" % (self.preamble, s)
+
+ def freeze(self, settings):
+ return self.__class__(self.value.freeze(settings))
+
+
+class Integer(_Component):
+ bounds = (None, None)
+ preamble = ""
+
+ def __init__(self, value):
+ v = int(value)
+ outofbounds = any([
+ self.bounds[0] is not None and v < self.bounds[0],
+ self.bounds[1] is not None and v > self.bounds[1]
+ ])
+ if outofbounds:
+ raise exceptions.ParseException(
+ "Integer value must be between %s and %s." % self.bounds,
+ 0, 0
+ )
+ self.value = str(value)
+
+ @classmethod
+ def expr(cls):
+ e = v_integer.copy()
+ if cls.preamble:
+ e = pp.Literal(cls.preamble).suppress() + e
+ return e.setParseAction(lambda x: cls(*x))
+
+ def values(self, settings):
+ return self.value
+
+ def spec(self):
+ return "%s%s" % (self.preamble, self.value)
+
+ def freeze(self, settings_):
+ return self
+
+
+class Value(_Component):
+
+ """
+ A value component lead by an optional preamble.
+ """
+ preamble = ""
+
+ def __init__(self, value):
+ self.value = value
+
+ @classmethod
+ def expr(cls):
+ e = (TokValue | TokNakedValue)
+ if cls.preamble:
+ e = pp.Literal(cls.preamble).suppress() + e
+ return e.setParseAction(lambda x: cls(*x))
+
+ def values(self, settings):
+ return [self.value.get_generator(settings)]
+
+ def spec(self):
+ return "%s%s" % (self.preamble, self.value.spec())
+
+ def freeze(self, settings):
+ return self.__class__(self.value.freeze(settings))
+
+
+class FixedLengthValue(Value):
+
+ """
+ A value component lead by an optional preamble.
+ """
+ preamble = ""
+ length = None
+
+ def __init__(self, value):
+ Value.__init__(self, value)
+ lenguess = None
+ try:
+ lenguess = len(value.get_generator(Settings()))
+ except exceptions.RenderError:
+ pass
+ # This check will fail if we know the length upfront
+ if lenguess is not None and lenguess != self.length:
+ raise exceptions.RenderError(
+ "Invalid value length: '%s' is %s bytes, should be %s." % (
+ self.spec(),
+ lenguess,
+ self.length
+ )
+ )
+
+ def values(self, settings):
+ ret = Value.values(self, settings)
+ l = sum(len(i) for i in ret)
+ # This check will fail if we don't know the length upfront - i.e. for
+ # file inputs
+ if l != self.length:
+ raise exceptions.RenderError(
+ "Invalid value length: '%s' is %s bytes, should be %s." % (
+ self.spec(),
+ l,
+ self.length
+ )
+ )
+ return ret
+
+
+class Boolean(_Component):
+
+ """
+ A boolean flag.
+ name = true
+ -name = false
+ """
+ name = ""
+
+ def __init__(self, value):
+ self.value = value
+
+ @classmethod
+ def expr(cls):
+ e = pp.Optional(pp.Literal("-"), default=True)
+ e += pp.Literal(cls.name).suppress()
+
+ def parse(s_, loc_, toks):
+ val = True
+ if toks[0] == "-":
+ val = False
+ return cls(val)
+
+ return e.setParseAction(parse)
+
+ def spec(self):
+ return "%s%s" % ("-" if not self.value else "", self.name)
+
+
+class IntField(_Component):
+
+ """
+ An integer field, where values can optionally specified by name.
+ """
+ names = {}
+ max = 16
+ preamble = ""
+
+ def __init__(self, value):
+ self.origvalue = value
+ self.value = self.names.get(value, value)
+ if self.value > self.max:
+ raise exceptions.ParseException(
+ "Value can't exceed %s" % self.max, 0, 0
+ )
+
+ @classmethod
+ def expr(cls):
+ parts = [pp.CaselessLiteral(i) for i in cls.names.keys()]
+ m = pp.MatchFirst(parts)
+ spec = m | v_integer.copy()
+ spec = spec.setParseAction(lambda x: cls(*x))
+ if cls.preamble:
+ spec = pp.Literal(cls.preamble).suppress() + spec
+ return spec
+
+ def values(self, settings):
+ return [str(self.value)]
+
+ def spec(self):
+ return "%s%s" % (self.preamble, self.origvalue)
+
+
+class NestedMessage(Token):
+
+ """
+ A nested message, as an escaped string with a preamble.
+ """
+ preamble = ""
+ nest_type = None
+
+ def __init__(self, value):
+ Token.__init__(self)
+ self.value = value
+ try:
+ self.parsed = self.nest_type(
+ self.nest_type.expr().parseString(
+ value.val,
+ parseAll=True
+ )
+ )
+ except pp.ParseException as v:
+ raise exceptions.ParseException(v.msg, v.line, v.col)
+
+ @classmethod
+ def expr(cls):
+ e = pp.Literal(cls.preamble).suppress()
+ e = e + TokValueLiteral.expr()
+ return e.setParseAction(lambda x: cls(*x))
+
+ def values(self, settings):
+ return [
+ self.value.get_generator(settings),
+ ]
+
+ def spec(self):
+ return "%s%s" % (self.preamble, self.value.spec())
+
+ def freeze(self, settings):
+ f = self.parsed.freeze(settings).spec()
+ return self.__class__(TokValueLiteral(f.encode("string_escape")))
diff --git a/pathod/libpathod/language/exceptions.py b/pathod/libpathod/language/exceptions.py
new file mode 100644
index 00000000..84ad3c02
--- /dev/null
+++ b/pathod/libpathod/language/exceptions.py
@@ -0,0 +1,22 @@
+
+class RenderError(Exception):
+ pass
+
+
+class FileAccessDenied(RenderError):
+ pass
+
+
+class ParseException(Exception):
+
+ def __init__(self, msg, s, col):
+ Exception.__init__(self)
+ self.msg = msg
+ self.s = s
+ self.col = col
+
+ def marked(self):
+ return "%s\n%s" % (self.s, " " * (self.col - 1) + "^")
+
+ def __str__(self):
+ return "%s at char %s" % (self.msg, self.col)
diff --git a/pathod/libpathod/language/generators.py b/pathod/libpathod/language/generators.py
new file mode 100644
index 00000000..a17e7052
--- /dev/null
+++ b/pathod/libpathod/language/generators.py
@@ -0,0 +1,86 @@
+import string
+import random
+import mmap
+
+DATATYPES = dict(
+ ascii_letters=string.ascii_letters,
+ ascii_lowercase=string.ascii_lowercase,
+ ascii_uppercase=string.ascii_uppercase,
+ digits=string.digits,
+ hexdigits=string.hexdigits,
+ octdigits=string.octdigits,
+ punctuation=string.punctuation,
+ whitespace=string.whitespace,
+ ascii=string.printable,
+ bytes="".join(chr(i) for i in range(256))
+)
+
+
+class TransformGenerator(object):
+
+ """
+ Perform a byte-by-byte transform another generator - that is, for each
+ input byte, the transformation must produce one output byte.
+
+ gen: A generator to wrap
+ transform: A function (offset, data) -> transformed
+ """
+
+ def __init__(self, gen, transform):
+ self.gen = gen
+ self.transform = transform
+
+ def __len__(self):
+ return len(self.gen)
+
+ def __getitem__(self, x):
+ d = self.gen.__getitem__(x)
+ return self.transform(x, d)
+
+ def __getslice__(self, a, b):
+ d = self.gen.__getslice__(a, b)
+ return self.transform(a, d)
+
+ def __repr__(self):
+ return "'transform(%s)'" % self.gen
+
+
+class RandomGenerator(object):
+
+ def __init__(self, dtype, length):
+ self.dtype = dtype
+ self.length = length
+
+ def __len__(self):
+ return self.length
+
+ def __getitem__(self, x):
+ return random.choice(DATATYPES[self.dtype])
+
+ def __getslice__(self, a, b):
+ b = min(b, self.length)
+ chars = DATATYPES[self.dtype]
+ return "".join(random.choice(chars) for x in range(a, b))
+
+ def __repr__(self):
+ return "%s random from %s" % (self.length, self.dtype)
+
+
+class FileGenerator(object):
+
+ def __init__(self, path):
+ self.path = path
+ self.fp = file(path, "rb")
+ self.map = mmap.mmap(self.fp.fileno(), 0, access=mmap.ACCESS_READ)
+
+ def __len__(self):
+ return len(self.map)
+
+ def __getitem__(self, x):
+ return self.map.__getitem__(x)
+
+ def __getslice__(self, a, b):
+ return self.map.__getslice__(a, b)
+
+ def __repr__(self):
+ return "<%s" % self.path
diff --git a/pathod/libpathod/language/http.py b/pathod/libpathod/language/http.py
new file mode 100644
index 00000000..a82f12fe
--- /dev/null
+++ b/pathod/libpathod/language/http.py
@@ -0,0 +1,381 @@
+
+import abc
+
+import pyparsing as pp
+
+import netlib.websockets
+from netlib.http import status_codes, user_agents
+from . import base, exceptions, actions, message
+
+# TODO: use netlib.semantics.protocol assemble method,
+# instead of duplicating the HTTP on-the-wire representation here.
+# see http2 language for an example
+
+class WS(base.CaselessLiteral):
+ TOK = "ws"
+
+
+class Raw(base.CaselessLiteral):
+ TOK = "r"
+
+
+class Path(base.Value):
+ pass
+
+
+class StatusCode(base.Integer):
+ pass
+
+
+class Reason(base.Value):
+ preamble = "m"
+
+
+class Body(base.Value):
+ preamble = "b"
+
+
+class Times(base.Integer):
+ preamble = "x"
+
+
+class Method(base.OptionsOrValue):
+ options = [
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ "OPTIONS",
+ "TRACE",
+ "CONNECT",
+ ]
+
+
+class _HeaderMixin(object):
+ unique_name = None
+
+ def format_header(self, key, value):
+ return [key, ": ", value, "\r\n"]
+
+ def values(self, settings):
+ return self.format_header(
+ self.key.get_generator(settings),
+ self.value.get_generator(settings),
+ )
+
+
+class Header(_HeaderMixin, base.KeyValue):
+ preamble = "h"
+
+
+class ShortcutContentType(_HeaderMixin, base.Value):
+ preamble = "c"
+ key = base.TokValueLiteral("Content-Type")
+
+
+class ShortcutLocation(_HeaderMixin, base.Value):
+ preamble = "l"
+ key = base.TokValueLiteral("Location")
+
+
+class ShortcutUserAgent(_HeaderMixin, base.OptionsOrValue):
+ preamble = "u"
+ options = [i[1] for i in user_agents.UASTRINGS]
+ key = base.TokValueLiteral("User-Agent")
+
+ def values(self, settings):
+ value = self.value.val
+ if self.option_used:
+ value = user_agents.get_by_shortcut(value.lower())[2]
+
+ return self.format_header(
+ self.key.get_generator(settings),
+ value
+ )
+
+
+def get_header(val, headers):
+ """
+ Header keys may be Values, so we have to "generate" them as we try the
+ match.
+ """
+ for h in headers:
+ k = h.key.get_generator({})
+ if len(k) == len(val) and k[:].lower() == val.lower():
+ return h
+ return None
+
+
+class _HTTPMessage(message.Message):
+ version = "HTTP/1.1"
+
+ @property
+ def actions(self):
+ return self.toks(actions._Action)
+
+ @property
+ def raw(self):
+ return bool(self.tok(Raw))
+
+ @property
+ def body(self):
+ return self.tok(Body)
+
+ @abc.abstractmethod
+ def preamble(self, settings): # pragma: no cover
+ pass
+
+ @property
+ def headers(self):
+ return self.toks(_HeaderMixin)
+
+ def values(self, settings):
+ vals = self.preamble(settings)
+ vals.append("\r\n")
+ for h in self.headers:
+ vals.extend(h.values(settings))
+ vals.append("\r\n")
+ if self.body:
+ vals.extend(self.body.values(settings))
+ return vals
+
+
+class Response(_HTTPMessage):
+ unique_name = None
+ comps = (
+ Header,
+ ShortcutContentType,
+ ShortcutLocation,
+ Raw,
+ Reason,
+ Body,
+
+ actions.PauseAt,
+ actions.DisconnectAt,
+ actions.InjectAt,
+ )
+ logattrs = ["status_code", "reason", "version", "body"]
+
+ @property
+ def ws(self):
+ return self.tok(WS)
+
+ @property
+ def status_code(self):
+ return self.tok(StatusCode)
+
+ @property
+ def reason(self):
+ return self.tok(Reason)
+
+ def preamble(self, settings):
+ l = [self.version, " "]
+ l.extend(self.status_code.values(settings))
+ status_code = int(self.status_code.value)
+ l.append(" ")
+ if self.reason:
+ l.extend(self.reason.values(settings))
+ else:
+ l.append(
+ status_codes.RESPONSES.get(
+ status_code,
+ "Unknown code"
+ )
+ )
+ return l
+
+ def resolve(self, settings, msg=None):
+ tokens = self.tokens[:]
+ if self.ws:
+ if not settings.websocket_key:
+ raise exceptions.RenderError(
+ "No websocket key - have we seen a client handshake?"
+ )
+ if not self.status_code:
+ tokens.insert(
+ 1,
+ StatusCode(101)
+ )
+ headers = netlib.websockets.WebsocketsProtocol.server_handshake_headers(
+ settings.websocket_key
+ )
+ for i in headers.fields:
+ if not get_header(i[0], self.headers):
+ tokens.append(
+ Header(
+ base.TokValueLiteral(i[0]),
+ base.TokValueLiteral(i[1]))
+ )
+ if not self.raw:
+ if not get_header("Content-Length", self.headers):
+ if not self.body:
+ length = 0
+ else:
+ length = sum(
+ len(i) for i in self.body.values(settings)
+ )
+ tokens.append(
+ Header(
+ base.TokValueLiteral("Content-Length"),
+ base.TokValueLiteral(str(length)),
+ )
+ )
+ intermediate = self.__class__(tokens)
+ return self.__class__(
+ [i.resolve(settings, intermediate) for i in tokens]
+ )
+
+ @classmethod
+ def expr(cls):
+ parts = [i.expr() for i in cls.comps]
+ atom = pp.MatchFirst(parts)
+ resp = pp.And(
+ [
+ pp.MatchFirst(
+ [
+ WS.expr() + pp.Optional(
+ base.Sep + StatusCode.expr()
+ ),
+ StatusCode.expr(),
+ ]
+ ),
+ pp.ZeroOrMore(base.Sep + atom)
+ ]
+ )
+ resp = resp.setParseAction(cls)
+ return resp
+
+ def spec(self):
+ return ":".join([i.spec() for i in self.tokens])
+
+
+class NestedResponse(base.NestedMessage):
+ preamble = "s"
+ nest_type = Response
+
+
+class Request(_HTTPMessage):
+ comps = (
+ Header,
+ ShortcutContentType,
+ ShortcutUserAgent,
+ Raw,
+ NestedResponse,
+ Body,
+ Times,
+
+ actions.PauseAt,
+ actions.DisconnectAt,
+ actions.InjectAt,
+ )
+ logattrs = ["method", "path", "body"]
+
+ @property
+ def ws(self):
+ return self.tok(WS)
+
+ @property
+ def method(self):
+ return self.tok(Method)
+
+ @property
+ def path(self):
+ return self.tok(Path)
+
+ @property
+ def times(self):
+ return self.tok(Times)
+
+ @property
+ def nested_response(self):
+ return self.tok(NestedResponse)
+
+ def preamble(self, settings):
+ v = self.method.values(settings)
+ v.append(" ")
+ v.extend(self.path.values(settings))
+ if self.nested_response:
+ v.append(self.nested_response.parsed.spec())
+ v.append(" ")
+ v.append(self.version)
+ return v
+
+ def resolve(self, settings, msg=None):
+ tokens = self.tokens[:]
+ if self.ws:
+ if not self.method:
+ tokens.insert(
+ 1,
+ Method("get")
+ )
+ for i in netlib.websockets.WebsocketsProtocol.client_handshake_headers().fields:
+ if not get_header(i[0], self.headers):
+ tokens.append(
+ Header(
+ base.TokValueLiteral(i[0]),
+ base.TokValueLiteral(i[1])
+ )
+ )
+ if not self.raw:
+ if not get_header("Content-Length", self.headers):
+ if self.body:
+ length = sum(
+ len(i) for i in self.body.values(settings)
+ )
+ tokens.append(
+ Header(
+ base.TokValueLiteral("Content-Length"),
+ base.TokValueLiteral(str(length)),
+ )
+ )
+ if settings.request_host:
+ if not get_header("Host", self.headers):
+ tokens.append(
+ Header(
+ base.TokValueLiteral("Host"),
+ base.TokValueLiteral(settings.request_host)
+ )
+ )
+ intermediate = self.__class__(tokens)
+ return self.__class__(
+ [i.resolve(settings, intermediate) for i in tokens]
+ )
+
+ @classmethod
+ def expr(cls):
+ parts = [i.expr() for i in cls.comps]
+ atom = pp.MatchFirst(parts)
+ resp = pp.And(
+ [
+ pp.MatchFirst(
+ [
+ WS.expr() + pp.Optional(
+ base.Sep + Method.expr()
+ ),
+ Method.expr(),
+ ]
+ ),
+ base.Sep,
+ Path.expr(),
+ pp.ZeroOrMore(base.Sep + atom)
+ ]
+ )
+ resp = resp.setParseAction(cls)
+ return resp
+
+ def spec(self):
+ return ":".join([i.spec() for i in self.tokens])
+
+
+def make_error_response(reason, body=None):
+ tokens = [
+ StatusCode("800"),
+ Header(
+ base.TokValueLiteral("Content-Type"),
+ base.TokValueLiteral("text/plain")
+ ),
+ Reason(base.TokValueLiteral(reason)),
+ Body(base.TokValueLiteral("pathod error: " + (body or reason))),
+ ]
+ return Response(tokens)
diff --git a/pathod/libpathod/language/http2.py b/pathod/libpathod/language/http2.py
new file mode 100644
index 00000000..d5e3ca31
--- /dev/null
+++ b/pathod/libpathod/language/http2.py
@@ -0,0 +1,299 @@
+import pyparsing as pp
+
+from netlib import http
+from netlib.http import user_agents, Headers
+from . import base, message
+
+"""
+ Normal HTTP requests:
+ <method>:<path>:<header>:<body>
+ e.g.:
+ GET:/
+ GET:/:h"foo"="bar"
+ POST:/:h"foo"="bar":b'content body payload'
+
+ Normal HTTP responses:
+ <code>:<header>:<body>
+ e.g.:
+ 200
+ 302:h"foo"="bar"
+ 404:h"foo"="bar":b'content body payload'
+
+ Individual HTTP/2 frames:
+ h2f:<payload_length>:<type>:<flags>:<stream_id>:<payload>
+ e.g.:
+ h2f:0:PING
+ h2f:42:HEADERS:END_HEADERS:0x1234567:foo=bar,host=example.com
+ h2f:42:DATA:END_STREAM,PADDED:0x1234567:'content body payload'
+"""
+
+def get_header(val, headers):
+ """
+ Header keys may be Values, so we have to "generate" them as we try the
+ match.
+ """
+ for h in headers:
+ k = h.key.get_generator({})
+ if len(k) == len(val) and k[:].lower() == val.lower():
+ return h
+ return None
+
+
+class _HeaderMixin(object):
+ unique_name = None
+
+ def values(self, settings):
+ return (
+ self.key.get_generator(settings),
+ self.value.get_generator(settings),
+ )
+
+class _HTTP2Message(message.Message):
+ @property
+ def actions(self):
+ return [] # self.toks(actions._Action)
+
+ @property
+ def headers(self):
+ headers = self.toks(_HeaderMixin)
+
+ if not self.raw:
+ if not get_header("content-length", headers):
+ if not self.body:
+ length = 0
+ else:
+ length = len(self.body.string())
+ headers.append(
+ Header(
+ base.TokValueLiteral("content-length"),
+ base.TokValueLiteral(str(length)),
+ )
+ )
+ return headers
+
+ @property
+ def raw(self):
+ return bool(self.tok(Raw))
+
+ @property
+ def body(self):
+ return self.tok(Body)
+
+ def resolve(self, settings):
+ return self
+
+
+class StatusCode(base.Integer):
+ pass
+
+
+class Method(base.OptionsOrValue):
+ options = [
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ ]
+
+
+class Path(base.Value):
+ pass
+
+
+class Header(_HeaderMixin, base.KeyValue):
+ preamble = "h"
+
+
+class ShortcutContentType(_HeaderMixin, base.Value):
+ preamble = "c"
+ key = base.TokValueLiteral("content-type")
+
+
+class ShortcutLocation(_HeaderMixin, base.Value):
+ preamble = "l"
+ key = base.TokValueLiteral("location")
+
+
+class ShortcutUserAgent(_HeaderMixin, base.OptionsOrValue):
+ preamble = "u"
+ options = [i[1] for i in user_agents.UASTRINGS]
+ key = base.TokValueLiteral("user-agent")
+
+ def values(self, settings):
+ value = self.value.val
+ if self.option_used:
+ value = user_agents.get_by_shortcut(value.lower())[2]
+
+ return (
+ self.key.get_generator(settings),
+ value
+ )
+
+
+class Raw(base.CaselessLiteral):
+ TOK = "r"
+
+
+class Body(base.Value):
+ preamble = "b"
+
+
+class Times(base.Integer):
+ preamble = "x"
+
+
+class Response(_HTTP2Message):
+ unique_name = None
+ comps = (
+ Header,
+ Body,
+ ShortcutContentType,
+ ShortcutLocation,
+ Raw,
+ )
+
+ def __init__(self, tokens):
+ super(Response, self).__init__(tokens)
+ self.rendered_values = None
+ self.stream_id = 2
+
+ @property
+ def status_code(self):
+ return self.tok(StatusCode)
+
+ @classmethod
+ def expr(cls):
+ parts = [i.expr() for i in cls.comps]
+ atom = pp.MatchFirst(parts)
+ resp = pp.And(
+ [
+ StatusCode.expr(),
+ pp.ZeroOrMore(base.Sep + atom)
+ ]
+ )
+ resp = resp.setParseAction(cls)
+ return resp
+
+ def values(self, settings):
+ if self.rendered_values:
+ return self.rendered_values
+ else:
+ headers = Headers([header.values(settings) for header in self.headers])
+
+ body = self.body
+ if body:
+ body = body.string()
+
+ resp = http.Response(
+ (2, 0),
+ self.status_code.string(),
+ '',
+ headers,
+ body,
+ )
+ resp.stream_id = self.stream_id
+
+ self.rendered_values = settings.protocol.assemble(resp)
+ return self.rendered_values
+
+ def spec(self):
+ return ":".join([i.spec() for i in self.tokens])
+
+
+class NestedResponse(base.NestedMessage):
+ preamble = "s"
+ nest_type = Response
+
+
+class Request(_HTTP2Message):
+ comps = (
+ Header,
+ ShortcutContentType,
+ ShortcutUserAgent,
+ Raw,
+ NestedResponse,
+ Body,
+ Times,
+ )
+ logattrs = ["method", "path"]
+
+ def __init__(self, tokens):
+ super(Request, self).__init__(tokens)
+ self.rendered_values = None
+ self.stream_id = 1
+
+ @property
+ def method(self):
+ return self.tok(Method)
+
+ @property
+ def path(self):
+ return self.tok(Path)
+
+ @property
+ def nested_response(self):
+ return self.tok(NestedResponse)
+
+ @property
+ def times(self):
+ return self.tok(Times)
+
+ @classmethod
+ def expr(cls):
+ parts = [i.expr() for i in cls.comps]
+ atom = pp.MatchFirst(parts)
+ resp = pp.And(
+ [
+ Method.expr(),
+ base.Sep,
+ Path.expr(),
+ pp.ZeroOrMore(base.Sep + atom)
+ ]
+ )
+ resp = resp.setParseAction(cls)
+ return resp
+
+ def values(self, settings):
+ if self.rendered_values:
+ return self.rendered_values
+ else:
+ path = self.path.string()
+ if self.nested_response:
+ path += self.nested_response.parsed.spec()
+
+ headers = Headers([header.values(settings) for header in self.headers])
+
+ body = self.body
+ if body:
+ body = body.string()
+
+ req = http.Request(
+ '',
+ self.method.string(),
+ '',
+ '',
+ '',
+ path,
+ (2, 0),
+ headers,
+ body,
+ )
+ req.stream_id = self.stream_id
+
+ self.rendered_values = settings.protocol.assemble(req)
+ return self.rendered_values
+
+ def spec(self):
+ return ":".join([i.spec() for i in self.tokens])
+
+def make_error_response(reason, body=None):
+ tokens = [
+ StatusCode("800"),
+ Body(base.TokValueLiteral("pathod error: " + (body or reason))),
+ ]
+ return Response(tokens)
+
+
+# class Frame(message.Message):
+# pass
diff --git a/pathod/libpathod/language/message.py b/pathod/libpathod/language/message.py
new file mode 100644
index 00000000..33124856
--- /dev/null
+++ b/pathod/libpathod/language/message.py
@@ -0,0 +1,96 @@
+import abc
+from . import actions, exceptions
+
+LOG_TRUNCATE = 1024
+
+
+class Message(object):
+ __metaclass__ = abc.ABCMeta
+ logattrs = []
+
+ def __init__(self, tokens):
+ track = set([])
+ for i in tokens:
+ if i.unique_name:
+ if i.unique_name in track:
+ raise exceptions.ParseException(
+ "Message has multiple %s clauses, "
+ "but should only have one." % i.unique_name,
+ 0, 0
+ )
+ else:
+ track.add(i.unique_name)
+ self.tokens = tokens
+
+ def strike_token(self, name):
+ toks = [i for i in self.tokens if i.unique_name != name]
+ return self.__class__(toks)
+
+ def toks(self, klass):
+ """
+ Fetch all tokens that are instances of klass
+ """
+ return [i for i in self.tokens if isinstance(i, klass)]
+
+ def tok(self, klass):
+ """
+ Fetch first token that is an instance of klass
+ """
+ l = self.toks(klass)
+ if l:
+ return l[0]
+
+ def length(self, settings):
+ """
+ Calculate the length of the base message without any applied
+ actions.
+ """
+ return sum(len(x) for x in self.values(settings))
+
+ def preview_safe(self):
+ """
+ Return a copy of this message that issafe for previews.
+ """
+ tokens = [i for i in self.tokens if not isinstance(i, actions.PauseAt)]
+ return self.__class__(tokens)
+
+ def maximum_length(self, settings):
+ """
+ Calculate the maximum length of the base message with all applied
+ actions.
+ """
+ l = self.length(settings)
+ for i in self.actions:
+ if isinstance(i, actions.InjectAt):
+ l += len(i.value.get_generator(settings))
+ return l
+
+ @classmethod
+ def expr(cls): # pragma: no cover
+ pass
+
+ def log(self, settings):
+ """
+ A dictionary that should be logged if this message is served.
+ """
+ ret = {}
+ for i in self.logattrs:
+ v = getattr(self, i)
+ # Careful not to log any VALUE specs without sanitizing them first.
+ # We truncate at 1k.
+ if hasattr(v, "values"):
+ v = [x[:LOG_TRUNCATE] for x in v.values(settings)]
+ v = "".join(v).encode("string_escape")
+ elif hasattr(v, "__len__"):
+ v = v[:LOG_TRUNCATE]
+ v = v.encode("string_escape")
+ ret[i] = v
+ ret["spec"] = self.spec()
+ return ret
+
+ def freeze(self, settings):
+ r = self.resolve(settings)
+ return self.__class__([i.freeze(settings) for i in r.tokens])
+
+ def __repr__(self):
+ return self.spec()
diff --git a/pathod/libpathod/language/websockets.py b/pathod/libpathod/language/websockets.py
new file mode 100644
index 00000000..ea7c870e
--- /dev/null
+++ b/pathod/libpathod/language/websockets.py
@@ -0,0 +1,241 @@
+import os
+import netlib.websockets
+import pyparsing as pp
+from . import base, generators, actions, message
+
+NESTED_LEADER = "pathod!"
+
+
+class WF(base.CaselessLiteral):
+ TOK = "wf"
+
+
+class OpCode(base.IntField):
+ names = {
+ "continue": netlib.websockets.OPCODE.CONTINUE,
+ "text": netlib.websockets.OPCODE.TEXT,
+ "binary": netlib.websockets.OPCODE.BINARY,
+ "close": netlib.websockets.OPCODE.CLOSE,
+ "ping": netlib.websockets.OPCODE.PING,
+ "pong": netlib.websockets.OPCODE.PONG,
+ }
+ max = 15
+ preamble = "c"
+
+
+class Body(base.Value):
+ preamble = "b"
+
+
+class RawBody(base.Value):
+ unique_name = "body"
+ preamble = "r"
+
+
+class Fin(base.Boolean):
+ name = "fin"
+
+
+class RSV1(base.Boolean):
+ name = "rsv1"
+
+
+class RSV2(base.Boolean):
+ name = "rsv2"
+
+
+class RSV3(base.Boolean):
+ name = "rsv3"
+
+
+class Mask(base.Boolean):
+ name = "mask"
+
+
+class Key(base.FixedLengthValue):
+ preamble = "k"
+ length = 4
+
+
+class KeyNone(base.CaselessLiteral):
+ unique_name = "key"
+ TOK = "knone"
+
+
+class Length(base.Integer):
+ bounds = (0, 1 << 64)
+ preamble = "l"
+
+
+class Times(base.Integer):
+ preamble = "x"
+
+
+COMPONENTS = (
+ OpCode,
+ Length,
+ # Bit flags
+ Fin,
+ RSV1,
+ RSV2,
+ RSV3,
+ Mask,
+ actions.PauseAt,
+ actions.DisconnectAt,
+ actions.InjectAt,
+ KeyNone,
+ Key,
+ Times,
+
+ Body,
+ RawBody,
+)
+
+
+class WebsocketFrame(message.Message):
+ components = COMPONENTS
+ logattrs = ["body"]
+ # Used for nested frames
+ unique_name = "body"
+
+ @property
+ def actions(self):
+ return self.toks(actions._Action)
+
+ @property
+ def body(self):
+ return self.tok(Body)
+
+ @property
+ def rawbody(self):
+ return self.tok(RawBody)
+
+ @property
+ def opcode(self):
+ return self.tok(OpCode)
+
+ @property
+ def fin(self):
+ return self.tok(Fin)
+
+ @property
+ def rsv1(self):
+ return self.tok(RSV1)
+
+ @property
+ def rsv2(self):
+ return self.tok(RSV2)
+
+ @property
+ def rsv3(self):
+ return self.tok(RSV3)
+
+ @property
+ def mask(self):
+ return self.tok(Mask)
+
+ @property
+ def key(self):
+ return self.tok(Key)
+
+ @property
+ def knone(self):
+ return self.tok(KeyNone)
+
+ @property
+ def times(self):
+ return self.tok(Times)
+
+ @property
+ def toklength(self):
+ return self.tok(Length)
+
+ @classmethod
+ def expr(cls):
+ parts = [i.expr() for i in cls.components]
+ atom = pp.MatchFirst(parts)
+ resp = pp.And(
+ [
+ WF.expr(),
+ base.Sep,
+ pp.ZeroOrMore(base.Sep + atom)
+ ]
+ )
+ resp = resp.setParseAction(cls)
+ return resp
+
+ @property
+ def nested_frame(self):
+ return self.tok(NestedFrame)
+
+ def resolve(self, settings, msg=None):
+ tokens = self.tokens[:]
+ if not self.mask and settings.is_client:
+ tokens.append(
+ Mask(True)
+ )
+ if not self.knone and self.mask and self.mask.value and not self.key:
+ tokens.append(
+ Key(base.TokValueLiteral(os.urandom(4)))
+ )
+ return self.__class__(
+ [i.resolve(settings, self) for i in tokens]
+ )
+
+ def values(self, settings):
+ if self.body:
+ bodygen = self.body.value.get_generator(settings)
+ length = len(self.body.value.get_generator(settings))
+ elif self.rawbody:
+ bodygen = self.rawbody.value.get_generator(settings)
+ length = len(self.rawbody.value.get_generator(settings))
+ elif self.nested_frame:
+ bodygen = NESTED_LEADER + self.nested_frame.parsed.spec()
+ length = len(bodygen)
+ else:
+ bodygen = None
+ length = 0
+ if self.toklength:
+ length = int(self.toklength.value)
+ frameparts = dict(
+ payload_length=length
+ )
+ if self.mask and self.mask.value:
+ frameparts["mask"] = True
+ if self.knone:
+ frameparts["masking_key"] = None
+ elif self.key:
+ key = self.key.values(settings)[0][:]
+ frameparts["masking_key"] = key
+ for i in ["opcode", "fin", "rsv1", "rsv2", "rsv3", "mask"]:
+ v = getattr(self, i, None)
+ if v is not None:
+ frameparts[i] = v.value
+ frame = netlib.websockets.FrameHeader(**frameparts)
+ vals = [bytes(frame)]
+ if bodygen:
+ if frame.masking_key and not self.rawbody:
+ masker = netlib.websockets.Masker(frame.masking_key)
+ vals.append(
+ generators.TransformGenerator(
+ bodygen,
+ masker.mask
+ )
+ )
+ else:
+ vals.append(bodygen)
+ return vals
+
+ def spec(self):
+ return ":".join([i.spec() for i in self.tokens])
+
+
+class NestedFrame(base.NestedMessage):
+ preamble = "f"
+ nest_type = WebsocketFrame
+
+
+class WebsocketClientFrame(WebsocketFrame):
+ components = COMPONENTS + (
+ NestedFrame,
+ )
diff --git a/pathod/libpathod/language/writer.py b/pathod/libpathod/language/writer.py
new file mode 100644
index 00000000..1a27e1ef
--- /dev/null
+++ b/pathod/libpathod/language/writer.py
@@ -0,0 +1,67 @@
+import time
+from netlib.exceptions import TcpDisconnect
+import netlib.tcp
+
+BLOCKSIZE = 1024
+# It's not clear what the upper limit for time.sleep is. It's lower than the
+# maximum int or float. 1 year should do.
+FOREVER = 60 * 60 * 24 * 365
+
+
+def send_chunk(fp, val, blocksize, start, end):
+ """
+ (start, end): Inclusive lower bound, exclusive upper bound.
+ """
+ for i in range(start, end, blocksize):
+ fp.write(
+ val[i:min(i + blocksize, end)]
+ )
+ return end - start
+
+
+def write_values(fp, vals, actions, sofar=0, blocksize=BLOCKSIZE):
+ """
+ vals: A list of values, which may be strings or Value objects.
+
+ actions: A list of (offset, action, arg) tuples. Action may be "pause"
+ or "disconnect".
+
+ Both vals and actions are in reverse order, with the first items last.
+
+ Return True if connection should disconnect.
+ """
+ sofar = 0
+ try:
+ while vals:
+ v = vals.pop()
+ offset = 0
+ while actions and actions[-1][0] < (sofar + len(v)):
+ a = actions.pop()
+ offset += send_chunk(
+ fp,
+ v,
+ blocksize,
+ offset,
+ a[0] - sofar - offset
+ )
+ if a[1] == "pause":
+ time.sleep(
+ FOREVER if a[2] == "f" else a[2]
+ )
+ elif a[1] == "disconnect":
+ return True
+ elif a[1] == "inject":
+ send_chunk(fp, a[2], blocksize, 0, len(a[2]))
+ send_chunk(fp, v, blocksize, offset, len(v))
+ sofar += len(v)
+ # Remainders
+ while actions:
+ a = actions.pop()
+ if a[1] == "pause":
+ time.sleep(a[2])
+ elif a[1] == "disconnect":
+ return True
+ elif a[1] == "inject":
+ send_chunk(fp, a[2], blocksize, 0, len(a[2]))
+ except TcpDisconnect: # pragma: no cover
+ return True
diff --git a/pathod/libpathod/log.py b/pathod/libpathod/log.py
new file mode 100644
index 00000000..f203542f
--- /dev/null
+++ b/pathod/libpathod/log.py
@@ -0,0 +1,83 @@
+import datetime
+
+import netlib.utils
+import netlib.tcp
+import netlib.http
+
+TIMEFMT = '%d-%m-%y %H:%M:%S'
+
+
+def write_raw(fp, lines):
+ if fp:
+ fp.write(
+ "%s: " % datetime.datetime.now().strftime(TIMEFMT)
+ )
+ for i in lines:
+ fp.write(i)
+ fp.write("\n")
+ fp.flush()
+
+
+class LogCtx(object):
+
+ def __init__(self, fp, hex, rfile, wfile):
+ self.lines = []
+ self.fp = fp
+ self.suppressed = False
+ self.hex = hex
+ self.rfile, self.wfile = rfile, wfile
+
+ def __enter__(self):
+ if self.wfile:
+ self.wfile.start_log()
+ if self.rfile:
+ self.rfile.start_log()
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ wlog = self.wfile.get_log() if self.wfile else None
+ rlog = self.rfile.get_log() if self.rfile else None
+ if self.suppressed or not self.fp:
+ return
+ if wlog:
+ self("Bytes written:")
+ self.dump(wlog, self.hex)
+ if rlog:
+ self("Bytes read:")
+ self.dump(rlog, self.hex)
+ if self.lines:
+ write_raw(
+ self.fp,
+ [
+ "\n".join(self.lines),
+ ]
+ )
+ if exc_value:
+ raise exc_type, exc_value, traceback
+
+ def suppress(self):
+ self.suppressed = True
+
+ def dump(self, data, hexdump):
+ if hexdump:
+ for line in netlib.utils.hexdump(data):
+ self("\t%s %s %s" % line)
+ else:
+ for i in netlib.utils.clean_bin(data).split("\n"):
+ self("\t%s" % i)
+
+ def __call__(self, line):
+ self.lines.append(line)
+
+
+class ConnectionLogger:
+ def __init__(self, fp, hex, rfile, wfile):
+ self.fp = fp
+ self.hex = hex
+ self.rfile, self.wfile = rfile, wfile
+
+ def ctx(self):
+ return LogCtx(self.fp, self.hex, self.rfile, self.wfile)
+
+ def write(self, lines):
+ write_raw(self.fp, lines)
diff --git a/pathod/libpathod/pathoc.py b/pathod/libpathod/pathoc.py
new file mode 100644
index 00000000..55c2a6e0
--- /dev/null
+++ b/pathod/libpathod/pathoc.py
@@ -0,0 +1,534 @@
+import contextlib
+import sys
+import os
+import itertools
+import hashlib
+import Queue
+import random
+import select
+import time
+import threading
+
+import OpenSSL.crypto
+import six
+
+from netlib import tcp, http, certutils, websockets, socks
+from netlib.exceptions import HttpException, TcpDisconnect, TcpTimeout, TlsException, TcpException, \
+ NetlibException
+from netlib.http import http1, http2
+
+import language.http
+import language.websockets
+from . import utils, log
+
+import logging
+from netlib.tutils import treq
+
+logging.getLogger("hpack").setLevel(logging.WARNING)
+
+
+class PathocError(Exception):
+ pass
+
+
+class SSLInfo(object):
+
+ def __init__(self, certchain, cipher, alp):
+ self.certchain, self.cipher, self.alp = certchain, cipher, alp
+
+ def __str__(self):
+ parts = [
+ "Application Layer Protocol: %s" % self.alp,
+ "Cipher: %s, %s bit, %s" % self.cipher,
+ "SSL certificate chain:"
+ ]
+ for i in self.certchain:
+ parts.append("\tSubject: ")
+ for cn in i.get_subject().get_components():
+ parts.append("\t\t%s=%s" % cn)
+ parts.append("\tIssuer: ")
+ for cn in i.get_issuer().get_components():
+ parts.append("\t\t%s=%s" % cn)
+ parts.extend(
+ [
+ "\tVersion: %s" % i.get_version(),
+ "\tValidity: %s - %s" % (
+ i.get_notBefore(), i.get_notAfter()
+ ),
+ "\tSerial: %s" % i.get_serial_number(),
+ "\tAlgorithm: %s" % i.get_signature_algorithm()
+ ]
+ )
+ pk = i.get_pubkey()
+ types = {
+ OpenSSL.crypto.TYPE_RSA: "RSA",
+ OpenSSL.crypto.TYPE_DSA: "DSA"
+ }
+ t = types.get(pk.type(), "Uknown")
+ parts.append("\tPubkey: %s bit %s" % (pk.bits(), t))
+ s = certutils.SSLCert(i)
+ if s.altnames:
+ parts.append("\tSANs: %s" % " ".join(s.altnames))
+ return "\n".join(parts)
+
+
+
+class WebsocketFrameReader(threading.Thread):
+
+ def __init__(
+ self,
+ rfile,
+ logfp,
+ showresp,
+ hexdump,
+ ws_read_limit,
+ timeout
+ ):
+ threading.Thread.__init__(self)
+ self.timeout = timeout
+ self.ws_read_limit = ws_read_limit
+ self.logfp = logfp
+ self.showresp = showresp
+ self.hexdump = hexdump
+ self.rfile = rfile
+ self.terminate = Queue.Queue()
+ self.frames_queue = Queue.Queue()
+ self.logger = log.ConnectionLogger(
+ self.logfp,
+ self.hexdump,
+ rfile if showresp else None,
+ None
+ )
+
+ @contextlib.contextmanager
+ def terminator(self):
+ yield
+ self.frames_queue.put(None)
+
+ def run(self):
+ starttime = time.time()
+ with self.terminator():
+ while True:
+ if self.ws_read_limit == 0:
+ return
+ r, _, _ = select.select([self.rfile], [], [], 0.05)
+ delta = time.time() - starttime
+ if not r and self.timeout and delta > self.timeout:
+ return
+ try:
+ self.terminate.get_nowait()
+ return
+ except Queue.Empty:
+ pass
+ for rfile in r:
+ with self.logger.ctx() as log:
+ try:
+ frm = websockets.Frame.from_file(self.rfile)
+ except TcpDisconnect:
+ return
+ self.frames_queue.put(frm)
+ log("<< %s" % frm.header.human_readable())
+ if self.ws_read_limit is not None:
+ self.ws_read_limit -= 1
+ starttime = time.time()
+
+
+class Pathoc(tcp.TCPClient):
+
+ def __init__(
+ self,
+ address,
+
+ # SSL
+ ssl=None,
+ sni=None,
+ ssl_version=tcp.SSL_DEFAULT_METHOD,
+ ssl_options=tcp.SSL_DEFAULT_OPTIONS,
+ clientcert=None,
+ ciphers=None,
+
+ # HTTP/2
+ use_http2=False,
+ http2_skip_connection_preface=False,
+ http2_framedump=False,
+
+ # Websockets
+ ws_read_limit=None,
+
+ # Network
+ timeout=None,
+
+ # Output control
+ showreq=False,
+ showresp=False,
+ explain=False,
+ hexdump=False,
+ ignorecodes=(),
+ ignoretimeout=False,
+ showsummary=False,
+ fp=sys.stdout
+ ):
+ """
+ spec: A request specification
+ showreq: Print requests
+ showresp: Print responses
+ explain: Print request explanation
+ showssl: Print info on SSL connection
+ hexdump: When printing requests or responses, use hex dump output
+ showsummary: Show a summary of requests
+ ignorecodes: Sequence of return codes to ignore
+ """
+ tcp.TCPClient.__init__(self, address)
+
+ self.ssl, self.sni = ssl, sni
+ self.clientcert = clientcert
+ self.ssl_version = ssl_version
+ self.ssl_options = ssl_options
+ self.ciphers = ciphers
+ self.sslinfo = None
+
+ self.use_http2 = use_http2
+ self.http2_skip_connection_preface = http2_skip_connection_preface
+ self.http2_framedump = http2_framedump
+
+ self.ws_read_limit = ws_read_limit
+
+ self.timeout = timeout
+
+ self.showreq = showreq
+ self.showresp = showresp
+ self.explain = explain
+ self.hexdump = hexdump
+ self.ignorecodes = ignorecodes
+ self.ignoretimeout = ignoretimeout
+ self.showsummary = showsummary
+ self.fp = fp
+
+ self.ws_framereader = None
+
+ if self.use_http2:
+ if not OpenSSL._util.lib.Cryptography_HAS_ALPN: # pragma: nocover
+ log.write_raw(
+ self.fp,
+ "HTTP/2 requires ALPN support. "
+ "Please use OpenSSL >= 1.0.2. "
+ "Pathoc might not be working as expected without ALPN."
+ )
+ self.protocol = http2.HTTP2Protocol(self, dump_frames=self.http2_framedump)
+ else:
+ self.protocol = http1
+
+ self.settings = language.Settings(
+ is_client=True,
+ staticdir=os.getcwd(),
+ unconstrained_file_access=True,
+ request_host=self.address.host,
+ protocol=self.protocol,
+ )
+
+ def http_connect(self, connect_to):
+ self.wfile.write(
+ 'CONNECT %s:%s HTTP/1.1\r\n' % tuple(connect_to) +
+ '\r\n'
+ )
+ self.wfile.flush()
+ try:
+ resp = self.protocol.read_response(self.rfile, treq(method="CONNECT"))
+ if resp.status_code != 200:
+ raise HttpException("Unexpected status code: %s" % resp.status_code)
+ except HttpException as e:
+ six.reraise(PathocError, PathocError(
+ "Proxy CONNECT failed: %s" % repr(e)
+ ))
+
+ def socks_connect(self, connect_to):
+ try:
+ client_greet = socks.ClientGreeting(socks.VERSION.SOCKS5, [socks.METHOD.NO_AUTHENTICATION_REQUIRED])
+ client_greet.to_file(self.wfile)
+ self.wfile.flush()
+
+ server_greet = socks.ServerGreeting.from_file(self.rfile)
+ server_greet.assert_socks5()
+ if server_greet.method != socks.METHOD.NO_AUTHENTICATION_REQUIRED:
+ raise socks.SocksError(
+ socks.METHOD.NO_ACCEPTABLE_METHODS,
+ "pathoc only supports SOCKS without authentication"
+ )
+
+ connect_request = socks.Message(
+ socks.VERSION.SOCKS5,
+ socks.CMD.CONNECT,
+ socks.ATYP.DOMAINNAME,
+ tcp.Address.wrap(connect_to)
+ )
+ connect_request.to_file(self.wfile)
+ self.wfile.flush()
+
+ connect_reply = socks.Message.from_file(self.rfile)
+ connect_reply.assert_socks5()
+ if connect_reply.msg != socks.REP.SUCCEEDED:
+ raise socks.SocksError(
+ connect_reply.msg,
+ "SOCKS server error"
+ )
+ except (socks.SocksError, TcpDisconnect) as e:
+ raise PathocError(str(e))
+
+ def connect(self, connect_to=None, showssl=False, fp=sys.stdout):
+ """
+ connect_to: A (host, port) tuple, which will be connected to with
+ an HTTP CONNECT request.
+ """
+ if self.use_http2 and not self.ssl:
+ raise NotImplementedError("HTTP2 without SSL is not supported.")
+
+ tcp.TCPClient.connect(self)
+
+ if connect_to:
+ self.http_connect(connect_to)
+
+ self.sslinfo = None
+ if self.ssl:
+ try:
+ alpn_protos = [b'http/1.1']
+ if self.use_http2:
+ alpn_protos.append(b'h2')
+
+ self.convert_to_ssl(
+ sni=self.sni,
+ cert=self.clientcert,
+ method=self.ssl_version,
+ options=self.ssl_options,
+ cipher_list=self.ciphers,
+ alpn_protos=alpn_protos
+ )
+ except TlsException as v:
+ raise PathocError(str(v))
+
+ self.sslinfo = SSLInfo(
+ self.connection.get_peer_cert_chain(),
+ self.get_current_cipher(),
+ self.get_alpn_proto_negotiated()
+ )
+ if showssl:
+ print >> fp, str(self.sslinfo)
+
+ if self.use_http2:
+ self.protocol.check_alpn()
+ if not self.http2_skip_connection_preface:
+ self.protocol.perform_client_connection_preface()
+
+ if self.timeout:
+ self.settimeout(self.timeout)
+
+ def stop(self):
+ if self.ws_framereader:
+ self.ws_framereader.terminate.put(None)
+
+ def wait(self, timeout=0.01, finish=True):
+ """
+ A generator that yields frames until Pathoc terminates.
+
+ timeout: If specified None may be yielded instead if timeout is
+ reached. If timeout is None, wait forever. If timeout is 0, return
+ immedately if nothing is on the queue.
+
+ finish: If true, consume messages until the reader shuts down.
+ Otherwise, return None on timeout.
+ """
+ if self.ws_framereader:
+ while True:
+ try:
+ frm = self.ws_framereader.frames_queue.get(
+ timeout=timeout,
+ block=True if timeout != 0 else False
+ )
+ except Queue.Empty:
+ if finish:
+ continue
+ else:
+ return
+ if frm is None:
+ self.ws_framereader.join()
+ return
+ yield frm
+
+ def websocket_send_frame(self, r):
+ """
+ Sends a single websocket frame.
+ """
+ logger = log.ConnectionLogger(
+ self.fp,
+ self.hexdump,
+ None,
+ self.wfile if self.showreq else None,
+ )
+ with logger.ctx() as lg:
+ lg(">> %s" % r)
+ language.serve(r, self.wfile, self.settings)
+ self.wfile.flush()
+
+ def websocket_start(self, r):
+ """
+ Performs an HTTP request, and attempts to drop into websocket
+ connection.
+ """
+ resp = self.http(r)
+ if resp.status_code == 101:
+ self.ws_framereader = WebsocketFrameReader(
+ self.rfile,
+ self.fp,
+ self.showresp,
+ self.hexdump,
+ self.ws_read_limit,
+ self.timeout
+ )
+ self.ws_framereader.start()
+ return resp
+
+ def http(self, r):
+ """
+ Performs a single request.
+
+ r: A language.http.Request object, or a string representing one
+ request.
+
+ Returns Response if we have a non-ignored response.
+
+ May raise a NetlibException
+ """
+ logger = log.ConnectionLogger(
+ self.fp,
+ self.hexdump,
+ self.rfile if self.showresp else None,
+ self.wfile if self.showreq else None,
+ )
+ with logger.ctx() as lg:
+ lg(">> %s" % r)
+ resp, req = None, None
+ try:
+ req = language.serve(r, self.wfile, self.settings)
+ self.wfile.flush()
+
+ resp = self.protocol.read_response(self.rfile, treq(method=req["method"].encode()))
+ resp.sslinfo = self.sslinfo
+ except HttpException as v:
+ lg("Invalid server response: %s" % v)
+ raise
+ except TcpTimeout:
+ if self.ignoretimeout:
+ lg("Timeout (ignored)")
+ return None
+ lg("Timeout")
+ raise
+ finally:
+ if resp:
+ lg("<< %s %s: %s bytes" % (
+ resp.status_code, utils.xrepr(resp.msg), len(resp.content)
+ ))
+ if resp.status_code in self.ignorecodes:
+ lg.suppress()
+ return resp
+
+ def request(self, r):
+ """
+ Performs a single request.
+
+ r: A language.message.Messsage object, or a string representing
+ one.
+
+ Returns Response if we have a non-ignored response.
+
+ May raise a NetlibException
+ """
+ if isinstance(r, basestring):
+ r = language.parse_pathoc(r, self.use_http2).next()
+
+ if isinstance(r, language.http.Request):
+ if r.ws:
+ return self.websocket_start(r)
+ else:
+ return self.http(r)
+ elif isinstance(r, language.websockets.WebsocketFrame):
+ self.websocket_send_frame(r)
+ elif isinstance(r, language.http2.Request):
+ return self.http(r)
+ # elif isinstance(r, language.http2.Frame):
+ # TODO: do something
+
+
+def main(args): # pragma: nocover
+ memo = set([])
+ trycount = 0
+ p = None
+ try:
+ cnt = 0
+ while True:
+ if cnt == args.repeat and args.repeat != 0:
+ break
+ if args.wait and cnt != 0:
+ time.sleep(args.wait)
+
+ cnt += 1
+ playlist = itertools.chain(*args.requests)
+ if args.random:
+ playlist = random.choice(args.requests)
+ p = Pathoc(
+ (args.host, args.port),
+ ssl=args.ssl,
+ sni=args.sni,
+ ssl_version=args.ssl_version,
+ ssl_options=args.ssl_options,
+ clientcert=args.clientcert,
+ ciphers=args.ciphers,
+ use_http2=args.use_http2,
+ http2_skip_connection_preface=args.http2_skip_connection_preface,
+ http2_framedump=args.http2_framedump,
+ showreq=args.showreq,
+ showresp=args.showresp,
+ explain=args.explain,
+ hexdump=args.hexdump,
+ ignorecodes=args.ignorecodes,
+ timeout=args.timeout,
+ ignoretimeout=args.ignoretimeout,
+ showsummary=True
+ )
+ trycount = 0
+ try:
+ p.connect(args.connect_to, args.showssl)
+ except TcpException as v:
+ print >> sys.stderr, str(v)
+ continue
+ except PathocError as v:
+ print >> sys.stderr, str(v)
+ sys.exit(1)
+ for spec in playlist:
+ if args.explain or args.memo:
+ spec = spec.freeze(p.settings)
+ if args.memo:
+ h = hashlib.sha256(spec.spec()).digest()
+ if h not in memo:
+ trycount = 0
+ memo.add(h)
+ else:
+ trycount += 1
+ if trycount > args.memolimit:
+ print >> sys.stderr, "Memo limit exceeded..."
+ return
+ else:
+ continue
+ try:
+ ret = p.request(spec)
+ if ret and args.oneshot:
+ return
+ # We consume the queue when we can, so it doesn't build up.
+ for i_ in p.wait(timeout=0, finish=False):
+ pass
+ except NetlibException:
+ break
+ for i_ in p.wait(timeout=0.01, finish=True):
+ pass
+ except KeyboardInterrupt:
+ pass
+ if p:
+ p.stop()
diff --git a/pathod/libpathod/pathoc_cmdline.py b/pathod/libpathod/pathoc_cmdline.py
new file mode 100644
index 00000000..bf827a9a
--- /dev/null
+++ b/pathod/libpathod/pathoc_cmdline.py
@@ -0,0 +1,226 @@
+import sys
+import argparse
+import os
+import os.path
+
+from netlib import tcp
+from netlib.http import user_agents
+from . import pathoc, version, language
+
+
+def args_pathoc(argv, stdout=sys.stdout, stderr=sys.stderr):
+ preparser = argparse.ArgumentParser(add_help=False)
+ preparser.add_argument(
+ "--show-uas", dest="showua", action="store_true", default=False,
+ help="Print user agent shortcuts and exit."
+ )
+ pa = preparser.parse_known_args(argv)[0]
+ if pa.showua:
+ print >> stdout, "User agent strings:"
+ for i in user_agents.UASTRINGS:
+ print >> stdout, " ", i[1], i[0]
+ sys.exit(0)
+
+ parser = argparse.ArgumentParser(
+ description='A perverse HTTP client.', parents=[preparser]
+ )
+ parser.add_argument(
+ '--version',
+ action='version',
+ version="pathoc " + version.VERSION
+ )
+ parser.add_argument(
+ "-c", dest="connect_to", type=str, default=False,
+ metavar="HOST:PORT",
+ help="Issue an HTTP CONNECT to connect to the specified host."
+ )
+ parser.add_argument(
+ "--memo-limit", dest='memolimit', default=5000, type=int, metavar="N",
+ help='Stop if we do not find a valid request after N attempts.'
+ )
+ parser.add_argument(
+ "-m", dest='memo', action="store_true", default=False,
+ help="""
+ Remember specs, and never play the same one twice. Note that this
+ means requests have to be rendered in memory, which means that
+ large generated data can cause issues.
+ """
+ )
+ parser.add_argument(
+ "-n", dest='repeat', default=1, type=int, metavar="N",
+ help='Repeat N times. If 0 repeat for ever.'
+ )
+ parser.add_argument(
+ "-w", dest='wait', default=0, type=float, metavar="N",
+ help='Wait N seconds between each request.'
+ )
+ parser.add_argument(
+ "-r", dest="random", action="store_true", default=False,
+ help="""
+ Select a random request from those specified. If this is not specified,
+ requests are all played in sequence.
+ """
+ )
+ parser.add_argument(
+ "-t", dest="timeout", type=int, default=None,
+ help="Connection timeout"
+ )
+ parser.add_argument(
+ "--http2", dest="use_http2", action="store_true", default=False,
+ help='Perform all requests over a single HTTP/2 connection.'
+ )
+ parser.add_argument(
+ "--http2-skip-connection-preface",
+ dest="http2_skip_connection_preface",
+ action="store_true",
+ default=False,
+ help='Skips the HTTP/2 connection preface before sending requests.')
+
+ parser.add_argument(
+ 'host', type=str,
+ metavar="host[:port]",
+ help='Host and port to connect to'
+ )
+ parser.add_argument(
+ 'requests', type=str, nargs="+",
+ help="""
+ Request specification, or path to a file containing request
+ specifcations
+ """
+ )
+
+ group = parser.add_argument_group(
+ 'SSL',
+ )
+ group.add_argument(
+ "-s", dest="ssl", action="store_true", default=False,
+ help="Connect with SSL"
+ )
+ group.add_argument(
+ "-C", dest="clientcert", type=str, default=False,
+ help="Path to a file containing client certificate and private key"
+ )
+ group.add_argument(
+ "-i", dest="sni", type=str, default=False,
+ help="SSL Server Name Indication"
+ )
+ group.add_argument(
+ "--ciphers", dest="ciphers", type=str, default=False,
+ help="SSL cipher specification"
+ )
+ group.add_argument(
+ "--ssl-version", dest="ssl_version", type=str, default="secure",
+ choices=tcp.sslversion_choices.keys(),
+ help="Set supported SSL/TLS versions. "
+ "SSLv2, SSLv3 and 'all' are INSECURE. Defaults to secure, which is TLS1.0+."
+ )
+
+ group = parser.add_argument_group(
+ 'Controlling Output',
+ """
+ Some of these options expand generated values for logging - if
+ you're generating large data, use them with caution.
+ """
+ )
+ group.add_argument(
+ "-I", dest="ignorecodes", type=str, default="",
+ help="Comma-separated list of response codes to ignore"
+ )
+ group.add_argument(
+ "-S", dest="showssl", action="store_true", default=False,
+ help="Show info on SSL connection"
+ )
+ group.add_argument(
+ "-e", dest="explain", action="store_true", default=False,
+ help="Explain requests"
+ )
+ group.add_argument(
+ "-o", dest="oneshot", action="store_true", default=False,
+ help="Oneshot - exit after first non-ignored response"
+ )
+ group.add_argument(
+ "-q", dest="showreq", action="store_true", default=False,
+ help="Print full request"
+ )
+ group.add_argument(
+ "-p", dest="showresp", action="store_true", default=False,
+ help="Print full response"
+ )
+ group.add_argument(
+ "-T", dest="ignoretimeout", action="store_true", default=False,
+ help="Ignore timeouts"
+ )
+ group.add_argument(
+ "-x", dest="hexdump", action="store_true", default=False,
+ help="Output in hexdump format"
+ )
+ group.add_argument(
+ "--http2-framedump", dest="http2_framedump", action="store_true", default=False,
+ help="Output all received & sent HTTP/2 frames"
+ )
+
+ args = parser.parse_args(argv[1:])
+
+ args.ssl_version, args.ssl_options = tcp.sslversion_choices[args.ssl_version]
+
+ args.port = None
+ if ":" in args.host:
+ h, p = args.host.rsplit(":", 1)
+ try:
+ p = int(p)
+ except ValueError:
+ return parser.error("Invalid port in host spec: %s" % args.host)
+ args.host = h
+ args.port = p
+
+ if args.port is None:
+ args.port = 443 if args.ssl else 80
+
+ try:
+ args.ignorecodes = [int(i) for i in args.ignorecodes.split(",") if i]
+ except ValueError:
+ return parser.error(
+ "Invalid return code specification: %s" %
+ args.ignorecodes)
+
+ if args.connect_to:
+ parts = args.connect_to.split(":")
+ if len(parts) != 2:
+ return parser.error(
+ "Invalid CONNECT specification: %s" %
+ args.connect_to)
+ try:
+ parts[1] = int(parts[1])
+ except ValueError:
+ return parser.error(
+ "Invalid CONNECT specification: %s" %
+ args.connect_to)
+ args.connect_to = parts
+ else:
+ args.connect_to = None
+
+ if args.http2_skip_connection_preface:
+ args.use_http2 = True
+
+ if args.use_http2:
+ args.ssl = True
+
+ reqs = []
+ for r in args.requests:
+ if os.path.isfile(r):
+ data = open(r).read()
+ r = data
+ try:
+ reqs.append(language.parse_pathoc(r, args.use_http2))
+ except language.ParseException as v:
+ print >> stderr, "Error parsing request spec: %s" % v.msg
+ print >> stderr, v.marked()
+ sys.exit(1)
+ args.requests = reqs
+
+ return args
+
+
+def go_pathoc(): # pragma: nocover
+ args = args_pathoc(sys.argv)
+ pathoc.main(args)
diff --git a/pathod/libpathod/pathod.py b/pathod/libpathod/pathod.py
new file mode 100644
index 00000000..55e75074
--- /dev/null
+++ b/pathod/libpathod/pathod.py
@@ -0,0 +1,503 @@
+import copy
+import logging
+import os
+import sys
+import threading
+import urllib
+
+from netlib import tcp, http, certutils, websockets
+from netlib.exceptions import HttpException, HttpReadDisconnect, TcpTimeout, TcpDisconnect, \
+ TlsException
+
+from . import version, app, language, utils, log, protocols
+import language.http
+import language.actions
+import language.exceptions
+import language.websockets
+
+
+DEFAULT_CERT_DOMAIN = "pathod.net"
+CONFDIR = "~/.mitmproxy"
+CERTSTORE_BASENAME = "mitmproxy"
+CA_CERT_NAME = "mitmproxy-ca.pem"
+DEFAULT_CRAFT_ANCHOR = "/p/"
+
+logger = logging.getLogger('pathod')
+
+
+class PathodError(Exception):
+ pass
+
+
+class SSLOptions(object):
+ def __init__(
+ self,
+ confdir=CONFDIR,
+ cn=None,
+ sans=(),
+ not_after_connect=None,
+ request_client_cert=False,
+ ssl_version=tcp.SSL_DEFAULT_METHOD,
+ ssl_options=tcp.SSL_DEFAULT_OPTIONS,
+ ciphers=None,
+ certs=None,
+ alpn_select=b'h2',
+ ):
+ self.confdir = confdir
+ self.cn = cn
+ self.sans = sans
+ self.not_after_connect = not_after_connect
+ self.request_client_cert = request_client_cert
+ self.ssl_version = ssl_version
+ self.ssl_options = ssl_options
+ self.ciphers = ciphers
+ self.alpn_select = alpn_select
+ self.certstore = certutils.CertStore.from_store(
+ os.path.expanduser(confdir),
+ CERTSTORE_BASENAME
+ )
+ for i in certs or []:
+ self.certstore.add_cert_file(*i)
+
+ def get_cert(self, name):
+ if self.cn:
+ name = self.cn
+ elif not name:
+ name = DEFAULT_CERT_DOMAIN
+ return self.certstore.get_cert(name, self.sans)
+
+
+class PathodHandler(tcp.BaseHandler):
+ wbufsize = 0
+ sni = None
+
+ def __init__(
+ self,
+ connection,
+ address,
+ server,
+ logfp,
+ settings,
+ http2_framedump=False
+ ):
+ tcp.BaseHandler.__init__(self, connection, address, server)
+ self.logfp = logfp
+ self.settings = copy.copy(settings)
+ self.protocol = None
+ self.use_http2 = False
+ self.http2_framedump = http2_framedump
+
+ def handle_sni(self, connection):
+ self.sni = connection.get_servername()
+
+ def http_serve_crafted(self, crafted, logctx):
+ error, crafted = self.server.check_policy(
+ crafted, self.settings
+ )
+ if error:
+ err = self.make_http_error_response(error)
+ language.serve(err, self.wfile, self.settings)
+ return None, dict(
+ type="error",
+ msg=error
+ )
+
+ if self.server.explain and not hasattr(crafted, 'is_error_response'):
+ crafted = crafted.freeze(self.settings)
+ logctx(">> Spec: %s" % crafted.spec())
+
+ response_log = language.serve(
+ crafted,
+ self.wfile,
+ self.settings
+ )
+ if response_log["disconnect"]:
+ return None, response_log
+ return self.handle_http_request, response_log
+
+
+ def handle_http_request(self, logger):
+ """
+ Returns a (handler, log) tuple.
+
+ handler: Handler for the next request, or None to disconnect
+ log: A dictionary, or None
+ """
+ with logger.ctx() as lg:
+ try:
+ req = self.protocol.read_request(self.rfile)
+ except HttpReadDisconnect:
+ return None, None
+ except HttpException as s:
+ s = str(s)
+ lg(s)
+ return None, dict(type="error", msg=s)
+
+ if req.method == 'CONNECT':
+ return self.protocol.handle_http_connect([req.host, req.port, req.http_version], lg)
+
+ method = req.method
+ path = req.path
+ http_version = req.http_version
+ headers = req.headers
+ body = req.content
+
+ clientcert = None
+ if self.clientcert:
+ clientcert = dict(
+ cn=self.clientcert.cn,
+ subject=self.clientcert.subject,
+ serial=self.clientcert.serial,
+ notbefore=self.clientcert.notbefore.isoformat(),
+ notafter=self.clientcert.notafter.isoformat(),
+ keyinfo=self.clientcert.keyinfo,
+ )
+
+ retlog = dict(
+ type="crafted",
+ protocol="http",
+ request=dict(
+ path=path,
+ method=method,
+ headers=headers.fields,
+ http_version=http_version,
+ sni=self.sni,
+ remote_address=self.address(),
+ clientcert=clientcert,
+ ),
+ cipher=None,
+ )
+ if self.ssl_established:
+ retlog["cipher"] = self.get_current_cipher()
+
+ m = utils.MemBool()
+ websocket_key = websockets.WebsocketsProtocol.check_client_handshake(headers)
+ self.settings.websocket_key = websocket_key
+
+ # If this is a websocket initiation, we respond with a proper
+ # server response, unless over-ridden.
+ if websocket_key:
+ anchor_gen = language.parse_pathod("ws")
+ else:
+ anchor_gen = None
+
+ for regex, spec in self.server.anchors:
+ if regex.match(path):
+ anchor_gen = language.parse_pathod(spec, self.use_http2)
+ break
+ else:
+ if m(path.startswith(self.server.craftanchor)):
+ spec = urllib.unquote(path)[len(self.server.craftanchor):]
+ if spec:
+ try:
+ anchor_gen = language.parse_pathod(spec, self.use_http2)
+ except language.ParseException as v:
+ lg("Parse error: %s" % v.msg)
+ anchor_gen = iter([self.make_http_error_response(
+ "Parse Error",
+ "Error parsing response spec: %s\n" % (
+ v.msg + v.marked()
+ )
+ )])
+ else:
+ if self.use_http2:
+ anchor_gen = iter([self.make_http_error_response(
+ "Spec Error",
+ "HTTP/2 only supports request/response with the craft anchor point: %s" %
+ self.server.craftanchor
+ )])
+
+ if anchor_gen:
+ spec = anchor_gen.next()
+
+ if self.use_http2 and isinstance(spec, language.http2.Response):
+ spec.stream_id = req.stream_id
+
+ lg("crafting spec: %s" % spec)
+ nexthandler, retlog["response"] = self.http_serve_crafted(
+ spec,
+ lg
+ )
+ if nexthandler and websocket_key:
+ self.protocol = protocols.websockets.WebsocketsProtocol(self)
+ return self.protocol.handle_websocket, retlog
+ else:
+ return nexthandler, retlog
+ else:
+ return self.protocol.handle_http_app(method, path, headers, body, lg)
+
+ def make_http_error_response(self, reason, body=None):
+ resp = self.protocol.make_error_response(reason, body)
+ resp.is_error_response = True
+ return resp
+
+ def handle(self):
+ self.settimeout(self.server.timeout)
+
+ if self.server.ssl:
+ try:
+ cert, key, _ = self.server.ssloptions.get_cert(None)
+ self.convert_to_ssl(
+ cert,
+ key,
+ handle_sni=self.handle_sni,
+ request_client_cert=self.server.ssloptions.request_client_cert,
+ cipher_list=self.server.ssloptions.ciphers,
+ method=self.server.ssloptions.ssl_version,
+ options=self.server.ssloptions.ssl_options,
+ alpn_select=self.server.ssloptions.alpn_select,
+ )
+ except TlsException as v:
+ s = str(v)
+ self.server.add_log(
+ dict(
+ type="error",
+ msg=s
+ )
+ )
+ log.write_raw(self.logfp, s)
+ return
+
+ alp = self.get_alpn_proto_negotiated()
+ if alp == b'h2':
+ self.protocol = protocols.http2.HTTP2Protocol(self)
+ self.use_http2 = True
+
+ if not self.protocol:
+ self.protocol = protocols.http.HTTPProtocol(self)
+
+ lr = self.rfile if self.server.logreq else None
+ lw = self.wfile if self.server.logresp else None
+ logger = log.ConnectionLogger(self.logfp, self.server.hexdump, lr, lw)
+
+ self.settings.protocol = self.protocol
+
+ handler = self.handle_http_request
+
+ while not self.finished:
+ handler, l = handler(logger)
+ if l:
+ self.addlog(l)
+ if not handler:
+ return
+
+ def addlog(self, log):
+ # FIXME: The bytes in the log should not be escaped. We do this at the
+ # moment because JSON encoding can't handle binary data, and I don't
+ # want to base64 everything.
+ if self.server.logreq:
+ encoded_bytes = self.rfile.get_log().encode("string_escape")
+ log["request_bytes"] = encoded_bytes
+ if self.server.logresp:
+ encoded_bytes = self.wfile.get_log().encode("string_escape")
+ log["response_bytes"] = encoded_bytes
+ self.server.add_log(log)
+
+
+class Pathod(tcp.TCPServer):
+ LOGBUF = 500
+
+ def __init__(
+ self,
+ addr,
+ ssl=False,
+ ssloptions=None,
+ craftanchor=DEFAULT_CRAFT_ANCHOR,
+ staticdir=None,
+ anchors=(),
+ sizelimit=None,
+ noweb=False,
+ nocraft=False,
+ noapi=False,
+ nohang=False,
+ timeout=None,
+ logreq=False,
+ logresp=False,
+ explain=False,
+ hexdump=False,
+ http2_framedump=False,
+ webdebug=False,
+ logfp=sys.stdout,
+ ):
+ """
+ addr: (address, port) tuple. If port is 0, a free port will be
+ automatically chosen.
+ ssloptions: an SSLOptions object.
+ craftanchor: URL prefix specifying the path under which to anchor
+ response generation.
+ staticdir: path to a directory of static resources, or None.
+ anchors: List of (regex object, language.Request object) tuples, or
+ None.
+ sizelimit: Limit size of served data.
+ nocraft: Disable response crafting.
+ noapi: Disable the API.
+ nohang: Disable pauses.
+ """
+ tcp.TCPServer.__init__(self, addr)
+ self.ssl = ssl
+ self.ssloptions = ssloptions or SSLOptions()
+ self.staticdir = staticdir
+ self.craftanchor = craftanchor
+ self.sizelimit = sizelimit
+ self.noweb, self.nocraft = noweb, nocraft
+ self.noapi, self.nohang = noapi, nohang
+ self.timeout, self.logreq = timeout, logreq
+ self.logresp, self.hexdump = logresp, hexdump
+ self.http2_framedump = http2_framedump
+ self.explain = explain
+ self.logfp = logfp
+
+ self.app = app.make_app(noapi, webdebug)
+ self.app.config["pathod"] = self
+ self.log = []
+ self.logid = 0
+ self.anchors = anchors
+
+ self.settings = language.Settings(
+ staticdir=self.staticdir
+ )
+
+ def check_policy(self, req, settings):
+ """
+ A policy check that verifies the request size is within limits.
+ """
+ if self.nocraft:
+ return "Crafting disabled.", None
+ try:
+ req = req.resolve(settings)
+ l = req.maximum_length(settings)
+ except language.FileAccessDenied:
+ return "File access denied.", None
+ if self.sizelimit and l > self.sizelimit:
+ return "Response too large.", None
+ pauses = [isinstance(i, language.actions.PauseAt) for i in req.actions]
+ if self.nohang and any(pauses):
+ return "Pauses have been disabled.", None
+ return None, req
+
+ def handle_client_connection(self, request, client_address):
+ h = PathodHandler(
+ request,
+ client_address,
+ self,
+ self.logfp,
+ self.settings,
+ self.http2_framedump,
+ )
+ try:
+ h.handle()
+ h.finish()
+ except TcpDisconnect: # pragma: no cover
+ log.write_raw(self.logfp, "Disconnect")
+ self.add_log(
+ dict(
+ type="error",
+ msg="Disconnect"
+ )
+ )
+ return
+ except TcpTimeout:
+ log.write_raw(self.logfp, "Timeout")
+ self.add_log(
+ dict(
+ type="timeout",
+ )
+ )
+ return
+
+ def add_log(self, d):
+ if not self.noapi:
+ lock = threading.Lock()
+ with lock:
+ d["id"] = self.logid
+ self.log.insert(0, d)
+ if len(self.log) > self.LOGBUF:
+ self.log.pop()
+ self.logid += 1
+ return d["id"]
+
+ def clear_log(self):
+ lock = threading.Lock()
+ with lock:
+ self.log = []
+
+ def log_by_id(self, identifier):
+ for i in self.log:
+ if i["id"] == identifier:
+ return i
+
+ def get_log(self):
+ return self.log
+
+
+def main(args): # pragma: nocover
+ ssloptions = SSLOptions(
+ cn=args.cn,
+ confdir=args.confdir,
+ not_after_connect=args.ssl_not_after_connect,
+ ciphers=args.ciphers,
+ ssl_version=args.ssl_version,
+ ssl_options=args.ssl_options,
+ certs=args.ssl_certs,
+ sans=args.sans,
+ )
+
+ root = logging.getLogger()
+ if root.handlers:
+ for handler in root.handlers:
+ root.removeHandler(handler)
+
+ log = logging.getLogger('pathod')
+ log.setLevel(logging.DEBUG)
+ fmt = logging.Formatter(
+ '%(asctime)s: %(message)s',
+ datefmt='%d-%m-%y %H:%M:%S',
+ )
+ if args.logfile:
+ fh = logging.handlers.WatchedFileHandler(args.logfile)
+ fh.setFormatter(fmt)
+ log.addHandler(fh)
+ if not args.daemonize:
+ sh = logging.StreamHandler()
+ sh.setFormatter(fmt)
+ log.addHandler(sh)
+
+ try:
+ pd = Pathod(
+ (args.address, args.port),
+ craftanchor=args.craftanchor,
+ ssl=args.ssl,
+ ssloptions=ssloptions,
+ staticdir=args.staticdir,
+ anchors=args.anchors,
+ sizelimit=args.sizelimit,
+ noweb=args.noweb,
+ nocraft=args.nocraft,
+ noapi=args.noapi,
+ nohang=args.nohang,
+ timeout=args.timeout,
+ logreq=args.logreq,
+ logresp=args.logresp,
+ hexdump=args.hexdump,
+ http2_framedump=args.http2_framedump,
+ explain=args.explain,
+ webdebug=args.webdebug
+ )
+ except PathodError as v:
+ print >> sys.stderr, "Error: %s" % v
+ sys.exit(1)
+ except language.FileAccessDenied as v:
+ print >> sys.stderr, "Error: %s" % v
+
+ if args.daemonize:
+ utils.daemonize()
+
+ try:
+ print "%s listening on %s:%s" % (
+ version.NAMEVERSION,
+ pd.address.host,
+ pd.address.port
+ )
+ pd.serve_forever()
+ except KeyboardInterrupt:
+ pass
diff --git a/pathod/libpathod/pathod_cmdline.py b/pathod/libpathod/pathod_cmdline.py
new file mode 100644
index 00000000..c9272249
--- /dev/null
+++ b/pathod/libpathod/pathod_cmdline.py
@@ -0,0 +1,231 @@
+import sys
+import argparse
+import os
+import os.path
+import re
+
+from netlib import tcp
+from . import pathod, version, utils
+
+
+def args_pathod(argv, stdout_=sys.stdout, stderr_=sys.stderr):
+ parser = argparse.ArgumentParser(
+ description='A pathological HTTP/S daemon.'
+ )
+ parser.add_argument(
+ '--version',
+ action='version',
+ version="pathod " + version.VERSION
+ )
+ parser.add_argument(
+ "-p",
+ dest='port',
+ default=9999,
+ type=int,
+ help='Port. Specify 0 to pick an arbitrary empty port. (9999)'
+ )
+ parser.add_argument(
+ "-l",
+ dest='address',
+ default="127.0.0.1",
+ type=str,
+ help='Listening address. (127.0.0.1)'
+ )
+ parser.add_argument(
+ "-a",
+ dest='anchors',
+ default=[],
+ type=str,
+ action="append",
+ metavar="ANCHOR",
+ help="""
+ Add an anchor. Specified as a string with the form
+ pattern=spec or pattern=filepath, where pattern is a regular
+ expression.
+ """
+ )
+ parser.add_argument(
+ "-c", dest='craftanchor', default=pathod.DEFAULT_CRAFT_ANCHOR, type=str,
+ help="""
+ URL path specifying prefix for URL crafting
+ commands. (%s)
+ """%pathod.DEFAULT_CRAFT_ANCHOR
+ )
+ parser.add_argument(
+ "--confdir",
+ action="store", type = str, dest="confdir", default='~/.mitmproxy',
+ help = "Configuration directory. (~/.mitmproxy)"
+ )
+ parser.add_argument(
+ "-d", dest='staticdir', default=None, type=str,
+ help='Directory for static files.'
+ )
+ parser.add_argument(
+ "-D", dest='daemonize', default=False, action="store_true",
+ help='Daemonize.'
+ )
+ parser.add_argument(
+ "-t", dest="timeout", type=int, default=None,
+ help="Connection timeout"
+ )
+ parser.add_argument(
+ "--limit-size",
+ dest='sizelimit',
+ default=None,
+ type=str,
+ help='Size limit of served responses. Understands size suffixes, i.e. 100k.')
+ parser.add_argument(
+ "--noapi", dest='noapi', default=False, action="store_true",
+ help='Disable API.'
+ )
+ parser.add_argument(
+ "--nohang", dest='nohang', default=False, action="store_true",
+ help='Disable pauses during crafted response generation.'
+ )
+ parser.add_argument(
+ "--noweb", dest='noweb', default=False, action="store_true",
+ help='Disable both web interface and API.'
+ )
+ parser.add_argument(
+ "--nocraft",
+ dest='nocraft',
+ default=False,
+ action="store_true",
+ help='Disable response crafting. If anchors are specified, they still work.')
+ parser.add_argument(
+ "--webdebug", dest='webdebug', default=False, action="store_true",
+ help='Debugging mode for the web app (dev only).'
+ )
+
+ group = parser.add_argument_group(
+ 'SSL',
+ )
+ group.add_argument(
+ "-s", dest='ssl', default=False, action="store_true",
+ help='Run in HTTPS mode.'
+ )
+ group.add_argument(
+ "--cn",
+ dest="cn",
+ type=str,
+ default=None,
+ help="CN for generated SSL certs. Default: %s" %
+ pathod.DEFAULT_CERT_DOMAIN)
+ group.add_argument(
+ "-C", dest='ssl_not_after_connect', default=False, action="store_true",
+ help="Don't expect SSL after a CONNECT request."
+ )
+ group.add_argument(
+ "--cert", dest='ssl_certs', default=[], type=str,
+ metavar = "SPEC", action="append",
+ help = """
+ Add an SSL certificate. SPEC is of the form "[domain=]path". The domain
+ may include a wildcard, and is equal to "*" if not specified. The file
+ at path is a certificate in PEM format. If a private key is included in
+ the PEM, it is used, else the default key in the conf dir is used. Can
+ be passed multiple times.
+ """
+ )
+ group.add_argument(
+ "--ciphers", dest="ciphers", type=str, default=False,
+ help="SSL cipher specification"
+ )
+ group.add_argument(
+ "--san", dest="sans", type=str, default=[], action="append",
+ metavar="SAN",
+ help="""
+ Subject Altnernate Name to add to the server certificate.
+ May be passed multiple times.
+ """
+ )
+ group.add_argument(
+ "--ssl-version", dest="ssl_version", type=str, default="secure",
+ choices=tcp.sslversion_choices.keys(),
+ help="Set supported SSL/TLS versions. "
+ "SSLv2, SSLv3 and 'all' are INSECURE. Defaults to secure, which is TLS1.0+."
+ )
+
+ group = parser.add_argument_group(
+ 'Controlling Logging',
+ """
+ Some of these options expand generated values for logging - if
+ you're generating large data, use them with caution.
+ """
+ )
+ group.add_argument(
+ "-e", dest="explain", action="store_true", default=False,
+ help="Explain responses"
+ )
+ group.add_argument(
+ "-f", dest='logfile', default=None, type=str,
+ help='Log to file.'
+ )
+ group.add_argument(
+ "-q", dest="logreq", action="store_true", default=False,
+ help="Log full request"
+ )
+ group.add_argument(
+ "-r", dest="logresp", action="store_true", default=False,
+ help="Log full response"
+ )
+ group.add_argument(
+ "-x", dest="hexdump", action="store_true", default=False,
+ help="Log request/response in hexdump format"
+ )
+ group.add_argument(
+ "--http2-framedump", dest="http2_framedump", action="store_true", default=False,
+ help="Output all received & sent HTTP/2 frames"
+ )
+
+
+ args = parser.parse_args(argv[1:])
+
+ args.ssl_version, args.ssl_options = tcp.sslversion_choices[args.ssl_version]
+
+ certs = []
+ for i in args.ssl_certs:
+ parts = i.split("=", 1)
+ if len(parts) == 1:
+ parts = ["*", parts[0]]
+ parts[1] = os.path.expanduser(parts[1])
+ if not os.path.isfile(parts[1]):
+ return parser.error(
+ "Certificate file does not exist: %s" %
+ parts[1])
+ certs.append(parts)
+ args.ssl_certs = certs
+
+ alst = []
+ for i in args.anchors:
+ parts = utils.parse_anchor_spec(i)
+ if not parts:
+ return parser.error("Invalid anchor specification: %s" % i)
+ alst.append(parts)
+ args.anchors = alst
+
+ sizelimit = None
+ if args.sizelimit:
+ try:
+ sizelimit = utils.parse_size(args.sizelimit)
+ except ValueError as v:
+ return parser.error(v)
+ args.sizelimit = sizelimit
+
+ anchors = []
+ for patt, spec in args.anchors:
+ if os.path.isfile(spec):
+ data = open(spec).read()
+ spec = data
+ try:
+ arex = re.compile(patt)
+ except re.error:
+ return parser.error("Invalid regex in anchor: %s" % patt)
+ anchors.append((arex, spec))
+ args.anchors = anchors
+
+ return args
+
+
+def go_pathod(): # pragma: nocover
+ args = args_pathod(sys.argv)
+ pathod.main(args)
diff --git a/pathod/libpathod/protocols/__init__.py b/pathod/libpathod/protocols/__init__.py
new file mode 100644
index 00000000..1a8c7dab
--- /dev/null
+++ b/pathod/libpathod/protocols/__init__.py
@@ -0,0 +1 @@
+from . import http, http2, websockets
diff --git a/pathod/libpathod/protocols/http.py b/pathod/libpathod/protocols/http.py
new file mode 100644
index 00000000..1f1765cb
--- /dev/null
+++ b/pathod/libpathod/protocols/http.py
@@ -0,0 +1,71 @@
+from netlib import tcp, wsgi
+from netlib.exceptions import HttpReadDisconnect, TlsException
+from netlib.http import http1, Request
+from .. import version, language
+
+
+class HTTPProtocol(object):
+ def __init__(self, pathod_handler):
+ self.pathod_handler = pathod_handler
+
+ def make_error_response(self, reason, body):
+ return language.http.make_error_response(reason, body)
+
+ def handle_http_app(self, method, path, headers, body, lg):
+ """
+ Handle a request to the built-in app.
+ """
+ if self.pathod_handler.server.noweb:
+ crafted = self.pathod_handler.make_http_error_response("Access Denied")
+ language.serve(crafted, self.pathod_handler.wfile, self.pathod_handler.settings)
+ return None, dict(
+ type="error",
+ msg="Access denied: web interface disabled"
+ )
+ lg("app: %s %s" % (method, path))
+ req = wsgi.Request("http", method, path, b"HTTP/1.1", headers, body)
+ flow = wsgi.Flow(self.pathod_handler.address, req)
+ sn = self.pathod_handler.connection.getsockname()
+ a = wsgi.WSGIAdaptor(
+ self.pathod_handler.server.app,
+ sn[0],
+ self.pathod_handler.server.address.port,
+ version.NAMEVERSION
+ )
+ a.serve(flow, self.pathod_handler.wfile)
+ return self.pathod_handler.handle_http_request, None
+
+ def handle_http_connect(self, connect, lg):
+ """
+ Handle a CONNECT request.
+ """
+
+ self.pathod_handler.wfile.write(
+ 'HTTP/1.1 200 Connection established\r\n' +
+ ('Proxy-agent: %s\r\n' % version.NAMEVERSION) +
+ '\r\n'
+ )
+ self.pathod_handler.wfile.flush()
+ if not self.pathod_handler.server.ssloptions.not_after_connect:
+ try:
+ cert, key, chain_file_ = self.pathod_handler.server.ssloptions.get_cert(
+ connect[0]
+ )
+ self.pathod_handler.convert_to_ssl(
+ cert,
+ key,
+ handle_sni=self.pathod_handler.handle_sni,
+ request_client_cert=self.pathod_handler.server.ssloptions.request_client_cert,
+ cipher_list=self.pathod_handler.server.ssloptions.ciphers,
+ method=self.pathod_handler.server.ssloptions.ssl_version,
+ options=self.pathod_handler.server.ssloptions.ssl_options,
+ alpn_select=self.pathod_handler.server.ssloptions.alpn_select,
+ )
+ except TlsException as v:
+ s = str(v)
+ lg(s)
+ return None, dict(type="error", msg=s)
+ return self.pathod_handler.handle_http_request, None
+
+ def read_request(self, lg=None):
+ return http1.read_request(self.pathod_handler.rfile)
diff --git a/pathod/libpathod/protocols/http2.py b/pathod/libpathod/protocols/http2.py
new file mode 100644
index 00000000..a098a14e
--- /dev/null
+++ b/pathod/libpathod/protocols/http2.py
@@ -0,0 +1,20 @@
+from netlib.http import http2
+from .. import version, app, language, utils, log
+
+class HTTP2Protocol:
+
+ def __init__(self, pathod_handler):
+ self.pathod_handler = pathod_handler
+ self.wire_protocol = http2.HTTP2Protocol(
+ self.pathod_handler, is_server=True, dump_frames=self.pathod_handler.http2_framedump
+ )
+
+ def make_error_response(self, reason, body):
+ return language.http2.make_error_response(reason, body)
+
+ def read_request(self, lg=None):
+ self.wire_protocol.perform_server_connection_preface()
+ return self.wire_protocol.read_request(self.pathod_handler.rfile)
+
+ def assemble(self, message):
+ return self.wire_protocol.assemble(message)
diff --git a/pathod/libpathod/protocols/websockets.py b/pathod/libpathod/protocols/websockets.py
new file mode 100644
index 00000000..134d27bc
--- /dev/null
+++ b/pathod/libpathod/protocols/websockets.py
@@ -0,0 +1,56 @@
+import time
+
+from netlib import websockets
+from .. import language
+from netlib.exceptions import NetlibException
+
+
+class WebsocketsProtocol:
+
+ def __init__(self, pathod_handler):
+ self.pathod_handler = pathod_handler
+
+ def handle_websocket(self, logger):
+ while True:
+ with logger.ctx() as lg:
+ started = time.time()
+ try:
+ frm = websockets.Frame.from_file(self.pathod_handler.rfile)
+ except NetlibException as e:
+ lg("Error reading websocket frame: %s" % e)
+ break
+ ended = time.time()
+ lg(frm.human_readable())
+ retlog = dict(
+ type="inbound",
+ protocol="websockets",
+ started=started,
+ duration=ended - started,
+ frame=dict(
+ ),
+ cipher=None,
+ )
+ if self.pathod_handler.ssl_established:
+ retlog["cipher"] = self.pathod_handler.get_current_cipher()
+ self.pathod_handler.addlog(retlog)
+ ld = language.websockets.NESTED_LEADER
+ if frm.payload.startswith(ld):
+ nest = frm.payload[len(ld):]
+ try:
+ wf_gen = language.parse_websocket_frame(nest)
+ except language.exceptions.ParseException as v:
+ logger.write(
+ "Parse error in reflected frame specifcation:"
+ " %s" % v.msg
+ )
+ return None, None
+ for frm in wf_gen:
+ with logger.ctx() as lg:
+ frame_log = language.serve(
+ frm,
+ self.pathod_handler.wfile,
+ self.pathod_handler.settings
+ )
+ lg("crafting websocket spec: %s" % frame_log["spec"])
+ self.pathod_handler.addlog(frame_log)
+ return self.handle_websocket, None
diff --git a/pathod/libpathod/static/bootstrap.min.css b/pathod/libpathod/static/bootstrap.min.css
new file mode 100644
index 00000000..2e79d91a
--- /dev/null
+++ b/pathod/libpathod/static/bootstrap.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Bootstrap v2.3.1
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:32px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:16px;line-height:22px;color:#555;background-color:#fff}a{color:#007fff;text-decoration:none}a:hover,a:focus{color:#06c;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:32px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 11px}.lead{margin-bottom:22px;font-size:24px;font-weight:200;line-height:33px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#dfdfdf}a.muted:hover,a.muted:focus{color:#c6c6c6}.text-warning{color:#fff}a.text-warning:hover,a.text-warning:focus{color:#e6e6e6}.text-error{color:#fff}a.text-error:hover,a.text-error:focus{color:#e6e6e6}.text-info{color:#fff}a.text-info:hover,a.text-info:focus{color:#e6e6e6}.text-success{color:#fff}a.text-success:hover,a.text-success:focus{color:#e6e6e6}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:11px 0;font-family:inherit;font-weight:300;line-height:22px;color:#080808;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#dfdfdf}h1,h2,h3{line-height:44px}h1{font-size:44px}h2{font-size:36px}h3{font-size:28px}h4{font-size:20px}h5{font-size:16px}h6{font-size:13.6px}h1 small{font-size:28px}h2 small{font-size:20px}h3 small{font-size:16px}h4 small{font-size:16px}.page-header{padding-bottom:10px;margin:44px 0 22px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 11px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:22px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:22px}dt,dd{line-height:22px}dt{font-weight:bold}dd{margin-left:11px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:22px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #dfdfdf}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 22px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:20px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:22px;color:#dfdfdf}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:22px;font-style:normal;line-height:22px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:14px;color:#999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:10.5px;margin:0 0 11px;font-size:15px;line-height:22px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}pre.prettyprint{margin-bottom:22px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 22px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:22px;font-size:24px;line-height:44px;color:#999;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:16.5px;color:#dfdfdf}label,input,button,select,textarea{font-size:16px;font-weight:normal;line-height:22px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:22px;padding:4px 6px;margin-bottom:11px;font-size:16px;line-height:22px;color:#bbb;vertical-align:middle;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #bbb;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:32px;*margin-top:4px;line-height:32px}select{width:220px;background-color:#fff;border:1px solid #bbb}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#dfdfdf;cursor:not-allowed;background-color:#fcfcfc;border-color:#bbb;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#bbb}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#bbb}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#bbb}.radio,.checkbox{min-height:22px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#fff}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#fff}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#fff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#fff;background-color:#ff7518;border-color:#fff}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#fff}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#fff}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#fff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#fff;background-color:#ff0039;border-color:#fff}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#fff}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#fff}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#fff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#fff;background-color:#3fb618;border-color:#fff}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#fff}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#fff}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#fff;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#e6e6e6;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #fff}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#fff;background-color:#9954bb;border-color:#fff}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:21px 20px 22px;margin-top:22px;margin-bottom:22px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#7b7b7b}.help-block{display:block;margin-bottom:11px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:11px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:16px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:22px;min-width:16px;padding:4px 5px;font-size:16px;font-weight:normal;line-height:22px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#96ed7a;border-color:#3fb618}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:11px}legend+.control-group{margin-top:22px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:22px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:11px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:22px}.table th,.table td{padding:8px;line-height:22px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-topleft:0}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:0;border-top-right-radius:0;-moz-border-radius-topright:0}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-topleft:0}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:0;border-top-right-radius:0;-moz-border-radius-topright:0}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#e8f8fd}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#3fb618}.table tbody tr.error>td{background-color:#ff0039}.table tbody tr.warning>td{background-color:#ff7518}.table tbody tr.info>td{background-color:#9954bb}.table-hover tbody tr.success:hover>td{background-color:#379f15}.table-hover tbody tr.error:hover>td{background-color:#e60033}.table-hover tbody tr.warning:hover>td{background-color:#fe6600}.table-hover tbody tr.info:hover>td{background-color:#8d46b0}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:10px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:22px;color:#999;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#007af5;background-image:-moz-linear-gradient(top,#007fff,#0072e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#007fff),to(#0072e6));background-image:-webkit-linear-gradient(top,#007fff,#0072e6);background-image:-o-linear-gradient(top,#007fff,#0072e6);background-image:linear-gradient(to bottom,#007fff,#0072e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff007fff',endColorstr='#ff0072e6',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#007af5;background-image:-moz-linear-gradient(top,#007fff,#0072e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#007fff),to(#0072e6));background-image:-webkit-linear-gradient(top,#007fff,#0072e6);background-image:-o-linear-gradient(top,#007fff,#0072e6);background-image:linear-gradient(to bottom,#007fff,#0072e6);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff007fff',endColorstr='#ff0072e6',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#dfdfdf}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#eee;border:1px solid #dcdcdc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.well-small{padding:9px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:22px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:16px;line-height:22px;color:#999;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#dfdfdf;*background-color:#c8c8c8;background-image:-moz-linear-gradient(top,#eee,#c8c8c8);background-image:-webkit-gradient(linear,0 0,0 100%,from(#eee),to(#c8c8c8));background-image:-webkit-linear-gradient(top,#eee,#c8c8c8);background-image:-o-linear-gradient(top,#eee,#c8c8c8);background-image:linear-gradient(to bottom,#eee,#c8c8c8);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:#c8c8c8 #c8c8c8 #a2a2a2;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#a2a2a2;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffeeeeee',endColorstr='#ffc8c8c8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#999;background-color:#c8c8c8;*background-color:#bbb}.btn:active,.btn.active{background-color:#aeaeae \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#999;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:22px 30px;font-size:20px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:13.6px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:2px 6px;font-size:12px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0f82f5;*background-color:#0072e6;background-image:-moz-linear-gradient(top,#1a8cff,#0072e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#1a8cff),to(#0072e6));background-image:-webkit-linear-gradient(top,#1a8cff,#0072e6);background-image:-o-linear-gradient(top,#1a8cff,#0072e6);background-image:linear-gradient(to bottom,#1a8cff,#0072e6);background-repeat:repeat-x;border-color:#0072e6 #0072e6 #004c99;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff1a8cff',endColorstr='#ff0072e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#0072e6;*background-color:#06c}.btn-primary:active,.btn-primary.active{background-color:#0059b3 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#fe781e;*background-color:#fe6600;background-image:-moz-linear-gradient(top,#ff8432,#fe6600);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ff8432),to(#fe6600));background-image:-webkit-linear-gradient(top,#ff8432,#fe6600);background-image:-o-linear-gradient(top,#ff8432,#fe6600);background-image:linear-gradient(to bottom,#ff8432,#fe6600);background-repeat:repeat-x;border-color:#fe6600 #fe6600 #b14700;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff8432',endColorstr='#fffe6600',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#fe6600;*background-color:#e45c00}.btn-warning:active,.btn-warning.active{background-color:#cb5200 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#f50f43;*background-color:#e60033;background-image:-moz-linear-gradient(top,#ff1a4d,#e60033);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ff1a4d),to(#e60033));background-image:-webkit-linear-gradient(top,#ff1a4d,#e60033);background-image:-o-linear-gradient(top,#ff1a4d,#e60033);background-image:linear-gradient(to bottom,#ff1a4d,#e60033);background-repeat:repeat-x;border-color:#e60033 #e60033 #902;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff1a4d',endColorstr='#ffe60033',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#e60033;*background-color:#cc002e}.btn-danger:active,.btn-danger.active{background-color:#b30028 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#41bb19;*background-color:#379f15;background-image:-moz-linear-gradient(top,#47cd1b,#379f15);background-image:-webkit-gradient(linear,0 0,0 100%,from(#47cd1b),to(#379f15));background-image:-webkit-linear-gradient(top,#47cd1b,#379f15);background-image:-o-linear-gradient(top,#47cd1b,#379f15);background-image:linear-gradient(to bottom,#47cd1b,#379f15);background-repeat:repeat-x;border-color:#379f15 #379f15 #205c0c;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff47cd1b',endColorstr='#ff379f15',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#379f15;*background-color:#2f8912}.btn-success:active,.btn-success.active{background-color:#28720f \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#9b59bb;*background-color:#8d46b0;background-image:-moz-linear-gradient(top,#a466c2,#8d46b0);background-image:-webkit-gradient(linear,0 0,0 100%,from(#a466c2),to(#8d46b0));background-image:-webkit-linear-gradient(top,#a466c2,#8d46b0);background-image:-o-linear-gradient(top,#a466c2,#8d46b0);background-image:linear-gradient(to bottom,#a466c2,#8d46b0);background-repeat:repeat-x;border-color:#8d46b0 #8d46b0 #613079;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffa466c2',endColorstr='#ff8d46b0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#8d46b0;*background-color:#7e3f9d}.btn-info:active,.btn-info.active{background-color:#6f378b \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#080808;*background-color:#000;background-image:-moz-linear-gradient(top,#0d0d0d,#000);background-image:-webkit-gradient(linear,0 0,0 100%,from(#0d0d0d),to(#000));background-image:-webkit-linear-gradient(top,#0d0d0d,#000);background-image:-o-linear-gradient(top,#0d0d0d,#000);background-image:linear-gradient(to bottom,#0d0d0d,#000);background-repeat:repeat-x;border-color:#000 #000 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0d0d0d',endColorstr='#ff000000',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#000;*background-color:#000}.btn-inverse:active,.btn-inverse.active{background-color:#000 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#007fff;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#06c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#999;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:11px;margin-bottom:11px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:16px}.btn-group>.btn-mini{font-size:12px}.btn-group>.btn-small{font-size:13.6px}.btn-group>.btn-large{font-size:20px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#c8c8c8}.btn-group.open .btn-primary.dropdown-toggle{background-color:#0072e6}.btn-group.open .btn-warning.dropdown-toggle{background-color:#fe6600}.btn-group.open .btn-danger.dropdown-toggle{background-color:#e60033}.btn-group.open .btn-success.dropdown-toggle{background-color:#379f15}.btn-group.open .btn-info.dropdown-toggle{background-color:#8d46b0}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#000}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.alert{padding:8px 35px 8px 14px;margin-bottom:22px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#ff7518;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.alert,.alert h4{color:#fff}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:22px}.alert-success{color:#fff;background-color:#3fb618;border-color:transparent}.alert-success h4{color:#fff}.alert-danger,.alert-error{color:#fff;background-color:#ff0039;border-color:transparent}.alert-danger h4,.alert-error h4{color:#fff}.alert-info{color:#fff;background-color:#9954bb;border-color:transparent}.alert-info h4{color:#fff}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:22px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:22px;color:#dfdfdf;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#007fff}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:10px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:22px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#bbb;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#007fff}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#007fff;border-bottom-color:#007fff}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#06c;border-bottom-color:#06c}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#bbb;border-bottom-color:#bbb}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#dfdfdf;border-color:#dfdfdf}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#dfdfdf}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#dfdfdf}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:22px;overflow:visible}.navbar-inner{min-height:50px;padding-right:20px;padding-left:20px;background-color:#080808;background-image:-moz-linear-gradient(top,#080808,#080808);background-image:-webkit-gradient(linear,0 0,0 100%,from(#080808),to(#080808));background-image:-webkit-linear-gradient(top,#080808,#080808);background-image:-o-linear-gradient(top,#080808,#080808);background-image:linear-gradient(to bottom,#080808,#080808);background-repeat:repeat-x;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808',endColorstr='#ff080808',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:14px 20px 14px;margin-left:-20px;font-size:20px;font-weight:200;color:#fff;text-shadow:0 1px 0 #080808}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:50px;color:#fff}.navbar-link{color:#fff}.navbar-link:hover,.navbar-link:focus{color:#fff}.navbar .divider-vertical{height:50px;margin:0 9px;border-right:1px solid #080808;border-left:1px solid #080808}.navbar .btn,.navbar .btn-group{margin-top:10px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:10px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:10px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:14px 15px 14px;color:#fff;text-decoration:none;text-shadow:0 1px 0 #080808}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#fff;text-decoration:none;background-color:#3b3b3b}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#fff;text-decoration:none;background-color:transparent;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#000;*background-color:#000;background-image:-moz-linear-gradient(top,#000,#000);background-image:-webkit-gradient(linear,0 0,0 100%,from(#000),to(#000));background-image:-webkit-linear-gradient(top,#000,#000);background-image:-o-linear-gradient(top,#000,#000);background-image:linear-gradient(to bottom,#000,#000);background-repeat:repeat-x;border-color:#000 #000 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff000000',endColorstr='#ff000000',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#000;*background-color:#000}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#000 \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:transparent}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#007fff;background-image:-moz-linear-gradient(top,#007fff,#007fff);background-image:-webkit-gradient(linear,0 0,0 100%,from(#007fff),to(#007fff));background-image:-webkit-linear-gradient(top,#007fff,#007fff);background-image:-o-linear-gradient(top,#007fff,#007fff);background-image:linear-gradient(to bottom,#007fff,#007fff);background-repeat:repeat-x;border-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff007fff',endColorstr='#ff007fff',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#fff}.navbar-inverse .navbar-text{color:#fff}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:rgba(0,0,0,0.05)}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#007fff}.navbar-inverse .navbar-link{color:#fff}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#007fff;border-left-color:#007fff}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#007fff}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#80bfff;border-color:#007fff;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#999}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#999}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#999}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#999;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0072e6;*background-color:#0072e6;background-image:-moz-linear-gradient(top,#0072e6,#0072e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#0072e6),to(#0072e6));background-image:-webkit-linear-gradient(top,#0072e6,#0072e6);background-image:-o-linear-gradient(top,#0072e6,#0072e6);background-image:linear-gradient(to bottom,#0072e6,#0072e6);background-repeat:repeat-x;border-color:#0072e6 #0072e6 #004c99;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0072e6',endColorstr='#ff0072e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#0072e6;*background-color:#06c}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#0059b3 \9}.breadcrumb{padding:8px 15px;margin:0 0 22px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#dfdfdf}.pagination{margin:22px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:22px;text-decoration:none;background-color:#dfdfdf;border:1px solid transparent;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#007fff}.pagination ul>.active>a,.pagination ul>.active>span{color:#dfdfdf;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#dfdfdf;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:22px 30px;font-size:20px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:0}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:0}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:13.6px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:2px 6px;font-size:12px}.pager{margin:22px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#dfdfdf;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#ff7518;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#ff7518;border-bottom:1px solid #fe6600;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:16px}.popover .arrow:after{border-width:15px;content:""}.popover.top .arrow{bottom:-16px;left:50%;margin-left:-16px;border-top-color:#999;border-top-color:transparent;border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-15px;border-top-color:#ff7518;border-bottom-width:0}.popover.right .arrow{top:50%;left:-16px;margin-top:-16px;border-right-color:#999;border-right-color:transparent;border-left-width:0}.popover.right .arrow:after{bottom:-15px;left:1px;border-right-color:#ff7518;border-left-width:0}.popover.bottom .arrow{top:-16px;left:50%;margin-left:-16px;border-bottom-color:#999;border-bottom-color:transparent;border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-15px;border-bottom-color:#ff7518;border-top-width:0}.popover.left .arrow{top:50%;right:-16px;margin-top:-16px;border-left-color:#999;border-left-color:transparent;border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-15px;border-left-color:#ff7518;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:22px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:22px;border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#007fff;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#bbb}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:13.536px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#dfdfdf}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#fff}.label-important[href],.badge-important[href]{background-color:#e6e6e6}.label-warning,.badge-warning{background-color:#ff7518}.label-warning[href],.badge-warning[href]{background-color:#e45c00}.label-success,.badge-success{background-color:#fff}.label-success[href],.badge-success[href]{background-color:#e6e6e6}.label-info,.badge-info{background-color:#fff}.label-info[href],.badge-info[href]{background-color:#e6e6e6}.label-inverse,.badge-inverse{background-color:#999}.label-inverse[href],.badge-inverse[href]{background-color:#808080}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:22px;margin-bottom:22px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#ff9046;background-image:-moz-linear-gradient(top,#ffa365,#ff7518);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ffa365),to(#ff7518));background-image:-webkit-linear-gradient(top,#ffa365,#ff7518);background-image:-o-linear-gradient(top,#ffa365,#ff7518);background-image:linear-gradient(to bottom,#ffa365,#ff7518);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffa365',endColorstr='#ffff7518',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#ffa365;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:22px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:22px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#080808;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#999;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:22px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:33px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:33px}body{overflow-y:scroll;font-weight:300}h1{font-size:50px}h2,h3{font-size:26px}h4{font-size:14px}h5,h6{font-size:11px}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{color:#999}blockquote{padding:10px 15px;background-color:#eee;border-left-color:#bbb}blockquote.pull-right{padding:10px 15px;border-right-color:#bbb}blockquote small{color:#999}.muted{color:#bbb}.text-warning{color:#ff7518}a.text-warning:hover{color:#e45c00}.text-error{color:#ff0039}a.text-error:hover{color:#cc002e}.text-info{color:#9954bb}a.text-info:hover{color:#7e3f9d}.text-success{color:#3fb618}a.text-success:hover{color:#2f8912}.navbar .navbar-inner{background-image:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.navbar .brand:hover{color:#fff}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{background-color:#3b3b3b;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#fff}.navbar .nav li.dropdown.open>.dropdown-toggle:hover,.navbar .nav li.dropdown.active>.dropdown-toggle:hover,.navbar .nav li.dropdown.open.active>.dropdown-toggle:hover{color:#eee}.navbar .navbar-search .search-query{line-height:normal}.navbar-inverse .brand,.navbar-inverse .nav>li>a{text-shadow:none}.navbar-inverse .brand:hover,.navbar-inverse .nav>.active>a,.navbar-inverse .nav>.active>a:hover,.navbar-inverse .nav>.active>a:focus{color:#fff;background-color:rgba(0,0,0,0.05);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.navbar-inverse .navbar-search .search-query{color:#080808}div.subnav{margin:0 1px;background:#dfdfdf none;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}div.subnav .nav{background-color:transparent}div.subnav .nav>li>a{border-color:transparent}div.subnav .nav>.active>a,div.subnav .nav>.active>a:hover{color:#fff;background-color:#000;border-color:transparent;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}div.subnav-fixed{top:51px;margin:0}.nav .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#007fff}.nav-tabs>li>a{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li>a:hover{color:#fff;background-color:#007fff}.nav-tabs.nav-stacked>.active>a,.nav-tabs.nav-stacked>.active>a:hover{color:#bbb;background-color:#fff}.nav-tabs.nav-stacked>li:first-child>a,.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.tabs-below>.nav-tabs>li>a,.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-pills>li>a{color:#000;background-color:#dfdfdf;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-pills>li>a:hover{color:#fff;background-color:#000}.nav-pills>.disabled>a,.nav-pills>.disabled>a:hover{color:#999;background-color:#eee}.nav-list>li>a{color:#080808}.nav-list>li>a:hover{color:#fff;text-shadow:none;background-color:#007fff}.nav-list .nav-header{font-size:16px;color:#000}.nav-list .divider{background-color:#bbb;border-bottom:0}.pagination ul{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.pagination ul>li>a,.pagination ul>li>span{margin-right:6px;color:#080808}.pagination ul>li>a:hover,.pagination ul>li>span:hover{color:#fff;background-color:#080808}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{margin-right:0}.pagination ul>.active>a,.pagination ul>.active>span{color:#fff}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;background-color:#eee}.pager li>a,.pager li>span{color:#080808;background-color:#dfdfdf;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.pager li>a:hover,.pager li>span:hover{color:#fff;background-color:#080808}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999;background-color:#eee}.breadcrumb{background-color:#dfdfdf}.breadcrumb li{text-shadow:none}.breadcrumb .divider,.breadcrumb .active{color:#080808;text-shadow:none}.btn{padding:5px 12px;color:#080808;text-shadow:none;background-image:none;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn.disabled{box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus{color:#000}.btn-large{padding:22px 30px}.btn-small{padding:2px 10px}.btn-mini{padding:2px 6px}.btn-group>.btn:first-child,.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.dropdown-toggle{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.table tbody tr.success td{color:#fff}.table tbody tr.error td{color:#fff}.table tbody tr.info td{color:#fff}.table-bordered{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"]{color:#080808}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#ff7518}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#080808;border-color:#ff7518}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#ff0039}.control-group.error input,.control-group.error select,.control-group.error textarea{color:#080808;border-color:#ff0039}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#3fb618}.control-group.success input,.control-group.success select,.control-group.success textarea{color:#080808;border-color:#3fb618}legend{color:#080808;border-bottom:0}.form-actions{background-color:#eee;border-top:0}.dropdown-menu{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.alert{text-shadow:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.alert-heading,.alert h1,.alert h2,.alert h3,.alert h4,.alert h5,.alert h6{color:#fff}.label{min-width:80px;min-height:80px;font-weight:300;text-shadow:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.label-success{background-color:#3fb618}.label-important{background-color:#ff0039}.label-info{background-color:#9954bb}.label-inverse{background-color:#000}.badge{font-weight:300;text-shadow:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.badge-success{background-color:#3fb618}.badge-important{background-color:#ff0039}.badge-info{background-color:#9954bb}.badge-inverse{background-color:#000}.hero-unit{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.well{border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}[class^="icon-"],[class*=" icon-"]{margin:0 2px;vertical-align:-2px}a.thumbnail{background-color:#dfdfdf}a.thumbnail:hover{background-color:#bbb;border-color:transparent}.progress{height:6px;background-color:#eee;background-image:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.progress .bar{background-color:#007fff;background-image:none}.progress-info{background-color:#9954bb}.progress-success{background-color:#3fb618}.progress-warning{background-color:#ff7518}.progress-danger{background-color:#ff0039}.modal{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.modal-header{border-bottom:0}.modal-footer{background-color:transparent;border-top:0}.popover{color:#fff;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.popover-title{color:#fff;border-bottom:0}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}pre{margin-top:10px;color:#333}pre.terminal{font-size:1em;color:#c0c0c0;background:#000}.tlist li{padding-top:.3em;paddint-bottom:.3em}
diff --git a/pathod/libpathod/static/bootstrap.min.js b/pathod/libpathod/static/bootstrap.min.js
new file mode 100644
index 00000000..14356981
--- /dev/null
+++ b/pathod/libpathod/static/bootstrap.min.js
@@ -0,0 +1,6 @@
+/*!
+* Bootstrap.js by @fat & @mdo
+* Copyright 2012 Twitter, Inc.
+* http://www.apache.org/licenses/LICENSE-2.0.txt
+*/
+!function(a){a(function(){"use strict",a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=c,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(a){return a||(this.paused=!0),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j=a.Event("slide");this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h]();if(e.hasClass("active"))return;if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c);e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():f.interval&&e.cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning)return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning)return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e,f,g;if(c.is(".disabled, :disabled"))return;return f=c.attr("data-target"),f||(f=c.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,"")),e=a(f),e.length||(e=c.parent()),g=e.hasClass("open"),d(),g||e.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,a.proxy(f,this)):f.call(this)):b&&b()}function f(){this.$backdrop.remove(),this.$backdrop=null}function g(){var b=this;this.isShown&&this.options.keyboard?a(document).on("keyup.dismiss.modal",function(a){a.which==27&&b.hide()}):this.isShown||a(document).off("keyup.dismiss.modal")}"use strict";var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this))};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;a("body").addClass("modal-open"),this.isShown=!0,g.call(this),e.call(this,function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in"),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();var e=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,a("body").removeClass("modal-open"),g.call(this),this.$element.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?c.call(this):d.call(this)}},a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a(function(){a("body").on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({},e.data(),c.data());b.preventDefault(),e.modal(f)})})}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,this.options.trigger!="manual"&&(e=this.options.trigger=="hover"?"mouseenter":"focus",f=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(e,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f,this.options.selector,a.proxy(this.leave,this))),this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,b,this.$element.data()),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);if(!c.options.delay||!c.options.delay.show)return c.show();clearTimeout(this.timeout),c.hoverState="in",this.timeout=setTimeout(function(){c.hoverState=="in"&&c.show()},c.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var a,b,c,d,e,f,g;if(this.hasContent()&&this.enabled){a=this.tip(),this.setContent(),this.options.animation&&a.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,b=/in/.test(f),a.remove().css({top:0,left:0,display:"block"}).appendTo(b?this.$element:document.body),c=this.getPosition(b),d=a[0].offsetWidth,e=a[0].offsetHeight;switch(b?f.split(" ")[1]:f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}a.css(g).addClass(f).addClass("in")}},isHTML:function(a){return typeof a!="string"||a.charAt(0)==="<"&&a.charAt(a.length-1)===">"&&a.length>=3||/^(?:[^<]*<[\w\W]+>[^>]*$)/.exec(a)},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.isHTML(b)?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function d(){var b=setTimeout(function(){c.off(a.support.transition.end).remove()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.remove()})}var b=this,c=this.tip();c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d():c.remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(b){return a.extend({},b?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}},a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover",title:"",delay:0}}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.isHTML(b)?"html":"text"](b),a.find(".popover-content > *")[this.isHTML(c)?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-content")||(typeof c.content=="function"?c.content.call(b[0]):c.content),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip}}),a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}"use strict",b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var b=a(this),c=b.data("target")||b.attr("href"),d=/^#\w/.test(c)&&a(c);return d&&c.length&&[[d.position().top,c]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu")&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}},a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a(function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active a").last()[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}},a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a(function(){a("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=a(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:b.top+b.height,left:b.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c=this,d,e;return this.query=this.$element.val(),this.query?(d=a.grep(this.source,function(a){return c.matcher(a)}),d=this.sorter(d),d.length?this.render(d.slice(0,this.options.items)).show():this.shown?this.hide():this):this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),(a.browser.webkit||a.browser.msie)&&this.$element.on("keydown",a.proxy(this.keypress,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this))},keyup:function(a){switch(a.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},keypress:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:if(a.type!="keydown")break;a.preventDefault(),this.prev();break;case 40:if(a.type!="keydown")break;a.preventDefault(),this.next()}a.stopPropagation()},blur:function(a){var b=this;setTimeout(function(){b.hide()},150)},click:function(a){a.stopPropagation(),a.preventDefault(),this.select()},mouseenter:function(b){this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>'},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;b.preventDefault(),c.typeahead(c.data())})})}(window.jQuery); \ No newline at end of file
diff --git a/pathod/libpathod/static/jquery-1.7.2.min.js b/pathod/libpathod/static/jquery-1.7.2.min.js
new file mode 100644
index 00000000..16ad06c5
--- /dev/null
+++ b/pathod/libpathod/static/jquery-1.7.2.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.7.2 jquery.com | jquery.org/license */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"<!doctype html>":"")+"<html><body>"),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bD.test(a)?d(a,e):b_(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&f.type(b)==="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bZ(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bS,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bZ(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bZ(a,c,d,e,"*",g));return l}function bY(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bO),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bB(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?1:0,g=4;if(d>0){if(c!=="border")for(;e<g;e+=2)c||(d-=parseFloat(f.css(a,"padding"+bx[e]))||0),c==="margin"?d+=parseFloat(f.css(a,c+bx[e]))||0:d-=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0;return d+"px"}d=by(a,b);if(d<0||d==null)d=a.style[b];if(bt.test(d))return d;d=parseFloat(d)||0;if(c)for(;e<g;e+=2)d+=parseFloat(f.css(a,"padding"+bx[e]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+bx[e]))||0);return d+"px"}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;b.nodeType===1&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?b.outerHTML=a.outerHTML:c!=="input"||a.type!=="checkbox"&&a.type!=="radio"?c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text):(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value)),b.removeAttribute(f.expando),b.removeAttribute("_submit_attached"),b.removeAttribute("_change_attached"))}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c,i[c][d])}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h,i){var j,k=d==null,l=0,m=a.length;if(d&&typeof d=="object"){for(l in d)e.access(a,c,l,d[l],1,h,f);g=1}else if(f!==b){j=i===b&&e.isFunction(f),k&&(j?(j=c,c=function(a,b,c){return j.call(e(a),c)}):(c.call(a,f),c=null));if(c)for(;l<m;l++)c(a[l],d,j?f.call(a[l],l,c(a[l],d)):f,i);g=1}return g?a:k?c.call(a):m?c(a[0],d):h},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m,n=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?n(g):h==="function"&&(!a.unique||!p.has(g))&&c.push(g)},o=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,j=!0,m=k||0,k=0,l=c.length;for(;c&&m<l;m++)if(c[m].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}j=!1,c&&(a.once?e===!0?p.disable():c=[]:d&&d.length&&(e=d.shift(),p.fireWith(e[0],e[1])))},p={add:function(){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){j&&f<=l&&(l--,f<=m&&m--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&p.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(j?a.once||d.push([b,c]):(!a.once||!e)&&o(b,c));return this},fire:function(){p.fireWith(this,arguments);return this},fired:function(){return!!i}};return p};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p=c.createElement("div"),q=c.documentElement;p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="<div "+n+"display:block;'><div style='"+t+"0;display:block;overflow:hidden;'></div></div>"+"<table "+n+"' cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="<table><tr><td style='"+t+"0;display:none'></td><td>t</td></tr></table>",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="<div style='width:5px;'></div>",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h,i,j=this[0],k=0,m=null;if(a===b){if(this.length){m=f.data(j);if(j.nodeType===1&&!f._data(j,"parsedAttrs")){g=j.attributes;for(i=g.length;k<i;k++)h=g[k].name,h.indexOf("data-")===0&&(h=f.camelCase(h.substring(5)),l(j,h,m[h]));f._data(j,"parsedAttrs",!0)}}return m}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!";return f.access(this,function(c){if(c===b){m=this.triggerHandler("getData"+e,[d[0]]),m===b&&j&&(m=f.data(j,a),m=l(j,a,m));return m===b&&d[1]?this.data(d[0]):m}d[1]=c,this.each(function(){var b=f(this);b.triggerHandler("setData"+e,d),f.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length<d)return f.queue(this[0],a);return c===b?this:this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise(c)}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,f.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i<g;i++)e=d[i],e&&(c=f.propFix[e]||e,h=u.test(e),h||f.attr(a,e,""),a.removeAttribute(v?e:c),h&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0,coords:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(
+a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:g&&G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=f.event.special[c.type]||{},j=[],k,l,m,n,o,p,q,r,s,t,u;g[0]=c,c.delegateTarget=this;if(!i.preDispatch||i.preDispatch.call(this,c)!==!1){if(e&&(!c.button||c.type!=="click")){n=f(this),n.context=this.ownerDocument||this;for(m=c.target;m!=this;m=m.parentNode||this)if(m.disabled!==!0){p={},r=[],n[0]=m;for(k=0;k<e;k++)s=d[k],t=s.selector,p[t]===b&&(p[t]=s.quick?H(m,s.quick):n.is(t)),p[t]&&r.push(s);r.length&&j.push({elem:m,matches:r})}}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k<j.length&&!c.isPropagationStopped();k++){q=j[k],c.currentTarget=q.elem;for(l=0;l<q.matches.length&&!c.isImmediatePropagationStopped();l++){s=q.matches[l];if(h||!c.namespace&&!s.namespace||c.namespace_re&&c.namespace_re.test(s.namespace))c.data=s.data,c.handleObj=s,o=((f.event.special[s.origType]||{}).handle||s.handler).apply(q.elem,g),o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()))}}i.postDispatch&&i.postDispatch.call(this,c);return c.result}},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),d._submit_attached=!0)})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9||d===11){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.globalPOS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")[\\s/>]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f
+.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(f.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(g){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,function(a,b){b.src?f.ajax({type:"GET",global:!1,url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1></$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]==="<table>"&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i<u;i++)bn(l[i]);else bn(l);l.nodeType?j.push(l):j=f.merge(j,l)}if(d){g=function(a){return!a.type||be.test(a.type)};for(k=0;j[k];k++){h=j[k];if(e&&f.nodeName(h,"script")&&(!h.type||be.test(h.type)))e.push(h.parentNode?h.parentNode.removeChild(h):h);else{if(h.nodeType===1){var v=f.grep(h.getElementsByTagName("script"),g);j.splice.apply(j,[k+1,0].concat(v))}d.appendChild(h)}}}return j},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bp=/alpha\([^)]*\)/i,bq=/opacity=([^)]*)/,br=/([A-Z]|^ms)/g,bs=/^[\-+]?(?:\d*\.)?\d+$/i,bt=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,bu=/^([\-+])=([\-+.\de]+)/,bv=/^margin/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Top","Right","Bottom","Left"],by,bz,bA;f.fn.css=function(a,c){return f.access(this,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)},a,c,arguments.length>1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[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","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),(e===""&&f.css(d,"display")==="none"||!f.contains(d.ownerDocument.documentElement,d))&&f._data(d,"olddisplay",cu(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ct("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(ct("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o,p,q;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]);if((k=f.cssHooks[g])&&"expand"in k){l=k.expand(a[g]),delete a[g];for(i in l)i in a||(a[i]=l[i])}}for(g in a){h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cu(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cm.test(h)?(q=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),q?(f._data(this,"toggle"+i,q==="show"?"hide":"show"),j[q]()):j[h]()):(m=cn.exec(h),n=j.cur(),m?(o=parseFloat(m[2]),p=m[3]||(f.cssNumber[i]?"":"px"),p!=="px"&&(f.style(this,i,(o||1)+p),n=(o||1)/j.cur()*n,f.style(this,i,n+p)),m[1]&&(o=(m[1]==="-="?-1:1)*o+n),j.custom(n,o,p)):j.custom(n,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:ct("show",1),slideUp:ct("hide",1),slideToggle:ct("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a){return a},swing:function(a){return-Math.cos(a*Math.PI)/2+.5}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cq||cr(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){f._data(e.elem,"fxshow"+e.prop)===b&&(e.options.hide?f._data(e.elem,"fxshow"+e.prop,e.start):e.options.show&&f._data(e.elem,"fxshow"+e.prop,e.end))},h()&&f.timers.push(h)&&!co&&(co=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cq||cr(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(cp.concat.apply([],cp),function(a,b){b.indexOf("margin")&&(f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)})}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cv,cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?cv=function(a,b,c,d){try{d=a.getBoundingClientRect()}catch(e){}if(!d||!f.contains(c,a))return d?{top:d.top,left:d.left}:{top:0,left:0};var g=b.body,h=cy(b),i=c.clientTop||g.clientTop||0,j=c.clientLeft||g.clientLeft||0,k=h.pageYOffset||f.support.boxModel&&c.scrollTop||g.scrollTop,l=h.pageXOffset||f.support.boxModel&&c.scrollLeft||g.scrollLeft,m=d.top+k-i,n=d.left+l-j;return{top:m,left:n}}:cv=function(a,b,c){var d,e=a.offsetParent,g=a,h=b.body,i=b.defaultView,j=i?i.getComputedStyle(a,null):a.currentStyle,k=a.offsetTop,l=a.offsetLeft;while((a=a.parentNode)&&a!==h&&a!==c){if(f.support.fixedPosition&&j.position==="fixed")break;d=i?i.getComputedStyle(a,null):a.currentStyle,k-=a.scrollTop,l-=a.scrollLeft,a===e&&(k+=a.offsetTop,l+=a.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(a.nodeName))&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),g=e,e=a.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),j=d}if(j.position==="relative"||j.position==="static")k+=h.offsetTop,l+=h.offsetLeft;f.support.fixedPosition&&j.position==="fixed"&&(k+=Math.max(c.scrollTop,h.scrollTop),l+=Math.max(c.scrollLeft,h.scrollLeft));return{top:k,left:l}},f.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){f.offset.setOffset(this,a,b)});var c=this[0],d=c&&c.ownerDocument;if(!d)return null;if(c===d.body)return f.offset.bodyOffset(c);return cv(c,d,d.documentElement)},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); \ No newline at end of file
diff --git a/pathod/libpathod/static/jquery.localscroll-min.js b/pathod/libpathod/static/jquery.localscroll-min.js
new file mode 100644
index 00000000..3f8d64cc
--- /dev/null
+++ b/pathod/libpathod/static/jquery.localscroll-min.js
@@ -0,0 +1,9 @@
+/**
+ * jQuery.LocalScroll - Animated scrolling navigation, using anchors.
+ * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 3/11/2009
+ * @author Ariel Flesler
+ * @version 1.2.7
+ **/
+;(function($){var l=location.href.replace(/#.*/,'');var g=$.localScroll=function(a){$('body').localScroll(a)};g.defaults={duration:1e3,axis:'y',event:'click',stop:true,target:window,reset:true};g.hash=function(a){if(location.hash){a=$.extend({},g.defaults,a);a.hash=false;if(a.reset){var e=a.duration;delete a.duration;$(a.target).scrollTo(0,a);a.duration=e}i(0,location,a)}};$.fn.localScroll=function(b){b=$.extend({},g.defaults,b);return b.lazy?this.bind(b.event,function(a){var e=$([a.target,a.target.parentNode]).filter(d)[0];if(e)i(a,e,b)}):this.find('a,area').filter(d).bind(b.event,function(a){i(a,this,b)}).end().end();function d(){return!!this.href&&!!this.hash&&this.href.replace(this.hash,'')==l&&(!b.filter||$(this).is(b.filter))}};function i(a,e,b){var d=e.hash.slice(1),f=document.getElementById(d)||document.getElementsByName(d)[0];if(!f)return;if(a)a.preventDefault();var h=$(b.target);if(b.lock&&h.is(':animated')||b.onBefore&&b.onBefore.call(b,a,f,h)===false)return;if(b.stop)h.stop(true);if(b.hash){var j=f.id==d?'id':'name',k=$('<a> </a>').attr(j,d).css({position:'absolute',top:$(window).scrollTop(),left:$(window).scrollLeft()});f[j]='';$('body').prepend(k);location=e.hash;k.remove();f[j]=d}h.scrollTo(f,b).trigger('notify.serialScroll',[f])}})(jQuery); \ No newline at end of file
diff --git a/pathod/libpathod/static/jquery.scrollTo-min.js b/pathod/libpathod/static/jquery.scrollTo-min.js
new file mode 100644
index 00000000..7d4001dc
--- /dev/null
+++ b/pathod/libpathod/static/jquery.scrollTo-min.js
@@ -0,0 +1,11 @@
+/**
+ * jQuery.ScrollTo - Easy element scrolling using jQuery.
+ * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 3/9/2009
+ * @author Ariel Flesler
+ * @version 1.4.1
+ *
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
+ */
+;(function($){var m=$.scrollTo=function(b,h,f){$(window).scrollTo(b,h,f)};m.defaults={axis:'xy',duration:parseFloat($.fn.jquery)>=1.3?0:1};m.window=function(b){return $(window).scrollable()};$.fn.scrollable=function(){return this.map(function(){var b=this,h=!b.nodeName||$.inArray(b.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!h)return b;var f=(b.contentWindow||b).document||b.ownerDocument||b;return $.browser.safari||f.compatMode=='BackCompat'?f.body:f.documentElement})};$.fn.scrollTo=function(l,j,a){if(typeof j=='object'){a=j;j=0}if(typeof a=='function')a={onAfter:a};if(l=='max')l=9e9;a=$.extend({},m.defaults,a);j=j||a.speed||a.duration;a.queue=a.queue&&a.axis.length>1;if(a.queue)j/=2;a.offset=n(a.offset);a.over=n(a.over);return this.scrollable().each(function(){var k=this,o=$(k),d=l,p,g={},q=o.is('html,body');switch(typeof d){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px)?$/.test(d)){d=n(d);break}d=$(d,this);case'object':if(d.is||d.style)p=(d=$(d)).offset()}$.each(a.axis.split(''),function(b,h){var f=h=='x'?'Left':'Top',i=f.toLowerCase(),c='scroll'+f,r=k[c],s=h=='x'?'Width':'Height';if(p){g[c]=p[i]+(q?0:r-o.offset()[i]);if(a.margin){g[c]-=parseInt(d.css('margin'+f))||0;g[c]-=parseInt(d.css('border'+f+'Width'))||0}g[c]+=a.offset[i]||0;if(a.over[i])g[c]+=d[s.toLowerCase()]()*a.over[i]}else g[c]=d[i];if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],u(s));if(!b&&a.queue){if(r!=g[c])t(a.onAfterFirst);delete g[c]}});t(a.onAfter);function t(b){o.animate(g,j,a.easing,b&&function(){b.call(this,l,a)})};function u(b){var h='scroll'+b;if(!q)return k[h];var f='client'+b,i=k.ownerDocument.documentElement,c=k.ownerDocument.body;return Math.max(i[h],c[h])-Math.min(i[f],c[f])}}).end()};function n(b){return typeof b=='object'?b:{top:b,left:b}}})(jQuery); \ No newline at end of file
diff --git a/pathod/libpathod/static/pathod.css b/pathod/libpathod/static/pathod.css
new file mode 100644
index 00000000..8b23b4d5
--- /dev/null
+++ b/pathod/libpathod/static/pathod.css
@@ -0,0 +1,56 @@
+
+
+.fronttable {
+}
+
+.bigtitle {
+ font-weight: bold;
+ font-size: 50px;
+ line-height: 55px;
+ text-align: center;
+ display: table;
+ height: 300px;
+}
+
+.bigtitle>div {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+section {
+ margin-top: 50px;
+}
+
+.example {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+.terminal {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ background: #000;
+ color: #fff;
+}
+
+.innerlink {
+ text-decoration: none;
+ border-bottom:1px dotted;
+ margin-bottom: 15px;
+}
+
+.masthead {
+ padding: 50px 0 60px;
+ text-align: center;
+
+}
+
+.header {
+ font-size: 1.5em;
+}
+
+.page-header {
+ margin-top: 10px;
+
+
+}
diff --git a/pathod/libpathod/static/start_quote.png b/pathod/libpathod/static/start_quote.png
new file mode 100644
index 00000000..8090f6e8
--- /dev/null
+++ b/pathod/libpathod/static/start_quote.png
Binary files differ
diff --git a/pathod/libpathod/static/syntax.css b/pathod/libpathod/static/syntax.css
new file mode 100644
index 00000000..e371658a
--- /dev/null
+++ b/pathod/libpathod/static/syntax.css
@@ -0,0 +1,120 @@
+.highlight { background: #f8f8f8; }
+.highlight .c { color: #408080; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
+.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408080; font-style: italic } /* 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: #808080 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0040D0 } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kp { color: #008000 } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #B00040 } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BA2121 } /* Literal.String */
+.highlight .na { color: #7D9029 } /* Name.Attribute */
+.highlight .nb { color: #008000 } /* Name.Builtin */
+.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0000FF } /* Name.Function */
+.highlight .nl { color: #A0A000 } /* Name.Label */
+.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #19177C } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .sc { color: #BA2121 } /* Literal.String.Char */
+.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
+.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
+.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
+.highlight .ss { color: #19177C } /* Literal.String.Symbol */
+.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #19177C } /* Name.Variable.Class */
+.highlight .vg { color: #19177C } /* Name.Variable.Global */
+.highlight .vi { color: #19177C } /* Name.Variable.Instance */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
+.grokdoc { background: #f8f8f8; }
+.grokdoc .c { color: #408080; font-style: italic } /* Comment */
+.grokdoc .err { border: 1px solid #FF0000 } /* Error */
+.grokdoc .k { color: #008000; font-weight: bold } /* Keyword */
+.grokdoc .o { color: #666666 } /* Operator */
+.grokdoc .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.grokdoc .cp { color: #BC7A00 } /* Comment.Preproc */
+.grokdoc .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.grokdoc .cs { color: #408080; font-style: italic } /* Comment.Special */
+.grokdoc .gd { color: #A00000 } /* Generic.Deleted */
+.grokdoc .ge { font-style: italic } /* Generic.Emph */
+.grokdoc .gr { color: #FF0000 } /* Generic.Error */
+.grokdoc .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.grokdoc .gi { color: #00A000 } /* Generic.Inserted */
+.grokdoc .go { color: #808080 } /* Generic.Output */
+.grokdoc .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.grokdoc .gs { font-weight: bold } /* Generic.Strong */
+.grokdoc .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.grokdoc .gt { color: #0040D0 } /* Generic.Traceback */
+.grokdoc .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.grokdoc .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.grokdoc .kp { color: #008000 } /* Keyword.Pseudo */
+.grokdoc .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.grokdoc .kt { color: #B00040 } /* Keyword.Type */
+.grokdoc .m { color: #666666 } /* Literal.Number */
+.grokdoc .s { color: #BA2121 } /* Literal.String */
+.grokdoc .na { color: #7D9029 } /* Name.Attribute */
+.grokdoc .nb { color: #008000 } /* Name.Builtin */
+.grokdoc .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.grokdoc .no { color: #880000 } /* Name.Constant */
+.grokdoc .nd { color: #AA22FF } /* Name.Decorator */
+.grokdoc .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.grokdoc .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.grokdoc .nf { color: #0000FF } /* Name.Function */
+.grokdoc .nl { color: #A0A000 } /* Name.Label */
+.grokdoc .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.grokdoc .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.grokdoc .nv { color: #19177C } /* Name.Variable */
+.grokdoc .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.grokdoc .w { color: #bbbbbb } /* Text.Whitespace */
+.grokdoc .mf { color: #666666 } /* Literal.Number.Float */
+.grokdoc .mh { color: #666666 } /* Literal.Number.Hex */
+.grokdoc .mi { color: #666666 } /* Literal.Number.Integer */
+.grokdoc .mo { color: #666666 } /* Literal.Number.Oct */
+.grokdoc .sb { color: #BA2121 } /* Literal.String.Backtick */
+.grokdoc .sc { color: #BA2121 } /* Literal.String.Char */
+.grokdoc .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.grokdoc .s2 { color: #BA2121 } /* Literal.String.Double */
+.grokdoc .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.grokdoc .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.grokdoc .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.grokdoc .sx { color: #008000 } /* Literal.String.Other */
+.grokdoc .sr { color: #BB6688 } /* Literal.String.Regex */
+.grokdoc .s1 { color: #BA2121 } /* Literal.String.Single */
+.grokdoc .ss { color: #19177C } /* Literal.String.Symbol */
+.grokdoc .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.grokdoc .vc { color: #19177C } /* Name.Variable.Class */
+.grokdoc .vg { color: #19177C } /* Name.Variable.Global */
+.grokdoc .vi { color: #19177C } /* Name.Variable.Instance */
+.grokdoc .il { color: #666666 } /* Literal.Number.Integer.Long */
diff --git a/pathod/libpathod/static/torture.png b/pathod/libpathod/static/torture.png
new file mode 100644
index 00000000..50e245ea
--- /dev/null
+++ b/pathod/libpathod/static/torture.png
Binary files differ
diff --git a/pathod/libpathod/templates/about.html b/pathod/libpathod/templates/about.html
new file mode 100644
index 00000000..340dc386
--- /dev/null
+++ b/pathod/libpathod/templates/about.html
@@ -0,0 +1,22 @@
+{% extends "frame.html" %} {% block body %}
+<section>
+ <div class="page-header">
+ <h1>About</h1>
+ </div>
+ <div class="row">
+ <div class="span6">
+ <div>
+ <p>pathod is developed by <a href="http://corte.si">Aldo Cortesi</a>.</p>
+ </div>
+
+ <div>
+ <ul>
+ <li>email: <a href="mailto:aldo@corte.si">aldo@corte.si</a></li>
+ <li>twitter: <a href="http://twitter.com/cortesi">@cortesi</a></li>
+ <li>github: <a href="https://github.com/cortesi">github.com/cortesi</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</section>
+{% endblock %}
diff --git a/pathod/libpathod/templates/docframe.html b/pathod/libpathod/templates/docframe.html
new file mode 100644
index 00000000..4cbdeebc
--- /dev/null
+++ b/pathod/libpathod/templates/docframe.html
@@ -0,0 +1,26 @@
+{% extends "layout.html" %}
+
+{% macro subs(s) %}
+ {% if subsection == s %}
+ class="active"
+ {% endif %}
+{% endmacro %}
+
+{% block content %}
+<div class="row">
+ <div class="span3">
+ <div class="well sidebar-nav">
+ <ul class="nav nav-list">
+ <li {{subs( "pathod")}}><a href="/docs/pathod">pathod</a></li>
+ <li {{subs( "pathoc")}}><a href="/docs/pathoc">pathoc</a></li>
+ <li {{subs( "lang")}}><a href="/docs/language">language</a></li>
+ <li {{subs( "libpathod")}}><a href="/docs/libpathod">libpathod</a></li>
+ <li {{subs( "test")}}><a href="/docs/test">libpathod.test</a></li>
+ </ul>
+ </div>
+ </div>
+ <div class="span9">
+ {% block body %} {% endblock %}
+ </div>
+</div>
+{% endblock %}
diff --git a/pathod/libpathod/templates/docs_lang.html b/pathod/libpathod/templates/docs_lang.html
new file mode 100644
index 00000000..a1d22aef
--- /dev/null
+++ b/pathod/libpathod/templates/docs_lang.html
@@ -0,0 +1,196 @@
+{% extends "docframe.html" %} {% block body %}
+<div class="page-header">
+ <h1>
+ Language Spec
+ <small>The mini-language at the heart of pathoc and pathod.</small>
+ </h1>
+</div>
+
+<ul class="nav nav-tabs">
+ <li class="active"><a href="#specifying_requests" data-toggle="tab">HTTP Requests</a></li>
+ <li><a href="#specifying_responses" data-toggle="tab">HTTP Responses</a></li>
+ <li><a href="#websockets" data-toggle="tab">Websocket Frames</a></li>
+</ul>
+
+<div class="tab-content">
+ <div class="tab-pane" id="specifying_responses">
+ {% include "docs_lang_responses.html" %}
+ </div>
+ <div class="tab-pane active" id="specifying_requests">
+ {% include "docs_lang_requests.html" %}
+ </div>
+ <div class="tab-pane" id="websockets">
+ {% include "docs_lang_websockets.html" %}
+ </div>
+</div>
+
+<section id="features">
+ <div class="page-header">
+ <h1>Features</h1>
+ </div>
+
+ <a id="offsetspec"></a>
+ <h2>OFFSET</h2>
+
+ <p>
+ Offsets are calculated relative to the base message, before any injections or other
+ transforms are applied. They have 3 flavors:
+ </p>
+
+ <ul>
+ <li>An integer byte offset </li>
+ <li><b>r</b> for a random location</li>
+ <li><b>a</b> for the end of the message</li>
+ </ul>
+
+ <a id="valuespec"></a>
+ <h2>VALUE</h2>
+
+ <h3>Literals</h3>
+
+ <p>Literal values are specified as a quoted strings: </p>
+
+ <pre class="example">"foo"</pre>
+
+ <p>
+ Either single or double quotes are accepted, and quotes can be escaped with backslashes
+ within the string:
+ </p>
+
+ <pre class="example">'fo\'o'</pre>
+
+ <p>Literal values can contain Python-style backslash escape sequences:</p>
+
+ <pre class="example">'foo\r\nbar'</pre>
+
+ <h3>Files</h3>
+
+ <p>
+ You can load a value from a specified file path. To do so, you have to specify a
+ _staticdir_ option to pathod on the command-line, like so:
+ </p>
+
+ <pre class="example">pathod -d ~/myassets</pre>
+
+ <p>
+ All paths are relative paths under this directory. File loads are indicated by starting
+ the value specifier with the left angle bracket:
+ </p>
+
+ <pre class="example">&lt;my/path</pre>
+
+ <p>The path value can also be a quoted string, with the same syntax as literals:</p>
+
+ <pre class="example">&lt;"my/path"</pre>
+
+
+ <h3>Generated values</h3>
+
+ <p>
+ An @-symbol lead-in specifies that generated data should be used. There are two components
+ to a generator specification - a size, and a data type. By default pathod
+ assumes a data type of "bytes".
+ </p>
+
+ <p>Here's a value specifier for generating 100 bytes:
+
+ <pre class="example">@100</pre>
+ </p>
+
+ <p>
+ You can use standard suffixes to indicate larger values. Here, for instance, is a
+ specifier for generating 100 megabytes:
+ </p>
+
+ <pre class="example">@100m</pre>
+
+ <p>
+ Data is generated and served efficiently - if you really want to send a terabyte
+ of data to a client, pathod can do it. The supported suffixes are:
+ </p>
+
+ <table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td>b</td>
+ <td>1024**0 (bytes)</td>
+ </tr>
+ <tr>
+ <td>k</td>
+ <td>1024**1 (kilobytes)</td>
+ </tr>
+ <tr>
+ <td>m</td>
+ <td>1024**2 (megabytes)</td>
+ </tr>
+ <tr>
+ <td>g</td>
+ <td>1024**3 (gigabytes)</td>
+ </tr>
+ <tr>
+ <td>t</td>
+ <td>1024**4 (terabytes)</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <p>
+ Data types are separated from the size specification by a comma. This specification
+ generates 100mb of ASCII:
+ </p>
+
+ <pre class="example">@100m,ascii</pre>
+
+ <p>Supported data types are:</p>
+
+ <table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td>ascii</td>
+ <td>All ASCII characters</td>
+ </tr>
+ <tr>
+ <td>ascii_letters</td>
+ <td>A-Za-z</td>
+ </tr>
+ <tr>
+ <td>ascii_lowercase</td>
+ <td>a-z</td>
+ </tr>
+ <tr>
+ <td>ascii_uppercase</td>
+ <td>A-Z</td>
+ </tr>
+ <tr>
+ <td>bytes</td>
+ <td>All 256 byte values</td>
+ </tr>
+ <tr>
+ <td>digits</td>
+ <td>0-9</td>
+ </tr>
+ <tr>
+ <td>hexdigits</td>
+ <td>0-f</td>
+ </tr>
+ <tr>
+ <td>octdigits</td>
+ <td>0-7</td>
+ </tr>
+ <tr>
+ <td>punctuation</td>
+ <td>
+ <pre>!"#$%&\'()*+,-./:;
+ <=>?@[\\]^_`{|}~</pre>
+ </td>
+ </tr>
+ <tr>
+ <td>whitespace</td>
+ <td>
+ <pre>\t\n\x0b\x0c\r and space</pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</section>
+{% endblock %}
diff --git a/pathod/libpathod/templates/docs_lang_requests.html b/pathod/libpathod/templates/docs_lang_requests.html
new file mode 100644
index 00000000..81aff535
--- /dev/null
+++ b/pathod/libpathod/templates/docs_lang_requests.html
@@ -0,0 +1,114 @@
+<pre class="example">method:path:[colon-separated list of features]</pre>
+</p>
+
+<table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td>method</td>
+ <td>
+ <p>
+ A <a href="#valuespec">VALUE</a> specifying the HTTP method to
+ use. Standard methods do not need to be enclosed in quotes, while
+ non-standard methods can be specified as quoted strings.
+ </p>
+
+ <p>
+ The special method <b>ws</b> creates a valid websocket upgrade
+ GET request, and signals to pathoc to switch to websocket recieve
+ mode if the server responds correctly. Apart from that, websocket
+ requests are just like any other, and all aspects of the request
+ can be over-ridden.
+ </p>
+ </td>
+ </tr>
+
+ <tr>
+ <td>h<a href="#valuespec">VALUE</a>=<a href="#valuespec">VALUE</a></td>
+ <td>
+ Set a header.
+ </td>
+ </tr>
+
+ <tr>
+ <td>r</td>
+ <td>
+ Set the "raw" flag on this response. Pathod will not calculate a Content-Length header
+ if a body is set.
+ </td>
+ </tr>
+
+ <tr>
+ <td>c<a href="#valuespec">VALUE</a></td>
+ <td>
+ A shortcut for setting the Content-Type header. Equivalent to h"Content-Type"=VALUE
+ </td>
+ </tr>
+
+ <tr>
+ <td>u<a href="#valuespec">VALUE</a>
+ <br> uSHORTCUT
+ </td>
+
+ <td>
+ Set a User-Agent header on this request. You can specify either a complete
+ <a href="#valuespec">VALUE</a>, or a User-Agent shortcut:
+
+ <table class="table table-condensed">
+ {% for i in uastrings %}
+ <tr>
+ <td><b>{{ i[1] }}</b></td>
+ <td>{{ i[0] }}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>b<a href="#valuespec">VALUE</a></td>
+ <td>
+ Set the body. The appropriate Content-Length header is added automatically unless
+ the "r" flag is set.
+ </td>
+ </tr>
+
+ <tr>
+ <td>s<a href="#valuespec">VALUE</a></td>
+ <td>
+ An embedded Response specification, appended to the path of the request.
+ </td>
+ </tr>
+
+ <tr>
+ <td>x<a href="#valuespec">INTEGER</a></td>
+ <td>
+ Repeat this message N times.
+ </td>
+ </tr>
+
+ <tr>
+ <td>d<a href="#offsetspec">OFFSET</a></td>
+ <td>
+ <span class="badge badge-info">HTTP/1 only</span> Disconnect after
+ OFFSET bytes.
+ </td>
+ </tr>
+
+ <tr>
+ <td>i<a href="#offsetspec">OFFSET</a>,<a href="#valuespec">VALUE</a></td>
+ <td>
+ <span class="badge badge-info">HTTP/1 only</span> Inject the specified
+ value at the offset.
+ </td>
+ </tr>
+
+ <tr>
+ <td>p<a href="#offsetspec">OFFSET</a>,SECONDS</td>
+ <td>
+ <span class="badge badge-info">HTTP/1 only</span> Pause for SECONDS
+ seconds after OFFSET bytes. SECONDS can be an integer or "f" to pause
+ forever.
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/pathod/libpathod/templates/docs_lang_responses.html b/pathod/libpathod/templates/docs_lang_responses.html
new file mode 100644
index 00000000..9a85ff1a
--- /dev/null
+++ b/pathod/libpathod/templates/docs_lang_responses.html
@@ -0,0 +1,88 @@
+<pre class="example">code:[colon-separated list of features]</pre>
+
+<table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td>code</td>
+ <td>
+ <p>An integer specifying the HTTP response code.</p>
+ <p>
+ The special method <b>ws</b> creates a valid websocket upgrade
+ response (code 101), and moves pathod to websocket mode. Apart
+ from that, websocket responses are just like any other, and all
+ aspects of the response can be over-ridden.
+ </p>
+ </td>
+ </tr>
+
+ <tr>
+ <td>m<a href="#valuespec">VALUE</a></td>
+ <td>
+ <span class="badge badge-info">HTTP/1 only</span> HTTP Reason message.
+ Automatically chosen according to the response code if not specified.
+ </td>
+ </tr>
+
+ <tr>
+ <td>h<a href="#valuespec">VALUE</a>=<a href="#valuespec">VALUE</a></td>
+ <td>
+ Set a header.
+ </td>
+ </tr>
+
+ <tr>
+ <td>r</td>
+ <td>
+ Set the "raw" flag on this response. Pathod will not calculate a Content-Length header
+ if a body is set, or add a Date header to the response.
+ </td>
+ </tr>
+
+ <tr>
+ <td>l<a href="#valuespec">VALUE</a></td>
+ <td>
+ A shortcut for setting the Location header. Equivalent to h"Location"=VALUE
+ </td>
+ </tr>
+
+ <tr>
+ <td>c<a href="#valuespec">VALUE</a></td>
+ <td>
+ A shortcut for setting the Content-Type header. Equivalent to h"Content-Type"=VALUE
+ </td>
+ </tr>
+
+ <tr>
+ <td>b<a href="#valuespec">VALUE</a></td>
+ <td>
+ Set the body. The appropriate Content-Length header is added automatically unless
+ the "r" flag is set.
+ </td>
+ </tr>
+
+ <tr>
+ <td>d<a href="#offsetspec">OFFSET</a></td>
+ <td>
+ <span class="badge badge-info">HTTP/1 only</span> Disconnect after
+ OFFSET bytes.
+ </td>
+ </tr>
+
+ <tr>
+ <td>i<a href="#offsetspec">OFFSET</a>,<a href="#valuespec">VALUE</a></td>
+ <td>
+ <span class="badge badge-info">HTTP/1 only</span> Inject the specified
+ value at the offset.
+ </td>
+ </tr>
+
+ <tr>
+ <td>p<a href="#offsetspec">OFFSET</a>,SECONDS</td>
+ <td>
+ <span class="badge badge-info">HTTP/1 only</span> Pause for SECONDS
+ seconds after OFFSET bytes. SECONDS can be an integer or "f" to pause
+ forever.
+ </td>
+ </tr>
+ </tbody>
+</table>
diff --git a/pathod/libpathod/templates/docs_lang_websockets.html b/pathod/libpathod/templates/docs_lang_websockets.html
new file mode 100644
index 00000000..dd318e0b
--- /dev/null
+++ b/pathod/libpathod/templates/docs_lang_websockets.html
@@ -0,0 +1,115 @@
+<pre class="example">wf:[colon-separated list of features]</pre>
+</p>
+
+<table class="table table-bordered">
+ <tbody>
+
+ <tr>
+ <td> b<a href="#valuespec">VALUE</a> </td>
+ <td>
+ Set the frame payload. If a masking key is present, the value is encoded automatically.
+ </td>
+ </tr>
+
+ <tr>
+ <td> c<a href="#valuespec">INTEGER</a> </td>
+ <td>
+
+ Set the op code. This can either be an integer from 0-15, or be one of the following
+ opcode names: <b>text</b> (the default),
+ <b>continue</b>, <b>binary</b>, <b>close</b>, <b>ping</b>,
+ <b>pong</b>.
+
+ </td>
+ </tr>
+
+ <tr>
+ <td> d<a href="#offsetspec">OFFSET</a> </td>
+ <td>
+ Disconnect after OFFSET bytes.
+ </td>
+ </tr>
+
+ <tr>
+ <td> [-]fin </td>
+ <td>
+ Set or un-set the <b>fin</b> bit.
+ </td>
+ </tr>
+
+ <tr>
+ <td> i<a href="#offsetspec">OFFSET</a>,<a href="#valuespec">VALUE</a> </td>
+ <td>
+ Inject the specified value at the offset.
+ </td>
+ </tr>
+
+ <tr>
+ <td> k<a href="#valuespec">VALUE</a> </td>
+ <td>
+ Set the masking key. The resulting value must be exactly 4 bytes long. The special
+ form
+ <b>knone</b> specifies that no key should be set, even if the mask
+ bit is on.
+ </td>
+ </tr>
+
+ <tr>
+ <td> l<a href="#valuespec">INTEGER</a> </td>
+ <td>
+ Set the payload length in the frame header, regardless of the actual body length.
+ </td>
+ </tr>
+
+ <tr>
+ <td> [-]mask </td>
+ <td>
+ Set or un-set the <b>mask</b> bit.
+ </td>
+ </tr>
+
+ <tr>
+ <td> p<a href="#offsetspec">OFFSET</a>,SECONDS </td>
+ <td>
+ Pause for SECONDS seconds after OFFSET bytes. SECONDS can be an integer or "f" to
+ pause forever.
+ </td>
+ </tr>
+
+ <tr>
+ <td> r<a href="#valuespec">VALUE</a> </td>
+ <td>
+ Set the raw frame payload. This disables masking, even if the key is present.
+ </td>
+ </tr>
+
+ <tr>
+ <td> [-]rsv1 </td>
+ <td>
+ Set or un-set the <b>rsv1</b> bit.
+ </td>
+ </tr>
+
+ <tr>
+ <td> [-]rsv2 </td>
+ <td>
+ Set or un-set the <b>rsv2</b> bit.
+ </td>
+ </tr>
+
+ <tr>
+ <td> [-]rsv3 </td>
+ <td>
+ Set or un-set the <b>rsv3</b> bit.
+ </td>
+ </tr>
+
+ <tr>
+ <td> x<a href="#valuespec">INTEGER</a> </td>
+ <td>
+ Repeat this message N times.
+ </td>
+ </tr>
+
+ </tbody>
+</table>
diff --git a/pathod/libpathod/templates/docs_libpathod.html b/pathod/libpathod/templates/docs_libpathod.html
new file mode 100644
index 00000000..6d504fe5
--- /dev/null
+++ b/pathod/libpathod/templates/docs_libpathod.html
@@ -0,0 +1,23 @@
+{% extends "docframe.html" %} {% block body %}
+<div class="page-header">
+ <h1>
+ libpathod
+ <small>Using pathod and pathoc in code.</small>
+ </h1>
+</div>
+
+<div class="row">
+ <div class="span6">
+ <p>
+ Behind the pathod and pathoc command-line tools lurks <b>libpathod</b>,
+ a powerful library for manipulating and serving HTTP requests and responses.
+ The canonical documentation for the library is in the code, and can be
+ accessed using pydoc.
+ </p>
+ </div>
+ <div class="span6">
+ <h1>pathoc</h1>
+ {% include "libpathod_pathoc.html" %}
+ </div>
+</div>
+{% endblock %}
diff --git a/pathod/libpathod/templates/docs_pathoc.html b/pathod/libpathod/templates/docs_pathoc.html
new file mode 100644
index 00000000..d38c3a77
--- /dev/null
+++ b/pathod/libpathod/templates/docs_pathoc.html
@@ -0,0 +1,211 @@
+{% extends "docframe.html" %} {% block body %}
+<div class="page-header">
+ <h1>
+ pathoc
+ <small>A perverse HTTP client.</small>
+ </h1>
+</div>
+
+<p>
+ Pathoc is a perverse HTTP daemon designed to let you craft almost any conceivable
+ HTTP request, including ones that creatively violate the standards. HTTP requests
+ are specified using a
+ <a href="/docs/language">small, terse language</a>, which pathod shares with
+ its server-side twin <a href="/docs/pathod">pathod</a>. To view pathoc's complete
+ range of options, use the command-line help:
+</p>
+
+<pre class="terminal">pathoc --help</pre>
+
+<section>
+ <div class="page-header">
+ <h1>Getting Started</h1>
+ </div>
+
+ <p>The basic pattern for pathoc commands is as follows: </p>
+
+ <pre class="terminal">pathoc hostname request [request ...]</pre>
+
+ <p>
+ That is, we specify the hostname to connect to, followed by one or more requests.
+ Lets start with a simple example:
+ </p>
+
+ <pre class="terminal">
+ &gt; pathoc google.com get:/ &lt;&lt; 301 Moved Permanently: 219 bytes
+ </pre>
+
+ <p>
+ Here, we make a GET request to the path / on port 80 of google.com. Pathoc's output
+ tells us that the server responded with a 301. We can tell pathoc to connect
+ using SSL, in which case the default port is changed to 443 (you can over-ride
+ the default port with the <b>-p</b> command-line option):
+ </p>
+
+ <pre class="terminal">
+ &gt; pathoc -s google.com get:/ &lt;&lt; 301 Moved Permanently: 219 bytes
+ </pre>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>Multiple Requests</h1>
+ </div>
+
+ <p>
+ There are two ways to tell pathoc to issue multiple requests. The first is to specify
+ them on the command-line, like so:
+ </p>
+
+ <pre class="terminal">
+ &gt; pathoc google.com get:/ get:/ &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt;
+ 301 Moved Permanently: 219 bytes
+ </pre>
+
+ <p>
+ In this case, pathoc issues the specified requests over the same TCP connection -
+ so in the above example only one connection is made to google.com
+ </p>
+
+ <p>The other way to issue multiple requets is to use the <b>-n</b> flag:</p>
+
+ <pre class="terminal">
+ &gt; pathoc -n 2 google.com get:/ &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt; 301
+ Moved Permanently: 219 bytes
+ </pre>
+
+ <p>
+ The output is identical, but two separate TCP connections are made to the upstream
+ server. These two specification styles can be combined:
+ </p>
+
+ <pre class="terminal">
+ &gt; pathoc -n 2 google.com get:/ get:/ &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt;
+ 301 Moved Permanently: 219 bytes &lt;&lt; 301 Moved Permanently: 219 bytes &lt;&lt;
+ 301 Moved Permanently: 219 bytes
+ </pre>
+
+ <p>Here, two distinct TCP connections are made, with two requests issued over each.</p>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>Basic Fuzzing</h1>
+ </div>
+
+ <p>
+ The combination of pathoc's powerful request specification language and a few of
+ its command-line options makes for quite a powerful basic fuzzer. Here's
+ an example:
+ </p>
+
+ <pre class="terminal">
+ &gt; pathoc -e -I 200 -t 2 -n 1000 localhost get:/:b@10:ir,@1
+ </pre>
+
+ <p>
+ The request specified here is a valid GET with a body consisting of 10 random bytes,
+ but with 1 random byte inserted in a random place. This could be in the headers,
+ in the initial request line, or in the body itself. There are a few things
+ to note here:
+ </p>
+
+ <ul>
+ <li>
+ Corrupting the request in this way will often make the server enter a state where
+ it's awaiting more input from the client. This is where the
+ <b>-t</b> option comes in, which sets a timeout that causes pathoc to
+ disconnect after two seconds.
+ </li>
+
+ <li>
+ The <b>-n</b> option tells pathoc to repeat the request 1000 times.
+ </li>
+
+ <li>
+ The <b>-I</b> option tells pathoc to ignore HTTP 200 response codes.
+ You can use this to fine-tune what pathoc considers to be an exceptional
+ condition, and therefore log-worthy.
+ </li>
+
+ <li>
+ The <b>-e</b> option tells pathoc to print an explanation of each logged
+ request, in the form of an expanded pathoc specification with all random
+ portions and automatic header additions resolved. This lets you precisely
+ replay a request that triggered an error.
+ </li>
+ </ul>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>Interacting with Proxies</h1>
+ </div>
+
+ <p>
+ Pathoc has a reasonably sophisticated suite of features for interacting with proxies.
+ The proxy request syntax very closely mirrors that of straight HTTP, which
+ means that it is possible to make proxy-style requests using pathoc without
+ any additional syntax, by simply specifying a full URL instead of a simple
+ path:
+ </p>
+
+ <pre class="terminal">&gt; pathoc -p 8080 localhost "get:'http://google.com'"</pre>
+
+ <p>
+ Another common use case is to use an HTTP CONNECT request to probe remote servers
+ via a proxy. This is done with the <b>-c</b> command-line option,
+ which allows you to specify a remote host and port pair:
+ </p>
+
+ <pre class="terminal">&gt; pathoc -c google.com:80 -p 8080 localhost get:/</pre>
+
+ <p>
+ Note that pathoc does <b>not</b> negotiate SSL without being explictly instructed
+ to do so. If you're making a CONNECT request to an SSL-protected resource,
+ you must also pass the <b>-s</b> flag:
+ </p>
+
+ <pre class="terminal">&gt; pathoc -sc google.com:443 -p 8080 localhost get:/</pre>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>Embedded response specification</h1>
+ </div>
+
+ <p>
+ One interesting feature of the Request sppecification language is that you can embed
+ a response specifcation in it, which is then added to the request path. Here's
+ an example:
+ </p>
+
+ <pre class="terminal">&gt; pathoc localhost:9999 "get:/p/:s'401:ir,@1'"</pre>
+
+ <p>
+ This crafts a request that connects to the pathod server, and which then crafts a
+ response that generates a 401, with one random byte embedded at a random
+ point. The response specification is parsed and expanded by pathoc, so you
+ see syntax errors immediately. This really becomes handy when combined with
+ the <b>-e</b> flag to show the expanded request:
+ </p>
+
+ <pre class="terminal">
+ &gt; > pathoc -e localhost:9999 "get:/p/:s'401:ir,@1'" >> Spec: get:/p/:s'401:i15,\'o\':h\'Content-Length\'=\'0\'':h'Content-Length'='0'
+ << 401 Unoauthorized: 0 bytes </pre>
+
+ <p>
+ Note that the embedded response has been resolved <i>before</i> being sent
+ to the server, so that "ir,@1" (embed a random byte at a random location)
+ has become "i15,\'o\'" (embed the character "o" at offset 15). You now have
+ a pathoc request specification that is precisely reproducable, even with
+ random components. This feature comes in terribly handy when testing a proxy,
+ since you can now drive the server repsonse completely from the client, and
+ have a complete log of reproducible requests to analyse afterwards.
+ </p>
+</section>
+{% endblock %}
diff --git a/pathod/libpathod/templates/docs_pathod.html b/pathod/libpathod/templates/docs_pathod.html
new file mode 100644
index 00000000..0d0ae933
--- /dev/null
+++ b/pathod/libpathod/templates/docs_pathod.html
@@ -0,0 +1,172 @@
+{% extends "docframe.html" %} {% block body %}
+<div class="page-header">
+ <h1>
+ pathod
+ <small>A pathological web daemon.</small>
+ </h1>
+</div>
+
+<p>
+ Pathod is a pathological HTTP daemon designed to let you craft almost any conceivable
+ HTTP response, including ones that creatively violate the standards. HTTP responses
+ are specified using a
+ <a href="/docs/language">small, terse language</a>, which pathod shares with
+ its evil twin <a href="/docs/pathoc">pathoc</a>.
+</p>
+
+<section>
+ <div class="page-header">
+ <h1>Getting started</h1>
+ </div>
+
+ <p>To start playing with pathod, simply fire up the daemon:</p>
+
+ <pre class="terminal">./pathod</pre>
+
+ <p>
+ By default, the service listens on port 9999 of localhost. Pathod's documentation
+ is self-hosting, and the pathod daemon exposes an interface that lets you
+ play with the specifciation language, preview what responses and requests
+ would look like on the wire, and view internal logs. To access all of this,
+ just fire up your browser, and point it to the following URL:
+ </p>
+
+ <pre class="example">http://localhost:9999</pre>
+
+ <p>
+ The default crafting anchor point is the path <b>/p/</b>. Anything after
+ this URL prefix is treated as a response specifier. So, hitting the following
+ URL will generate an HTTP 200 response with 100 bytes of random data:
+ </p>
+
+ <pre class="example">http://localhost:9999/p/200:b@100</pre>
+
+ <p>
+ See the <a href="/docs/language">language documentation</a> to get (much)
+ fancier. The pathod daemon also takes a range of configuration options. To
+ view those, use the command-line help:
+ </p>
+
+ <pre class="terminal">./pathod --help</pre>
+
+</section>
+
+<section>
+ <div class="page-header">
+ <h1>Acting as a proxy</h1>
+ </div>
+
+ <p>
+ Pathod automatically responds to both straight HTTP and proxy requests. For proxy
+ requests, the upstream host is ignored, and the path portion of the URL is
+ used to match anchors. This lets you test software that supports a proxy
+ configuration by spoofing responses from upstream servers.
+ </p>
+
+ <p>
+ By default, we treat all proxy CONNECT requests as HTTPS traffic, serving the response
+ using either pathod's built-in certificates, or the cert/key pair specified
+ by the user. You can over-ride this behaviour if you're testing a client
+ that makes a non-SSL CONNECT request using the -C command-line option.
+ </p>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>Anchors</h1>
+ </div>
+
+ <p>
+ Anchors provide an alternative to specifying the response in the URL. Instead, you
+ attach a response to a pre-configured anchor point, specified with a regex.
+ When a URL matching the regex is requested, the specified response is served.
+ </p>
+
+ <pre class="terminal">./pathod -a "/foo=200"</pre>
+
+ <p>
+ Here, "/foo" is the regex specifying the anchor path, and the part after the "="
+ is a response specifier.
+ </p>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>File Access</h1>
+ </div>
+
+ <p>
+ There are two operators in the <a href="/docs/language">language</a> that
+ load contents from file - the <b>+</b> operator to load an entire request
+ specification from file, and the <b>&gt;</b> value specifier. In pathod,
+ both of these operators are restricted to a directory specified at startup,
+ or disabled if no directory is specified:</p>
+ <pre class="terminal">./pathod -d ~/staticdir"</pre>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>Internal Error Responses</h1>
+ </div>
+
+ <p>
+ Pathod uses the non-standard 800 response code to indicate internal errors, to distinguish
+ them from crafted responses. For example, a request to:
+ </p>
+
+ <pre class="example">http://localhost:9999/p/foo</pre>
+
+ <p>
+ ... will return an 800 response because "foo" is not a valid page specifier.
+ </p>
+</section>
+
+
+<section>
+ <div class="page-header">
+ <h1>API</h1>
+ </div>
+
+ <p>
+ pathod exposes a simple API, intended to make it possible to drive and inspect the
+ daemon remotely for use in unit testing and the like.
+ </p>
+
+ <table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td>
+ /api/clear_log
+ </td>
+ <td>
+ A POST to this URL clears the log buffer.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ /api/info
+ </td>
+ <td>
+ Basic version and configuration info.
+ </td>
+ </tr>
+ <tr>
+ <td>
+ /api/log
+ </td>
+ <td>
+ Returns the current log buffer. At the moment the buffer size is 500 entries - when
+ the log grows larger than this, older entries are discarded.
+ The returned data is a JSON dictionary, with the form:
+
+ <pre>{ 'log': [ ENTRIES ] } </pre> You can preview the JSON data
+ returned for a log entry through the built-in web interface.
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</section>
+{% endblock %}
diff --git a/pathod/libpathod/templates/docs_test.html b/pathod/libpathod/templates/docs_test.html
new file mode 100644
index 00000000..0502c984
--- /dev/null
+++ b/pathod/libpathod/templates/docs_test.html
@@ -0,0 +1,50 @@
+{% extends "docframe.html" %} {% block body %}
+<div class="page-header">
+ <h1>
+ libpathod.test
+ <small>Using libpathod in unit tests.</small>
+ </h1>
+</div>
+
+<p>The <b>libpathod.test</b> module is a light, flexible testing layer for HTTP clients.
+ It works by firing up a Pathod instance in a separate thread, letting you use
+ Pathod's full abilities to generate responses, and then query Pathod's internal
+ logs to establish what happened. All the mechanics of startup, shutdown, finding
+ free ports and so forth are taken care of for you.
+</p>
+
+<p>The canonical docs can be accessed using pydoc: </p>
+
+<pre class="terminal">pydoc libpathod.test</pre>
+
+<p>
+ The remainder of this page demonstrates some common interaction patterns using
+ <a href="http://nose.readthedocs.org/en/latest/">nose</a>. These examples are
+ also applicable with only minor modification to most commonly used Python testing
+ engines.
+</p>
+
+<section>
+ <div class="page-header">
+ <h1>Context Manager</h1>
+ </div>
+
+ {% include "examples_context.html" %}
+</section>
+
+<section>
+ <div class="page-header">
+ <h1>One instance per test</h1>
+ </div>
+
+ {% include "examples_setup.html" %}
+</section>
+
+<section>
+ <div class="page-header">
+ <h1>One instance per suite</h1>
+ </div>
+
+ {% include "examples_setupall.html" %}
+</section>
+{% endblock %}
diff --git a/pathod/libpathod/templates/download.html b/pathod/libpathod/templates/download.html
new file mode 100644
index 00000000..bd8950e8
--- /dev/null
+++ b/pathod/libpathod/templates/download.html
@@ -0,0 +1,39 @@
+{% extends "frame.html" %} {% block body %}
+<section>
+ <div class="page-header">
+ <h1>pip</h1>
+ </div>
+
+ <p>The easiest way to install pathod is to use pip:</p>
+
+ <pre>pip install pathod</pre>
+
+ <p>
+ This will automatically pull in all the dependencies, and you should be good to go.
+ </p>
+</section>
+
+<section>
+ <div class="page-header">
+ <h1>github</h1>
+ </div>
+
+ <p>You can find the project source on GitHub:</p>
+
+ <div style="margin-top: 20px; margin-bottom: 20px">
+ <a class="btn btn-primary btn-large" href="https://github.com/mitmproxy/pathod">github.com/mitmproxy/pathod</a>
+ </div>
+
+ <p>Please also use the <a href="https://github.com/mitmproxy/pathod/issues">github issue tracker</a> to report bugs.</p>
+</section>
+
+<section>
+ <div class="page-header">
+ <h1>tarball</h1>
+ </div>
+
+ <div style="margin-top: 20px; margin-bottom: 20px">
+ <a class="btn btn-primary btn-large" href="https://github.com/downloads/mitmproxy/pathod/pathod-{{version}}.tar.gz">pathod-{{version}}.tar.gz</a>
+ </div>
+</section>
+{% endblock %}
diff --git a/pathod/libpathod/templates/examples_context.html b/pathod/libpathod/templates/examples_context.html
new file mode 100644
index 00000000..afb3bd48
--- /dev/null
+++ b/pathod/libpathod/templates/examples_context.html
@@ -0,0 +1,24 @@
+<div class="highlight"><pre><span class="kn">import</span> <span class="nn">requests</span>
+<span class="kn">from</span> <span class="nn">libpathod</span> <span class="kn">import</span> <span class="n">test</span>
+
+
+<span class="k">def</span> <span class="nf">test_simple</span><span class="p">():</span>
+ <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> Testing the requests module with</span>
+<span class="sd"> a pathod context manager.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="c"># Start pathod in a separate thread</span>
+ <span class="k">with</span> <span class="n">test</span><span class="o">.</span><span class="n">Daemon</span><span class="p">()</span> <span class="k">as</span> <span class="n">d</span><span class="p">:</span>
+ <span class="c"># Get a URL for a pathod spec</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">d</span><span class="o">.</span><span class="n">p</span><span class="p">(</span><span class="s">&quot;200:b@100&quot;</span><span class="p">)</span>
+ <span class="c"># ... and request it</span>
+ <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
+
+ <span class="c"># Check the returned data</span>
+ <span class="k">assert</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span>
+ <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span>
+
+ <span class="c"># Check pathod&#39;s internal log</span>
+ <span class="n">log</span> <span class="o">=</span> <span class="n">d</span><span class="o">.</span><span class="n">last_log</span><span class="p">()[</span><span class="s">&quot;request&quot;</span><span class="p">]</span>
+ <span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;PUT&quot;</span>
+</pre></div>
diff --git a/pathod/libpathod/templates/examples_setup.html b/pathod/libpathod/templates/examples_setup.html
new file mode 100644
index 00000000..c2da1cd1
--- /dev/null
+++ b/pathod/libpathod/templates/examples_setup.html
@@ -0,0 +1,32 @@
+<div class="highlight"><pre><span class="kn">import</span> <span class="nn">requests</span>
+<span class="kn">from</span> <span class="nn">libpathod</span> <span class="kn">import</span> <span class="n">test</span>
+
+
+<span class="k">class</span> <span class="nc">Test</span><span class="p">:</span>
+
+ <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> Testing the requests module with</span>
+<span class="sd"> a pathod instance started for</span>
+<span class="sd"> each test.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">d</span> <span class="o">=</span> <span class="n">test</span><span class="o">.</span><span class="n">Daemon</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">shutdown</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">test_simple</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="c"># Get a URL for a pathod spec</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">p</span><span class="p">(</span><span class="s">&quot;200:b@100&quot;</span><span class="p">)</span>
+ <span class="c"># ... and request it</span>
+ <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
+
+ <span class="c"># Check the returned data</span>
+ <span class="k">assert</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span>
+ <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span>
+
+ <span class="c"># Check pathod&#39;s internal log</span>
+ <span class="n">log</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">last_log</span><span class="p">()[</span><span class="s">&quot;request&quot;</span><span class="p">]</span>
+ <span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;PUT&quot;</span>
+</pre></div>
diff --git a/pathod/libpathod/templates/examples_setupall.html b/pathod/libpathod/templates/examples_setupall.html
new file mode 100644
index 00000000..629d11e0
--- /dev/null
+++ b/pathod/libpathod/templates/examples_setupall.html
@@ -0,0 +1,40 @@
+<div class="highlight"><pre><span class="kn">import</span> <span class="nn">requests</span>
+<span class="kn">from</span> <span class="nn">libpathod</span> <span class="kn">import</span> <span class="n">test</span>
+
+
+<span class="k">class</span> <span class="nc">Test</span><span class="p">:</span>
+
+ <span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> Testing the requests module with</span>
+<span class="sd"> a single pathod instance started</span>
+<span class="sd"> for the test suite.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="nd">@classmethod</span>
+ <span class="k">def</span> <span class="nf">setUpAll</span><span class="p">(</span><span class="n">cls</span><span class="p">):</span>
+ <span class="n">cls</span><span class="o">.</span><span class="n">d</span> <span class="o">=</span> <span class="n">test</span><span class="o">.</span><span class="n">Daemon</span><span class="p">()</span>
+
+ <span class="nd">@classmethod</span>
+ <span class="k">def</span> <span class="nf">tearDownAll</span><span class="p">(</span><span class="n">cls</span><span class="p">):</span>
+ <span class="n">cls</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">shutdown</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="c"># Clear the pathod logs between tests</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">clear_log</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">test_simple</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="c"># Get a URL for a pathod spec</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">p</span><span class="p">(</span><span class="s">&quot;200:b@100&quot;</span><span class="p">)</span>
+ <span class="c"># ... and request it</span>
+ <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
+
+ <span class="c"># Check the returned data</span>
+ <span class="k">assert</span> <span class="n">r</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span>
+ <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">100</span>
+
+ <span class="c"># Check pathod&#39;s internal log</span>
+ <span class="n">log</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">last_log</span><span class="p">()[</span><span class="s">&quot;request&quot;</span><span class="p">]</span>
+ <span class="k">assert</span> <span class="n">log</span><span class="p">[</span><span class="s">&quot;method&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;PUT&quot;</span>
+
+ <span class="k">def</span> <span class="nf">test_two</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">assert</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">d</span><span class="o">.</span><span class="n">log</span><span class="p">()</span>
+</pre></div>
diff --git a/pathod/libpathod/templates/frame.html b/pathod/libpathod/templates/frame.html
new file mode 100644
index 00000000..4223458d
--- /dev/null
+++ b/pathod/libpathod/templates/frame.html
@@ -0,0 +1,7 @@
+{% extends "layout.html" %} {% block content %}
+<div class="row">
+ <div class="span12">
+ {% block body %} {% endblock %}
+ </div>
+</div>
+{% endblock %}
diff --git a/pathod/libpathod/templates/index.html b/pathod/libpathod/templates/index.html
new file mode 100644
index 00000000..a85a4040
--- /dev/null
+++ b/pathod/libpathod/templates/index.html
@@ -0,0 +1,60 @@
+{% extends "frame.html" %} {% block body %}
+<div class="masthead">
+ <div class="container">
+ <h1>pathod: pathological HTTP</h1>
+
+ <p>Crafted malice for tormenting HTTP clients and servers</p>
+
+ <img src="/static/torture.png">
+ </div>
+</div>
+
+<div class="row">
+ <div class="span6">
+ <div>
+ <h2><a href="/docs/pathod">pathod</a></h2>
+
+ <p>A pathological web daemon.</p>
+
+ {% include "response_previewform.html" %}
+ <br>
+ </div>
+ </div>
+
+ <div class="span6">
+ <div>
+ <h2><a href="/docs/pathoc">pathoc</a></h2>
+
+ <p>A perverse HTTP client.</p>
+
+ {% include "request_previewform.html" %}
+ </div>
+ </div>
+</div>
+
+<section>
+ <div class="page-header">
+ <h1>Install</h1>
+ </div>
+ <div class="row">
+ <div class="span6">
+ <div>
+ <h2>pip</h2>
+
+ <pre>pip install pathod</pre>
+ </div>
+ </div>
+
+ <div class="span6">
+ <div>
+ <h2>source</h2>
+
+ <ul>
+ <li>Current release: <a href="http://mitmproxy.org/download/pathod-{{version}}.tar.gz">pathod {{version}}</a></li>
+ <li>GitHub: <a href="https://github.com/mitmproxy/pathod">github.com/mitmproxy/pathod</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</section>
+{% endblock %}
diff --git a/pathod/libpathod/templates/layout.html b/pathod/libpathod/templates/layout.html
new file mode 100644
index 00000000..af2857b1
--- /dev/null
+++ b/pathod/libpathod/templates/layout.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="utf-8">
+ <title>pathod</title>
+ <link href="/static/bootstrap.min.css" rel="stylesheet">
+ <link href="/static/pathod.css" rel="stylesheet">
+ <link href="/static/syntax.css" rel="stylesheet">
+ <script src="/static/jquery-1.7.2.min.js"></script>
+ <script src="/static/jquery.scrollTo-min.js"></script>
+ <script src="/static/jquery.localscroll-min.js"></script>
+ <script src="/static/bootstrap.min.js"></script>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="description" content="">
+ <meta name="author" content="">
+ <style type="text/css">
+ body {
+ padding-top: 60px;
+ padding-bottom: 40px;
+ }
+
+ </style>
+ <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+</head>
+
+<body>
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </a>
+ <a class="brand" href="/index.html">pathod</a>
+ <div class="nav-collapse">
+ <ul class="nav">
+ <li {% if section=="main" %} class="active" {% endif %}><a href="/">home</a></li>
+ {% if not noapi %}
+ <li {% if section=="log" %} class="active" {% endif %}><a href="/log">log</a></li>
+ {% endif %}
+ <li {% if section=="docs" %} class="active" {% endif %}><a href="/docs/pathod">docs</a></li>
+ <li {% if section=="about" %} class="active" {% endif %}><a href="/about">about</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ {% block content %} {% endblock %}
+ <hr>
+ <footer>
+ <span>&copy; Aldo Cortesi 2015</span>
+ <span class="pull-right">[served with pathod]</span>
+ </footer>
+ </div>
+</body>
+<script>
+ $(function() {
+ $.localScroll({
+ duration: 300,
+ offset: {
+ top: -45
+ }
+ });
+ });
+
+</script>
+
+</html>
diff --git a/pathod/libpathod/templates/libpathod_pathoc.html b/pathod/libpathod/templates/libpathod_pathoc.html
new file mode 100644
index 00000000..f5871b16
--- /dev/null
+++ b/pathod/libpathod/templates/libpathod_pathoc.html
@@ -0,0 +1,8 @@
+<div class="highlight"><pre><span class="c">#!/usr/bin/env python</span>
+<span class="kn">from</span> <span class="nn">libpathod</span> <span class="kn">import</span> <span class="n">pathoc</span>
+
+<span class="n">p</span> <span class="o">=</span> <span class="n">pathoc</span><span class="o">.</span><span class="n">Pathoc</span><span class="p">((</span><span class="s">&quot;google.com&quot;</span><span class="p">,</span> <span class="mi">80</span><span class="p">))</span>
+<span class="n">p</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
+<span class="k">print</span> <span class="n">p</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&quot;get:/&quot;</span><span class="p">)</span>
+<span class="k">print</span> <span class="n">p</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&quot;get:/foo&quot;</span><span class="p">)</span>
+</pre></div>
diff --git a/pathod/libpathod/templates/log.html b/pathod/libpathod/templates/log.html
new file mode 100644
index 00000000..b0484cb8
--- /dev/null
+++ b/pathod/libpathod/templates/log.html
@@ -0,0 +1,31 @@
+{% extends "frame.html" %} {% block body %}
+<form style="float: right" method="POST" action="/log/clear">
+ <button type="submit" class="btn">clear</button>
+</form>
+
+<h1>Logs</h1>
+<hr>
+
+<table class="table table-striped table-condensed">
+ <thead>
+ <tr>
+ <th>id</th>
+ <th>method</th>
+ <th>path</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for i in log %}
+ <tr>
+ {% if i["type"] == 'error' %}
+ <td colspan="3">ERROR: {{ i["msg"] }}</td>
+ {% else %}
+ <td>{{ i["id"] }}</td>
+ <td>{{ i["request"]["method"] }}</td>
+ <td><a href="/log/{{ i[" id "] }}">{{ i["request"]["path"] }}</a></td>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </tbody>
+</table>
+{% endblock %}
diff --git a/pathod/libpathod/templates/onelog.html b/pathod/libpathod/templates/onelog.html
new file mode 100644
index 00000000..c222ad60
--- /dev/null
+++ b/pathod/libpathod/templates/onelog.html
@@ -0,0 +1,8 @@
+{% extends "frame.html" %} {% block body %}
+<h2>Log entry {{ lid }}</h2>
+<hr>
+
+<pre>
+ {{ alog }}
+</pre>
+{% endblock %}
diff --git a/pathod/libpathod/templates/request_preview.html b/pathod/libpathod/templates/request_preview.html
new file mode 100644
index 00000000..25d73679
--- /dev/null
+++ b/pathod/libpathod/templates/request_preview.html
@@ -0,0 +1,44 @@
+{% extends "frame.html" %} {% block body %}
+<div class="page-header">
+ <h1>pathoc preview</h1>
+</div>
+
+<div style="margin-bottom: 20px" class="row">
+ <div class="span2 header">
+ Specification:
+ </div>
+ <div class="span10">
+ {% include "request_previewform.html" %}
+ </div>
+</div>
+
+{% if syntaxerror %}
+<div class="row">
+ <div class="span2 header">
+ Error:
+ </div>
+ <div class="span10">
+ <p style="color: #ff0000">{{ syntaxerror }}</p>
+ <pre>{{ marked }}</pre>
+ </div>
+</div>
+{% elif error %}
+<div class="row">
+ <div class="span2 header">
+ Error:
+ </div>
+ <div class="span10">
+ <p style="color: #ff0000">{{ error }}</p>
+ </div>
+</div>
+{% else %}
+<div class="row">
+ <div class="span2 header">
+ Request:
+ </div>
+ <div class="span10">
+ <pre>{{ output }}</pre>
+ <p>Note: pauses are skipped when generating previews!</p>
+ </div>
+</div>
+{% endif %} {% endblock %}
diff --git a/pathod/libpathod/templates/request_previewform.html b/pathod/libpathod/templates/request_previewform.html
new file mode 100644
index 00000000..91b5598a
--- /dev/null
+++ b/pathod/libpathod/templates/request_previewform.html
@@ -0,0 +1,53 @@
+<form style="margin-bottom: 0" class="form-inline" method="GET" action="/request_preview">
+ <input style="width: 18em" id="spec" name="spec" class="input-medium" value="{{spec}}"
+ placeholder="method:path:[features]">
+ <input type="submit" class="btn" value="preview">
+</form>
+
+<a class="innerlink" data-toggle="collapse" data-target="#requestexamples">examples</a>
+
+<div id="requestexamples" class="collapse">
+ <p>
+ Check out the <a href="/docs/language">complete language docs</a>. Here are
+ some examples to get you started:
+ </p>
+
+ <table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td><a href="/request_preview?spec=get:/">get:/</a></td>
+ <td>Get path /</td>
+ </tr>
+ <tr>
+ <td><a href="/request_preview?spec=get:/:b@100">get:/:b@100</a></td>
+ <td>100 random bytes as the body</td>
+ </tr>
+ <tr>
+ <td><a href='/request_preview?spec=get:/:h"Etag"="&apos;;drop table browsers;"'>get:/:h"Etag"="';drop table browsers;"</a></td>
+ <td>Add a header</td>
+ </tr>
+ <tr>
+ <td><a href='/request_preview?spec=get:/:u"&apos;;drop table browsers;"'>get:/:u"';drop table browsers;"</a></td>
+ <td>Add a User-Agent header</td>
+ </tr>
+ <tr>
+ <td><a href="/request_preview?spec=get:/:b@100:dr">get:/:b@100:dr</a></td>
+ <td>Drop the connection randomly</td>
+ </tr>
+ <tr>
+ <td>
+ <a href="/request_preview?spec="></a>
+ </td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><a href="/request_preview?spec=get:/:b@100,ascii:ir,@1">get:/:b@100,ascii:ir,@1</a></td>
+ <td>100 ASCII bytes as the body, and randomly inject a random byte</td>
+ </tr>
+ <tr>
+ <td><a href="/request_preview?spec=ws:/">ws:/</a></td>
+ <td>Initiate a websocket handshake.</td>
+ </tr>
+ </tbody>
+ </table>
+</div>
diff --git a/pathod/libpathod/templates/response_preview.html b/pathod/libpathod/templates/response_preview.html
new file mode 100644
index 00000000..bbce6d6c
--- /dev/null
+++ b/pathod/libpathod/templates/response_preview.html
@@ -0,0 +1,44 @@
+{% extends "frame.html" %} {% block body %}
+<div class="page-header">
+ <h1>pathod preview</h1>
+</div>
+
+<div style="margin-bottom: 20px" class="row">
+ <div class="span2 header">
+ Specification:
+ </div>
+ <div class="span10">
+ {% include "response_previewform.html" %}
+ </div>
+</div>
+
+{% if syntaxerror %}
+<div class="row">
+ <div class="span2 header">
+ Error:
+ </div>
+ <div class="span10">
+ <p style="color: #ff0000">{{ syntaxerror }}</p>
+ <pre>{{ marked }}</pre>
+ </div>
+</div>
+{% elif error %}
+<div class="row">
+ <div class="span2 header">
+ Error:
+ </div>
+ <div class="span10">
+ <p style="color: #ff0000">{{ error }}</p>
+ </div>
+</div>
+{% else %}
+<div class="row">
+ <div class="span2 header">
+ Response:
+ </div>
+ <div class="span10">
+ <pre>{{ output }}</pre>
+ <p>Note: pauses are skipped when generating previews!</p>
+ </div>
+</div>
+{% endif %} {% endblock %}
diff --git a/pathod/libpathod/templates/response_previewform.html b/pathod/libpathod/templates/response_previewform.html
new file mode 100644
index 00000000..d46043f3
--- /dev/null
+++ b/pathod/libpathod/templates/response_previewform.html
@@ -0,0 +1,87 @@
+<form style="margin-bottom: 0" class="form-inline" method="GET" action="/response_preview">
+ <input style="width: 18em" id="spec" name="spec" class="input-medium" value="{{spec}}"
+ placeholder="code:[features]">
+ <input type="submit" class="btn" value="preview">
+ {% if not nocraft %}
+ <a href="#" id="submitspec" class="btn">go</a>
+ {% endif %}
+</form>
+
+<a class="innerlink" data-toggle="collapse" data-target="#responseexamples">examples</a>
+
+<div id="responseexamples" class="collapse">
+ <p>
+ Check out the <a href="/docs/language">complete language docs</a>. Here are
+ some examples to get you started:
+ </p>
+
+ <table class="table table-bordered">
+ <tbody>
+ <tr>
+ <td><a href="/response_preview?spec=200">200</a></td>
+ <td>A basic HTTP 200 response.</td>
+ </tr>
+ <tr>
+ <td><a href="/response_preview?spec=200:r">200:r</a></td>
+ <td>A basic HTTP 200 response with no Content-Length header. This will
+ hang.
+ </td>
+ </tr>
+ <tr>
+ <td><a href="/response_preview?spec=200:da">200:da</a></td>
+ <td>Server-side disconnect after all content has been sent.</td>
+ </tr>
+ <tr>
+ <td><a href="/response_preview?spec=200:b@100">200:b@100</a></td>
+ <td>
+ 100 random bytes as the body. A Content-Lenght header is added, so the disconnect
+ is no longer needed.
+ </td>
+ </tr>
+ <tr>
+ <td><a href='/response_preview?spec=200:b@100:h"Server"="&apos;;drop table servers;"'>200:b@100:h"Etag"="';drop table servers;"</a></td>
+ <td>Add a Server header</td>
+ </tr>
+ <tr>
+ <td><a href="/response_preview?spec=200:b@100:dr">200:b@100:dr</a></td>
+ <td>Drop the connection randomly</td>
+ </tr>
+ <tr>
+ <td><a href="/response_preview?spec=200:b@100,ascii:ir,@1">200:b@100,ascii:ir,@1</a></td>
+ <td>100 ASCII bytes as the body, and randomly inject a random byte</td>
+ </tr>
+ <tr>
+ <td><a href='/response_preview?spec=200:b@1k:c"text/json"'>200:b@1k:c"text/json"</a></td>
+ <td>1k of random bytes, with a text/json content type</td>
+ </tr>
+ <tr>
+ <td><a href='/response_preview?spec=200:b@1k:p50,120'>200:b@1k:p50,120</a></td>
+ <td>1k of random bytes, pause for 120 seconds after 50 bytes</td>
+ </tr>
+ <tr>
+ <td><a href='/response_preview?spec=200:b@1k:pr,f'>200:b@1k:pr,f</a></td>
+ <td>1k of random bytes, but hang forever at a random location</td>
+ </tr>
+ <tr>
+ <td>
+ <a href="/response_preview?spec=200:b@100:h@1k,ascii_letters='foo'">200:b@100:h@1k,ascii_letters='foo'</a>
+ </td>
+ <td>
+ 100 ASCII bytes as the body, randomly generated 100k header name, with the value
+ 'foo'.
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+
+{% if not nocraft %}
+<script>
+ $(function() {
+ $("#submitspec").click(function() {
+ document.location = "{{craftanchor}}" + $("#spec").val()
+ });
+ });
+
+</script>
+{% endif %}
diff --git a/pathod/libpathod/test.py b/pathod/libpathod/test.py
new file mode 100644
index 00000000..33a6b763
--- /dev/null
+++ b/pathod/libpathod/test.py
@@ -0,0 +1,103 @@
+import cStringIO
+import threading
+import Queue
+
+import requests
+import requests.packages.urllib3
+from . import pathod
+
+requests.packages.urllib3.disable_warnings()
+
+
+class Daemon:
+ IFACE = "127.0.0.1"
+
+ def __init__(self, ssl=None, **daemonargs):
+ self.q = Queue.Queue()
+ self.logfp = cStringIO.StringIO()
+ daemonargs["logfp"] = self.logfp
+ self.thread = _PaThread(self.IFACE, self.q, ssl, daemonargs)
+ self.thread.start()
+ self.port = self.q.get(True, 5)
+ self.urlbase = "%s://%s:%s" % (
+ "https" if ssl else "http",
+ self.IFACE,
+ self.port
+ )
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ self.logfp.truncate(0)
+ self.shutdown()
+ return False
+
+ def p(self, spec):
+ """
+ Return a URL that will render the response in spec.
+ """
+ return "%s/p/%s" % (self.urlbase, spec)
+
+ def info(self):
+ """
+ Return some basic info about the remote daemon.
+ """
+ resp = requests.get("%s/api/info" % self.urlbase, verify=False)
+ return resp.json()
+
+ def text_log(self):
+ return self.logfp.getvalue()
+
+ def last_log(self):
+ """
+ Returns the last logged request, or None.
+ """
+ l = self.log()
+ if not l:
+ return None
+ return l[0]
+
+ def log(self):
+ """
+ Return the log buffer as a list of dictionaries.
+ """
+ resp = requests.get("%s/api/log" % self.urlbase, verify=False)
+ return resp.json()["log"]
+
+ def clear_log(self):
+ """
+ Clear the log.
+ """
+ self.logfp.truncate(0)
+ resp = requests.get("%s/api/clear_log" % self.urlbase, verify=False)
+ return resp.ok
+
+ def shutdown(self):
+ """
+ Shut the daemon down, return after the thread has exited.
+ """
+ self.thread.server.shutdown()
+ self.thread.join()
+
+
+class _PaThread(threading.Thread):
+
+ def __init__(self, iface, q, ssl, daemonargs):
+ threading.Thread.__init__(self)
+ self.name = "PathodThread"
+ self.iface, self.q, self.ssl = iface, q, ssl
+ self.daemonargs = daemonargs
+
+ def run(self):
+ self.server = pathod.Pathod(
+ (self.iface, 0),
+ ssl=self.ssl,
+ **self.daemonargs
+ )
+ self.name = "PathodThread (%s:%s)" % (
+ self.server.address.host,
+ self.server.address.port
+ )
+ self.q.put(self.server.address.port)
+ self.server.serve_forever()
diff --git a/pathod/libpathod/utils.py b/pathod/libpathod/utils.py
new file mode 100644
index 00000000..a1109a3c
--- /dev/null
+++ b/pathod/libpathod/utils.py
@@ -0,0 +1,124 @@
+import os
+import sys
+
+
+SIZE_UNITS = dict(
+ b=1024 ** 0,
+ k=1024 ** 1,
+ m=1024 ** 2,
+ g=1024 ** 3,
+ t=1024 ** 4,
+)
+
+
+class MemBool(object):
+
+ """
+ Truth-checking with a memory, for use in chained if statements.
+ """
+
+ def __init__(self):
+ self.v = None
+
+ def __call__(self, v):
+ self.v = v
+ return bool(v)
+
+
+def parse_size(s):
+ try:
+ return int(s)
+ except ValueError:
+ pass
+ for i in SIZE_UNITS.keys():
+ if s.endswith(i):
+ try:
+ return int(s[:-1]) * SIZE_UNITS[i]
+ except ValueError:
+ break
+ raise ValueError("Invalid size specification.")
+
+
+def parse_anchor_spec(s):
+ """
+ Return a tuple, or None on error.
+ """
+ if "=" not in s:
+ return None
+ return tuple(s.split("=", 1))
+
+
+def xrepr(s):
+ return repr(s)[1:-1]
+
+
+def inner_repr(s):
+ """
+ Returns the inner portion of a string or unicode repr (i.e. without the
+ quotes)
+ """
+ if isinstance(s, unicode):
+ return repr(s)[2:-1]
+ else:
+ return repr(s)[1:-1]
+
+
+def escape_unprintables(s):
+ """
+ Like inner_repr, but preserves line breaks.
+ """
+ s = s.replace("\r\n", "PATHOD_MARKER_RN")
+ s = s.replace("\n", "PATHOD_MARKER_N")
+ s = inner_repr(s)
+ s = s.replace("PATHOD_MARKER_RN", "\n")
+ s = s.replace("PATHOD_MARKER_N", "\n")
+ return s
+
+
+class Data(object):
+
+ def __init__(self, name):
+ m = __import__(name)
+ dirname, _ = os.path.split(m.__file__)
+ self.dirname = os.path.abspath(dirname)
+
+ def path(self, path):
+ """
+ Returns a path to the package data housed at 'path' under this
+ module.Path can be a path to a file, or to a directory.
+
+ This function will raise ValueError if the path does not exist.
+ """
+ fullpath = os.path.join(self.dirname, path)
+ if not os.path.exists(fullpath):
+ raise ValueError("dataPath: %s does not exist." % fullpath)
+ return fullpath
+
+
+data = Data(__name__)
+
+
+def daemonize(stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): # pragma: nocover
+ try:
+ pid = os.fork()
+ if pid > 0:
+ sys.exit(0)
+ except OSError as e:
+ sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
+ sys.exit(1)
+ os.chdir("/")
+ os.umask(0)
+ os.setsid()
+ try:
+ pid = os.fork()
+ if pid > 0:
+ sys.exit(0)
+ except OSError as e:
+ sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
+ sys.exit(1)
+ si = open(stdin, 'rb')
+ so = open(stdout, 'a+b')
+ se = open(stderr, 'a+b', 0)
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
diff --git a/pathod/libpathod/version.py b/pathod/libpathod/version.py
new file mode 100644
index 00000000..b99ae40b
--- /dev/null
+++ b/pathod/libpathod/version.py
@@ -0,0 +1,11 @@
+from __future__ import (absolute_import, print_function, division)
+
+IVERSION = (0, 17)
+VERSION = ".".join(str(i) for i in IVERSION)
+MINORVERSION = ".".join(str(i) for i in IVERSION[:2])
+NAME = "pathod"
+NAMEVERSION = NAME + " " + VERSION
+
+NEXT_MINORVERSION = list(IVERSION)
+NEXT_MINORVERSION[1] += 1
+NEXT_MINORVERSION = ".".join(str(i) for i in NEXT_MINORVERSION[:2])