From 848bdcccddd826628c35f56a93478f4dc926e170 Mon Sep 17 00:00:00 2001 From: Sam Lau Date: Thu, 3 Sep 2015 22:14:59 -0700 Subject: [PATCH 1/2] Generate basic documentation using Sphinx And also adds a Makefile to make building/viewing the docs a little easier. The Makefile adds these commands: install to install the datascience package locally test to run the tests docs to build the docs clean_docs to remove the doc files serve_docs to serve the docs from a local Python server --- .gitignore | 3 - Makefile | 26 + docs/Makefile | 192 + docs/_build/doctrees/environment.pickle | Bin 0 -> 69119 bytes docs/_build/doctrees/index.doctree | Bin 0 -> 141589 bytes docs/_build/html/.buildinfo | 4 + .../html/_modules/datascience/formats.html | 198 + .../html/_modules/datascience/maps.html | 583 + .../html/_modules/datascience/tables.html | 944 ++ .../html/_modules/datascience/util.html | 113 + docs/_build/html/_modules/index.html | 93 + docs/_build/html/_sources/index.txt | 32 + docs/_build/html/_static/ajax-loader.gif | Bin 0 -> 673 bytes docs/_build/html/_static/alabaster.css | 591 + docs/_build/html/_static/basic.css | 599 + docs/_build/html/_static/classic.css | 261 + docs/_build/html/_static/comment-bright.png | Bin 0 -> 3500 bytes docs/_build/html/_static/comment-close.png | Bin 0 -> 3578 bytes docs/_build/html/_static/comment.png | Bin 0 -> 3445 bytes docs/_build/html/_static/doctools.js | 263 + docs/_build/html/_static/down-pressed.png | Bin 0 -> 347 bytes docs/_build/html/_static/down.png | Bin 0 -> 347 bytes docs/_build/html/_static/file.png | Bin 0 -> 358 bytes docs/_build/html/_static/jquery-1.11.1.js | 10308 ++++++++++++++++ docs/_build/html/_static/jquery.js | 4 + docs/_build/html/_static/minus.png | Bin 0 -> 173 bytes docs/_build/html/_static/plus.png | Bin 0 -> 173 bytes docs/_build/html/_static/pygments.css | 63 + docs/_build/html/_static/searchtools.js | 622 + docs/_build/html/_static/sidebar.js | 159 + docs/_build/html/_static/underscore-1.3.1.js | 999 ++ docs/_build/html/_static/underscore.js | 31 + docs/_build/html/_static/up-pressed.png | Bin 0 -> 345 bytes docs/_build/html/_static/up.png | Bin 0 -> 345 bytes docs/_build/html/_static/websupport.js | 808 ++ docs/_build/html/genindex.html | 518 + docs/_build/html/index.html | 641 + docs/_build/html/objects.inv | Bin 0 -> 664 bytes docs/_build/html/py-modindex.html | 124 + docs/_build/html/search.html | 105 + docs/_build/html/searchindex.js | 1 + docs/conf.py | 288 + docs/index.rst | 32 + 43 files changed, 18602 insertions(+), 3 deletions(-) create mode 100644 Makefile create mode 100644 docs/Makefile create mode 100644 docs/_build/doctrees/environment.pickle create mode 100644 docs/_build/doctrees/index.doctree create mode 100644 docs/_build/html/.buildinfo create mode 100644 docs/_build/html/_modules/datascience/formats.html create mode 100644 docs/_build/html/_modules/datascience/maps.html create mode 100644 docs/_build/html/_modules/datascience/tables.html create mode 100644 docs/_build/html/_modules/datascience/util.html create mode 100644 docs/_build/html/_modules/index.html create mode 100644 docs/_build/html/_sources/index.txt create mode 100644 docs/_build/html/_static/ajax-loader.gif create mode 100644 docs/_build/html/_static/alabaster.css create mode 100644 docs/_build/html/_static/basic.css create mode 100644 docs/_build/html/_static/classic.css create mode 100644 docs/_build/html/_static/comment-bright.png create mode 100644 docs/_build/html/_static/comment-close.png create mode 100644 docs/_build/html/_static/comment.png create mode 100644 docs/_build/html/_static/doctools.js create mode 100644 docs/_build/html/_static/down-pressed.png create mode 100644 docs/_build/html/_static/down.png create mode 100644 docs/_build/html/_static/file.png create mode 100644 docs/_build/html/_static/jquery-1.11.1.js create mode 100644 docs/_build/html/_static/jquery.js create mode 100644 docs/_build/html/_static/minus.png create mode 100644 docs/_build/html/_static/plus.png create mode 100644 docs/_build/html/_static/pygments.css create mode 100644 docs/_build/html/_static/searchtools.js create mode 100644 docs/_build/html/_static/sidebar.js create mode 100644 docs/_build/html/_static/underscore-1.3.1.js create mode 100644 docs/_build/html/_static/underscore.js create mode 100644 docs/_build/html/_static/up-pressed.png create mode 100644 docs/_build/html/_static/up.png create mode 100644 docs/_build/html/_static/websupport.js create mode 100644 docs/_build/html/genindex.html create mode 100644 docs/_build/html/index.html create mode 100644 docs/_build/html/objects.inv create mode 100644 docs/_build/html/py-modindex.html create mode 100644 docs/_build/html/search.html create mode 100644 docs/_build/html/searchindex.js create mode 100644 docs/conf.py create mode 100644 docs/index.rst diff --git a/.gitignore b/.gitignore index d3660b4d9..ae5d0f5d1 100644 --- a/.gitignore +++ b/.gitignore @@ -49,9 +49,6 @@ coverage.xml # Django stuff: *.log -# Sphinx documentation -docs/_build/ - # PyBuilder target/ diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..b7cb716e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +.PHONY: help docs serve_docs install test + +DOCS_DIR = docs + +help: + @echo "Please use 'make ' where is one of:" + @echo " install to install the datascience package locally" + @echo " test to run the tests" + @echo " docs to build the docs" + @echo " clean_docs to remove the doc files" + @echo " serve_docs to serve the docs from a local Python server" + +install: + python setup.py develop + +test: + python setup.py test + +docs: + cd $(DOCS_DIR) ; make html + +clean_docs: + cd $(DOCS_DIR) ; make clean + +serve_docs: + cd $(DOCS_DIR)/_build/html ; python -m http.server diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000..4e43c4455 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,192 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/datascience.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/datascience.qhc" + +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/datascience" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/datascience" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..bab850f5d4ee56df77069303ac382fc34ffb0862 GIT binary patch literal 69119 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 literal 0 HcmV?d00001 diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..dffbbc879c35a4046f6d999ef99f7a841946a44c GIT binary patch literal 141589 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 F{}zgI=VYp4kCFx|ItyU0ii=` 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

gXBjd!6~z_uA01<%kJ z7yb%E+Zh_s&d_LfhDNe8G{pfVgJMVO)S{|rI=48c2;0H{9WV51)-aGxPy zpCM46AwUPA0geNY0OT_S;xh!`AYN$8nKmwQML>r2pHmom3L^2S_chw;eZ9rdo<(16w4xVQz2gw=FY4HzZc)oBcVO#`f2)yiR*4;->!@s?F- zS#G)Bu9jdumsPcamO)t7)GAbPn$WhIb?^f2ZqVaAhe-gE0=FrJwb91&2G_YhiY(!H8dzF91fI4 z%v5jNZ>eod5rD6YH(fC#I6R~W&Kn_u6&_>=uWz{&pEn@AzD2m zEi&MEU>R&n!h~r&p;WB?HpJ?$v$OgVD}mLeVOC!c=|ikKzr>2gZ5{)_C#Hh1xVNlQ z%9AlbXLyA_G9VpT4rh@Qevr^D*Rg`PnR%2sqg~otkfpz`D5shB6}x;t*JLl`I6lL3ZRk-C0vbxFRTqpunSX= zbw#sq6o|m!b_p}CsupUKZ5SxQ!m<(s#!j+p9d8Be7Q*de>@cE!HrPY}q^?a=Ci7@E zNrbSN2VX$y(Rm|co2Xx~7!kvQ@V?F3C zvTH|BOsGY9P`U=xQ#l5*tbi`8hPKk#Sq>3T8@!h~8l&~TN$WBQ&9a)b04C_{W(`(b zLc+CRe(E4b_1!xASfzzp*=oCaG45O9t%1>S%RbhEHktx9TM+m>vr$Z=f JU+wXc{|~3?TW$aV literal 0 HcmV?d00001 diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo new file mode 100644 index 000000000..7a30abb1c --- /dev/null +++ b/docs/_build/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: faf3b74cfc24bac603df052cf0893300 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/_modules/datascience/formats.html b/docs/_build/html/_modules/datascience/formats.html new file mode 100644 index 000000000..9fd5dd781 --- /dev/null +++ b/docs/_build/html/_modules/datascience/formats.html @@ -0,0 +1,198 @@ + + + + + + + + datascience.formats — datascience 0.3.3 documentation + + + + + + + + + + + + +

