├── requirements.txt
├── docs
├── build
│ ├── html
│ │ ├── objects.inv
│ │ ├── _static
│ │ │ ├── down.png
│ │ │ ├── file.png
│ │ │ ├── plus.png
│ │ │ ├── up.png
│ │ │ ├── minus.png
│ │ │ ├── comment.png
│ │ │ ├── ajax-loader.gif
│ │ │ ├── up-pressed.png
│ │ │ ├── comment-bright.png
│ │ │ ├── comment-close.png
│ │ │ ├── down-pressed.png
│ │ │ ├── pygments.css
│ │ │ ├── default.css
│ │ │ ├── sidebar.js
│ │ │ ├── doctools.js
│ │ │ ├── basic.css
│ │ │ ├── searchtools.js
│ │ │ ├── websupport.js
│ │ │ └── underscore.js
│ │ ├── _sources
│ │ │ ├── settrie.txt
│ │ │ ├── test_settrie.txt
│ │ │ └── index.txt
│ │ ├── .buildinfo
│ │ ├── searchindex.js
│ │ ├── genindex.html
│ │ ├── test_settrie.html
│ │ ├── _modules
│ │ │ └── index.html
│ │ ├── search.html
│ │ ├── settrie.html
│ │ ├── py-modindex.html
│ │ └── index.html
│ └── doctrees
│ │ ├── index.doctree
│ │ ├── settrie.doctree
│ │ ├── environment.pickle
│ │ └── test_settrie.doctree
├── source
│ ├── settrie.rst
│ ├── test_settrie.rst
│ ├── index.rst
│ ├── make.bat
│ └── conf.py
└── Makefile
├── .travis.yml
├── .gitignore
├── setup.py
├── README.md
├── LICENSE
└── tests
└── test_settrie.py
/requirements.txt:
--------------------------------------------------------------------------------
1 | pytest
2 |
--------------------------------------------------------------------------------
/docs/build/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/objects.inv
--------------------------------------------------------------------------------
/docs/build/html/_static/down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/down.png
--------------------------------------------------------------------------------
/docs/build/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/file.png
--------------------------------------------------------------------------------
/docs/build/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/plus.png
--------------------------------------------------------------------------------
/docs/build/html/_static/up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/up.png
--------------------------------------------------------------------------------
/docs/build/doctrees/index.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/doctrees/index.doctree
--------------------------------------------------------------------------------
/docs/build/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/minus.png
--------------------------------------------------------------------------------
/docs/build/doctrees/settrie.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/doctrees/settrie.doctree
--------------------------------------------------------------------------------
/docs/build/html/_static/comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/comment.png
--------------------------------------------------------------------------------
/docs/build/doctrees/environment.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/doctrees/environment.pickle
--------------------------------------------------------------------------------
/docs/build/html/_static/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/ajax-loader.gif
--------------------------------------------------------------------------------
/docs/build/html/_static/up-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/up-pressed.png
--------------------------------------------------------------------------------
/docs/build/doctrees/test_settrie.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/doctrees/test_settrie.doctree
--------------------------------------------------------------------------------
/docs/build/html/_static/comment-bright.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/comment-bright.png
--------------------------------------------------------------------------------
/docs/build/html/_static/comment-close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/comment-close.png
--------------------------------------------------------------------------------
/docs/build/html/_static/down-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mmihaltz/pysettrie/HEAD/docs/build/html/_static/down-pressed.png
--------------------------------------------------------------------------------
/docs/source/settrie.rst:
--------------------------------------------------------------------------------
1 | settrie Module
2 | ==============
3 |
4 | .. automodule:: settrie
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/build/html/_sources/settrie.txt:
--------------------------------------------------------------------------------
1 | settrie Module
2 | ==============
3 |
4 | .. automodule:: settrie
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/source/test_settrie.rst:
--------------------------------------------------------------------------------
1 | test_settrie Module
2 | ===================
3 |
4 | .. automodule:: test_settrie
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/build/html/_sources/test_settrie.txt:
--------------------------------------------------------------------------------
1 | test_settrie Module
2 | ===================
3 |
4 | .. automodule:: test_settrie
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
--------------------------------------------------------------------------------
/docs/build/html/.buildinfo:
--------------------------------------------------------------------------------
1 | # Sphinx build info version 1
2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3 | config: ce9d209b997a681ba47f07f4cf48211f
4 | tags: 645f666f9bcd5a90fca523b33c5a78b7
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | branches:
2 | only:
3 | - master
4 | - "/^v.*$/"
5 | language: python
6 | sudo: false
7 | python:
8 | - 3.3
9 | - 3.4
10 | - 3.5
11 | - 3.6
12 | install:
13 | - pip install --upgrade pip
14 | - pip install --upgrade -r requirements.txt
15 | - pip install -e .
16 | script:
17 | - pytest -v
18 |
--------------------------------------------------------------------------------
/docs/build/html/searchindex.js:
--------------------------------------------------------------------------------
1 | Search.setIndex({filenames:["settrie","test_settrie","index"],terms:{modul:2,page:2,content:2,search:2,settri:2,index:2},objects:{},objnames:{},objtypes:{},titleterms:{modul:[0,1],indic:2,welcom:2,test_settri:1,tabl:2,settri:0,document:2,pysettri:2},envversion:43,titles:["settrie Module","test_settrie Module","Welcome to pysettrie’s documentation!"]})
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. .. documentation master file, created by
2 | sphinx-quickstart on Mon Dec 8 13:09:28 2014.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to pysettrie's documentation!
7 | ==============================
8 |
9 | Contents:
10 |
11 | .. toctree::
12 | :maxdepth: 4
13 |
14 | settrie
15 |
16 |
17 | Indices and tables
18 | ==================
19 |
20 | * :ref:`genindex`
21 | * :ref:`modindex`
22 | * :ref:`search`
23 |
24 |
--------------------------------------------------------------------------------
/docs/build/html/_sources/index.txt:
--------------------------------------------------------------------------------
1 | .. .. documentation master file, created by
2 | sphinx-quickstart on Mon Dec 8 13:09:28 2014.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to pysettrie's documentation!
7 | ==============================
8 |
9 | Contents:
10 |
11 | .. toctree::
12 | :maxdepth: 4
13 |
14 | settrie
15 |
16 |
17 | Indices and tables
18 | ==================
19 |
20 | * :ref:`genindex`
21 | * :ref:`modindex`
22 | * :ref:`search`
23 |
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | lib/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | *.egg-info/
22 | .installed.cfg
23 | *.egg
24 |
25 | # PyInstaller
26 | # Usually these files are written by a python script from a template
27 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
28 | *.manifest
29 | *.spec
30 |
31 | # Installer logs
32 | pip-log.txt
33 | pip-delete-this-directory.txt
34 |
35 | # Unit test / coverage reports
36 | htmlcov/
37 | .tox/
38 | .coverage
39 | .cache
40 | nosetests.xml
41 | coverage.xml
42 |
43 | # Translations
44 | *.mo
45 | *.pot
46 |
47 | # Django stuff:
48 | *.log
49 |
50 | # Sphinx documentation
51 | docs/_build/
52 |
53 | # PyBuilder
54 | target/
55 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | try:
5 | from setuptools import setup
6 | except ImportError :
7 | raise ImportError("setuptools module required, please go to https://pypi.python.org/pypi/setuptools and follow the instructions for installing setuptools")
8 |
9 | setup(
10 | name='pysettrie',
11 | url='https://github.com/mmihaltz/pysettrie',
12 | version='0.1.3',
13 | author='Márton Miháltz ',
14 | description='Efficient storage and querying of sets of sets using the trie data structure',
15 | packages=['settrie'],
16 | install_requires=['sortedcontainers'],
17 | classifiers=[
18 | 'Development Status :: 4 - Beta',
19 | 'Intended Audience :: Developers',
20 | 'Intended Audience :: Science/Research',
21 | 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)',
22 | 'Natural Language :: English',
23 | 'Operating System :: MacOS :: MacOS X',
24 | 'Operating System :: Microsoft :: Windows',
25 | 'Operating System :: POSIX',
26 | 'Programming Language :: Python :: 3.5',
27 | 'Topic :: Software Development :: Libraries :: Python Modules',
28 | 'Topic :: Scientific/Engineering',
29 | 'Topic :: Scientific/Engineering :: Information Analysis'],
30 | )
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | pysettrie
2 | =========
3 | [](https://travis-ci.org/mmihaltz/pysettrie)
4 |
5 | https://github.com/mmihaltz/pysettrie
6 |
7 | pysettrie is a python3 package that provides support for efficient storage and querying of sets of sets
8 | using the trie data structure, supporting operations like finding all the supersets/subsets of a given set
9 | from a collection of sets.
10 | The original motivation for this module was to provide efficient search for supersets of sets of feature-value pairs in our natural language parser project (e.g. matching nouns against verb argument positions).
11 |
12 | The following classes are included:
13 | - SetTrie: set-trie container for sets; supports efficient supersets/subsets of a given search set calculations.
14 | - SetTrieMap: mapping container using sets as keys; supports efficient operations like SetTrie but also stores values associated to the key sets.
15 | - SetTrieMultiMap: like SetTrieMap, but supports multiple values associated to each key.
16 |
17 | For further information, please see [documentation](docs/build/html/index.html)
18 |
19 | Module test_settrie.py contains unittests for all the containers.
20 |
21 | Author: Márton Miháltz
22 | [https://sites.google.com/site/mmihaltz/](https://sites.google.com/site/mmihaltz/)
23 |
24 | This package depends on the [sortedcollection](http://grantjenks.com/docs/sortedcontainers/) module.
25 | One recommended way to install (tested on Ubuntu):
26 | ```
27 | sudo pip3 install sortedcontainers
28 | ```
29 | If you don't have pip3:
30 | ```
31 | sudo apt-get install python3-setuptools
32 | sudo easy_install3 pip
33 | ```
34 |
35 | pysettrie is partly based on:
36 | I.Savnik: Index data structure for fast subset and superset queries. CD-ARES, IFIP LNCS, 2013.
37 | http://osebje.famnit.upr.si/~savnik/papers/cdares13.pdf
38 | Remarks on paper:
39 | - Algorithm 1. does not mention to sort children (or do sorted insert) in insert operation (line 5)
40 | - Algorithm 4. is wrong, will always return false, line 7 should be: "for (each child of node labeled l: word.currentElement <= l) & (while not found) do"
41 | - the descriptions of getAllSubSets and getAllSuperSets operations are wrong, would not produce all sub/supersets
42 |
43 | See also:
44 | - http://stackoverflow.com/questions/9353100/quickly-checking-if-set-is-superset-of-stored-sets
45 | - http://stackoverflow.com/questions/1263524/superset-search?rq=1
46 |
47 | Changes:
48 | * Version 0.1.3:
49 | - SetTrieMultiMap.assign() returns number of values associated to key after assignment.
50 |
51 | Licensed under the [GNU LESSER GENERAL PUBLIC LICENSE, Version 3](https://www.gnu.org/licenses/lgpl.html).
52 |
53 |
--------------------------------------------------------------------------------
/docs/build/html/genindex.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Index — pysettrie documentation
11 |
12 |
13 |
14 |
15 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
Index
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
76 |
77 |
78 |
87 |
91 |
92 |
--------------------------------------------------------------------------------
/docs/build/html/test_settrie.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | test_settrie Module — pysettrie documentation
10 |
11 |
12 |
13 |
14 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
test_settrie Module
46 |
47 |
48 |
49 |
50 |
51 |
52 |
74 |
75 |
76 |
85 |
89 |
90 |
--------------------------------------------------------------------------------
/docs/build/html/_modules/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Overview: module code — pysettrie documentation
12 |
13 |
14 |
15 |
16 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
All modules for which code is available
50 |
53 |
54 |
55 |
56 |
57 |
74 |
75 |
76 |
88 |
92 |
93 |
--------------------------------------------------------------------------------
/docs/build/html/search.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Search — pysettrie documentation
10 |
11 |
12 |
13 |
14 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
Search
53 |
54 |
55 |
56 | Please activate JavaScript to enable the search
57 | functionality.
58 |
59 |
60 |
61 | From here you can search these documents. Enter your search
62 | words into the box below and click "search". Note that the search
63 | function will automatically search for all of the words. Pages
64 | containing fewer words won't appear in the result list.
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
83 |
84 |
85 |
94 |
98 |
99 |
--------------------------------------------------------------------------------
/docs/build/html/settrie.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | settrie Module — pysettrie documentation
10 |
11 |
12 |
13 |
14 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
settrie Module
50 |
51 |
52 |
53 |
54 |
55 |
56 |
81 |
82 |
83 |
95 |
99 |
100 |
--------------------------------------------------------------------------------
/docs/build/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | .highlight .hll { background-color: #ffffcc }
2 | .highlight { background: #eeffcc; }
3 | .highlight .c { color: #408090; font-style: italic } /* Comment */
4 | .highlight .err { border: 1px solid #FF0000 } /* Error */
5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */
6 | .highlight .o { color: #666666 } /* Operator */
7 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
8 | .highlight .cp { color: #007020 } /* Comment.Preproc */
9 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
10 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
11 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
12 | .highlight .ge { font-style: italic } /* Generic.Emph */
13 | .highlight .gr { color: #FF0000 } /* Generic.Error */
14 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
15 | .highlight .gi { color: #00A000 } /* Generic.Inserted */
16 | .highlight .go { color: #333333 } /* Generic.Output */
17 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
18 | .highlight .gs { font-weight: bold } /* Generic.Strong */
19 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
20 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
21 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
22 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
23 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
24 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */
25 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
26 | .highlight .kt { color: #902000 } /* Keyword.Type */
27 | .highlight .m { color: #208050 } /* Literal.Number */
28 | .highlight .s { color: #4070a0 } /* Literal.String */
29 | .highlight .na { color: #4070a0 } /* Name.Attribute */
30 | .highlight .nb { color: #007020 } /* Name.Builtin */
31 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
32 | .highlight .no { color: #60add5 } /* Name.Constant */
33 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
34 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
35 | .highlight .ne { color: #007020 } /* Name.Exception */
36 | .highlight .nf { color: #06287e } /* Name.Function */
37 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
38 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
39 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
40 | .highlight .nv { color: #bb60d5 } /* Name.Variable */
41 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
43 | .highlight .mf { color: #208050 } /* Literal.Number.Float */
44 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */
45 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */
46 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */
47 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
48 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */
49 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
50 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */
51 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
52 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
53 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
54 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */
55 | .highlight .sr { color: #235388 } /* Literal.String.Regex */
56 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */
57 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */
58 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
59 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
60 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
61 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
62 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/docs/build/html/py-modindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Python Module Index — pysettrie documentation
12 |
13 |
14 |
15 |
16 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
Python Module Index
58 |
59 |
63 |
64 |
65 |
66 |
67 | s
68 |
69 |
70 |
71 | settrie
72 |
73 |
74 |
75 | t
76 |
77 |
78 |
79 | test_settrie
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
104 |
105 |
106 |
118 |
122 |
123 |
--------------------------------------------------------------------------------
/docs/build/html/index.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Welcome to pysettrie’s documentation! — pysettrie documentation
10 |
11 |
12 |
13 |
14 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
Welcome to pysettrie’s documentation!
50 |
Contents:
51 |
56 |
57 |
58 |
Indices and tables
59 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
101 |
102 |
103 |
115 |
119 |
120 |
--------------------------------------------------------------------------------
/docs/build/html/_static/default.css:
--------------------------------------------------------------------------------
1 | /*
2 | * default.css_t
3 | * ~~~~~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- default theme.
6 | *
7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | @import url("basic.css");
13 |
14 | /* -- page layout ----------------------------------------------------------- */
15 |
16 | body {
17 | font-family: sans-serif;
18 | font-size: 100%;
19 | background-color: #11303d;
20 | color: #000;
21 | margin: 0;
22 | padding: 0;
23 | }
24 |
25 | div.document {
26 | background-color: #1c4e63;
27 | }
28 |
29 | div.documentwrapper {
30 | float: left;
31 | width: 100%;
32 | }
33 |
34 | div.bodywrapper {
35 | margin: 0 0 0 230px;
36 | }
37 |
38 | div.body {
39 | background-color: #ffffff;
40 | color: #000000;
41 | padding: 0 20px 30px 20px;
42 | }
43 |
44 | div.footer {
45 | color: #ffffff;
46 | width: 100%;
47 | padding: 9px 0 9px 0;
48 | text-align: center;
49 | font-size: 75%;
50 | }
51 |
52 | div.footer a {
53 | color: #ffffff;
54 | text-decoration: underline;
55 | }
56 |
57 | div.related {
58 | background-color: #133f52;
59 | line-height: 30px;
60 | color: #ffffff;
61 | }
62 |
63 | div.related a {
64 | color: #ffffff;
65 | }
66 |
67 | div.sphinxsidebar {
68 | }
69 |
70 | div.sphinxsidebar h3 {
71 | font-family: 'Trebuchet MS', sans-serif;
72 | color: #ffffff;
73 | font-size: 1.4em;
74 | font-weight: normal;
75 | margin: 0;
76 | padding: 0;
77 | }
78 |
79 | div.sphinxsidebar h3 a {
80 | color: #ffffff;
81 | }
82 |
83 | div.sphinxsidebar h4 {
84 | font-family: 'Trebuchet MS', sans-serif;
85 | color: #ffffff;
86 | font-size: 1.3em;
87 | font-weight: normal;
88 | margin: 5px 0 0 0;
89 | padding: 0;
90 | }
91 |
92 | div.sphinxsidebar p {
93 | color: #ffffff;
94 | }
95 |
96 | div.sphinxsidebar p.topless {
97 | margin: 5px 10px 10px 10px;
98 | }
99 |
100 | div.sphinxsidebar ul {
101 | margin: 10px;
102 | padding: 0;
103 | color: #ffffff;
104 | }
105 |
106 | div.sphinxsidebar a {
107 | color: #98dbcc;
108 | }
109 |
110 | div.sphinxsidebar input {
111 | border: 1px solid #98dbcc;
112 | font-family: sans-serif;
113 | font-size: 1em;
114 | }
115 |
116 |
117 |
118 | /* -- hyperlink styles ------------------------------------------------------ */
119 |
120 | a {
121 | color: #355f7c;
122 | text-decoration: none;
123 | }
124 |
125 | a:visited {
126 | color: #355f7c;
127 | text-decoration: none;
128 | }
129 |
130 | a:hover {
131 | text-decoration: underline;
132 | }
133 |
134 |
135 |
136 | /* -- body styles ----------------------------------------------------------- */
137 |
138 | div.body h1,
139 | div.body h2,
140 | div.body h3,
141 | div.body h4,
142 | div.body h5,
143 | div.body h6 {
144 | font-family: 'Trebuchet MS', sans-serif;
145 | background-color: #f2f2f2;
146 | font-weight: normal;
147 | color: #20435c;
148 | border-bottom: 1px solid #ccc;
149 | margin: 20px -20px 10px -20px;
150 | padding: 3px 0 3px 10px;
151 | }
152 |
153 | div.body h1 { margin-top: 0; font-size: 200%; }
154 | div.body h2 { font-size: 160%; }
155 | div.body h3 { font-size: 140%; }
156 | div.body h4 { font-size: 120%; }
157 | div.body h5 { font-size: 110%; }
158 | div.body h6 { font-size: 100%; }
159 |
160 | a.headerlink {
161 | color: #c60f0f;
162 | font-size: 0.8em;
163 | padding: 0 4px 0 4px;
164 | text-decoration: none;
165 | }
166 |
167 | a.headerlink:hover {
168 | background-color: #c60f0f;
169 | color: white;
170 | }
171 |
172 | div.body p, div.body dd, div.body li {
173 | text-align: justify;
174 | line-height: 130%;
175 | }
176 |
177 | div.admonition p.admonition-title + p {
178 | display: inline;
179 | }
180 |
181 | div.admonition p {
182 | margin-bottom: 5px;
183 | }
184 |
185 | div.admonition pre {
186 | margin-bottom: 5px;
187 | }
188 |
189 | div.admonition ul, div.admonition ol {
190 | margin-bottom: 5px;
191 | }
192 |
193 | div.note {
194 | background-color: #eee;
195 | border: 1px solid #ccc;
196 | }
197 |
198 | div.seealso {
199 | background-color: #ffc;
200 | border: 1px solid #ff6;
201 | }
202 |
203 | div.topic {
204 | background-color: #eee;
205 | }
206 |
207 | div.warning {
208 | background-color: #ffe4e4;
209 | border: 1px solid #f66;
210 | }
211 |
212 | p.admonition-title {
213 | display: inline;
214 | }
215 |
216 | p.admonition-title:after {
217 | content: ":";
218 | }
219 |
220 | pre {
221 | padding: 5px;
222 | background-color: #eeffcc;
223 | color: #333333;
224 | line-height: 120%;
225 | border: 1px solid #ac9;
226 | border-left: none;
227 | border-right: none;
228 | }
229 |
230 | tt {
231 | background-color: #ecf0f3;
232 | padding: 0 1px 0 1px;
233 | font-size: 0.95em;
234 | }
235 |
236 | th {
237 | background-color: #ede;
238 | }
239 |
240 | .warning tt {
241 | background: #efc2c2;
242 | }
243 |
244 | .note tt {
245 | background: #d6d6d6;
246 | }
247 |
248 | .viewcode-back {
249 | font-family: sans-serif;
250 | }
251 |
252 | div.viewcode-block:target {
253 | background-color: #f4debf;
254 | border-top: 1px solid #ac9;
255 | border-bottom: 1px solid #ac9;
256 | }
--------------------------------------------------------------------------------
/docs/build/html/_static/sidebar.js:
--------------------------------------------------------------------------------
1 | /*
2 | * sidebar.js
3 | * ~~~~~~~~~~
4 | *
5 | * This script makes the Sphinx sidebar collapsible.
6 | *
7 | * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
8 | * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
9 | * used to collapse and expand the sidebar.
10 | *
11 | * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
12 | * and the width of the sidebar and the margin-left of the document
13 | * are decreased. When the sidebar is expanded the opposite happens.
14 | * This script saves a per-browser/per-session cookie used to
15 | * remember the position of the sidebar among the pages.
16 | * Once the browser is closed the cookie is deleted and the position
17 | * reset to the default (expanded).
18 | *
19 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
20 | * :license: BSD, see LICENSE for details.
21 | *
22 | */
23 |
24 | $(function() {
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | // global elements used by the functions.
34 | // the 'sidebarbutton' element is defined as global after its
35 | // creation, in the add_sidebar_button function
36 | var bodywrapper = $('.bodywrapper');
37 | var sidebar = $('.sphinxsidebar');
38 | var sidebarwrapper = $('.sphinxsidebarwrapper');
39 |
40 | // for some reason, the document has no sidebar; do not run into errors
41 | if (!sidebar.length) return;
42 |
43 | // original margin-left of the bodywrapper and width of the sidebar
44 | // with the sidebar expanded
45 | var bw_margin_expanded = bodywrapper.css('margin-left');
46 | var ssb_width_expanded = sidebar.width();
47 |
48 | // margin-left of the bodywrapper and width of the sidebar
49 | // with the sidebar collapsed
50 | var bw_margin_collapsed = '.8em';
51 | var ssb_width_collapsed = '.8em';
52 |
53 | // colors used by the current theme
54 | var dark_color = $('.related').css('background-color');
55 | var light_color = $('.document').css('background-color');
56 |
57 | function sidebar_is_collapsed() {
58 | return sidebarwrapper.is(':not(:visible)');
59 | }
60 |
61 | function toggle_sidebar() {
62 | if (sidebar_is_collapsed())
63 | expand_sidebar();
64 | else
65 | collapse_sidebar();
66 | }
67 |
68 | function collapse_sidebar() {
69 | sidebarwrapper.hide();
70 | sidebar.css('width', ssb_width_collapsed);
71 | bodywrapper.css('margin-left', bw_margin_collapsed);
72 | sidebarbutton.css({
73 | 'margin-left': '0',
74 | 'height': bodywrapper.height()
75 | });
76 | sidebarbutton.find('span').text('»');
77 | sidebarbutton.attr('title', _('Expand sidebar'));
78 | document.cookie = 'sidebar=collapsed';
79 | }
80 |
81 | function expand_sidebar() {
82 | bodywrapper.css('margin-left', bw_margin_expanded);
83 | sidebar.css('width', ssb_width_expanded);
84 | sidebarwrapper.show();
85 | sidebarbutton.css({
86 | 'margin-left': ssb_width_expanded-12,
87 | 'height': bodywrapper.height()
88 | });
89 | sidebarbutton.find('span').text('«');
90 | sidebarbutton.attr('title', _('Collapse sidebar'));
91 | document.cookie = 'sidebar=expanded';
92 | }
93 |
94 | function add_sidebar_button() {
95 | sidebarwrapper.css({
96 | 'float': 'left',
97 | 'margin-right': '0',
98 | 'width': ssb_width_expanded - 28
99 | });
100 | // create the button
101 | sidebar.append(
102 | ''
103 | );
104 | var sidebarbutton = $('#sidebarbutton');
105 | light_color = sidebarbutton.css('background-color');
106 | // find the height of the viewport to center the '<<' in the page
107 | var viewport_height;
108 | if (window.innerHeight)
109 | viewport_height = window.innerHeight;
110 | else
111 | viewport_height = $(window).height();
112 | sidebarbutton.find('span').css({
113 | 'display': 'block',
114 | 'margin-top': (viewport_height - sidebar.position().top - 20) / 2
115 | });
116 |
117 | sidebarbutton.click(toggle_sidebar);
118 | sidebarbutton.attr('title', _('Collapse sidebar'));
119 | sidebarbutton.css({
120 | 'color': '#FFFFFF',
121 | 'border-left': '1px solid ' + dark_color,
122 | 'font-size': '1.2em',
123 | 'cursor': 'pointer',
124 | 'height': bodywrapper.height(),
125 | 'padding-top': '1px',
126 | 'margin-left': ssb_width_expanded - 12
127 | });
128 |
129 | sidebarbutton.hover(
130 | function () {
131 | $(this).css('background-color', dark_color);
132 | },
133 | function () {
134 | $(this).css('background-color', light_color);
135 | }
136 | );
137 | }
138 |
139 | function set_position_from_cookie() {
140 | if (!document.cookie)
141 | return;
142 | var items = document.cookie.split(';');
143 | for(var k=0; k` where ^ is one of
21 | echo. html to make standalone HTML files
22 | echo. dirhtml to make HTML files named index.html in directories
23 | echo. singlehtml to make a single large HTML file
24 | echo. pickle to make pickle files
25 | echo. json to make JSON files
26 | echo. htmlhelp to make HTML files and a HTML help project
27 | echo. qthelp to make HTML files and a qthelp project
28 | echo. devhelp to make HTML files and a Devhelp project
29 | echo. epub to make an epub
30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
31 | echo. text to make text files
32 | echo. man to make manual pages
33 | echo. texinfo to make Texinfo files
34 | echo. gettext to make PO message catalogs
35 | echo. changes to make an overview over all changed/added/deprecated items
36 | echo. linkcheck to check all external links for integrity
37 | echo. doctest to run all doctests embedded in the documentation if enabled
38 | goto end
39 | )
40 |
41 | if "%1" == "clean" (
42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
43 | del /q /s %BUILDDIR%\*
44 | goto end
45 | )
46 |
47 | if "%1" == "html" (
48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
49 | if errorlevel 1 exit /b 1
50 | echo.
51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
52 | goto end
53 | )
54 |
55 | if "%1" == "dirhtml" (
56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
57 | if errorlevel 1 exit /b 1
58 | echo.
59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
60 | goto end
61 | )
62 |
63 | if "%1" == "singlehtml" (
64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
65 | if errorlevel 1 exit /b 1
66 | echo.
67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
68 | goto end
69 | )
70 |
71 | if "%1" == "pickle" (
72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
73 | if errorlevel 1 exit /b 1
74 | echo.
75 | echo.Build finished; now you can process the pickle files.
76 | goto end
77 | )
78 |
79 | if "%1" == "json" (
80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
81 | if errorlevel 1 exit /b 1
82 | echo.
83 | echo.Build finished; now you can process the JSON files.
84 | goto end
85 | )
86 |
87 | if "%1" == "htmlhelp" (
88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
89 | if errorlevel 1 exit /b 1
90 | echo.
91 | echo.Build finished; now you can run HTML Help Workshop with the ^
92 | .hhp project file in %BUILDDIR%/htmlhelp.
93 | goto end
94 | )
95 |
96 | if "%1" == "qthelp" (
97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
98 | if errorlevel 1 exit /b 1
99 | echo.
100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
101 | .qhcp project file in %BUILDDIR%/qthelp, like this:
102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\.qhcp
103 | echo.To view the help file:
104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\.ghc
105 | goto end
106 | )
107 |
108 | if "%1" == "devhelp" (
109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
110 | if errorlevel 1 exit /b 1
111 | echo.
112 | echo.Build finished.
113 | goto end
114 | )
115 |
116 | if "%1" == "epub" (
117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
118 | if errorlevel 1 exit /b 1
119 | echo.
120 | echo.Build finished. The epub file is in %BUILDDIR%/epub.
121 | goto end
122 | )
123 |
124 | if "%1" == "latex" (
125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
126 | if errorlevel 1 exit /b 1
127 | echo.
128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
129 | goto end
130 | )
131 |
132 | if "%1" == "text" (
133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
134 | if errorlevel 1 exit /b 1
135 | echo.
136 | echo.Build finished. The text files are in %BUILDDIR%/text.
137 | goto end
138 | )
139 |
140 | if "%1" == "man" (
141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
142 | if errorlevel 1 exit /b 1
143 | echo.
144 | echo.Build finished. The manual pages are in %BUILDDIR%/man.
145 | goto end
146 | )
147 |
148 | if "%1" == "texinfo" (
149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
150 | if errorlevel 1 exit /b 1
151 | echo.
152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
153 | goto end
154 | )
155 |
156 | if "%1" == "gettext" (
157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
158 | if errorlevel 1 exit /b 1
159 | echo.
160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
161 | goto end
162 | )
163 |
164 | if "%1" == "changes" (
165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
166 | if errorlevel 1 exit /b 1
167 | echo.
168 | echo.The overview file is in %BUILDDIR%/changes.
169 | goto end
170 | )
171 |
172 | if "%1" == "linkcheck" (
173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
174 | if errorlevel 1 exit /b 1
175 | echo.
176 | echo.Link check complete; look for any errors in the above output ^
177 | or in %BUILDDIR%/linkcheck/output.txt.
178 | goto end
179 | )
180 |
181 | if "%1" == "doctest" (
182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
183 | if errorlevel 1 exit /b 1
184 | echo.
185 | echo.Testing of doctests in the sources finished, look at the ^
186 | results in %BUILDDIR%/doctest/output.txt.
187 | goto end
188 | )
189 |
190 | :end
191 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = build
9 |
10 | # Internal variables.
11 | PAPEROPT_a4 = -D latex_paper_size=a4
12 | PAPEROPT_letter = -D latex_paper_size=letter
13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
14 | # the i18n builder cannot share the environment and doctrees with the others
15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16 |
17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18 |
19 | help:
20 | @echo "Please use \`make ' where is one of"
21 | @echo " html to make standalone HTML files"
22 | @echo " dirhtml to make HTML files named index.html in directories"
23 | @echo " singlehtml to make a single large HTML file"
24 | @echo " pickle to make pickle files"
25 | @echo " json to make JSON files"
26 | @echo " htmlhelp to make HTML files and a HTML help project"
27 | @echo " qthelp to make HTML files and a qthelp project"
28 | @echo " devhelp to make HTML files and a Devhelp project"
29 | @echo " epub to make an epub"
30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
32 | @echo " text to make text files"
33 | @echo " man to make manual pages"
34 | @echo " texinfo to make Texinfo files"
35 | @echo " info to make Texinfo files and run them through makeinfo"
36 | @echo " gettext to make PO message catalogs"
37 | @echo " changes to make an overview of all changed/added/deprecated items"
38 | @echo " linkcheck to check all external links for integrity"
39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40 |
41 | clean:
42 | -rm -rf $(BUILDDIR)/*
43 |
44 | html:
45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46 | @echo
47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48 |
49 | dirhtml:
50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51 | @echo
52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53 |
54 | singlehtml:
55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56 | @echo
57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58 |
59 | pickle:
60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61 | @echo
62 | @echo "Build finished; now you can process the pickle files."
63 |
64 | json:
65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66 | @echo
67 | @echo "Build finished; now you can process the JSON files."
68 |
69 | htmlhelp:
70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71 | @echo
72 | @echo "Build finished; now you can run HTML Help Workshop with the" \
73 | ".hhp project file in $(BUILDDIR)/htmlhelp."
74 |
75 | qthelp:
76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77 | @echo
78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/.qhcp"
81 | @echo "To view the help file:"
82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/.qhc"
83 |
84 | devhelp:
85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86 | @echo
87 | @echo "Build finished."
88 | @echo "To view the help file:"
89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/"
90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/"
91 | @echo "# devhelp"
92 |
93 | epub:
94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95 | @echo
96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97 |
98 | latex:
99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100 | @echo
101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
103 | "(use \`make latexpdf' here to do that automatically)."
104 |
105 | latexpdf:
106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107 | @echo "Running LaTeX files through pdflatex..."
108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110 |
111 | text:
112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113 | @echo
114 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
115 |
116 | man:
117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118 | @echo
119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120 |
121 | texinfo:
122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123 | @echo
124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125 | @echo "Run \`make' in that directory to run these through makeinfo" \
126 | "(use \`make info' here to do that automatically)."
127 |
128 | info:
129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130 | @echo "Running Texinfo files through makeinfo..."
131 | make -C $(BUILDDIR)/texinfo info
132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133 |
134 | gettext:
135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136 | @echo
137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138 |
139 | changes:
140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141 | @echo
142 | @echo "The overview file is in $(BUILDDIR)/changes."
143 |
144 | linkcheck:
145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146 | @echo
147 | @echo "Link check complete; look for any errors in the above output " \
148 | "or in $(BUILDDIR)/linkcheck/output.txt."
149 |
150 | doctest:
151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152 | @echo "Testing of doctests in the sources finished, look at the " \
153 | "results in $(BUILDDIR)/doctest/output.txt."
154 |
--------------------------------------------------------------------------------
/docs/build/html/_static/doctools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * doctools.js
3 | * ~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for all documentation.
6 | *
7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /**
13 | * select a different prefix for underscore
14 | */
15 | $u = _.noConflict();
16 |
17 | /**
18 | * make the code below compatible with browsers without
19 | * an installed firebug like debugger
20 | if (!window.console || !console.firebug) {
21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
23 | "profile", "profileEnd"];
24 | window.console = {};
25 | for (var i = 0; i < names.length; ++i)
26 | window.console[names[i]] = function() {};
27 | }
28 | */
29 |
30 | /**
31 | * small helper function to urldecode strings
32 | */
33 | jQuery.urldecode = function(x) {
34 | return decodeURIComponent(x).replace(/\+/g, ' ');
35 | };
36 |
37 | /**
38 | * small helper function to urlencode strings
39 | */
40 | jQuery.urlencode = encodeURIComponent;
41 |
42 | /**
43 | * This function returns the parsed url parameters of the
44 | * current request. Multiple values per key are supported,
45 | * it will always return arrays of strings for the value parts.
46 | */
47 | jQuery.getQueryParameters = function(s) {
48 | if (typeof s == 'undefined')
49 | s = document.location.search;
50 | var parts = s.substr(s.indexOf('?') + 1).split('&');
51 | var result = {};
52 | for (var i = 0; i < parts.length; i++) {
53 | var tmp = parts[i].split('=', 2);
54 | var key = jQuery.urldecode(tmp[0]);
55 | var value = jQuery.urldecode(tmp[1]);
56 | if (key in result)
57 | result[key].push(value);
58 | else
59 | result[key] = [value];
60 | }
61 | return result;
62 | };
63 |
64 | /**
65 | * highlight a given string on a jquery object by wrapping it in
66 | * span elements with the given class name.
67 | */
68 | jQuery.fn.highlightText = function(text, className) {
69 | function highlight(node) {
70 | if (node.nodeType == 3) {
71 | var val = node.nodeValue;
72 | var pos = val.toLowerCase().indexOf(text);
73 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
74 | var span = document.createElement("span");
75 | span.className = className;
76 | span.appendChild(document.createTextNode(val.substr(pos, text.length)));
77 | node.parentNode.insertBefore(span, node.parentNode.insertBefore(
78 | document.createTextNode(val.substr(pos + text.length)),
79 | node.nextSibling));
80 | node.nodeValue = val.substr(0, pos);
81 | }
82 | }
83 | else if (!jQuery(node).is("button, select, textarea")) {
84 | jQuery.each(node.childNodes, function() {
85 | highlight(this);
86 | });
87 | }
88 | }
89 | return this.each(function() {
90 | highlight(this);
91 | });
92 | };
93 |
94 | /**
95 | * Small JavaScript module for the documentation.
96 | */
97 | var Documentation = {
98 |
99 | init : function() {
100 | this.fixFirefoxAnchorBug();
101 | this.highlightSearchWords();
102 | this.initIndexTable();
103 | },
104 |
105 | /**
106 | * i18n support
107 | */
108 | TRANSLATIONS : {},
109 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
110 | LOCALE : 'unknown',
111 |
112 | // gettext and ngettext don't access this so that the functions
113 | // can safely bound to a different name (_ = Documentation.gettext)
114 | gettext : function(string) {
115 | var translated = Documentation.TRANSLATIONS[string];
116 | if (typeof translated == 'undefined')
117 | return string;
118 | return (typeof translated == 'string') ? translated : translated[0];
119 | },
120 |
121 | ngettext : function(singular, plural, n) {
122 | var translated = Documentation.TRANSLATIONS[singular];
123 | if (typeof translated == 'undefined')
124 | return (n == 1) ? singular : plural;
125 | return translated[Documentation.PLURALEXPR(n)];
126 | },
127 |
128 | addTranslations : function(catalog) {
129 | for (var key in catalog.messages)
130 | this.TRANSLATIONS[key] = catalog.messages[key];
131 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
132 | this.LOCALE = catalog.locale;
133 | },
134 |
135 | /**
136 | * add context elements like header anchor links
137 | */
138 | addContextElements : function() {
139 | $('div[id] > :header:first').each(function() {
140 | $('').
141 | attr('href', '#' + this.id).
142 | attr('title', _('Permalink to this headline')).
143 | appendTo(this);
144 | });
145 | $('dt[id]').each(function() {
146 | $('').
147 | attr('href', '#' + this.id).
148 | attr('title', _('Permalink to this definition')).
149 | appendTo(this);
150 | });
151 | },
152 |
153 | /**
154 | * workaround a firefox stupidity
155 | */
156 | fixFirefoxAnchorBug : function() {
157 | if (document.location.hash && $.browser.mozilla)
158 | window.setTimeout(function() {
159 | document.location.href += '';
160 | }, 10);
161 | },
162 |
163 | /**
164 | * highlight the search words provided in the url in the text
165 | */
166 | highlightSearchWords : function() {
167 | var params = $.getQueryParameters();
168 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
169 | if (terms.length) {
170 | var body = $('div.body');
171 | if (!body.length) {
172 | body = $('body');
173 | }
174 | window.setTimeout(function() {
175 | $.each(terms, function() {
176 | body.highlightText(this.toLowerCase(), 'highlighted');
177 | });
178 | }, 10);
179 | $('' + _('Hide Search Matches') + '
')
181 | .appendTo($('#searchbox'));
182 | }
183 | },
184 |
185 | /**
186 | * init the domain index toggle buttons
187 | */
188 | initIndexTable : function() {
189 | var togglers = $('img.toggler').click(function() {
190 | var src = $(this).attr('src');
191 | var idnum = $(this).attr('id').substr(7);
192 | $('tr.cg-' + idnum).toggle();
193 | if (src.substr(-9) == 'minus.png')
194 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
195 | else
196 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
197 | }).css('display', '');
198 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
199 | togglers.click();
200 | }
201 | },
202 |
203 | /**
204 | * helper function to hide the search marks again
205 | */
206 | hideSearchWords : function() {
207 | $('#searchbox .highlight-link').fadeOut(300);
208 | $('span.highlighted').removeClass('highlighted');
209 | },
210 |
211 | /**
212 | * make the url absolute
213 | */
214 | makeURL : function(relativeURL) {
215 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
216 | },
217 |
218 | /**
219 | * get the current relative url
220 | */
221 | getCurrentURL : function() {
222 | var path = document.location.pathname;
223 | var parts = path.split(/\//);
224 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
225 | if (this == '..')
226 | parts.pop();
227 | });
228 | var url = parts.join('/');
229 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
230 | }
231 | };
232 |
233 | // quick alias for translations
234 | _ = Documentation.gettext;
235 |
236 | $(document).ready(function() {
237 | Documentation.init();
238 | });
239 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
167 |
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # .. documentation build configuration file, created by
5 | # sphinx-quickstart on Mon Dec 8 13:09:28 2014.
6 | #
7 | # This file is execfile()d with the current directory set to its containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import sys, os
16 |
17 | # If extensions (or modules to document with autodoc) are in another directory,
18 | # add these directories to sys.path here. If the directory is relative to the
19 | # documentation root, use os.path.abspath to make it absolute, like shown here.
20 | #sys.path.insert(0, os.path.abspath('.'))
21 |
22 | # -- General configuration -----------------------------------------------------
23 |
24 | # If your documentation needs a minimal Sphinx version, state it here.
25 | #needs_sphinx = '1.0'
26 |
27 | # Add any Sphinx extension module names here, as strings. They can be extensions
28 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
29 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
30 |
31 | # Add any paths that contain templates here, relative to this directory.
32 | templates_path = ['_templates']
33 |
34 | # The suffix of source filenames.
35 | source_suffix = '.rst'
36 |
37 | # The encoding of source files.
38 | #source_encoding = 'utf-8-sig'
39 |
40 | # The master toctree document.
41 | master_doc = 'index'
42 |
43 | # General information about the project.
44 | project = 'pysettrie'
45 | copyright = '2014, Marton Mihaltz'
46 |
47 | # The version info for the project you're documenting, acts as replacement for
48 | # |version| and |release|, also used in various other places throughout the
49 | # built documents.
50 | #
51 | # The short X.Y version.
52 | version = '1.0'
53 | # The full version, including alpha/beta/rc tags.
54 | release = ''
55 |
56 | # The language for content autogenerated by Sphinx. Refer to documentation
57 | # for a list of supported languages.
58 | #language = None
59 |
60 | # There are two options for replacing |today|: either, you set today to some
61 | # non-false value, then it is used:
62 | #today = ''
63 | # Else, today_fmt is used as the format for a strftime call.
64 | #today_fmt = '%B %d, %Y'
65 |
66 | # List of patterns, relative to source directory, that match files and
67 | # directories to ignore when looking for source files.
68 | exclude_patterns = ['_build']
69 |
70 | # The reST default role (used for this markup: `text`) to use for all documents.
71 | #default_role = None
72 |
73 | # If true, '()' will be appended to :func: etc. cross-reference text.
74 | #add_function_parentheses = True
75 |
76 | # If true, the current module name will be prepended to all description
77 | # unit titles (such as .. function::).
78 | #add_module_names = True
79 |
80 | # If true, sectionauthor and moduleauthor directives will be shown in the
81 | # output. They are ignored by default.
82 | #show_authors = False
83 |
84 | # The name of the Pygments (syntax highlighting) style to use.
85 | pygments_style = 'sphinx'
86 |
87 | # A list of ignored prefixes for module index sorting.
88 | #modindex_common_prefix = []
89 |
90 |
91 | # -- Options for HTML output ---------------------------------------------------
92 |
93 | # The theme to use for HTML and HTML Help pages. See the documentation for
94 | # a list of builtin themes.
95 | html_theme = 'default'
96 |
97 | # Theme options are theme-specific and customize the look and feel of a theme
98 | # further. For a list of options available for each theme, see the
99 | # documentation.
100 | #html_theme_options = {}
101 |
102 | # Add any paths that contain custom themes here, relative to this directory.
103 | #html_theme_path = []
104 |
105 | # The name for this set of Sphinx documents. If None, it defaults to
106 | # " v documentation".
107 | #html_title = None
108 |
109 | # A shorter title for the navigation bar. Default is the same as html_title.
110 | #html_short_title = None
111 |
112 | # The name of an image file (relative to this directory) to place at the top
113 | # of the sidebar.
114 | #html_logo = None
115 |
116 | # The name of an image file (within the static path) to use as favicon of the
117 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
118 | # pixels large.
119 | #html_favicon = None
120 |
121 | # Add any paths that contain custom static files (such as style sheets) here,
122 | # relative to this directory. They are copied after the builtin static files,
123 | # so a file named "default.css" will overwrite the builtin "default.css".
124 | html_static_path = ['_static']
125 |
126 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
127 | # using the given strftime format.
128 | #html_last_updated_fmt = '%b %d, %Y'
129 |
130 | # If true, SmartyPants will be used to convert quotes and dashes to
131 | # typographically correct entities.
132 | #html_use_smartypants = True
133 |
134 | # Custom sidebar templates, maps document names to template names.
135 | #html_sidebars = {}
136 |
137 | # Additional templates that should be rendered to pages, maps page names to
138 | # template names.
139 | #html_additional_pages = {}
140 |
141 | # If false, no module index is generated.
142 | #html_domain_indices = True
143 |
144 | # If false, no index is generated.
145 | #html_use_index = True
146 |
147 | # If true, the index is split into individual pages for each letter.
148 | #html_split_index = False
149 |
150 | # If true, links to the reST sources are added to the pages.
151 | #html_show_sourcelink = True
152 |
153 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
154 | #html_show_sphinx = True
155 |
156 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
157 | #html_show_copyright = True
158 |
159 | # If true, an OpenSearch description file will be output, and all pages will
160 | # contain a tag referring to it. The value of this option must be the
161 | # base URL from which the finished HTML is served.
162 | #html_use_opensearch = ''
163 |
164 | # This is the file name suffix for HTML files (e.g. ".xhtml").
165 | #html_file_suffix = None
166 |
167 | # Output file base name for HTML help builder.
168 | htmlhelp_basename = 'doc'
169 |
170 |
171 | # -- Options for LaTeX output --------------------------------------------------
172 |
173 | latex_elements = {
174 | # The paper size ('letterpaper' or 'a4paper').
175 | #'papersize': 'letterpaper',
176 |
177 | # The font size ('10pt', '11pt' or '12pt').
178 | #'pointsize': '10pt',
179 |
180 | # Additional stuff for the LaTeX preamble.
181 | #'preamble': '',
182 | }
183 |
184 | # Grouping the document tree into LaTeX files. List of tuples
185 | # (source start file, target name, title, author, documentclass [howto/manual]).
186 | latex_documents = [
187 | ('index', '.tex', '.. Documentation',
188 | 'Author', 'manual'),
189 | ]
190 |
191 | # The name of an image file (relative to this directory) to place at the top of
192 | # the title page.
193 | #latex_logo = None
194 |
195 | # For "manual" documents, if this is true, then toplevel headings are parts,
196 | # not chapters.
197 | #latex_use_parts = False
198 |
199 | # If true, show page references after internal links.
200 | #latex_show_pagerefs = False
201 |
202 | # If true, show URL addresses after external links.
203 | #latex_show_urls = False
204 |
205 | # Documents to append as an appendix to all manuals.
206 | #latex_appendices = []
207 |
208 | # If false, no module index is generated.
209 | #latex_domain_indices = True
210 |
211 |
212 | # -- Options for manual page output --------------------------------------------
213 |
214 | # One entry per manual page. List of tuples
215 | # (source start file, name, description, authors, manual section).
216 | man_pages = [
217 | ('index', '', '.. Documentation',
218 | ['Author'], 1)
219 | ]
220 |
221 | # If true, show URL addresses after external links.
222 | #man_show_urls = False
223 |
224 |
225 | # -- Options for Texinfo output ------------------------------------------------
226 |
227 | # Grouping the document tree into Texinfo files. List of tuples
228 | # (source start file, target name, title, author,
229 | # dir menu entry, description, category)
230 | texinfo_documents = [
231 | ('index', '', '.. Documentation',
232 | 'Author', '', 'One line description of project.',
233 | 'Miscellaneous'),
234 | ]
235 |
236 | # Documents to append as an appendix to all manuals.
237 | #texinfo_appendices = []
238 |
239 | # If false, no module index is generated.
240 | #texinfo_domain_indices = True
241 |
242 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
243 | #texinfo_show_urls = 'footnote'
244 |
245 |
246 | # -- Options for Epub output ---------------------------------------------------
247 |
248 | # Bibliographic Dublin Core info.
249 | epub_title = '..'
250 | epub_author = 'Author'
251 | epub_publisher = 'Author'
252 | epub_copyright = '2014, Author'
253 |
254 | # The language of the text. It defaults to the language option
255 | # or en if the language is not set.
256 | #epub_language = ''
257 |
258 | # The scheme of the identifier. Typical schemes are ISBN or URL.
259 | #epub_scheme = ''
260 |
261 | # The unique identifier of the text. This can be a ISBN number
262 | # or the project homepage.
263 | #epub_identifier = ''
264 |
265 | # A unique identification for the text.
266 | #epub_uid = ''
267 |
268 | # A tuple containing the cover image and cover page html template filenames.
269 | #epub_cover = ()
270 |
271 | # HTML files that should be inserted before the pages created by sphinx.
272 | # The format is a list of tuples containing the path and title.
273 | #epub_pre_files = []
274 |
275 | # HTML files shat should be inserted after the pages created by sphinx.
276 | # The format is a list of tuples containing the path and title.
277 | #epub_post_files = []
278 |
279 | # A list of files that should not be packed into the epub file.
280 | #epub_exclude_files = []
281 |
282 | # The depth of the table of contents in toc.ncx.
283 | #epub_tocdepth = 3
284 |
285 | # Allow duplicate toc entries.
286 | #epub_tocdup = True
287 |
--------------------------------------------------------------------------------
/docs/build/html/_static/basic.css:
--------------------------------------------------------------------------------
1 | /*
2 | * basic.css
3 | * ~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- basic theme.
6 | *
7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /* -- main layout ----------------------------------------------------------- */
13 |
14 | div.clearer {
15 | clear: both;
16 | }
17 |
18 | /* -- relbar ---------------------------------------------------------------- */
19 |
20 | div.related {
21 | width: 100%;
22 | font-size: 90%;
23 | }
24 |
25 | div.related h3 {
26 | display: none;
27 | }
28 |
29 | div.related ul {
30 | margin: 0;
31 | padding: 0 0 0 10px;
32 | list-style: none;
33 | }
34 |
35 | div.related li {
36 | display: inline;
37 | }
38 |
39 | div.related li.right {
40 | float: right;
41 | margin-right: 5px;
42 | }
43 |
44 | /* -- sidebar --------------------------------------------------------------- */
45 |
46 | div.sphinxsidebarwrapper {
47 | padding: 10px 5px 0 10px;
48 | }
49 |
50 | div.sphinxsidebar {
51 | float: left;
52 | width: 230px;
53 | margin-left: -100%;
54 | font-size: 90%;
55 | }
56 |
57 | div.sphinxsidebar ul {
58 | list-style: none;
59 | }
60 |
61 | div.sphinxsidebar ul ul,
62 | div.sphinxsidebar ul.want-points {
63 | margin-left: 20px;
64 | list-style: square;
65 | }
66 |
67 | div.sphinxsidebar ul ul {
68 | margin-top: 0;
69 | margin-bottom: 0;
70 | }
71 |
72 | div.sphinxsidebar form {
73 | margin-top: 10px;
74 | }
75 |
76 | div.sphinxsidebar input {
77 | border: 1px solid #98dbcc;
78 | font-family: sans-serif;
79 | font-size: 1em;
80 | }
81 |
82 | div.sphinxsidebar #searchbox input[type="text"] {
83 | width: 170px;
84 | }
85 |
86 | div.sphinxsidebar #searchbox input[type="submit"] {
87 | width: 30px;
88 | }
89 |
90 | img {
91 | border: 0;
92 | max-width: 100%;
93 | }
94 |
95 | /* -- search page ----------------------------------------------------------- */
96 |
97 | ul.search {
98 | margin: 10px 0 0 20px;
99 | padding: 0;
100 | }
101 |
102 | ul.search li {
103 | padding: 5px 0 5px 20px;
104 | background-image: url(file.png);
105 | background-repeat: no-repeat;
106 | background-position: 0 7px;
107 | }
108 |
109 | ul.search li a {
110 | font-weight: bold;
111 | }
112 |
113 | ul.search li div.context {
114 | color: #888;
115 | margin: 2px 0 0 30px;
116 | text-align: left;
117 | }
118 |
119 | ul.keywordmatches li.goodmatch a {
120 | font-weight: bold;
121 | }
122 |
123 | /* -- index page ------------------------------------------------------------ */
124 |
125 | table.contentstable {
126 | width: 90%;
127 | }
128 |
129 | table.contentstable p.biglink {
130 | line-height: 150%;
131 | }
132 |
133 | a.biglink {
134 | font-size: 1.3em;
135 | }
136 |
137 | span.linkdescr {
138 | font-style: italic;
139 | padding-top: 5px;
140 | font-size: 90%;
141 | }
142 |
143 | /* -- general index --------------------------------------------------------- */
144 |
145 | table.indextable {
146 | width: 100%;
147 | }
148 |
149 | table.indextable td {
150 | text-align: left;
151 | vertical-align: top;
152 | }
153 |
154 | table.indextable dl, table.indextable dd {
155 | margin-top: 0;
156 | margin-bottom: 0;
157 | }
158 |
159 | table.indextable tr.pcap {
160 | height: 10px;
161 | }
162 |
163 | table.indextable tr.cap {
164 | margin-top: 10px;
165 | background-color: #f2f2f2;
166 | }
167 |
168 | img.toggler {
169 | margin-right: 3px;
170 | margin-top: 3px;
171 | cursor: pointer;
172 | }
173 |
174 | div.modindex-jumpbox {
175 | border-top: 1px solid #ddd;
176 | border-bottom: 1px solid #ddd;
177 | margin: 1em 0 1em 0;
178 | padding: 0.4em;
179 | }
180 |
181 | div.genindex-jumpbox {
182 | border-top: 1px solid #ddd;
183 | border-bottom: 1px solid #ddd;
184 | margin: 1em 0 1em 0;
185 | padding: 0.4em;
186 | }
187 |
188 | /* -- general body styles --------------------------------------------------- */
189 |
190 | a.headerlink {
191 | visibility: hidden;
192 | }
193 |
194 | h1:hover > a.headerlink,
195 | h2:hover > a.headerlink,
196 | h3:hover > a.headerlink,
197 | h4:hover > a.headerlink,
198 | h5:hover > a.headerlink,
199 | h6:hover > a.headerlink,
200 | dt:hover > a.headerlink {
201 | visibility: visible;
202 | }
203 |
204 | div.body p.caption {
205 | text-align: inherit;
206 | }
207 |
208 | div.body td {
209 | text-align: left;
210 | }
211 |
212 | .field-list ul {
213 | padding-left: 1em;
214 | }
215 |
216 | .first {
217 | margin-top: 0 !important;
218 | }
219 |
220 | p.rubric {
221 | margin-top: 30px;
222 | font-weight: bold;
223 | }
224 |
225 | img.align-left, .figure.align-left, object.align-left {
226 | clear: left;
227 | float: left;
228 | margin-right: 1em;
229 | }
230 |
231 | img.align-right, .figure.align-right, object.align-right {
232 | clear: right;
233 | float: right;
234 | margin-left: 1em;
235 | }
236 |
237 | img.align-center, .figure.align-center, object.align-center {
238 | display: block;
239 | margin-left: auto;
240 | margin-right: auto;
241 | }
242 |
243 | .align-left {
244 | text-align: left;
245 | }
246 |
247 | .align-center {
248 | text-align: center;
249 | }
250 |
251 | .align-right {
252 | text-align: right;
253 | }
254 |
255 | /* -- sidebars -------------------------------------------------------------- */
256 |
257 | div.sidebar {
258 | margin: 0 0 0.5em 1em;
259 | border: 1px solid #ddb;
260 | padding: 7px 7px 0 7px;
261 | background-color: #ffe;
262 | width: 40%;
263 | float: right;
264 | }
265 |
266 | p.sidebar-title {
267 | font-weight: bold;
268 | }
269 |
270 | /* -- topics ---------------------------------------------------------------- */
271 |
272 | div.topic {
273 | border: 1px solid #ccc;
274 | padding: 7px 7px 0 7px;
275 | margin: 10px 0 10px 0;
276 | }
277 |
278 | p.topic-title {
279 | font-size: 1.1em;
280 | font-weight: bold;
281 | margin-top: 10px;
282 | }
283 |
284 | /* -- admonitions ----------------------------------------------------------- */
285 |
286 | div.admonition {
287 | margin-top: 10px;
288 | margin-bottom: 10px;
289 | padding: 7px;
290 | }
291 |
292 | div.admonition dt {
293 | font-weight: bold;
294 | }
295 |
296 | div.admonition dl {
297 | margin-bottom: 0;
298 | }
299 |
300 | p.admonition-title {
301 | margin: 0px 10px 5px 0px;
302 | font-weight: bold;
303 | }
304 |
305 | div.body p.centered {
306 | text-align: center;
307 | margin-top: 25px;
308 | }
309 |
310 | /* -- tables ---------------------------------------------------------------- */
311 |
312 | table.docutils {
313 | border: 0;
314 | border-collapse: collapse;
315 | }
316 |
317 | table.docutils td, table.docutils th {
318 | padding: 1px 8px 1px 5px;
319 | border-top: 0;
320 | border-left: 0;
321 | border-right: 0;
322 | border-bottom: 1px solid #aaa;
323 | }
324 |
325 | table.field-list td, table.field-list th {
326 | border: 0 !important;
327 | }
328 |
329 | table.footnote td, table.footnote th {
330 | border: 0 !important;
331 | }
332 |
333 | th {
334 | text-align: left;
335 | padding-right: 5px;
336 | }
337 |
338 | table.citation {
339 | border-left: solid 1px gray;
340 | margin-left: 1px;
341 | }
342 |
343 | table.citation td {
344 | border-bottom: none;
345 | }
346 |
347 | /* -- other body styles ----------------------------------------------------- */
348 |
349 | ol.arabic {
350 | list-style: decimal;
351 | }
352 |
353 | ol.loweralpha {
354 | list-style: lower-alpha;
355 | }
356 |
357 | ol.upperalpha {
358 | list-style: upper-alpha;
359 | }
360 |
361 | ol.lowerroman {
362 | list-style: lower-roman;
363 | }
364 |
365 | ol.upperroman {
366 | list-style: upper-roman;
367 | }
368 |
369 | dl {
370 | margin-bottom: 15px;
371 | }
372 |
373 | dd p {
374 | margin-top: 0px;
375 | }
376 |
377 | dd ul, dd table {
378 | margin-bottom: 10px;
379 | }
380 |
381 | dd {
382 | margin-top: 3px;
383 | margin-bottom: 10px;
384 | margin-left: 30px;
385 | }
386 |
387 | dt:target, .highlighted {
388 | background-color: #fbe54e;
389 | }
390 |
391 | dl.glossary dt {
392 | font-weight: bold;
393 | font-size: 1.1em;
394 | }
395 |
396 | .field-list ul {
397 | margin: 0;
398 | padding-left: 1em;
399 | }
400 |
401 | .field-list p {
402 | margin: 0;
403 | }
404 |
405 | .optional {
406 | font-size: 1.3em;
407 | }
408 |
409 | .versionmodified {
410 | font-style: italic;
411 | }
412 |
413 | .system-message {
414 | background-color: #fda;
415 | padding: 5px;
416 | border: 3px solid red;
417 | }
418 |
419 | .footnote:target {
420 | background-color: #ffa;
421 | }
422 |
423 | .line-block {
424 | display: block;
425 | margin-top: 1em;
426 | margin-bottom: 1em;
427 | }
428 |
429 | .line-block .line-block {
430 | margin-top: 0;
431 | margin-bottom: 0;
432 | margin-left: 1.5em;
433 | }
434 |
435 | .guilabel, .menuselection {
436 | font-family: sans-serif;
437 | }
438 |
439 | .accelerator {
440 | text-decoration: underline;
441 | }
442 |
443 | .classifier {
444 | font-style: oblique;
445 | }
446 |
447 | abbr, acronym {
448 | border-bottom: dotted 1px;
449 | cursor: help;
450 | }
451 |
452 | /* -- code displays --------------------------------------------------------- */
453 |
454 | pre {
455 | overflow: auto;
456 | overflow-y: hidden; /* fixes display issues on Chrome browsers */
457 | }
458 |
459 | td.linenos pre {
460 | padding: 5px 0px;
461 | border: 0;
462 | background-color: transparent;
463 | color: #aaa;
464 | }
465 |
466 | table.highlighttable {
467 | margin-left: 0.5em;
468 | }
469 |
470 | table.highlighttable td {
471 | padding: 0 0.5em 0 0.5em;
472 | }
473 |
474 | tt.descname {
475 | background-color: transparent;
476 | font-weight: bold;
477 | font-size: 1.2em;
478 | }
479 |
480 | tt.descclassname {
481 | background-color: transparent;
482 | }
483 |
484 | tt.xref, a tt {
485 | background-color: transparent;
486 | font-weight: bold;
487 | }
488 |
489 | h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
490 | background-color: transparent;
491 | }
492 |
493 | .viewcode-link {
494 | float: right;
495 | }
496 |
497 | .viewcode-back {
498 | float: right;
499 | font-family: sans-serif;
500 | }
501 |
502 | div.viewcode-block:target {
503 | margin: -1px -10px;
504 | padding: 0 10px;
505 | }
506 |
507 | /* -- math display ---------------------------------------------------------- */
508 |
509 | img.math {
510 | vertical-align: middle;
511 | }
512 |
513 | div.body div.math p {
514 | text-align: center;
515 | }
516 |
517 | span.eqno {
518 | float: right;
519 | }
520 |
521 | /* -- printout stylesheet --------------------------------------------------- */
522 |
523 | @media print {
524 | div.document,
525 | div.documentwrapper,
526 | div.bodywrapper {
527 | margin: 0 !important;
528 | width: 100%;
529 | }
530 |
531 | div.sphinxsidebar,
532 | div.related,
533 | div.footer,
534 | #top-link {
535 | display: none;
536 | }
537 | }
--------------------------------------------------------------------------------
/tests/test_settrie.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # coding: utf8
3 | """
4 | Unit tests for module PySetTrie (see settrie.py).
5 |
6 | Author: Márton Miháltz
7 | https://sites.google.com/site/mmihaltz/
8 | """
9 |
10 | import unittest
11 | from settrie import SetTrie, SetTrieMap, SetTrieMultiMap
12 |
13 |
14 | class TestSetTrie(unittest.TestCase):
15 | """
16 | UnitTest for SetTrie class
17 | """
18 |
19 | def setUp(self):
20 | self.t = SetTrie([{1, 3}, {1, 3, 5}, {1, 4}, {1, 2, 4}, {2, 4}, {2, 3, 5}])
21 |
22 | def test_print(self):
23 | expected = """None
24 | 1
25 | 2
26 | 4#
27 | 3#
28 | 5#
29 | 4#
30 | 2
31 | 3
32 | 5#
33 | 4#
34 | """
35 | from io import StringIO
36 | outp = StringIO()
37 | self.t.printtree(stream=outp)
38 | self.assertEqual(outp.getvalue(), expected)
39 |
40 | def test_iter(self):
41 | a = []
42 | for s in self.t:
43 | a.append(s)
44 | self.assertEqual(a, [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}, {2, 3, 5}, {2, 4}])
45 |
46 | def test_iter2(self):
47 | it = iter(self.t)
48 | for s in it:
49 | pass
50 | self.assertRaises(StopIteration, it.__next__)
51 |
52 | def test_iter3(self):
53 | t2 = SetTrie()
54 | it = iter(t2)
55 | self.assertRaises(StopIteration, it.__next__)
56 |
57 | def test_aslist(self):
58 | self.assertEqual(self.t.aslist(), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}, {2, 3, 5}, {2, 4}])
59 |
60 | def test_str(self):
61 | self.assertEqual(str(self.t), "[{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}, {2, 3, 5}, {2, 4}]")
62 |
63 | def test_contains(self):
64 | self.assertTrue(self.t.contains( {1, 3} ))
65 | self.assertFalse(self.t.contains( {1} ))
66 | self.assertTrue(self.t.contains( {1, 3, 5} ))
67 | self.assertFalse(self.t.contains( {1, 3, 5, 7} ))
68 |
69 | def test_in(self):
70 | self.assertTrue({1, 3} in self.t)
71 | self.assertFalse({1} in self.t)
72 | self.assertTrue({1, 3, 5} in self.t)
73 | self.assertFalse({1, 3, 5, 7} in self.t)
74 |
75 | def test_hassuperset(self):
76 | self.assertTrue(self.t.hassuperset({3, 5}))
77 | self.assertFalse(self.t.hassuperset({6}))
78 | self.assertTrue(self.t.hassuperset({1, 2, 4}))
79 | self.assertFalse(self.t.hassuperset({2, 4, 5} ))
80 |
81 | def test_supersets(self):
82 | self.assertEqual(self.t.supersets({3, 5}), [{1, 3, 5}, {2, 3, 5}])
83 | self.assertEqual(self.t.supersets({1, 4}), [{1, 2, 4}, {1, 4}])
84 | self.assertEqual(self.t.supersets({1, 3, 5}), [{1, 3, 5}])
85 | self.assertEqual(self.t.supersets({2}), [{1, 2, 4}, {2, 3, 5}, {2, 4}])
86 | self.assertEqual(self.t.supersets({1}), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}])
87 | self.assertEqual(self.t.supersets({1, 2, 5}), [])
88 | self.assertEqual(self.t.supersets({1, 2, 4, 5}), [])
89 | self.assertEqual(self.t.supersets({6}), [])
90 |
91 | def test_hassubset(self):
92 | self.assertTrue(self.t.hassubset({1, 2, 3}))
93 | self.assertTrue(self.t.hassubset({2, 3, 4, 5}))
94 | self.assertTrue(self.t.hassubset({1, 4}))
95 | self.assertTrue(self.t.hassubset({2, 3, 5}))
96 | self.assertFalse(self.t.hassubset({3, 4, 5}))
97 | self.assertFalse(self.t.hassubset({6, 7, 8, 9, 1000}))
98 |
99 | def test_subsets(self):
100 | self.assertEqual(self.t.subsets({1, 2, 4, 11}), [{1, 2, 4}, {1, 4}, {2, 4}])
101 | self.assertEqual(self.t.subsets({1, 2, 4}), [{1, 2, 4}, {1, 4}, {2, 4}])
102 | self.assertEqual(self.t.subsets({1, 2}), [])
103 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}, {2, 3, 5}, {2, 4}])
104 | self.assertEqual(self.t.subsets({0, 1, 3, 5}), [{1, 3}, {1, 3, 5}])
105 | self.assertEqual(self.t.subsets({1, 2, 5}), [])
106 | self.assertEqual(self.t.subsets({1, 4}), [{1, 4}]) # :)
107 | self.assertEqual(self.t.subsets({1, 3, 5}), [{1, 3}, {1, 3, 5}])
108 | self.assertEqual(self.t.subsets({1, 3, 5, 111}), [{1, 3}, {1, 3, 5}])
109 | self.assertEqual(self.t.subsets({1, 4, 8}), [{1, 4}])
110 | self.assertEqual(self.t.subsets({2, 3, 4, 5}), [{2, 3, 5}, {2, 4}])
111 | self.assertEqual(self.t.subsets({2, 3, 5, 6}), [{2, 3, 5}])
112 |
113 |
114 | class TestSetTrieMap(unittest.TestCase):
115 | """
116 | UnitTest for SetTrieMap class
117 | """
118 |
119 | def setUp(self):
120 | self.t = SetTrieMap([({1, 3}, 'A'), ({1, 3, 5}, 'B'), ({1, 4}, 'C'),
121 | ({1, 2, 4}, 'D'), ({2, 4}, 'E'), ({2, 3, 5}, 'F')])
122 | #self.t.printtree()
123 |
124 | def test_print(self):
125 | expected = """None
126 | 1
127 | 2
128 | 4: 'D'
129 | 3: 'A'
130 | 5: 'B'
131 | 4: 'C'
132 | 2
133 | 3
134 | 5: 'F'
135 | 4: 'E'
136 | """
137 | from io import StringIO
138 | outp = StringIO()
139 | self.t.printtree(stream=outp)
140 | self.assertEqual(outp.getvalue(), expected)
141 |
142 | def test_contains(self):
143 | self.assertTrue(self.t.contains( {1, 3} ))
144 | self.assertFalse(self.t.contains( {1} ))
145 | self.assertTrue(self.t.contains( {1, 3, 5} ))
146 | self.assertFalse(self.t.contains( {1, 3, 5, 7} ))
147 |
148 | def test_in(self):
149 | self.assertTrue({1, 3} in self.t)
150 | self.assertFalse({1} in self.t)
151 | self.assertTrue({1, 3, 5} in self.t)
152 | self.assertFalse({1, 3, 5, 7} in self.t)
153 |
154 | def test_get(self):
155 | self.assertEqual(self.t.get({1, 3}), 'A')
156 | self.assertEqual(self.t.get({1, 3, 5}), 'B')
157 | self.assertEqual(self.t.get({1, 4}), 'C')
158 | self.assertEqual(self.t.get({1, 2, 4}), 'D')
159 | self.assertEqual(self.t.get({2, 4}), 'E')
160 | self.assertEqual(self.t.get({2, 3, 5}), 'F')
161 | self.assertEqual(self.t.get({1, 2, 3}), None)
162 | self.assertEqual(self.t.get({100, 101, 102}, 0xDEADBEEF), 0xDEADBEEF)
163 | self.assertEqual(self.t.get({}), None)
164 |
165 | def test_assign(self):
166 | self.assertEqual(self.t.get({1, 3}), 'A')
167 | self.t.assign({1, 3}, 'AAA')
168 | self.assertEqual(self.t.get({1, 3}), 'AAA')
169 | self.assertEqual(self.t.get({100, 200}), None)
170 | self.t.assign({100, 200}, 'FOO')
171 | self.assertEqual(self.t.get({100, 200}), 'FOO')
172 | self.setUp()
173 |
174 | def test_hassuperset(self):
175 | self.assertTrue(self.t.hassuperset({3, 5}))
176 | self.assertFalse(self.t.hassuperset({6}))
177 | self.assertTrue(self.t.hassuperset({1, 2, 4}))
178 | self.assertFalse(self.t.hassuperset({2, 4, 5} ))
179 |
180 | def test_supersets(self):
181 | self.assertEqual(self.t.supersets({3, 5}), [({1, 3, 5}, 'B'), ({2, 3, 5}, 'F')])
182 | self.assertEqual(self.t.supersets({1}), [({1, 2, 4}, 'D'), ({1, 3}, 'A'), ({1, 3, 5}, 'B'), ({1, 4}, 'C')])
183 | self.assertEqual(self.t.supersets({1, 2, 5}), [])
184 | self.assertEqual(self.t.supersets({3, 5}, mode='keys'), [{1, 3, 5}, {2, 3, 5}])
185 | self.assertEqual(self.t.supersets({1}, mode='keys'), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}])
186 | self.assertEqual(self.t.supersets({1, 2, 5}, mode='keys'), [])
187 | self.assertEqual(self.t.supersets({3, 5}, mode='values'), ['B', 'F'])
188 | self.assertEqual(self.t.supersets({1}, mode='values'), ['D', 'A', 'B', 'C'])
189 | self.assertEqual(self.t.supersets({1, 2, 5}, mode='values'), [])
190 |
191 | def test_hassubset(self):
192 | self.assertTrue(self.t.hassubset({1, 2, 3}))
193 | self.assertTrue(self.t.hassubset({2, 3, 4, 5}))
194 | self.assertTrue(self.t.hassubset({1, 4}))
195 | self.assertTrue(self.t.hassubset({2, 3, 5}))
196 | self.assertFalse(self.t.hassubset({3, 4, 5}))
197 | self.assertFalse(self.t.hassubset({6, 7, 8, 9, 1000}))
198 |
199 | def test_subsets(self):
200 | self.assertEqual(self.t.subsets({1, 2, 4, 11}), [({1, 2, 4}, 'D'), ({1, 4}, 'C'), ({2, 4}, 'E')])
201 | self.assertEqual(self.t.subsets({1, 2, 4}), [({1, 2, 4}, 'D'), ({1, 4}, 'C'), ({2, 4}, 'E')])
202 | self.assertEqual(self.t.subsets({1, 2}), [])
203 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}), [({1, 2, 4}, 'D'),
204 | ({1, 3}, 'A'),
205 | ({1, 3, 5}, 'B'),
206 | ({1, 4}, 'C'),
207 | ({2, 3, 5}, 'F'),
208 | ({2, 4}, 'E')] )
209 | self.assertEqual(self.t.subsets({0, 1, 3, 5}), [({1, 3}, 'A'), ({1, 3, 5}, 'B')])
210 | self.assertEqual(self.t.subsets({1, 2, 5}), [])
211 | self.assertEqual(self.t.subsets({1, 2, 4, 11}, mode='keys'), [{1, 2, 4}, {1, 4}, {2, 4}])
212 | self.assertEqual(self.t.subsets({1, 2, 4}, mode='keys'), [{1, 2, 4}, {1, 4}, {2, 4}])
213 | self.assertEqual(self.t.subsets({1, 2}, mode='keys'), [])
214 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}, mode='keys'), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}, {2, 3, 5}, {2, 4}])
215 | self.assertEqual(self.t.subsets({0, 1, 3, 5}, mode='keys'), [{1, 3}, {1, 3, 5}])
216 | self.assertEqual(self.t.subsets({1, 2, 5}, mode='keys'), [])
217 | self.assertEqual(self.t.subsets({1, 2, 4, 11}, mode='values'), ['D', 'C', 'E'])
218 | self.assertEqual(self.t.subsets({1, 2, 4}, mode='values'), ['D', 'C', 'E'])
219 | self.assertEqual(self.t.subsets({1, 2}, mode='values'), [])
220 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}, mode='values'), ['D', 'A', 'B', 'C', 'F', 'E'])
221 | self.assertEqual(self.t.subsets({0, 1, 3, 5}, mode='values'), ['A', 'B'])
222 | self.assertEqual(self.t.subsets({1, 2, 5}, mode='values'), [])
223 | self.assertEqual(self.t.subsets({1, 4}), [({1, 4}, 'C')])
224 | self.assertEqual(self.t.subsets({1, 3, 5}), [({1, 3}, 'A'), ({1, 3, 5}, 'B')])
225 | self.assertEqual(self.t.subsets({1, 3, 5, 111}), [({1, 3}, 'A'), ({1, 3, 5}, 'B')])
226 | self.assertEqual(self.t.subsets({1, 4, 8}), [({1, 4}, 'C')])
227 | self.assertEqual(self.t.subsets({2, 3, 4, 5}), [({2, 3, 5}, 'F'), ({2, 4}, 'E')])
228 | self.assertEqual(self.t.subsets({2, 3, 5, 6}), [({2, 3, 5}, 'F')])
229 |
230 |
231 |
232 | def test_iters(self):
233 | self.assertEqual(self.t.aslist(),
234 | [({1, 2, 4}, 'D'), ({1, 3}, 'A'), ({1, 3, 5}, 'B'), ({1, 4}, 'C'), ({2, 3, 5}, 'F'), ({2, 4}, 'E')] )
235 | self.assertEqual(list(self.t.keys()), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}, {2, 3, 5}, {2, 4}] )
236 | self.assertEqual(list(self.t.values()), ['D', 'A', 'B', 'C', 'F', 'E'] )
237 | self.assertEqual(list(self.t.__iter__()), list(self.t.keys()))
238 |
239 |
240 | class TestSetTrieMultiMap(unittest.TestCase):
241 | """
242 | UnitTest for SetTrieMultiMap class
243 | """
244 |
245 | def setUp(self):
246 | self.t = SetTrieMultiMap([({1, 3}, 'A'), ({1, 3}, 'AA'), ({1, 3, 5}, 'B'), ({1, 4}, 'C'), ({1, 4}, 'CC'),
247 | ({1, 2, 4}, 'D'), ({1, 2, 4}, 'DD'), ({2, 4}, 'E'), ({2, 3, 5}, 'F'),
248 | ({2, 3, 5}, 'FF'), ({2, 3, 5}, 'FFF')])
249 |
250 | def test_aslist(self):
251 | self.assertEqual(self.t.aslist(),
252 | [({1, 2, 4}, 'D'), ({1, 2, 4}, 'DD'), ({1, 3}, 'A'), ({1, 3}, 'AA'), ({1, 3, 5}, 'B'),
253 | ({1, 4}, 'C'), ({1, 4}, 'CC'), ({2, 3, 5}, 'F'), ({2, 3, 5}, 'FF'), ({2, 3, 5}, 'FFF'), ({2, 4}, 'E')] )
254 |
255 | def test_assign_returned_value(self):
256 | x = SetTrieMultiMap()
257 | self.assertEqual(x.assign({1, 3}, 'A'), 1)
258 | self.assertEqual(x.assign({1, 3}, 'AA'), 2)
259 | self.assertEqual(x.assign({1, 3}, 'A'), 3)
260 | self.assertEqual(x.assign({2, 4, 5}, 'Y'), 1)
261 |
262 | def test_count(self):
263 | self.assertEqual(self.t.count({1, 3}), 2)
264 | self.assertEqual(self.t.count({1, 3, 5}), 1)
265 | self.assertEqual(self.t.count({1, 3, 4}), 0)
266 | self.assertEqual(self.t.count({111, 222}), 0)
267 | self.assertEqual(self.t.count({2, 3, 5}), 3)
268 |
269 | def test_iterget(self):
270 | self.assertEqual(list(self.t.iterget({1, 3})), ['A', 'AA'])
271 | self.assertEqual(list(self.t.iterget({1, 3, 4})), [])
272 |
273 | def test_get(self):
274 | self.assertEqual(self.t.get({1, 3}), ['A', 'AA'])
275 | self.assertEqual(self.t.get({1, 2, 4}), ['D', 'DD'])
276 | self.assertEqual(self.t.get({1, 3, 5}), ['B'])
277 | self.assertEqual(self.t.get({2, 3, 5}), ['F', 'FF', 'FFF'])
278 | self.assertEqual(self.t.get({2, 4}), ['E'])
279 | self.assertEqual(self.t.get({1, 3, 4}), None)
280 | self.assertEqual(self.t.get({44}, []), [])
281 |
282 | def test_hassuperset(self):
283 | self.assertTrue(self.t.hassuperset({3, 5}))
284 | self.assertFalse(self.t.hassuperset({6}))
285 | self.assertTrue(self.t.hassuperset({1, 2, 4}))
286 | self.assertFalse(self.t.hassuperset({2, 4, 5} ))
287 |
288 | def test_supersets(self):
289 | self.assertEqual(self.t.supersets({3, 5}), [({1, 3, 5}, 'B'), ({2, 3, 5}, 'F'), ({2, 3, 5}, 'FF'), ({2, 3, 5}, 'FFF')])
290 | self.assertEqual(self.t.supersets({3, 5}, mode='values'), ['B', 'F', 'FF', 'FFF'])
291 | self.assertEqual(self.t.supersets({3, 5}, mode='keys'), [{1, 3, 5}, {2, 3, 5}])
292 | self.assertEqual(self.t.supersets({1}), [({1, 2, 4}, 'D'), ({1, 2, 4}, 'DD'), ({1, 3}, 'A'),
293 | ({1, 3}, 'AA'), ({1, 3, 5}, 'B'), ({1, 4}, 'C'), ({1, 4}, 'CC')] )
294 | self.assertEqual(self.t.supersets({1}, mode='keys'), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}])
295 | self.assertEqual(self.t.supersets({1}, mode='values'), ['D', 'DD', 'A', 'AA', 'B', 'C', 'CC'])
296 | self.assertEqual(self.t.supersets({1, 2, 5}), [])
297 | self.assertEqual(self.t.supersets({1, 2, 5}, mode='keys'), [])
298 | self.assertEqual(self.t.supersets({1, 2, 5}, mode='values'), [])
299 |
300 | def test_hassubset(self):
301 | self.assertTrue(self.t.hassubset({1, 2, 3}))
302 | self.assertTrue(self.t.hassubset({2, 3, 4, 5}))
303 | self.assertTrue(self.t.hassubset({1, 4}))
304 | self.assertTrue(self.t.hassubset({2, 3, 5}))
305 | self.assertFalse(self.t.hassubset({3, 4, 5}))
306 | self.assertFalse(self.t.hassubset({6, 7, 8, 9, 1000}))
307 |
308 | def test_subsets(self):
309 | self.assertEqual(self.t.subsets({1, 2, 4, 11}), [({1, 2, 4}, 'D'), ({1, 2, 4}, 'DD'), ({1, 4}, 'C'),
310 | ({1, 4}, 'CC'), ({2, 4}, 'E')] )
311 | self.assertEqual(self.t.subsets({1, 2, 4, 11}, mode='keys'), [{1, 2, 4}, {1, 4}, {2, 4}])
312 | self.assertEqual(self.t.subsets({1, 2, 4, 11}, mode='values'), ['D', 'DD', 'C', 'CC', 'E'])
313 | self.assertEqual(self.t.subsets({1, 2, 4}), [({1, 2, 4}, 'D'), ({1, 2, 4}, 'DD'), ({1, 4}, 'C'), ({1, 4}, 'CC'),
314 | ({2, 4}, 'E')])
315 | self.assertEqual(self.t.subsets({1, 2, 4}, mode='keys'), [{1, 2, 4}, {1, 4}, {2, 4}])
316 | self.assertEqual(self.t.subsets({1, 2, 4}, mode='values'), ['D', 'DD', 'C', 'CC', 'E'])
317 | self.assertEqual(self.t.subsets({1, 2}), [])
318 | self.assertEqual(self.t.subsets({1, 2}, mode='keys'), [])
319 | self.assertEqual(self.t.subsets({1, 2}, mode='values'), [])
320 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}),
321 | [({1, 2, 4}, 'D'), ({1, 2, 4}, 'DD'), ({1, 3}, 'A'), ({1, 3}, 'AA'), ({1, 3, 5}, 'B'),
322 | ({1, 4}, 'C'), ({1, 4}, 'CC'), ({2, 3, 5}, 'F'), ({2, 3, 5}, 'FF'), ({2, 3, 5}, 'FFF'), ({2, 4}, 'E')] )
323 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}), self.t.aslist())
324 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}, mode='keys'), list(self.t.keys()))
325 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}, mode='keys'), [{1, 2, 4}, {1, 3}, {1, 3, 5}, {1, 4}, {2, 3, 5}, {2, 4}])
326 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}, mode='values'),
327 | ['D', 'DD', 'A', 'AA', 'B', 'C', 'CC', 'F', 'FF', 'FFF', 'E'])
328 | self.assertEqual(self.t.subsets({1, 2, 3, 4, 5}, mode='values'), list(self.t.values()))
329 | self.assertEqual(self.t.subsets({0, 1, 3, 5}), [({1, 3}, 'A'), ({1, 3}, 'AA'), ({1, 3, 5}, 'B')])
330 | self.assertEqual(self.t.subsets({0, 1, 3, 5}, mode='keys'), [{1, 3}, {1, 3, 5}])
331 | self.assertEqual(self.t.subsets({0, 1, 3, 5}, mode='values'), ['A', 'AA', 'B'])
332 | self.assertEqual(self.t.subsets({1, 2, 5}), [])
333 | self.assertEqual(self.t.subsets({1, 2, 5}, mode='keys'), [])
334 | self.assertEqual(self.t.subsets({1, 2, 5}, mode='values'), [])
335 | self.assertEqual(self.t.subsets({1, 4}), [({1, 4}, 'C'), ({1, 4}, 'CC')])
336 | self.assertEqual(self.t.subsets({1, 3, 5}), [({1, 3}, 'A'), ({1, 3}, 'AA'), ({1, 3, 5}, 'B')])
337 | self.assertEqual(self.t.subsets({1, 3, 5, 111}), [({1, 3}, 'A'), ({1, 3}, 'AA'), ({1, 3, 5}, 'B')])
338 | self.assertEqual(self.t.subsets({1, 4, 8}), [({1, 4}, 'C'), ({1, 4}, 'CC')])
339 | self.assertEqual(self.t.subsets({2, 3, 4, 5}), [({2, 3, 5}, 'F'), ({2, 3, 5}, 'FF'), ({2, 3, 5}, 'FFF'), ({2, 4}, 'E')])
340 | self.assertEqual(self.t.subsets({2, 3, 5, 6}), [({2, 3, 5}, 'F'), ({2, 3, 5}, 'FF'), ({2, 3, 5}, 'FFF')])
341 |
342 | # - - - - - - -
343 |
344 | # If module is executed from command line, perform tests:
345 | if __name__ == "__main__":
346 | unittest.main(verbosity=2)
347 |
--------------------------------------------------------------------------------
/docs/build/html/_static/searchtools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * searchtools.js_t
3 | * ~~~~~~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilties for the full-text search.
6 | *
7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 |
13 | /**
14 | * Porter Stemmer
15 | */
16 | var Stemmer = function() {
17 |
18 | var step2list = {
19 | ational: 'ate',
20 | tional: 'tion',
21 | enci: 'ence',
22 | anci: 'ance',
23 | izer: 'ize',
24 | bli: 'ble',
25 | alli: 'al',
26 | entli: 'ent',
27 | eli: 'e',
28 | ousli: 'ous',
29 | ization: 'ize',
30 | ation: 'ate',
31 | ator: 'ate',
32 | alism: 'al',
33 | iveness: 'ive',
34 | fulness: 'ful',
35 | ousness: 'ous',
36 | aliti: 'al',
37 | iviti: 'ive',
38 | biliti: 'ble',
39 | logi: 'log'
40 | };
41 |
42 | var step3list = {
43 | icate: 'ic',
44 | ative: '',
45 | alize: 'al',
46 | iciti: 'ic',
47 | ical: 'ic',
48 | ful: '',
49 | ness: ''
50 | };
51 |
52 | var c = "[^aeiou]"; // consonant
53 | var v = "[aeiouy]"; // vowel
54 | var C = c + "[^aeiouy]*"; // consonant sequence
55 | var V = v + "[aeiou]*"; // vowel sequence
56 |
57 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
58 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
59 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
60 | var s_v = "^(" + C + ")?" + v; // vowel in stem
61 |
62 | this.stemWord = function (w) {
63 | var stem;
64 | var suffix;
65 | var firstch;
66 | var origword = w;
67 |
68 | if (w.length < 3)
69 | return w;
70 |
71 | var re;
72 | var re2;
73 | var re3;
74 | var re4;
75 |
76 | firstch = w.substr(0,1);
77 | if (firstch == "y")
78 | w = firstch.toUpperCase() + w.substr(1);
79 |
80 | // Step 1a
81 | re = /^(.+?)(ss|i)es$/;
82 | re2 = /^(.+?)([^s])s$/;
83 |
84 | if (re.test(w))
85 | w = w.replace(re,"$1$2");
86 | else if (re2.test(w))
87 | w = w.replace(re2,"$1$2");
88 |
89 | // Step 1b
90 | re = /^(.+?)eed$/;
91 | re2 = /^(.+?)(ed|ing)$/;
92 | if (re.test(w)) {
93 | var fp = re.exec(w);
94 | re = new RegExp(mgr0);
95 | if (re.test(fp[1])) {
96 | re = /.$/;
97 | w = w.replace(re,"");
98 | }
99 | }
100 | else if (re2.test(w)) {
101 | var fp = re2.exec(w);
102 | stem = fp[1];
103 | re2 = new RegExp(s_v);
104 | if (re2.test(stem)) {
105 | w = stem;
106 | re2 = /(at|bl|iz)$/;
107 | re3 = new RegExp("([^aeiouylsz])\\1$");
108 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
109 | if (re2.test(w))
110 | w = w + "e";
111 | else if (re3.test(w)) {
112 | re = /.$/;
113 | w = w.replace(re,"");
114 | }
115 | else if (re4.test(w))
116 | w = w + "e";
117 | }
118 | }
119 |
120 | // Step 1c
121 | re = /^(.+?)y$/;
122 | if (re.test(w)) {
123 | var fp = re.exec(w);
124 | stem = fp[1];
125 | re = new RegExp(s_v);
126 | if (re.test(stem))
127 | w = stem + "i";
128 | }
129 |
130 | // Step 2
131 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
132 | if (re.test(w)) {
133 | var fp = re.exec(w);
134 | stem = fp[1];
135 | suffix = fp[2];
136 | re = new RegExp(mgr0);
137 | if (re.test(stem))
138 | w = stem + step2list[suffix];
139 | }
140 |
141 | // Step 3
142 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
143 | if (re.test(w)) {
144 | var fp = re.exec(w);
145 | stem = fp[1];
146 | suffix = fp[2];
147 | re = new RegExp(mgr0);
148 | if (re.test(stem))
149 | w = stem + step3list[suffix];
150 | }
151 |
152 | // Step 4
153 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
154 | re2 = /^(.+?)(s|t)(ion)$/;
155 | if (re.test(w)) {
156 | var fp = re.exec(w);
157 | stem = fp[1];
158 | re = new RegExp(mgr1);
159 | if (re.test(stem))
160 | w = stem;
161 | }
162 | else if (re2.test(w)) {
163 | var fp = re2.exec(w);
164 | stem = fp[1] + fp[2];
165 | re2 = new RegExp(mgr1);
166 | if (re2.test(stem))
167 | w = stem;
168 | }
169 |
170 | // Step 5
171 | re = /^(.+?)e$/;
172 | if (re.test(w)) {
173 | var fp = re.exec(w);
174 | stem = fp[1];
175 | re = new RegExp(mgr1);
176 | re2 = new RegExp(meq1);
177 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
178 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
179 | w = stem;
180 | }
181 | re = /ll$/;
182 | re2 = new RegExp(mgr1);
183 | if (re.test(w) && re2.test(w)) {
184 | re = /.$/;
185 | w = w.replace(re,"");
186 | }
187 |
188 | // and turn initial Y back to y
189 | if (firstch == "y")
190 | w = firstch.toLowerCase() + w.substr(1);
191 | return w;
192 | }
193 | }
194 |
195 |
196 |
197 | /**
198 | * Simple result scoring code.
199 | */
200 | var Scorer = {
201 | // Implement the following function to further tweak the score for each result
202 | // The function takes a result array [filename, title, anchor, descr, score]
203 | // and returns the new score.
204 | /*
205 | score: function(result) {
206 | return result[4];
207 | },
208 | */
209 |
210 | // query matches the full name of an object
211 | objNameMatch: 11,
212 | // or matches in the last dotted part of the object name
213 | objPartialMatch: 6,
214 | // Additive scores depending on the priority of the object
215 | objPrio: {0: 15, // used to be importantResults
216 | 1: 5, // used to be objectResults
217 | 2: -5}, // used to be unimportantResults
218 | // Used when the priority is not in the mapping.
219 | objPrioDefault: 0,
220 |
221 | // query found in title
222 | title: 15,
223 | // query found in terms
224 | term: 5
225 | };
226 |
227 |
228 | /**
229 | * Search Module
230 | */
231 | var Search = {
232 |
233 | _index : null,
234 | _queued_query : null,
235 | _pulse_status : -1,
236 |
237 | init : function() {
238 | var params = $.getQueryParameters();
239 | if (params.q) {
240 | var query = params.q[0];
241 | $('input[name="q"]')[0].value = query;
242 | this.performSearch(query);
243 | }
244 | },
245 |
246 | loadIndex : function(url) {
247 | $.ajax({type: "GET", url: url, data: null,
248 | dataType: "script", cache: true,
249 | complete: function(jqxhr, textstatus) {
250 | if (textstatus != "success") {
251 | document.getElementById("searchindexloader").src = url;
252 | }
253 | }});
254 | },
255 |
256 | setIndex : function(index) {
257 | var q;
258 | this._index = index;
259 | if ((q = this._queued_query) !== null) {
260 | this._queued_query = null;
261 | Search.query(q);
262 | }
263 | },
264 |
265 | hasIndex : function() {
266 | return this._index !== null;
267 | },
268 |
269 | deferQuery : function(query) {
270 | this._queued_query = query;
271 | },
272 |
273 | stopPulse : function() {
274 | this._pulse_status = 0;
275 | },
276 |
277 | startPulse : function() {
278 | if (this._pulse_status >= 0)
279 | return;
280 | function pulse() {
281 | var i;
282 | Search._pulse_status = (Search._pulse_status + 1) % 4;
283 | var dotString = '';
284 | for (i = 0; i < Search._pulse_status; i++)
285 | dotString += '.';
286 | Search.dots.text(dotString);
287 | if (Search._pulse_status > -1)
288 | window.setTimeout(pulse, 500);
289 | }
290 | pulse();
291 | },
292 |
293 | /**
294 | * perform a search for something (or wait until index is loaded)
295 | */
296 | performSearch : function(query) {
297 | // create the required interface elements
298 | this.out = $('#search-results');
299 | this.title = $('' + _('Searching') + ' ').appendTo(this.out);
300 | this.dots = $(' ').appendTo(this.title);
301 | this.status = $('
').appendTo(this.out);
302 | this.output = $('').appendTo(this.out);
303 |
304 | $('#search-progress').text(_('Preparing search...'));
305 | this.startPulse();
306 |
307 | // index already loaded, the browser was quick!
308 | if (this.hasIndex())
309 | this.query(query);
310 | else
311 | this.deferQuery(query);
312 | },
313 |
314 | /**
315 | * execute search (requires search index to be loaded)
316 | */
317 | query : function(query) {
318 | var i;
319 | var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
320 |
321 | // stem the searchterms and add them to the correct list
322 | var stemmer = new Stemmer();
323 | var searchterms = [];
324 | var excluded = [];
325 | var hlterms = [];
326 | var tmp = query.split(/\s+/);
327 | var objectterms = [];
328 | for (i = 0; i < tmp.length; i++) {
329 | if (tmp[i] !== "") {
330 | objectterms.push(tmp[i].toLowerCase());
331 | }
332 |
333 | if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
334 | tmp[i] === "") {
335 | // skip this "word"
336 | continue;
337 | }
338 | // stem the word
339 | var word = stemmer.stemWord(tmp[i].toLowerCase());
340 | var toAppend;
341 | // select the correct list
342 | if (word[0] == '-') {
343 | toAppend = excluded;
344 | word = word.substr(1);
345 | }
346 | else {
347 | toAppend = searchterms;
348 | hlterms.push(tmp[i].toLowerCase());
349 | }
350 | // only add if not already in the list
351 | if (!$u.contains(toAppend, word))
352 | toAppend.push(word);
353 | }
354 | var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
355 |
356 | // console.debug('SEARCH: searching for:');
357 | // console.info('required: ', searchterms);
358 | // console.info('excluded: ', excluded);
359 |
360 | // prepare search
361 | var terms = this._index.terms;
362 | var titleterms = this._index.titleterms;
363 |
364 | // array of [filename, title, anchor, descr, score]
365 | var results = [];
366 | $('#search-progress').empty();
367 |
368 | // lookup as object
369 | for (i = 0; i < objectterms.length; i++) {
370 | var others = [].concat(objectterms.slice(0, i),
371 | objectterms.slice(i+1, objectterms.length));
372 | results = results.concat(this.performObjectSearch(objectterms[i], others));
373 | }
374 |
375 | // lookup as search terms in fulltext
376 | results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
377 | .concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
378 |
379 | // let the scorer override scores with a custom scoring function
380 | if (Scorer.score) {
381 | for (i = 0; i < results.length; i++)
382 | results[i][4] = Scorer.score(results[i]);
383 | }
384 |
385 | // now sort the results by score (in opposite order of appearance, since the
386 | // display function below uses pop() to retrieve items) and then
387 | // alphabetically
388 | results.sort(function(a, b) {
389 | var left = a[4];
390 | var right = b[4];
391 | if (left > right) {
392 | return 1;
393 | } else if (left < right) {
394 | return -1;
395 | } else {
396 | // same score: sort alphabetically
397 | left = a[1].toLowerCase();
398 | right = b[1].toLowerCase();
399 | return (left > right) ? -1 : ((left < right) ? 1 : 0);
400 | }
401 | });
402 |
403 | // for debugging
404 | //Search.lastresults = results.slice(); // a copy
405 | //console.info('search results:', Search.lastresults);
406 |
407 | // print the results
408 | var resultCount = results.length;
409 | function displayNextItem() {
410 | // results left, load the summary and display it
411 | if (results.length) {
412 | var item = results.pop();
413 | var listItem = $(' ');
414 | if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
415 | // dirhtml builder
416 | var dirname = item[0] + '/';
417 | if (dirname.match(/\/index\/$/)) {
418 | dirname = dirname.substring(0, dirname.length-6);
419 | } else if (dirname == 'index/') {
420 | dirname = '';
421 | }
422 | listItem.append($(' ').attr('href',
423 | DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
424 | highlightstring + item[2]).html(item[1]));
425 | } else {
426 | // normal html builders
427 | listItem.append($(' ').attr('href',
428 | item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
429 | highlightstring + item[2]).html(item[1]));
430 | }
431 | if (item[3]) {
432 | listItem.append($(' (' + item[3] + ') '));
433 | Search.output.append(listItem);
434 | listItem.slideDown(5, function() {
435 | displayNextItem();
436 | });
437 | } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
438 | $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
439 | dataType: "text",
440 | complete: function(jqxhr, textstatus) {
441 | var data = jqxhr.responseText;
442 | if (data !== '') {
443 | listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
444 | }
445 | Search.output.append(listItem);
446 | listItem.slideDown(5, function() {
447 | displayNextItem();
448 | });
449 | }});
450 | } else {
451 | // no source available, just display title
452 | Search.output.append(listItem);
453 | listItem.slideDown(5, function() {
454 | displayNextItem();
455 | });
456 | }
457 | }
458 | // search finished, update title and status message
459 | else {
460 | Search.stopPulse();
461 | Search.title.text(_('Search Results'));
462 | if (!resultCount)
463 | Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
464 | else
465 | Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
466 | Search.status.fadeIn(500);
467 | }
468 | }
469 | displayNextItem();
470 | },
471 |
472 | /**
473 | * search for object names
474 | */
475 | performObjectSearch : function(object, otherterms) {
476 | var filenames = this._index.filenames;
477 | var objects = this._index.objects;
478 | var objnames = this._index.objnames;
479 | var titles = this._index.titles;
480 |
481 | var i;
482 | var results = [];
483 |
484 | for (var prefix in objects) {
485 | for (var name in objects[prefix]) {
486 | var fullname = (prefix ? prefix + '.' : '') + name;
487 | if (fullname.toLowerCase().indexOf(object) > -1) {
488 | var score = 0;
489 | var parts = fullname.split('.');
490 | // check for different match types: exact matches of full name or
491 | // "last name" (i.e. last dotted part)
492 | if (fullname == object || parts[parts.length - 1] == object) {
493 | score += Scorer.objNameMatch;
494 | // matches in last name
495 | } else if (parts[parts.length - 1].indexOf(object) > -1) {
496 | score += Scorer.objPartialMatch;
497 | }
498 | var match = objects[prefix][name];
499 | var objname = objnames[match[1]][2];
500 | var title = titles[match[0]];
501 | // If more than one term searched for, we require other words to be
502 | // found in the name/title/description
503 | if (otherterms.length > 0) {
504 | var haystack = (prefix + ' ' + name + ' ' +
505 | objname + ' ' + title).toLowerCase();
506 | var allfound = true;
507 | for (i = 0; i < otherterms.length; i++) {
508 | if (haystack.indexOf(otherterms[i]) == -1) {
509 | allfound = false;
510 | break;
511 | }
512 | }
513 | if (!allfound) {
514 | continue;
515 | }
516 | }
517 | var descr = objname + _(', in ') + title;
518 |
519 | var anchor = match[3];
520 | if (anchor === '')
521 | anchor = fullname;
522 | else if (anchor == '-')
523 | anchor = objnames[match[1]][1] + '-' + fullname;
524 | // add custom score for some objects according to scorer
525 | if (Scorer.objPrio.hasOwnProperty(match[2])) {
526 | score += Scorer.objPrio[match[2]];
527 | } else {
528 | score += Scorer.objPrioDefault;
529 | }
530 | results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
531 | }
532 | }
533 | }
534 |
535 | return results;
536 | },
537 |
538 | /**
539 | * search for full-text terms in the index
540 | */
541 | performTermsSearch : function(searchterms, excluded, terms, score) {
542 | var filenames = this._index.filenames;
543 | var titles = this._index.titles;
544 |
545 | var i, j, file, files;
546 | var fileMap = {};
547 | var results = [];
548 |
549 | // perform the search on the required terms
550 | for (i = 0; i < searchterms.length; i++) {
551 | var word = searchterms[i];
552 | // no match but word was a required one
553 | if ((files = terms[word]) === undefined)
554 | break;
555 | if (files.length === undefined) {
556 | files = [files];
557 | }
558 | // create the mapping
559 | for (j = 0; j < files.length; j++) {
560 | file = files[j];
561 | if (file in fileMap)
562 | fileMap[file].push(word);
563 | else
564 | fileMap[file] = [word];
565 | }
566 | }
567 |
568 | // now check if the files don't contain excluded terms
569 | for (file in fileMap) {
570 | var valid = true;
571 |
572 | // check if all requirements are matched
573 | if (fileMap[file].length != searchterms.length)
574 | continue;
575 |
576 | // ensure that none of the excluded terms is in the search result
577 | for (i = 0; i < excluded.length; i++) {
578 | if (terms[excluded[i]] == file ||
579 | $u.contains(terms[excluded[i]] || [], file)) {
580 | valid = false;
581 | break;
582 | }
583 | }
584 |
585 | // if we have still a valid result we can add it to the result list
586 | if (valid) {
587 | results.push([filenames[file], titles[file], '', null, score]);
588 | }
589 | }
590 | return results;
591 | },
592 |
593 | /**
594 | * helper function to return a node containing the
595 | * search summary for a given text. keywords is a list
596 | * of stemmed words, hlwords is the list of normal, unstemmed
597 | * words. the first one is used to find the occurance, the
598 | * latter for highlighting it.
599 | */
600 | makeSearchSummary : function(text, keywords, hlwords) {
601 | var textLower = text.toLowerCase();
602 | var start = 0;
603 | $.each(keywords, function() {
604 | var i = textLower.indexOf(this.toLowerCase());
605 | if (i > -1)
606 | start = i;
607 | });
608 | start = Math.max(start - 120, 0);
609 | var excerpt = ((start > 0) ? '...' : '') +
610 | $.trim(text.substr(start, 240)) +
611 | ((start + 240 - text.length) ? '...' : '');
612 | var rv = $('
').text(excerpt);
613 | $.each(hlwords, function() {
614 | rv = rv.highlightText(this, 'highlighted');
615 | });
616 | return rv;
617 | }
618 | };
619 |
620 | $(document).ready(function() {
621 | Search.init();
622 | });
--------------------------------------------------------------------------------
/docs/build/html/_static/websupport.js:
--------------------------------------------------------------------------------
1 | /*
2 | * websupport.js
3 | * ~~~~~~~~~~~~~
4 | *
5 | * sphinx.websupport utilties for all documentation.
6 | *
7 | * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | (function($) {
13 | $.fn.autogrow = function() {
14 | return this.each(function() {
15 | var textarea = this;
16 |
17 | $.fn.autogrow.resize(textarea);
18 |
19 | $(textarea)
20 | .focus(function() {
21 | textarea.interval = setInterval(function() {
22 | $.fn.autogrow.resize(textarea);
23 | }, 500);
24 | })
25 | .blur(function() {
26 | clearInterval(textarea.interval);
27 | });
28 | });
29 | };
30 |
31 | $.fn.autogrow.resize = function(textarea) {
32 | var lineHeight = parseInt($(textarea).css('line-height'), 10);
33 | var lines = textarea.value.split('\n');
34 | var columns = textarea.cols;
35 | var lineCount = 0;
36 | $.each(lines, function() {
37 | lineCount += Math.ceil(this.length / columns) || 1;
38 | });
39 | var height = lineHeight * (lineCount + 1);
40 | $(textarea).css('height', height);
41 | };
42 | })(jQuery);
43 |
44 | (function($) {
45 | var comp, by;
46 |
47 | function init() {
48 | initEvents();
49 | initComparator();
50 | }
51 |
52 | function initEvents() {
53 | $('a.comment-close').live("click", function(event) {
54 | event.preventDefault();
55 | hide($(this).attr('id').substring(2));
56 | });
57 | $('a.vote').live("click", function(event) {
58 | event.preventDefault();
59 | handleVote($(this));
60 | });
61 | $('a.reply').live("click", function(event) {
62 | event.preventDefault();
63 | openReply($(this).attr('id').substring(2));
64 | });
65 | $('a.close-reply').live("click", function(event) {
66 | event.preventDefault();
67 | closeReply($(this).attr('id').substring(2));
68 | });
69 | $('a.sort-option').live("click", function(event) {
70 | event.preventDefault();
71 | handleReSort($(this));
72 | });
73 | $('a.show-proposal').live("click", function(event) {
74 | event.preventDefault();
75 | showProposal($(this).attr('id').substring(2));
76 | });
77 | $('a.hide-proposal').live("click", function(event) {
78 | event.preventDefault();
79 | hideProposal($(this).attr('id').substring(2));
80 | });
81 | $('a.show-propose-change').live("click", function(event) {
82 | event.preventDefault();
83 | showProposeChange($(this).attr('id').substring(2));
84 | });
85 | $('a.hide-propose-change').live("click", function(event) {
86 | event.preventDefault();
87 | hideProposeChange($(this).attr('id').substring(2));
88 | });
89 | $('a.accept-comment').live("click", function(event) {
90 | event.preventDefault();
91 | acceptComment($(this).attr('id').substring(2));
92 | });
93 | $('a.delete-comment').live("click", function(event) {
94 | event.preventDefault();
95 | deleteComment($(this).attr('id').substring(2));
96 | });
97 | $('a.comment-markup').live("click", function(event) {
98 | event.preventDefault();
99 | toggleCommentMarkupBox($(this).attr('id').substring(2));
100 | });
101 | }
102 |
103 | /**
104 | * Set comp, which is a comparator function used for sorting and
105 | * inserting comments into the list.
106 | */
107 | function setComparator() {
108 | // If the first three letters are "asc", sort in ascending order
109 | // and remove the prefix.
110 | if (by.substring(0,3) == 'asc') {
111 | var i = by.substring(3);
112 | comp = function(a, b) { return a[i] - b[i]; };
113 | } else {
114 | // Otherwise sort in descending order.
115 | comp = function(a, b) { return b[by] - a[by]; };
116 | }
117 |
118 | // Reset link styles and format the selected sort option.
119 | $('a.sel').attr('href', '#').removeClass('sel');
120 | $('a.by' + by).removeAttr('href').addClass('sel');
121 | }
122 |
123 | /**
124 | * Create a comp function. If the user has preferences stored in
125 | * the sortBy cookie, use those, otherwise use the default.
126 | */
127 | function initComparator() {
128 | by = 'rating'; // Default to sort by rating.
129 | // If the sortBy cookie is set, use that instead.
130 | if (document.cookie.length > 0) {
131 | var start = document.cookie.indexOf('sortBy=');
132 | if (start != -1) {
133 | start = start + 7;
134 | var end = document.cookie.indexOf(";", start);
135 | if (end == -1) {
136 | end = document.cookie.length;
137 | by = unescape(document.cookie.substring(start, end));
138 | }
139 | }
140 | }
141 | setComparator();
142 | }
143 |
144 | /**
145 | * Show a comment div.
146 | */
147 | function show(id) {
148 | $('#ao' + id).hide();
149 | $('#ah' + id).show();
150 | var context = $.extend({id: id}, opts);
151 | var popup = $(renderTemplate(popupTemplate, context)).hide();
152 | popup.find('textarea[name="proposal"]').hide();
153 | popup.find('a.by' + by).addClass('sel');
154 | var form = popup.find('#cf' + id);
155 | form.submit(function(event) {
156 | event.preventDefault();
157 | addComment(form);
158 | });
159 | $('#s' + id).after(popup);
160 | popup.slideDown('fast', function() {
161 | getComments(id);
162 | });
163 | }
164 |
165 | /**
166 | * Hide a comment div.
167 | */
168 | function hide(id) {
169 | $('#ah' + id).hide();
170 | $('#ao' + id).show();
171 | var div = $('#sc' + id);
172 | div.slideUp('fast', function() {
173 | div.remove();
174 | });
175 | }
176 |
177 | /**
178 | * Perform an ajax request to get comments for a node
179 | * and insert the comments into the comments tree.
180 | */
181 | function getComments(id) {
182 | $.ajax({
183 | type: 'GET',
184 | url: opts.getCommentsURL,
185 | data: {node: id},
186 | success: function(data, textStatus, request) {
187 | var ul = $('#cl' + id);
188 | var speed = 100;
189 | $('#cf' + id)
190 | .find('textarea[name="proposal"]')
191 | .data('source', data.source);
192 |
193 | if (data.comments.length === 0) {
194 | ul.html('No comments yet. ');
195 | ul.data('empty', true);
196 | } else {
197 | // If there are comments, sort them and put them in the list.
198 | var comments = sortComments(data.comments);
199 | speed = data.comments.length * 100;
200 | appendComments(comments, ul);
201 | ul.data('empty', false);
202 | }
203 | $('#cn' + id).slideUp(speed + 200);
204 | ul.slideDown(speed);
205 | },
206 | error: function(request, textStatus, error) {
207 | showError('Oops, there was a problem retrieving the comments.');
208 | },
209 | dataType: 'json'
210 | });
211 | }
212 |
213 | /**
214 | * Add a comment via ajax and insert the comment into the comment tree.
215 | */
216 | function addComment(form) {
217 | var node_id = form.find('input[name="node"]').val();
218 | var parent_id = form.find('input[name="parent"]').val();
219 | var text = form.find('textarea[name="comment"]').val();
220 | var proposal = form.find('textarea[name="proposal"]').val();
221 |
222 | if (text == '') {
223 | showError('Please enter a comment.');
224 | return;
225 | }
226 |
227 | // Disable the form that is being submitted.
228 | form.find('textarea,input').attr('disabled', 'disabled');
229 |
230 | // Send the comment to the server.
231 | $.ajax({
232 | type: "POST",
233 | url: opts.addCommentURL,
234 | dataType: 'json',
235 | data: {
236 | node: node_id,
237 | parent: parent_id,
238 | text: text,
239 | proposal: proposal
240 | },
241 | success: function(data, textStatus, error) {
242 | // Reset the form.
243 | if (node_id) {
244 | hideProposeChange(node_id);
245 | }
246 | form.find('textarea')
247 | .val('')
248 | .add(form.find('input'))
249 | .removeAttr('disabled');
250 | var ul = $('#cl' + (node_id || parent_id));
251 | if (ul.data('empty')) {
252 | $(ul).empty();
253 | ul.data('empty', false);
254 | }
255 | insertComment(data.comment);
256 | var ao = $('#ao' + node_id);
257 | ao.find('img').attr({'src': opts.commentBrightImage});
258 | if (node_id) {
259 | // if this was a "root" comment, remove the commenting box
260 | // (the user can get it back by reopening the comment popup)
261 | $('#ca' + node_id).slideUp();
262 | }
263 | },
264 | error: function(request, textStatus, error) {
265 | form.find('textarea,input').removeAttr('disabled');
266 | showError('Oops, there was a problem adding the comment.');
267 | }
268 | });
269 | }
270 |
271 | /**
272 | * Recursively append comments to the main comment list and children
273 | * lists, creating the comment tree.
274 | */
275 | function appendComments(comments, ul) {
276 | $.each(comments, function() {
277 | var div = createCommentDiv(this);
278 | ul.append($(document.createElement('li')).html(div));
279 | appendComments(this.children, div.find('ul.comment-children'));
280 | // To avoid stagnating data, don't store the comments children in data.
281 | this.children = null;
282 | div.data('comment', this);
283 | });
284 | }
285 |
286 | /**
287 | * After adding a new comment, it must be inserted in the correct
288 | * location in the comment tree.
289 | */
290 | function insertComment(comment) {
291 | var div = createCommentDiv(comment);
292 |
293 | // To avoid stagnating data, don't store the comments children in data.
294 | comment.children = null;
295 | div.data('comment', comment);
296 |
297 | var ul = $('#cl' + (comment.node || comment.parent));
298 | var siblings = getChildren(ul);
299 |
300 | var li = $(document.createElement('li'));
301 | li.hide();
302 |
303 | // Determine where in the parents children list to insert this comment.
304 | for(i=0; i < siblings.length; i++) {
305 | if (comp(comment, siblings[i]) <= 0) {
306 | $('#cd' + siblings[i].id)
307 | .parent()
308 | .before(li.html(div));
309 | li.slideDown('fast');
310 | return;
311 | }
312 | }
313 |
314 | // If we get here, this comment rates lower than all the others,
315 | // or it is the only comment in the list.
316 | ul.append(li.html(div));
317 | li.slideDown('fast');
318 | }
319 |
320 | function acceptComment(id) {
321 | $.ajax({
322 | type: 'POST',
323 | url: opts.acceptCommentURL,
324 | data: {id: id},
325 | success: function(data, textStatus, request) {
326 | $('#cm' + id).fadeOut('fast');
327 | $('#cd' + id).removeClass('moderate');
328 | },
329 | error: function(request, textStatus, error) {
330 | showError('Oops, there was a problem accepting the comment.');
331 | }
332 | });
333 | }
334 |
335 | function deleteComment(id) {
336 | $.ajax({
337 | type: 'POST',
338 | url: opts.deleteCommentURL,
339 | data: {id: id},
340 | success: function(data, textStatus, request) {
341 | var div = $('#cd' + id);
342 | if (data == 'delete') {
343 | // Moderator mode: remove the comment and all children immediately
344 | div.slideUp('fast', function() {
345 | div.remove();
346 | });
347 | return;
348 | }
349 | // User mode: only mark the comment as deleted
350 | div
351 | .find('span.user-id:first')
352 | .text('[deleted]').end()
353 | .find('div.comment-text:first')
354 | .text('[deleted]').end()
355 | .find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
356 | ', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
357 | .remove();
358 | var comment = div.data('comment');
359 | comment.username = '[deleted]';
360 | comment.text = '[deleted]';
361 | div.data('comment', comment);
362 | },
363 | error: function(request, textStatus, error) {
364 | showError('Oops, there was a problem deleting the comment.');
365 | }
366 | });
367 | }
368 |
369 | function showProposal(id) {
370 | $('#sp' + id).hide();
371 | $('#hp' + id).show();
372 | $('#pr' + id).slideDown('fast');
373 | }
374 |
375 | function hideProposal(id) {
376 | $('#hp' + id).hide();
377 | $('#sp' + id).show();
378 | $('#pr' + id).slideUp('fast');
379 | }
380 |
381 | function showProposeChange(id) {
382 | $('#pc' + id).hide();
383 | $('#hc' + id).show();
384 | var textarea = $('#pt' + id);
385 | textarea.val(textarea.data('source'));
386 | $.fn.autogrow.resize(textarea[0]);
387 | textarea.slideDown('fast');
388 | }
389 |
390 | function hideProposeChange(id) {
391 | $('#hc' + id).hide();
392 | $('#pc' + id).show();
393 | var textarea = $('#pt' + id);
394 | textarea.val('').removeAttr('disabled');
395 | textarea.slideUp('fast');
396 | }
397 |
398 | function toggleCommentMarkupBox(id) {
399 | $('#mb' + id).toggle();
400 | }
401 |
402 | /** Handle when the user clicks on a sort by link. */
403 | function handleReSort(link) {
404 | var classes = link.attr('class').split(/\s+/);
405 | for (var i=0; iThank you! Your comment will show up '
558 | + 'once it is has been approved by a moderator.');
559 | }
560 | // Prettify the comment rating.
561 | comment.pretty_rating = comment.rating + ' point' +
562 | (comment.rating == 1 ? '' : 's');
563 | // Make a class (for displaying not yet moderated comments differently)
564 | comment.css_class = comment.displayed ? '' : ' moderate';
565 | // Create a div for this comment.
566 | var context = $.extend({}, opts, comment);
567 | var div = $(renderTemplate(commentTemplate, context));
568 |
569 | // If the user has voted on this comment, highlight the correct arrow.
570 | if (comment.vote) {
571 | var direction = (comment.vote == 1) ? 'u' : 'd';
572 | div.find('#' + direction + 'v' + comment.id).hide();
573 | div.find('#' + direction + 'u' + comment.id).show();
574 | }
575 |
576 | if (opts.moderator || comment.text != '[deleted]') {
577 | div.find('a.reply').show();
578 | if (comment.proposal_diff)
579 | div.find('#sp' + comment.id).show();
580 | if (opts.moderator && !comment.displayed)
581 | div.find('#cm' + comment.id).show();
582 | if (opts.moderator || (opts.username == comment.username))
583 | div.find('#dc' + comment.id).show();
584 | }
585 | return div;
586 | }
587 |
588 | /**
589 | * A simple template renderer. Placeholders such as <%id%> are replaced
590 | * by context['id'] with items being escaped. Placeholders such as <#id#>
591 | * are not escaped.
592 | */
593 | function renderTemplate(template, context) {
594 | var esc = $(document.createElement('div'));
595 |
596 | function handle(ph, escape) {
597 | var cur = context;
598 | $.each(ph.split('.'), function() {
599 | cur = cur[this];
600 | });
601 | return escape ? esc.text(cur || "").html() : cur;
602 | }
603 |
604 | return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
605 | return handle(arguments[2], arguments[1] == '%' ? true : false);
606 | });
607 | }
608 |
609 | /** Flash an error message briefly. */
610 | function showError(message) {
611 | $(document.createElement('div')).attr({'class': 'popup-error'})
612 | .append($(document.createElement('div'))
613 | .attr({'class': 'error-message'}).text(message))
614 | .appendTo('body')
615 | .fadeIn("slow")
616 | .delay(2000)
617 | .fadeOut("slow");
618 | }
619 |
620 | /** Add a link the user uses to open the comments popup. */
621 | $.fn.comment = function() {
622 | return this.each(function() {
623 | var id = $(this).attr('id').substring(1);
624 | var count = COMMENT_METADATA[id];
625 | var title = count + ' comment' + (count == 1 ? '' : 's');
626 | var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
627 | var addcls = count == 0 ? ' nocomment' : '';
628 | $(this)
629 | .append(
630 | $(document.createElement('a')).attr({
631 | href: '#',
632 | 'class': 'sphinx-comment-open' + addcls,
633 | id: 'ao' + id
634 | })
635 | .append($(document.createElement('img')).attr({
636 | src: image,
637 | alt: 'comment',
638 | title: title
639 | }))
640 | .click(function(event) {
641 | event.preventDefault();
642 | show($(this).attr('id').substring(2));
643 | })
644 | )
645 | .append(
646 | $(document.createElement('a')).attr({
647 | href: '#',
648 | 'class': 'sphinx-comment-close hidden',
649 | id: 'ah' + id
650 | })
651 | .append($(document.createElement('img')).attr({
652 | src: opts.closeCommentImage,
653 | alt: 'close',
654 | title: 'close'
655 | }))
656 | .click(function(event) {
657 | event.preventDefault();
658 | hide($(this).attr('id').substring(2));
659 | })
660 | );
661 | });
662 | };
663 |
664 | var opts = {
665 | processVoteURL: '/_process_vote',
666 | addCommentURL: '/_add_comment',
667 | getCommentsURL: '/_get_comments',
668 | acceptCommentURL: '/_accept_comment',
669 | deleteCommentURL: '/_delete_comment',
670 | commentImage: '/static/_static/comment.png',
671 | closeCommentImage: '/static/_static/comment-close.png',
672 | loadingImage: '/static/_static/ajax-loader.gif',
673 | commentBrightImage: '/static/_static/comment-bright.png',
674 | upArrow: '/static/_static/up.png',
675 | downArrow: '/static/_static/down.png',
676 | upArrowPressed: '/static/_static/up-pressed.png',
677 | downArrowPressed: '/static/_static/down-pressed.png',
678 | voting: false,
679 | moderator: false
680 | };
681 |
682 | if (typeof COMMENT_OPTIONS != "undefined") {
683 | opts = jQuery.extend(opts, COMMENT_OPTIONS);
684 | }
685 |
686 | var popupTemplate = '\
687 | ';
723 |
724 | var commentTemplate = '\
725 | \
768 | ';
769 |
770 | var replyTemplate = '\
771 | \
772 | \
773 | \
780 |
\
781 | ';
782 |
783 | $(document).ready(function() {
784 | init();
785 | });
786 | })(jQuery);
787 |
788 | $(document).ready(function() {
789 | // add comment anchors for all paragraphs that are commentable
790 | $('.sphinx-has-comment').comment();
791 |
792 | // highlight search words in search results
793 | $("div.context").each(function() {
794 | var params = $.getQueryParameters();
795 | var terms = (params.q) ? params.q[0].split(/\s+/) : [];
796 | var result = $(this);
797 | $.each(terms, function() {
798 | result.highlightText(this.toLowerCase(), 'highlighted');
799 | });
800 | });
801 |
802 | // directly open comment window if requested
803 | var anchor = document.location.hash;
804 | if (anchor.substring(0, 9) == '#comment-') {
805 | $('#ao' + anchor.substring(9)).click();
806 | document.location.hash = '#s' + anchor.substring(9);
807 | }
808 | });
809 |
--------------------------------------------------------------------------------
/docs/build/html/_static/underscore.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.4.4
2 | // http://underscorejs.org
3 | // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
4 | // Underscore may be freely distributed under the MIT license.
5 |
6 | (function() {
7 |
8 | // Baseline setup
9 | // --------------
10 |
11 | // Establish the root object, `window` in the browser, or `global` on the server.
12 | var root = this;
13 |
14 | // Save the previous value of the `_` variable.
15 | var previousUnderscore = root._;
16 |
17 | // Establish the object that gets returned to break out of a loop iteration.
18 | var breaker = {};
19 |
20 | // Save bytes in the minified (but not gzipped) version:
21 | var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
22 |
23 | // Create quick reference variables for speed access to core prototypes.
24 | var push = ArrayProto.push,
25 | slice = ArrayProto.slice,
26 | concat = ArrayProto.concat,
27 | toString = ObjProto.toString,
28 | hasOwnProperty = ObjProto.hasOwnProperty;
29 |
30 | // All **ECMAScript 5** native function implementations that we hope to use
31 | // are declared here.
32 | var
33 | nativeForEach = ArrayProto.forEach,
34 | nativeMap = ArrayProto.map,
35 | nativeReduce = ArrayProto.reduce,
36 | nativeReduceRight = ArrayProto.reduceRight,
37 | nativeFilter = ArrayProto.filter,
38 | nativeEvery = ArrayProto.every,
39 | nativeSome = ArrayProto.some,
40 | nativeIndexOf = ArrayProto.indexOf,
41 | nativeLastIndexOf = ArrayProto.lastIndexOf,
42 | nativeIsArray = Array.isArray,
43 | nativeKeys = Object.keys,
44 | nativeBind = FuncProto.bind;
45 |
46 | // Create a safe reference to the Underscore object for use below.
47 | var _ = function(obj) {
48 | if (obj instanceof _) return obj;
49 | if (!(this instanceof _)) return new _(obj);
50 | this._wrapped = obj;
51 | };
52 |
53 | // Export the Underscore object for **Node.js**, with
54 | // backwards-compatibility for the old `require()` API. If we're in
55 | // the browser, add `_` as a global object via a string identifier,
56 | // for Closure Compiler "advanced" mode.
57 | if (typeof exports !== 'undefined') {
58 | if (typeof module !== 'undefined' && module.exports) {
59 | exports = module.exports = _;
60 | }
61 | exports._ = _;
62 | } else {
63 | root._ = _;
64 | }
65 |
66 | // Current version.
67 | _.VERSION = '1.4.4';
68 |
69 | // Collection Functions
70 | // --------------------
71 |
72 | // The cornerstone, an `each` implementation, aka `forEach`.
73 | // Handles objects with the built-in `forEach`, arrays, and raw objects.
74 | // Delegates to **ECMAScript 5**'s native `forEach` if available.
75 | var each = _.each = _.forEach = function(obj, iterator, context) {
76 | if (obj == null) return;
77 | if (nativeForEach && obj.forEach === nativeForEach) {
78 | obj.forEach(iterator, context);
79 | } else if (obj.length === +obj.length) {
80 | for (var i = 0, l = obj.length; i < l; i++) {
81 | if (iterator.call(context, obj[i], i, obj) === breaker) return;
82 | }
83 | } else {
84 | for (var key in obj) {
85 | if (_.has(obj, key)) {
86 | if (iterator.call(context, obj[key], key, obj) === breaker) return;
87 | }
88 | }
89 | }
90 | };
91 |
92 | // Return the results of applying the iterator to each element.
93 | // Delegates to **ECMAScript 5**'s native `map` if available.
94 | _.map = _.collect = function(obj, iterator, context) {
95 | var results = [];
96 | if (obj == null) return results;
97 | if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
98 | each(obj, function(value, index, list) {
99 | results[results.length] = iterator.call(context, value, index, list);
100 | });
101 | return results;
102 | };
103 |
104 | var reduceError = 'Reduce of empty array with no initial value';
105 |
106 | // **Reduce** builds up a single result from a list of values, aka `inject`,
107 | // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
108 | _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
109 | var initial = arguments.length > 2;
110 | if (obj == null) obj = [];
111 | if (nativeReduce && obj.reduce === nativeReduce) {
112 | if (context) iterator = _.bind(iterator, context);
113 | return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
114 | }
115 | each(obj, function(value, index, list) {
116 | if (!initial) {
117 | memo = value;
118 | initial = true;
119 | } else {
120 | memo = iterator.call(context, memo, value, index, list);
121 | }
122 | });
123 | if (!initial) throw new TypeError(reduceError);
124 | return memo;
125 | };
126 |
127 | // The right-associative version of reduce, also known as `foldr`.
128 | // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
129 | _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
130 | var initial = arguments.length > 2;
131 | if (obj == null) obj = [];
132 | if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
133 | if (context) iterator = _.bind(iterator, context);
134 | return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
135 | }
136 | var length = obj.length;
137 | if (length !== +length) {
138 | var keys = _.keys(obj);
139 | length = keys.length;
140 | }
141 | each(obj, function(value, index, list) {
142 | index = keys ? keys[--length] : --length;
143 | if (!initial) {
144 | memo = obj[index];
145 | initial = true;
146 | } else {
147 | memo = iterator.call(context, memo, obj[index], index, list);
148 | }
149 | });
150 | if (!initial) throw new TypeError(reduceError);
151 | return memo;
152 | };
153 |
154 | // Return the first value which passes a truth test. Aliased as `detect`.
155 | _.find = _.detect = function(obj, iterator, context) {
156 | var result;
157 | any(obj, function(value, index, list) {
158 | if (iterator.call(context, value, index, list)) {
159 | result = value;
160 | return true;
161 | }
162 | });
163 | return result;
164 | };
165 |
166 | // Return all the elements that pass a truth test.
167 | // Delegates to **ECMAScript 5**'s native `filter` if available.
168 | // Aliased as `select`.
169 | _.filter = _.select = function(obj, iterator, context) {
170 | var results = [];
171 | if (obj == null) return results;
172 | if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
173 | each(obj, function(value, index, list) {
174 | if (iterator.call(context, value, index, list)) results[results.length] = value;
175 | });
176 | return results;
177 | };
178 |
179 | // Return all the elements for which a truth test fails.
180 | _.reject = function(obj, iterator, context) {
181 | return _.filter(obj, function(value, index, list) {
182 | return !iterator.call(context, value, index, list);
183 | }, context);
184 | };
185 |
186 | // Determine whether all of the elements match a truth test.
187 | // Delegates to **ECMAScript 5**'s native `every` if available.
188 | // Aliased as `all`.
189 | _.every = _.all = function(obj, iterator, context) {
190 | iterator || (iterator = _.identity);
191 | var result = true;
192 | if (obj == null) return result;
193 | if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
194 | each(obj, function(value, index, list) {
195 | if (!(result = result && iterator.call(context, value, index, list))) return breaker;
196 | });
197 | return !!result;
198 | };
199 |
200 | // Determine if at least one element in the object matches a truth test.
201 | // Delegates to **ECMAScript 5**'s native `some` if available.
202 | // Aliased as `any`.
203 | var any = _.some = _.any = function(obj, iterator, context) {
204 | iterator || (iterator = _.identity);
205 | var result = false;
206 | if (obj == null) return result;
207 | if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
208 | each(obj, function(value, index, list) {
209 | if (result || (result = iterator.call(context, value, index, list))) return breaker;
210 | });
211 | return !!result;
212 | };
213 |
214 | // Determine if the array or object contains a given value (using `===`).
215 | // Aliased as `include`.
216 | _.contains = _.include = function(obj, target) {
217 | if (obj == null) return false;
218 | if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
219 | return any(obj, function(value) {
220 | return value === target;
221 | });
222 | };
223 |
224 | // Invoke a method (with arguments) on every item in a collection.
225 | _.invoke = function(obj, method) {
226 | var args = slice.call(arguments, 2);
227 | var isFunc = _.isFunction(method);
228 | return _.map(obj, function(value) {
229 | return (isFunc ? method : value[method]).apply(value, args);
230 | });
231 | };
232 |
233 | // Convenience version of a common use case of `map`: fetching a property.
234 | _.pluck = function(obj, key) {
235 | return _.map(obj, function(value){ return value[key]; });
236 | };
237 |
238 | // Convenience version of a common use case of `filter`: selecting only objects
239 | // containing specific `key:value` pairs.
240 | _.where = function(obj, attrs, first) {
241 | if (_.isEmpty(attrs)) return first ? null : [];
242 | return _[first ? 'find' : 'filter'](obj, function(value) {
243 | for (var key in attrs) {
244 | if (attrs[key] !== value[key]) return false;
245 | }
246 | return true;
247 | });
248 | };
249 |
250 | // Convenience version of a common use case of `find`: getting the first object
251 | // containing specific `key:value` pairs.
252 | _.findWhere = function(obj, attrs) {
253 | return _.where(obj, attrs, true);
254 | };
255 |
256 | // Return the maximum element or (element-based computation).
257 | // Can't optimize arrays of integers longer than 65,535 elements.
258 | // See: https://bugs.webkit.org/show_bug.cgi?id=80797
259 | _.max = function(obj, iterator, context) {
260 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
261 | return Math.max.apply(Math, obj);
262 | }
263 | if (!iterator && _.isEmpty(obj)) return -Infinity;
264 | var result = {computed : -Infinity, value: -Infinity};
265 | each(obj, function(value, index, list) {
266 | var computed = iterator ? iterator.call(context, value, index, list) : value;
267 | computed >= result.computed && (result = {value : value, computed : computed});
268 | });
269 | return result.value;
270 | };
271 |
272 | // Return the minimum element (or element-based computation).
273 | _.min = function(obj, iterator, context) {
274 | if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
275 | return Math.min.apply(Math, obj);
276 | }
277 | if (!iterator && _.isEmpty(obj)) return Infinity;
278 | var result = {computed : Infinity, value: Infinity};
279 | each(obj, function(value, index, list) {
280 | var computed = iterator ? iterator.call(context, value, index, list) : value;
281 | computed < result.computed && (result = {value : value, computed : computed});
282 | });
283 | return result.value;
284 | };
285 |
286 | // Shuffle an array.
287 | _.shuffle = function(obj) {
288 | var rand;
289 | var index = 0;
290 | var shuffled = [];
291 | each(obj, function(value) {
292 | rand = _.random(index++);
293 | shuffled[index - 1] = shuffled[rand];
294 | shuffled[rand] = value;
295 | });
296 | return shuffled;
297 | };
298 |
299 | // An internal function to generate lookup iterators.
300 | var lookupIterator = function(value) {
301 | return _.isFunction(value) ? value : function(obj){ return obj[value]; };
302 | };
303 |
304 | // Sort the object's values by a criterion produced by an iterator.
305 | _.sortBy = function(obj, value, context) {
306 | var iterator = lookupIterator(value);
307 | return _.pluck(_.map(obj, function(value, index, list) {
308 | return {
309 | value : value,
310 | index : index,
311 | criteria : iterator.call(context, value, index, list)
312 | };
313 | }).sort(function(left, right) {
314 | var a = left.criteria;
315 | var b = right.criteria;
316 | if (a !== b) {
317 | if (a > b || a === void 0) return 1;
318 | if (a < b || b === void 0) return -1;
319 | }
320 | return left.index < right.index ? -1 : 1;
321 | }), 'value');
322 | };
323 |
324 | // An internal function used for aggregate "group by" operations.
325 | var group = function(obj, value, context, behavior) {
326 | var result = {};
327 | var iterator = lookupIterator(value || _.identity);
328 | each(obj, function(value, index) {
329 | var key = iterator.call(context, value, index, obj);
330 | behavior(result, key, value);
331 | });
332 | return result;
333 | };
334 |
335 | // Groups the object's values by a criterion. Pass either a string attribute
336 | // to group by, or a function that returns the criterion.
337 | _.groupBy = function(obj, value, context) {
338 | return group(obj, value, context, function(result, key, value) {
339 | (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
340 | });
341 | };
342 |
343 | // Counts instances of an object that group by a certain criterion. Pass
344 | // either a string attribute to count by, or a function that returns the
345 | // criterion.
346 | _.countBy = function(obj, value, context) {
347 | return group(obj, value, context, function(result, key) {
348 | if (!_.has(result, key)) result[key] = 0;
349 | result[key]++;
350 | });
351 | };
352 |
353 | // Use a comparator function to figure out the smallest index at which
354 | // an object should be inserted so as to maintain order. Uses binary search.
355 | _.sortedIndex = function(array, obj, iterator, context) {
356 | iterator = iterator == null ? _.identity : lookupIterator(iterator);
357 | var value = iterator.call(context, obj);
358 | var low = 0, high = array.length;
359 | while (low < high) {
360 | var mid = (low + high) >>> 1;
361 | iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
362 | }
363 | return low;
364 | };
365 |
366 | // Safely convert anything iterable into a real, live array.
367 | _.toArray = function(obj) {
368 | if (!obj) return [];
369 | if (_.isArray(obj)) return slice.call(obj);
370 | if (obj.length === +obj.length) return _.map(obj, _.identity);
371 | return _.values(obj);
372 | };
373 |
374 | // Return the number of elements in an object.
375 | _.size = function(obj) {
376 | if (obj == null) return 0;
377 | return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
378 | };
379 |
380 | // Array Functions
381 | // ---------------
382 |
383 | // Get the first element of an array. Passing **n** will return the first N
384 | // values in the array. Aliased as `head` and `take`. The **guard** check
385 | // allows it to work with `_.map`.
386 | _.first = _.head = _.take = function(array, n, guard) {
387 | if (array == null) return void 0;
388 | return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
389 | };
390 |
391 | // Returns everything but the last entry of the array. Especially useful on
392 | // the arguments object. Passing **n** will return all the values in
393 | // the array, excluding the last N. The **guard** check allows it to work with
394 | // `_.map`.
395 | _.initial = function(array, n, guard) {
396 | return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
397 | };
398 |
399 | // Get the last element of an array. Passing **n** will return the last N
400 | // values in the array. The **guard** check allows it to work with `_.map`.
401 | _.last = function(array, n, guard) {
402 | if (array == null) return void 0;
403 | if ((n != null) && !guard) {
404 | return slice.call(array, Math.max(array.length - n, 0));
405 | } else {
406 | return array[array.length - 1];
407 | }
408 | };
409 |
410 | // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
411 | // Especially useful on the arguments object. Passing an **n** will return
412 | // the rest N values in the array. The **guard**
413 | // check allows it to work with `_.map`.
414 | _.rest = _.tail = _.drop = function(array, n, guard) {
415 | return slice.call(array, (n == null) || guard ? 1 : n);
416 | };
417 |
418 | // Trim out all falsy values from an array.
419 | _.compact = function(array) {
420 | return _.filter(array, _.identity);
421 | };
422 |
423 | // Internal implementation of a recursive `flatten` function.
424 | var flatten = function(input, shallow, output) {
425 | each(input, function(value) {
426 | if (_.isArray(value)) {
427 | shallow ? push.apply(output, value) : flatten(value, shallow, output);
428 | } else {
429 | output.push(value);
430 | }
431 | });
432 | return output;
433 | };
434 |
435 | // Return a completely flattened version of an array.
436 | _.flatten = function(array, shallow) {
437 | return flatten(array, shallow, []);
438 | };
439 |
440 | // Return a version of the array that does not contain the specified value(s).
441 | _.without = function(array) {
442 | return _.difference(array, slice.call(arguments, 1));
443 | };
444 |
445 | // Produce a duplicate-free version of the array. If the array has already
446 | // been sorted, you have the option of using a faster algorithm.
447 | // Aliased as `unique`.
448 | _.uniq = _.unique = function(array, isSorted, iterator, context) {
449 | if (_.isFunction(isSorted)) {
450 | context = iterator;
451 | iterator = isSorted;
452 | isSorted = false;
453 | }
454 | var initial = iterator ? _.map(array, iterator, context) : array;
455 | var results = [];
456 | var seen = [];
457 | each(initial, function(value, index) {
458 | if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
459 | seen.push(value);
460 | results.push(array[index]);
461 | }
462 | });
463 | return results;
464 | };
465 |
466 | // Produce an array that contains the union: each distinct element from all of
467 | // the passed-in arrays.
468 | _.union = function() {
469 | return _.uniq(concat.apply(ArrayProto, arguments));
470 | };
471 |
472 | // Produce an array that contains every item shared between all the
473 | // passed-in arrays.
474 | _.intersection = function(array) {
475 | var rest = slice.call(arguments, 1);
476 | return _.filter(_.uniq(array), function(item) {
477 | return _.every(rest, function(other) {
478 | return _.indexOf(other, item) >= 0;
479 | });
480 | });
481 | };
482 |
483 | // Take the difference between one array and a number of other arrays.
484 | // Only the elements present in just the first array will remain.
485 | _.difference = function(array) {
486 | var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
487 | return _.filter(array, function(value){ return !_.contains(rest, value); });
488 | };
489 |
490 | // Zip together multiple lists into a single array -- elements that share
491 | // an index go together.
492 | _.zip = function() {
493 | var args = slice.call(arguments);
494 | var length = _.max(_.pluck(args, 'length'));
495 | var results = new Array(length);
496 | for (var i = 0; i < length; i++) {
497 | results[i] = _.pluck(args, "" + i);
498 | }
499 | return results;
500 | };
501 |
502 | // Converts lists into objects. Pass either a single array of `[key, value]`
503 | // pairs, or two parallel arrays of the same length -- one of keys, and one of
504 | // the corresponding values.
505 | _.object = function(list, values) {
506 | if (list == null) return {};
507 | var result = {};
508 | for (var i = 0, l = list.length; i < l; i++) {
509 | if (values) {
510 | result[list[i]] = values[i];
511 | } else {
512 | result[list[i][0]] = list[i][1];
513 | }
514 | }
515 | return result;
516 | };
517 |
518 | // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
519 | // we need this function. Return the position of the first occurrence of an
520 | // item in an array, or -1 if the item is not included in the array.
521 | // Delegates to **ECMAScript 5**'s native `indexOf` if available.
522 | // If the array is large and already in sort order, pass `true`
523 | // for **isSorted** to use binary search.
524 | _.indexOf = function(array, item, isSorted) {
525 | if (array == null) return -1;
526 | var i = 0, l = array.length;
527 | if (isSorted) {
528 | if (typeof isSorted == 'number') {
529 | i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
530 | } else {
531 | i = _.sortedIndex(array, item);
532 | return array[i] === item ? i : -1;
533 | }
534 | }
535 | if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
536 | for (; i < l; i++) if (array[i] === item) return i;
537 | return -1;
538 | };
539 |
540 | // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
541 | _.lastIndexOf = function(array, item, from) {
542 | if (array == null) return -1;
543 | var hasIndex = from != null;
544 | if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
545 | return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
546 | }
547 | var i = (hasIndex ? from : array.length);
548 | while (i--) if (array[i] === item) return i;
549 | return -1;
550 | };
551 |
552 | // Generate an integer Array containing an arithmetic progression. A port of
553 | // the native Python `range()` function. See
554 | // [the Python documentation](http://docs.python.org/library/functions.html#range).
555 | _.range = function(start, stop, step) {
556 | if (arguments.length <= 1) {
557 | stop = start || 0;
558 | start = 0;
559 | }
560 | step = arguments[2] || 1;
561 |
562 | var len = Math.max(Math.ceil((stop - start) / step), 0);
563 | var idx = 0;
564 | var range = new Array(len);
565 |
566 | while(idx < len) {
567 | range[idx++] = start;
568 | start += step;
569 | }
570 |
571 | return range;
572 | };
573 |
574 | // Function (ahem) Functions
575 | // ------------------
576 |
577 | // Create a function bound to a given object (assigning `this`, and arguments,
578 | // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
579 | // available.
580 | _.bind = function(func, context) {
581 | if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
582 | var args = slice.call(arguments, 2);
583 | return function() {
584 | return func.apply(context, args.concat(slice.call(arguments)));
585 | };
586 | };
587 |
588 | // Partially apply a function by creating a version that has had some of its
589 | // arguments pre-filled, without changing its dynamic `this` context.
590 | _.partial = function(func) {
591 | var args = slice.call(arguments, 1);
592 | return function() {
593 | return func.apply(this, args.concat(slice.call(arguments)));
594 | };
595 | };
596 |
597 | // Bind all of an object's methods to that object. Useful for ensuring that
598 | // all callbacks defined on an object belong to it.
599 | _.bindAll = function(obj) {
600 | var funcs = slice.call(arguments, 1);
601 | if (funcs.length === 0) funcs = _.functions(obj);
602 | each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
603 | return obj;
604 | };
605 |
606 | // Memoize an expensive function by storing its results.
607 | _.memoize = function(func, hasher) {
608 | var memo = {};
609 | hasher || (hasher = _.identity);
610 | return function() {
611 | var key = hasher.apply(this, arguments);
612 | return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
613 | };
614 | };
615 |
616 | // Delays a function for the given number of milliseconds, and then calls
617 | // it with the arguments supplied.
618 | _.delay = function(func, wait) {
619 | var args = slice.call(arguments, 2);
620 | return setTimeout(function(){ return func.apply(null, args); }, wait);
621 | };
622 |
623 | // Defers a function, scheduling it to run after the current call stack has
624 | // cleared.
625 | _.defer = function(func) {
626 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
627 | };
628 |
629 | // Returns a function, that, when invoked, will only be triggered at most once
630 | // during a given window of time.
631 | _.throttle = function(func, wait) {
632 | var context, args, timeout, result;
633 | var previous = 0;
634 | var later = function() {
635 | previous = new Date;
636 | timeout = null;
637 | result = func.apply(context, args);
638 | };
639 | return function() {
640 | var now = new Date;
641 | var remaining = wait - (now - previous);
642 | context = this;
643 | args = arguments;
644 | if (remaining <= 0) {
645 | clearTimeout(timeout);
646 | timeout = null;
647 | previous = now;
648 | result = func.apply(context, args);
649 | } else if (!timeout) {
650 | timeout = setTimeout(later, remaining);
651 | }
652 | return result;
653 | };
654 | };
655 |
656 | // Returns a function, that, as long as it continues to be invoked, will not
657 | // be triggered. The function will be called after it stops being called for
658 | // N milliseconds. If `immediate` is passed, trigger the function on the
659 | // leading edge, instead of the trailing.
660 | _.debounce = function(func, wait, immediate) {
661 | var timeout, result;
662 | return function() {
663 | var context = this, args = arguments;
664 | var later = function() {
665 | timeout = null;
666 | if (!immediate) result = func.apply(context, args);
667 | };
668 | var callNow = immediate && !timeout;
669 | clearTimeout(timeout);
670 | timeout = setTimeout(later, wait);
671 | if (callNow) result = func.apply(context, args);
672 | return result;
673 | };
674 | };
675 |
676 | // Returns a function that will be executed at most one time, no matter how
677 | // often you call it. Useful for lazy initialization.
678 | _.once = function(func) {
679 | var ran = false, memo;
680 | return function() {
681 | if (ran) return memo;
682 | ran = true;
683 | memo = func.apply(this, arguments);
684 | func = null;
685 | return memo;
686 | };
687 | };
688 |
689 | // Returns the first function passed as an argument to the second,
690 | // allowing you to adjust arguments, run code before and after, and
691 | // conditionally execute the original function.
692 | _.wrap = function(func, wrapper) {
693 | return function() {
694 | var args = [func];
695 | push.apply(args, arguments);
696 | return wrapper.apply(this, args);
697 | };
698 | };
699 |
700 | // Returns a function that is the composition of a list of functions, each
701 | // consuming the return value of the function that follows.
702 | _.compose = function() {
703 | var funcs = arguments;
704 | return function() {
705 | var args = arguments;
706 | for (var i = funcs.length - 1; i >= 0; i--) {
707 | args = [funcs[i].apply(this, args)];
708 | }
709 | return args[0];
710 | };
711 | };
712 |
713 | // Returns a function that will only be executed after being called N times.
714 | _.after = function(times, func) {
715 | if (times <= 0) return func();
716 | return function() {
717 | if (--times < 1) {
718 | return func.apply(this, arguments);
719 | }
720 | };
721 | };
722 |
723 | // Object Functions
724 | // ----------------
725 |
726 | // Retrieve the names of an object's properties.
727 | // Delegates to **ECMAScript 5**'s native `Object.keys`
728 | _.keys = nativeKeys || function(obj) {
729 | if (obj !== Object(obj)) throw new TypeError('Invalid object');
730 | var keys = [];
731 | for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
732 | return keys;
733 | };
734 |
735 | // Retrieve the values of an object's properties.
736 | _.values = function(obj) {
737 | var values = [];
738 | for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
739 | return values;
740 | };
741 |
742 | // Convert an object into a list of `[key, value]` pairs.
743 | _.pairs = function(obj) {
744 | var pairs = [];
745 | for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
746 | return pairs;
747 | };
748 |
749 | // Invert the keys and values of an object. The values must be serializable.
750 | _.invert = function(obj) {
751 | var result = {};
752 | for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
753 | return result;
754 | };
755 |
756 | // Return a sorted list of the function names available on the object.
757 | // Aliased as `methods`
758 | _.functions = _.methods = function(obj) {
759 | var names = [];
760 | for (var key in obj) {
761 | if (_.isFunction(obj[key])) names.push(key);
762 | }
763 | return names.sort();
764 | };
765 |
766 | // Extend a given object with all the properties in passed-in object(s).
767 | _.extend = function(obj) {
768 | each(slice.call(arguments, 1), function(source) {
769 | if (source) {
770 | for (var prop in source) {
771 | obj[prop] = source[prop];
772 | }
773 | }
774 | });
775 | return obj;
776 | };
777 |
778 | // Return a copy of the object only containing the whitelisted properties.
779 | _.pick = function(obj) {
780 | var copy = {};
781 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
782 | each(keys, function(key) {
783 | if (key in obj) copy[key] = obj[key];
784 | });
785 | return copy;
786 | };
787 |
788 | // Return a copy of the object without the blacklisted properties.
789 | _.omit = function(obj) {
790 | var copy = {};
791 | var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
792 | for (var key in obj) {
793 | if (!_.contains(keys, key)) copy[key] = obj[key];
794 | }
795 | return copy;
796 | };
797 |
798 | // Fill in a given object with default properties.
799 | _.defaults = function(obj) {
800 | each(slice.call(arguments, 1), function(source) {
801 | if (source) {
802 | for (var prop in source) {
803 | if (obj[prop] == null) obj[prop] = source[prop];
804 | }
805 | }
806 | });
807 | return obj;
808 | };
809 |
810 | // Create a (shallow-cloned) duplicate of an object.
811 | _.clone = function(obj) {
812 | if (!_.isObject(obj)) return obj;
813 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
814 | };
815 |
816 | // Invokes interceptor with the obj, and then returns obj.
817 | // The primary purpose of this method is to "tap into" a method chain, in
818 | // order to perform operations on intermediate results within the chain.
819 | _.tap = function(obj, interceptor) {
820 | interceptor(obj);
821 | return obj;
822 | };
823 |
824 | // Internal recursive comparison function for `isEqual`.
825 | var eq = function(a, b, aStack, bStack) {
826 | // Identical objects are equal. `0 === -0`, but they aren't identical.
827 | // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
828 | if (a === b) return a !== 0 || 1 / a == 1 / b;
829 | // A strict comparison is necessary because `null == undefined`.
830 | if (a == null || b == null) return a === b;
831 | // Unwrap any wrapped objects.
832 | if (a instanceof _) a = a._wrapped;
833 | if (b instanceof _) b = b._wrapped;
834 | // Compare `[[Class]]` names.
835 | var className = toString.call(a);
836 | if (className != toString.call(b)) return false;
837 | switch (className) {
838 | // Strings, numbers, dates, and booleans are compared by value.
839 | case '[object String]':
840 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
841 | // equivalent to `new String("5")`.
842 | return a == String(b);
843 | case '[object Number]':
844 | // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
845 | // other numeric values.
846 | return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
847 | case '[object Date]':
848 | case '[object Boolean]':
849 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their
850 | // millisecond representations. Note that invalid dates with millisecond representations
851 | // of `NaN` are not equivalent.
852 | return +a == +b;
853 | // RegExps are compared by their source patterns and flags.
854 | case '[object RegExp]':
855 | return a.source == b.source &&
856 | a.global == b.global &&
857 | a.multiline == b.multiline &&
858 | a.ignoreCase == b.ignoreCase;
859 | }
860 | if (typeof a != 'object' || typeof b != 'object') return false;
861 | // Assume equality for cyclic structures. The algorithm for detecting cyclic
862 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
863 | var length = aStack.length;
864 | while (length--) {
865 | // Linear search. Performance is inversely proportional to the number of
866 | // unique nested structures.
867 | if (aStack[length] == a) return bStack[length] == b;
868 | }
869 | // Add the first object to the stack of traversed objects.
870 | aStack.push(a);
871 | bStack.push(b);
872 | var size = 0, result = true;
873 | // Recursively compare objects and arrays.
874 | if (className == '[object Array]') {
875 | // Compare array lengths to determine if a deep comparison is necessary.
876 | size = a.length;
877 | result = size == b.length;
878 | if (result) {
879 | // Deep compare the contents, ignoring non-numeric properties.
880 | while (size--) {
881 | if (!(result = eq(a[size], b[size], aStack, bStack))) break;
882 | }
883 | }
884 | } else {
885 | // Objects with different constructors are not equivalent, but `Object`s
886 | // from different frames are.
887 | var aCtor = a.constructor, bCtor = b.constructor;
888 | if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
889 | _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
890 | return false;
891 | }
892 | // Deep compare objects.
893 | for (var key in a) {
894 | if (_.has(a, key)) {
895 | // Count the expected number of properties.
896 | size++;
897 | // Deep compare each member.
898 | if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
899 | }
900 | }
901 | // Ensure that both objects contain the same number of properties.
902 | if (result) {
903 | for (key in b) {
904 | if (_.has(b, key) && !(size--)) break;
905 | }
906 | result = !size;
907 | }
908 | }
909 | // Remove the first object from the stack of traversed objects.
910 | aStack.pop();
911 | bStack.pop();
912 | return result;
913 | };
914 |
915 | // Perform a deep comparison to check if two objects are equal.
916 | _.isEqual = function(a, b) {
917 | return eq(a, b, [], []);
918 | };
919 |
920 | // Is a given array, string, or object empty?
921 | // An "empty" object has no enumerable own-properties.
922 | _.isEmpty = function(obj) {
923 | if (obj == null) return true;
924 | if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
925 | for (var key in obj) if (_.has(obj, key)) return false;
926 | return true;
927 | };
928 |
929 | // Is a given value a DOM element?
930 | _.isElement = function(obj) {
931 | return !!(obj && obj.nodeType === 1);
932 | };
933 |
934 | // Is a given value an array?
935 | // Delegates to ECMA5's native Array.isArray
936 | _.isArray = nativeIsArray || function(obj) {
937 | return toString.call(obj) == '[object Array]';
938 | };
939 |
940 | // Is a given variable an object?
941 | _.isObject = function(obj) {
942 | return obj === Object(obj);
943 | };
944 |
945 | // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
946 | each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
947 | _['is' + name] = function(obj) {
948 | return toString.call(obj) == '[object ' + name + ']';
949 | };
950 | });
951 |
952 | // Define a fallback version of the method in browsers (ahem, IE), where
953 | // there isn't any inspectable "Arguments" type.
954 | if (!_.isArguments(arguments)) {
955 | _.isArguments = function(obj) {
956 | return !!(obj && _.has(obj, 'callee'));
957 | };
958 | }
959 |
960 | // Optimize `isFunction` if appropriate.
961 | if (typeof (/./) !== 'function') {
962 | _.isFunction = function(obj) {
963 | return typeof obj === 'function';
964 | };
965 | }
966 |
967 | // Is a given object a finite number?
968 | _.isFinite = function(obj) {
969 | return isFinite(obj) && !isNaN(parseFloat(obj));
970 | };
971 |
972 | // Is the given value `NaN`? (NaN is the only number which does not equal itself).
973 | _.isNaN = function(obj) {
974 | return _.isNumber(obj) && obj != +obj;
975 | };
976 |
977 | // Is a given value a boolean?
978 | _.isBoolean = function(obj) {
979 | return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
980 | };
981 |
982 | // Is a given value equal to null?
983 | _.isNull = function(obj) {
984 | return obj === null;
985 | };
986 |
987 | // Is a given variable undefined?
988 | _.isUndefined = function(obj) {
989 | return obj === void 0;
990 | };
991 |
992 | // Shortcut function for checking if an object has a given property directly
993 | // on itself (in other words, not on a prototype).
994 | _.has = function(obj, key) {
995 | return hasOwnProperty.call(obj, key);
996 | };
997 |
998 | // Utility Functions
999 | // -----------------
1000 |
1001 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
1002 | // previous owner. Returns a reference to the Underscore object.
1003 | _.noConflict = function() {
1004 | root._ = previousUnderscore;
1005 | return this;
1006 | };
1007 |
1008 | // Keep the identity function around for default iterators.
1009 | _.identity = function(value) {
1010 | return value;
1011 | };
1012 |
1013 | // Run a function **n** times.
1014 | _.times = function(n, iterator, context) {
1015 | var accum = Array(n);
1016 | for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
1017 | return accum;
1018 | };
1019 |
1020 | // Return a random integer between min and max (inclusive).
1021 | _.random = function(min, max) {
1022 | if (max == null) {
1023 | max = min;
1024 | min = 0;
1025 | }
1026 | return min + Math.floor(Math.random() * (max - min + 1));
1027 | };
1028 |
1029 | // List of HTML entities for escaping.
1030 | var entityMap = {
1031 | escape: {
1032 | '&': '&',
1033 | '<': '<',
1034 | '>': '>',
1035 | '"': '"',
1036 | "'": ''',
1037 | '/': '/'
1038 | }
1039 | };
1040 | entityMap.unescape = _.invert(entityMap.escape);
1041 |
1042 | // Regexes containing the keys and values listed immediately above.
1043 | var entityRegexes = {
1044 | escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
1045 | unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
1046 | };
1047 |
1048 | // Functions for escaping and unescaping strings to/from HTML interpolation.
1049 | _.each(['escape', 'unescape'], function(method) {
1050 | _[method] = function(string) {
1051 | if (string == null) return '';
1052 | return ('' + string).replace(entityRegexes[method], function(match) {
1053 | return entityMap[method][match];
1054 | });
1055 | };
1056 | });
1057 |
1058 | // If the value of the named property is a function then invoke it;
1059 | // otherwise, return it.
1060 | _.result = function(object, property) {
1061 | if (object == null) return null;
1062 | var value = object[property];
1063 | return _.isFunction(value) ? value.call(object) : value;
1064 | };
1065 |
1066 | // Add your own custom functions to the Underscore object.
1067 | _.mixin = function(obj) {
1068 | each(_.functions(obj), function(name){
1069 | var func = _[name] = obj[name];
1070 | _.prototype[name] = function() {
1071 | var args = [this._wrapped];
1072 | push.apply(args, arguments);
1073 | return result.call(this, func.apply(_, args));
1074 | };
1075 | });
1076 | };
1077 |
1078 | // Generate a unique integer id (unique within the entire client session).
1079 | // Useful for temporary DOM ids.
1080 | var idCounter = 0;
1081 | _.uniqueId = function(prefix) {
1082 | var id = ++idCounter + '';
1083 | return prefix ? prefix + id : id;
1084 | };
1085 |
1086 | // By default, Underscore uses ERB-style template delimiters, change the
1087 | // following template settings to use alternative delimiters.
1088 | _.templateSettings = {
1089 | evaluate : /<%([\s\S]+?)%>/g,
1090 | interpolate : /<%=([\s\S]+?)%>/g,
1091 | escape : /<%-([\s\S]+?)%>/g
1092 | };
1093 |
1094 | // When customizing `templateSettings`, if you don't want to define an
1095 | // interpolation, evaluation or escaping regex, we need one that is
1096 | // guaranteed not to match.
1097 | var noMatch = /(.)^/;
1098 |
1099 | // Certain characters need to be escaped so that they can be put into a
1100 | // string literal.
1101 | var escapes = {
1102 | "'": "'",
1103 | '\\': '\\',
1104 | '\r': 'r',
1105 | '\n': 'n',
1106 | '\t': 't',
1107 | '\u2028': 'u2028',
1108 | '\u2029': 'u2029'
1109 | };
1110 |
1111 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
1112 |
1113 | // JavaScript micro-templating, similar to John Resig's implementation.
1114 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
1115 | // and correctly escapes quotes within interpolated code.
1116 | _.template = function(text, data, settings) {
1117 | var render;
1118 | settings = _.defaults({}, settings, _.templateSettings);
1119 |
1120 | // Combine delimiters into one regular expression via alternation.
1121 | var matcher = new RegExp([
1122 | (settings.escape || noMatch).source,
1123 | (settings.interpolate || noMatch).source,
1124 | (settings.evaluate || noMatch).source
1125 | ].join('|') + '|$', 'g');
1126 |
1127 | // Compile the template source, escaping string literals appropriately.
1128 | var index = 0;
1129 | var source = "__p+='";
1130 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
1131 | source += text.slice(index, offset)
1132 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
1133 |
1134 | if (escape) {
1135 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
1136 | }
1137 | if (interpolate) {
1138 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
1139 | }
1140 | if (evaluate) {
1141 | source += "';\n" + evaluate + "\n__p+='";
1142 | }
1143 | index = offset + match.length;
1144 | return match;
1145 | });
1146 | source += "';\n";
1147 |
1148 | // If a variable is not specified, place data values in local scope.
1149 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
1150 |
1151 | source = "var __t,__p='',__j=Array.prototype.join," +
1152 | "print=function(){__p+=__j.call(arguments,'');};\n" +
1153 | source + "return __p;\n";
1154 |
1155 | try {
1156 | render = new Function(settings.variable || 'obj', '_', source);
1157 | } catch (e) {
1158 | e.source = source;
1159 | throw e;
1160 | }
1161 |
1162 | if (data) return render(data, _);
1163 | var template = function(data) {
1164 | return render.call(this, data, _);
1165 | };
1166 |
1167 | // Provide the compiled function source as a convenience for precompilation.
1168 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
1169 |
1170 | return template;
1171 | };
1172 |
1173 | // Add a "chain" function, which will delegate to the wrapper.
1174 | _.chain = function(obj) {
1175 | return _(obj).chain();
1176 | };
1177 |
1178 | // OOP
1179 | // ---------------
1180 | // If Underscore is called as a function, it returns a wrapped object that
1181 | // can be used OO-style. This wrapper holds altered versions of all the
1182 | // underscore functions. Wrapped objects may be chained.
1183 |
1184 | // Helper function to continue chaining intermediate results.
1185 | var result = function(obj) {
1186 | return this._chain ? _(obj).chain() : obj;
1187 | };
1188 |
1189 | // Add all of the Underscore functions to the wrapper object.
1190 | _.mixin(_);
1191 |
1192 | // Add all mutator Array functions to the wrapper.
1193 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
1194 | var method = ArrayProto[name];
1195 | _.prototype[name] = function() {
1196 | var obj = this._wrapped;
1197 | method.apply(obj, arguments);
1198 | if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
1199 | return result.call(this, obj);
1200 | };
1201 | });
1202 |
1203 | // Add all accessor Array functions to the wrapper.
1204 | each(['concat', 'join', 'slice'], function(name) {
1205 | var method = ArrayProto[name];
1206 | _.prototype[name] = function() {
1207 | return result.call(this, method.apply(this._wrapped, arguments));
1208 | };
1209 | });
1210 |
1211 | _.extend(_.prototype, {
1212 |
1213 | // Start chaining a wrapped Underscore object.
1214 | chain: function() {
1215 | this._chain = true;
1216 | return this;
1217 | },
1218 |
1219 | // Extracts the result from a wrapped and chained object.
1220 | value: function() {
1221 | return this._wrapped;
1222 | }
1223 |
1224 | });
1225 |
1226 | }).call(this);
1227 |
--------------------------------------------------------------------------------
\ 689 | Sort by:\ 690 | best rated\ 691 | newest\ 692 | oldest\ 693 |
\ 694 |\ 698 |
Add a comment\ 700 | (markup):
\ 701 |