Merge ~ahasenack/ubuntu/+source/python-maxminddb:focal-python-maxminddb-1.5.2-update into ubuntu/+source/python-maxminddb:ubuntu/devel

Proposed by Andreas Hasenack
Status: Merged
Approved by: Andreas Hasenack
Approved revision: 21f19875d091eecd13074ff3e7fbed52e3000507
Merge reported by: Andreas Hasenack
Merged at revision: 21f19875d091eecd13074ff3e7fbed52e3000507
Proposed branch: ~ahasenack/ubuntu/+source/python-maxminddb:focal-python-maxminddb-1.5.2-update
Merge into: ubuntu/+source/python-maxminddb:ubuntu/devel
Diff against target: 69325 lines (+16657/-798)
42 files modified
HISTORY.rst (+29/-4)
PKG-INFO (+140/-0)
README.rst (+14/-5)
debian/changelog (+16/-0)
debian/control (+3/-1)
debian/copyright (+1/-1)
debian/patches/rebuild-sphinx-docs.patch (+283/-0)
debian/patches/series (+1/-0)
debian/rules (+5/-4)
dev/null (+0/-528)
docs/html/.buildinfo (+4/-0)
docs/html/_sources/index.rst.txt (+1/-1)
docs/html/_static/basic.css (+768/-0)
docs/html/_static/doctools.js (+314/-0)
docs/html/_static/documentation_options.js (+11/-0)
docs/html/_static/jquery-3.4.1.js (+10598/-0)
docs/html/_static/jquery.js (+2/-0)
docs/html/_static/language_data.js (+297/-0)
docs/html/_static/pygments.css (+69/-0)
docs/html/_static/searchtools.js (+506/-0)
docs/html/_static/sphinxdoc.css (+345/-0)
docs/html/_static/underscore-1.3.1.js (+999/-0)
docs/html/_static/underscore.js (+31/-0)
docs/html/genindex.html (+218/-0)
docs/html/index.html (+439/-0)
docs/html/py-modindex.html (+105/-0)
docs/html/search.html (+91/-0)
docs/html/searchindex.js (+1/-0)
extension/maxminddb.c (+759/-0)
maxminddb.egg-info/PKG-INFO (+140/-0)
maxminddb.egg-info/SOURCES.txt (+74/-0)
maxminddb.egg-info/dependency_links.txt (+1/-0)
maxminddb.egg-info/top_level.txt (+1/-0)
maxminddb/__init__.py (+3/-3)
maxminddb/compat.py (+0/-3)
maxminddb/decoder.py (+64/-51)
maxminddb/file.py (+3/-5)
maxminddb/reader.py (+45/-28)
setup.cfg (+5/-1)
setup.py (+51/-61)
tests/decoder_test.py (+3/-6)
tests/reader_test.py (+217/-96)
Reviewer Review Type Date Requested Status
Christian Ehrhardt  (community) Approve
Canonical Server Pending
Review via email: mp+380854@code.launchpad.net

Description of the change

Update to version 1.5.2, going ahead of debian.

Long description because this is for a MIR. FFe bug linked.

PPA: https://launchpad.net/~ahasenack/+archive/ubuntu/python-maxminddb-update/

Long explanation for the single patch I added.

TL;DR we don't want to ship duplicates of javascript files in the doc package, like jquery, which has its own deb package already.

There are two places for upstream releases:
- https://github.com/maxmind/MaxMind-DB-Reader-python/releases: basically a git checkout
- https://pypi.org/project/maxminddb/ a trimmed down tarball, and this is where d/watch points at. This is the tarball I used.

The github tarballs lack the test files, so tests fail to run. But they have the doc source directory, which means sphinx can be used to rebuild the docs.

The pypi tarball has the sphinx docs already built, and has the test files. Looks like a winner!

The problem with sphinx docs being already built, despite making lintian unhappy, is that it means some javascript files will be shipped with the doc package, files for which we have packages in ubuntu already. Duplication. Security (potential) nightmare.