+ +
+
+
+
+ +

Source code for datascience.formats

+"""String formatting for table entries."""
+
+import numpy as np
+
+from datetime import datetime, timezone
+
+
+
[docs]class Formatter: + """String formatter that truncates long values.""" + + min_width = 4 + max_width = 60 + etc = ' ...' + + def __init__(self, min_width=None, max_width=None, etc=None): + if min_width is not None: + self.min_width = min_width + if max_width is not None: + self.max_width = max_width + if etc is not None: + self.etc = etc + +
[docs] def format_column(self, label, column): + """Return a formatting function that pads & truncates values.""" + if len(column) == 0: + val_width = 0 + else: + val_width = max(len(self.format_value(v)) for v in column) + val_width = min(val_width, self.max_width) + width = max(val_width, len(str(label)), self.min_width, len(self.etc)) + def pad(value, label=False): + if label: + raw = value + else: + raw = self.format_value(value) + if len(raw) > width: + prefix = raw[:width-len(self.etc)] + self.etc + else: + prefix = raw + return prefix.ljust(width) + return pad +
+ @staticmethod +
[docs] def format_value(value): + """Pretty-print an arbitrary value.""" + if isinstance(value, (bool, np.bool_)): + return str(value) + elif isinstance(value, (int, np.integer)): + return '{:n}'.format(value) + elif isinstance(value, (float, np.floating)): + return '{:g}'.format(value) + else: + return str(value) +
+ @staticmethod +
[docs] def convert(value): + """Identity conversion (override to convert values).""" + return value +
+ @property + def converts_values(self): + """Whether this Formatter also converts values.""" + return self.convert is not Formatter.convert + +
+default_formatter = Formatter() + + +
[docs]class CurrencyFormatter(Formatter): + """Format currency and convert to float.""" + + converts_values = True + + def __init__(self, symbol="$", *args, **vargs): + super().__init__(*args, **vargs) + assert isinstance(symbol, str) + self.symbol = symbol + +
[docs] def convert(self, value): + """Convert string $1.25 to float 1.25.""" + assert isinstance(value, str), "Currency is not a string" + assert value.startswith(self.symbol), "Currency does not start with " + self.symbol + return float(value.lstrip(self.symbol)) +
+
[docs] def format_value(self, value): + """Format currency.""" + return self.symbol + "{0:,.2f}".format(value) + +
+
[docs]class DateFormatter(Formatter): + """Format date & time and convert to UNIX timestamp.""" + + converts_values = True + + def __init__(self, format="%Y-%m-%d %H:%M:%S.%f", *args, **vargs): + super().__init__(*args, **vargs) + assert isinstance(format, str) + self.format = format + +
[docs] def convert(self, value): + """Convert 2015-08-03 to a Unix timestamp int.""" + return datetime.strptime(value, self.format).timestamp() +
+
[docs] def format_value(self, value): + """Format timestamp as a string.""" + return datetime.fromtimestamp(value).strftime(self.format)
+
+ +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/datascience/maps.html b/docs/_build/html/_modules/datascience/maps.html new file mode 100644 index 000000000..6eaed5e95 --- /dev/null +++ b/docs/_build/html/_modules/datascience/maps.html @@ -0,0 +1,583 @@ + + + + + + + + datascience.maps — datascience 0.3.3 documentation + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for datascience.maps

+"""Draw maps using folium."""
+
+import IPython.display
+import folium
+import pandas
+import numpy as np
+
+import abc
+import collections
+import collections.abc
+import json
+import functools
+import random
+
+_number = (int, float, np.number)
+
+
+class _FoliumWrapper(abc.ABC):
+    """A map element that can be drawn."""
+    _width = 0
+    _height = 0
+    _folium_map = None
+
+    def draw(self):
+        """Draw and cache map."""
+        if not self._folium_map:
+            self._set_folium_map()
+        return self._folium_map
+
+    def as_html(self):
+        """Generate HTML to display map."""
+        if not self._folium_map:
+            self.draw()
+        return self._inline_map(self._folium_map, self._width, self._height)
+
+    def show(self):
+        """Publish HTML."""
+        IPython.display.display(IPython.display.HTML(self.as_html()))
+
+    def _repr_html_(self):
+        return self.as_html()
+
+    @staticmethod
+    def _inline_map(m, width, height):
+        """Returns an embedded iframe of a folium.map."""
+        m._build_map()
+        src = m.HTML.replace('"', '&quot;')
+        style = "width: {}px; height: {}px".format(width, height)
+        html = '<iframe srcdoc="{}" style="{}"; border: none"></iframe>'.format(src, style)
+        # See https://github.com/python-visualization/folium/issues/176
+        if hasattr(m, 'json_data'):
+            for name, data in m.json_data.items():
+                stub = 'function(callback){callback(null, JSON.parse('
+                replace = stub + repr(json.dumps(data).replace('"', '&quot;')) + '))}'
+                html = html.replace('d3.json, ' + repr(name), replace)
+        return html
+
+    @abc.abstractmethod
+    def _set_folium_map(self):
+        """Set the _folium_map attribute to a map."""
+
+
+
[docs]class Map(_FoliumWrapper, collections.abc.Mapping): + """A map from IDs to features. Keyword args are forwarded to folium.""" + + _mapper = folium.Map + _default_lat_lon = (37.872, -122.258) + _default_zoom = 12 + + def __init__(self, features=(), ids=(), width=960, height=500, **kwargs): + if isinstance(features, (tuple, set, list)): + if len(ids) == len(features): + features = dict(zip(ids, features)) + else: + assert len(ids) == 0 + features = dict(enumerate(features)) + elif isinstance(features, _MapFeature): + features = {0: features} + assert isinstance(features, dict), 'Map takes a list or dict of features' + self._features = features + self._attrs = { + 'tiles': 'Stamen Toner', + 'max_zoom': 17, + 'min_zoom': 10, + } + self._width = width + self._height = height + self._attrs.update(kwargs) + + def __getitem__(self, id): + return self._features[id] + + def __len__(self): + return len(self._features) + + def __iter__(self): + return iter(self._features) + + def _set_folium_map(self): + self._folium_map = self._create_map() + for feature in self._features.values(): + feature.draw_on(self._folium_map) + + def _create_map(self): + attrs = {'width': self._width, 'height': self._height} + attrs.update(self._autozoom()) + attrs.update(self._attrs.copy()) + # Enforce zoom consistency + attrs['max_zoom'] = max(attrs['zoom_start']+2, attrs['max_zoom']) + attrs['min_zoom'] = min(attrs['zoom_start']-2, attrs['min_zoom']) + return self._mapper(**attrs) + + def _autozoom(self): + """Calculate zoom and location.""" + bounds = self._autobounds() + attrs = {} + + midpoint = lambda a, b: (a + b)/2 + attrs['location'] = ( + midpoint(bounds['min_lat'], bounds['max_lat']), + midpoint(bounds['min_lon'], bounds['max_lon']) + ) + + # TODO(Alvin): uncomment with new Folium release + # self._folium_map.fit_bounds( + # [bounds['min_long'], bounds['min_lat']], + # [bounds['max_long'], bounds['max_lat']] + # ) + + # remove the following with new Folium release + # rough approximation, assuming max_zoom is 18 + import math + try: + factor = 1.2 + lat_diff = bounds['max_lat'] - bounds['min_lat'] + lon_diff = bounds['max_lon'] - bounds['min_lon'] + area, max_area = lat_diff*lon_diff, 180*360 + if area: + zoom = math.log(area/max_area)/-factor + else: + zoom = self._default_zoom + zoom = max(1, min(18, round(zoom))) + attrs['zoom_start'] = zoom + except ValueError as e: + raise Exception('Check that your locations are lat-lon pairs', e) + + return attrs + + def _autobounds(self): + """Simple calculation for bounds.""" + bounds = {} + + def check(prop, compare, extreme, val): + opp = min if compare is max else max + bounds.setdefault(prop, val) + bounds[prop] = opp(compare(bounds[prop], val), extreme) + + def bound_check(lat_lon): + lat, lon = lat_lon + check('max_lat', max, 90, lat) + check('min_lat', min, -90, lat) + check('max_lon', max, 180, lon) + check('min_lon', min, -180, lon) + + lat_lons = [lat_lon for feature in self._features.values() for + lat_lon in feature.lat_lons] + if not lat_lons: + lat_lons.append(self._default_lat_lon) + for lat_lon in lat_lons: + bound_check(lat_lon) + + return bounds + +
[docs] def format(self, **kwargs): + """Apply formatting.""" + attrs = self._attrs.copy() + attrs.update({'width': self._width, 'height': self._height}) + attrs.update(kwargs) + return Map(self._features, **attrs) +
+
[docs] def geojson(self): + """Render features as a FeatureCollection.""" + return { + "type": "FeatureCollection", + "features": [f.geojson(i) for i, f in self._features.items()] + } +
+
[docs] def color(self, values, ids=(), key_on='feature.id', palette='YlOrBr', **kwargs): + """Color map features by binning values. + + values -- a sequence of values or a table of keys and values + ids -- an ID for each value; if none are provided, indices are used + key_on -- attribute of each feature to match to ids + palette -- one of the following color brewer palettes: + 'BuGn', 'BuPu', 'GnBu', 'OrRd', 'PuBu', 'PuBuGn', 'PuRd', 'RdPu', + 'YlGn', 'YlGnBu', 'YlOrBr', and 'YlOrRd'. + + Defaults from Folium: + + threshold_scale: list, default None + Data range for D3 threshold scale. Defaults to the following range + of quantiles: [0, 0.5, 0.75, 0.85, 0.9], rounded to the nearest + order-of-magnitude integer. Ex: 270 rounds to 200, 5600 to 6000. + fill_opacity: float, default 0.6 + Area fill opacity, range 0-1. + line_color: string, default 'black' + GeoJSON geopath line color. + line_weight: int, default 1 + GeoJSON geopath line weight. + line_opacity: float, default 1 + GeoJSON geopath line opacity, range 0-1. + legend_name: string, default None + Title for data legend. If not passed, defaults to columns[1]. + """ + # TODO Unfortunately, this method doesn't work inside a notebook. + # See: https://github.com/python-visualization/folium/issues/176 + + # Set values and ids to both be simple sequences by inspecting values + id_name, value_name = 'IDs', 'values' + if isinstance(values, collections.abc.Mapping): + assert not ids, 'IDs and a map cannot both be used together' + if hasattr(values, 'columns') and len(values.columns) == 2: + table = values + ids, values = table.columns + id_name, value_name = table.column_labels + else: + dictionary = values + ids, values = list(dictionary.keys()), list(dictionary.values()) + if len(ids) != len(values): + assert len(ids) == 0 + # Use indices as IDs + ids = list(range(len(values))) + + m = self._create_map() + data = pandas.DataFrame({id_name: ids, value_name: values}) + attrs = { + 'geo_str': json.dumps(self.geojson()), + 'data': data, + 'columns': [id_name, value_name], + 'key_on': key_on, + 'fill_color': palette, + } + kwargs.update(attrs) + m.geo_json(**kwargs) + colored = self.format() + colored._folium_map = m + return colored +
+ @classmethod +
[docs] def read_geojson(cls, path_or_json_or_string): + """Read a geoJSON string, object, or file. Return a dict of features keyed by ID.""" + assert path_or_json_or_string + data = None + if isinstance(path_or_json_or_string, (dict, list)): + data = path_or_json_or_string + try: + data = json.loads(path_or_json_or_string) + except ValueError: + pass + try: + data = json.loads(open(path_or_json_or_string, 'r').read()) + except FileNotFoundError: + pass + # TODO web address + assert data, 'MapData accepts a valid geoJSON object, geoJSON string, or path to a geoJSON file' + return cls(cls._read_geojson_features(data)) +
+ @staticmethod + def _read_geojson_features(data, features=None, prefix=""): + """Return a dict of features keyed by ID.""" + if features is None: + features = collections.OrderedDict() + for i, feature in enumerate(data['features']): + key = feature.get('id', prefix + str(i)) + feature_type = feature['geometry']['type'] + if feature_type == 'FeatureCollection': + _read_geojson_features(feature, features, prefix + '.' + key) + elif feature_type == 'Point': + value = Circle._convert_point(feature) + else: + value = Region(feature) + features[key] = value + return features + +
+class _MapFeature(_FoliumWrapper, abc.ABC): + """A feature displayed on a map. When displayed alone, a map is created.""" + + # Method name for a folium.Map to add the feature + _map_method_name = "" + + # Default dimensions for displaying the feature in isolation + _width = 180 + _height = 180 + + def draw_on(self, folium_map): + """Add feature to Folium map object.""" + f = getattr(folium_map, self._map_method_name) + f(**self._folium_kwargs) + + def _set_folium_map(self): + """A map containing only the feature.""" + m = Map(features=[self], width=self._width, height=self._height) + self._folium_map = m.draw() + + ############# + # Interface # + ############# + + @property + @abc.abstractmethod + def lat_lons(self): + """Sequence of lat_lons that describe a map feature (for zooming).""" + + @property + @abc.abstractmethod + def _folium_kwargs(self): + """kwargs for a call to a map method.""" + + @abc.abstractmethod + def geojson(self, feature_id): + """Return GeoJSON.""" + + +
[docs]class Marker(_MapFeature): + """A marker displayed with Folium's simple_marker method. + + popup -- text that pops up when marker is clicked + color -- fill color + + Defaults from Folium: + + marker_icon: string, default 'info-sign' + icon from (http://getbootstrap.com/components/) you want on the + marker + clustered_marker: boolean, default False + boolean of whether or not you want the marker clustered with + other markers + icon_angle: int, default 0 + angle of icon + popup_width: int, default 300 + width of popup + """ + + _map_method_name = 'simple_marker' + _color_param = 'marker_color' + + def __init__(self, lat, lon, popup='', color='blue', **kwargs): + assert isinstance(lat, _number) + assert isinstance(lon, _number) + self.lat_lon = (lat, lon) + self._attrs = { + 'popup': popup, + 'popup_on': bool(popup), + self._color_param: color, + } + self._attrs.update(kwargs) + + @property + def lat_lons(self): + return [self.lat_lon] + +
[docs] def copy(self): + """Return a deep copy""" + return type(self)(self.lat_lon[:], **self._attrs) +
+ @property + def _folium_kwargs(self): + attrs = self._attrs.copy() + attrs['location'] = self.lat_lon + return attrs + +
[docs] def geojson(self, feature_id): + """GeoJSON representation of the marker as a point.""" + lat, lon = self.lat_lon + return { + 'type': 'Feature', + 'id': feature_id, + 'geometry': { + 'type': 'Point', + 'coordinates': (lon, lat), + }, + } +
+
[docs] def format(self, **kwargs): + """Apply formatting.""" + attrs = self._attrs.copy() + attrs.update(kwargs) + lat, lon = self.lat_lon + return type(self)(lat, lon, **attrs) +
+ @classmethod + def _convert_point(cls, feature): + """Convert a GeoJSON point to a Marker.""" + lon, lat = feature['geometry']['coordinates'] + popup = feature['properties'].get('name', '') + return cls(lat, lon) + + @classmethod +
[docs] def map(cls, latitudes, longitudes, labels=None, colors=None, **kwargs): + """Return markers from columns of coordinates, labels, & colors.""" + assert len(latitudes) == len(longitudes) + inputs = [latitudes, longitudes] + if labels is not None: + assert len(labels) == len(latitudes) + inputs.append(labels) + else: + inputs.append(("",) * len(latitudes)) + if colors is not None: + assert len(colors) == len(latitudes) + inputs.append(colors) + ms = [cls(*args, **kwargs) for args in zip(*inputs)] + return Map(ms) +
+ @classmethod +
[docs] def map_table(cls, table, **kwargs): + """Return markers from the colums of a table.""" + return cls.map(*table.columns, **kwargs) + +
+
[docs]class Circle(Marker): + """A marker displayed with Folium's circle_marker method. + + popup -- text that pops up when marker is clicked + color -- fill color + radius -- pixel radius of the circle + + Defaults from Folium: + + fill_opacity: float, default 0.6 + Circle fill opacity + """ + + _map_method_name = 'circle_marker' + _color_param = 'fill_color' + + def __init__(self, lat, lon, popup='', color='blue', radius=10, **kwargs): + super().__init__(lat, lon, popup, color, radius=radius, line_color=None, **kwargs) + +
+
[docs]class Region(_MapFeature): + """A GeoJSON feature displayed with Folium's geo_json method.""" + + _map_method_name = 'geo_json' + + def __init__(self, geojson, **kwargs): + assert 'type' in geojson + assert geojson['type'] == 'Feature' + self._geojson = geojson + self._attrs = kwargs + + @property + def lat_lons(self): + return _lat_lons_from_geojson(self._geojson['geometry']['coordinates']) + +
[docs] def copy(self): + """Return a deep copy""" + return type(self)(self._geojson.copy(), **self._attrs) +
+ @property + def _folium_kwargs(self): + attrs = self._attrs.copy() + attrs['geo_str'] = json.dumps(self._geojson) + return attrs + +
[docs] def geojson(self, feature_id): + """Return GeoJSON with ID substituted.""" + if self._geojson.get('id', feature_id) == feature_id: + return self._geojson + else: + geo = self._geojson.copy() + geo['id'] = feature_id + return geo +
+
[docs] def format(self, **kwargs): + """Apply formatting.""" + attrs = self._attrs.copy() + attrs.update(kwargs) + return Region(self._geojson, **attrs) + +
+def _lat_lons_from_geojson(s): + """Return a latitude-longitude pairs from nested GeoJSON coordinates. + + GeoJSON coordinates are always stored in (longitude, latitude) order. + """ + if len(s) >= 2 and isinstance(s[0], _number) and isinstance(s[0], _number): + lat, lon = s[1], s[0] + return [(lat, lon)] + else: + return [lat_lon for sub in s for lat_lon in _lat_lons_from_geojson(sub)] +
+ +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/datascience/tables.html b/docs/_build/html/_modules/datascience/tables.html new file mode 100644 index 000000000..226015644 --- /dev/null +++ b/docs/_build/html/_modules/datascience/tables.html @@ -0,0 +1,944 @@ + + + + + + + + datascience.tables — datascience 0.3.3 documentation + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for datascience.tables

+"""Tables as ordered dictionaries of Numpy arrays."""
+
+import collections
+import collections.abc
+import functools
+import itertools
+import operator
+import random
+
+import numpy as np
+import matplotlib.pyplot as plt
+import pandas
+import IPython
+
+import datascience.maps as _maps
+import datascience.formats as _formats
+from .util import *
+
+
[docs]class Table(collections.abc.MutableMapping): + """A sequence of labeled columns. + + >>> letters = ['a', 'b', 'c', 'z'] + >>> counts = [9, 3, 3, 1] + >>> points = [1, 2, 2, 10] + >>> t = Table([letters, counts, points], ['letter', 'count', 'points']) + >>> print(t) + letter | count | points + a | 9 | 1 + b | 3 | 2 + c | 3 | 2 + z | 1 | 10 + """ + + def __init__(self, columns=None, labels=None, formatter=_formats.default_formatter): + """Create a table from a list or dictionary of sequences. + + columns -- a dictionary of sequences keyed by label [labels == None] OR + a sequence of sequences [labels != None] + labels -- a sequence of labels; columns must not contain labels + """ + self._columns = collections.OrderedDict() + self._formats = dict() + self.formatter = formatter + if not columns: + assert not labels, 'labels but no columns' + columns, labels = [], [] + if isinstance(columns, collections.abc.Mapping): + assert labels is None, 'labels must be None if columns has labels' + columns, labels = columns.values(), columns.keys() + assert labels is not None, 'Labels are required' + assert len(labels) == len(columns), 'label/column number mismatch' + for column, label in zip(columns, labels): + self[label] = column + + def __getitem__(self, label): + return self._columns[label] + + def __setitem__(self, label, values): + if not isinstance(values, np.ndarray): + # Coerce a single value to a sequence + if not _is_non_string_iterable(values): + values = [values] * max(self.num_rows, 1) + values = np.array(tuple(values)) + if hasattr(self, '_num_rows') & self.num_rows > 0: + assert len(values) == self.num_rows, 'column length mismatch' + else: + self._num_rows = len(values) + self._columns[label] = values + + def __delitem__(self, label): + del self._columns[label] + if label in self._formats: + del self._formats[label] + + def __len__(self): + return len(self._columns) + + def __iter__(self): + return iter(self.column_labels) + + def __getattr__(self, attr): + """Return a method that applies to all columns or a table of attributes. + + E.g., t.sum() on a Table will return a table with the sum of each column. + """ + if self.columns and all(hasattr(c, attr) for c in self.columns): + attrs = [getattr(c, attr) for c in self.columns] + if all(callable(attr) for attr in attrs): + @functools.wraps(attrs[0]) + def method(*args, **vargs): + """Create a table from the results of calling attrs.""" + columns = [attr(*args, **vargs) for attr in attrs] + return self._with_columns(columns) + return method + else: + return self._with_columns([[attr] for attr in attrs]) + else: + msg = "'{0}' object has no attribute '{1}'".format(type(self).__name__, attr) + raise AttributeError(msg) + + @property + def num_rows(self): + """Number of rows.""" + if hasattr(self, '_num_rows'): + return self._num_rows + else: + return 0 + + @property + def rows(self): + """Return a view of all rows.""" + return self.Rows(self) + + @property + def column_labels(self): + """Return a tuple of column labels.""" + return tuple(self._columns.keys()) + + @property + def columns(self): + return tuple(self._columns.values()) + +
[docs] def column_index(self, column_label): + """Return the index of a column.""" + return self.column_labels.index(column_label) +
+
[docs] def apply(self, fn, column_label): + """Apply a function to each element of a column.""" + return [fn(v) for v in self[column_label]] + + ########## + # Modify # + ########## +
+
[docs] def set_format(self, column_label_or_labels, formatter): + """Set the format of a column.""" + for label in _as_labels(column_label_or_labels): + if callable(formatter): + self._formats[label] = lambda v, label: v if label else str(formatter(v)) + elif isinstance(formatter, _formats.Formatter): + if formatter.converts_values: + self[label] = self.apply(formatter.convert, label) + column = self[label] + self._formats[label] = formatter.format_column(label, column) + else: + raise Exception('Expected Formatter or function: ' + str(formatter)) + return self +
+
[docs] def move_to_start(self, column_label): + """Move a column to the first in order.""" + self._columns.move_to_end(column_label, last=False) + return self +
+
[docs] def move_to_end(self, column_label): + """Move a column to the last in order.""" + self._columns.move_to_end(column_label) + return self +
+
[docs] def append(self, row_or_table): + """Append a row or all rows of a table. An appended table must have all + columns of self.""" + if not row_or_table: + return + if isinstance(row_or_table, Table): + t = row_or_table + row = list(t.select(self.column_labels)._columns.values()) + n = t.num_rows + else: + row, n = row_or_table, 1 + for i, column in enumerate(self._columns): + self._columns[column] = np.append(self[column], row[i]) + self._num_rows = self.num_rows + n + return self +
+
[docs] def relabel(self, column_label, new_label): + """Change the label of a column.""" + assert column_label in self._columns + rewrite = lambda s: new_label if s == column_label else s + columns = [(rewrite(s), c) for s, c in self._columns.items()] + self._columns = collections.OrderedDict(columns) + if column_label in self._formats: + formatter = self._formats.pop(column_label) + self._formats[new_label] = formatter + return self + + ########## + # Create # + ########## +
+ @classmethod +
[docs] def from_rows(cls, rows, column_labels): + """Create a table from a sequence of rows (fixed-length sequences).""" + return cls(list(zip(*rows)), column_labels) +
+ @classmethod +
[docs] def from_records(cls, records): + """Create a table from a sequence of records (dicts with fixed keys).""" + if not records: + return cls() + labels = sorted(list(records[0].keys())) + return cls([[rec[label] for rec in records] for label in labels], labels) +
+ @classmethod +
[docs] def read_table(cls, filepath_or_buffer, *args, **vargs): + """Read a table from a file or web address. + + filepath_or_buffer -- string or file handle / StringIO; The string + could be a URL. Valid URL schemes include http, + ftp, s3, and file. + """ + if filepath_or_buffer.endswith('.csv') and 'sep' not in vargs: + vargs['sep'] = ',' + df = pandas.read_table(filepath_or_buffer, *args, **vargs) + labels = df.columns + return Table([df[label].values for label in labels], labels) +
+ def _with_columns(self, columns): + """Create a table from a sequence of columns, copying column labels.""" + table = Table() + for label, column in zip(self.column_labels, columns): + self._add_column_and_format(table, label, column) + return table + + def _add_column_and_format(self, table, label, column): + """Add a column to table, copying the formatter from self.""" + table[label] = column + if label in self._formats: + table._formats[label] = self._formats[label] + + ############# + # Transform # + ############# + +
[docs] def copy(self): + """Return a copy of a Table.""" + table = Table() + for label in self.column_labels: + self._add_column_and_format(table, label, np.copy(self[label])) + return table +
+
[docs] def select(self, column_label_or_labels): + """Return a Table with selected column or columns by label.""" + column_labels = _as_labels(column_label_or_labels) + table = Table() + for label in column_labels: + self._add_column_and_format(table, label, np.copy(self[label])) + return table +
+
[docs] def drop(self, column_label_or_labels): + """Return a Table with only columns other than selected label or labels.""" + exclude = _as_labels(column_label_or_labels) + return self.select([c for c in self.column_labels if c not in exclude]) +
+
[docs] def take(self, row_numbers): + """Return a Table of a sequence of rows taken by number.""" + columns = [np.take(column, row_numbers, axis=0) for column in self.columns] + return self._with_columns(columns) +
+
[docs] def where(self, column_or_label, value=None): + """Return a Table of rows for which the column is value or a non-zero value.""" + column = self._get_column(column_or_label) + if value is not None: + column = column == value + return self.take(np.nonzero(column)[0]) +
+
[docs] def sort(self, column_or_label, descending=False, distinct=False): + """Return a Table of sorted rows by the values in a column.""" + column = self._get_column(column_or_label) + if distinct: + _, row_numbers = np.unique(column, return_index=True) + else: + row_numbers = np.argsort(column, axis=0) + assert (row_numbers < self.num_rows).all(), row_numbers + if descending: + row_numbers = np.array(row_numbers[::-1]) + return self.take(row_numbers) +
+
[docs] def group(self, column_or_label, collect=lambda s: s): + """Group rows by unique values in column_label, aggregating values. + + collect -- an optional function applied to the values for each group. + + The grouped column will appear first in the result table. + """ + self = self._with_columns(self.columns) # Shallow self + collect = _zero_on_type_error(collect) + + # Remove column used for grouping + column = self._get_column(column_or_label) + if column_or_label in self.column_labels: + column_label = column_or_label + del self[column_label] + else: + column_label = self._unused_label('group') + + # Generate grouped columns + groups = self.index_by(column) + keys = sorted(groups.keys()) + columns, labels = [], [] + for i, label in enumerate(self.column_labels): + labels.append(_collected_label(collect, label)) + c = [collect(np.array([row[i] for row in groups[k]])) for k in keys] + columns.append(c) + + grouped = type(self)(columns, labels) + assert column_label == self._unused_label(column_label) + grouped[column_label] = keys + grouped.move_to_start(column_label) + return grouped +
+
[docs] def groups(self, column_labels, collect=lambda s: s): + """Group rows by multiple columns, aggregating values.""" + collect = _zero_on_type_error(collect) + columns = [] + for label in column_labels: + assert label in self.column_labels + columns.append(self._get_column(label)) + grouped = self.group(list(zip(*columns))) + grouped._columns.popitem(last=False) # Discard the column of tuples + + # Flatten grouping values and move them to front + for label in column_labels[::-1]: + grouped[label] = grouped.apply(_assert_same, label) + grouped.move_to_start(label) + + # Aggregate other values + for label in grouped.column_labels: + if label in column_labels: + continue + column = [collect(v) for v in grouped[label]] + del grouped[label] + grouped[_collected_label(collect, label)] = column + + return grouped +
+
[docs] def pivot(self, columns, rows, values, collect=lambda s:s, zero=None): + """Generate a table with a column for rows (or a column for each row + in rows list) and a column for each unique value in columns. Each row + aggregates over the values that match both row and column. + + columns, values -- column labels in self + rows -- column label or a list of column labels + collect -- aggregation function over values + zero -- zero value for non-existent row-column combinations + """ + rows = _as_labels(rows) + selected = self.select([columns, values] + rows) + grouped = selected.groups([columns] + rows, collect) + + # Generate existing combinations of values from columns in rows + rows_values = sorted(list(set(self.select(rows).rows))) + pivoted = Table.from_rows(rows_values, rows) + + # Generate other columns and add them to pivoted + by_columns = grouped.index_by(columns) + for label in sorted(by_columns): + tuples = [t[1:] for t in by_columns[label]] # Discard column value + column = _fill_with_zeros(rows_values, tuples, zero) + pivot = self._unused_label(str(label) + ' ' + values) + pivoted[pivot] = column + return pivoted +
+
[docs] def stack(self, key, column_labels=None): + """ + Takes k original columns and returns two columns, with col. 1 of + all column names and col. 2 of all associated data. + """ + rows, column_labels = [], column_labels or self.column_labels + for row in self.rows: + [rows.append((getattr(row, key), k, v)) for k, v in row._asdict().items() + if k != key and k in column_labels] + return Table.from_rows(rows, [key, 'column', 'value']) +
+
[docs] def join(self, column_label, other, other_label=None): + """Generate a table with the columns of self and other, containing rows + for all values of a column that appear in both tables. + If a join value appears more than once in self, each row will be used, + but in the other table, only the first of each will be used. + + If the result is empty, return None. + """ + if self.num_rows == 0 or other.num_rows == 0: + return None + if not other_label: + other_label = column_label + + self_rows = self.index_by(column_label) + other_rows = other.index_by(other_label) + + # Gather joined rows from self_rows that have join values in other_rows + joined_rows = [] + for label, rows in self_rows.items(): + if label in other_rows: + other_row = other_rows[label][0] + joined_rows += [row + other_row for row in rows] + if not joined_rows: + return None + + labels = list(self.column_labels) + labels += [self._unused_label(s) for s in other.column_labels] + joined = Table.from_rows(joined_rows, labels) + del joined[self._unused_label(other_label)] # Remove redundant column + return joined.move_to_start(column_label).sort(column_label) +
+
[docs] def stats(self, ops=(min, max, np.median, sum)): + """Compute statistics for each column and place them in a table.""" + names = [op.__name__ for op in ops] + ops = [_zero_on_type_error(op) for op in ops] + columns = [[op(column) for op in ops] for column in self.columns] + table = self._with_columns(columns) + stats = table._unused_label('statistic') + table[stats] = names + table.move_to_start(stats) + return table +
+ def _unused_label(self, label): + """Generate an unused label.""" + original = label + existing = self.column_labels + i = 2 + while label in existing: + label = '{}_{}'.format(original, i) + i += 1 + return label + + def _get_column(self, column_or_label): + """Convert label to column and check column length.""" + c = column_or_label + if isinstance(c, collections.Hashable) and c in self.column_labels: + return self[c] + elif isinstance(c, str): + assert c in self.column_labels, 'label "{}" not in labels {}'.format(c, self.column_labels) + else: + assert len(c) == self.num_rows, 'column length mismatch' + return c + +
[docs] def percentile(self, p): + """Assumes that each column only contains one type of value. + + Returns a new table with one row and the same column labels. + The row contains the pth percentile of the original column, where the + pth percentile of a column is the smallest value that at at least as + large as the p% of numbers in the column. + + >>> print(t) + count | points + 9 | 1 + 3 | 2 + 3 | 2 + 1 | 10 + >>> t.percentile(67) + count | points + 9 | 10 + """ + percentiles = [percentile(p, self[column_name]) for column_name in self] + return Table(percentiles, self.column_labels) + + ################## + # Export/Display # + ################## +
+ def __repr__(self): + return '<{0}({1} rows): | {3} |>'.format( + type(self).__name__, + len(self),self.num_rows, + " | ".join(map(str, self.column_labels))) + + def __str__(self): + return self.as_text(self.max_str_rows) + + def _repr_html_(self): + return self.as_html(self.max_str_rows) + +
[docs] def show(self, max_rows=0): + """Display the table.""" + IPython.display.display(IPython.display.HTML(self.as_html(max_rows))) +
+ max_str_rows = 10 + +
[docs] def as_text(self, max_rows=0, sep=" | "): + """Format table as text.""" + if not max_rows or max_rows > self.num_rows: + max_rows = self.num_rows + omitted = max(0, self.num_rows - max_rows) + labels = self._columns.keys() + fmts = [self._formats.get(k, self.formatter.format_column(k, v[:max_rows])) for + k, v in self._columns.items()] + rows = [[fmt(label, label=True) for fmt, label in zip(fmts, labels)]] + for row in itertools.islice(self.rows, max_rows): + rows.append([f(v, label=False) for v, f in zip(row, fmts)]) + lines = [sep.join(row) for row in rows] + if omitted: + lines.append('... ({} rows omitted)'.format(omitted)) + return '\n'.join([line.rstrip() for line in lines]) +
+
[docs] def as_html(self, max_rows=0): + """Format table as HTML.""" + if not max_rows or max_rows > self.num_rows: + max_rows = self.num_rows + omitted = max(0, self.num_rows - max_rows) + labels = self.column_labels + lines = [ + (0, '<table border="1" class="dataframe">'), + (1, '<thead>'), + (2, '<tr>'), + (3, ' '.join('<th>' + label + '</th>' for label in labels)), + (2, '</tr>'), + (1, '</thead>'), + (1, '<tbody>'), + ] + fmts = [self._formats.get(k, self.formatter.format_column(k, v[:max_rows])) for + k, v in self._columns.items()] + for row in itertools.islice(self.rows, max_rows): + lines += [ + (2, '<tr>'), + (3, ' '.join('<td>' + fmt(v, label=False) + '</td>' for + v, fmt in zip(row, fmts))), + (2, '</tr>'), + (1, '</tbody>'), + ] + lines.append((0, '</table>')) + if omitted: + lines.append((0, '<p>... ({} rows omitted)</p'.format(omitted))) + return '\n'.join(4 * indent * ' ' + text for indent, text in lines) +
+
[docs] def matrix(self): + """Return a 2-D array with the contents of the table.""" + return np.matrix(list(self._columns.values())) +
+
[docs] def index_by(self, column_or_label): + """Return a dict keyed by values in a column that contains lists of + rows corresponding to each value. + """ + column = self._get_column(column_or_label) + index = {} + for key, row in zip(column, self.rows): + index.setdefault(key, []).append(row) + return index +
+ def _sample(self, k, with_replacement, weights): + """Returns list of sampled rows""" + n = self.num_rows + indices = np.random.choice( + n, k or n, replace=with_replacement, p=weights) + return [self.rows[i] for i in indices] + +
[docs] def sample(self, k=None, with_replacement=False, weights=None): + """Returns a new table""" + return Table.from_rows( + self._sample(k, with_replacement, weights), + self.column_labels) + + ############# + # Visualize # + ############# +
+ chart_colors = ( + '#001A44', + '#FFC800', + '#576884', + '#B39C4D', + '#768948', + '#067BC2', + '#FB5012', + '#19381F', + '#4C3C37', + ) + + default_options = { + 'alpha': 0.8, + } + +
[docs] def plot(self, column_for_xticks=None, overlay=False, **vargs): + """Plot contents as lines.""" + options = self.default_options.copy() + options.update(vargs) + xticks, labels = self._split(column_for_xticks) + def draw(axis, label, color): + axis.plot(self[label], color=color, **options) + def annotate(axis, ticks): + axis.set_xticklabels(ticks, rotation='vertical') + self._visualize(labels, xticks, overlay, draw, annotate) +
+
[docs] def barh(self, column_for_categories, overlay=False, **vargs): + """Plot contents as a horizontal bar chart.""" + options = self.default_options.copy() + options.update(vargs) + yticks, labels = self._split(column_for_categories) + index = np.arange(self.num_rows) + margin = 0.1 + width = 1 - 2 * margin + if overlay: + width /= len(labels) + def draw(axis, label, color): + if overlay: + ypos = index + margin + (1-2*margin)*labels.index(label)/len(labels) + else: + ypos = index + axis.barh(ypos, self[label], width, color=color, **options) + def annotate(axis, ticks): + axis.set_yticks(index+0.5) # Center labels on bars + axis.set_yticklabels(ticks, stretch='ultra-condensed') + height = max(4, len(index)/2) + if 'height' in vargs: + height = vargs.pop('height') + self._visualize(labels, yticks, overlay, draw, annotate, height=height) +
+ def _visualize(self, labels, ticks, overlay, draw, annotate, width=6, height=4): + """Generic visualization that overlays or separates the draw function.""" + n = len(labels) + colors = list(itertools.islice(itertools.cycle(self.chart_colors), n)) + if overlay: + _, axis = plt.subplots(figsize=(width, height)) + for label, color in zip(labels, colors): + draw(axis, label, color) + if ticks is not None: + annotate(axis, ticks) + axis.legend(labels, bbox_to_anchor=(1.5, 1.0)) + else: + fig, axes = plt.subplots(n, 1, figsize=(width, height * n)) + if not isinstance(axes, collections.Iterable): + axes=[axes] + for axis, label, color in zip(axes, labels, colors): + draw(axis, label, color) + axis.set_xlabel(label, fontsize=16) + if ticks is not None: + annotate(axis, ticks) + + def _split(self, column_or_label): + """Return the specified column and labels of other columns.""" + labels = list(self.column_labels) + if column_or_label is None: + return None, labels + if column_or_label in labels: + labels.remove(column_or_label) + column = self._get_column(column_or_label) + return column, labels + +
[docs] def pivot_hist(self, pivot_column_label, value_column_label, overlay=False, **vargs): + """Draw histograms of each category in a column.""" + pvt_labels = np.unique(self[pivot_column_label]) + pvt_columns = [self[value_column_label][np.where(self[pivot_column_label] == pivot)] for pivot in pvt_labels] + n = len(pvt_labels) + colors = list(itertools.islice(itertools.cycle(('b', 'g', 'r')), n)) + if overlay: + plt.figure(figsize=(6, 4)) + vals, bins, patches = plt.hist(pvt_columns, color=colors, **vargs) + plt.legend(pvt_labels) + else: + _, axes = plt.subplots(n, 1, figsize=(6, 4 * n)) + vals = [] + bins = None + for axis, label, column, color in zip(axes, pvt_labels, pvt_columns, colors): + if isinstance(bins, np.ndarray): + avals, abins, patches = axis.hist(column, color=color, bins=bins, **vargs) + else: + avals, abins, patches = axis.hist(column, color=color, **vargs) + axis.set_xlabel(label, fontsize=16) + vals.append(avals) + if not isinstance(bins, np.ndarray): bins = abins + else: assert bins.all() == abins.all(), "Inconsistent bins in hist" + t = Table() + t['start'] = bins[0:-1] + t['end'] = bins[1:] + for label, column in zip(pvt_labels,vals): + t[label] = column + return t +
+
[docs] def hist(self, overlay=False, **vargs): + """Requires all columns in the table to contain numerical values only. + If the columns contain other types, a ValueError is raised. + + Draw one histogram per column. If the overlay argument is True, a legend + containing the column name is shown on each histogram. + + See http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist + for additional arguments that can be passed into vargs. These include: + bins, range, normed, cumulative, and orientation, to name a few. + + >>> table + count | points + 9 | 1 + 3 | 2 + 3 | 2 + 1 | 10 + + >>> table.hist() + <histogram of values in count> + <histogram of values in points> + """ + # Check for non-numerical values and raise a ValueError if any found + # TODO(sam): Is a ValueError the right thing to raise? + for col in self: + if any(isinstance(cell, np.flexible) for cell in self[col]): + raise ValueError("The column '{0}' contains non-numerical " + "values. A histogram cannot be drawn for this table." + .format(col)) + + n = len(self) + colors = list(itertools.islice(itertools.cycle(('b', 'g', 'r')), n)) + if overlay: + plt.figure(figsize=(6, 4)) + plt.hist(self.columns, color=colors, **vargs) + plt.legend(self.column_labels) + else: + _, axes = plt.subplots(n, 1, figsize=(6, 4 * n)) + if n == 1: + axes = [axes] + for axis, label, color in zip(axes, self.column_labels, colors): + axis.hist(self[label], color=color, **vargs) + axis.set_xlabel(label, fontsize=16) +
+ def points(self, column__lat, column__long, + radii=None, labels=None, colors=None, **kwargs) : + latitudes = self._get_column(column__lat) + longitudes = self._get_column(column__long) + if labels is None : labels = [''] * self.num_rows + else : labels = self._get_column(labels) + if colors is None : colors = ['#3186cc'] * self.num_rows + else : colors = self._get_column(colors) + if radii is None : radii = [5] * self.num_rows + else : radii = self._get_column(radii) + points = [_maps.MapPoint((lat,long),radius=radius, + popup=label, + fill_color = color, + line_color = color, + **kwargs) + for lat,long,label,color,radius in zip(latitudes,longitudes, + labels,colors,radii)] + center_lat = sum(latitudes)/len(latitudes) + center_long = sum(longitudes)/len(longitudes) + return _maps.draw_map((center_lat,center_long), points = points) + + + ########### + # Support # + ########### + +
[docs] class Rows(collections.abc.Sequence): + """An iterable view over the rows in a table.""" + def __init__(self, table): + self._table = table + self._labels = None + + def __getitem__(self, i): + if isinstance(i, slice): + return [self[j] for j in range(*i.indices(len(self)))] + labels = tuple(self._table.column_labels) + if labels != self._labels: + self._labels = labels + self._row = collections.namedtuple('Row', labels, rename=True) + return self._row(*[c[i] for c in self._table._columns.values()]) + + def __len__(self): + return self._table.num_rows + + def __repr__(self): + return '{0}({1})'.format(type(self).__name__, repr(self._table)) + +
+class Q: + """Query manager for Tables.""" + array = None + + def __init__(self, array): + """save numpy array""" + self.array = array + + def __and__(self, other): + """allows bitwise & operations""" + return np.logical_and(self.array, other.array) + + def __or__(self, other): + return np.logical_or(self.array, other.array) + + +def _zero_on_type_error(column_fn): + """Wrap a function on an np.ndarray to return 0 on a type error.""" + @functools.wraps(column_fn) + def wrapped(column): + try: + return column_fn(column) + except TypeError: + if isinstance(column, np.ndarray): + return column.dtype.type() # A typed zero value + else: + raise + return wrapped + + +def _fill_with_zeros(partials, rows, zero=None): + """Find and return values from rows for all partials. In cases where no + row matches a partial, zero is assumed as value. For a row, the first + (n-1) fields are assumed to be the partial, and the last field, + the value, where n is the total number of fields in each row. It is + assumed that there is a unique row for each partial. + partials -- single field values or tuples of field values + rows -- table rows + zero -- value used when no rows match a particular partial + """ + assert len(rows) > 0 + if not _is_non_string_iterable(partials): + # Convert partials to tuple for comparison against row slice later + partials = [(partial,) for partial in partials] + + # Construct mapping of partials to values in rows + mapping = {} + for row in rows: + mapping[tuple(row[:-1])] = row[-1] + + if zero is None: + # Try to infer zero from given row values. + array = np.array(tuple(mapping.values())) + if len(array.shape) == 1: + zero = array.dtype.type() + return np.array([mapping.get(partial, zero) for partial in partials]) + + +def _as_labels(column_label_or_labels): + """Return a list of labels for a label or labels.""" + if not _is_non_string_iterable(column_label_or_labels): + return [column_label_or_labels] + else: + return column_label_or_labels + + +def _assert_same(values): + """Assert that all values are identical and return the unique value.""" + assert len(values) > 0 + first, rest = values[0], values[1:] + for v in rest: + assert v == first + return first + + +def _collected_label(collect, label): + """Label of a collected column.""" + if not collect.__name__.startswith('<'): + return label + ' ' + collect.__name__ + else: + return label + + +def _is_non_string_iterable(value): + """Whether a value is iterable.""" + if isinstance(value, str): + return False + if hasattr(value, '__iter__'): + return True + if isinstance(value, collections.abc.Sequence): + return True + return False +
+ +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/datascience/util.html b/docs/_build/html/_modules/datascience/util.html new file mode 100644 index 000000000..bf1382d5a --- /dev/null +++ b/docs/_build/html/_modules/datascience/util.html @@ -0,0 +1,113 @@ + + + + + + + + datascience.util — datascience 0.3.3 documentation + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for datascience.util

+"""Utility functions"""
+
+import numpy as np
+
+
[docs]def percentile(p, arr=None): + """Returns the pth percentile of the input array (the value that is at + least as great as p% of the values in the array) + + If arr is not provided, percentile returns itself curried with p + + >>> percentile(67, [1, 3, 5, 9]) + 9 + >>> percentile(66, [1, 3, 5, 9]) + 5 + >>> f = percentile(66) + >>> f([1, 3, 5, 9]) + 5 + """ + if arr is None: + return lambda arr: percentile(p, arr) + return np.percentile(arr, p, interpolation='higher')
+
+ +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_modules/index.html b/docs/_build/html/_modules/index.html new file mode 100644 index 000000000..7cbbb282a --- /dev/null +++ b/docs/_build/html/_modules/index.html @@ -0,0 +1,93 @@ + + + + + + + + Overview: module code — datascience 0.3.3 documentation + + + + + + + + + + + + + +
+
+
+
+ +

All modules for which code is available

+ + +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/_build/html/_sources/index.txt b/docs/_build/html/_sources/index.txt new file mode 100644 index 000000000..b6721fa75 --- /dev/null +++ b/docs/_build/html/_sources/index.txt @@ -0,0 +1,32 @@ +.. datascience documentation master file, created by + sphinx-quickstart on Thu Sep 3 21:52:53 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to datascience's documentation! +======================================= + +Contents: + +.. toctree:: + :maxdepth: 2 + +.. autoclass:: datascience.Table + :members: + +.. automodule:: datascience.util + :members: + +.. automodule:: datascience.maps + :members: + +.. automodule:: datascience.formats + :members: + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/_build/html/_static/ajax-loader.gif b/docs/_build/html/_static/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..61faf8cab23993bd3e1560bff0668bd628642330 GIT binary patch literal 673 zcmZ?wbhEHb6krfw_{6~Q|Nno%(3)e{?)x>&1u}A`t?OF7Z|1gRivOgXi&7IyQd1Pl zGfOfQ60;I3a`F>X^fL3(@);C=vM_KlFfb_o=k{|A33hf2a5d61U}gjg=>Rd%XaNQW zW@Cw{|b%Y*pl8F?4B9 zlo4Fz*0kZGJabY|>}Okf0}CCg{u4`zEPY^pV?j2@h+|igy0+Kz6p;@SpM4s6)XEMg z#3Y4GX>Hjlml5ftdH$4x0JGdn8~MX(U~_^d!Hi)=HU{V%g+mi8#UGbE-*ao8f#h+S z2a0-5+vc7MU$e-NhmBjLIC1v|)9+Im8x1yacJ7{^tLX(ZhYi^rpmXm0`@ku9b53aN zEXH@Y3JaztblgpxbJt{AtE1ad1Ca>{v$rwwvK(>{m~Gf_=-Ro7Fk{#;i~+{{>QtvI yb2P8Zac~?~=sRA>$6{!(^3;ZP0TPFR(G_-UDU(8Jl0?(IXu$~#4A!880|o%~Al1tN literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/alabaster.css b/docs/_build/html/_static/alabaster.css new file mode 100644 index 000000000..0857c04b3 --- /dev/null +++ b/docs/_build/html/_static/alabaster.css @@ -0,0 +1,591 @@ + + + + + + + + + + + + + + + + + + + + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; + font-size: 17px; + background-color: white; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #ffffff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +div.related { + display: none; +} + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebar { + font-size: 14px; + line-height: 1.5; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: 'Garamond', 'Georgia', serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #999; + background: #999; + + text-align: left; + margin-left: 0; + width: 50%; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Garamond', 'Georgia', serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #FCC; + border: 1px solid #FAA; +} + +div.admonition tt.xref, div.admonition a tt { + border-bottom: 1px solid #fafafa; +} + +dd div.admonition { + margin-left: -60px; + padding-left: 60px; +} + +div.admonition p.admonition-title { + font-family: 'Garamond', 'Georgia', serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: white; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #eee; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #eee; + -webkit-box-shadow: 2px 2px 4px #eee; + box-shadow: 2px 2px 4px #eee; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.footnote td.label { + width: 0px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +dl pre, blockquote pre, li pre { + margin-left: -60px; + padding-left: 60px; +} + +dl dl pre { + margin-left: -90px; + padding-left: 90px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid white; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: white; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: white; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.related { + display: block; + margin: 0; + padding: 10px 0 20px 0; + } + + div.related ul, + div.related ul li { + margin: 0; + padding: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} \ No newline at end of file diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css new file mode 100644 index 000000000..9fa77d886 --- /dev/null +++ b/docs/_build/html/_static/basic.css @@ -0,0 +1,599 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 30px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_build/html/_static/classic.css b/docs/_build/html/_static/classic.css new file mode 100644 index 000000000..2da923464 --- /dev/null +++ b/docs/_build/html/_static/classic.css @@ -0,0 +1,261 @@ +/* + * default.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- default theme. + * + * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + + + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +code { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th { + background-color: #ede; +} + +.warning code { + background: #efc2c2; +} + +.note code { + background: #d6d6d6; +} + +.viewcode-back { + font-family: sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +div.code-block-caption { + color: #efefef; + background-color: #1c4e63; +} \ No newline at end of file diff --git a/docs/_build/html/_static/comment-bright.png b/docs/_build/html/_static/comment-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..551517b8c83b76f734ff791f847829a760ad1903 GIT binary patch literal 3500 zcmV;d4O8-oP)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RV2niQ93PPz|JOBU!-bqA3 zR5;6pl1pe^WfX zkSdl!omi0~*ntl;2q{jA^;J@WT8O!=A(Gck8fa>hn{#u{`Tyg)!KXI6l>4dj==iVKK6+%4zaRizy(5eryC3d2 z+5Y_D$4}k5v2=Siw{=O)SWY2HJwR3xX1*M*9G^XQ*TCNXF$Vj(kbMJXK0DaS_Sa^1 z?CEa!cFWDhcwxy%a?i@DN|G6-M#uuWU>lss@I>;$xmQ|`u3f;MQ|pYuHxxvMeq4TW;>|7Z2*AsqT=`-1O~nTm6O&pNEK?^cf9CX= zkq5|qAoE7un3V z^yy=@%6zqN^x`#qW+;e7j>th{6GV}sf*}g7{(R#T)yg-AZh0C&U;WA`AL$qz8()5^ zGFi2`g&L7!c?x+A2oOaG0c*Bg&YZt8cJ{jq_W{uTdA-<;`@iP$$=$H?gYIYc_q^*$ z#k(Key`d40R3?+GmgK8hHJcwiQ~r4By@w9*PuzR>x3#(F?YW_W5pPc(t(@-Y{psOt zz2!UE_5S)bLF)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RV2oe()A>y0J-2easEJ;K` zR5;6Jl3z%jbr{D#&+mQTbB>-f&3W<<%ayjKi&ZjBc2N<@)`~{dMXWB0(ajbV85_gJ zf(EU`iek}4Bt%55ix|sVMm1u8KvB#hnmU~_r<Ogd(A5vg_omvd-#L!=(BMVklxVqhdT zofSj`QA^|)G*lu58>#vhvA)%0Or&dIsb%b)st*LV8`ANnOipDbh%_*c7`d6# z21*z~Xd?ovgf>zq(o0?Et~9ti+pljZC~#_KvJhA>u91WRaq|uqBBKP6V0?p-NL59w zrK0w($_m#SDPQ!Z$nhd^JO|f+7k5xca94d2OLJ&sSxlB7F%NtrF@@O7WWlkHSDtor zzD?u;b&KN$*MnHx;JDy9P~G<{4}9__s&MATBV4R+MuA8TjlZ3ye&qZMCUe8ihBnHI zhMSu zSERHwrmBb$SWVr+)Yk2k^FgTMR6mP;@FY2{}BeV|SUo=mNk<-XSOHNErw>s{^rR-bu$@aN7= zj~-qXcS2!BA*(Q**BOOl{FggkyHdCJi_Fy>?_K+G+DYwIn8`29DYPg&s4$}7D`fv? zuyJ2sMfJX(I^yrf6u!(~9anf(AqAk&ke}uL0SIb-H!SaDQvd(}07*qoM6N<$g1Ha7 A2LJ#7 literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/comment.png b/docs/_build/html/_static/comment.png new file mode 100644 index 0000000000000000000000000000000000000000..92feb52b8824c6b0f59b658b1196c61de9162a95 GIT binary patch literal 3445 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 Xn!ZpXD%P(H00000NkvXXu0mjf= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/_build/html/_static/down-pressed.png b/docs/_build/html/_static/down-pressed.png new file mode 100644 index 0000000000000000000000000000000000000000..7c30d004b71b32bb2fc06b3bd4dc8278baab0946 GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~&H|6fVxZ#d zAk65bF}ngN$X?><>&kwMor^(NtW3yF87Slz;1l8sq&LUMQwy<>&kwMol#tg zK_ydLmzem(vK1>2TzUEGl*lj!N<7$PCrdoWV0 z$w0*Ap!bZ4if7h;-yfL#MC0e;t{xY+$l~DX2EWYIPet1cohf^BdG+jXhtuq&W-0|c zKPmlKv-7OTjb}T)7@fTGd9y~u4{g8An;)c2U=w=nwQ7}zVDc>n+a literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/file.png b/docs/_build/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..254c60bfbe2715ae2edca48ebccfd074deb8031d GIT binary patch literal 358 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJXMsm#F#`j)FbFd;%$g$s6l5>) z^mS#w%FV~i&ZxO9L3Zxqw8>dd4I&zcKG){Yx14xKr0

ZQJ$m%mv17-NAAj}g)$7-<-@JMA z_U+TRK=AR}yLa#2zkmPX!-tO_KYsf3>Hq)#%qnY_1Fd8&3GxeO2wSmci|LJf=|BO- zByV>Yl`U*PX977no-U3d5|XS39sLdkFt8q|+|QqL_#ErUf6I%zFA7b%b>3$hFGGFs zc72AL|61pRJ1(+5wNdg|xP#*`gQ~lOnTFKiIjl#S3)+QV=h{~`9{M=hx#5uZ&-tIF sG!8onYS_8EFr8v&@CavkqYey&g)1epR*Fkm0PSV)boFyt=akR{044O6bN~PV literal 0 HcmV?d00001 diff --git a/docs/_build/html/_static/jquery-1.11.1.js b/docs/_build/html/_static/jquery-1.11.1.js new file mode 100644 index 000000000..d4b67f7e6 --- /dev/null +++ b/docs/_build/html/_static/jquery-1.11.1.js @@ -0,0 +1,10308 @@ +/*! + * jQuery JavaScript Library v1.11.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-05-01T17:42Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper window is present, + // execute the factory and get jQuery + // For environments that do not inherently posses a window with a document + // (such as Node.js), expose a jQuery-making factory as module.exports + // This accentuates the need for the creation of a real window + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +// + +var deletedIds = []; + +var slice = deletedIds.slice; + +var concat = deletedIds.concat; + +var push = deletedIds.push; + +var indexOf = deletedIds.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + version = "1.11.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android<4.1, IE<9 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: deletedIds.sort, + splice: deletedIds.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( support.ownLast ) { + for ( key in obj ) { + return hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call(obj) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Support: Android<4.1, IE<9 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( indexOf ) { + return indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + while ( j < len ) { + first[ i++ ] = second[ j++ ]; + } + + // Support: IE<9 + // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) + if ( len !== len ) { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: function() { + return +( new Date() ); + }, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v1.10.19 + * http://sizzlejs.com/ + * + * Copyright 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-04-18 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + characterEncoding + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( documentIsHTML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document (jQuery #6963) + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== strundefined && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, + doc = node ? node.ownerDocument || node : preferredDoc, + parent = doc.defaultView; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsHTML = !isXML( doc ); + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent !== parent.top ) { + // IE11 does not have attachEvent, so all must suffer + if ( parent.addEventListener ) { + parent.addEventListener( "unload", function() { + setDocument(); + }, false ); + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", function() { + setDocument(); + }); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if getElementsByClassName can be trusted + support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { + div.innerHTML = "

"; + + // Support: Safari<4 + // Catch class over-caching + div.firstChild.className = "i"; + // Support: Opera<10 + // Catch gEBCN failure to find non-leading classes + return div.getElementsByClassName("i").length === 2; + }); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowclip^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (oldCache = outerCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + outerCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context !== document && context; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is no seed and only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome<14 +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; + }); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +}); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof rootjQuery.ready !== "undefined" ? + rootjQuery.ready( selector ) : + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.extend({ + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +jQuery.fn.extend({ + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.unique( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.unique( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +}); +var rnotwhite = (/\S+/g); + + + +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + + } else if ( !(--remaining) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend({ + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +}); + +/** + * Clean-up method for dom ready events + */ +function detach() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } +} + +/** + * The ready event handler and self cleanup method + */ +function completed() { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + + +var strundefined = typeof undefined; + + + +// Support: IE<9 +// Iteration over object's inherited properties before its own +var i; +for ( i in jQuery( support ) ) { + break; +} +support.ownLast = i !== "0"; + +// Note: most support tests are defined in their respective modules. +// false until the test is run +support.inlineBlockNeedsLayout = false; + +// Execute ASAP in case we need to set body.style.zoom +jQuery(function() { + // Minified: var a,b,c,d + var val, div, body, container; + + body = document.getElementsByTagName( "body" )[ 0 ]; + if ( !body || !body.style ) { + // Return for frameset docs that don't have a body + return; + } + + // Setup + div = document.createElement( "div" ); + container = document.createElement( "div" ); + container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; + body.appendChild( container ).appendChild( div ); + + if ( typeof div.style.zoom !== strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; + + support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; + if ( val ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); +}); + + + + +(function() { + var div = document.createElement( "div" ); + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +/** + * Determines whether an object can have data + */ +jQuery.acceptData = function( elem ) { + var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], + nodeType = +elem.nodeType || 1; + + // Do not set data on non-element DOM nodes because it will not be cleared (#8335). + return nodeType !== 1 && nodeType !== 9 ? + false : + + // Nodes accept data unless otherwise specified; rejection can be conditional + !noData || noData !== true && elem.getAttribute("classid") === noData; +}; + + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + +function internalData( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // The following elements (space-suffixed to avoid Object.prototype collisions) + // throw uncatchable exceptions if you attempt to set expando properties + noData: { + "applet ": true, + "embed ": true, + // ...but Flash objects (which have this classid) *can* handle expandos + "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var i, name, data, + elem = this[0], + attrs = elem && elem.attributes; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return arguments.length > 1 ? + + // Sets one value + this.each(function() { + jQuery.data( this, key, value ); + }) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + + +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; +}; +var rcheckableType = (/^(?:checkbox|radio)$/i); + + + +(function() { + // Minified: var a,b,c + var input = document.createElement( "input" ), + div = document.createElement( "div" ), + fragment = document.createDocumentFragment(); + + // Setup + div.innerHTML = "
a"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName( "tbody" ).length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = + document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + input.type = "checkbox"; + input.checked = true; + fragment.appendChild( input ); + support.appendChecked = input.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE6-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // #11217 - WebKit loses check when the name is after the checked attribute + fragment.appendChild( div ); + div.innerHTML = ""; + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + support.noCloneEvent = true; + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } +})(); + + +(function() { + var i, eventName, + div = document.createElement( "div" ); + + // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) + for ( i in { submit: true, change: true, focusin: true }) { + eventName = "on" + i; + + if ( !(support[ i + "Bubbles" ] = eventName in window) ) { + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + div.setAttribute( eventName, "t" ); + support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && jQuery.acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + // Support: IE < 9, Android < 4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + jQuery._removeData( doc, fix ); + } else { + jQuery._data( doc, fix, attaches ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + col: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!support.noCloneEvent || !support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
" && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + deletedIds.push( id ); + } + } + } + } + } +}); + +jQuery.fn.extend({ + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + remove: function( selector, keepData /* Internal Use Only */ ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map(function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var arg = arguments[ 0 ]; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + arg = this.parentNode; + + jQuery.cleanData( getAll( this ) ); + + if ( arg ) { + arg.replaceChild( elem, this ); + } + }); + + // Force removal if there was no new content (e.g., from empty arguments) + return arg && (arg.length || arg.nodeType) ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, self.html() ); + } + self.domManip( args, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[i], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + + +var iframe, + elemdisplay = {}; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var style, + elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + // getDefaultComputedStyle might be reliably used only on attached element + display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? + + // Use of this method is a temporary fix (more like optmization) until something better comes along, + // since it was removed from specification and supported only in FF + style.display : jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = (iframe || jQuery( "