dh_sphinxdoc can be used to detect this, and replace those files with symlinks to /usr/share/javascript/**, where they are installed by their respective packages. Nice.

To do that, dh_sphinxdoc checks the md5 hash of the files in /usr/share/javascript/** and compares it to the md5 hash of the files shipped in the python-maxminddb source. For jquery, they don't match, because that tarball was generated on a system with jquery 3.4.1, and ubuntu has 3.3.1. Oops.

dh_sphinxdoc is also not happy with the built documentation, and complains about unknown javascript files, and has a bug[1] which was fixed in debian already, but not Ubuntu.

I thought it would be easier to rebuild the sphinx doc in this package than to copy over from some other git repo the binary database files used for the tests. After all, the "source" of the documentation is a simple index.rst file that is shipped in the tarball, despite the docs being pre-built.

For the other changes:
- didn't cherry-pick https://salsa.debian.org/debian/python-maxminddb/-/commit/f94b9331c12093b12ea9dfa781dc4e566ec54963 because the examples/ directory is gone from the pypi (d/watch) tarball
- lintian fix for R³
- clean up the clean (hah) d/rules override

Let's talk about lintian:
$ lintian -I --pedantic
E: python-maxminddb source: source-is-missing docs/html/_static/jquery.js line length is 32683 characters (>512)
E: python-maxminddb source: source-is-missing docs/html/_static/underscore.js line length is 519 characters (>512)
I: python-maxminddb source: out-of-date-standards-version 4.4.0 (released 2019-07-07) (current is 4.5.0)
P: python-maxminddb source: source-contains-prebuilt-javascript-object docs/html/_static/jquery.js line length is 32683 characters (>512)
P: python-maxminddb source: source-contains-prebuilt-javascript-object docs/html/_static/underscore.js line length is 519 characters (>512)
P: python-maxminddb source: source-contains-prebuilt-sphinx-documentation docs/html/
P: python-maxminddb source: very-long-line-length-in-source-file docs/html/_static/jquery.js line length is 32683 characters (>512)
P: python-maxminddb source: very-long-line-length-in-source-file docs/html/_static/underscore.js line length is 519 characters (>512)

Lintian is definitely upset with the built sphinx docs. Since we are rebuilding the docs, there isn't really much to do about the above. Perhaps the "E:" tags could be fixed by this, as suggested by lintian:

N: Please repack your package to include the source or add it to
N: "debian/missing-sources" directory.

I mean the debian/missing-sources directory. If you want me to try something about that, let me know.

1. https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=953567

To post a comment you must log in.
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

I came up with a bunch of questions on review, but re-reading the statement above answered all of them. Thanks for explaining the background and decisions taking while working on this!

Rebuilding the docs was the right choice, that way if ever someone patches the doc-src it will actually have an impact to the results - otherwise people might wonder when entertaining this.
So it is the right choice not only to silence lintian :-)

The doc build tries to access "http://docs.python.org/objects.inv" - it gladly fails and goes on. Just saying this is a dynamic we might not want to have in the build, but not a blocker for now.

I also know that mdeslaur asked for the tests to work, and I found at least those to run properly at build:
  Ran 231 tests in 3.925s

You could open a salsa MP as well (or chime in on 953567) to complete this. Just to help Debian as well as increasing the chance to later on be able to make this a sync again.

+1 overall, thanks!

review: Approve
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

> I also know that mdeslaur asked for the tests to work, and I found at least those to run properly > at build:
> Ran 231 tests in 3.925s

That was for libcbor, of the openssh fido mir

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Thanks for the review. I'll upload this, so we can close the MIR, and then check with debian.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Taggina and uploading 21f19875d091eecd13074ff3e7fbed52e3000507

$ git push pkg upload/1.5.2-0ubuntu1
Enumerating objects: 153, done.
Counting objects: 100% (153/153), done.
Delta compression using up to 4 threads
Compressing objects: 100% (102/102), done.
Writing objects: 100% (109/109), 273.36 KiB | 283.00 KiB/s, done.
Total 109 (delta 33), reused 1 (delta 0)
remote: Resolving deltas: 100% (33/33), completed with 15 local objects.
To ssh://git.launchpad.net/~usd-import-team/ubuntu/+source/python-maxminddb
 * [new tag] upload/1.5.2-0ubuntu1 -> upload/1.5.2-0ubuntu1

$ dput ubuntu ../python-maxminddb_1.5.2-0ubuntu1_source.changes
Checking signature on .changes
gpg: ../python-maxminddb_1.5.2-0ubuntu1_source.changes: Valid signature from AC983EB5BF6BCBA9
Checking signature on .dsc
gpg: ../python-maxminddb_1.5.2-0ubuntu1.dsc: Valid signature from AC983EB5BF6BCBA9
Uploading to ubuntu (via ftp to upload.ubuntu.com):
  Uploading python-maxminddb_1.5.2-0ubuntu1.dsc: done.
  Uploading python-maxminddb_1.5.2.orig.tar.gz: done.
  Uploading python-maxminddb_1.5.2-0ubuntu1.debian.tar.xz: done.
  Uploading python-maxminddb_1.5.2-0ubuntu1_source.buildinfo: done.
  Uploading python-maxminddb_1.5.2-0ubuntu1_source.changes: done.
Successfully uploaded packages.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

This migrated into focal release.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/.gitignore b/.gitignore
2deleted file mode 100644
3index 7c72610..0000000
4--- a/.gitignore
5+++ /dev/null
6@@ -1,20 +0,0 @@
7-*.egg
8-*.iml
9-*.pyc
10-*.so
11-*.sw?
12-*~
13-.coverage
14-.eggs
15-.idea
16-build
17-core
18-dist
19-docs/_build
20-docs/html
21-env/
22-MANIFEST
23-maxminddb.egg-info/
24-pylint.txt
25-valgrind-python.supp
26-violations.pyflakes.txt
27diff --git a/.gitmodules b/.gitmodules
28deleted file mode 100644
29index 9cf24ec..0000000
30--- a/.gitmodules
31+++ /dev/null
32@@ -1,3 +0,0 @@
33-[submodule "tests/data"]
34- path = tests/data
35- url = git://github.com/maxmind/MaxMind-DB.git
36diff --git a/.pylintrc b/.pylintrc
37deleted file mode 100644
38index 19353df..0000000
39--- a/.pylintrc
40+++ /dev/null
41@@ -1,6 +0,0 @@
42-[MESSAGES CONTROL]
43-disable=R0201,W0105
44-
45-[BASIC]
46-
47-no-docstring-rgx=_.*
48diff --git a/.travis-yapf.sh b/.travis-yapf.sh
49deleted file mode 100755
50index eb9f613..0000000
51--- a/.travis-yapf.sh
52+++ /dev/null
53@@ -1,14 +0,0 @@
54-#!/bin/bash
55-
56-diff=$(yapf -rd maxminddb tests)
57-
58-if [[ $? != 0 ]]; then
59- echo "yapf failed to run."
60- echo "$diff"
61- exit $?
62-elif [[ $diff ]]; then
63- echo "$diff"
64- exit 1
65-else
66- exit 0
67-fi
68diff --git a/.travis.yml b/.travis.yml
69deleted file mode 100644
70index 3e8e174..0000000
71--- a/.travis.yml
72+++ /dev/null
73@@ -1,55 +0,0 @@
74-language: python
75-
76-python:
77- - 2.6
78- - 2.7
79- - 3.3
80- - 3.4
81- - 3.5
82- - 3.6
83- - 3.7-dev
84- - pypy
85-
86-before_install:
87- - git submodule update --init --recursive
88- - git clone --recursive git://github.com/maxmind/libmaxminddb
89- - cd libmaxminddb
90- - ./bootstrap
91- - ./configure
92- - make
93- - sudo make install
94- - sudo ldconfig
95- - cd ..
96- - pip install coverage coveralls
97- - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pip install pylint yapf; fi
98- - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi
99-
100-script:
101- - if [[ $TRAVIS_PYTHON_VERSION != 'pypy' ]]; then export MM_FORCE_EXT_TESTS=1; fi
102- - CFLAGS="-Werror -Wall -Wextra" coverage run --source maxminddb setup.py test
103- - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pylint --rcfile .pylintrc maxminddb/*.py; fi
104- - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then ./.travis-yapf.sh; fi
105-
106-after_success:
107- - coveralls
108-
109-notifications:
110- email:
111- recipients:
112- - dev-ci@maxmind.com
113- on_success: change
114- on_failure: always
115-
116-env:
117- global:
118- - secure: "pVcpV/al5Q607TbRzl/sbkdsx5hUjxehaJm6t5tgWrFn45icwdZrPw3JWcpt0R57NhPvXHxcJdm4WBtcGElWoDtR52QOW3yYh+gRw23y1MJg+5qHIbh5R1sOC/fLJ9TzQzvvRH5QQ5bKIe1hRQW9Cpqm7nX5Zhq6SqnAzcG1emE="
119-
120-addons:
121- coverity_scan:
122- project:
123- name: "maxmind/MaxMind-DB-Reader-python"
124- description: "Build submitted via Travis CI"
125- notification_email: dev-ci@maxmind.com
126- build_command_prepend: "python setup.py clean"
127- build_command: "python setup.py build"
128- branch_pattern: .*coverity.*
129diff --git a/.uncrustify.cfg b/.uncrustify.cfg
130deleted file mode 100644
131index 46b4428..0000000
132--- a/.uncrustify.cfg
133+++ /dev/null
134@@ -1,78 +0,0 @@
135-#
136-# based on uncrustify config file for the linux kernel
137-#
138-
139-code_width = 80
140-indent_case_brace = 4
141-indent_columns = 4
142-indent_label = 2 # pos: absolute col, neg: relative column
143-indent_with_tabs = 0
144-
145-#
146-# inter-symbol newlines
147-#
148-nl_brace_else = remove # "} else" vs "} \n else" - cuddle else
149-nl_brace_while = remove # "} while" vs "} \n while" - cuddle while
150-nl_do_brace = remove # "do {" vs "do \n {"
151-nl_else_brace = remove # "else {" vs "else \n {"
152-nl_enum_brace = remove # "enum {" vs "enum \n {"
153-nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{"
154-nl_fdef_brace = force # "int foo() {" vs "int foo()\n{"
155-nl_for_brace = remove # "for () {" vs "for () \n {"
156-nl_func_var_def_blk = 0 # don't add newlines after a block of var declarations
157-nl_if_brace = remove # "if () {" vs "if () \n {"
158-nl_multi_line_define = true
159-nl_struct_brace = remove # "struct {" vs "struct \n {"
160-nl_switch_brace = remove # "switch () {" vs "switch () \n {"
161-nl_union_brace = remove # "union {" vs "union \n {"
162-nl_while_brace = remove # "while () {" vs "while () \n {"
163-
164-
165-#
166-# Source code modifications
167-#
168-mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();"
169-mod_full_brace_for = force # "for () a--;" vs "for () { a--; }"
170-mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }"
171-mod_full_brace_nl = 3 # don't remove if more than 3 newlines
172-mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }"
173-mod_paren_on_return = remove # "return 1;" vs "return (1);"
174-
175-
176-#
177-# inter-character spacing options
178-#
179-sp_after_cast = remove # "(int) a" vs "(int)a"
180-sp_after_comma = force
181-sp_after_sparen = force # "if () {" vs "if (){"
182-sp_arith = force
183-sp_assign = force
184-sp_assign = force
185-sp_before_comma = remove
186-sp_before_ptr_star = force # "char *foo" vs "char* foo
187-sp_before_sparen = force # "if (" vs "if("
188-sp_between_ptr_star = remove # "char * *foo" vs "char **foo"
189-sp_bool = force
190-sp_compare = force
191-sp_func_call_paren = remove # "foo (" vs "foo("
192-sp_func_def_paren = remove # "int foo (){" vs "int foo(){"
193-sp_func_proto_paren = remove # "int foo ();" vs "int foo();"
194-sp_inside_braces = force # "{ 1 }" vs "{1}"
195-sp_inside_braces_enum = force # "{ 1 }" vs "{1}"
196-sp_inside_braces_struct = force # "{ 1 }" vs "{1}"
197-sp_inside_sparen = remove
198-sp_paren_brace = force
199-sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)"
200-
201-#
202-# Aligning stuff
203-#
204-align_enum_equ_span = 4 # '=' in enum definition
205-align_nl_cont = true
206-align_on_tabstop = FALSE # align on tabstops
207-align_right_cmt_span = 3
208-align_struct_init_span = 1
209-align_struct_init_span = 3 # align stuff in a structure init '= { }'
210-align_var_def_star_style = 2 # void *foo;
211-align_var_struct_span = 0
212-align_with_tabs = FALSE # use tabs to align
213diff --git a/HISTORY.rst b/HISTORY.rst
214index 390f5f0..5784604 100644
215--- a/HISTORY.rst
216+++ b/HISTORY.rst
217@@ -3,6 +3,31 @@
218 History
219 -------
220
221+1.5.2 (2019-12-20)
222+++++++++++++++++++
223+
224+* Minor performance improvements in the pure Python reader.
225+
226+1.5.1 (2019-09-27)
227+++++++++++++++++++
228+
229+* Fix a possible segfault due to not correctly incrementing the reference
230+ on a returned object.
231+
232+1.5.0 (2019-09-27)
233+++++++++++++++++++
234+
235+* Python 3.3 and 3.4 are no longer supported.
236+* The extension source directory was moved to prevent an ``ImportWarning``
237+ when importing the module on Python 2 with ``-Wdefault`` set. Reported by
238+ David Szotten and Craig de Stigter. GitHub #31.
239+* The ``get`` method now accepts ``ipaddress.IPv4Address`` and
240+ ``ipaddress.IPv6Address`` objects in addition to strings. This works with
241+ both the pure Python implementation as well as the extension. Based on a
242+ pull request #48 by Eric Pruitt. GitHub #50.
243+* A new method, ``get_with_prefix_len``, was added. This method returns a
244+ tuple containing the record and the prefix length.
245+
246 1.4.1 (2018-06-22)
247 ++++++++++++++++++
248
249@@ -12,13 +37,13 @@ History
250 ++++++++++++++++++
251
252 * IMPORTANT: Previously, the pure Python reader would allow
253- `ipaddress.IPv4Address` and `ipaddress.IPv6Address` objects when calling
254- `.get()`. This would fail with the C extension. The fact that these objects
255+ ``ipaddress.IPv4Address`` and ``ipaddress.IPv6Address`` objects when calling
256+ ``.get()``. This would fail with the C extension. The fact that these objects
257 worked at all was an implementation detail and has varied with different
258 releases. This release makes the pure Python implementation consistent
259- with the extension. A `TypeError` will now be thrown if you attempt to
260+ with the extension. A ``TypeError`` will now be thrown if you attempt to
261 use these types with either the pure Python implementation or the
262- extension. The IP address passed to `.get()` should be a string type.
263+ extension. The IP address passed to ``.get()`` should be a string type.
264 * Fix issue where incorrect size was used when unpacking some types with the
265 pure Python reader. Reported by Lee Symes. GitHub #30.
266 * You may now pass in the database via a file descriptor rather than a file
267diff --git a/PKG-INFO b/PKG-INFO
268new file mode 100644
269index 0000000..1a961e9
270--- /dev/null
271+++ b/PKG-INFO
272@@ -0,0 +1,140 @@
273+Metadata-Version: 1.2
274+Name: maxminddb
275+Version: 1.5.2
276+Summary: Reader for the MaxMind DB format
277+Home-page: http://www.maxmind.com/
278+Author: Gregory Oschwald
279+Author-email: goschwald@maxmind.com
280+License: Apache License, Version 2.0
281+Description: ========================
282+ MaxMind DB Python Module
283+ ========================
284+
285+ Description
286+ -----------
287+
288+ This is a Python module for reading MaxMind DB files. The module includes both
289+ a pure Python reader and an optional C extension.
290+
291+ MaxMind DB is a binary file format that stores data indexed by IP address
292+ subnets (IPv4 or IPv6).
293+
294+ Installation
295+ ------------
296+
297+ If you want to use the C extension, you must first install `libmaxminddb
298+ <https://github.com/maxmind/libmaxminddb>`_ C library installed before
299+ installing this extension. If the library is not available, the module will
300+ fall-back to a pure Python implementation.
301+
302+ To install maxminddb, type:
303+
304+ .. code-block:: bash
305+
306+ $ pip install maxminddb
307+
308+ If you are not able to use pip, you may also use easy_install from the
309+ source directory:
310+
311+ .. code-block:: bash
312+
313+ $ easy_install .
314+
315+ Usage
316+ -----
317+
318+ To use this module, you must first download or create a MaxMind DB file. We
319+ provide `free GeoLite2 databases
320+ <https://dev.maxmind.com/geoip/geoip2/geolite2>`_. These files must be
321+ decompressed with ``gunzip``.
322+
323+ After you have obtained a database and imported the module, call
324+ ``open_database`` with a path, or file descriptor (in the case of MODE_FD),
325+ to the database as the first argument. Optionally, you may pass a mode as the
326+ second argument. The modes are exported from ``maxminddb``. Valid modes are:
327+
328+ * MODE_MMAP_EXT - use the C extension with memory map.
329+ * MODE_MMAP - read from memory map. Pure Python.
330+ * MODE_FILE - read database as standard file. Pure Python.
331+ * MODE_MEMORY - load database into memory. Pure Python.
332+ * MODE_FD - load database into memory from a file descriptor. Pure Python.
333+ * MODE_AUTO - try MODE_MMAP_EXT, MODE_MMAP, MODE_FILE in that order. Default.
334+
335+ **NOTE**: When using ``MODE_FD``, it is the *caller's* responsibility to be
336+ sure that the file descriptor gets closed properly. The caller may close the
337+ file descriptor immediately after the ``Reader`` object is created.
338+
339+ The ``open_database`` function returns a ``Reader`` object. To look up an IP
340+ address, use the ``get`` method on this object. The method will return the
341+ corresponding values for the IP address from the database (e.g., a dictionary
342+ for GeoIP2/GeoLite2 databases). If the database does not contain a record for
343+ that IP address, the method will return ``None``.
344+
345+ If you wish to also retrieve the prefix length for the record, use the
346+ ``get_with_prefix_len`` method. This returns a tuple containing the record
347+ followed by the network prefix length associated with the record.
348+
349+ Example
350+ -------
351+
352+ .. code-block:: pycon
353+
354+ >>> import maxminddb
355+ >>>
356+ >>> reader = maxminddb.open_database('GeoLite2-City.mmdb')
357+ >>>
358+ >>> reader.get('1.1.1.1')
359+ {'country': ... }
360+ >>>
361+ >>> reader.get_with_prefix_len('1.1.1.1')
362+ ({'country': ... }, 24)
363+ >>>
364+ >>> reader.close()
365+
366+ Exceptions
367+ ----------
368+
369+ The module will return an ``InvalidDatabaseError`` if the database is corrupt
370+ or otherwise invalid. A ``ValueError`` will be thrown if you look up an
371+ invalid IP address or an IPv6 address in an IPv4 database.
372+
373+ Requirements
374+ ------------
375+
376+ This code requires Python 2.7+ or 3.5+. Older versions are not supported. The C
377+ extension requires CPython. The pure Python implementation has been tested with
378+ PyPy.
379+
380+ On Python 2, the `ipaddress module <https://pypi.python.org/pypi/ipaddress>`_ is
381+ required.
382+
383+ Versioning
384+ ----------
385+
386+ The MaxMind DB Python module uses `Semantic Versioning <https://semver.org/>`_.
387+
388+ Support
389+ -------
390+
391+ Please report all issues with this code using the `GitHub issue tracker
392+ <https://github.com/maxmind/MaxMind-DB-Reader-python/issues>`_
393+
394+ If you are having an issue with a MaxMind service that is not specific to this
395+ API, please contact `MaxMind support <https://www.maxmind.com/en/support>`_ for
396+ assistance.
397+
398+Platform: UNKNOWN
399+Classifier: Development Status :: 5 - Production/Stable
400+Classifier: Environment :: Web Environment
401+Classifier: Intended Audience :: Developers
402+Classifier: Intended Audience :: System Administrators
403+Classifier: License :: OSI Approved :: Apache Software License
404+Classifier: Programming Language :: Python :: 2.7
405+Classifier: Programming Language :: Python :: 3
406+Classifier: Programming Language :: Python :: 3.5
407+Classifier: Programming Language :: Python :: 3.6
408+Classifier: Programming Language :: Python :: 3.7
409+Classifier: Programming Language :: Python
410+Classifier: Topic :: Internet :: Proxy Servers
411+Classifier: Topic :: Internet
412+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
413diff --git a/README.rst b/README.rst
414index aa2eaab..e905493 100644
415--- a/README.rst
416+++ b/README.rst
417@@ -37,7 +37,7 @@ Usage
418
419 To use this module, you must first download or create a MaxMind DB file. We
420 provide `free GeoLite2 databases
421-<http://dev.maxmind.com/geoip/geoip2/geolite2>`_. These files must be
422+<https://dev.maxmind.com/geoip/geoip2/geolite2>`_. These files must be
423 decompressed with ``gunzip``.
424
425 After you have obtained a database and imported the module, call
426@@ -62,6 +62,10 @@ corresponding values for the IP address from the database (e.g., a dictionary
427 for GeoIP2/GeoLite2 databases). If the database does not contain a record for
428 that IP address, the method will return ``None``.
429
430+If you wish to also retrieve the prefix length for the record, use the
431+``get_with_prefix_len`` method. This returns a tuple containing the record
432+followed by the network prefix length associated with the record.
433+
434 Example
435 -------
436
437@@ -70,9 +74,13 @@ Example
438 >>> import maxminddb
439 >>>
440 >>> reader = maxminddb.open_database('GeoLite2-City.mmdb')
441+ >>>
442 >>> reader.get('1.1.1.1')
443 {'country': ... }
444 >>>
445+ >>> reader.get_with_prefix_len('1.1.1.1')
446+ ({'country': ... }, 24)
447+ >>>
448 >>> reader.close()
449
450 Exceptions
451@@ -85,8 +93,9 @@ invalid IP address or an IPv6 address in an IPv4 database.
452 Requirements
453 ------------
454
455-This code requires Python 2.6+ or 3.3+. The C extension requires CPython. The
456-pure Python implementation has been tested with PyPy.
457+This code requires Python 2.7+ or 3.5+. Older versions are not supported. The C
458+extension requires CPython. The pure Python implementation has been tested with
459+PyPy.
460
461 On Python 2, the `ipaddress module <https://pypi.python.org/pypi/ipaddress>`_ is
462 required.
463@@ -94,7 +103,7 @@ required.
464 Versioning
465 ----------
466
467-The MaxMind DB Python module uses `Semantic Versioning <http://semver.org/>`_.
468+The MaxMind DB Python module uses `Semantic Versioning <https://semver.org/>`_.
469
470 Support
471 -------
472@@ -103,5 +112,5 @@ Please report all issues with this code using the `GitHub issue tracker
473 <https://github.com/maxmind/MaxMind-DB-Reader-python/issues>`_
474
475 If you are having an issue with a MaxMind service that is not specific to this
476-API, please contact `MaxMind support <http://www.maxmind.com/en/support>`_ for
477+API, please contact `MaxMind support <https://www.maxmind.com/en/support>`_ for
478 assistance.
479diff --git a/debian/changelog b/debian/changelog
480index ff5ce3d..d333eda 100644
481--- a/debian/changelog
482+++ b/debian/changelog
483@@ -1,3 +1,19 @@
484+python-maxminddb (1.5.2-0ubuntu1) focal; urgency=medium
485+
486+ * New upstream release: 1.5.2 (LP: #1867919)
487+ * Rebuild sphinx docs to avoid shipping other copies of several
488+ javascript files, like jquery.js, in the doc package:
489+ - d/p/rebuild-sphinx-docs.patch: pull in upstream's sphinx-build conf.py
490+ - d/rules: use docs-source for building docs
491+ - d/rules: remove the index.rst file from docs-source during clean
492+ * d/control: add Rules-Requires-Root: no
493+ * d/rules: update dh_auto_clean override
494+
495+ [ Faidon Liambotis]
496+ * d/copyright: Switch the copyright format URI to https
497+
498+ -- Andreas Hasenack <andreas@canonical.com> Wed, 18 Mar 2020 17:57:58 -0300
499+
500 python-maxminddb (1.4.1-2build2) focal; urgency=medium
501
502 * No-change rebuild to drop python3.7.
503diff --git a/debian/control b/debian/control
504index 390ce71..1c9fa11 100644
505--- a/debian/control
506+++ b/debian/control
507@@ -1,5 +1,6 @@
508 Source: python-maxminddb
509-Maintainer: Faidon Liambotis <paravoid@debian.org>
510+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
511+XSBC-Original-Maintainer: Faidon Liambotis <paravoid@debian.org>
512 Section: python
513 Priority: optional
514 Build-Depends:
515@@ -17,6 +18,7 @@ Homepage: https://github.com/maxmind/MaxMind-DB-Reader-python
516 Vcs-Browser: https://salsa.debian.org/debian/python-maxminddb
517 Vcs-Git: https://salsa.debian.org/debian/python-maxminddb.git
518 Testsuite: autopkgtest-pkg-python
519+Rules-Requires-Root: no
520
521 Package: python3-maxminddb
522 Architecture: any
523diff --git a/debian/copyright b/debian/copyright
524index 7d6c0ba..365443a 100644
525--- a/debian/copyright
526+++ b/debian/copyright
527@@ -1,4 +1,4 @@
528-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
529+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
530 Upstream-Name: MaxMind-DB-Reader-python
531 Source: https://github.com/maxmind/MaxMind-DB-Reader-python
532
533diff --git a/debian/patches/rebuild-sphinx-docs.patch b/debian/patches/rebuild-sphinx-docs.patch
534new file mode 100644
535index 0000000..bbce8e6
536--- /dev/null
537+++ b/debian/patches/rebuild-sphinx-docs.patch
538@@ -0,0 +1,283 @@
539+Description: Allow rebuilding the docs with sphinx
540+ The upstream tarball at https://pypi.org/project/maxminddb/ has the sphinx
541+ docs already built, but using jquery 3.4.1. Since Ubuntu has 3.3.1 at this
542+ time, dh_sphinxdoc won't symlink the jquery.js file to the sphinx copy in
543+ /usr/share/javascript/sphinxdoc/1.0/jquery.js, which will result in us
544+ shipping another jquery.js file in a debian package.
545+ .
546+ The easiest solution is to rebuild the docs at package build time, but that
547+ upstream tarball does not have the conf.py file needed by sphinx-build. That
548+ is available in the upstream git repo at
549+ https://github.com/maxmind/MaxMind-DB-Reader-python/blob/master/docs/conf.py
550+ or in the github tarball releases at
551+ https://github.com/maxmind/MaxMind-DB-Reader-python/releases
552+ .
553+ The github tarball release, on the other hand, do not have the datafiles used
554+ for the tests: they come from another remote (see the "data" directory in
555+ https://github.com/maxmind/MaxMind-DB-Reader-python/tree/master/tests). If we
556+ use the github tarball releases, we don't get to run the tests.
557+ .
558+ I believe the simplest solution is to copy over the docs/conf.py file from the
559+ github 1.5.2 release tarball, and this is what this patch does:
560+ .
561+ https://github.com/maxmind/MaxMind-DB-Reader-python/archive/v1.5.2.tar.gz
562+ SHA256: d60742040d99cbe75ca049dc901b57867b4ff07df7058af640768d51d92a82a3
563+Author: Andreas Hasenack <andreas@canonical.com)
564+Forwarded: not-needed
565+Last-Update: 2020-03-18
566+---
567+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
568+diff --git a/docs-source/conf.py b/docs-source/conf.py
569+new file mode 100644
570+index 0000000..f0ae2c9
571+--- /dev/null
572++++ b/docs-source/conf.py
573+@@ -0,0 +1,248 @@
574++#!/usr/bin/env python3
575++# -*- coding: utf-8 -*-
576++#
577++# maxminddb documentation build configuration file, created by
578++# sphinx-quickstart on Tue Apr 9 13:34:57 2013.
579++#
580++# This file is execfile()d with the current directory set to its containing dir.
581++#
582++# Note that not all possible configuration values are present in this
583++# autogenerated file.
584++#
585++# All configuration values have a default; values that are commented out
586++# serve to show the default.
587++
588++import sys
589++import os
590++
591++sys.path.insert(0, os.path.abspath('..'))
592++import maxminddb
593++
594++__version__ = maxminddb.__version__
595++
596++# If extensions (or modules to document with autodoc) are in another directory,
597++# add these directories to sys.path here. If the directory is relative to the
598++# documentation root, use os.path.abspath to make it absolute, like shown here.
599++sys.path.insert(0, os.path.abspath('..'))
600++
601++# -- General configuration -----------------------------------------------
602++
603++# If your documentation needs a minimal Sphinx version, state it here.
604++#needs_sphinx = '1.0'
605++
606++# Add any Sphinx extension module names here, as strings. They can be extensions
607++# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
608++extensions = [
609++ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
610++ 'sphinx.ext.coverage'
611++]
612++
613++# Add any paths that contain templates here, relative to this directory.
614++templates_path = ['_templates']
615++
616++# The suffix of source filenames.
617++source_suffix = '.rst'
618++
619++# The encoding of source files.
620++#source_encoding = 'utf-8-sig'
621++
622++# The master toctree document.
623++master_doc = 'index'
624++
625++# General information about the project.
626++project = 'maxminddb'
627++copyright = '2013-2019, MaxMind, Inc.'
628++
629++# The version info for the project you're documenting, acts as replacement for
630++# |version| and |release|, also used in various other places throughout the
631++# built documents.
632++#
633++# The short X.Y version.
634++version = __version__
635++# The full version, including alpha/beta/rc tags.
636++release = __version__
637++
638++# The language for content autogenerated by Sphinx. Refer to documentation
639++# for a list of supported languages.
640++#language = None
641++
642++# There are two options for replacing |today|: either, you set today to some
643++# non-false value, then it is used:
644++#today = ''
645++# Else, today_fmt is used as the format for a strftime call.
646++#today_fmt = '%B %d, %Y'
647++
648++# List of patterns, relative to source directory, that match files and
649++# directories to ignore when looking for source files.
650++exclude_patterns = ['_build']
651++
652++# The reST default role (used for this markup: `text`) to use for all documents.
653++#default_role = None
654++
655++# If true, '()' will be appended to :func: etc. cross-reference text.
656++#add_function_parentheses = True
657++
658++# If true, the current module name will be prepended to all description
659++# unit titles (such as .. function::).
660++#add_module_names = True
661++
662++# If true, sectionauthor and moduleauthor directives will be shown in the
663++# output. They are ignored by default.
664++#show_authors = False
665++
666++# The name of the Pygments (syntax highlighting) style to use.
667++pygments_style = 'sphinx'
668++
669++# A list of ignored prefixes for module index sorting.
670++#modindex_common_prefix = []
671++
672++# -- Options for HTML output ---------------------------------------------
673++
674++# The theme to use for HTML and HTML Help pages. See the documentation for
675++# a list of builtin themes.
676++html_theme = 'sphinxdoc'
677++
678++# Theme options are theme-specific and customize the look and feel of a theme
679++# further. For a list of options available for each theme, see the
680++# documentation.
681++#html_theme_options = {}
682++
683++# Add any paths that contain custom themes here, relative to this directory.
684++#html_theme_path = []
685++
686++# The name for this set of Sphinx documents. If None, it defaults to
687++# "<project> v<release> documentation".
688++#html_title = None
689++
690++# A shorter title for the navigation bar. Default is the same as html_title.
691++#html_short_title = None
692++
693++# The name of an image file (relative to this directory) to place at the top
694++# of the sidebar.
695++#html_logo = None
696++
697++# The name of an image file (within the static path) to use as favicon of the
698++# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
699++# pixels large.
700++#html_favicon = None
701++
702++# Add any paths that contain custom static files (such as style sheets) here,
703++# relative to this directory. They are copied after the builtin static files,
704++# so a file named "default.css" will overwrite the builtin "default.css".
705++html_static_path = ['_static']
706++
707++# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
708++# using the given strftime format.
709++#html_last_updated_fmt = '%b %d, %Y'
710++
711++# If true, SmartyPants will be used to convert quotes and dashes to
712++# typographically correct entities.
713++#html_use_smartypants = True
714++
715++# Custom sidebar templates, maps document names to template names.
716++#html_sidebars = {}
717++
718++# Additional templates that should be rendered to pages, maps page names to
719++# template names.
720++#html_additional_pages = {}
721++
722++# If false, no module index is generated.
723++#html_domain_indices = True
724++
725++# If false, no index is generated.
726++#html_use_index = True
727++
728++# If true, the index is split into individual pages for each letter.
729++#html_split_index = False
730++
731++# If true, links to the reST sources are added to the pages.
732++#html_show_sourcelink = True
733++
734++# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
735++#html_show_sphinx = True
736++
737++# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
738++#html_show_copyright = True
739++
740++# If true, an OpenSearch description file will be output, and all pages will
741++# contain a <link> tag referring to it. The value of this option must be the
742++# base URL from which the finished HTML is served.
743++#html_use_opensearch = ''
744++
745++# This is the file name suffix for HTML files (e.g. ".xhtml").
746++#html_file_suffix = None
747++
748++# Output file base name for HTML help builder.
749++htmlhelp_basename = 'maxminddbdoc'
750++
751++# -- Options for LaTeX output --------------------------------------------
752++
753++latex_elements = {
754++ # The paper size ('letterpaper' or 'a4paper').
755++ #'papersize': 'letterpaper',
756++
757++ # The font size ('10pt', '11pt' or '12pt').
758++ #'pointsize': '10pt',
759++
760++ # Additional stuff for the LaTeX preamble.
761++ #'preamble': '',
762++}
763++
764++# Grouping the document tree into LaTeX files. List of tuples
765++# (source start file, target name, title, author, documentclass [howto/manual]).
766++latex_documents = [
767++ ('index', 'maxminddb.tex', 'maxminddb Documentation', 'Gregory Oschwald',
768++ 'manual'),
769++]
770++
771++# The name of an image file (relative to this directory) to place at the top of
772++# the title page.
773++#latex_logo = None
774++
775++# For "manual" documents, if this is true, then toplevel headings are parts,
776++# not chapters.
777++#latex_use_parts = False
778++
779++# If true, show page references after internal links.
780++#latex_show_pagerefs = False
781++
782++# If true, show URL addresses after external links.
783++#latex_show_urls = False
784++
785++# Documents to append as an appendix to all manuals.
786++#latex_appendices = []
787++
788++# If false, no module index is generated.
789++#latex_domain_indices = True
790++
791++# -- Options for manual page output --------------------------------------
792++
793++# One entry per manual page. List of tuples
794++# (source start file, name, description, authors, manual section).
795++man_pages = [('index', 'maxminddb', 'maxminddb Documentation',
796++ ['Gregory Oschwald'], 1)]
797++
798++# If true, show URL addresses after external links.
799++#man_show_urls = False
800++
801++# -- Options for Texinfo output ------------------------------------------
802++
803++# Grouping the document tree into Texinfo files. List of tuples
804++# (source start file, target name, title, author,
805++# dir menu entry, description, category)
806++texinfo_documents = [
807++ ('index', 'maxminddb', 'maxminddb Documentation', 'Gregory Oschwald',
808++ 'maxminddb', 'MaxMind DB Reader', 'Miscellaneous'),
809++]
810++
811++# Documents to append as an appendix to all manuals.
812++#texinfo_appendices = []
813++
814++# If false, no module index is generated.
815++#texinfo_domain_indices = True
816++
817++# How to display URL addresses: 'footnote', 'no', or 'inline'.
818++#texinfo_show_urls = 'footnote'
819++
820++# Example configuration for intersphinx: refer to the Python standard library.
821++intersphinx_mapping = {'http://docs.python.org/': None}
822diff --git a/debian/patches/series b/debian/patches/series
823new file mode 100644
824index 0000000..f8a9263
825--- /dev/null
826+++ b/debian/patches/series
827@@ -0,0 +1 @@
828+rebuild-sphinx-docs.patch
829diff --git a/debian/rules b/debian/rules
830index 3774142..ac48e30 100755
831--- a/debian/rules
832+++ b/debian/rules
833@@ -7,13 +7,14 @@ export PYBUILD_NAME=maxminddb
834 dh $@ --with python3,sphinxdoc --buildsystem=pybuild
835
836 override_dh_auto_build:
837- PYTHONPATH=.:$$PYTHONPATH sphinx-build -b html -d .build/.doctrees -N docs .build/html
838+ cp docs/html/_sources/index.rst.txt docs-source/index.rst
839+ PYTHONPATH=.:$$PYTHONPATH sphinx-build -b html -d .build/.doctrees -N docs-source .build/html
840 dh_auto_build
841
842 override_dh_auto_clean:
843- dh_auto_clean
844- rm -f maxminddb/extension.so maxminddb/extension.*.so
845- rm -rf .build/ maxminddb.egg-info/
846+ dh_auto_clean --buildsystem=pybuild
847+ rm -rf .build/
848+ rm -f docs-source/index.rst
849
850 override_dh_auto_test:
851 dh_auto_test -- --before-test "ln -sf {dir}/README.rst {build_dir}/" \
852diff --git a/dev-bin/release.sh b/dev-bin/release.sh
853deleted file mode 100755
854index bd0060a..0000000
855--- a/dev-bin/release.sh
856+++ /dev/null
857@@ -1,66 +0,0 @@
858-#!/bin/bash
859-
860-set -eu -o pipefail
861-
862-changelog=$(cat HISTORY.rst)
863-
864-regex='
865-([0-9]+\.[0-9]+\.[0-9]+) \(([0-9]{4}-[0-9]{2}-[0-9]{2})\)
866-\+*
867-
868-((.|
869-)*)
870-'
871-
872-if [[ ! $changelog =~ $regex ]]; then
873- echo "Could not find date line in change log!"
874- exit 1
875-fi
876-
877-version="${BASH_REMATCH[1]}"
878-date="${BASH_REMATCH[2]}"
879-notes="$(echo "${BASH_REMATCH[3]}" | sed -n -e '/^[0-9]\+\.[0-9]\+\.[0-9]\+/,$!p')"
880-
881-if [[ "$date" -ne $(date +"%Y-%m-%d") ]]; then
882- echo "$date is not today!"
883- exit 1
884-fi
885-
886-tag="v$version"
887-
888-if [ -n "$(git status --porcelain)" ]; then
889- echo ". is not clean." >&2
890- exit 1
891-fi
892-
893-perl -pi -e "s/(?<=__version__ = ').+?(?=')/$version/gsm" maxminddb/__init__.py
894-
895-echo $"Test results:"
896-python setup.py test
897-
898-echo $'\nDiff:'
899-git diff
900-
901-echo $'\nRelease notes:'
902-echo "$notes"
903-
904-read -e -p "Commit changes and push to origin? " should_push
905-
906-if [ "$should_push" != "y" ]; then
907- echo "Aborting"
908- exit 1
909-fi
910-
911-git commit -m "Update for $tag" -a
912-
913-git push
914-
915-message="$version
916-
917-$notes"
918-
919-hub release create -m "$message" "$tag"
920-
921-git push --tags
922-
923-python setup.py release
924diff --git a/docs/Makefile b/docs/Makefile
925deleted file mode 100644
926index 316a75a..0000000
927--- a/docs/Makefile
928+++ /dev/null
929@@ -1,153 +0,0 @@
930-# Makefile for Sphinx documentation
931-#
932-
933-# You can set these variables from the command line.
934-SPHINXOPTS =
935-SPHINXBUILD = sphinx-build
936-PAPER =
937-BUILDDIR = _build
938-
939-# Internal variables.
940-PAPEROPT_a4 = -D latex_paper_size=a4
941-PAPEROPT_letter = -D latex_paper_size=letter
942-ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
943-# the i18n builder cannot share the environment and doctrees with the others
944-I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
945-
946-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
947-
948-help:
949- @echo "Please use \`make <target>' where <target> is one of"
950- @echo " html to make standalone HTML files"
951- @echo " dirhtml to make HTML files named index.html in directories"
952- @echo " singlehtml to make a single large HTML file"
953- @echo " pickle to make pickle files"
954- @echo " json to make JSON files"
955- @echo " htmlhelp to make HTML files and a HTML help project"
956- @echo " qthelp to make HTML files and a qthelp project"
957- @echo " devhelp to make HTML files and a Devhelp project"
958- @echo " epub to make an epub"
959- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
960- @echo " latexpdf to make LaTeX files and run them through pdflatex"
961- @echo " text to make text files"
962- @echo " man to make manual pages"
963- @echo " texinfo to make Texinfo files"
964- @echo " info to make Texinfo files and run them through makeinfo"
965- @echo " gettext to make PO message catalogs"
966- @echo " changes to make an overview of all changed/added/deprecated items"
967- @echo " linkcheck to check all external links for integrity"
968- @echo " doctest to run all doctests embedded in the documentation (if enabled)"
969-
970-clean:
971- -rm -rf $(BUILDDIR)/*
972-
973-html:
974- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
975- @echo
976- @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
977-
978-dirhtml:
979- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
980- @echo
981- @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
982-
983-singlehtml:
984- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
985- @echo
986- @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
987-
988-pickle:
989- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
990- @echo
991- @echo "Build finished; now you can process the pickle files."
992-
993-json:
994- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
995- @echo
996- @echo "Build finished; now you can process the JSON files."
997-
998-htmlhelp:
999- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
1000- @echo
1001- @echo "Build finished; now you can run HTML Help Workshop with the" \
1002- ".hhp project file in $(BUILDDIR)/htmlhelp."
1003-
1004-qthelp:
1005- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
1006- @echo
1007- @echo "Build finished; now you can run "qcollectiongenerator" with the" \
1008- ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
1009- @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/maxminddb.qhcp"
1010- @echo "To view the help file:"
1011- @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/maxminddb.qhc"
1012-
1013-devhelp:
1014- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
1015- @echo
1016- @echo "Build finished."
1017- @echo "To view the help file:"
1018- @echo "# mkdir -p $$HOME/.local/share/devhelp/maxminddb"
1019- @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/maxminddb"
1020- @echo "# devhelp"
1021-
1022-epub:
1023- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
1024- @echo
1025- @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
1026-
1027-latex:
1028- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
1029- @echo
1030- @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
1031- @echo "Run \`make' in that directory to run these through (pdf)latex" \
1032- "(use \`make latexpdf' here to do that automatically)."
1033-
1034-latexpdf:
1035- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
1036- @echo "Running LaTeX files through pdflatex..."
1037- $(MAKE) -C $(BUILDDIR)/latex all-pdf
1038- @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
1039-
1040-text:
1041- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
1042- @echo
1043- @echo "Build finished. The text files are in $(BUILDDIR)/text."
1044-
1045-man:
1046- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
1047- @echo
1048- @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
1049-
1050-texinfo:
1051- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
1052- @echo
1053- @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
1054- @echo "Run \`make' in that directory to run these through makeinfo" \
1055- "(use \`make info' here to do that automatically)."
1056-
1057-info:
1058- $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
1059- @echo "Running Texinfo files through makeinfo..."
1060- make -C $(BUILDDIR)/texinfo info
1061- @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
1062-
1063-gettext:
1064- $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
1065- @echo
1066- @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
1067-
1068-changes:
1069- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
1070- @echo
1071- @echo "The overview file is in $(BUILDDIR)/changes."
1072-
1073-linkcheck:
1074- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
1075- @echo
1076- @echo "Link check complete; look for any errors in the above output " \
1077- "or in $(BUILDDIR)/linkcheck/output.txt."
1078-
1079-doctest:
1080- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
1081- @echo "Testing of doctests in the sources finished, look at the " \
1082- "results in $(BUILDDIR)/doctest/output.txt."
1083diff --git a/docs/conf.py b/docs/conf.py
1084deleted file mode 100644
1085index 9b107b4..0000000
1086--- a/docs/conf.py
1087+++ /dev/null
1088@@ -1,248 +0,0 @@
1089-#!/usr/bin/env python3
1090-# -*- coding: utf-8 -*-
1091-#
1092-# maxminddb documentation build configuration file, created by
1093-# sphinx-quickstart on Tue Apr 9 13:34:57 2013.
1094-#
1095-# This file is execfile()d with the current directory set to its containing dir.
1096-#
1097-# Note that not all possible configuration values are present in this
1098-# autogenerated file.
1099-#
1100-# All configuration values have a default; values that are commented out
1101-# serve to show the default.
1102-
1103-import sys
1104-import os
1105-
1106-sys.path.insert(0, os.path.abspath('..'))
1107-import maxminddb
1108-
1109-__version__ = maxminddb.__version__
1110-
1111-# If extensions (or modules to document with autodoc) are in another directory,
1112-# add these directories to sys.path here. If the directory is relative to the
1113-# documentation root, use os.path.abspath to make it absolute, like shown here.
1114-sys.path.insert(0, os.path.abspath('..'))
1115-
1116-# -- General configuration -----------------------------------------------
1117-
1118-# If your documentation needs a minimal Sphinx version, state it here.
1119-#needs_sphinx = '1.0'
1120-
1121-# Add any Sphinx extension module names here, as strings. They can be extensions
1122-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
1123-extensions = [
1124- 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
1125- 'sphinx.ext.coverage'
1126-]
1127-
1128-# Add any paths that contain templates here, relative to this directory.
1129-templates_path = ['_templates']
1130-
1131-# The suffix of source filenames.
1132-source_suffix = '.rst'
1133-
1134-# The encoding of source files.
1135-#source_encoding = 'utf-8-sig'
1136-
1137-# The master toctree document.
1138-master_doc = 'index'
1139-
1140-# General information about the project.
1141-project = 'maxminddb'
1142-copyright = '2013-2018, MaxMind, Inc.'
1143-
1144-# The version info for the project you're documenting, acts as replacement for
1145-# |version| and |release|, also used in various other places throughout the
1146-# built documents.
1147-#
1148-# The short X.Y version.
1149-version = __version__
1150-# The full version, including alpha/beta/rc tags.
1151-release = __version__
1152-
1153-# The language for content autogenerated by Sphinx. Refer to documentation
1154-# for a list of supported languages.
1155-#language = None
1156-
1157-# There are two options for replacing |today|: either, you set today to some
1158-# non-false value, then it is used:
1159-#today = ''
1160-# Else, today_fmt is used as the format for a strftime call.
1161-#today_fmt = '%B %d, %Y'
1162-
1163-# List of patterns, relative to source directory, that match files and
1164-# directories to ignore when looking for source files.
1165-exclude_patterns = ['_build']
1166-
1167-# The reST default role (used for this markup: `text`) to use for all documents.
1168-#default_role = None
1169-
1170-# If true, '()' will be appended to :func: etc. cross-reference text.
1171-#add_function_parentheses = True
1172-
1173-# If true, the current module name will be prepended to all description
1174-# unit titles (such as .. function::).
1175-#add_module_names = True
1176-
1177-# If true, sectionauthor and moduleauthor directives will be shown in the
1178-# output. They are ignored by default.
1179-#show_authors = False
1180-
1181-# The name of the Pygments (syntax highlighting) style to use.
1182-pygments_style = 'sphinx'
1183-
1184-# A list of ignored prefixes for module index sorting.
1185-#modindex_common_prefix = []
1186-
1187-# -- Options for HTML output ---------------------------------------------
1188-
1189-# The theme to use for HTML and HTML Help pages. See the documentation for
1190-# a list of builtin themes.
1191-html_theme = 'sphinxdoc'
1192-
1193-# Theme options are theme-specific and customize the look and feel of a theme
1194-# further. For a list of options available for each theme, see the
1195-# documentation.
1196-#html_theme_options = {}
1197-
1198-# Add any paths that contain custom themes here, relative to this directory.
1199-#html_theme_path = []
1200-
1201-# The name for this set of Sphinx documents. If None, it defaults to
1202-# "<project> v<release> documentation".
1203-#html_title = None
1204-
1205-# A shorter title for the navigation bar. Default is the same as html_title.
1206-#html_short_title = None
1207-
1208-# The name of an image file (relative to this directory) to place at the top
1209-# of the sidebar.
1210-#html_logo = None
1211-
1212-# The name of an image file (within the static path) to use as favicon of the
1213-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
1214-# pixels large.
1215-#html_favicon = None
1216-
1217-# Add any paths that contain custom static files (such as style sheets) here,
1218-# relative to this directory. They are copied after the builtin static files,
1219-# so a file named "default.css" will overwrite the builtin "default.css".
1220-html_static_path = ['_static']
1221-
1222-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
1223-# using the given strftime format.
1224-#html_last_updated_fmt = '%b %d, %Y'
1225-
1226-# If true, SmartyPants will be used to convert quotes and dashes to
1227-# typographically correct entities.
1228-#html_use_smartypants = True
1229-
1230-# Custom sidebar templates, maps document names to template names.
1231-#html_sidebars = {}
1232-
1233-# Additional templates that should be rendered to pages, maps page names to
1234-# template names.
1235-#html_additional_pages = {}
1236-
1237-# If false, no module index is generated.
1238-#html_domain_indices = True
1239-
1240-# If false, no index is generated.
1241-#html_use_index = True
1242-
1243-# If true, the index is split into individual pages for each letter.
1244-#html_split_index = False
1245-
1246-# If true, links to the reST sources are added to the pages.
1247-#html_show_sourcelink = True
1248-
1249-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
1250-#html_show_sphinx = True
1251-
1252-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
1253-#html_show_copyright = True
1254-
1255-# If true, an OpenSearch description file will be output, and all pages will
1256-# contain a <link> tag referring to it. The value of this option must be the
1257-# base URL from which the finished HTML is served.
1258-#html_use_opensearch = ''
1259-
1260-# This is the file name suffix for HTML files (e.g. ".xhtml").
1261-#html_file_suffix = None
1262-
1263-# Output file base name for HTML help builder.
1264-htmlhelp_basename = 'maxminddbdoc'
1265-
1266-# -- Options for LaTeX output --------------------------------------------
1267-
1268-latex_elements = {
1269- # The paper size ('letterpaper' or 'a4paper').
1270- #'papersize': 'letterpaper',
1271-
1272- # The font size ('10pt', '11pt' or '12pt').
1273- #'pointsize': '10pt',
1274-
1275- # Additional stuff for the LaTeX preamble.
1276- #'preamble': '',
1277-}
1278-
1279-# Grouping the document tree into LaTeX files. List of tuples
1280-# (source start file, target name, title, author, documentclass [howto/manual]).
1281-latex_documents = [
1282- ('index', 'maxminddb.tex', 'maxminddb Documentation', 'Gregory Oschwald',
1283- 'manual'),
1284-]
1285-
1286-# The name of an image file (relative to this directory) to place at the top of
1287-# the title page.
1288-#latex_logo = None
1289-
1290-# For "manual" documents, if this is true, then toplevel headings are parts,
1291-# not chapters.
1292-#latex_use_parts = False
1293-
1294-# If true, show page references after internal links.
1295-#latex_show_pagerefs = False
1296-
1297-# If true, show URL addresses after external links.
1298-#latex_show_urls = False
1299-
1300-# Documents to append as an appendix to all manuals.
1301-#latex_appendices = []
1302-
1303-# If false, no module index is generated.
1304-#latex_domain_indices = True
1305-
1306-# -- Options for manual page output --------------------------------------
1307-
1308-# One entry per manual page. List of tuples
1309-# (source start file, name, description, authors, manual section).
1310-man_pages = [('index', 'maxminddb', 'maxminddb Documentation',
1311- ['Gregory Oschwald'], 1)]
1312-
1313-# If true, show URL addresses after external links.
1314-#man_show_urls = False
1315-
1316-# -- Options for Texinfo output ------------------------------------------
1317-
1318-# Grouping the document tree into Texinfo files. List of tuples
1319-# (source start file, target name, title, author,
1320-# dir menu entry, description, category)
1321-texinfo_documents = [
1322- ('index', 'maxminddb', 'maxminddb Documentation', 'Gregory Oschwald',
1323- 'maxminddb', 'MaxMind DB Reader', 'Miscellaneous'),
1324-]
1325-
1326-# Documents to append as an appendix to all manuals.
1327-#texinfo_appendices = []
1328-
1329-# If false, no module index is generated.
1330-#texinfo_domain_indices = True
1331-
1332-# How to display URL addresses: 'footnote', 'no', or 'inline'.
1333-#texinfo_show_urls = 'footnote'
1334-
1335-# Example configuration for intersphinx: refer to the Python standard library.
1336-intersphinx_mapping = {'http://docs.python.org/': None}
1337diff --git a/docs/html/.buildinfo b/docs/html/.buildinfo
1338new file mode 100644
1339index 0000000..5e0172d
1340--- /dev/null
1341+++ b/docs/html/.buildinfo
1342@@ -0,0 +1,4 @@
1343+# Sphinx build info version 1
1344+# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
1345+config: f4b35ba4b456e07a1fe93fc0f298d57b
1346+tags: 645f666f9bcd5a90fca523b33c5a78b7
1347diff --git a/docs/index.rst b/docs/html/_sources/index.rst.txt
1348similarity index 96%
1349rename from docs/index.rst
1350rename to docs/html/_sources/index.rst.txt
1351index a003c74..20fdb5a 100644
1352--- a/docs/index.rst
1353+++ b/docs/html/_sources/index.rst.txt
1354@@ -35,6 +35,6 @@ Indices and tables
1355 * :ref:`modindex`
1356 * :ref:`search`
1357
1358-:copyright: (c) 2013-2018 by MaxMind, Inc.
1359+:copyright: (c) 2013-2019 by MaxMind, Inc.
1360 :license: Apache License, Version 2.0
1361
1362diff --git a/docs/html/_static/basic.css b/docs/html/_static/basic.css
1363new file mode 100644
1364index 0000000..b04360d
1365--- /dev/null
1366+++ b/docs/html/_static/basic.css
1367@@ -0,0 +1,768 @@
1368+/*
1369+ * basic.css
1370+ * ~~~~~~~~~
1371+ *
1372+ * Sphinx stylesheet -- basic theme.
1373+ *
1374+ * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
1375+ * :license: BSD, see LICENSE for details.
1376+ *
1377+ */
1378+
1379+/* -- main layout ----------------------------------------------------------- */
1380+
1381+div.clearer {
1382+ clear: both;
1383+}
1384+
1385+/* -- relbar ---------------------------------------------------------------- */
1386+
1387+div.related {
1388+ width: 100%;
1389+ font-size: 90%;
1390+}
1391+
1392+div.related h3 {
1393+ display: none;
1394+}
1395+
1396+div.related ul {
1397+ margin: 0;
1398+ padding: 0 0 0 10px;
1399+ list-style: none;
1400+}
1401+
1402+div.related li {
1403+ display: inline;
1404+}
1405+
1406+div.related li.right {
1407+ float: right;
1408+ margin-right: 5px;
1409+}
1410+
1411+/* -- sidebar --------------------------------------------------------------- */
1412+
1413+div.sphinxsidebarwrapper {
1414+ padding: 10px 5px 0 10px;
1415+}
1416+
1417+div.sphinxsidebar {
1418+ float: left;
1419+ width: 230px;
1420+ margin-left: -100%;
1421+ font-size: 90%;
1422+ word-wrap: break-word;
1423+ overflow-wrap : break-word;
1424+}
1425+
1426+div.sphinxsidebar ul {
1427+ list-style: none;
1428+}
1429+
1430+div.sphinxsidebar ul ul,
1431+div.sphinxsidebar ul.want-points {
1432+ margin-left: 20px;
1433+ list-style: square;
1434+}
1435+
1436+div.sphinxsidebar ul ul {
1437+ margin-top: 0;
1438+ margin-bottom: 0;
1439+}
1440+
1441+div.sphinxsidebar form {
1442+ margin-top: 10px;
1443+}
1444+
1445+div.sphinxsidebar input {
1446+ border: 1px solid #98dbcc;
1447+ font-family: sans-serif;
1448+ font-size: 1em;
1449+}
1450+
1451+div.sphinxsidebar #searchbox form.search {
1452+ overflow: hidden;
1453+}
1454+
1455+div.sphinxsidebar #searchbox input[type="text"] {
1456+ float: left;
1457+ width: 80%;
1458+ padding: 0.25em;
1459+ box-sizing: border-box;
1460+}
1461+
1462+div.sphinxsidebar #searchbox input[type="submit"] {
1463+ float: left;
1464+ width: 20%;
1465+ border-left: none;
1466+ padding: 0.25em;
1467+ box-sizing: border-box;
1468+}
1469+
1470+
1471+img {
1472+ border: 0;
1473+ max-width: 100%;
1474+}
1475+
1476+/* -- search page ----------------------------------------------------------- */
1477+
1478+ul.search {
1479+ margin: 10px 0 0 20px;
1480+ padding: 0;
1481+}
1482+
1483+ul.search li {
1484+ padding: 5px 0 5px 20px;
1485+ background-image: url(file.png);
1486+ background-repeat: no-repeat;
1487+ background-position: 0 7px;
1488+}
1489+
1490+ul.search li a {
1491+ font-weight: bold;
1492+}
1493+
1494+ul.search li div.context {
1495+ color: #888;
1496+ margin: 2px 0 0 30px;
1497+ text-align: left;
1498+}
1499+
1500+ul.keywordmatches li.goodmatch a {
1501+ font-weight: bold;
1502+}
1503+
1504+/* -- index page ------------------------------------------------------------ */
1505+
1506+table.contentstable {
1507+ width: 90%;
1508+ margin-left: auto;
1509+ margin-right: auto;
1510+}
1511+
1512+table.contentstable p.biglink {
1513+ line-height: 150%;
1514+}
1515+
1516+a.biglink {
1517+ font-size: 1.3em;
1518+}
1519+
1520+span.linkdescr {
1521+ font-style: italic;
1522+ padding-top: 5px;
1523+ font-size: 90%;
1524+}
1525+
1526+/* -- general index --------------------------------------------------------- */
1527+
1528+table.indextable {
1529+ width: 100%;
1530+}
1531+
1532+table.indextable td {
1533+ text-align: left;
1534+ vertical-align: top;
1535+}
1536+
1537+table.indextable ul {
1538+ margin-top: 0;
1539+ margin-bottom: 0;
1540+ list-style-type: none;
1541+}
1542+
1543+table.indextable > tbody > tr > td > ul {
1544+ padding-left: 0em;
1545+}
1546+
1547+table.indextable tr.pcap {
1548+ height: 10px;
1549+}
1550+
1551+table.indextable tr.cap {
1552+ margin-top: 10px;
1553+ background-color: #f2f2f2;
1554+}
1555+
1556+img.toggler {
1557+ margin-right: 3px;
1558+ margin-top: 3px;
1559+ cursor: pointer;
1560+}
1561+
1562+div.modindex-jumpbox {
1563+ border-top: 1px solid #ddd;
1564+ border-bottom: 1px solid #ddd;
1565+ margin: 1em 0 1em 0;
1566+ padding: 0.4em;
1567+}
1568+
1569+div.genindex-jumpbox {
1570+ border-top: 1px solid #ddd;
1571+ border-bottom: 1px solid #ddd;
1572+ margin: 1em 0 1em 0;
1573+ padding: 0.4em;
1574+}
1575+
1576+/* -- domain module index --------------------------------------------------- */
1577+
1578+table.modindextable td {
1579+ padding: 2px;
1580+ border-collapse: collapse;
1581+}
1582+
1583+/* -- general body styles --------------------------------------------------- */
1584+
1585+div.body {
1586+ min-width: 450px;
1587+ max-width: 800px;
1588+}
1589+
1590+div.body p, div.body dd, div.body li, div.body blockquote {
1591+ -moz-hyphens: auto;
1592+ -ms-hyphens: auto;
1593+ -webkit-hyphens: auto;
1594+ hyphens: auto;
1595+}
1596+
1597+a.headerlink {
1598+ visibility: hidden;
1599+}
1600+
1601+a.brackets:before,
1602+span.brackets > a:before{
1603+ content: "[";
1604+}
1605+
1606+a.brackets:after,
1607+span.brackets > a:after {
1608+ content: "]";
1609+}
1610+
1611+h1:hover > a.headerlink,
1612+h2:hover > a.headerlink,
1613+h3:hover > a.headerlink,
1614+h4:hover > a.headerlink,
1615+h5:hover > a.headerlink,
1616+h6:hover > a.headerlink,
1617+dt:hover > a.headerlink,
1618+caption:hover > a.headerlink,
1619+p.caption:hover > a.headerlink,
1620+div.code-block-caption:hover > a.headerlink {
1621+ visibility: visible;
1622+}
1623+
1624+div.body p.caption {
1625+ text-align: inherit;
1626+}
1627+
1628+div.body td {
1629+ text-align: left;
1630+}
1631+
1632+.first {
1633+ margin-top: 0 !important;
1634+}
1635+
1636+p.rubric {
1637+ margin-top: 30px;
1638+ font-weight: bold;
1639+}
1640+
1641+img.align-left, .figure.align-left, object.align-left {
1642+ clear: left;
1643+ float: left;
1644+ margin-right: 1em;
1645+}
1646+
1647+img.align-right, .figure.align-right, object.align-right {
1648+ clear: right;
1649+ float: right;
1650+ margin-left: 1em;
1651+}
1652+
1653+img.align-center, .figure.align-center, object.align-center {
1654+ display: block;
1655+ margin-left: auto;
1656+ margin-right: auto;
1657+}
1658+
1659+img.align-default, .figure.align-default {
1660+ display: block;
1661+ margin-left: auto;
1662+ margin-right: auto;
1663+}
1664+
1665+.align-left {
1666+ text-align: left;
1667+}
1668+
1669+.align-center {
1670+ text-align: center;
1671+}
1672+
1673+.align-default {
1674+ text-align: center;
1675+}
1676+
1677+.align-right {
1678+ text-align: right;
1679+}
1680+
1681+/* -- sidebars -------------------------------------------------------------- */
1682+
1683+div.sidebar {
1684+ margin: 0 0 0.5em 1em;
1685+ border: 1px solid #ddb;
1686+ padding: 7px 7px 0 7px;
1687+ background-color: #ffe;
1688+ width: 40%;
1689+ float: right;
1690+}
1691+
1692+p.sidebar-title {
1693+ font-weight: bold;
1694+}
1695+
1696+/* -- topics ---------------------------------------------------------------- */
1697+
1698+div.topic {
1699+ border: 1px solid #ccc;
1700+ padding: 7px 7px 0 7px;
1701+ margin: 10px 0 10px 0;
1702+}
1703+
1704+p.topic-title {
1705+ font-size: 1.1em;
1706+ font-weight: bold;
1707+ margin-top: 10px;
1708+}
1709+
1710+/* -- admonitions ----------------------------------------------------------- */
1711+
1712+div.admonition {
1713+ margin-top: 10px;
1714+ margin-bottom: 10px;
1715+ padding: 7px;
1716+}
1717+
1718+div.admonition dt {
1719+ font-weight: bold;
1720+}
1721+
1722+div.admonition dl {
1723+ margin-bottom: 0;
1724+}
1725+
1726+p.admonition-title {
1727+ margin: 0px 10px 5px 0px;
1728+ font-weight: bold;
1729+}
1730+
1731+div.body p.centered {
1732+ text-align: center;
1733+ margin-top: 25px;
1734+}
1735+
1736+/* -- tables ---------------------------------------------------------------- */
1737+
1738+table.docutils {
1739+ border: 0;
1740+ border-collapse: collapse;
1741+}
1742+
1743+table.align-center {
1744+ margin-left: auto;
1745+ margin-right: auto;
1746+}
1747+
1748+table.align-default {
1749+ margin-left: auto;
1750+ margin-right: auto;
1751+}
1752+
1753+table caption span.caption-number {
1754+ font-style: italic;
1755+}
1756+
1757+table caption span.caption-text {
1758+}
1759+
1760+table.docutils td, table.docutils th {
1761+ padding: 1px 8px 1px 5px;
1762+ border-top: 0;
1763+ border-left: 0;
1764+ border-right: 0;
1765+ border-bottom: 1px solid #aaa;
1766+}
1767+
1768+table.footnote td, table.footnote th {
1769+ border: 0 !important;
1770+}
1771+
1772+th {
1773+ text-align: left;
1774+ padding-right: 5px;
1775+}
1776+
1777+table.citation {
1778+ border-left: solid 1px gray;
1779+ margin-left: 1px;
1780+}
1781+
1782+table.citation td {
1783+ border-bottom: none;
1784+}
1785+
1786+th > p:first-child,
1787+td > p:first-child {
1788+ margin-top: 0px;
1789+}
1790+
1791+th > p:last-child,
1792+td > p:last-child {
1793+ margin-bottom: 0px;
1794+}
1795+
1796+/* -- figures --------------------------------------------------------------- */
1797+
1798+div.figure {
1799+ margin: 0.5em;
1800+ padding: 0.5em;
1801+}
1802+
1803+div.figure p.caption {
1804+ padding: 0.3em;
1805+}
1806+
1807+div.figure p.caption span.caption-number {
1808+ font-style: italic;
1809+}
1810+
1811+div.figure p.caption span.caption-text {
1812+}
1813+
1814+/* -- field list styles ----------------------------------------------------- */
1815+
1816+table.field-list td, table.field-list th {
1817+ border: 0 !important;
1818+}
1819+
1820+.field-list ul {
1821+ margin: 0;
1822+ padding-left: 1em;
1823+}
1824+
1825+.field-list p {
1826+ margin: 0;
1827+}
1828+
1829+.field-name {
1830+ -moz-hyphens: manual;
1831+ -ms-hyphens: manual;
1832+ -webkit-hyphens: manual;
1833+ hyphens: manual;
1834+}
1835+
1836+/* -- hlist styles ---------------------------------------------------------- */
1837+
1838+table.hlist td {
1839+ vertical-align: top;
1840+}
1841+
1842+
1843+/* -- other body styles ----------------------------------------------------- */
1844+
1845+ol.arabic {
1846+ list-style: decimal;
1847+}
1848+
1849+ol.loweralpha {
1850+ list-style: lower-alpha;
1851+}
1852+
1853+ol.upperalpha {
1854+ list-style: upper-alpha;
1855+}
1856+
1857+ol.lowerroman {
1858+ list-style: lower-roman;
1859+}
1860+
1861+ol.upperroman {
1862+ list-style: upper-roman;
1863+}
1864+
1865+li > p:first-child {
1866+ margin-top: 0px;
1867+}
1868+
1869+li > p:last-child {
1870+ margin-bottom: 0px;
1871+}
1872+
1873+dl.footnote > dt,
1874+dl.citation > dt {
1875+ float: left;
1876+}
1877+
1878+dl.footnote > dd,
1879+dl.citation > dd {
1880+ margin-bottom: 0em;
1881+}
1882+
1883+dl.footnote > dd:after,
1884+dl.citation > dd:after {
1885+ content: "";
1886+ clear: both;
1887+}
1888+
1889+dl.field-list {
1890+ display: grid;
1891+ grid-template-columns: fit-content(30%) auto;
1892+}
1893+
1894+dl.field-list > dt {
1895+ font-weight: bold;
1896+ word-break: break-word;
1897+ padding-left: 0.5em;
1898+ padding-right: 5px;
1899+}
1900+
1901+dl.field-list > dt:after {
1902+ content: ":";
1903+}
1904+
1905+dl.field-list > dd {
1906+ padding-left: 0.5em;
1907+ margin-top: 0em;
1908+ margin-left: 0em;
1909+ margin-bottom: 0em;
1910+}
1911+
1912+dl {
1913+ margin-bottom: 15px;
1914+}
1915+
1916+dd > p:first-child {
1917+ margin-top: 0px;
1918+}
1919+
1920+dd ul, dd table {
1921+ margin-bottom: 10px;
1922+}
1923+
1924+dd {
1925+ margin-top: 3px;
1926+ margin-bottom: 10px;
1927+ margin-left: 30px;
1928+}
1929+
1930+dt:target, span.highlighted {
1931+ background-color: #fbe54e;
1932+}
1933+
1934+rect.highlighted {
1935+ fill: #fbe54e;
1936+}
1937+
1938+dl.glossary dt {
1939+ font-weight: bold;
1940+ font-size: 1.1em;
1941+}
1942+
1943+.optional {
1944+ font-size: 1.3em;
1945+}
1946+
1947+.sig-paren {
1948+ font-size: larger;
1949+}
1950+
1951+.versionmodified {
1952+ font-style: italic;
1953+}
1954+
1955+.system-message {
1956+ background-color: #fda;
1957+ padding: 5px;
1958+ border: 3px solid red;
1959+}
1960+
1961+.footnote:target {
1962+ background-color: #ffa;
1963+}
1964+
1965+.line-block {
1966+ display: block;
1967+ margin-top: 1em;
1968+ margin-bottom: 1em;
1969+}
1970+
1971+.line-block .line-block {
1972+ margin-top: 0;
1973+ margin-bottom: 0;
1974+ margin-left: 1.5em;
1975+}
1976+
1977+.guilabel, .menuselection {
1978+ font-family: sans-serif;
1979+}
1980+
1981+.accelerator {
1982+ text-decoration: underline;
1983+}
1984+
1985+.classifier {
1986+ font-style: oblique;
1987+}
1988+
1989+.classifier:before {
1990+ font-style: normal;
1991+ margin: 0.5em;
1992+ content: ":";
1993+}
1994+
1995+abbr, acronym {
1996+ border-bottom: dotted 1px;
1997+ cursor: help;
1998+}
1999+
2000+/* -- code displays --------------------------------------------------------- */
2001+
2002+pre {
2003+ overflow: auto;
2004+ overflow-y: hidden; /* fixes display issues on Chrome browsers */
2005+}
2006+
2007+span.pre {
2008+ -moz-hyphens: none;
2009+ -ms-hyphens: none;
2010+ -webkit-hyphens: none;
2011+ hyphens: none;
2012+}
2013+
2014+td.linenos pre {
2015+ padding: 5px 0px;
2016+ border: 0;
2017+ background-color: transparent;
2018+ color: #aaa;
2019+}
2020+
2021+table.highlighttable {
2022+ margin-left: 0.5em;
2023+}
2024+
2025+table.highlighttable td {
2026+ padding: 0 0.5em 0 0.5em;
2027+}
2028+
2029+div.code-block-caption {
2030+ padding: 2px 5px;
2031+ font-size: small;
2032+}
2033+
2034+div.code-block-caption code {
2035+ background-color: transparent;
2036+}
2037+
2038+div.code-block-caption + div > div.highlight > pre {
2039+ margin-top: 0;
2040+}
2041+
2042+div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */
2043+ user-select: none;
2044+}
2045+
2046+div.code-block-caption span.caption-number {
2047+ padding: 0.1em 0.3em;
2048+ font-style: italic;
2049+}
2050+
2051+div.code-block-caption span.caption-text {
2052+}
2053+
2054+div.literal-block-wrapper {
2055+ padding: 1em 1em 0;
2056+}
2057+
2058+div.literal-block-wrapper div.highlight {
2059+ margin: 0;
2060+}
2061+
2062+code.descname {
2063+ background-color: transparent;
2064+ font-weight: bold;
2065+ font-size: 1.2em;
2066+}
2067+
2068+code.descclassname {
2069+ background-color: transparent;
2070+}
2071+
2072+code.xref, a code {
2073+ background-color: transparent;
2074+ font-weight: bold;
2075+}
2076+
2077+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
2078+ background-color: transparent;
2079+}
2080+
2081+.viewcode-link {
2082+ float: right;
2083+}
2084+
2085+.viewcode-back {
2086+ float: right;
2087+ font-family: sans-serif;
2088+}
2089+
2090+div.viewcode-block:target {
2091+ margin: -1px -10px;
2092+ padding: 0 10px;
2093+}
2094+
2095+/* -- math display ---------------------------------------------------------- */
2096+
2097+img.math {
2098+ vertical-align: middle;
2099+}
2100+
2101+div.body div.math p {
2102+ text-align: center;
2103+}
2104+
2105+span.eqno {
2106+ float: right;
2107+}
2108+
2109+span.eqno a.headerlink {
2110+ position: relative;
2111+ left: 0px;
2112+ z-index: 1;
2113+}
2114+
2115+div.math:hover a.headerlink {
2116+ visibility: visible;
2117+}
2118+
2119+/* -- printout stylesheet --------------------------------------------------- */
2120+
2121+@media print {
2122+ div.document,
2123+ div.documentwrapper,
2124+ div.bodywrapper {
2125+ margin: 0 !important;
2126+ width: 100%;
2127+ }
2128+
2129+ div.sphinxsidebar,
2130+ div.related,
2131+ div.footer,
2132+ #top-link {
2133+ display: none;
2134+ }
2135+}
2136\ No newline at end of file
2137diff --git a/docs/html/_static/contents.png b/docs/html/_static/contents.png
2138new file mode 100644
2139index 0000000..6c59aa1
2140Binary files /dev/null and b/docs/html/_static/contents.png differ
2141diff --git a/docs/html/_static/doctools.js b/docs/html/_static/doctools.js
2142new file mode 100644
2143index 0000000..b33f87f
2144--- /dev/null
2145+++ b/docs/html/_static/doctools.js
2146@@ -0,0 +1,314 @@
2147+/*
2148+ * doctools.js
2149+ * ~~~~~~~~~~~
2150+ *
2151+ * Sphinx JavaScript utilities for all documentation.
2152+ *
2153+ * :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
2154+ * :license: BSD, see LICENSE for details.
2155+ *
2156+ */
2157+
2158+/**
2159+ * select a different prefix for underscore
2160+ */
2161+$u = _.noConflict();
2162+
2163+/**
2164+ * make the code below compatible with browsers without
2165+ * an installed firebug like debugger
2166+if (!window.console || !console.firebug) {
2167+ var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
2168+ "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
2169+ "profile", "profileEnd"];
2170+ window.console = {};
2171+ for (var i = 0; i < names.length; ++i)
2172+ window.console[names[i]] = function() {};
2173+}
2174+ */
2175+
2176+/**
2177+ * small helper function to urldecode strings
2178+ */
2179+jQuery.urldecode = function(x) {
2180+ return decodeURIComponent(x).replace(/\+/g, ' ');
2181+};
2182+
2183+/**
2184+ * small helper function to urlencode strings
2185+ */
2186+jQuery.urlencode = encodeURIComponent;
2187+
2188+/**
2189+ * This function returns the parsed url parameters of the
2190+ * current request. Multiple values per key are supported,
2191+ * it will always return arrays of strings for the value parts.
2192+ */
2193+jQuery.getQueryParameters = function(s) {
2194+ if (typeof s === 'undefined')
2195+ s = document.location.search;
2196+ var parts = s.substr(s.indexOf('?') + 1).split('&');
2197+ var result = {};
2198+ for (var i = 0; i < parts.length; i++) {
2199+ var tmp = parts[i].split('=', 2);
2200+ var key = jQuery.urldecode(tmp[0]);
2201+ var value = jQuery.urldecode(tmp[1]);
2202+ if (key in result)
2203+ result[key].push(value);
2204+ else
2205+ result[key] = [value];
2206+ }
2207+ return result;
2208+};
2209+
2210+/**
2211+ * highlight a given string on a jquery object by wrapping it in
2212+ * span elements with the given class name.
2213+ */
2214+jQuery.fn.highlightText = function(text, className) {
2215+ function highlight(node, addItems) {
2216+ if (node.nodeType === 3) {
2217+ var val = node.nodeValue;
2218+ var pos = val.toLowerCase().indexOf(text);
2219+ if (pos >= 0 &&
2220+ !jQuery(node.parentNode).hasClass(className) &&
2221+ !jQuery(node.parentNode).hasClass("nohighlight")) {
2222+ var span;
2223+ var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
2224+ if (isInSVG) {
2225+ span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
2226+ } else {
2227+ span = document.createElement("span");
2228+ span.className = className;
2229+ }
2230+ span.appendChild(document.createTextNode(val.substr(pos, text.length)));
2231+ node.parentNode.insertBefore(span, node.parentNode.insertBefore(
2232+ document.createTextNode(val.substr(pos + text.length)),
2233+ node.nextSibling));
2234+ node.nodeValue = val.substr(0, pos);
2235+ if (isInSVG) {
2236+ var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
2237+ var bbox = node.parentElement.getBBox();
2238+ rect.x.baseVal.value = bbox.x;
2239+ rect.y.baseVal.value = bbox.y;
2240+ rect.width.baseVal.value = bbox.width;
2241+ rect.height.baseVal.value = bbox.height;
2242+ rect.setAttribute('class', className);
2243+ addItems.push({
2244+ "parent": node.parentNode,
2245+ "target": rect});
2246+ }
2247+ }
2248+ }
2249+ else if (!jQuery(node).is("button, select, textarea")) {
2250+ jQuery.each(node.childNodes, function() {
2251+ highlight(this, addItems);
2252+ });
2253+ }
2254+ }
2255+ var addItems = [];
2256+ var result = this.each(function() {
2257+ highlight(this, addItems);
2258+ });
2259+ for (var i = 0; i < addItems.length; ++i) {
2260+ jQuery(addItems[i].parent).before(addItems[i].target);
2261+ }
2262+ return result;
2263+};
2264+
2265+/*
2266+ * backward compatibility for jQuery.browser
2267+ * This will be supported until firefox bug is fixed.
2268+ */
2269+if (!jQuery.browser) {
2270+ jQuery.uaMatch = function(ua) {
2271+ ua = ua.toLowerCase();
2272+
2273+ var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
2274+ /(webkit)[ \/]([\w.]+)/.exec(ua) ||
2275+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
2276+ /(msie) ([\w.]+)/.exec(ua) ||
2277+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
2278+ [];
2279+
2280+ return {
2281+ browser: match[ 1 ] || "",
2282+ version: match[ 2 ] || "0"
2283+ };
2284+ };
2285+ jQuery.browser = {};
2286+ jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
2287+}
2288+
2289+/**
2290+ * Small JavaScript module for the documentation.
2291+ */
2292+var Documentation = {
2293+
2294+ init : function() {
2295+ this.fixFirefoxAnchorBug();
2296+ this.highlightSearchWords();
2297+ this.initIndexTable();
2298+ if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {
2299+ this.initOnKeyListeners();
2300+ }
2301+ },
2302+
2303+ /**
2304+ * i18n support
2305+ */
2306+ TRANSLATIONS : {},
2307+ PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
2308+ LOCALE : 'unknown',
2309+
2310+ // gettext and ngettext don't access this so that the functions
2311+ // can safely bound to a different name (_ = Documentation.gettext)
2312+ gettext : function(string) {
2313+ var translated = Documentation.TRANSLATIONS[string];
2314+ if (typeof translated === 'undefined')
2315+ return string;
2316+ return (typeof translated === 'string') ? translated : translated[0];
2317+ },
2318+
2319+ ngettext : function(singular, plural, n) {
2320+ var translated = Documentation.TRANSLATIONS[singular];
2321+ if (typeof translated === 'undefined')
2322+ return (n == 1) ? singular : plural;
2323+ return translated[Documentation.PLURALEXPR(n)];
2324+ },
2325+
2326+ addTranslations : function(catalog) {
2327+ for (var key in catalog.messages)
2328+ this.TRANSLATIONS[key] = catalog.messages[key];
2329+ this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
2330+ this.LOCALE = catalog.locale;
2331+ },
2332+
2333+ /**
2334+ * add context elements like header anchor links
2335+ */
2336+ addContextElements : function() {
2337+ $('div[id] > :header:first').each(function() {
2338+ $('<a class="headerlink">\u00B6</a>').
2339+ attr('href', '#' + this.id).
2340+ attr('title', _('Permalink to this headline')).
2341+ appendTo(this);
2342+ });
2343+ $('dt[id]').each(function() {
2344+ $('<a class="headerlink">\u00B6</a>').
2345+ attr('href', '#' + this.id).
2346+ attr('title', _('Permalink to this definition')).
2347+ appendTo(this);
2348+ });
2349+ },
2350+
2351+ /**
2352+ * workaround a firefox stupidity
2353+ * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
2354+ */
2355+ fixFirefoxAnchorBug : function() {
2356+ if (document.location.hash && $.browser.mozilla)
2357+ window.setTimeout(function() {
2358+ document.location.href += '';
2359+ }, 10);
2360+ },
2361+
2362+ /**
2363+ * highlight the search words provided in the url in the text
2364+ */
2365+ highlightSearchWords : function() {
2366+ var params = $.getQueryParameters();
2367+ var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
2368+ if (terms.length) {
2369+ var body = $('div.body');
2370+ if (!body.length) {
2371+ body = $('body');
2372+ }
2373+ window.setTimeout(function() {
2374+ $.each(terms, function() {
2375+ body.highlightText(this.toLowerCase(), 'highlighted');
2376+ });
2377+ }, 10);
2378+ $('<p class="highlight-link"><a href="javascript:Documentation.' +
2379+ 'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
2380+ .appendTo($('#searchbox'));
2381+ }
2382+ },
2383+
2384+ /**
2385+ * init the domain index toggle buttons
2386+ */
2387+ initIndexTable : function() {
2388+ var togglers = $('img.toggler').click(function() {
2389+ var src = $(this).attr('src');
2390+ var idnum = $(this).attr('id').substr(7);
2391+ $('tr.cg-' + idnum).toggle();
2392+ if (src.substr(-9) === 'minus.png')
2393+ $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
2394+ else
2395+ $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
2396+ }).css('display', '');
2397+ if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
2398+ togglers.click();
2399+ }
2400+ },
2401+
2402+ /**
2403+ * helper function to hide the search marks again
2404+ */
2405+ hideSearchWords : function() {
2406+ $('#searchbox .highlight-link').fadeOut(300);
2407+ $('span.highlighted').removeClass('highlighted');
2408+ },
2409+
2410+ /**
2411+ * make the url absolute
2412+ */
2413+ makeURL : function(relativeURL) {
2414+ return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
2415+ },
2416+
2417+ /**
2418+ * get the current relative url
2419+ */
2420+ getCurrentURL : function() {
2421+ var path = document.location.pathname;
2422+ var parts = path.split(/\//);
2423+ $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
2424+ if (this === '..')
2425+ parts.pop();
2426+ });
2427+ var url = parts.join('/');
2428+ return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
2429+ },
2430+
2431+ initOnKeyListeners: function() {
2432+ $(document).keyup(function(event) {
2433+ var activeElementType = document.activeElement.tagName;
2434+ // don't navigate when in search box or textarea
2435+ if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') {
2436+ switch (event.keyCode) {
2437+ case 37: // left
2438+ var prevHref = $('link[rel="prev"]').prop('href');
2439+ if (prevHref) {
2440+ window.location.href = prevHref;
2441+ return false;
2442+ }
2443+ case 39: // right
2444+ var nextHref = $('link[rel="next"]').prop('href');
2445+ if (nextHref) {
2446+ window.location.href = nextHref;
2447+ return false;
2448+ }
2449+ }
2450+ }
2451+ });
2452+ }
2453+};
2454+
2455+// quick alias for translations
2456+_ = Documentation.gettext;
2457+
2458+$(document).ready(function() {
2459+ Documentation.init();
2460+});
2461diff --git a/docs/html/_static/documentation_options.js b/docs/html/_static/documentation_options.js
2462new file mode 100644
2463index 0000000..375482b
2464--- /dev/null
2465+++ b/docs/html/_static/documentation_options.js
2466@@ -0,0 +1,11 @@
2467+var DOCUMENTATION_OPTIONS = {
2468+ URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
2469+ VERSION: '1.5.2',
2470+ LANGUAGE: 'None',
2471+ COLLAPSE_INDEX: false,
2472+ BUILDER: 'html',
2473+ FILE_SUFFIX: '.html',
2474+ HAS_SOURCE: true,
2475+ SOURCELINK_SUFFIX: '.txt',
2476+ NAVIGATION_WITH_KEYS: false
2477+};
2478\ No newline at end of file
2479diff --git a/docs/html/_static/file.png b/docs/html/_static/file.png
2480new file mode 100644
2481index 0000000..a858a41
2482Binary files /dev/null and b/docs/html/_static/file.png differ
2483diff --git a/docs/html/_static/jquery-3.4.1.js b/docs/html/_static/jquery-3.4.1.js
2484new file mode 100644
2485index 0000000..773ad95
2486--- /dev/null
2487+++ b/docs/html/_static/jquery-3.4.1.js
2488@@ -0,0 +1,10598 @@
2489+/*!
2490+ * jQuery JavaScript Library v3.4.1
2491+ * https://jquery.com/
2492+ *
2493+ * Includes Sizzle.js
2494+ * https://sizzlejs.com/
2495+ *
2496+ * Copyright JS Foundation and other contributors
2497+ * Released under the MIT license
2498+ * https://jquery.org/license
2499+ *
2500+ * Date: 2019-05-01T21:04Z
2501+ */
2502+( function( global, factory ) {
2503+
2504+ "use strict";
2505+
2506+ if ( typeof module === "object" && typeof module.exports === "object" ) {
2507+
2508+ // For CommonJS and CommonJS-like environments where a proper `window`
2509+ // is present, execute the factory and get jQuery.
2510+ // For environments that do not have a `window` with a `document`
2511+ // (such as Node.js), expose a factory as module.exports.
2512+ // This accentuates the need for the creation of a real `window`.
2513+ // e.g. var jQuery = require("jquery")(window);
2514+ // See ticket #14549 for more info.
2515+ module.exports = global.document ?
2516+ factory( global, true ) :
2517+ function( w ) {
2518+ if ( !w.document ) {
2519+ throw new Error( "jQuery requires a window with a document" );
2520+ }
2521+ return factory( w );
2522+ };
2523+ } else {
2524+ factory( global );
2525+ }
2526+
2527+// Pass this if window is not defined yet
2528+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
2529+
2530+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
2531+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
2532+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
2533+// enough that all such attempts are guarded in a try block.
2534+"use strict";
2535+
2536+var arr = [];
2537+
2538+var document = window.document;
2539+
2540+var getProto = Object.getPrototypeOf;
2541+
2542+var slice = arr.slice;
2543+
2544+var concat = arr.concat;
2545+
2546+var push = arr.push;
2547+
2548+var indexOf = arr.indexOf;
2549+
2550+var class2type = {};
2551+
2552+var toString = class2type.toString;
2553+
2554+var hasOwn = class2type.hasOwnProperty;
2555+
2556+var fnToString = hasOwn.toString;
2557+
2558+var ObjectFunctionString = fnToString.call( Object );
2559+
2560+var support = {};
2561+
2562+var isFunction = function isFunction( obj ) {
2563+
2564+ // Support: Chrome <=57, Firefox <=52
2565+ // In some browsers, typeof returns "function" for HTML <object> elements
2566+ // (i.e., `typeof document.createElement( "object" ) === "function"`).
2567+ // We don't want to classify *any* DOM node as a function.
2568+ return typeof obj === "function" && typeof obj.nodeType !== "number";
2569+ };
2570+
2571+
2572+var isWindow = function isWindow( obj ) {
2573+ return obj != null && obj === obj.window;
2574+ };
2575+
2576+
2577+
2578+
2579+ var preservedScriptAttributes = {
2580+ type: true,
2581+ src: true,
2582+ nonce: true,
2583+ noModule: true
2584+ };
2585+
2586+ function DOMEval( code, node, doc ) {
2587+ doc = doc || document;
2588+
2589+ var i, val,
2590+ script = doc.createElement( "script" );
2591+
2592+ script.text = code;
2593+ if ( node ) {
2594+ for ( i in preservedScriptAttributes ) {
2595+
2596+ // Support: Firefox 64+, Edge 18+
2597+ // Some browsers don't support the "nonce" property on scripts.
2598+ // On the other hand, just using `getAttribute` is not enough as
2599+ // the `nonce` attribute is reset to an empty string whenever it
2600+ // becomes browsing-context connected.
2601+ // See https://github.com/whatwg/html/issues/2369
2602+ // See https://html.spec.whatwg.org/#nonce-attributes
2603+ // The `node.getAttribute` check was added for the sake of
2604+ // `jQuery.globalEval` so that it can fake a nonce-containing node
2605+ // via an object.
2606+ val = node[ i ] || node.getAttribute && node.getAttribute( i );
2607+ if ( val ) {
2608+ script.setAttribute( i, val );
2609+ }
2610+ }
2611+ }
2612+ doc.head.appendChild( script ).parentNode.removeChild( script );
2613+ }
2614+
2615+
2616+function toType( obj ) {
2617+ if ( obj == null ) {
2618+ return obj + "";
2619+ }
2620+
2621+ // Support: Android <=2.3 only (functionish RegExp)
2622+ return typeof obj === "object" || typeof obj === "function" ?
2623+ class2type[ toString.call( obj ) ] || "object" :
2624+ typeof obj;
2625+}
2626+/* global Symbol */
2627+// Defining this global in .eslintrc.json would create a danger of using the global
2628+// unguarded in another place, it seems safer to define global only for this module
2629+
2630+
2631+
2632+var
2633+ version = "3.4.1",
2634+
2635+ // Define a local copy of jQuery
2636+ jQuery = function( selector, context ) {
2637+
2638+ // The jQuery object is actually just the init constructor 'enhanced'
2639+ // Need init if jQuery is called (just allow error to be thrown if not included)
2640+ return new jQuery.fn.init( selector, context );
2641+ },
2642+
2643+ // Support: Android <=4.0 only
2644+ // Make sure we trim BOM and NBSP
2645+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
2646+
2647+jQuery.fn = jQuery.prototype = {
2648+
2649+ // The current version of jQuery being used
2650+ jquery: version,
2651+
2652+ constructor: jQuery,
2653+
2654+ // The default length of a jQuery object is 0
2655+ length: 0,
2656+
2657+ toArray: function() {
2658+ return slice.call( this );
2659+ },
2660+
2661+ // Get the Nth element in the matched element set OR
2662+ // Get the whole matched element set as a clean array
2663+ get: function( num ) {
2664+
2665+ // Return all the elements in a clean array
2666+ if ( num == null ) {
2667+ return slice.call( this );
2668+ }
2669+
2670+ // Return just the one element from the set
2671+ return num < 0 ? this[ num + this.length ] : this[ num ];
2672+ },
2673+
2674+ // Take an array of elements and push it onto the stack
2675+ // (returning the new matched element set)
2676+ pushStack: function( elems ) {
2677+
2678+ // Build a new jQuery matched element set
2679+ var ret = jQuery.merge( this.constructor(), elems );
2680+
2681+ // Add the old object onto the stack (as a reference)
2682+ ret.prevObject = this;
2683+
2684+ // Return the newly-formed element set
2685+ return ret;
2686+ },
2687+
2688+ // Execute a callback for every element in the matched set.
2689+ each: function( callback ) {
2690+ return jQuery.each( this, callback );
2691+ },
2692+
2693+ map: function( callback ) {
2694+ return this.pushStack( jQuery.map( this, function( elem, i ) {
2695+ return callback.call( elem, i, elem );
2696+ } ) );
2697+ },
2698+
2699+ slice: function() {
2700+ return this.pushStack( slice.apply( this, arguments ) );
2701+ },
2702+
2703+ first: function() {
2704+ return this.eq( 0 );
2705+ },
2706+
2707+ last: function() {
2708+ return this.eq( -1 );
2709+ },
2710+
2711+ eq: function( i ) {
2712+ var len = this.length,
2713+ j = +i + ( i < 0 ? len : 0 );
2714+ return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
2715+ },
2716+
2717+ end: function() {
2718+ return this.prevObject || this.constructor();
2719+ },
2720+
2721+ // For internal use only.
2722+ // Behaves like an Array's method, not like a jQuery method.
2723+ push: push,
2724+ sort: arr.sort,
2725+ splice: arr.splice
2726+};
2727+
2728+jQuery.extend = jQuery.fn.extend = function() {
2729+ var options, name, src, copy, copyIsArray, clone,
2730+ target = arguments[ 0 ] || {},
2731+ i = 1,
2732+ length = arguments.length,
2733+ deep = false;
2734+
2735+ // Handle a deep copy situation
2736+ if ( typeof target === "boolean" ) {
2737+ deep = target;
2738+
2739+ // Skip the boolean and the target
2740+ target = arguments[ i ] || {};
2741+ i++;
2742+ }
2743+
2744+ // Handle case when target is a string or something (possible in deep copy)
2745+ if ( typeof target !== "object" && !isFunction( target ) ) {
2746+ target = {};
2747+ }
2748+
2749+ // Extend jQuery itself if only one argument is passed
2750+ if ( i === length ) {
2751+ target = this;
2752+ i--;
2753+ }
2754+
2755+ for ( ; i < length; i++ ) {
2756+
2757+ // Only deal with non-null/undefined values
2758+ if ( ( options = arguments[ i ] ) != null ) {
2759+
2760+ // Extend the base object
2761+ for ( name in options ) {
2762+ copy = options[ name ];
2763+
2764+ // Prevent Object.prototype pollution
2765+ // Prevent never-ending loop
2766+ if ( name === "__proto__" || target === copy ) {
2767+ continue;
2768+ }
2769+
2770+ // Recurse if we're merging plain objects or arrays
2771+ if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
2772+ ( copyIsArray = Array.isArray( copy ) ) ) ) {
2773+ src = target[ name ];
2774+
2775+ // Ensure proper type for the source value
2776+ if ( copyIsArray && !Array.isArray( src ) ) {
2777+ clone = [];
2778+ } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
2779+ clone = {};
2780+ } else {
2781+ clone = src;
2782+ }
2783+ copyIsArray = false;
2784+
2785+ // Never move original objects, clone them
2786+ target[ name ] = jQuery.extend( deep, clone, copy );
2787+
2788+ // Don't bring in undefined values
2789+ } else if ( copy !== undefined ) {
2790+ target[ name ] = copy;
2791+ }
2792+ }
2793+ }
2794+ }
2795+
2796+ // Return the modified object
2797+ return target;
2798+};
2799+
2800+jQuery.extend( {
2801+
2802+ // Unique for each copy of jQuery on the page
2803+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
2804+
2805+ // Assume jQuery is ready without the ready module
2806+ isReady: true,
2807+
2808+ error: function( msg ) {
2809+ throw new Error( msg );
2810+ },
2811+
2812+ noop: function() {},
2813+
2814+ isPlainObject: function( obj ) {
2815+ var proto, Ctor;
2816+
2817+ // Detect obvious negatives
2818+ // Use toString instead of jQuery.type to catch host objects
2819+ if ( !obj || toString.call( obj ) !== "[object Object]" ) {
2820+ return false;
2821+ }
2822+
2823+ proto = getProto( obj );
2824+
2825+ // Objects with no prototype (e.g., `Object.create( null )`) are plain
2826+ if ( !proto ) {
2827+ return true;
2828+ }
2829+
2830+ // Objects with prototype are plain iff they were constructed by a global Object function
2831+ Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
2832+ return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
2833+ },
2834+
2835+ isEmptyObject: function( obj ) {
2836+ var name;
2837+
2838+ for ( name in obj ) {
2839+ return false;
2840+ }
2841+ return true;
2842+ },
2843+
2844+ // Evaluates a script in a global context
2845+ globalEval: function( code, options ) {
2846+ DOMEval( code, { nonce: options && options.nonce } );
2847+ },
2848+
2849+ each: function( obj, callback ) {
2850+ var length, i = 0;
2851+
2852+ if ( isArrayLike( obj ) ) {
2853+ length = obj.length;
2854+ for ( ; i < length; i++ ) {
2855+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
2856+ break;
2857+ }
2858+ }
2859+ } else {
2860+ for ( i in obj ) {
2861+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
2862+ break;
2863+ }
2864+ }
2865+ }
2866+
2867+ return obj;
2868+ },
2869+
2870+ // Support: Android <=4.0 only
2871+ trim: function( text ) {
2872+ return text == null ?
2873+ "" :
2874+ ( text + "" ).replace( rtrim, "" );
2875+ },
2876+
2877+ // results is for internal usage only
2878+ makeArray: function( arr, results ) {
2879+ var ret = results || [];
2880+
2881+ if ( arr != null ) {
2882+ if ( isArrayLike( Object( arr ) ) ) {
2883+ jQuery.merge( ret,
2884+ typeof arr === "string" ?
2885+ [ arr ] : arr
2886+ );
2887+ } else {
2888+ push.call( ret, arr );
2889+ }
2890+ }
2891+
2892+ return ret;
2893+ },
2894+
2895+ inArray: function( elem, arr, i ) {
2896+ return arr == null ? -1 : indexOf.call( arr, elem, i );
2897+ },
2898+
2899+ // Support: Android <=4.0 only, PhantomJS 1 only
2900+ // push.apply(_, arraylike) throws on ancient WebKit
2901+ merge: function( first, second ) {
2902+ var len = +second.length,
2903+ j = 0,
2904+ i = first.length;
2905+
2906+ for ( ; j < len; j++ ) {
2907+ first[ i++ ] = second[ j ];
2908+ }
2909+
2910+ first.length = i;
2911+
2912+ return first;
2913+ },
2914+
2915+ grep: function( elems, callback, invert ) {
2916+ var callbackInverse,
2917+ matches = [],
2918+ i = 0,
2919+ length = elems.length,
2920+ callbackExpect = !invert;
2921+
2922+ // Go through the array, only saving the items
2923+ // that pass the validator function
2924+ for ( ; i < length; i++ ) {
2925+ callbackInverse = !callback( elems[ i ], i );
2926+ if ( callbackInverse !== callbackExpect ) {
2927+ matches.push( elems[ i ] );
2928+ }
2929+ }
2930+
2931+ return matches;
2932+ },
2933+
2934+ // arg is for internal usage only
2935+ map: function( elems, callback, arg ) {
2936+ var length, value,
2937+ i = 0,
2938+ ret = [];
2939+
2940+ // Go through the array, translating each of the items to their new values
2941+ if ( isArrayLike( elems ) ) {
2942+ length = elems.length;
2943+ for ( ; i < length; i++ ) {
2944+ value = callback( elems[ i ], i, arg );
2945+
2946+ if ( value != null ) {
2947+ ret.push( value );
2948+ }
2949+ }
2950+
2951+ // Go through every key on the object,
2952+ } else {
2953+ for ( i in elems ) {
2954+ value = callback( elems[ i ], i, arg );
2955+
2956+ if ( value != null ) {
2957+ ret.push( value );
2958+ }
2959+ }
2960+ }
2961+
2962+ // Flatten any nested arrays
2963+ return concat.apply( [], ret );
2964+ },
2965+
2966+ // A global GUID counter for objects
2967+ guid: 1,
2968+
2969+ // jQuery.support is not used in Core but other projects attach their
2970+ // properties to it so it needs to exist.
2971+ support: support
2972+} );
2973+
2974+if ( typeof Symbol === "function" ) {
2975+ jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
2976+}
2977+
2978+// Populate the class2type map
2979+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
2980+function( i, name ) {
2981+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
2982+} );
2983+
2984+function isArrayLike( obj ) {
2985+
2986+ // Support: real iOS 8.2 only (not reproducible in simulator)
2987+ // `in` check used to prevent JIT error (gh-2145)
2988+ // hasOwn isn't used here due to false negatives
2989+ // regarding Nodelist length in IE
2990+ var length = !!obj && "length" in obj && obj.length,
2991+ type = toType( obj );
2992+
2993+ if ( isFunction( obj ) || isWindow( obj ) ) {
2994+ return false;
2995+ }
2996+
2997+ return type === "array" || length === 0 ||
2998+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
2999+}
3000+var Sizzle =
3001+/*!
3002+ * Sizzle CSS Selector Engine v2.3.4
3003+ * https://sizzlejs.com/
3004+ *
3005+ * Copyright JS Foundation and other contributors
3006+ * Released under the MIT license
3007+ * https://js.foundation/
3008+ *
3009+ * Date: 2019-04-08
3010+ */
3011+(function( window ) {
3012+
3013+var i,
3014+ support,
3015+ Expr,
3016+ getText,
3017+ isXML,
3018+ tokenize,
3019+ compile,
3020+ select,
3021+ outermostContext,
3022+ sortInput,
3023+ hasDuplicate,
3024+
3025+ // Local document vars
3026+ setDocument,
3027+ document,
3028+ docElem,
3029+ documentIsHTML,
3030+ rbuggyQSA,
3031+ rbuggyMatches,
3032+ matches,
3033+ contains,
3034+
3035+ // Instance-specific data
3036+ expando = "sizzle" + 1 * new Date(),
3037+ preferredDoc = window.document,
3038+ dirruns = 0,
3039+ done = 0,
3040+ classCache = createCache(),
3041+ tokenCache = createCache(),
3042+ compilerCache = createCache(),
3043+ nonnativeSelectorCache = createCache(),
3044+ sortOrder = function( a, b ) {
3045+ if ( a === b ) {
3046+ hasDuplicate = true;
3047+ }
3048+ return 0;
3049+ },
3050+
3051+ // Instance methods
3052+ hasOwn = ({}).hasOwnProperty,
3053+ arr = [],
3054+ pop = arr.pop,
3055+ push_native = arr.push,
3056+ push = arr.push,
3057+ slice = arr.slice,
3058+ // Use a stripped-down indexOf as it's faster than native
3059+ // https://jsperf.com/thor-indexof-vs-for/5
3060+ indexOf = function( list, elem ) {
3061+ var i = 0,
3062+ len = list.length;
3063+ for ( ; i < len; i++ ) {
3064+ if ( list[i] === elem ) {
3065+ return i;
3066+ }
3067+ }
3068+ return -1;
3069+ },
3070+
3071+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
3072+
3073+ // Regular expressions
3074+
3075+ // http://www.w3.org/TR/css3-selectors/#whitespace
3076+ whitespace = "[\\x20\\t\\r\\n\\f]",
3077+
3078+ // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
3079+ identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
3080+
3081+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
3082+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
3083+ // Operator (capture 2)
3084+ "*([*^$|!~]?=)" + whitespace +
3085+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
3086+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
3087+ "*\\]",
3088+
3089+ pseudos = ":(" + identifier + ")(?:\\((" +
3090+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
3091+ // 1. quoted (capture 3; capture 4 or capture 5)
3092+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
3093+ // 2. simple (capture 6)
3094+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
3095+ // 3. anything else (capture 2)
3096+ ".*" +
3097+ ")\\)|)",
3098+
3099+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
3100+ rwhitespace = new RegExp( whitespace + "+", "g" ),
3101+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
3102+
3103+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
3104+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
3105+ rdescend = new RegExp( whitespace + "|>" ),
3106+
3107+ rpseudo = new RegExp( pseudos ),
3108+ ridentifier = new RegExp( "^" + identifier + "$" ),
3109+
3110+ matchExpr = {
3111+ "ID": new RegExp( "^#(" + identifier + ")" ),
3112+ "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
3113+ "TAG": new RegExp( "^(" + identifier + "|[*])" ),
3114+ "ATTR": new RegExp( "^" + attributes ),
3115+ "PSEUDO": new RegExp( "^" + pseudos ),
3116+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
3117+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
3118+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
3119+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
3120+ // For use in libraries implementing .is()
3121+ // We use this for POS matching in `select`
3122+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
3123+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
3124+ },
3125+
3126+ rhtml = /HTML$/i,
3127+ rinputs = /^(?:input|select|textarea|button)$/i,
3128+ rheader = /^h\d$/i,
3129+
3130+ rnative = /^[^{]+\{\s*\[native \w/,
3131+
3132+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
3133+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
3134+
3135+ rsibling = /[+~]/,
3136+
3137+ // CSS escapes
3138+ // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
3139+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
3140+ funescape = function( _, escaped, escapedWhitespace ) {
3141+ var high = "0x" + escaped - 0x10000;
3142+ // NaN means non-codepoint
3143+ // Support: Firefox<24
3144+ // Workaround erroneous numeric interpretation of +"0x"
3145+ return high !== high || escapedWhitespace ?
3146+ escaped :
3147+ high < 0 ?
3148+ // BMP codepoint
3149+ String.fromCharCode( high + 0x10000 ) :
3150+ // Supplemental Plane codepoint (surrogate pair)
3151+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
3152+ },
3153+
3154+ // CSS string/identifier serialization
3155+ // https://drafts.csswg.org/cssom/#common-serializing-idioms
3156+ rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
3157+ fcssescape = function( ch, asCodePoint ) {
3158+ if ( asCodePoint ) {
3159+
3160+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
3161+ if ( ch === "\0" ) {
3162+ return "\uFFFD";
3163+ }
3164+
3165+ // Control characters and (dependent upon position) numbers get escaped as code points
3166+ return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
3167+ }
3168+
3169+ // Other potentially-special ASCII characters get backslash-escaped
3170+ return "\\" + ch;
3171+ },
3172+
3173+ // Used for iframes
3174+ // See setDocument()
3175+ // Removing the function wrapper causes a "Permission Denied"
3176+ // error in IE
3177+ unloadHandler = function() {
3178+ setDocument();
3179+ },
3180+
3181+ inDisabledFieldset = addCombinator(
3182+ function( elem ) {
3183+ return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
3184+ },
3185+ { dir: "parentNode", next: "legend" }
3186+ );
3187+
3188+// Optimize for push.apply( _, NodeList )
3189+try {
3190+ push.apply(
3191+ (arr = slice.call( preferredDoc.childNodes )),
3192+ preferredDoc.childNodes
3193+ );
3194+ // Support: Android<4.0
3195+ // Detect silently failing push.apply
3196+ arr[ preferredDoc.childNodes.length ].nodeType;
3197+} catch ( e ) {
3198+ push = { apply: arr.length ?
3199+
3200+ // Leverage slice if possible
3201+ function( target, els ) {
3202+ push_native.apply( target, slice.call(els) );
3203+ } :
3204+
3205+ // Support: IE<9
3206+ // Otherwise append directly
3207+ function( target, els ) {
3208+ var j = target.length,
3209+ i = 0;
3210+ // Can't trust NodeList.length
3211+ while ( (target[j++] = els[i++]) ) {}
3212+ target.length = j - 1;
3213+ }
3214+ };
3215+}
3216+
3217+function Sizzle( selector, context, results, seed ) {
3218+ var m, i, elem, nid, match, groups, newSelector,
3219+ newContext = context && context.ownerDocument,
3220+
3221+ // nodeType defaults to 9, since context defaults to document
3222+ nodeType = context ? context.nodeType : 9;
3223+
3224+ results = results || [];
3225+
3226+ // Return early from calls with invalid selector or context
3227+ if ( typeof selector !== "string" || !selector ||
3228+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
3229+
3230+ return results;
3231+ }
3232+
3233+ // Try to shortcut find operations (as opposed to filters) in HTML documents
3234+ if ( !seed ) {
3235+
3236+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
3237+ setDocument( context );
3238+ }
3239+ context = context || document;
3240+
3241+ if ( documentIsHTML ) {
3242+
3243+ // If the selector is sufficiently simple, try using a "get*By*" DOM method
3244+ // (excepting DocumentFragment context, where the methods don't exist)
3245+ if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
3246+
3247+ // ID selector
3248+ if ( (m = match[1]) ) {
3249+
3250+ // Document context
3251+ if ( nodeType === 9 ) {
3252+ if ( (elem = context.getElementById( m )) ) {
3253+
3254+ // Support: IE, Opera, Webkit
3255+ // TODO: identify versions
3256+ // getElementById can match elements by name instead of ID
3257+ if ( elem.id === m ) {
3258+ results.push( elem );
3259+ return results;
3260+ }
3261+ } else {
3262+ return results;
3263+ }
3264+
3265+ // Element context
3266+ } else {
3267+
3268+ // Support: IE, Opera, Webkit
3269+ // TODO: identify versions
3270+ // getElementById can match elements by name instead of ID
3271+ if ( newContext && (elem = newContext.getElementById( m )) &&
3272+ contains( context, elem ) &&
3273+ elem.id === m ) {
3274+
3275+ results.push( elem );
3276+ return results;
3277+ }
3278+ }
3279+
3280+ // Type selector
3281+ } else if ( match[2] ) {
3282+ push.apply( results, context.getElementsByTagName( selector ) );
3283+ return results;
3284+
3285+ // Class selector
3286+ } else if ( (m = match[3]) && support.getElementsByClassName &&
3287+ context.getElementsByClassName ) {
3288+
3289+ push.apply( results, context.getElementsByClassName( m ) );
3290+ return results;
3291+ }
3292+ }
3293+
3294+ // Take advantage of querySelectorAll
3295+ if ( support.qsa &&
3296+ !nonnativeSelectorCache[ selector + " " ] &&
3297+ (!rbuggyQSA || !rbuggyQSA.test( selector )) &&
3298+
3299+ // Support: IE 8 only
3300+ // Exclude object elements
3301+ (nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) {
3302+
3303+ newSelector = selector;
3304+ newContext = context;
3305+
3306+ // qSA considers elements outside a scoping root when evaluating child or
3307+ // descendant combinators, which is not what we want.
3308+ // In such cases, we work around the behavior by prefixing every selector in the
3309+ // list with an ID selector referencing the scope context.
3310+ // Thanks to Andrew Dupont for this technique.
3311+ if ( nodeType === 1 && rdescend.test( selector ) ) {
3312+
3313+ // Capture the context ID, setting it first if necessary
3314+ if ( (nid = context.getAttribute( "id" )) ) {
3315+ nid = nid.replace( rcssescape, fcssescape );
3316+ } else {
3317+ context.setAttribute( "id", (nid = expando) );
3318+ }
3319+
3320+ // Prefix every selector in the list
3321+ groups = tokenize( selector );
3322+ i = groups.length;
3323+ while ( i-- ) {
3324+ groups[i] = "#" + nid + " " + toSelector( groups[i] );
3325+ }
3326+ newSelector = groups.join( "," );
3327+
3328+ // Expand context for sibling selectors
3329+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
3330+ context;
3331+ }
3332+
3333+ try {
3334+ push.apply( results,
3335+ newContext.querySelectorAll( newSelector )
3336+ );
3337+ return results;
3338+ } catch ( qsaError ) {
3339+ nonnativeSelectorCache( selector, true );
3340+ } finally {
3341+ if ( nid === expando ) {
3342+ context.removeAttribute( "id" );
3343+ }
3344+ }
3345+ }
3346+ }
3347+ }
3348+
3349+ // All others
3350+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
3351+}
3352+
3353+/**
3354+ * Create key-value caches of limited size
3355+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
3356+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
3357+ * deleting the oldest entry
3358+ */
3359+function createCache() {
3360+ var keys = [];
3361+
3362+ function cache( key, value ) {
3363+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
3364+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
3365+ // Only keep the most recent entries
3366+ delete cache[ keys.shift() ];
3367+ }
3368+ return (cache[ key + " " ] = value);
3369+ }
3370+ return cache;
3371+}
3372+
3373+/**
3374+ * Mark a function for special use by Sizzle
3375+ * @param {Function} fn The function to mark
3376+ */
3377+function markFunction( fn ) {
3378+ fn[ expando ] = true;
3379+ return fn;
3380+}
3381+
3382+/**
3383+ * Support testing using an element
3384+ * @param {Function} fn Passed the created element and returns a boolean result
3385+ */
3386+function assert( fn ) {
3387+ var el = document.createElement("fieldset");
3388+
3389+ try {
3390+ return !!fn( el );
3391+ } catch (e) {
3392+ return false;
3393+ } finally {
3394+ // Remove from its parent by default
3395+ if ( el.parentNode ) {
3396+ el.parentNode.removeChild( el );
3397+ }
3398+ // release memory in IE
3399+ el = null;
3400+ }
3401+}
3402+
3403+/**
3404+ * Adds the same handler for all of the specified attrs
3405+ * @param {String} attrs Pipe-separated list of attributes
3406+ * @param {Function} handler The method that will be applied
3407+ */
3408+function addHandle( attrs, handler ) {
3409+ var arr = attrs.split("|"),
3410+ i = arr.length;
3411+
3412+ while ( i-- ) {
3413+ Expr.attrHandle[ arr[i] ] = handler;
3414+ }
3415+}
3416+
3417+/**
3418+ * Checks document order of two siblings
3419+ * @param {Element} a
3420+ * @param {Element} b
3421+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
3422+ */
3423+function siblingCheck( a, b ) {
3424+ var cur = b && a,
3425+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
3426+ a.sourceIndex - b.sourceIndex;
3427+
3428+ // Use IE sourceIndex if available on both nodes
3429+ if ( diff ) {
3430+ return diff;
3431+ }
3432+
3433+ // Check if b follows a
3434+ if ( cur ) {
3435+ while ( (cur = cur.nextSibling) ) {
3436+ if ( cur === b ) {
3437+ return -1;
3438+ }
3439+ }
3440+ }
3441+
3442+ return a ? 1 : -1;
3443+}
3444+
3445+/**
3446+ * Returns a function to use in pseudos for input types
3447+ * @param {String} type
3448+ */
3449+function createInputPseudo( type ) {
3450+ return function( elem ) {
3451+ var name = elem.nodeName.toLowerCase();
3452+ return name === "input" && elem.type === type;
3453+ };
3454+}
3455+
3456+/**
3457+ * Returns a function to use in pseudos for buttons
3458+ * @param {String} type
3459+ */
3460+function createButtonPseudo( type ) {
3461+ return function( elem ) {
3462+ var name = elem.nodeName.toLowerCase();
3463+ return (name === "input" || name === "button") && elem.type === type;
3464+ };
3465+}
3466+
3467+/**
3468+ * Returns a function to use in pseudos for :enabled/:disabled
3469+ * @param {Boolean} disabled true for :disabled; false for :enabled
3470+ */
3471+function createDisabledPseudo( disabled ) {
3472+
3473+ // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
3474+ return function( elem ) {
3475+
3476+ // Only certain elements can match :enabled or :disabled
3477+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
3478+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
3479+ if ( "form" in elem ) {
3480+
3481+ // Check for inherited disabledness on relevant non-disabled elements:
3482+ // * listed form-associated elements in a disabled fieldset
3483+ // https://html.spec.whatwg.org/multipage/forms.html#category-listed
3484+ // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
3485+ // * option elements in a disabled optgroup
3486+ // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
3487+ // All such elements have a "form" property.
3488+ if ( elem.parentNode && elem.disabled === false ) {
3489+
3490+ // Option elements defer to a parent optgroup if present
3491+ if ( "label" in elem ) {
3492+ if ( "label" in elem.parentNode ) {
3493+ return elem.parentNode.disabled === disabled;
3494+ } else {
3495+ return elem.disabled === disabled;
3496+ }
3497+ }
3498+
3499+ // Support: IE 6 - 11
3500+ // Use the isDisabled shortcut property to check for disabled fieldset ancestors
3501+ return elem.isDisabled === disabled ||
3502+
3503+ // Where there is no isDisabled, check manually
3504+ /* jshint -W018 */
3505+ elem.isDisabled !== !disabled &&
3506+ inDisabledFieldset( elem ) === disabled;
3507+ }
3508+
3509+ return elem.disabled === disabled;
3510+
3511+ // Try to winnow out elements that can't be disabled before trusting the disabled property.
3512+ // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
3513+ // even exist on them, let alone have a boolean value.
3514+ } else if ( "label" in elem ) {
3515+ return elem.disabled === disabled;
3516+ }
3517+
3518+ // Remaining elements are neither :enabled nor :disabled
3519+ return false;
3520+ };
3521+}
3522+
3523+/**
3524+ * Returns a function to use in pseudos for positionals
3525+ * @param {Function} fn
3526+ */
3527+function createPositionalPseudo( fn ) {
3528+ return markFunction(function( argument ) {
3529+ argument = +argument;
3530+ return markFunction(function( seed, matches ) {
3531+ var j,
3532+ matchIndexes = fn( [], seed.length, argument ),
3533+ i = matchIndexes.length;
3534+
3535+ // Match elements found at the specified indexes
3536+ while ( i-- ) {
3537+ if ( seed[ (j = matchIndexes[i]) ] ) {
3538+ seed[j] = !(matches[j] = seed[j]);
3539+ }
3540+ }
3541+ });
3542+ });
3543+}
3544+
3545+/**
3546+ * Checks a node for validity as a Sizzle context
3547+ * @param {Element|Object=} context
3548+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
3549+ */
3550+function testContext( context ) {
3551+ return context && typeof context.getElementsByTagName !== "undefined" && context;
3552+}
3553+
3554+// Expose support vars for convenience
3555+support = Sizzle.support = {};
3556+
3557+/**
3558+ * Detects XML nodes
3559+ * @param {Element|Object} elem An element or a document
3560+ * @returns {Boolean} True iff elem is a non-HTML XML node
3561+ */
3562+isXML = Sizzle.isXML = function( elem ) {
3563+ var namespace = elem.namespaceURI,
3564+ docElem = (elem.ownerDocument || elem).documentElement;
3565+
3566+ // Support: IE <=8
3567+ // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
3568+ // https://bugs.jquery.com/ticket/4833
3569+ return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
3570+};
3571+
3572+/**
3573+ * Sets document-related variables once based on the current document
3574+ * @param {Element|Object} [doc] An element or document object to use to set the document
3575+ * @returns {Object} Returns the current document
3576+ */
3577+setDocument = Sizzle.setDocument = function( node ) {
3578+ var hasCompare, subWindow,
3579+ doc = node ? node.ownerDocument || node : preferredDoc;
3580+
3581+ // Return early if doc is invalid or already selected
3582+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
3583+ return document;
3584+ }
3585+
3586+ // Update global variables
3587+ document = doc;
3588+ docElem = document.documentElement;
3589+ documentIsHTML = !isXML( document );
3590+
3591+ // Support: IE 9-11, Edge
3592+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
3593+ if ( preferredDoc !== document &&
3594+ (subWindow = document.defaultView) && subWindow.top !== subWindow ) {
3595+
3596+ // Support: IE 11, Edge
3597+ if ( subWindow.addEventListener ) {
3598+ subWindow.addEventListener( "unload", unloadHandler, false );
3599+
3600+ // Support: IE 9 - 10 only
3601+ } else if ( subWindow.attachEvent ) {
3602+ subWindow.attachEvent( "onunload", unloadHandler );
3603+ }
3604+ }
3605+
3606+ /* Attributes
3607+ ---------------------------------------------------------------------- */
3608+
3609+ // Support: IE<8
3610+ // Verify that getAttribute really returns attributes and not properties
3611+ // (excepting IE8 booleans)
3612+ support.attributes = assert(function( el ) {
3613+ el.className = "i";
3614+ return !el.getAttribute("className");
3615+ });
3616+
3617+ /* getElement(s)By*
3618+ ---------------------------------------------------------------------- */
3619+
3620+ // Check if getElementsByTagName("*") returns only elements
3621+ support.getElementsByTagName = assert(function( el ) {
3622+ el.appendChild( document.createComment("") );
3623+ return !el.getElementsByTagName("*").length;
3624+ });
3625+
3626+ // Support: IE<9
3627+ support.getElementsByClassName = rnative.test( document.getElementsByClassName );
3628+
3629+ // Support: IE<10
3630+ // Check if getElementById returns elements by name
3631+ // The broken getElementById methods don't pick up programmatically-set names,
3632+ // so use a roundabout getElementsByName test
3633+ support.getById = assert(function( el ) {
3634+ docElem.appendChild( el ).id = expando;
3635+ return !document.getElementsByName || !document.getElementsByName( expando ).length;
3636+ });
3637+
3638+ // ID filter and find
3639+ if ( support.getById ) {
3640+ Expr.filter["ID"] = function( id ) {
3641+ var attrId = id.replace( runescape, funescape );
3642+ return function( elem ) {
3643+ return elem.getAttribute("id") === attrId;
3644+ };
3645+ };
3646+ Expr.find["ID"] = function( id, context ) {
3647+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
3648+ var elem = context.getElementById( id );
3649+ return elem ? [ elem ] : [];
3650+ }
3651+ };
3652+ } else {
3653+ Expr.filter["ID"] = function( id ) {
3654+ var attrId = id.replace( runescape, funescape );
3655+ return function( elem ) {
3656+ var node = typeof elem.getAttributeNode !== "undefined" &&
3657+ elem.getAttributeNode("id");
3658+ return node && node.value === attrId;
3659+ };
3660+ };
3661+
3662+ // Support: IE 6 - 7 only
3663+ // getElementById is not reliable as a find shortcut
3664+ Expr.find["ID"] = function( id, context ) {
3665+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
3666+ var node, i, elems,
3667+ elem = context.getElementById( id );
3668+
3669+ if ( elem ) {
3670+
3671+ // Verify the id attribute
3672+ node = elem.getAttributeNode("id");
3673+ if ( node && node.value === id ) {
3674+ return [ elem ];
3675+ }
3676+
3677+ // Fall back on getElementsByName
3678+ elems = context.getElementsByName( id );
3679+ i = 0;
3680+ while ( (elem = elems[i++]) ) {
3681+ node = elem.getAttributeNode("id");
3682+ if ( node && node.value === id ) {
3683+ return [ elem ];
3684+ }
3685+ }
3686+ }
3687+
3688+ return [];
3689+ }
3690+ };
3691+ }
3692+
3693+ // Tag
3694+ Expr.find["TAG"] = support.getElementsByTagName ?
3695+ function( tag, context ) {
3696+ if ( typeof context.getElementsByTagName !== "undefined" ) {
3697+ return context.getElementsByTagName( tag );
3698+
3699+ // DocumentFragment nodes don't have gEBTN
3700+ } else if ( support.qsa ) {
3701+ return context.querySelectorAll( tag );
3702+ }
3703+ } :
3704+
3705+ function( tag, context ) {
3706+ var elem,
3707+ tmp = [],
3708+ i = 0,
3709+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
3710+ results = context.getElementsByTagName( tag );
3711+
3712+ // Filter out possible comments
3713+ if ( tag === "*" ) {
3714+ while ( (elem = results[i++]) ) {
3715+ if ( elem.nodeType === 1 ) {
3716+ tmp.push( elem );
3717+ }
3718+ }
3719+
3720+ return tmp;
3721+ }
3722+ return results;
3723+ };
3724+
3725+ // Class
3726+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
3727+ if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
3728+ return context.getElementsByClassName( className );
3729+ }
3730+ };
3731+
3732+ /* QSA/matchesSelector
3733+ ---------------------------------------------------------------------- */
3734+
3735+ // QSA and matchesSelector support
3736+
3737+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
3738+ rbuggyMatches = [];
3739+
3740+ // qSa(:focus) reports false when true (Chrome 21)
3741+ // We allow this because of a bug in IE8/9 that throws an error
3742+ // whenever `document.activeElement` is accessed on an iframe
3743+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
3744+ // See https://bugs.jquery.com/ticket/13378
3745+ rbuggyQSA = [];
3746+
3747+ if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
3748+ // Build QSA regex
3749+ // Regex strategy adopted from Diego Perini
3750+ assert(function( el ) {
3751+ // Select is set to empty string on purpose
3752+ // This is to test IE's treatment of not explicitly
3753+ // setting a boolean content attribute,
3754+ // since its presence should be enough
3755+ // https://bugs.jquery.com/ticket/12359
3756+ docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
3757+ "<select id='" + expando + "-\r\\' msallowcapture=''>" +
3758+ "<option selected=''></option></select>";
3759+
3760+ // Support: IE8, Opera 11-12.16
3761+ // Nothing should be selected when empty strings follow ^= or $= or *=
3762+ // The test attribute must be unknown in Opera but "safe" for WinRT
3763+ // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
3764+ if ( el.querySelectorAll("[msallowcapture^='']").length ) {
3765+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
3766+ }
3767+
3768+ // Support: IE8
3769+ // Boolean attributes and "value" are not treated correctly
3770+ if ( !el.querySelectorAll("[selected]").length ) {
3771+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
3772+ }
3773+
3774+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
3775+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
3776+ rbuggyQSA.push("~=");
3777+ }
3778+
3779+ // Webkit/Opera - :checked should return selected option elements
3780+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
3781+ // IE8 throws error here and will not see later tests
3782+ if ( !el.querySelectorAll(":checked").length ) {
3783+ rbuggyQSA.push(":checked");
3784+ }
3785+
3786+ // Support: Safari 8+, iOS 8+
3787+ // https://bugs.webkit.org/show_bug.cgi?id=136851
3788+ // In-page `selector#id sibling-combinator selector` fails
3789+ if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
3790+ rbuggyQSA.push(".#.+[+~]");
3791+ }
3792+ });
3793+
3794+ assert(function( el ) {
3795+ el.innerHTML = "<a href='' disabled='disabled'></a>" +
3796+ "<select disabled='disabled'><option/></select>";
3797+
3798+ // Support: Windows 8 Native Apps
3799+ // The type and name attributes are restricted during .innerHTML assignment
3800+ var input = document.createElement("input");
3801+ input.setAttribute( "type", "hidden" );
3802+ el.appendChild( input ).setAttribute( "name", "D" );
3803+
3804+ // Support: IE8
3805+ // Enforce case-sensitivity of name attribute
3806+ if ( el.querySelectorAll("[name=d]").length ) {
3807+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
3808+ }
3809+
3810+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
3811+ // IE8 throws error here and will not see later tests
3812+ if ( el.querySelectorAll(":enabled").length !== 2 ) {
3813+ rbuggyQSA.push( ":enabled", ":disabled" );
3814+ }
3815+
3816+ // Support: IE9-11+
3817+ // IE's :disabled selector does not pick up the children of disabled fieldsets
3818+ docElem.appendChild( el ).disabled = true;
3819+ if ( el.querySelectorAll(":disabled").length !== 2 ) {
3820+ rbuggyQSA.push( ":enabled", ":disabled" );
3821+ }
3822+
3823+ // Opera 10-11 does not throw on post-comma invalid pseudos
3824+ el.querySelectorAll("*,:x");
3825+ rbuggyQSA.push(",.*:");
3826+ });
3827+ }
3828+
3829+ if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
3830+ docElem.webkitMatchesSelector ||
3831+ docElem.mozMatchesSelector ||
3832+ docElem.oMatchesSelector ||
3833+ docElem.msMatchesSelector) )) ) {
3834+
3835+ assert(function( el ) {
3836+ // Check to see if it's possible to do matchesSelector
3837+ // on a disconnected node (IE 9)
3838+ support.disconnectedMatch = matches.call( el, "*" );
3839+
3840+ // This should fail with an exception
3841+ // Gecko does not error, returns false instead
3842+ matches.call( el, "[s!='']:x" );
3843+ rbuggyMatches.push( "!=", pseudos );
3844+ });
3845+ }
3846+
3847+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
3848+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
3849+
3850+ /* Contains
3851+ ---------------------------------------------------------------------- */
3852+ hasCompare = rnative.test( docElem.compareDocumentPosition );
3853+
3854+ // Element contains another
3855+ // Purposefully self-exclusive
3856+ // As in, an element does not contain itself
3857+ contains = hasCompare || rnative.test( docElem.contains ) ?
3858+ function( a, b ) {
3859+ var adown = a.nodeType === 9 ? a.documentElement : a,
3860+ bup = b && b.parentNode;
3861+ return a === bup || !!( bup && bup.nodeType === 1 && (
3862+ adown.contains ?
3863+ adown.contains( bup ) :
3864+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
3865+ ));
3866+ } :
3867+ function( a, b ) {
3868+ if ( b ) {
3869+ while ( (b = b.parentNode) ) {
3870+ if ( b === a ) {
3871+ return true;
3872+ }
3873+ }
3874+ }
3875+ return false;
3876+ };
3877+
3878+ /* Sorting
3879+ ---------------------------------------------------------------------- */
3880+
3881+ // Document order sorting
3882+ sortOrder = hasCompare ?
3883+ function( a, b ) {
3884+
3885+ // Flag for duplicate removal
3886+ if ( a === b ) {
3887+ hasDuplicate = true;
3888+ return 0;
3889+ }
3890+
3891+ // Sort on method existence if only one input has compareDocumentPosition
3892+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
3893+ if ( compare ) {
3894+ return compare;
3895+ }
3896+
3897+ // Calculate position if both inputs belong to the same document
3898+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
3899+ a.compareDocumentPosition( b ) :
3900+
3901+ // Otherwise we know they are disconnected
3902+ 1;
3903+
3904+ // Disconnected nodes
3905+ if ( compare & 1 ||
3906+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
3907+
3908+ // Choose the first element that is related to our preferred document
3909+ if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
3910+ return -1;
3911+ }
3912+ if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
3913+ return 1;
3914+ }
3915+
3916+ // Maintain original order
3917+ return sortInput ?
3918+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
3919+ 0;
3920+ }
3921+
3922+ return compare & 4 ? -1 : 1;
3923+ } :
3924+ function( a, b ) {
3925+ // Exit early if the nodes are identical
3926+ if ( a === b ) {
3927+ hasDuplicate = true;
3928+ return 0;
3929+ }
3930+
3931+ var cur,
3932+ i = 0,
3933+ aup = a.parentNode,
3934+ bup = b.parentNode,
3935+ ap = [ a ],
3936+ bp = [ b ];
3937+
3938+ // Parentless nodes are either documents or disconnected
3939+ if ( !aup || !bup ) {
3940+ return a === document ? -1 :
3941+ b === document ? 1 :
3942+ aup ? -1 :
3943+ bup ? 1 :
3944+ sortInput ?
3945+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
3946+ 0;
3947+
3948+ // If the nodes are siblings, we can do a quick check
3949+ } else if ( aup === bup ) {
3950+ return siblingCheck( a, b );
3951+ }
3952+
3953+ // Otherwise we need full lists of their ancestors for comparison
3954+ cur = a;
3955+ while ( (cur = cur.parentNode) ) {
3956+ ap.unshift( cur );
3957+ }
3958+ cur = b;
3959+ while ( (cur = cur.parentNode) ) {
3960+ bp.unshift( cur );
3961+ }
3962+
3963+ // Walk down the tree looking for a discrepancy
3964+ while ( ap[i] === bp[i] ) {
3965+ i++;
3966+ }
3967+
3968+ return i ?
3969+ // Do a sibling check if the nodes have a common ancestor
3970+ siblingCheck( ap[i], bp[i] ) :
3971+
3972+ // Otherwise nodes in our document sort first
3973+ ap[i] === preferredDoc ? -1 :
3974+ bp[i] === preferredDoc ? 1 :
3975+ 0;
3976+ };
3977+
3978+ return document;
3979+};
3980+
3981+Sizzle.matches = function( expr, elements ) {
3982+ return Sizzle( expr, null, null, elements );
3983+};
3984+
3985+Sizzle.matchesSelector = function( elem, expr ) {
3986+ // Set document vars if needed
3987+ if ( ( elem.ownerDocument || elem ) !== document ) {
3988+ setDocument( elem );
3989+ }
3990+
3991+ if ( support.matchesSelector && documentIsHTML &&
3992+ !nonnativeSelectorCache[ expr + " " ] &&
3993+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
3994+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
3995+
3996+ try {
3997+ var ret = matches.call( elem, expr );
3998+
3999+ // IE 9's matchesSelector returns false on disconnected nodes
4000+ if ( ret || support.disconnectedMatch ||
4001+ // As well, disconnected nodes are said to be in a document
4002+ // fragment in IE 9
4003+ elem.document && elem.document.nodeType !== 11 ) {
4004+ return ret;
4005+ }
4006+ } catch (e) {
4007+ nonnativeSelectorCache( expr, true );
4008+ }
4009+ }
4010+
4011+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
4012+};
4013+
4014+Sizzle.contains = function( context, elem ) {
4015+ // Set document vars if needed
4016+ if ( ( context.ownerDocument || context ) !== document ) {
4017+ setDocument( context );
4018+ }
4019+ return contains( context, elem );
4020+};
4021+
4022+Sizzle.attr = function( elem, name ) {
4023+ // Set document vars if needed
4024+ if ( ( elem.ownerDocument || elem ) !== document ) {
4025+ setDocument( elem );
4026+ }
4027+
4028+ var fn = Expr.attrHandle[ name.toLowerCase() ],
4029+ // Don't get fooled by Object.prototype properties (jQuery #13807)
4030+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
4031+ fn( elem, name, !documentIsHTML ) :
4032+ undefined;
4033+
4034+ return val !== undefined ?
4035+ val :
4036+ support.attributes || !documentIsHTML ?
4037+ elem.getAttribute( name ) :
4038+ (val = elem.getAttributeNode(name)) && val.specified ?
4039+ val.value :
4040+ null;
4041+};
4042+
4043+Sizzle.escape = function( sel ) {
4044+ return (sel + "").replace( rcssescape, fcssescape );
4045+};
4046+
4047+Sizzle.error = function( msg ) {
4048+ throw new Error( "Syntax error, unrecognized expression: " + msg );
4049+};
4050+
4051+/**
4052+ * Document sorting and removing duplicates
4053+ * @param {ArrayLike} results
4054+ */
4055+Sizzle.uniqueSort = function( results ) {
4056+ var elem,
4057+ duplicates = [],
4058+ j = 0,
4059+ i = 0;
4060+
4061+ // Unless we *know* we can detect duplicates, assume their presence
4062+ hasDuplicate = !support.detectDuplicates;
4063+ sortInput = !support.sortStable && results.slice( 0 );
4064+ results.sort( sortOrder );
4065+
4066+ if ( hasDuplicate ) {
4067+ while ( (elem = results[i++]) ) {
4068+ if ( elem === results[ i ] ) {
4069+ j = duplicates.push( i );
4070+ }
4071+ }
4072+ while ( j-- ) {
4073+ results.splice( duplicates[ j ], 1 );
4074+ }
4075+ }
4076+
4077+ // Clear input after sorting to release objects
4078+ // See https://github.com/jquery/sizzle/pull/225
4079+ sortInput = null;
4080+
4081+ return results;
4082+};
4083+
4084+/**
4085+ * Utility function for retrieving the text value of an array of DOM nodes
4086+ * @param {Array|Element} elem
4087+ */
4088+getText = Sizzle.getText = function( elem ) {
4089+ var node,
4090+ ret = "",
4091+ i = 0,
4092+ nodeType = elem.nodeType;
4093+
4094+ if ( !nodeType ) {
4095+ // If no nodeType, this is expected to be an array
4096+ while ( (node = elem[i++]) ) {
4097+ // Do not traverse comment nodes
4098+ ret += getText( node );
4099+ }
4100+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
4101+ // Use textContent for elements
4102+ // innerText usage removed for consistency of new lines (jQuery #11153)
4103+ if ( typeof elem.textContent === "string" ) {
4104+ return elem.textContent;
4105+ } else {
4106+ // Traverse its children
4107+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
4108+ ret += getText( elem );
4109+ }
4110+ }
4111+ } else if ( nodeType === 3 || nodeType === 4 ) {
4112+ return elem.nodeValue;
4113+ }
4114+ // Do not include comment or processing instruction nodes
4115+
4116+ return ret;
4117+};
4118+
4119+Expr = Sizzle.selectors = {
4120+
4121+ // Can be adjusted by the user
4122+ cacheLength: 50,
4123+
4124+ createPseudo: markFunction,
4125+
4126+ match: matchExpr,
4127+
4128+ attrHandle: {},
4129+
4130+ find: {},
4131+
4132+ relative: {
4133+ ">": { dir: "parentNode", first: true },
4134+ " ": { dir: "parentNode" },
4135+ "+": { dir: "previousSibling", first: true },
4136+ "~": { dir: "previousSibling" }
4137+ },
4138+
4139+ preFilter: {
4140+ "ATTR": function( match ) {
4141+ match[1] = match[1].replace( runescape, funescape );
4142+
4143+ // Move the given value to match[3] whether quoted or unquoted
4144+ match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
4145+
4146+ if ( match[2] === "~=" ) {
4147+ match[3] = " " + match[3] + " ";
4148+ }
4149+
4150+ return match.slice( 0, 4 );
4151+ },
4152+
4153+ "CHILD": function( match ) {
4154+ /* matches from matchExpr["CHILD"]
4155+ 1 type (only|nth|...)
4156+ 2 what (child|of-type)
4157+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
4158+ 4 xn-component of xn+y argument ([+-]?\d*n|)
4159+ 5 sign of xn-component
4160+ 6 x of xn-component
4161+ 7 sign of y-component
4162+ 8 y of y-component
4163+ */
4164+ match[1] = match[1].toLowerCase();
4165+
4166+ if ( match[1].slice( 0, 3 ) === "nth" ) {
4167+ // nth-* requires argument
4168+ if ( !match[3] ) {
4169+ Sizzle.error( match[0] );
4170+ }
4171+
4172+ // numeric x and y parameters for Expr.filter.CHILD
4173+ // remember that false/true cast respectively to 0/1
4174+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
4175+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
4176+
4177+ // other types prohibit arguments
4178+ } else if ( match[3] ) {
4179+ Sizzle.error( match[0] );
4180+ }
4181+
4182+ return match;
4183+ },
4184+
4185+ "PSEUDO": function( match ) {
4186+ var excess,
4187+ unquoted = !match[6] && match[2];
4188+
4189+ if ( matchExpr["CHILD"].test( match[0] ) ) {
4190+ return null;
4191+ }
4192+
4193+ // Accept quoted arguments as-is
4194+ if ( match[3] ) {
4195+ match[2] = match[4] || match[5] || "";
4196+
4197+ // Strip excess characters from unquoted arguments
4198+ } else if ( unquoted && rpseudo.test( unquoted ) &&
4199+ // Get excess from tokenize (recursively)
4200+ (excess = tokenize( unquoted, true )) &&
4201+ // advance to the next closing parenthesis
4202+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
4203+
4204+ // excess is a negative index
4205+ match[0] = match[0].slice( 0, excess );
4206+ match[2] = unquoted.slice( 0, excess );
4207+ }
4208+
4209+ // Return only captures needed by the pseudo filter method (type and argument)
4210+ return match.slice( 0, 3 );
4211+ }
4212+ },
4213+
4214+ filter: {
4215+
4216+ "TAG": function( nodeNameSelector ) {
4217+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
4218+ return nodeNameSelector === "*" ?
4219+ function() { return true; } :
4220+ function( elem ) {
4221+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
4222+ };
4223+ },
4224+
4225+ "CLASS": function( className ) {
4226+ var pattern = classCache[ className + " " ];
4227+
4228+ return pattern ||
4229+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
4230+ classCache( className, function( elem ) {
4231+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
4232+ });
4233+ },
4234+
4235+ "ATTR": function( name, operator, check ) {
4236+ return function( elem ) {
4237+ var result = Sizzle.attr( elem, name );
4238+
4239+ if ( result == null ) {
4240+ return operator === "!=";
4241+ }
4242+ if ( !operator ) {
4243+ return true;
4244+ }
4245+
4246+ result += "";
4247+
4248+ return operator === "=" ? result === check :
4249+ operator === "!=" ? result !== check :
4250+ operator === "^=" ? check && result.indexOf( check ) === 0 :
4251+ operator === "*=" ? check && result.indexOf( check ) > -1 :
4252+ operator === "$=" ? check && result.slice( -check.length ) === check :
4253+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
4254+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
4255+ false;
4256+ };
4257+ },
4258+
4259+ "CHILD": function( type, what, argument, first, last ) {
4260+ var simple = type.slice( 0, 3 ) !== "nth",
4261+ forward = type.slice( -4 ) !== "last",
4262+ ofType = what === "of-type";
4263+
4264+ return first === 1 && last === 0 ?
4265+
4266+ // Shortcut for :nth-*(n)
4267+ function( elem ) {
4268+ return !!elem.parentNode;
4269+ } :
4270+
4271+ function( elem, context, xml ) {
4272+ var cache, uniqueCache, outerCache, node, nodeIndex, start,
4273+ dir = simple !== forward ? "nextSibling" : "previousSibling",
4274+ parent = elem.parentNode,
4275+ name = ofType && elem.nodeName.toLowerCase(),
4276+ useCache = !xml && !ofType,
4277+ diff = false;
4278+
4279+ if ( parent ) {
4280+
4281+ // :(first|last|only)-(child|of-type)
4282+ if ( simple ) {
4283+ while ( dir ) {
4284+ node = elem;
4285+ while ( (node = node[ dir ]) ) {
4286+ if ( ofType ?
4287+ node.nodeName.toLowerCase() === name :
4288+ node.nodeType === 1 ) {
4289+
4290+ return false;
4291+ }
4292+ }
4293+ // Reverse direction for :only-* (if we haven't yet done so)
4294+ start = dir = type === "only" && !start && "nextSibling";
4295+ }
4296+ return true;
4297+ }
4298+
4299+ start = [ forward ? parent.firstChild : parent.lastChild ];
4300+
4301+ // non-xml :nth-child(...) stores cache data on `parent`
4302+ if ( forward && useCache ) {
4303+
4304+ // Seek `elem` from a previously-cached index
4305+
4306+ // ...in a gzip-friendly way
4307+ node = parent;
4308+ outerCache = node[ expando ] || (node[ expando ] = {});
4309+
4310+ // Support: IE <9 only
4311+ // Defend against cloned attroperties (jQuery gh-1709)
4312+ uniqueCache = outerCache[ node.uniqueID ] ||
4313+ (outerCache[ node.uniqueID ] = {});
4314+
4315+ cache = uniqueCache[ type ] || [];
4316+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
4317+ diff = nodeIndex && cache[ 2 ];
4318+ node = nodeIndex && parent.childNodes[ nodeIndex ];
4319+
4320+ while ( (node = ++nodeIndex && node && node[ dir ] ||
4321+
4322+ // Fallback to seeking `elem` from the start
4323+ (diff = nodeIndex = 0) || start.pop()) ) {
4324+
4325+ // When found, cache indexes on `parent` and break
4326+ if ( node.nodeType === 1 && ++diff && node === elem ) {
4327+ uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
4328+ break;
4329+ }
4330+ }
4331+
4332+ } else {
4333+ // Use previously-cached element index if available
4334+ if ( useCache ) {
4335+ // ...in a gzip-friendly way
4336+ node = elem;
4337+ outerCache = node[ expando ] || (node[ expando ] = {});
4338+
4339+ // Support: IE <9 only
4340+ // Defend against cloned attroperties (jQuery gh-1709)
4341+ uniqueCache = outerCache[ node.uniqueID ] ||
4342+ (outerCache[ node.uniqueID ] = {});
4343+
4344+ cache = uniqueCache[ type ] || [];
4345+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
4346+ diff = nodeIndex;
4347+ }
4348+
4349+ // xml :nth-child(...)
4350+ // or :nth-last-child(...) or :nth(-last)?-of-type(...)
4351+ if ( diff === false ) {
4352+ // Use the same loop as above to seek `elem` from the start
4353+ while ( (node = ++nodeIndex && node && node[ dir ] ||
4354+ (diff = nodeIndex = 0) || start.pop()) ) {
4355+
4356+ if ( ( ofType ?
4357+ node.nodeName.toLowerCase() === name :
4358+ node.nodeType === 1 ) &&
4359+ ++diff ) {
4360+
4361+ // Cache the index of each encountered element
4362+ if ( useCache ) {
4363+ outerCache = node[ expando ] || (node[ expando ] = {});
4364+
4365+ // Support: IE <9 only
4366+ // Defend against cloned attroperties (jQuery gh-1709)
4367+ uniqueCache = outerCache[ node.uniqueID ] ||
4368+ (outerCache[ node.uniqueID ] = {});
4369+
4370+ uniqueCache[ type ] = [ dirruns, diff ];
4371+ }
4372+
4373+ if ( node === elem ) {
4374+ break;
4375+ }
4376+ }
4377+ }
4378+ }
4379+ }
4380+
4381+ // Incorporate the offset, then check against cycle size
4382+ diff -= last;
4383+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
4384+ }
4385+ };
4386+ },
4387+
4388+ "PSEUDO": function( pseudo, argument ) {
4389+ // pseudo-class names are case-insensitive
4390+ // http://www.w3.org/TR/selectors/#pseudo-classes
4391+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
4392+ // Remember that setFilters inherits from pseudos
4393+ var args,
4394+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
4395+ Sizzle.error( "unsupported pseudo: " + pseudo );
4396+
4397+ // The user may use createPseudo to indicate that
4398+ // arguments are needed to create the filter function
4399+ // just as Sizzle does
4400+ if ( fn[ expando ] ) {
4401+ return fn( argument );
4402+ }
4403+
4404+ // But maintain support for old signatures
4405+ if ( fn.length > 1 ) {
4406+ args = [ pseudo, pseudo, "", argument ];
4407+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
4408+ markFunction(function( seed, matches ) {
4409+ var idx,
4410+ matched = fn( seed, argument ),
4411+ i = matched.length;
4412+ while ( i-- ) {
4413+ idx = indexOf( seed, matched[i] );
4414+ seed[ idx ] = !( matches[ idx ] = matched[i] );
4415+ }
4416+ }) :
4417+ function( elem ) {
4418+ return fn( elem, 0, args );
4419+ };
4420+ }
4421+
4422+ return fn;
4423+ }
4424+ },
4425+
4426+ pseudos: {
4427+ // Potentially complex pseudos
4428+ "not": markFunction(function( selector ) {
4429+ // Trim the selector passed to compile
4430+ // to avoid treating leading and trailing
4431+ // spaces as combinators
4432+ var input = [],
4433+ results = [],
4434+ matcher = compile( selector.replace( rtrim, "$1" ) );
4435+
4436+ return matcher[ expando ] ?
4437+ markFunction(function( seed, matches, context, xml ) {
4438+ var elem,
4439+ unmatched = matcher( seed, null, xml, [] ),
4440+ i = seed.length;
4441+
4442+ // Match elements unmatched by `matcher`
4443+ while ( i-- ) {
4444+ if ( (elem = unmatched[i]) ) {
4445+ seed[i] = !(matches[i] = elem);
4446+ }
4447+ }
4448+ }) :
4449+ function( elem, context, xml ) {
4450+ input[0] = elem;
4451+ matcher( input, null, xml, results );
4452+ // Don't keep the element (issue #299)
4453+ input[0] = null;
4454+ return !results.pop();
4455+ };
4456+ }),
4457+
4458+ "has": markFunction(function( selector ) {
4459+ return function( elem ) {
4460+ return Sizzle( selector, elem ).length > 0;
4461+ };
4462+ }),
4463+
4464+ "contains": markFunction(function( text ) {
4465+ text = text.replace( runescape, funescape );
4466+ return function( elem ) {
4467+ return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
4468+ };
4469+ }),
4470+
4471+ // "Whether an element is represented by a :lang() selector
4472+ // is based solely on the element's language value
4473+ // being equal to the identifier C,
4474+ // or beginning with the identifier C immediately followed by "-".
4475+ // The matching of C against the element's language value is performed case-insensitively.
4476+ // The identifier C does not have to be a valid language name."
4477+ // http://www.w3.org/TR/selectors/#lang-pseudo
4478+ "lang": markFunction( function( lang ) {
4479+ // lang value must be a valid identifier
4480+ if ( !ridentifier.test(lang || "") ) {
4481+ Sizzle.error( "unsupported lang: " + lang );
4482+ }
4483+ lang = lang.replace( runescape, funescape ).toLowerCase();
4484+ return function( elem ) {
4485+ var elemLang;
4486+ do {
4487+ if ( (elemLang = documentIsHTML ?
4488+ elem.lang :
4489+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
4490+
4491+ elemLang = elemLang.toLowerCase();
4492+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
4493+ }
4494+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
4495+ return false;
4496+ };
4497+ }),
4498+
4499+ // Miscellaneous
4500+ "target": function( elem ) {
4501+ var hash = window.location && window.location.hash;
4502+ return hash && hash.slice( 1 ) === elem.id;
4503+ },
4504+
4505+ "root": function( elem ) {
4506+ return elem === docElem;
4507+ },
4508+
4509+ "focus": function( elem ) {
4510+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
4511+ },
4512+
4513+ // Boolean properties
4514+ "enabled": createDisabledPseudo( false ),
4515+ "disabled": createDisabledPseudo( true ),
4516+
4517+ "checked": function( elem ) {
4518+ // In CSS3, :checked should return both checked and selected elements
4519+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
4520+ var nodeName = elem.nodeName.toLowerCase();
4521+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
4522+ },
4523+
4524+ "selected": function( elem ) {
4525+ // Accessing this property makes selected-by-default
4526+ // options in Safari work properly
4527+ if ( elem.parentNode ) {
4528+ elem.parentNode.selectedIndex;
4529+ }
4530+
4531+ return elem.selected === true;
4532+ },
4533+
4534+ // Contents
4535+ "empty": function( elem ) {
4536+ // http://www.w3.org/TR/selectors/#empty-pseudo
4537+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
4538+ // but not by others (comment: 8; processing instruction: 7; etc.)
4539+ // nodeType < 6 works because attributes (2) do not appear as children
4540+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
4541+ if ( elem.nodeType < 6 ) {
4542+ return false;
4543+ }
4544+ }
4545+ return true;
4546+ },
4547+
4548+ "parent": function( elem ) {
4549+ return !Expr.pseudos["empty"]( elem );
4550+ },
4551+
4552+ // Element/input types
4553+ "header": function( elem ) {
4554+ return rheader.test( elem.nodeName );
4555+ },
4556+
4557+ "input": function( elem ) {
4558+ return rinputs.test( elem.nodeName );
4559+ },
4560+
4561+ "button": function( elem ) {
4562+ var name = elem.nodeName.toLowerCase();
4563+ return name === "input" && elem.type === "button" || name === "button";
4564+ },
4565+
4566+ "text": function( elem ) {
4567+ var attr;
4568+ return elem.nodeName.toLowerCase() === "input" &&
4569+ elem.type === "text" &&
4570+
4571+ // Support: IE<8
4572+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
4573+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
4574+ },
4575+
4576+ // Position-in-collection
4577+ "first": createPositionalPseudo(function() {
4578+ return [ 0 ];
4579+ }),
4580+
4581+ "last": createPositionalPseudo(function( matchIndexes, length ) {
4582+ return [ length - 1 ];
4583+ }),
4584+
4585+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
4586+ return [ argument < 0 ? argument + length : argument ];
4587+ }),
4588+
4589+ "even": createPositionalPseudo(function( matchIndexes, length ) {
4590+ var i = 0;
4591+ for ( ; i < length; i += 2 ) {
4592+ matchIndexes.push( i );
4593+ }
4594+ return matchIndexes;
4595+ }),
4596+
4597+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
4598+ var i = 1;
4599+ for ( ; i < length; i += 2 ) {
4600+ matchIndexes.push( i );
4601+ }
4602+ return matchIndexes;
4603+ }),
4604+
4605+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
4606+ var i = argument < 0 ?
4607+ argument + length :
4608+ argument > length ?
4609+ length :
4610+ argument;
4611+ for ( ; --i >= 0; ) {
4612+ matchIndexes.push( i );
4613+ }
4614+ return matchIndexes;
4615+ }),
4616+
4617+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
4618+ var i = argument < 0 ? argument + length : argument;
4619+ for ( ; ++i < length; ) {
4620+ matchIndexes.push( i );
4621+ }
4622+ return matchIndexes;
4623+ })
4624+ }
4625+};
4626+
4627+Expr.pseudos["nth"] = Expr.pseudos["eq"];
4628+
4629+// Add button/input type pseudos
4630+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
4631+ Expr.pseudos[ i ] = createInputPseudo( i );
4632+}
4633+for ( i in { submit: true, reset: true } ) {
4634+ Expr.pseudos[ i ] = createButtonPseudo( i );
4635+}
4636+
4637+// Easy API for creating new setFilters
4638+function setFilters() {}
4639+setFilters.prototype = Expr.filters = Expr.pseudos;
4640+Expr.setFilters = new setFilters();
4641+
4642+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
4643+ var matched, match, tokens, type,
4644+ soFar, groups, preFilters,
4645+ cached = tokenCache[ selector + " " ];
4646+
4647+ if ( cached ) {
4648+ return parseOnly ? 0 : cached.slice( 0 );
4649+ }
4650+
4651+ soFar = selector;
4652+ groups = [];
4653+ preFilters = Expr.preFilter;
4654+
4655+ while ( soFar ) {
4656+
4657+ // Comma and first run
4658+ if ( !matched || (match = rcomma.exec( soFar )) ) {
4659+ if ( match ) {
4660+ // Don't consume trailing commas as valid
4661+ soFar = soFar.slice( match[0].length ) || soFar;
4662+ }
4663+ groups.push( (tokens = []) );
4664+ }
4665+
4666+ matched = false;
4667+
4668+ // Combinators
4669+ if ( (match = rcombinators.exec( soFar )) ) {
4670+ matched = match.shift();
4671+ tokens.push({
4672+ value: matched,
4673+ // Cast descendant combinators to space
4674+ type: match[0].replace( rtrim, " " )
4675+ });
4676+ soFar = soFar.slice( matched.length );
4677+ }
4678+
4679+ // Filters
4680+ for ( type in Expr.filter ) {
4681+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
4682+ (match = preFilters[ type ]( match ))) ) {
4683+ matched = match.shift();
4684+ tokens.push({
4685+ value: matched,
4686+ type: type,
4687+ matches: match
4688+ });
4689+ soFar = soFar.slice( matched.length );
4690+ }
4691+ }
4692+
4693+ if ( !matched ) {
4694+ break;
4695+ }
4696+ }
4697+
4698+ // Return the length of the invalid excess
4699+ // if we're just parsing
4700+ // Otherwise, throw an error or return tokens
4701+ return parseOnly ?
4702+ soFar.length :
4703+ soFar ?
4704+ Sizzle.error( selector ) :
4705+ // Cache the tokens
4706+ tokenCache( selector, groups ).slice( 0 );
4707+};
4708+
4709+function toSelector( tokens ) {
4710+ var i = 0,
4711+ len = tokens.length,
4712+ selector = "";
4713+ for ( ; i < len; i++ ) {
4714+ selector += tokens[i].value;
4715+ }
4716+ return selector;
4717+}
4718+
4719+function addCombinator( matcher, combinator, base ) {
4720+ var dir = combinator.dir,
4721+ skip = combinator.next,
4722+ key = skip || dir,
4723+ checkNonElements = base && key === "parentNode",
4724+ doneName = done++;
4725+
4726+ return combinator.first ?
4727+ // Check against closest ancestor/preceding element
4728+ function( elem, context, xml ) {
4729+ while ( (elem = elem[ dir ]) ) {
4730+ if ( elem.nodeType === 1 || checkNonElements ) {
4731+ return matcher( elem, context, xml );
4732+ }
4733+ }
4734+ return false;
4735+ } :
4736+
4737+ // Check against all ancestor/preceding elements
4738+ function( elem, context, xml ) {
4739+ var oldCache, uniqueCache, outerCache,
4740+ newCache = [ dirruns, doneName ];
4741+
4742+ // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
4743+ if ( xml ) {
4744+ while ( (elem = elem[ dir ]) ) {
4745+ if ( elem.nodeType === 1 || checkNonElements ) {
4746+ if ( matcher( elem, context, xml ) ) {
4747+ return true;
4748+ }
4749+ }
4750+ }
4751+ } else {
4752+ while ( (elem = elem[ dir ]) ) {
4753+ if ( elem.nodeType === 1 || checkNonElements ) {
4754+ outerCache = elem[ expando ] || (elem[ expando ] = {});
4755+
4756+ // Support: IE <9 only
4757+ // Defend against cloned attroperties (jQuery gh-1709)
4758+ uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
4759+
4760+ if ( skip && skip === elem.nodeName.toLowerCase() ) {
4761+ elem = elem[ dir ] || elem;
4762+ } else if ( (oldCache = uniqueCache[ key ]) &&
4763+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
4764+
4765+ // Assign to newCache so results back-propagate to previous elements
4766+ return (newCache[ 2 ] = oldCache[ 2 ]);
4767+ } else {
4768+ // Reuse newcache so results back-propagate to previous elements
4769+ uniqueCache[ key ] = newCache;
4770+
4771+ // A match means we're done; a fail means we have to keep checking
4772+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
4773+ return true;
4774+ }
4775+ }
4776+ }
4777+ }
4778+ }
4779+ return false;
4780+ };
4781+}
4782+
4783+function elementMatcher( matchers ) {
4784+ return matchers.length > 1 ?
4785+ function( elem, context, xml ) {
4786+ var i = matchers.length;
4787+ while ( i-- ) {
4788+ if ( !matchers[i]( elem, context, xml ) ) {
4789+ return false;
4790+ }
4791+ }
4792+ return true;
4793+ } :
4794+ matchers[0];
4795+}
4796+
4797+function multipleContexts( selector, contexts, results ) {
4798+ var i = 0,
4799+ len = contexts.length;
4800+ for ( ; i < len; i++ ) {
4801+ Sizzle( selector, contexts[i], results );
4802+ }
4803+ return results;
4804+}
4805+
4806+function condense( unmatched, map, filter, context, xml ) {
4807+ var elem,
4808+ newUnmatched = [],
4809+ i = 0,
4810+ len = unmatched.length,
4811+ mapped = map != null;
4812+
4813+ for ( ; i < len; i++ ) {
4814+ if ( (elem = unmatched[i]) ) {
4815+ if ( !filter || filter( elem, context, xml ) ) {
4816+ newUnmatched.push( elem );
4817+ if ( mapped ) {
4818+ map.push( i );
4819+ }
4820+ }
4821+ }
4822+ }
4823+
4824+ return newUnmatched;
4825+}
4826+
4827+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
4828+ if ( postFilter && !postFilter[ expando ] ) {
4829+ postFilter = setMatcher( postFilter );
4830+ }
4831+ if ( postFinder && !postFinder[ expando ] ) {
4832+ postFinder = setMatcher( postFinder, postSelector );
4833+ }
4834+ return markFunction(function( seed, results, context, xml ) {
4835+ var temp, i, elem,
4836+ preMap = [],
4837+ postMap = [],
4838+ preexisting = results.length,
4839+
4840+ // Get initial elements from seed or context
4841+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
4842+
4843+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
4844+ matcherIn = preFilter && ( seed || !selector ) ?
4845+ condense( elems, preMap, preFilter, context, xml ) :
4846+ elems,
4847+
4848+ matcherOut = matcher ?
4849+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
4850+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
4851+
4852+ // ...intermediate processing is necessary
4853+ [] :
4854+
4855+ // ...otherwise use results directly
4856+ results :
4857+ matcherIn;
4858+
4859+ // Find primary matches
4860+ if ( matcher ) {
4861+ matcher( matcherIn, matcherOut, context, xml );
4862+ }
4863+
4864+ // Apply postFilter
4865+ if ( postFilter ) {
4866+ temp = condense( matcherOut, postMap );
4867+ postFilter( temp, [], context, xml );
4868+
4869+ // Un-match failing elements by moving them back to matcherIn
4870+ i = temp.length;
4871+ while ( i-- ) {
4872+ if ( (elem = temp[i]) ) {
4873+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
4874+ }
4875+ }
4876+ }
4877+
4878+ if ( seed ) {
4879+ if ( postFinder || preFilter ) {
4880+ if ( postFinder ) {
4881+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
4882+ temp = [];
4883+ i = matcherOut.length;
4884+ while ( i-- ) {
4885+ if ( (elem = matcherOut[i]) ) {
4886+ // Restore matcherIn since elem is not yet a final match
4887+ temp.push( (matcherIn[i] = elem) );
4888+ }
4889+ }
4890+ postFinder( null, (matcherOut = []), temp, xml );
4891+ }
4892+
4893+ // Move matched elements from seed to results to keep them synchronized
4894+ i = matcherOut.length;
4895+ while ( i-- ) {
4896+ if ( (elem = matcherOut[i]) &&
4897+ (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
4898+
4899+ seed[temp] = !(results[temp] = elem);
4900+ }
4901+ }
4902+ }
4903+
4904+ // Add elements to results, through postFinder if defined
4905+ } else {
4906+ matcherOut = condense(
4907+ matcherOut === results ?
4908+ matcherOut.splice( preexisting, matcherOut.length ) :
4909+ matcherOut
4910+ );
4911+ if ( postFinder ) {
4912+ postFinder( null, results, matcherOut, xml );
4913+ } else {
4914+ push.apply( results, matcherOut );
4915+ }
4916+ }
4917+ });
4918+}
4919+
4920+function matcherFromTokens( tokens ) {
4921+ var checkContext, matcher, j,
4922+ len = tokens.length,
4923+ leadingRelative = Expr.relative[ tokens[0].type ],
4924+ implicitRelative = leadingRelative || Expr.relative[" "],
4925+ i = leadingRelative ? 1 : 0,
4926+
4927+ // The foundational matcher ensures that elements are reachable from top-level context(s)
4928+ matchContext = addCombinator( function( elem ) {
4929+ return elem === checkContext;
4930+ }, implicitRelative, true ),
4931+ matchAnyContext = addCombinator( function( elem ) {
4932+ return indexOf( checkContext, elem ) > -1;
4933+ }, implicitRelative, true ),
4934+ matchers = [ function( elem, context, xml ) {
4935+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
4936+ (checkContext = context).nodeType ?
4937+ matchContext( elem, context, xml ) :
4938+ matchAnyContext( elem, context, xml ) );
4939+ // Avoid hanging onto element (issue #299)
4940+ checkContext = null;
4941+ return ret;
4942+ } ];
4943+
4944+ for ( ; i < len; i++ ) {
4945+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
4946+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
4947+ } else {
4948+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
4949+
4950+ // Return special upon seeing a positional matcher
4951+ if ( matcher[ expando ] ) {
4952+ // Find the next relative operator (if any) for proper handling
4953+ j = ++i;
4954+ for ( ; j < len; j++ ) {
4955+ if ( Expr.relative[ tokens[j].type ] ) {
4956+ break;
4957+ }
4958+ }
4959+ return setMatcher(
4960+ i > 1 && elementMatcher( matchers ),
4961+ i > 1 && toSelector(
4962+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
4963+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
4964+ ).replace( rtrim, "$1" ),
4965+ matcher,
4966+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
4967+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
4968+ j < len && toSelector( tokens )
4969+ );
4970+ }
4971+ matchers.push( matcher );
4972+ }
4973+ }
4974+
4975+ return elementMatcher( matchers );
4976+}
4977+
4978+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
4979+ var bySet = setMatchers.length > 0,
4980+ byElement = elementMatchers.length > 0,
4981+ superMatcher = function( seed, context, xml, results, outermost ) {
4982+ var elem, j, matcher,
4983+ matchedCount = 0,
4984+ i = "0",
4985+ unmatched = seed && [],
4986+ setMatched = [],
4987+ contextBackup = outermostContext,
4988+ // We must always have either seed elements or outermost context
4989+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
4990+ // Use integer dirruns iff this is the outermost matcher
4991+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
4992+ len = elems.length;
4993+
4994+ if ( outermost ) {
4995+ outermostContext = context === document || context || outermost;
4996+ }
4997+
4998+ // Add elements passing elementMatchers directly to results
4999+ // Support: IE<9, Safari
5000+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches