diff --git a/.checkignore b/.checkignore deleted file mode 100644 index 32a27fe..0000000 --- a/.checkignore +++ /dev/null @@ -1,2 +0,0 @@ -# Ignore folder content -tests/* \ No newline at end of file diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f4b5048..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -tutorials/* linguist-vendored=true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 960e4ad..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -The piece of code that reproduce the bug. - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Output** -The obtained output. Please include the entire error trace. - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 11fc491..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/help-wanted.md b/.github/ISSUE_TEMPLATE/help-wanted.md deleted file mode 100644 index 97d1c1e..0000000 --- a/.github/ISSUE_TEMPLATE/help-wanted.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Help wanted -about: Ask help for using the package -title: '' -labels: help wanted -assignees: '' - ---- - -**The objective** -A clear description of the purpose of your application. - -**Already tried tests** -The snippet of code you have already tried in order to obtain the wanted outcome. diff --git a/.github/workflows/create-tag.yml b/.github/workflows/create-tag.yml deleted file mode 100644 index 6376708..0000000 --- a/.github/workflows/create-tag.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Create Git Tag - -on: - workflow_dispatch: - inputs: - tag_name: - description: "Tag name (eg. v1.3.0)" - required: true - type: string - -permissions: - contents: write - -jobs: - create_tag: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - persist-credentials: false - - - name: Configure git with PAT - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git remote set-url origin "https://x-access-token:${{ secrets.PAT_BLADEX_PUSH }}@github.com/${{ github.repository }}.git" - - - name: Check if the tag is already existing - run: | - TAG="${{ inputs.tag_name }}" - git fetch --tags - if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then - echo "❌ Tag $TAG already exists" - exit 1 - fi - - - name: Create and push the tag - run: | - TAG="${{ inputs.tag_name }}" - git tag "$TAG" - git push origin "$TAG" diff --git a/.github/workflows/testing_pr.yml b/.github/workflows/testing_pr.yml deleted file mode 100644 index d416067..0000000 --- a/.github/workflows/testing_pr.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: "Testing Pull Request" - -on: - pull_request: - branches: - - "master" - - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [windows-latest, macos-latest, ubuntu-latest] - python-version: ["3.9", "3.10", "3.11", "3.12"] - - steps: - - uses: actions/checkout@v4 - - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Setup Conda - uses: conda-incubator/setup-miniconda@v3 - with: - channels: conda-forge, defaults - activate-environment: "" - - - name: Install Python dependencies on Linux/MacOS - shell: bash -el {0} - if: startsWith(matrix.os, 'windows') != true - run: | - conda create -n occ python=${{ matrix.python-version }} pythonocc-core - conda info - conda activate occ - conda info - python -m pip install --upgrade pip - python -m pip install smithers[vtk] - python -m pip install .[test] - python -c 'import OCC' - - - name: Install Python dependencies on Windows - if: startsWith(matrix.os, 'windows') - run: | - conda install --yes pythonocc-core - python -m pip install --upgrade pip - python -m pip install smithers[vtk] - python -m pip install .[test] - - - name: Test with pytest on Windows - if: startsWith(matrix.os, 'windows') - run: python -m pytest - - - name: Test with pytest on Linux/MacOS - shell: bash -el {0} - if: startsWith(matrix.os, 'windows') != true - run: | - conda activate occ - python -m pytest diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a23ab24..0000000 --- a/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# mac file systems -.DS_Store - -# compiled python codes -*.pyc \ No newline at end of file diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index 3eb8f80..0000000 --- a/.pylintrc +++ /dev/null @@ -1,427 +0,0 @@ -[MASTER] - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Add files or directories matching the regex patterns to the blacklist. The -# regex matches against base names, not paths. -ignore-patterns= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Pickle collected data for later comparisons. -persistent=yes - -# Specify a configuration file. -#rcfile= - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -#disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,invalid-name - -disable = invalid-name,no-member -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time (only on the command line, not in the configuration file where -# it should appear only once). See also the "--disable" option for examples. -enable= - - -[REPORTS] - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - -# Set the output format. Available formats are text, parseable, colorized, json -# and msvs (visual studio).You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Tells whether to display a full report or only the messages -reports=no - -# Activate the evaluation score. -score=yes - - -[REFACTORING] - -# Maximum number of nested blocks for function / method body -max-nested-blocks=5 - - -[VARIABLES] - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# Tells whether unused global variables should be treated as a violation. -allow-global-unused-variables=yes - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.*|^ignored_|^unused_ - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# List of qualified module names which can have objects that can redefine -# builtins. -redefining-builtins-modules=six.moves,future.builtins - - -[TYPECHECK] - -# List of decorators that produce context managers, such as -# contextlib.contextmanager. Add to this list to register other decorators that -# produce valid context managers. -contextmanager-decorators=contextlib.contextmanager - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E1101 when accessed. Python regular -# expressions are accepted. -generated-members= - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# This flag controls whether pylint should warn about no-member and similar -# checks whenever an opaque object is returned when inferring. The inference -# can return multiple potential results while evaluating a Python object, but -# some branches might not be evaluated, which results in partial inference. In -# that case, it might be useful to still emit no-member and other checks for -# the rest of the inferred objects. -ignore-on-opaque-inference=yes - -# List of class names for which member attributes should not be checked (useful -# for classes with dynamically set attributes). This supports the use of -# qualified names. -ignored-classes=optparse.Values,thread._local,_thread._local - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis. It -# supports qualified module names, as well as Unix pattern matching. -ignored-modules= - -# Show a hint with possible names when a member name was not found. The aspect -# of finding the hint is based on edit distance. -missing-member-hint=yes - -# The minimum edit distance a name should have in order to be considered a -# similar match for a missing member name. -missing-member-hint-distance=1 - -# The total number of similar names that should be taken in consideration when -# showing a hint for a missing member. -missing-member-max-choices=1 - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[SIMILARITIES] - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - -# Minimum lines number of a similarity. -min-similarity-lines=4 - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[FORMAT] - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format= - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=" " - -# Maximum number of characters on a single line. -max-line-length=80 - -# Maximum number of lines in a module -max-module-lines=1000 - -# List of optional constructs for which whitespace checking is disabled. `dict- -# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. -# `trailing-comma` allows a space between comma and closing bracket: (a, ). -# `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator - -# Allow the body of a class to be on the same line as the declaration if body -# contains single statement. -single-line-class-stmt=no - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - - -[BASIC] - -# Naming hint for argument names -argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct argument names -argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Naming hint for attribute names -attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct attribute names -attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - -# Naming hint for function names -function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct function names -function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_,* - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for method names -method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct method names -method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=^_ - -# List of decorators that produce properties, such as abc.abstractproperty. Add -# to this list to register other decorators that produce valid properties. -property-classes=abc.abstractproperty - -# Naming hint for variable names -variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -# Regular expression matching correct variable names -variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ - -pylint: disable=C0103 - -[IMPORTS] - -# Allow wildcard imports from modules that define __all__. -allow-wildcard-with-all=no - -# Analyse import fallback blocks. This can be used to support both Python 2 and -# 3 compatible code, which means that the block might have code that exists -# only in one or another interpreter, leading to false positives when analysed. -analyse-fallback-blocks=no - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=optparse,tkinter.tix - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - -# Force import order to recognize a module as part of the standard -# compatibility libraries. -known-standard-library= - -# Force import order to recognize a module as part of a third party library. -known-third-party=enchant - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Maximum number of attributes for a class (see R0902). -max-attributes=12 - -# Maximum number of boolean expressions in a if statement -max-bool-expr=5 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of statements in function / method body -max-statements=50 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - - -[CLASSES] - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 25d24d6..0000000 --- a/.travis.yml +++ /dev/null @@ -1,68 +0,0 @@ -sudo: true -dist: xenial - -language: python - -service: docker - -jobs: - include: - - os: linux - python: 3.7 - env: TOXENV=py37 - - os: osx - osx_image: xcode12.2 - language: generic - env: TOXENV=py37 - -before_script: - - "export DISPLAY=:99.0" - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - sh -e /etc/init.d/xvfb start; - sleep 3; - fi - -before_install: - # We do this conditionally because it saves us some downloading if the - # version is the same. - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; - else - brew update; - brew install python; - wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda.sh; - fi - - python --version - - chmod +x miniconda.sh - - bash miniconda.sh -b -p $HOME/miniconda - - export PATH="$HOME/miniconda/bin:$HOME/miniconda/lib:$PATH" - - hash -r - - conda config --set always_yes yes --set changeps1 no - - conda update -q conda - # Useful for debugging any issues with conda - - conda info -a - - conda config --add channels conda-forge - -install: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - conda create --yes -n test python=$TRAVIS_PYTHON_VERSION; - else - conda create --yes -n test python="3.7"; - fi - - source activate test - - echo $LD_LIBRARY_PATH - - echo $DYLD_LIBRARY_PATH - - echo $PATH - - python --version - - conda install --yes -c conda-forge pythonocc-core=7.4.0 numpy scipy matplotlib pip nose sip=4.18 setuptools coveralls python=3.7; - - python setup.py install - -script: - - coverage run test.py - -after_success: - - coveralls - -branches: - only: - - master diff --git a/CITATION.cff b/CITATION.cff deleted file mode 100644 index a503f6c..0000000 --- a/CITATION.cff +++ /dev/null @@ -1,20 +0,0 @@ -cff-version: 1.2.0 -message: "If you use this software, please cite it as below." -authors: -- family-names: "Gadalla" - given-names: "Mahmoud" - orcid: "https://orcid.org/0000-0001-9507-9468" -- family-names: "Tezzele" - given-names: "Marco" - orcid: "https://orcid.org/0000-0001-9747-6328" -- family-names: "Mola" - given-names: "Andrea" - orcid: "https://orcid.org/0000-0002-4483-0212" -- family-names: "Rozza" - given-names: "Gianluigi" - orcid: "https://orcid.org/0000-0002-0810-8812" -title: "BladeX: Python Blade Morphing" -version: 0.1 -doi: 10.21105/joss.01203 -date-released: 2019-02-4 -url: "https://github.com/mathLab/BladeX" diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000..821a478 --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,220 @@ + + + + + + + + + + + License — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+
+ +
+

License

+

The MIT License (MIT)

+

Copyright (c) 2017-2018 BladeX contributors

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+ + +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LICENSE.rst b/LICENSE.rst deleted file mode 100644 index 2c4082e..0000000 --- a/LICENSE.rst +++ /dev/null @@ -1,24 +0,0 @@ -License -============== - -The MIT License (MIT) - -Copyright (c) 2017-2019 BladeX contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 4cc9c3b..0000000 --- a/README.md +++ /dev/null @@ -1,213 +0,0 @@ -

- - Python Package for Blade Deformation - -

-

- - JOSS DOI - - - Software License - - - Build Status - - - Coverage Status - - - Codacy Badge - -

- -[BladeX](http://mathlab.github.io/BladeX/) (Python Blade Morphing) is a Python package for geometrical parametrization and bottom-up construction of propeller blades. It allows to generate and deform a blade based on the radial distribution of its parameters. - -## Table of contents -* [Description](#description) -* [Dependencies and installation](#dependencies-and-installation) - * [Installing from source](#installing-from-source) -* [Documentation](#documentation) -* [Testing](#testing) -* [Examples](#examples) -* [How to cite](#how-to-cite) - * [Recent works with BladeX](#recent-works-with-bladex) -* [Authors and contributors](#authors-and-contributors) -* [Support](#support) -* [How to contribute](#how-to-contribute) - * [Submitting a patch](#submitting-a-patch) -* [SISSA mathLab packages for reduced order modeling](#sissa-mathlab-packages-for-reduced-order-modeling) -* [License](#license) - -## Description -**BladeX** is a Python package for geometrical parametrization and bottom-up construction of propeller blades. It allows to generate and deform a blade based on the radial distribution of its parameters such as `pitch`, `rake`, `skew`, and the sectional foils' parameters such as `chord` and `camber`. The package is ideally suited for parametric simulations on large number of blade deformations. It provides an automated procedure for the CAD generation, hence reducing the time and effort required for modelling. The main scope of BladeX is to deal with propeller blades, however it can be flexible to be applied on further applications with analogous geometrical structures such as aircraft wings, turbomachinery, or wind turbine blades. - -See the [**Examples**](#examples) section below and the [**Tutorials**](tutorials/README.md) to have an idea of the potential of this package. - -## Dependencies and installation -**BladeX** requires `numpy`, `scipy`, `matplotlib`, `sphinx` (for the documentation), and `pytest` (for the local test). They can be easily installed using `pip`. -**BladeX** is compatible with Python>=3.9. Moreover, some of the modules require `OCC` to be installed for the `.iges` or `.stl` CAD generation. This requirement cannot be satisfied through `pip`, but the precompiled binaries are available on `conda` using the command: - -```bash -> conda install -c conda-forge pythonocc-core -``` - -You can also refer to `pythonocc.org` or `github.com/tpaviot/pythonocc-core` for further instructions. - -### Installing from source -The official distribution is on GitHub, and you can clone the repository using -```bash -> git clone https://github.com/mathLab/BladeX -``` - -To install the latest version of the package just type: -```bash -> pip install git+https://github.com/mathLab/BladeX.git -``` - -Otherwise to install your own local branch you can use the `setup.py` file -```bash -> pip install -e . -``` - -To uninstall the package just use pip again: - -```bash -> pip uninstall bladex -``` - -## Documentation -**BladeX** uses [Sphinx](http://www.sphinx-doc.org/en/stable/) for code documentation. You can view the documentation online [here](http://mathlab.github.io/BladeX/). To build the html version of the docs locally simply: - -```bash -> cd docs -> make html -``` - -The generated html can be found in `docs/build/html`. Open up the `index.html` you find there to browse. - - -## Testing - -We are using Github Actions for continuous intergration testing. You can check out the current status [here](https://github.com/mathLab/BladeX/actions/workflows/testing_pr.yml). - -To run tests locally: - -```bash -> pytest -``` - -## Examples -You can find useful tutorials on how to use the package in the [tutorials](tutorials/README.md) folder. -Here we show a bottom-up parametrized construction of the [Potsdam Propeller Test Case (PPTC)](https://www.sva-potsdam.de/pptc-smp11-workshop) provided the sectional profiles as well as the radial distribution of the `pitch`, `rake`, `skew`. The blade is generated and exported to .iges and .stl formats. - -

- -

-

-PPTC blade generation according to the radial distribution of the pitch, rake, skew. The generated blade is then exported to .iges and .stl formats. -

- -Two possible deformed geometry configurations, to show the capabilities of the package, are presented here: - -

- -

-

-Undeformed reference blade on the left, and a couple of deformed configurations obtained by moving some control points defining the skew and chord length radial distributions. -

- -## How to cite -If you use this package in your publications please cite the package as follows: - -Gadalla et al., (2019). BladeX: Python Blade Morphing. Journal of Open Source Software, 4(34), 1203, https://doi.org/10.21105/joss.01203 - -Or if you use LaTeX: -```tex -@article{gadalla19bladex, - Author = {Gadalla, Mahmoud and Tezzele, Marco and Mola, Andrea and Rozza, Gianluigi}, - Title = {{BladeX: Python Blade Morphing}}, - Journal = {The Journal of Open Source Software}, - Volume = {4}, - Number = {34}, - Pages = {1203}, - Year = {2019}, - Doi = {https://doi.org/10.21105/joss.01203} -} -``` - -### Recent works with BladeX -Here there is a list of the scientific works involving **BladeX** you can consult and/or cite. If you want to add one, please open a PR. - -* Mola, Tezzele, Gadalla, Valdenazzi, Grassi, Padovan, Rozza. *Efficient reduction in shape parameter space dimension for ship propeller blade design*. In Proceedings of MARINE 2019: VIII International Conference on Computational Methods in Marine Engineering, pages 201–212, 2019. [[DOI](https://congress.cimne.com/marine2019/frontal/Doc/EbookMarine2019.pdf)] [[arXiv](https://arxiv.org/abs/1905.09815)] [[bibitem](readme/mola2019marine.bib)]. - -* Tezzele, Demo, Mola, Rozza. *An integrated data-driven computational pipeline with model order reduction for industrial and applied mathematics*. Submitted, 2018. [[arXiv](https://arxiv.org/abs/1810.12364)] [[bibitem](readme/tezzele2018ecmi.bib)]. - - -## Authors and contributors -**BladeX** is currently developed and mantained at [SISSA mathLab](http://mathlab.sissa.it/) by -* [Mahmoud Gadalla](mailto:gadalla.mah@gmail.com) -* [Marco Tezzele](mailto:marcotez@gmail.com) - -under the supervision of [Dr. Andrea Mola](mailto:andrea.mola@sissa.it) and [Prof. Gianluigi Rozza](mailto:gianluigi.rozza@sissa.it) in the framework of the project [PRELICA: Advanced Methodologies for Hydro-acoustic Design of Naval Propulsion](https://mathlab.sissa.it/project/prelica-metodologie-avanzate-la-progettazione-idro-acustica-dell%E2%80%99elica-navale-por-fesr-2017). - -## Support - -Contact us by email for further information or questions about **BladeX**. Feel free to suggest pull requests or to open GitHub issues. Contributions improving either the code or the documentation are welcome! - - -## How to contribute -We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. - -### Submitting a patch - - 1. It's generally best to start by opening a new issue describing the bug or - feature you're intending to fix. Even if you think it's relatively minor, - it's helpful to know what people are working on. Mention in the initial - issue that you are planning to work on that bug or feature so that it can - be assigned to you. - - 2. Follow the normal process of [forking][] the project, and setup a new - branch to work in. It's important that each group of changes be done in - separate branches in order to ensure that a pull request only includes the - commits related to that bug or feature. - - 3. To ensure properly formatted code, please make sure to use 4 - spaces to indent the code. The easy way is to run on your bash the provided - script: ./code_formatter.sh. You should also run [pylint][] over your code. - It's not strictly necessary that your code be completely "lint-free", - but this will help you find common style issues. - - 4. Any significant changes should almost always be accompanied by tests. The - project already has good test coverage, so look at some of the existing - tests if you're unsure how to go about it. We're using [coveralls][] that - is an invaluable tools for seeing which parts of your code aren't being - exercised by your tests. - - 5. Do your best to have [well-formed commit messages][] for each change. - This provides consistency throughout the project, and ensures that commit - messages are able to be formatted properly by various git tools. - - 6. Finally, push the commits to your fork and submit a [pull request][]. Please, - remember to rebase properly in order to maintain a clean, linear git history. - -[forking]: https://help.github.com/articles/fork-a-repo -[pylint]: https://www.pylint.org/ -[coveralls]: https://coveralls.io -[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html -[pull request]: https://help.github.com/articles/creating-a-pull-request - -## SISSA mathLab packages for reduced order modeling - -Below you can find a list of useful reduced order modelling packages from SISSA mathLab group: -* **PyGeM**: Python library for Geometrical Morphing, that uses free form deformation to parametrize and morph complex geometries, [https://github.com/mathLab/PyGeM](https://github.com/mathLab/PyGeM). -* **PyDMD**: Python library for Dynamic Mode Decomposition, for a data-driven model simplification based on spatiotemporal coherent structures, [https://github.com/mathLab/PyDMD](https://github.com/mathLab/PyDMD). -* **RBniCS**: reduced order modelling in FEniCS, is an implementation in FEniCS of several reduced order modelling techniques for parametrized problems, [https://github.com/mathLab/RBniCS](https://github.com/mathLab/RBniCS). -* **EZyRB**: Easy Reduced Basis method, is a python library for the Model Order Reduction based on baricentric triangulation for the selection of the parameter points and on Proper Orthogonal Decomposition for the selection of the modes, [https://github.com/mathLab/EZyRB](https://github.com/mathLab/EZyRB). -* **ITHACA-FV**: In real Time Highly Advanced Computational Applications for Finite Volumes, is C++ library based on the finite volume solver OpenFOAM. It consists of the implementation of several reduced order modeling techniques for parametrized problems, [https://github.com/mathLab/ITHACA-FV](https://github.com/mathLab/ITHACA-FV). -* **ITHACA-DG**: In real Time Highly Advanced Computational Applications for Discontinuous Galerkin Methods, is C++ library based on the Discontinuous Galerkin Methods solver HopeFOAM. It consists of the implementation of reduced order modeling techniques for parametrized problems, [https://github.com/mathLab/ITHACA-DG](https://github.com/mathLab/ITHACA-DG). -* **ITHACA-SEM**: In real Time Highly Advanced Computational Applications for Spectral Element Methods, is C++ library based on the spectral element solver Nektar++. It consists of the implementation of several reduced order modeling techniques for parametrized problems, [https://github.com/mathLab/ITHACA-SEM](https://github.com/mathLab/ITHACA-SEM). - -## License - -See the [LICENSE](LICENSE.rst) file for license rights and limitations (MIT). diff --git a/docs/source/_static/logo_bladex.png b/_images/logo_bladex.png similarity index 100% rename from docs/source/_static/logo_bladex.png rename to _images/logo_bladex.png diff --git a/_images/math/00e0261a8ecc36eeaf94b411593647cf1335925c.png b/_images/math/00e0261a8ecc36eeaf94b411593647cf1335925c.png new file mode 100644 index 0000000..f2e08da Binary files /dev/null and b/_images/math/00e0261a8ecc36eeaf94b411593647cf1335925c.png differ diff --git a/_images/math/06674415564207dfcafd647119d9d1ce584a9a34.png b/_images/math/06674415564207dfcafd647119d9d1ce584a9a34.png new file mode 100644 index 0000000..203d276 Binary files /dev/null and b/_images/math/06674415564207dfcafd647119d9d1ce584a9a34.png differ diff --git a/_images/math/0ad4ddce7481706da16d2747bfaf713e571acc23.png b/_images/math/0ad4ddce7481706da16d2747bfaf713e571acc23.png new file mode 100644 index 0000000..c5d6185 Binary files /dev/null and b/_images/math/0ad4ddce7481706da16d2747bfaf713e571acc23.png differ diff --git a/_images/math/0e2977f7d8604803c0ed7c3a91e3efde8b33a8fe.png b/_images/math/0e2977f7d8604803c0ed7c3a91e3efde8b33a8fe.png new file mode 100644 index 0000000..d7861aa Binary files /dev/null and b/_images/math/0e2977f7d8604803c0ed7c3a91e3efde8b33a8fe.png differ diff --git a/_images/math/123d83de8cbcc148dc258051d46ce2c495d8892c.png b/_images/math/123d83de8cbcc148dc258051d46ce2c495d8892c.png new file mode 100644 index 0000000..a1df81d Binary files /dev/null and b/_images/math/123d83de8cbcc148dc258051d46ce2c495d8892c.png differ diff --git a/_images/math/168a7f0405a1c5485269d6ad299d52c48087397a.png b/_images/math/168a7f0405a1c5485269d6ad299d52c48087397a.png new file mode 100644 index 0000000..42c19b3 Binary files /dev/null and b/_images/math/168a7f0405a1c5485269d6ad299d52c48087397a.png differ diff --git a/_images/math/16cc752aab4769834c3c11dabc9e3bd5dde0162e.png b/_images/math/16cc752aab4769834c3c11dabc9e3bd5dde0162e.png new file mode 100644 index 0000000..5c4e566 Binary files /dev/null and b/_images/math/16cc752aab4769834c3c11dabc9e3bd5dde0162e.png differ diff --git a/_images/math/1bc9f431f4f80227aa7027f1ff71fcaea3fa0a25.png b/_images/math/1bc9f431f4f80227aa7027f1ff71fcaea3fa0a25.png new file mode 100644 index 0000000..967fc28 Binary files /dev/null and b/_images/math/1bc9f431f4f80227aa7027f1ff71fcaea3fa0a25.png differ diff --git a/_images/math/1fb53a6e43d7ce3b8f6b9680713299ee42199ead.png b/_images/math/1fb53a6e43d7ce3b8f6b9680713299ee42199ead.png new file mode 100644 index 0000000..f8dcdc2 Binary files /dev/null and b/_images/math/1fb53a6e43d7ce3b8f6b9680713299ee42199ead.png differ diff --git a/_images/math/25ce74d54bf8eec960a53b7b613479854fe4b151.png b/_images/math/25ce74d54bf8eec960a53b7b613479854fe4b151.png new file mode 100644 index 0000000..49a6465 Binary files /dev/null and b/_images/math/25ce74d54bf8eec960a53b7b613479854fe4b151.png differ diff --git a/_images/math/27b7bb9f8709a50e7b3bffa1f6e1a4d6be487f2d.png b/_images/math/27b7bb9f8709a50e7b3bffa1f6e1a4d6be487f2d.png new file mode 100644 index 0000000..490f81e Binary files /dev/null and b/_images/math/27b7bb9f8709a50e7b3bffa1f6e1a4d6be487f2d.png differ diff --git a/_images/math/333eb798c920afae61f6917ffd0b4e0352856975.png b/_images/math/333eb798c920afae61f6917ffd0b4e0352856975.png new file mode 100644 index 0000000..195d54a Binary files /dev/null and b/_images/math/333eb798c920afae61f6917ffd0b4e0352856975.png differ diff --git a/_images/math/3af77d39a308102bdbe2f9f20276293b2e0ba9da.png b/_images/math/3af77d39a308102bdbe2f9f20276293b2e0ba9da.png new file mode 100644 index 0000000..673ba47 Binary files /dev/null and b/_images/math/3af77d39a308102bdbe2f9f20276293b2e0ba9da.png differ diff --git a/_images/math/3d0c8181b10e011b0518993ed3a10a6f4ad1c82b.png b/_images/math/3d0c8181b10e011b0518993ed3a10a6f4ad1c82b.png new file mode 100644 index 0000000..4ed75bf Binary files /dev/null and b/_images/math/3d0c8181b10e011b0518993ed3a10a6f4ad1c82b.png differ diff --git a/_images/math/3e2d82177c217fba8c95196fbd9609f57e61564d.png b/_images/math/3e2d82177c217fba8c95196fbd9609f57e61564d.png new file mode 100644 index 0000000..77965c0 Binary files /dev/null and b/_images/math/3e2d82177c217fba8c95196fbd9609f57e61564d.png differ diff --git a/_images/math/42972469b5fee8570673711f3339fade8942a0d5.png b/_images/math/42972469b5fee8570673711f3339fade8942a0d5.png new file mode 100644 index 0000000..b3d9534 Binary files /dev/null and b/_images/math/42972469b5fee8570673711f3339fade8942a0d5.png differ diff --git a/_images/math/45dd05b7ae8ec69094085f29d426b567f90f3b6a.png b/_images/math/45dd05b7ae8ec69094085f29d426b567f90f3b6a.png new file mode 100644 index 0000000..053f1f9 Binary files /dev/null and b/_images/math/45dd05b7ae8ec69094085f29d426b567f90f3b6a.png differ diff --git a/_images/math/4caad23c3f87f09f7f76f735348359dd87f5b119.png b/_images/math/4caad23c3f87f09f7f76f735348359dd87f5b119.png new file mode 100644 index 0000000..0043c92 Binary files /dev/null and b/_images/math/4caad23c3f87f09f7f76f735348359dd87f5b119.png differ diff --git a/_images/math/4d3785cfc36fd0d9a9e2d7afe8376783b403f3c8.png b/_images/math/4d3785cfc36fd0d9a9e2d7afe8376783b403f3c8.png new file mode 100644 index 0000000..eebef12 Binary files /dev/null and b/_images/math/4d3785cfc36fd0d9a9e2d7afe8376783b403f3c8.png differ diff --git a/_images/math/57cc08e8cd332371bdaab4e8f0524cd9edbe7a7d.png b/_images/math/57cc08e8cd332371bdaab4e8f0524cd9edbe7a7d.png new file mode 100644 index 0000000..4ebb42a Binary files /dev/null and b/_images/math/57cc08e8cd332371bdaab4e8f0524cd9edbe7a7d.png differ diff --git a/_images/math/5ce234001023809d7e5c7714fe5e7f59a46c2d04.png b/_images/math/5ce234001023809d7e5c7714fe5e7f59a46c2d04.png new file mode 100644 index 0000000..b0beeb9 Binary files /dev/null and b/_images/math/5ce234001023809d7e5c7714fe5e7f59a46c2d04.png differ diff --git a/_images/math/5fc881227ec12be3b2218d9f66f8009f4ec7c939.png b/_images/math/5fc881227ec12be3b2218d9f66f8009f4ec7c939.png new file mode 100644 index 0000000..5e9a534 Binary files /dev/null and b/_images/math/5fc881227ec12be3b2218d9f66f8009f4ec7c939.png differ diff --git a/_images/math/6761b422e5536ab9a92eaf52707c92076819b2a8.png b/_images/math/6761b422e5536ab9a92eaf52707c92076819b2a8.png new file mode 100644 index 0000000..fa0539d Binary files /dev/null and b/_images/math/6761b422e5536ab9a92eaf52707c92076819b2a8.png differ diff --git a/_images/math/692ea71caf5050658e481945caff5cfd938d429d.png b/_images/math/692ea71caf5050658e481945caff5cfd938d429d.png new file mode 100644 index 0000000..913de7b Binary files /dev/null and b/_images/math/692ea71caf5050658e481945caff5cfd938d429d.png differ diff --git a/_images/math/86fc341e7bf84b2a5fa1b8274a4e721dd574b084.png b/_images/math/86fc341e7bf84b2a5fa1b8274a4e721dd574b084.png new file mode 100644 index 0000000..988685a Binary files /dev/null and b/_images/math/86fc341e7bf84b2a5fa1b8274a4e721dd574b084.png differ diff --git a/_images/math/989dee8049ef0358e3fa647a45a2f7874e1f470a.png b/_images/math/989dee8049ef0358e3fa647a45a2f7874e1f470a.png new file mode 100644 index 0000000..53828b8 Binary files /dev/null and b/_images/math/989dee8049ef0358e3fa647a45a2f7874e1f470a.png differ diff --git a/_images/math/9dcbbef8e0f76051d388013b90a95bec3069e484.png b/_images/math/9dcbbef8e0f76051d388013b90a95bec3069e484.png new file mode 100644 index 0000000..2578a66 Binary files /dev/null and b/_images/math/9dcbbef8e0f76051d388013b90a95bec3069e484.png differ diff --git a/_images/math/a750e61f154a3ea879227f1e63a102f80c2a1e52.png b/_images/math/a750e61f154a3ea879227f1e63a102f80c2a1e52.png new file mode 100644 index 0000000..b418377 Binary files /dev/null and b/_images/math/a750e61f154a3ea879227f1e63a102f80c2a1e52.png differ diff --git a/_images/math/ab345268cb5c5c528eab0ec30a93f105fa88e24a.png b/_images/math/ab345268cb5c5c528eab0ec30a93f105fa88e24a.png new file mode 100644 index 0000000..463e5f4 Binary files /dev/null and b/_images/math/ab345268cb5c5c528eab0ec30a93f105fa88e24a.png differ diff --git a/_images/math/aeea44fb480f1aacc712343b97e28afeaf89afaa.png b/_images/math/aeea44fb480f1aacc712343b97e28afeaf89afaa.png new file mode 100644 index 0000000..dc280b1 Binary files /dev/null and b/_images/math/aeea44fb480f1aacc712343b97e28afeaf89afaa.png differ diff --git a/_images/math/b9c28f274fce3341a90a8b625dde6892e63b4bfb.png b/_images/math/b9c28f274fce3341a90a8b625dde6892e63b4bfb.png new file mode 100644 index 0000000..93ee80e Binary files /dev/null and b/_images/math/b9c28f274fce3341a90a8b625dde6892e63b4bfb.png differ diff --git a/_images/math/bbe9ddb8181d5b3f006f47e7c33c1a296d517598.png b/_images/math/bbe9ddb8181d5b3f006f47e7c33c1a296d517598.png new file mode 100644 index 0000000..64f8c15 Binary files /dev/null and b/_images/math/bbe9ddb8181d5b3f006f47e7c33c1a296d517598.png differ diff --git a/_images/math/bfb2be9ba7b4f0f668e762c5121a72430d97570c.png b/_images/math/bfb2be9ba7b4f0f668e762c5121a72430d97570c.png new file mode 100644 index 0000000..e89136a Binary files /dev/null and b/_images/math/bfb2be9ba7b4f0f668e762c5121a72430d97570c.png differ diff --git a/_images/math/cfe336ede8769c02efbc60461f331efcec155961.png b/_images/math/cfe336ede8769c02efbc60461f331efcec155961.png new file mode 100644 index 0000000..d7861aa Binary files /dev/null and b/_images/math/cfe336ede8769c02efbc60461f331efcec155961.png differ diff --git a/_images/math/d54a3ff1a87698bdbccb7e038ae981d1f43f3d3d.png b/_images/math/d54a3ff1a87698bdbccb7e038ae981d1f43f3d3d.png new file mode 100644 index 0000000..9b5d08e Binary files /dev/null and b/_images/math/d54a3ff1a87698bdbccb7e038ae981d1f43f3d3d.png differ diff --git a/_images/math/df0deb143e5ac127f00bd248ee8001ecae572adc.png b/_images/math/df0deb143e5ac127f00bd248ee8001ecae572adc.png new file mode 100644 index 0000000..afc7f80 Binary files /dev/null and b/_images/math/df0deb143e5ac127f00bd248ee8001ecae572adc.png differ diff --git a/_images/math/e642ffd6726d886833d89dc0683273e07f01d0e1.png b/_images/math/e642ffd6726d886833d89dc0683273e07f01d0e1.png new file mode 100644 index 0000000..8657a7c Binary files /dev/null and b/_images/math/e642ffd6726d886833d89dc0683273e07f01d0e1.png differ diff --git a/_images/math/f02f62471ad5a6429f487a4700bfb9a7a0e895ba.png b/_images/math/f02f62471ad5a6429f487a4700bfb9a7a0e895ba.png new file mode 100644 index 0000000..a2bebeb Binary files /dev/null and b/_images/math/f02f62471ad5a6429f487a4700bfb9a7a0e895ba.png differ diff --git a/_images/math/f664f102404a0938b0d2fc21843059f059a9eeff.png b/_images/math/f664f102404a0938b0d2fc21843059f059a9eeff.png new file mode 100644 index 0000000..6dcea7e Binary files /dev/null and b/_images/math/f664f102404a0938b0d2fc21843059f059a9eeff.png differ diff --git a/docs/source/_tutorials/pictures/transformations.png b/_images/transformations.png similarity index 100% rename from docs/source/_tutorials/pictures/transformations.png rename to _images/transformations.png diff --git a/_modules/bladex/blade.html b/_modules/bladex/blade.html new file mode 100644 index 0000000..734e4d4 --- /dev/null +++ b/_modules/bladex/blade.html @@ -0,0 +1,1269 @@ + + + + + + + + + + + bladex.blade — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+
+ +

Source code for bladex.blade

+"""
+Module for the blade bottom-up parametrized construction.
+"""
+import numpy as np
+import matplotlib.pyplot as plt
+from mpl_toolkits.mplot3d import Axes3D
+
+
+
[docs]class Blade(object): + """ + Bottom-up parametrized blade construction. + + Given the following parameters of a propeller blade: + + - :math:`(X, Y)` coordinates of the blade cylindrical sections after + being expanded in 2D to create airfoils. + + - Radial distance :math:`(r_i)` from the propeller axis of rotation + to each cylindrical section. + + - Pitch angle :math:`(\\varphi)`, for each cylindrical section. + + - Rake :math:`(k)`, in distance units, for each cylindrical section. + + - Skew angle :math:`(\\theta_s)`, for each cylindrical section. + + then, a bottom-up construction procedure is performed by applying series of + transformation operations on the airfoils according to the provided + parameters, to end up with a 3D CAD model of the blade, which can be + exported into IGES format. Also surface or volume meshes can be obtained. + + Useful definitions on the propeller geometry: + + - Blade cylindrical section: the cross section of a blade cut by a + cylinder whose centerline is the propeller axis of rotation. + We may also refer as "radial section". + + - Pitch :math:`(P)`: the linear distance that a propeller would move in + one revolution with no slippage. The geometric pitch angle + :math:`(\\varphi)` is the angle between the pitch reference line + and a line perpendicular to the propeller axis of rotation. + + .. math:: + tan (\\varphi) = \\frac{\\text{pitch}} + {\\text{propeller circumference}} = \\frac{P}{2 \\pi r} + + - Rake: the fore or aft slant of the blade with respect to a line + perpendicular to the propeller axis of rotation. + + - Skew: the transverse sweeping of a blade such that viewing the blades + from fore or aft would show an asymmetrical shape. + + References: + + - Carlton, J. Marine propellers and propulsion. Butterworth-Heinemann, 2012. + http://navalex.com/downloads/Michigan_Wheel_Propeller_Geometry.pdf + + - J. Babicz. Wartsila Encyclopedia of Ship Technology. 2nd ed. Wartsila + Corporation. 2015. + + .. _transformation_operations: + + Transformation operations according to the provided parameters: + + .. figure:: ../../readme/transformations.png + :scale: 75 % + :alt: transformations + + Airfoil 2D transformations corresponding to the pitch, rake, and skew of + the blade expanded cylindrical section. + + -------------------------- + + :param array_like sections: 1D array, each element is an object of the + BaseProfile class at specific radial section. + :param array_like radii: 1D array, contains the radii values of the + sectional profiles. + :param array_like chord_lengths: 1D array, contains the value of the + airfoil's chord length for each radial section of the blade. + :param array_like pitch: 1D array, contains the local pitch values + (in unit length) for each radial section of the blade. + :param array_like rake: 1D array, contains the local rake values for each + radial section of the blade. + :param array_like skew_angles: 1D array, contains the skew angles + (in degrees) for each radial section of the blade. + + Note that, each of the previous array_like parameters must be consistent + with the other parameters in terms of the radial ordering of the blade + sections. In particular, an array_like elements must follow the radial + distribution of the blade sections starting from the blade root and ends up + with the blade tip since the blade surface generator depends on that order. + + Finally, beware that the profiles class objects in the array 'sections' + undergo several transformations that affect their coordinates. Therefore + the array must be specific to each blade class instance. For example, if + we generate 12 sectional profiles using NACA airfoils and we need to use + them in two different blade classes, then we should instantiate two class + objects for the profiles, as well as the blade. The following example + explains the fault and the correct implementations (assuming we already + have the arrays radii, chord, pitch, rake, skew): + + INCORRECT IMPLEMENTATION: + + >>> sections = [bladex.profiles.NacaProfile(digits='0012', n_points=240, + cosine_spacing=True) for i in range(12)] + >>> blade_1 = Blade( + sections=sections, + radii=radii, + chord_lengths=chord, + pitch=pitch, + rake=rake, + skew_angles=skew) + >>> blade_1.apply_transformations() + >>> blade_2 = Blade( + sections=sections, + radii=radii, + chord_lengths=chord, + pitch=pitch, + rake=rake, + skew_angles=skew) + >>> blade_2.apply_transformations() + + The previous implementation would lead into erroneous blade coordinates due + to the transformed data in the array sections + + CORRECT IMPLEMENTATION: + + >>> sections_1 = [bladex.profiles.NacaProfile(digits='0012', n_points=240, + cosine_spacing=True) for i in range(12)] + >>> sections_2 = [bladex.profiles.NacaProfile(digits='0012', n_points=240, + cosine_spacing=True) for i in range(12)] + >>> blade_1 = Blade( + sections=sections_1, + radii=radii, + chord_lengths=chord, + pitch=pitch, + rake=rake, + skew_angles=skew) + >>> blade_1.apply_transformations() + >>> blade_2 = Blade( + sections=sections_2, + radii=radii, + chord_lengths=chord, + pitch=pitch, + rake=rake, + skew_angles=skew) + >>> blade_2.apply_transformations() + """ + + def __init__(self, sections, radii, chord_lengths, pitch, rake, + skew_angles): + # Data are given in absolute values + self.sections = sections + self.n_sections = len(sections) + self.radii = radii + self.chord_lengths = chord_lengths + self.pitch = pitch + self.rake = rake + self.skew_angles = skew_angles + self._check_params() + + self.pitch_angles = self._compute_pitch_angle() + self.induced_rake = self._induced_rake_from_skew() + + self.blade_coordinates_up = [] + self.blade_coordinates_down = [] + + self.generated_upper_face = None + self.generated_lower_face = None + self.generated_tip = None + +
[docs] def _check_params(self): + """ + Private method to check if all the blade arguments are numpy.ndarrays + with the same shape. + """ + if not isinstance(self.sections, np.ndarray): + self.sections = np.asarray(self.sections) + if not isinstance(self.radii, np.ndarray): + self.radii = np.asarray(self.radii) + if not isinstance(self.chord_lengths, np.ndarray): + self.chord_lengths = np.asarray(self.chord_lengths) + if not isinstance(self.pitch, np.ndarray): + self.pitch = np.asarray(self.pitch) + if not isinstance(self.rake, np.ndarray): + self.rake = np.asarray(self.rake) + if not isinstance(self.skew_angles, np.ndarray): + self.skew_angles = np.asarray(self.skew_angles) + + if not (self.sections.shape == self.radii.shape == + self.chord_lengths.shape == self.pitch.shape == self.rake.shape + == self.skew_angles.shape): + raise ValueError('Arrays {sections, radii, chord_lengths, pitch, '\ + 'rake, skew_angles} do not have the same shape.')
+ +
[docs] def _compute_pitch_angle(self): + """ + Private method that computes the pitch angle from the linear pitch for + all blade sections. + + :return: pitch angle in radians + :rtype: numpy.ndarray + """ + return np.arctan(self.pitch / (2.0 * np.pi * self.radii))
+ +
[docs] def _induced_rake_from_skew(self): + """ + Private method that computes the induced rake from skew for all the + blade sections, according to :ref:`mytransformation_operations`. + + :return: induced rake from skew + :rtype: numpy.ndarray + """ + return self.radii * np.radians(self.skew_angles) * np.tan( + self.pitch_angles)
+ +
[docs] def _planar_to_cylindrical(self): + """ + Private method that transforms the 2D planar airfoils into 3D + cylindrical sections. + + The cylindrical transformation is defined by the following formulas: + + - :math:`x = x_{i} \\qquad \\forall x_i \\in X` + + - :math:`y = r \\sin\\left( \\frac{y_i}{r} \\right) \\qquad + \\forall y_i \\in Y` + + - :math:`z = -r \\cos\\left( \\frac{y_i}{r} \\right) \\qquad + \\forall y_i \\in Y` + + After transformation, the method also fills the numpy.ndarray + "blade_coordinates_up" and "blade_coordinates_down" with the new + :math:`(X, Y, Z)` coordinates. + """ + for section, radius in zip(self.sections, self.radii): + theta_up = section.yup_coordinates / radius + theta_down = section.ydown_coordinates / radius + + y_section_up = radius * np.sin(theta_up) + y_section_down = radius * np.sin(theta_down) + + z_section_up = -radius * np.cos(theta_up) + z_section_down = -radius * np.cos(theta_down) + + self.blade_coordinates_up.append( + np.array([section.xup_coordinates, y_section_up, z_section_up])) + self.blade_coordinates_down.append( + np.array( + [section.xdown_coordinates, y_section_down, + z_section_down]))
+ +
[docs] def apply_transformations(self, reflect=True): + """ + Generate a bottom-up constructed propeller blade based on the airfoil + transformations, see :ref:`mytransformation_operations`. + + The order of the transformation operations is as follows: + + 1. Translate airfoils by reference points into origin. + + 2. Scale X, Y coordinates by a factor of the chord length. Also + reflect the airfoils if necessary. + + 3. Rotate the airfoils counter-clockwise according to the local + pitch angles. Beware of the orientation system. + + 4. Translate airfoils along X-axis by a magnitude of the local + rake. Perform another translation for the skew-induced rake. + + 5. Translate airfoils along Y-axis by a magnitude of the skewness. + + 6. Transform the 2D airfoils into cylindrical sections, by laying + each foil on a cylinder of radius equals to the section radius, + and the cylinder axis is the propeller axis of rotation. + + :param bool reflect: if true, then reflect the coordinates of all the + airfoils about both X-axis and Y-axis. Default value is True. + + We note that the implemented transformation operations with the current + Cartesian coordinate system shown in :ref:`mytransformation_operations` + assumes a right-handed propeller. In case of a desired left-handed + propeller the user can either change the code for the negative + Z-coordinates in the cylindrical transformation (i.e. + `_planar_to_cylindrical` private method), or manipulating the + orientation of the generated CAD with respect to the hub. + """ + for i in range(self.n_sections): + # Translate reference point into origin + self.sections[i].translate(-self.sections[i].reference_point) + + if reflect: + self.sections[i].reflect() + + # Scale the unit chord to actual length. + self.sections[i].scale(self.chord_lengths[i]) + + # Rotate according to the pitch angle. + # Since the current orientation system is not standard (It is + # left-handed Cartesian orientation system, where Y-axis points + # downwards and X-axis points to the right), the standard rotation + # matrix yields clockwise rotation. + self.sections[i].rotate( + rad_angle=np.pi / 2.0 - self.pitch_angles[i]) + + # Translation due to skew. + self.sections[i].translate( + [0, -self.radii[i] * np.radians(self.skew_angles[i])]) + + # Translate due to total rake. + self.sections[i].translate( + [-(self.rake[i] + self.induced_rake[i]), 0]) + + self._planar_to_cylindrical()
+ +
[docs] def rotate(self, deg_angle=None, rad_angle=None): + """ + 3D counter clockwise rotation about the X-axis of the Cartesian + coordinate system, which is the axis of rotation of the propeller hub. + + The rotation matrix, :math:`R(\\theta)`, is used to perform rotation + in the 3D Euclidean space about the X-axis, which is -- by default -- + the propeller axis of rotation. + + :math:`R(\\theta)` is defined by: + + .. math:: + \\left(\\begin{matrix} 1 & 0 & 0 \\\\ + 0 & cos (\\theta) & - sin (\\theta) \\\\ + 0 & sin (\\theta) & cos (\\theta) \\end{matrix}\\right) + + Given the coordinates of point :math:`P` such that + + .. math:: + P = \\left(\\begin{matrix} x \\\\ + y \\\\ z \\end{matrix}\\right), + + Then, the rotated coordinates will be: + + .. math:: + P^{'} = \\left(\\begin{matrix} x^{'} \\\\ + y^{'} \\\\ z^{'} \\end{matrix}\\right) + = R (\\theta) \\cdot P + + :param float deg_angle: angle in degrees. Default value is None + :param float rad_angle: angle in radians. Default value is None + :raises ValueError: if both rad_angle and deg_angle are inserted, + or if neither is inserted + + """ + if not self.blade_coordinates_up: + raise ValueError('You must apply transformations before rotation.') + + # Check rotation angle + if deg_angle is not None and rad_angle is not None: + raise ValueError( + 'You have to pass either the angle in radians or in degrees,' \ + ' not both.') + if rad_angle is not None: + cosine = np.cos(rad_angle) + sine = np.sin(rad_angle) + elif deg_angle is not None: + cosine = np.cos(np.radians(deg_angle)) + sine = np.sin(np.radians(deg_angle)) + else: + raise ValueError( + 'You have to pass either the angle in radians or in degrees.') + + # Rotation is always about the X-axis, which is the center if the hub + # according to the implemented transformation procedure + rot_matrix = np.array([1, 0, 0, 0, cosine, -sine, 0, sine, + cosine]).reshape((3, 3)) + + for i in range(self.n_sections): + coord_matrix_up = np.vstack((self.blade_coordinates_up[i][0], + self.blade_coordinates_up[i][1], + self.blade_coordinates_up[i][2])) + coord_matrix_down = np.vstack((self.blade_coordinates_down[i][0], + self.blade_coordinates_down[i][1], + self.blade_coordinates_down[i][2])) + + new_coord_matrix_up = np.dot(rot_matrix, coord_matrix_up) + new_coord_matrix_down = np.dot(rot_matrix, coord_matrix_down) + + self.blade_coordinates_up[i][0] = new_coord_matrix_up[0] + self.blade_coordinates_up[i][1] = new_coord_matrix_up[1] + self.blade_coordinates_up[i][2] = new_coord_matrix_up[2] + + self.blade_coordinates_down[i][0] = new_coord_matrix_down[0] + self.blade_coordinates_down[i][1] = new_coord_matrix_down[1] + self.blade_coordinates_down[i][2] = new_coord_matrix_down[2]
+ +
[docs] def plot(self, elev=None, azim=None, ax=None, outfile=None): + """ + Plot the generated blade sections. + + :param int elev: set the view elevation of the axes. This can be used + to rotate the axes programatically. 'elev' stores the elevation + angle in the z plane. If elev is None, then the initial value is + used which was specified in the mplot3d.Axes3D constructor. Default + value is None + :param int azim: set the view azimuth angle of the axes. This can be + used to rotate the axes programatically. 'azim' stores the azimuth + angle in the x,y plane. If azim is None, then the initial value is + used which was specified in the mplot3d.Axes3D constructor. Default + value is None + :param matplotlib.axes ax: allows to pass the instance of figure axes + to the current plot. This is useful when the user needs to plot the + coordinates of several blade objects on the same figure (see the + example below). If nothing is passed then the method plots on a new + figure axes. Default value is None + :param string outfile: save the plot if a filename string is provided. + Default value is None + + EXAMPLE: + Assume we already have the arrays radii, chord, pitch, rake, skew for + 10 blade sections. + + >>> sections_1 = np.asarray([blade.NacaProfile(digits='0012') + for i in range(10)]) + >>> blade_1 = blade.Blade(sections=sections, + radii=radii, + chord_lengths=chord, + pitch=pitch, + rake=rake, + skew_angles=skew) + >>> blade_1.apply_transformations() + + >>> sections_2 = np.asarray([blade.NacaProfile(digits='0012') + for i in range(10)]) + >>> blade_2 = blade.Blade(sections=sections, + radii=radii, + chord_lengths=chord, + pitch=pitch, + rake=rake, + skew_angles=skew) + >>> blade_2.apply_transformations() + >>> blade_2.rotate(rot_angle_deg=72) + + >>> fig = plt.figure() + >>> ax = fig.gca(projection=Axes3D.name) + >>> blade_1.plot(ax=ax) + >>> blade_2.plot(ax=ax) + + On the other hand, if we need to plot for a single blade object, + we can just ignore such parameter, and the method will internally + create a new instance for the figure axes, i.e. + + >>> sections = np.asarray([blade.NacaProfile(digits='0012') + for i in range(10)]) + >>> blade = blade.Blade(sections=sections, + radii=radii, + chord_lengths=chord, + pitch=pitch, + rake=rake, + skew_angles=skew) + >>> blade.apply_transformations() + >>> blade.plot() + """ + if not self.blade_coordinates_up: + raise ValueError('You must apply transformations before plotting.') + if ax: + ax = ax + else: + fig = plt.figure() + ax = fig.gca(projection=Axes3D.name) + ax.set_aspect('equal') + + for i in range(self.n_sections): + ax.plot(self.blade_coordinates_up[i][0], + self.blade_coordinates_up[i][1], + self.blade_coordinates_up[i][2]) + ax.plot(self.blade_coordinates_down[i][0], + self.blade_coordinates_down[i][1], + self.blade_coordinates_down[i][2]) + + plt.axis('equal') + ax.set_xlabel('X axis') + ax.set_ylabel('Y axis') + ax.set_zlabel('radii axis') + ax.xaxis.label.set_color('red') + ax.yaxis.label.set_color('red') + ax.zaxis.label.set_color('red') + ax.view_init(elev=elev, azim=azim) + + if outfile: + plt.savefig(outfile)
+ + @staticmethod +
[docs] def _import_occ_libs(): + """ + Private static method to import specific modules from the OCC package. + """ + from OCC.BRepOffsetAPI import BRepOffsetAPI_ThruSections + from OCC.gp import gp_Pnt + from OCC.TColgp import TColgp_HArray1OfPnt + from OCC.GeomAPI import GeomAPI_Interpolate + from OCC.BRepBuilderAPI import BRepBuilderAPI_MakeVertex,\ + BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire + + # Set the imported modules as global variables to be used out of scope + global BRepOffsetAPI_ThruSections, gp_Pnt, TColgp_HArray1OfPnt,\ + GeomAPI_Interpolate, BRepBuilderAPI_MakeVertex,\ + BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire
+ +
[docs] def _generate_upper_face(self, maxDeg): + """ + Private method to generate the blade upper face. + + :param int maxDeg: Define the maximal U degree of generated surface + """ + self._import_occ_libs() + # Initializes ThruSections algorithm for building a shell passing + # through a set of sections (wires). The generated faces between + # the edges of every two consecutive wires are smoothed out with + # a precision criterion = 1e-10 + generator = BRepOffsetAPI_ThruSections(False, False, 1e-10) + generator.SetMaxDegree(maxDeg) + # Define upper edges (wires) for the face generation + for i in range(self.n_sections): + npoints = len(self.blade_coordinates_up[i][0]) + vertices = TColgp_HArray1OfPnt(1, npoints) + for j in range(npoints): + vertices.SetValue( + j + 1, + gp_Pnt(1000 * self.blade_coordinates_up[i][0][j], + 1000 * self.blade_coordinates_up[i][1][j], + 1000 * self.blade_coordinates_up[i][2][j])) + # Initializes an algorithm for constructing a constrained + # BSpline curve passing through the points of the blade i-th + # section, with tolerance = 1e-9 + bspline = GeomAPI_Interpolate(vertices.GetHandle(), False, 1e-9) + bspline.Perform() + edge = BRepBuilderAPI_MakeEdge(bspline.Curve()).Edge() + if i == 0: + bound_root_edge = edge + # Add BSpline wire to the generator constructor + generator.AddWire(BRepBuilderAPI_MakeWire(edge).Wire()) + # Returns the shape built by the shape construction algorithm + generator.Build() + # Returns the Face generated by each edge of the first section + self.generated_upper_face = generator.GeneratedFace(bound_root_edge)
+ +
[docs] def _generate_lower_face(self, maxDeg): + """ + Private method to generate the blade lower face. + + :param int maxDeg: Define the maximal U degree of generated surface + """ + self._import_occ_libs() + # Initializes ThruSections algorithm for building a shell passing + # through a set of sections (wires). The generated faces between + # the edges of every two consecutive wires are smoothed out with + # a precision criterion = 1e-10 + generator = BRepOffsetAPI_ThruSections(False, False, 1e-10) + generator.SetMaxDegree(maxDeg) + # Define upper edges (wires) for the face generation + for i in range(self.n_sections): + npoints = len(self.blade_coordinates_down[i][0]) + vertices = TColgp_HArray1OfPnt(1, npoints) + for j in range(npoints): + vertices.SetValue( + j + 1, + gp_Pnt(1000 * self.blade_coordinates_down[i][0][j], + 1000 * self.blade_coordinates_down[i][1][j], + 1000 * self.blade_coordinates_down[i][2][j])) + # Initializes an algorithm for constructing a constrained + # BSpline curve passing through the points of the blade i-th + # section, with tolerance = 1e-9 + bspline = GeomAPI_Interpolate(vertices.GetHandle(), False, 1e-9) + bspline.Perform() + edge = BRepBuilderAPI_MakeEdge(bspline.Curve()).Edge() + if i == 0: + bound_root_edge = edge + # Add BSpline wire to the generator constructor + generator.AddWire(BRepBuilderAPI_MakeWire(edge).Wire()) + # Returns the shape built by the shape construction algorithm + generator.Build() + # Returns the Face generated by each edge of the first section + self.generated_lower_face = generator.GeneratedFace(bound_root_edge)
+ +
[docs] def _generate_tip(self, maxDeg): + """ + Private method to generate the surface that closing the blade tip. + + :param int maxDeg: Define the maximal U degree of generated surface + """ + self._import_occ_libs() + + generator = BRepOffsetAPI_ThruSections(False, False, 1e-10) + generator.SetMaxDegree(maxDeg) + # npoints_up == npoints_down + npoints = len(self.blade_coordinates_down[-1][0]) + vertices_1 = TColgp_HArray1OfPnt(1, npoints) + vertices_2 = TColgp_HArray1OfPnt(1, npoints) + for j in range(npoints): + vertices_1.SetValue( + j + 1, + gp_Pnt(1000 * self.blade_coordinates_down[-1][0][j], + 1000 * self.blade_coordinates_down[-1][1][j], + 1000 * self.blade_coordinates_down[-1][2][j])) + + vertices_2.SetValue( + j + 1, + gp_Pnt(1000 * self.blade_coordinates_up[-1][0][j], + 1000 * self.blade_coordinates_up[-1][1][j], + 1000 * self.blade_coordinates_up[-1][2][j])) + + # Initializes an algorithm for constructing a constrained + # BSpline curve passing through the points of the blade last + # section, with tolerance = 1e-9 + bspline_1 = GeomAPI_Interpolate(vertices_1.GetHandle(), False, 1e-9) + bspline_1.Perform() + + bspline_2 = GeomAPI_Interpolate(vertices_2.GetHandle(), False, 1e-9) + bspline_2.Perform() + + edge_1 = BRepBuilderAPI_MakeEdge(bspline_1.Curve()).Edge() + edge_2 = BRepBuilderAPI_MakeEdge(bspline_2.Curve()).Edge() + + # Add BSpline wire to the generator constructor + generator.AddWire(BRepBuilderAPI_MakeWire(edge_1).Wire()) + generator.AddWire(BRepBuilderAPI_MakeWire(edge_2).Wire()) + # Returns the shape built by the shape construction algorithm + generator.Build() + # Returns the Face generated by each edge of the first section + self.generated_tip = generator.GeneratedFace(edge_1)
+ +
[docs] def _write_blade_errors(self, upper_face, lower_face, errors): + """ + Private method to write the errors between the generated foil points in + 3D space from the parametric transformations, and their projections on + the generated blade faces from the OCC algorithm. + + :param string upper_face: if string is passed then the method generates + the blade upper surface using the BRepOffsetAPI_ThruSections + algorithm, then exports the generated CAD into .iges file holding + the name <upper_face_string>.iges + :param string lower_face: if string is passed then the method generates + the blade lower surface using the BRepOffsetAPI_ThruSections + algorithm, then exports the generated CAD into .iges file holding + the name <lower_face_string>.iges + :param string errors: if string is passed then the method writes out + the distances between each discrete point used to construct the + blade and the nearest point on the CAD that is perpendicular to + that point + """ + from OCC.gp import gp_Pnt + from OCC.BRepBuilderAPI import BRepBuilderAPI_MakeVertex + from OCC.BRepExtrema import BRepExtrema_DistShapeShape + + output_string = '\n' + with open(errors + '.txt', 'w') as f: + if upper_face: + output_string += '########## UPPER FACE ##########\n\n' + output_string += 'N_section\t\tN_point\t\t\tX_crds\t\t\t\t' + output_string += 'Y_crds\t\t\t\t\tZ_crds\t\t\t\t\tDISTANCE' + output_string += '\n\n' + for i in range(self.n_sections): + alength = len(self.blade_coordinates_up[i][0]) + for j in range(alength): + vertex = BRepBuilderAPI_MakeVertex( + gp_Pnt( + 1000 * self.blade_coordinates_up[i][0][j], + 1000 * self.blade_coordinates_up[i][1][j], 1000 + * self.blade_coordinates_up[i][2][j])).Vertex() + projection = BRepExtrema_DistShapeShape( + self.generated_upper_face, vertex) + projection.Perform() + output_string += str( + i) + '\t\t\t' + str(j) + '\t\t\t' + str( + 1000 * + self.blade_coordinates_up[i][0][j]) + '\t\t\t' + output_string += str( + 1000 * self.blade_coordinates_up[i][1] + [j]) + '\t\t\t' + str( + 1000 * self.blade_coordinates_up[i][2] + [j]) + '\t\t\t' + str(projection.Value()) + output_string += '\n' + + if lower_face: + output_string += '########## LOWER FACE ##########\n\n' + output_string += 'N_section\t\tN_point\t\t\tX_crds\t\t\t\t' + output_string += 'Y_crds\t\t\t\t\tZ_crds\t\t\t\t\tDISTANCE' + output_string += '\n\n' + for i in range(self.n_sections): + alength = len(self.blade_coordinates_down[i][0]) + for j in range(alength): + vertex = BRepBuilderAPI_MakeVertex( + gp_Pnt( + 1000 * self.blade_coordinates_down[i][0][j], + 1000 * self.blade_coordinates_down[i][1][j], + 1000 * + self.blade_coordinates_down[i][2][j])).Vertex() + projection = BRepExtrema_DistShapeShape( + self.generated_lower_face, vertex) + projection.Perform() + output_string += str( + i) + '\t\t\t' + str(j) + '\t\t\t' + str( + 1000 * + self.blade_coordinates_down[i][0][j]) + '\t\t\t' + output_string += str( + 1000 * self.blade_coordinates_down[i][1] + [j]) + '\t\t\t' + str( + 1000 * self.blade_coordinates_down[i][2] + [j]) + '\t\t\t' + str(projection.Value()) + output_string += '\n' + f.write(output_string)
+ +
[docs] def generate_iges(self, + upper_face=None, + lower_face=None, + tip=None, + maxDeg=1, + display=False, + errors=None): + """ + Generate and export the .iges CAD for the blade upper face, lower face, + and tip. This method requires PythonOCC to be installed. + + :param string upper_face: if string is passed then the method generates + the blade upper surface using the BRepOffsetAPI_ThruSections + algorithm, then exports the generated CAD into .iges file holding + the name <upper_face_string>.iges. Default value is None + :param string lower_face: if string is passed then the method generates + the blade lower surface using the BRepOffsetAPI_ThruSections + algorithm, then exports the generated CAD into .iges file holding + the name <lower_face_string>.iges. Default value is None + :param string tip: if string is passed then the method generates + the blade tip using the BRepOffsetAPI_ThruSections algorithm + in order to close the blade, then exports the generated CAD into + .iges file holding the name <tip_string>.iges. Default value is None + :param int maxDeg: Define the maximal U degree of generated surface. + Default value is 1 + :param bool display: if True, then display the generated CAD. Default + value is False + :param string errors: if string is passed then the method writes out + the distances between each discrete point used to construct the + blade and the nearest point on the CAD that is perpendicular to + that point. Default value is None + + We note that the blade object must have its radial sections be arranged + in order from the blade root to the blade tip, so that generate_iges + method can build the CAD surface that passes through the corresponding + airfoils. Also to be able to identify and close the blade tip. + """ + + from OCC.IGESControl import IGESControl_Writer + from OCC.Display.SimpleGui import init_display + + if maxDeg <= 0: + raise ValueError('maxDeg argument must be a positive integer.') + + if upper_face: + self._check_string(filename=upper_face) + self._generate_upper_face(maxDeg=maxDeg) + # Write IGES + iges_writer = IGESControl_Writer() + iges_writer.AddShape(self.generated_upper_face) + iges_writer.Write(upper_face + '.iges') + + if lower_face: + self._check_string(filename=lower_face) + self._generate_lower_face(maxDeg=maxDeg) + # Write IGES + iges_writer = IGESControl_Writer() + iges_writer.AddShape(self.generated_lower_face) + iges_writer.Write(lower_face + '.iges') + + if tip: + self._check_string(filename=tip) + self._generate_tip(maxDeg=maxDeg) + iges_writer = IGESControl_Writer() + iges_writer.AddShape(self.generated_tip) + iges_writer.Write(tip + '.iges') + + if errors: + # Write out errors between discrete points and constructed faces + self._check_string(filename=errors) + self._check_errors(upper_face=upper_face, lower_face=lower_face) + + self._write_blade_errors( + upper_face=upper_face, lower_face=lower_face, errors=errors) + + if display: + display, start_display, add_menu, add_function_to_menu = init_display( + ) + + ## DISPLAY FACES + if upper_face: + display.DisplayShape(generated_upper_face, update=True) + if lower_face: + display.DisplayShape(generated_lower_face, update=True) + if tip: + display.DisplayShape(generated_tip, update=True) + start_display()
+ +
[docs] def generate_stl(self, min_length=None, max_length=None, outfile_stl=None): + """ + Generate and export the .STL surface mesh for the blade as a whole, + including the upper face, lower face and tip. The method utilizes + modules from OCC SMESH which is standalone mesh framework based on + SALOME mesher project. Please refer to https://github.com/tpaviot + and http://docs.salome-platform.org/7/gui/SMESH/index.html for + further details. + + This method requires PythonOCC and SMESH to be installed. + + :param double min_length: smallest distance between two nodes. Default + value is None + :param double max_length: largest distance between two nodes. Default + value is None + :param string outfile_stl: if string is passed then the method exports + the generated 2D surface mesh into .stl file holding the name + <outfile_stl>.stl. Default value is None + + We note that since the current implementation performs triangulation + based on a topological compound that combines the blade 3 generated + shapes without "fusion", it may happen that the generated triangulation + of the upper and lower blade faces do not share the same exact nodes + on the joint edge/wire resulting from the faces intersection. The + current implementation can be enough for visualization purpose. However + if the generated mesh is intended for computational analysis then a + manual mesh healing is recommended by the user (e.g. see + "Repair > Sewing" in SALOME GUI) for a proper mesh closure. + """ + from OCC.SMESH import SMESH_Gen + from OCC.StdMeshers import ( + StdMeshers_Arithmetic1D, StdMeshers_TrianglePreference, + StdMeshers_Regular_1D, StdMeshers_MEFISTO_2D) + from OCC.BRep import BRep_Builder + from OCC.TopoDS import TopoDS_Shape, TopoDS_Compound + + if min_length <= 0 or max_length <= 0: + raise ValueError('min_length and max_length must be positive.') + if min_length >= max_length: + raise ValueError('min_length can not be greater than max_length') + + # First we check that blade shapes are generated, otherwise we generate + # them. After that we combine the generated_upper_face, + # generated_lower_face, and generated_tip into a topological compound + # that we use to compute the surface mesh + if (self.generated_upper_face is None) or not isinstance( + self.generated_upper_face, TopoDS_Shape): + # Upper face is generated with a maximal U degree = 1 + self._generate_upper_face(maxDeg=1) + if (self.generated_lower_face is None) or not isinstance( + self.generated_lower_face, TopoDS_Shape): + # Upper face is generated with a maximal U degree = 1 + self._generate_lower_face(maxDeg=1) + if (self.generated_tip is None) or not isinstance( + self.generated_tip, TopoDS_Shape): + # Upper face is generated with a maximal U degree = 1 + self._generate_tip(maxDeg=1) + + # Now we regroup all the shapes into a TopoDS_Compound + aCompound = TopoDS_Compound() + aBuilder = BRep_Builder() + aBuilder.MakeCompound(aCompound) + # Add shapes + aBuilder.Add(aCompound, self.generated_upper_face) + aBuilder.Add(aCompound, self.generated_lower_face) + aBuilder.Add(aCompound, self.generated_tip) + + # In the following we build the surface mesh according to the given + # hypotheses + aMeshGen = SMESH_Gen() + aMesh = aMeshGen.CreateMesh(0, True) + # Adding 1D hypothesis and algorithms + # Wire discretization. Nodes are distributed based on Arithmetic1D + # hypothesis which allows to split edges into segments with a length + # that changes in arithmetic progression (Lk = Lk-1 + d) beginning + # from a given min length and up to a given max length. More about + # 1D hypotheses can be viewed through: + # http://docs.salome-platform.org/7/gui/SMESH/a1d_meshing_hypo_page.html + an1DHypothesis = StdMeshers_Arithmetic1D(0, 0, aMeshGen) + # Smallest distance between 2 points + an1DHypothesis.SetLength(min_length, False) + # Longest distance between 2 points + an1DHypothesis.SetLength(max_length, True) + # Regular Interpolation + an1DAlgo = StdMeshers_Regular_1D(1, 0, aMeshGen) + # Adding 2D hypothesis and algorithms + # 2D surface mesh -- Triangulations + a2dHypothseis = StdMeshers_TrianglePreference(2, 0, aMeshGen) + a2dAlgo = StdMeshers_MEFISTO_2D(3, 0, aMeshGen) + + #Calculate mesh for the topological compound containing the 3 shapes + aMesh.ShapeToMesh(aCompound) + + #Assign hyptothesis to mesh + aMesh.AddHypothesis(aCompound, 0) + aMesh.AddHypothesis(aCompound, 1) + aMesh.AddHypothesis(aCompound, 2) + aMesh.AddHypothesis(aCompound, 3) + + if outfile_stl is not None: + if not isinstance(outfile_stl, str): + raise ValueError('outfile_stl must be a valid string.') + + #Compute the data + aMeshGen.Compute(aMesh, aMesh.GetShapeToMesh()) + # Export STL + aMesh.ExportSTL(outfile_stl + '.stl', False)
+ + @staticmethod +
[docs] def _check_string(filename): + """ + Private method to check if the parameter type is string + + :param string filename: filename of the generated .iges surface + """ + if not isinstance(filename, str): + raise TypeError('IGES filename must be a valid string.')
+ + @staticmethod +
[docs] def _check_errors(upper_face, lower_face): + """ + Private method to check if either the blade upper face or lower face + is passed in the generate_iges method. Otherwise it raises an exception + + :param string upper_face: blade upper face. + :param string lower_face: blade lower face. + """ + if not (upper_face or lower_face): + raise ValueError( + 'Either upper_face or lower_face must not be None.')
+ +
[docs] def _abs_to_norm(self, D_prop): + """ + Private method to normalize the blade parameters. + + :param float D_prop: propeller diameter + """ + self.radii = self.radii * 2. / D_prop + self.chord_lengths = self.chord_lengths / D_prop + self.pitch = self.pitch / D_prop + self.rake = self.rake / D_prop
+ +
[docs] def _norm_to_abs(self, D_prop): + """ + Private method that converts the normalized blade parameters into the + actual values. + + :param float D_prop: propeller diameter + """ + self.radii = self.radii * D_prop / 2. + self.chord_lengths = self.chord_lengths * D_prop + self.pitch = self.pitch * D_prop + self.rake = self.rake * D_prop
+ +
[docs] def export_ppg(self, + filename='data_out.ppg', + D_prop=0.25, + D_hub=0.075, + n_blades=5, + params_normalized=False): + """ + Export the generated blade parameters and sectional profiles into + .ppg format. + + :param string filename: name of the exported file. Default is + 'data/data_out.ppg' + :param float D_prop: propeller diameter + :param float D_hub: hub diameter + :param float n_blades: number of blades + :param bool params_normalized: since the standard .ppg format contains + the blade parameters in the normalized form, therefore the user + needs to inform whether the provided parameters (from the class + Blade) are normalized or not. By default the argument is set to + False, which assumes the user provides the blade parameters in + their actual values, i.e. not normalized, hence a normalization + operation needs to be applied so as to follow the .ppg standard + format. + """ + thickness = np.zeros(self.n_sections) + camber = np.zeros(self.n_sections) + for i, section in enumerate(self.sections): + # Evaluate maximum profile thickness and camber for each section. + # We assume at the current step, that sectional profiles already + # have the coordinates (x_up,x_down) normalized by chord length (C) + # and subsequently (y_up,y_down) are also scaled. This implies that + # the computed thickness and camber are given in their normalized + # form, i.e. thickness=t/C and camber=f/C. + thickness[i] = section.max_thickness() + camber[i] = section.max_camber() + + if params_normalized is False: + # Put the parameters (radii, chord, pitch, rake) in the normalized + # form. + self._abs_to_norm(D_prop=D_prop) + + output_string = "" + output_string += 'propeller id = SVA\n' + output_string += 'propeller diameter = ' + str(D_prop) + '\n' + output_string += 'hub diameter = ' + str(D_hub) + '\n' + output_string += 'number of blades = ' + str(n_blades) + '\n' + output_string += "'Elica PPTC workshop'\n" + output_string += 'number of radial sections = ' + str( + self.n_sections) + '\n' + output_string += 'number of radial sections = ' + str( + self.n_sections) + '\n' + output_string += 'number of sectional profiles = ' + str( + self.n_sections) + '\n' + output_string += 'description of sectional profiles = BNF\n' + output_string += ' r/R c/D skew[deg]'\ + ' rake/D P/D t/C'\ + ' f/C\n' + for i in range(self.n_sections): + output_string += ' ' + str("%.8e" % self.radii[i]) + ' ' + str( + "%.8e" % self.chord_lengths[i]) + ' ' + str( + "%.8e" % self.skew_angles[i]) + ' ' + str( + "%.8e" % self.rake[i]) + output_string += ' ' + str("%.8e" % self.pitch[i]) + ' ' + str( + "%.8e" % thickness[i]) + ' ' + str("%.8e" % camber[i]) + '\n' + + for i in range(self.n_sections): + output_string += str("%.8e" % self.radii[i]) + ' ' + str( + len(self.sections[i].xup_coordinates)) + '\n' + + for value in self.sections[i].xup_coordinates: + output_string += ' ' + str("%.8e" % value) + output_string += ' \n' + for value in self.sections[i].yup_coordinates: + output_string += ' ' + str("%.8e" % value) + output_string += ' \n' + for value in self.sections[i].ydown_coordinates: + output_string += ' ' + str("%.8e" % value) + output_string += ' \n' + + hub_offsets = np.asarray( + [[-3.0, 0.305], [-0.57, 0.305], [-0.49, 0.305], [-0.41, 0.305], + [-0.33, 0.305], [-0.25, 0.305], [-0.17, 0.305], [0.23, 0.305], + [0.31, 0.285], [0.39, 0.2656], [0.47, 0.2432], [0.55, 0.2124], + [0.63, 0.1684], [0.71, 0.108], [0.79, 0.0]]) + + output_string += 'number of Hub offsets = ' + str( + len(hub_offsets)) + '\n' + + for i, offset in enumerate(hub_offsets): + if i == len(hub_offsets) - 1: + output_string += str("%.8e" % offset[0]) + ' ' + str( + "%.8e" % hub_offsets[i][1]) + continue + output_string += str("%.8e" % offset[0]) + ' ' + str( + "%.8e" % offset[1]) + '\n' + + with open(filename, 'w') as f: + f.write(output_string) + + if params_normalized is False: + # Revert back normalized parameters into actual values. + self._norm_to_abs(D_prop=D_prop)
+ + def __str__(self): + """ + This method prints all the parameters on the screen. Its purpose is + for debugging. + """ + string = '' + string += 'Blade number of sections = {}'.format(self.n_sections) + string += '\nBlade radii sections = {}'.format(self.radii) + string += '\nChord lengths of the sectional profiles'\ + ' = {}'.format(self.chord_lengths) + string += '\nRadial distribution of the pitch (in unit lengths)'\ + ' = {}'.format(self.pitch) + string += '\nRadial distribution of the rake (in unit length)'\ + ' = {}'.format(self.rake) + string += '\nRadial distribution of the skew angles'\ + ' (in degrees) = {}'.format(self.skew_angles) + string += '\nPitch angles (in radians) for the'\ + ' sections = {}'.format(self.pitch_angles) + string += '\nInduced rake from skew (in unit length)'\ + ' for the sections = {}'.format(self.induced_rake) + return string
+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/bladex/deform.html b/_modules/bladex/deform.html new file mode 100644 index 0000000..b170242 --- /dev/null +++ b/_modules/bladex/deform.html @@ -0,0 +1,727 @@ + + + + + + + + + + + bladex.deform — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+
+ +

Source code for bladex.deform

+"""
+Module to deform blade's parameters, based on a given parameter file.
+"""
+
+import numpy as np
+import matplotlib.pyplot as plt
+from .ndinterpolator import reconstruct_f, scipy_bspline
+from .params import ParamFile
+
+
+
[docs]class Deformation(object): + """ + Deform parameter curves {chord, pitch, rake, skew, camber} according to + specific information passed through a parameter file. + + The module contains several methods that are able to: + + 1. compute coordinates of the optimal control points, provided their + number from the parameter file. + + 2. update control points Y coordinates, provided the magnitude of the + Y deformation from the parameter file. + + 3. generate B-spline curve using the computed control points (before or + after their deformation), provided npoints from the parameter file + for spline estimation. + + 4. plot parametric curves, with several options. Finally export a new + parameter file containing the new deformed parameters. + + :param str paramfile: parameter file name + :cvar str paramfile: parameter file name + :cvar class param: class object instantiated by the module params, and + contains all the attributes assigned by reading the parameter file. + Possible attributes are: + + - `param.radii` + - `param.parameters` + - `param.nbasis` + - `param.degree` + - `param.deformations` + + First attribute is array defines the radial sections, while the + remaining attributes are dictionaries with possible keys: `chord`, + `pitch`, `rake`, `skew`, `camber`. + + :cvar dict deformed_parameters: dictionary that contains the deformed + parameters at the same radial sections, provided some tolerance due to + the spline interpolation. Possible dictionary keys are the parameters + `chord`, `pitch`, `rake`, `skew`, `camber`. Default value is array of + zeros with length equal to the radial sections. + :cvar dict control_points: dictionary that contains the 2D coordinates of + the control points associated with the B-spline parametric curve. The + dictionary possible keys are the parameters `chord`, `pitch`, `rake`, + `skew`, `camber`. Default value is None + :cvar dict spline: dictionary that contains the B-spline interpolation for + the parametric curves. The dictionary possible keys are the parameters + `chord`, `pitch`, `rake`, `skew`, `camber`. Each value is a 2D numpy + array containing the radii interpolations against the interpolations + for one of the parameters mentioned in the dictionary keys. Default + value is None. + """ + + def __init__(self, paramfile): + self.paramfile = paramfile + self.param = ParamFile() + self.param.read_parameters(filename=paramfile) + self.deformed_parameters = { + 'chord': np.zeros(self.param.radii.size), + 'pitch': np.zeros(self.param.radii.size), + 'rake': np.zeros(self.param.radii.size), + 'skew': np.zeros(self.param.radii.size), + 'camber': np.zeros(self.param.radii.size) + } + self.control_points = { + 'chord': None, + 'pitch': None, + 'rake': None, + 'skew': None, + 'camber': None + } + self.spline = { + 'chord': None, + 'pitch': None, + 'rake': None, + 'skew': None, + 'camber': None + } + + @staticmethod +
[docs] def _optimum_control_points(X, Y, degree, nbasis, rbf_points): + """ + Private static method that computes the optimum coordinates of the + B-spline control points. + + :param array_like X: Array of original points of the parametric curve + X-axis, usually array of the radii sections + :param array_like Y: radial distribution of parameter `chord` or + `pitch` or `rake` or `skew` or `camber`, corresponding to the + radial sections in X + :param int degree: degree of the B-spline construction for the + parametric curve + :param int nbasis: number of control points associated with the + parametric curve + :param int rbf_points: if specified greater than zero, then the X and Y + arrays are interpolated using the Wendland C2 radial basis function + to produce X and Y arrays with length = rbf_points. The larger + number of rbf_points implies better estimation of the optimum + control coordinates. To turn it off (i.e. compute control points + based on original X, Y arrays) then insert 0. (Negative values or + None results in same effect as zero) + :return: control points 2D coordinates + :rtype: numpy.ndarray + """ + if not isinstance(rbf_points, int): + # in case inserted as None, then converts to zero, + # otherwise returns the inserted value. Useful when dealing with + # the parameter as a flag + rbf_points = int(rbf_points or 0) + + if rbf_points > 0: + xx = np.linspace(X[0], X[-1], num=rbf_points) + yy = np.zeros(rbf_points) + reconstruct_f( + original_input=X, + original_output=Y, + rbf_input=xx, + rbf_output=yy, + basis='beckert_wendland_c2_basis', + radius=2.0) + X = xx + Y = yy + + A = np.zeros((len(X), nbasis)) + At = np.zeros((len(X), nbasis - 2)) + + for i in range(nbasis): + cv_new = np.zeros((nbasis, 3)) + cv_new[i, 0] = 1. + # i-th basis function in the reference space + A[:, i] = scipy_bspline(cv_new, A.shape[0], degree)[:, 0] + + # A tilde for the constraints on the first and last point + At = A[:, 1:-1] + # x and y of the ctrl points with constrained least square. + # we subtract the contribution of the first and last basis function + cvt_x = np.linalg.lstsq( + At, X - A[:, 0] * X[0] - A[:, -1] * X[-1], rcond=-1)[0] + cvt_y = np.linalg.lstsq( + At, Y - A[:, 0] * Y[0] - A[:, -1] * Y[-1], rcond=-1)[0] + + # fill with the constraints the first and last point + opt_ctrl = np.zeros((nbasis, 2)) + opt_ctrl[0, 0] = X[0] + opt_ctrl[-1, 0] = X[-1] + opt_ctrl[0, 1] = Y[0] + opt_ctrl[-1, 1] = Y[-1] + opt_ctrl[1:-1, 0] = cvt_x + opt_ctrl[1:-1, 1] = cvt_y + + return opt_ctrl
+ + @staticmethod +
[docs] def _check_param(param): + """ + Private static method that checks the passed parameter. + + :param str param: passed parameter to check. Valid values + are: `chord`, `pitch`, `rake`, `skew`, `camber` + :raises ValueError: if the param value is not one of the previous + """ + params = ['chord', 'pitch', 'rake', 'skew', 'camber'] + if not param in params: + raise ValueError( + 'Valid param values are: "chord", "pitch", "rake", "skew",'\ + ' "camber".')
+ +
[docs] def _check_control_points(self, param): + """ + Private method to check if control points are computed. + + :param str param: passed parameter to check. Valid values + are: `chord`, `pitch`, `rake`, `skew`, `camber` + :raises ValueError: if the control points have None value, i.e. not + computed + """ + if self.control_points[param] is None: + raise ValueError( + 'control_points has None value. You must compute them first.')
+ +
[docs] def _check_spline(self, param): + """ + Private method to check if spline interpolation is computed. + + :param str param: passed parameter to check. Valid values + are: `chord`, `pitch`, `rake`, `skew`, `camber` + :raises ValueError: if the spline of that parameter curve has None + value, i.e. not computed + """ + if self.spline[param] is None: + raise ValueError( + param + ' spline is None. You must first generate spline.')
+ +
[docs] def _check_deformed(self, param): + """ + Private method to check if the deformed parameters are computed. + + :param str param: passed parameter to check. Valid values + are: `chord`, `pitch`, `rake`, `skew`, `camber` + :raises ValueError: if the deformed parameters have array of zeros, + i.e. not computed + """ + if self.deformed_parameters[param].all() == 0: + raise ValueError(param + ' deformed points are not computed.')
+ +
[docs] def compute_control_points(self, param, rbf_points=1000): + """ + Compute the control points 2D coordinates for one of the parametric + curves. + + :param str param: parameter corresponding to the parametric curve. + possible values are `chord`, `pitch`, `rake`, `skew`, `camber` + :param int rbf_points: if greater than zero then the Wendland C2 radial + basis function is used to interpolate the original arrays for the + parametric curve, so that the control points are computed according + to the interpolated arrays. Needless to mention that longer arrays + would produce better estimation of the control points optimum + coordinates. In order to turn off the rbf interpolation: specify + either 0 or -1 (Also a None value can be used too). Default value + is 1000 + """ + self._check_param(param=param) + self.control_points[param] = self._optimum_control_points( + X=self.param.radii, + Y=self.param.parameters[param], + degree=self.param.degree[param], + nbasis=self.param.nbasis[param], + rbf_points=rbf_points)
+ +
[docs] def update_control_points(self, param): + """ + Update the control point Y coordinate with the deformation values + specified in the parameter file. + + :param str param: parameter corresponding to the parametric curve. + possible values are `chord`, `pitch`, `rake`, `skew`, `camber` + """ + self._check_param(param=param) + self._check_control_points(param=param) + + if not self.control_points[param].shape[0] == len( + self.param.deformations[param]): + raise ValueError( + 'array of deformations must equal to number of control points') + + for i in range(self.control_points[param].shape[0]): + self.control_points[param][i, 1] += self.param.deformations[param][ + i]
+ +
[docs] def generate_spline(self, param): + """ + Generate the B-spline interpolations, using the information: `degree`, + `npoints` from the parameter file, as well as the computed 2D + coordinates of the control points. + + :param str param: parameter corresponding to the parametric curve. + possible values are `chord`, `pitch`, `rake`, `skew`, `camber` + """ + self._check_param(param=param) + self._check_control_points(param=param) + + self.spline[param] = scipy_bspline( + cv=self.control_points[param], + npoints=self.param.npoints[param], + degree=self.param.degree[param])
+ +
[docs] def compute_deformed_parameters(self, param, tol=1e-3): + """ + This method uses the spline npoints interpolation of the parametric + curve to extract the parameters corresponding to the radial + distribution of the original undeformed array. Therefore the resulting + deformed parameters should be arrays of same length like that of the + original parameters. + + :param str param: parameter corresponding to the parametric curve. + possible values are `chord`, `pitch`, `rake`, `skew`, `camber` + :param float tol: tolerance required to find the B-spline estimation + within the neighborhood of each of the radii sections. It is + important to specify the value carefully as it depends on the order + of the original array values, as well as the number of points for + the spline interpolations. Default value is 1e-3 + """ + self._check_param(param=param) + self._check_spline(param=param) + + for i, val in enumerate(self.param.radii): + index = np.where(np.fabs(self.spline[param][:, 0] - val) < tol)[0] + if len(index) == 0: + raise ValueError( + 'Could not compute deformed parameter "' + param + + '" at radius "' + str(val) + + '". Either increase the tolerance for that parameter, or'\ + ' increase the spline npoints in the parameter file.' + ) + if index.shape[0] > 1: + # In case more neighbors are found, then take first value only. + index = index[0] + self.deformed_parameters[param][i] = self.spline[param][index, 1]
+ +
[docs] def compute_all(self, + rbf_points=1000, + tol_chord=1e-3, + tol_pitch=1e-3, + tol_rake=1e-3, + tol_skew=1e-3, + tol_camber=1e-3): + """ + Computes everything: + - control points 2D coordinates + - deformed control points + - spline npoints interpolations + - deformed parameters of the original arrays + + The previous procedure is applied for all the parameters: `chord`, + `pitch`, `rake`, `skew`, `camber` + + :param int rbf_points: if greater than zero then the Wendland C2 radial + basis function is used to interpolate the original arrays for the + parametric curve, so that the control points are computed according + to the interpolated arrays. Needless to mention that longer arrays + would produce better estimation of the control points optimum + coordinates. In order to turn off the rbf interpolation then + specify either 0 or -1 (Also a None value can be used too). Default + value is 1000 + :param float tol_chord: tolerance used to extract the chord radial + distribution for the deformed B-spline interpolation. Default value + is 1e-3 + :param float tol_pitch: tolerance used to extract the pitch radial + distribution for the deformed B-spline interpolation. Default value + is 1e-3 + :param float tol_rake: tolerance used to extract the rake radial + distribution for the deformed B-spline interpolation. Default value + is 1e-3 + :param float tol_skew: tolerance used to extract the skew radial + distribution for the deformed B-spline interpolation. Default value + is 1e-3 + :param float tol_camber: tolerance used to extract the camber radial + distribution for the deformed B-spline interpolation. Default value + is 1e-3 + + """ + tols = { + 'chord': tol_chord, + 'pitch': tol_pitch, + 'rake': tol_rake, + 'skew': tol_skew, + 'camber': tol_camber + } + params = ['chord', 'pitch', 'rake', 'skew', 'camber'] + for param in params: + self.compute_control_points(param=param, rbf_points=rbf_points) + self.update_control_points(param=param) + self.generate_spline(param=param) + self.compute_deformed_parameters(param=param, tol=tols[param])
+ +
[docs] def _plot_parametric_curve(self, + param, + original=True, + ctrl_points=True, + spline=True, + rbf=False, + rbf_points=500, + deformed=False, + outfile=None): + """ + Private method to plot the parametric curve. Several options + can be specified. + + :param str param: parameter corresponding to the parametric curve + needs to be plotted. possible values are `chord`, `pitch`, `rake`, + `skew`, `camber` + :param bool original: if True, then plot the original points of the + parameter at the radii sections. + :param bool ctrl_points: if True, then plot the control points of + that parametric curve. + :param bool spline: If True, then plot the B-spline interpolation of + the parametric curve. + :param bool rbf: if True, then plot the radial basis functions + interpolation of the parametric curve. + :param int rbf_points: number of points used for the rbf interpolation, + if the flag `rbf` is set True. Beware that this argument does not + have the same function of that when computing the control points, + although both uses the radial basis function interpolation with + the Wendland basis. + :param bool deformed: if True, then plot the deformed points of the + parameter radial distribution, estimated using the B-spline + interpolations within a given tolerance. + :param str outfile: if string is passed, then the plot is saved + with that name. If the value is None, then the plot is shown on + the screen. + """ + self._check_param(param=param) + + plt.figure() + + if original: + plt.plot( + self.param.radii, + self.param.parameters[param], + 'o', + label='original points') + + if ctrl_points: + self._check_control_points(param=param) + plt.plot( + self.control_points[param][:, 0], + self.control_points[param][:, 1], + '*-', + label='control points') + + if spline: + self._check_spline(param=param) + plt.plot( + self.spline[param][:, 0], + self.spline[param][:, 1], + label='spline') + + if rbf: + xx = np.linspace( + self.param.radii[0], self.param.radii[-1], num=rbf_points) + yy = np.zeros(rbf_points) + reconstruct_f( + original_input=self.param.radii, + original_output=self.param.parameters[param], + rbf_input=xx, + rbf_output=yy, + basis='beckert_wendland_c2_basis', + radius=2.0) + plt.plot(xx, yy, label='rbf') + + if deformed: + self._check_deformed(param=param) + plt.plot( + self.param.radii, + self.deformed_parameters[param], + '+', + label='deformed points') + + plt.grid(linestyle='dotted') + plt.title(param + ' curve') + plt.legend() + + if outfile: + if not isinstance(outfile, str): + raise ValueError('Output file name must be string.') + plt.savefig(outfile) + else: + plt.show()
+ +
[docs] def plot(self, + param, + original=True, + ctrl_points=True, + spline=True, + rbf=False, + rbf_points=500, + deformed=False, + outfile=None): + """ + Plot the parametric curve. Several options + can be specified. + + :param array_like param: array_like of strings corresponding to the + parametric curve that needs to be plotted. possible values are + `chord`, `pitch`, `rake`, `skew`, `camber` + :param bool original: if True, then plot the original points of the + parameter at the radii sections. Default value is True + :param bool ctrl_points: if True, then plot the control points of + that parametric curve. Default value is True + :param bool spline: If True, then plot the B-spline interpolation of + the parametric curve. Default value is True + :param bool rbf: if True, then plot the radial basis functions + interpolation of the parametric curve. Default value is True + :param int rbf_points: number of points used for the rbf interpolation, + if the flag `rbf` is set True. Beware that this argument does not + have the same function of that when computing the control points, + although both uses the radial basis function interpolation with + the Wendland basis. Default value is 500 + :param bool deformed: if True, then plot the deformed points of the + parameter radial distribution, estimated using the B-spline + interpolations within a given tolerance. Default value is False + :param str outfile: if string is passed, then the plot is saved + with that name. If the value is None, then the plot is shown on + the screen. Default value is None + """ + if not isinstance(param, (list, tuple, np.ndarray)): + param = [param] + + for par in param: + self._plot_parametric_curve( + param=par, + original=original, + ctrl_points=ctrl_points, + spline=spline, + rbf=rbf, + rbf_points=rbf_points, + deformed=deformed, + outfile=outfile)
+ +
[docs] def export_param_file(self, outfile='parameters_mod.prm'): + """ + Export a new parameter file with the new deformed parameters, while + all other values are kept the same as in the original parameter file + with the undeformed parameters. In the new parameter file (i.e. with + deformed parameters) the deformations arrays become array of zeros. + + :param str outfile: file name to be written out + """ + + prm = ParamFile() + prm.radii = self.param.radii + params = ['chord', 'pitch', 'rake', 'skew', 'camber'] + for param in params: + if np.all(self.param.deformations[param] == 0): + prm.parameters[param] = self.param.parameters[param] + else: + prm.parameters[param] = self.deformed_parameters[param] + prm.nbasis[param] = self.param.nbasis[param] + prm.degree[param] = self.param.nbasis[param] + prm.npoints[param] = self.param.npoints[param] + prm.deformations[param] = np.zeros(self.param.nbasis[param]) + + prm.write_parameters(filename=outfile)
+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/bladex/ndinterpolator.html b/_modules/bladex/ndinterpolator.html new file mode 100644 index 0000000..c83c101 --- /dev/null +++ b/_modules/bladex/ndinterpolator.html @@ -0,0 +1,466 @@ + + + + + + + + + + + bladex.ndinterpolator — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+
+ +

Source code for bladex.ndinterpolator

+import numpy as np
+from scipy.spatial.distance import cdist
+from scipy.interpolate import splev
+
+
+
[docs]class RBF(object): + """ + .. _ndinterpolator-label: + + RBF ndinterpolator + ====================== + + Module focused on the implementation of the Radial Basis Functions + interpolation technique. This technique is still based on the use of + a set of parameters, the so-called control points, as for FFD, but RBF + is interpolatory. Another important key point of RBF strategy relies in + the way we can locate the control points: in fact, instead of FFD where + control points need to be placed inside a regular lattice, with RBF we + havo no more limitations. So we have the possibility to perform localized + control points refiniments. + + :Theoretical Insight: + As reference please consult M.D. Buhmann, Radial Basis Functions, + volume 12 of Cambridge monographs on applied and computational + mathematics. Cambridge University Press, UK, 2003. This implementation + follows D. Forti and G. Rozza, Efficient geometrical parametrization + techniques of interfaces for reduced order modelling: application to + fluid-structure interaction coupling problems, International Journal + of Computational Fluid Dynamics. + + RBF shape parametrization technique is based on the definition of a map + :math:`\\mathcal{M}(\\boldsymbol{x}) : \\mathbb{R}^n \\rightarrow + \\mathbb{R}^n`, that allows the possibility of transferring data across + non-matching grids and facing the dynamic mesh handling. The map + introduced is defines as follows + + .. math:: + \\mathcal{M}(\\boldsymbol{x}) = p(\\boldsymbol{x}) + + \\sum_{i=1}^{\\mathcal{N}_C} \\gamma_i + \\varphi(\\| \\boldsymbol{x} - \\boldsymbol{x_{C_i}} \\|) + + where :math:`p(\\boldsymbol{x})` is a low_degree polynomial term, + :math:`\\gamma_i` is the weight, corresponding to the a-priori selected + :math:`\\mathcal{N}_C` control points, associated to the :math:`i`-th + basis function, and :math:`\\varphi(\\| \\boldsymbol{x} - + \\boldsymbol{x_{C_i}} \\|)` a radial function based on the Euclidean + distance between the control points position :math:`\\boldsymbol{x_{C_i}}` + and :math:`\\boldsymbol{x}`. A radial basis function, generally, is a + real-valued function whose value depends only on the distance from the + origin, so that :math:`\\varphi(\\boldsymbol{x}) = \\tilde{\\varphi}( + \\|\\boldsymbol{x} \\|)`. + + The matrix version of the formula above is: + + .. math:: + \\mathcal{M}(\\boldsymbol{x}) = \\boldsymbol{c} + + \\boldsymbol{Q}\\boldsymbol{x} + + \\boldsymbol{W^T}\\boldsymbol{d}(\\boldsymbol{x}) + + The idea is that after the computation of the weights and the + polynomial terms from the coordinates of the control points before and + after the deformation, we can deform all the points of the mesh + accordingly. Among the most common used radial basis functions for + modelling 2D and 3D shapes, we consider Gaussian splines, Multi- + uadratic biharmonic splines, Inverted multi-quadratic biharmonic + splines, Thin-plate splines, Beckert and Wendland :math:`C^2` basis all + defined and implemented below. + + :param string basis: RBF basis function + :param float radius: cut-off radius + + """ + + def __init__(self, basis, radius): + self.bases = { + 'gaussian_spline': + self.gaussian_spline, + 'multi_quadratic_biharmonic_spline': + self.multi_quadratic_biharmonic_spline, + 'inv_multi_quadratic_biharmonic_spline': + self.inv_multi_quadratic_biharmonic_spline, + 'thin_plate_spline': + self.thin_plate_spline, + 'beckert_wendland_c2_basis': + self.beckert_wendland_c2_basis + } + + if basis in self.bases: + self.basis = self.bases[basis] + else: + raise NameError( + """The name of the basis function is not correct. Check + the documentation for all the available functions.""") + + self.radius = radius + + # The following static methods are the implementations + # of the most common radial basis functions + @staticmethod +
[docs] def gaussian_spline(X, r): + """ + It implements the following formula: + + .. math:: + \\varphi(\\| \\boldsymbol{x} \\|) = + e^{-\\frac{\\| \\boldsymbol{x} \\|^2}{r^2}} + + :param numpy.ndarray X: l2-norm between given inputs of a function + and the locations to perform rbf approximation to that function. + :param float r: smoothing length, also called the cut-off radius. + + :return: result: the result of the formula above. + :rtype: float + """ + return np.exp(-(X * X) / (r * r))
+ + @staticmethod +
[docs] def multi_quadratic_biharmonic_spline(X, r): + """ + It implements the following formula: + + .. math:: + \\varphi(\\| \\boldsymbol{x} \\|) = + \\sqrt{\\| \\boldsymbol{x} \\|^2 + r^2} + + :param numpy.ndarray X: l2-norm between given inputs of a function + and the locations to perform rbf approximation to that function. + :param float r: smoothing length, also called the cut-off radius. + + :return: result: the result of the formula above. + :rtype: float + """ + return np.sqrt((X * X) + (r * r))
+ + @staticmethod +
[docs] def inv_multi_quadratic_biharmonic_spline(X, r): + """ + It implements the following formula: + + .. math:: + \\varphi(\\| \\boldsymbol{x} \\|) = + (\\| \\boldsymbol{x} \\|^2 + r^2 )^{-\\frac{1}{2}} + + :param numpy.ndarray X: l2-norm between given inputs of a function + and the locations to perform rbf approximation to that function. + :param float r: smoothing length, also called the cut-off radius. + + :return: result: the result of the formula above. + :rtype: float + """ + return 1.0 / (np.sqrt((X * X) + (r * r)))
+ + @staticmethod +
[docs] def thin_plate_spline(X, r): + """ + It implements the following formula: + + .. math:: + \\varphi(\\| \\boldsymbol{x} \\|) = + \\left\\| \\frac{\\boldsymbol{x} }{r} \\right\\|^2 + \\ln \\left\\| \\frac{\\boldsymbol{x} }{r} \\right\\| + + :param numpy.ndarray X: l2-norm between given inputs of a function + and the locations to perform rbf approximation to that function. + :param float r: smoothing length, also called the cut-off radius. + + :return: result: the result of the formula above. + :rtype: float + """ + arg = X / r + result = arg * arg + result = np.where(arg > 0, result * np.log(arg), result) + return result
+ + @staticmethod +
[docs] def beckert_wendland_c2_basis(X, r): + """ + It implements the following formula: + + .. math:: + \\varphi(\\| \\boldsymbol{x} \\|) = + \\left( 1 - \\frac{\\| \\boldsymbol{x} \\|}{r} \\right)^4 + + \\left( 4 \\frac{\\| \\boldsymbol{x} \\|}{r} + 1 \\right) + + :param numpy.ndarray X: l2-norm between given inputs of a function + and the locations to perform rbf approximation to that function. + :param float r: smoothing length, also called the cut-off radius. + + :return: result: the result of the formula above. + :rtype: float + """ + arg = X / r + first = np.where((1 - arg) > 0, np.power((1 - arg), 4), 0) + second = (4 * arg) + 1 + return first * second
+ +
[docs] def weights_matrix(self, X1, X2): + """ + This method returns the following matrix: + + .. math:: + \\boldsymbol{D_{ij}} = \\varphi(\\| \\boldsymbol{x_i} - + \\boldsymbol{y_j} \\|) + + :param numpy.ndarray X1: the vector x in the formula above. + :param numpy.ndarray X2: the vector y in the formula above. + + :return: matrix: the matrix D. + :rtype: numpy.ndarray + """ + if X1.size == X1.shape[0]: + X1 = X1.reshape(-1, 1) + if X2.size == X2.shape[0]: + X2 = X2.reshape(-1, 1) + return self.basis(cdist(X1, X2), self.radius)
+ + +
[docs]def reconstruct_f(original_input, original_output, rbf_input, rbf_output, basis, + radius): + """ + Reconstruct a function by using the radial basis function approximations. + + :param array_like original_input: the original values of function inputs. + :param array_like original_output: the original values of function output. + :param array_like rbf_input: the input data for RBF approximation. + :param array_like rbf_output: the array elements to be updated with the RBF + interpolated outputs after the approximation. + :param string basis: radial basis function. + :param float radius: smoothing length, also called the cut-off radius. + + :Example: + >>> import numpy as np + >>> from bladex.ndinterpolator import reconstruct_f + >>> x = np.arange(10) + >>> y = np.square(x) + >>> radius = 10 + >>> n_interp = 50 + >>> x_rbf = np.linspace(x[0], x[-1], num=n_interp) + >>> y_rbf = np.zeros(n_interp) + >>> reconstruct_f(original_input=x, original_output=y, rbf_input=x_rbf, + rbf_output=y_rbf, radius=radius, basis='beckert_wendland_c2_basis') + + """ + radial = RBF(basis=basis, radius=radius) + + weights_coeff = np.linalg.solve( + radial.weights_matrix(original_input, original_input), original_output) + + weights_rbf = radial.weights_matrix(rbf_input, original_input) + + for i in range(rbf_input.shape[0]): + for j in range(original_input.shape[0]): + rbf_output[i] += weights_coeff[j] * weights_rbf[i][j]
+ + +
[docs]def scipy_bspline(cv, npoints, degree): + """ + Construct B-Spline curve via the control points. + + :param array_like cv: control points vector (spline coefficients). + :param int npoints: number of points on the curve. + :param int degree: BSpline degree. + """ + c = cv.shape[0] + # calculating BSpline knots + kv = np.clip(np.arange(c+degree+1)-degree, 0, c-degree) + # u is the array of points at which to return the value of the smoothed spline + u = np.linspace(0, c-degree, npoints) + # Calculate resulting spline + # splev requires u, and a tuple which is a sequence of length 3 containing + # the knots, coefficients, and degree of the spline. + return np.array(splev(u, (kv, cv.T, degree))).T
+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/bladex/params.html b/_modules/bladex/params.html new file mode 100644 index 0000000..5d25eb1 --- /dev/null +++ b/_modules/bladex/params.html @@ -0,0 +1,484 @@ + + + + + + + + + + + bladex.params — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+
+ +

Source code for bladex.params

+"""
+Module to read and write a parameter file
+which can be used for parameters deformations.
+"""
+try:
+    import configparser as configparser
+except ImportError:
+    import ConfigParser as configparser
+import os
+import numpy as np
+
+
+
[docs]class ParamFile(object): + """ + Read and Write a parameter file + + :cvar array_like radii: contains radii values of the blade sectional + profiles, starting from the hub. Default value is None + :cvar dict parameters: dictionary that contains the radial distribution + of parameters `chord`, `pitch`, `rake`, `skew`, `camber` at specific + blade sections. Each element of the dictionary is an array_like of + length equals to that of the array radii. Both parameters `chord` and + `camber` descibes the chord length and the camber of the 2D foil + representing the blade section. Possible dictionary keys are `chord`, + `pitch`, `rake`, `skew`, `camber`. Default values are None + :cvar dict nbasis: dictionary that contains number of control points for + each parameter. Possible dictionary keys are: `chord`, `pitch`, `rake`, + `skew`, `camber` + :cvar dict degree: dictionary that contains degree of the BSpline to be + constructed according to the parameter radial distribution. Possible + dictionary keys are: `chord`, `pitch`, `rake`, `skew`, `camber` + :cvar dict npoints: dictionary that contains number of points to be + evaluated using the BSpline interpolation, for each of the parameter + curves. Possible dictionary keys for the parameters are: `chord`, + `pitch`, `rake`, `skew`, `camber` + :cvar dict deformations: dictionary that contains the control points + Y-deformations of the parameter BSpline curve. Possible dictionary + keys are: `chord`, `pitch`, `rake`, `skew`, `camber` + """ + + def __init__(self): + self.radii = None + self.parameters = { + 'chord': None, + 'pitch': None, + 'rake': None, + 'skew': None, + 'camber': None + } + self.nbasis = { + 'chord': 10, + 'pitch': 10, + 'rake': 10, + 'skew': 10, + 'camber': 10 + } + self.degree = { + 'chord': 3, + 'pitch': 3, + 'rake': 3, + 'skew': 3, + 'camber': 3 + } + self.npoints = { + 'chord': 500, + 'pitch': 500, + 'rake': 500, + 'skew': 500, + 'camber': 500 + } + self.deformations = { + 'chord': np.zeros(self.nbasis['chord']), + 'pitch': np.zeros(self.nbasis['chord']), + 'rake': np.zeros(self.nbasis['chord']), + 'skew': np.zeros(self.nbasis['chord']), + 'camber': np.zeros(self.nbasis['chord']) + } + +
[docs] def _check_params(self): + """ + Private method that is called while writing a parameter file. + + 1. The method checks if the user specifies a radii array, otherwise it + raises exception. + + 2. In case no values assigned to any of the remaining parameter arrays + then an array of zeros is assigned, in which its length is equal + to the radii array. + + 3. Any array that is not numpy is converted to be one. Finally, in case + the user specifies the parameter array values but not with same length, + then an exception is raised. + """ + if self.radii is None: + raise ValueError('Array radii can not have a None value.') + + if not isinstance(self.radii, np.ndarray): + self.radii = np.asarray(self.radii) + + for param in ['chord', 'pitch', 'rake', 'skew', 'camber']: + # If any parameter is not inserted then assign that parameter + # with array of zeros. This is useful in case the user is + # interested in only one or few parameters, while not interested + # in (or does have information about) the remaining ones. + if self.parameters[param] is None: + self.parameters[param] = np.zeros(self.radii.shape[0]) + + # In case inserted parameters are not numpy arrays + if not isinstance(self.parameters[param], np.ndarray): + self.parameters[param] = np.asarray(self.parameters[param]) + + # check the case if user inserts inhomogeneous radial distributions + if not self.parameters[param].shape == self.radii.shape: + raise ValueError( + 'Array ' + param + ' must have same shape of array radii.') + + # If inserted deformations array not correspond to nbasis + if not self.nbasis[param] == len(self.deformations[param]): + raise ValueError( + param + ' deformations must correspond to nbasis.')
+ +
[docs] def read_parameters(self, filename='parameters.prm'): + """ + Reads in the parameters file and fill the self structure. + + :param str filename: parameters file to be read in. Default value is + parameters.prm + """ + if not isinstance(filename, str): + raise TypeError('filename must be a string') + + # Checks if the parameters file exists. If not it writes a default + # parameters file with zero deformations for all parameters at uniform + # radial sections. + if not os.path.isfile(filename): + self.radii = np.arange(0.3, 1.1, 0.1) + self.write_parameters(filename=filename) + + config = configparser.RawConfigParser() + config.read(filename) + + radii = config.get('Original parameters', 'Radial sections') + lines = radii.split('\n') + self.radii = np.zeros(len(lines)) + for j, line in enumerate(lines): + if len(line.split()) > 1: + raise ValueError( + 'Radial sections must have single value at each section.') + self.radii[j] = float(line) + + params = ['chord', 'pitch', 'rake', 'skew', 'camber'] + for param in params: + parameters = config.get('Original parameters', + 'Radial distribution of ' + param) + lines = parameters.split('\n') + self.parameters[param] = np.zeros(len(lines)) + for j, line in enumerate(lines): + if len(line.split()) > 1: + raise ValueError( + param + + ' radial distribution must have single value at each'\ + ' radial section.' + ) + self.parameters[param][j] = float(line) + + if not (len(self.radii) == + len(self.parameters['chord']) == + len(self.parameters['pitch']) == + len(self.parameters['rake']) == + len(self.parameters['skew']) == + len(self.parameters['camber'])): + raise ValueError( + 'Arrays "radii", "chord", "pitch", "rake", "skew", "camber"'\ + ' must have same length.' + ) + + section_all = [ + 'Chord B-Spline', 'Pitch B-Spline', 'Rake B-Spline', + 'Skew B-Spline', 'Camber B-Spline' + ] + + for section, param in zip(section_all, params): + self.degree[param] = config.getint(section, 'spline degree') + self.npoints[param] = config.getint(section, 'spline npoints') + self.nbasis[param] = config.getint(section, + 'number of control points') + + deformations = config.get(section, 'control points Y-deformations') + if bool(deformations) is False: + raise ValueError('control points Y-deformations in section [' + + section + '] must be non-empty.') + lines = deformations.split('\n') + self.deformations[param] = np.zeros(len(lines)) + for j, line in enumerate(lines): + if len(line.split()) > 1: + raise ValueError( + 'You can pass only one value for each control point', + ' Y-deformation of the ' + param) + self.deformations[param][j] = float(line) + if not len(self.deformations[param]) == self.nbasis[param]: + raise ValueError(param + ' has nbasis not equal deformations.')
+ +
[docs] def write_parameters(self, filename='parameters.prm'): + """ + This method writes a parameters file (.prm) called `filename` and fills + it with all the parameters class members. Default value is + parameters.prm. + + :param str filename: parameters file to be written out. + :param bool param_pptc: if True, then the parameter arrays are replaced + with that of the benchmark PPTC propeller. + """ + if not isinstance(filename, str): + raise TypeError("filename must be a string") + + self._check_params() + + output_string = "" + + output_string += '\n[Original parameters]\n' + output_string += '# This section describes the radial distributions'\ + ' of the parameters:\n' + output_string += '# "chord lengths", "pitch", "rake", "skew angles",'\ + ' and "camber"\n' + output_string += '# at given radial sections.\n' + + output_string += '\nRadial sections = ' + offset = 1 + for radius in self.radii: + output_string += offset * ' ' + str(radius) + '\n' + offset = 19 + + params = ['chord', 'pitch', 'rake', 'skew', 'camber'] + gaps = [0, 0, 1, 1, -1] + + for param, gap in zip(params, gaps): + offset = 1 + gap + output_string += '\nRadial distribution of ' + param + ' = ' + for parameter in self.parameters[param]: + output_string += offset * ' ' + str(parameter) + '\n' + offset = 32 + + sections = [ + '[Chord B-Spline]', '[Pitch B-Spline]', '[Rake B-Spline]', + '[Skew B-Spline]', '[Camber B-Spline]' + ] + + for section, param in zip(sections, params): + output_string += '\n\n' + section + '\n' + output_string += '# This section describes the B-Spline'\ + ' construction of the RADII -- ' + param.upper() + ' curve.\n' + output_string += '\n# degree of the B-Spline curve\n' + output_string += 'spline degree: {}\n'.format( + str(self.degree[param])) + output_string += '\n# number of points to be evaluated with the'\ + ' B-Spline interpolation\n' + output_string += 'spline npoints: {}\n'.format( + str(self.npoints[param])) + output_string += '\n# number of the control points\n' + output_string += 'number of control points: {}\n'.format( + str(self.nbasis[param])) + output_string += '\n# Y-deformations of the control points.\n' + output_string += 'control points Y-deformations = ' + offset = 1 + for i in range(self.nbasis[param]): + output_string += offset * ' ' + str( + self.deformations[param][i]) + '\n' + offset = 33 + + with open(filename, 'w') as f: + f.write(output_string)
+ +
[docs] def __str__(self): + """ + This method prints all the parameters on the screen. Its purpose is + for debugging. + """ + string = '' + string += 'radii = {}'.format(self.radii) + params = ['chord', 'pitch', 'rake', 'skew', 'camber'] + for param in params: + string += '\n\n' + param + ' = {}'.format(self.parameters[param]) + string += '\n' + param + ' degree = {}'.format( + self.degree[param]) + string += '\n' + param + ' npoints = {}'.format( + self.npoints[param]) + string += '\n' + param + ' nbasis = {}'.format(self.nbasis[param]) + string += '\n' + param + ' control points deformations = ' + string += '{}'.format(self.deformations[param]) + return string
+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/bladex/profilebase.html b/_modules/bladex/profilebase.html new file mode 100644 index 0000000..4166d10 --- /dev/null +++ b/_modules/bladex/profilebase.html @@ -0,0 +1,775 @@ + + + + + + + + + + + bladex.profilebase — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+
+ +

Source code for bladex.profilebase

+"""
+Base module that provides essential tools and transformations on airfoils.
+"""
+
+import numpy as np
+import matplotlib.pyplot as plt
+from .ndinterpolator import reconstruct_f
+
+
+
[docs]class ProfileBase(object): + """ + Base sectional profile of the propeller blade. + + Each sectional profile is a 2D airfoil that is split into two parts: the + upper and lower parts. The coordiates of each part is represented by two + arrays corresponding to the X and Y components in the 2D coordinate system. + Such coordinates can be either generated using NACA functions, or be + inserted directly by the user as custom profiles. + + :param numpy.ndarray xup_coordinates: 1D array that contains the + X-components of the airfoil upper-half surface. Default value is None + :param numpy.ndarray xdown_coordinates: 1D array that contains the + X-components of the airfoil lower-half surface. Default value is None + :param numpy.ndarray yup_coordinates: 1D array that contains the + Y-components of the airfoil upper-half surface. Default value is None + :param numpy.ndarray ydown_coordinates: 1D array that contains the + Y-components of the airfoil lower-half surface. Default value is None + :param numpy.ndarray chord_line: contains the X and Y coordinates of the + straight line joining between the leading and trailing edges. Default + value is None + :param numpy.ndarray camber_line: contains the X and Y coordinates of the + curve passing through all the mid-points between the upper and lower + surfaces of the airfoil. Default value is None + :param numpy.ndarray leading_edge: 2D coordinates of the airfoil's + leading edge. Default values are zeros + :param numpy.ndarray trailing_edge: 2D coordinates of the airfoil's + trailing edge. Default values are zeros + """ + + def __init__(self): + self.xup_coordinates = None + self.xdown_coordinates = None + self.yup_coordinates = None + self.ydown_coordinates = None + self.chord_line = None + self.camber_line = None + self.leading_edge = np.zeros(2) + self.trailing_edge = np.zeros(2) + +
[docs] def _update_edges(self): + """ + Private method that identifies and updates the airfoil's leading and + trailing edges. + + Given the airfoil coordinates from the leading to the trailing edge, + if the trailing edge has a non-zero thickness, then the average value + between the upper and lower trailing edges is taken as the true + trailing edge, hence both the leading and the trailing edges are always + unique. + """ + if np.fabs(self.xup_coordinates[0] - self.xdown_coordinates[0]) > 1e-4: + raise ValueError('Airfoils must have xup_coordinates[0] '\ + 'almost equal to xdown_coordinates[0]') + if np.fabs( + self.xup_coordinates[-1] - self.xdown_coordinates[-1]) > 1e-4: + raise ValueError('Airfoils must have xup_coordinates[-1] '\ + 'almost equal to xdown_coordinates[-1]') + + self.leading_edge[0] = self.xup_coordinates[0] + self.leading_edge[1] = self.yup_coordinates[0] + self.trailing_edge[0] = self.xup_coordinates[-1] + + if self.yup_coordinates[-1] == self.ydown_coordinates[-1]: + self.trailing_edge[1] = self.yup_coordinates[-1] + else: + self.trailing_edge[1] = 0.5 * ( + self.yup_coordinates[-1] + self.ydown_coordinates[-1])
+ +
[docs] def interpolate_coordinates(self, num=500, radius=1.0): + """ + Interpolate the airfoil coordinates from the given data set of + discrete points. + + The interpolation applies the Radial Basis Function (RBF) method, + to construct approximations of the two functions that correspond to the + airfoil upper half and lower half coordinates. The RBF implementation + is present in :ref:`RBF ndinterpolator <ndinterpolator-label>`. + + References: + + Buhmann, Martin D. (2003), Radial Basis Functions: Theory + and Implementations. + http://www.cs.bham.ac.uk/~jxb/NN/l12.pdf + https://www.cc.gatech.edu/~isbell/tutorials/rbf-intro.pdf + + :param int num: number of interpolated points. Default value is 500 + :param float radius: range of the cut-off radius necessary for the RBF + interpolation. Default value is 1.0. It is quite necessary to + adjust the value properly so as to ensure a smooth interpolation + :return: interpolation points for the airfoil upper half X-component, + interpolation points for the airfoil lower half X-component, + interpolation points for the airfoil upper half Y-component, + interpolation points for the airfoil lower half Y-component + :rtype: numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray + :raises TypeError: if num is not of type int + :raises ValueError: if num is not positive, or if radius is not + positive + """ + if not isinstance(num, int): + raise TypeError('Inserted value must be of type integer.') + if num <= 0 or radius <= 0: + raise ValueError('Inserted value must be positive.') + + xx_up = np.linspace( + self.xup_coordinates[0], self.xup_coordinates[-1], num=num) + yy_up = np.zeros(num) + reconstruct_f( + basis='beckert_wendland_c2_basis', + radius=radius, + original_input=self.xup_coordinates, + original_output=self.yup_coordinates, + rbf_input=xx_up, + rbf_output=yy_up) + xx_down = np.linspace( + self.xdown_coordinates[0], self.xdown_coordinates[-1], num=num) + yy_down = np.zeros(num) + reconstruct_f( + basis='beckert_wendland_c2_basis', + radius=radius, + original_input=self.xdown_coordinates, + original_output=self.ydown_coordinates, + rbf_input=xx_down, + rbf_output=yy_down) + + return xx_up, xx_down, yy_up, yy_down
+ +
[docs] def compute_chord_line(self, n_interpolated_points=None): + """ + Compute the 2D coordinates of the chord line. Also updates + the chord_line class member. + + The chord line is the straight line that joins between the leading edge + and the trailing edge. It is simply computed from the equation of + a line passing through two points, the LE and TE. + + :param int n_interpolated_points: number of points to be used for the + equally-spaced sample computations. If None then there is no + interpolation, unless the arrays x_up != x_down elementwise which + implies that the corresponding y_up and y_down can not be + comparable, hence a uniform interpolation is required. Default + value is None + """ + self._update_edges() + aratio = ((self.trailing_edge[1] - self.leading_edge[1]) / + (self.trailing_edge[0] - self.leading_edge[0])) + if not (self.xup_coordinates == self.xdown_coordinates + ).all() and n_interpolated_points is None: + # If x_up != x_down element-wise, then the corresponding y_up and + # y_down can not be comparable, hence a uniform interpolation is + # required. Also in case the interpolated_points is None, + # then we assume a default number of interpolated points + n_interpolated_points = 500 + + if n_interpolated_points: + cl_x_coordinates = np.linspace( + self.leading_edge[0], + self.trailing_edge[0], + num=n_interpolated_points) + cl_y_coordinates = (aratio * + (cl_x_coordinates - self.leading_edge[0]) + + self.leading_edge[1]) + self.chord_line = np.array([cl_x_coordinates, cl_y_coordinates]) + else: + cl_y_coordinates = (aratio * + (self.xup_coordinates - self.leading_edge[0]) + + self.leading_edge[1]) + self.chord_line = np.array([self.xup_coordinates, cl_y_coordinates])
+ +
[docs] def compute_camber_line(self, n_interpolated_points=None): + """ + Compute the 2D coordinates of the camber line. Also updates the + camber_line class member. + + The camber line is defined by the curve passing through all the mid + points between the upper surface and the lower surface of the airfoil. + + :param int n_interpolated_points: number of points to be used for the + equally-spaced sample computations. If None then there is no + interpolation, unless the arrays x_up != x_down elementwise which + implies that the corresponding y_up and y_down can not be + comparable, hence a uniform interpolation is required. Default + value is None + + We note that a uniform interpolation becomes necessary for the cases + when the X-coordinates of the upper and lower surfaces do not + correspond to the same vertical sections, since this would imply + inaccurate measurements for obtaining the camber line. + """ + if not (self.xup_coordinates == self.xdown_coordinates + ).all() and n_interpolated_points is None: + # If x_up != x_down element-wise, then the corresponding y_up and + # y_down can not be comparable, hence a uniform interpolation is + # required. Also in case the interpolated_points is None, + # then we assume a default number of interpolated points + n_interpolated_points = 500 + + if n_interpolated_points: + cl_x_coordinates, yy_up, yy_down = ( + self.interpolate_coordinates(num=n_interpolated_points)[1:]) + cl_y_coordinates = 0.5 * (yy_up + yy_down) + self.camber_line = np.array([cl_x_coordinates, cl_y_coordinates]) + else: + cl_y_coordinates = (0.5 * + (self.ydown_coordinates + self.yup_coordinates)) + self.camber_line = np.array( + [self.xup_coordinates, cl_y_coordinates])
+ +
[docs] def deform_camber_line(self, percent_change, n_interpolated_points=None): + """ + Deform camber line according to a given percentage of change of the + maximum camber. Also reconstructs the deformed airfoil's coordinates. + + The percentage of change is defined as follows: + + .. math:: + \\frac{\\text{new magnitude of max camber - old magnitude of maximum \ + camber}}{\\text{old magnitude of maximum camber}} * 100 + + A positive percentage means the new camber is larger than the max + camber value, while a negative percentage indicates the new value + is smaller. + + We note that the method works only for airfoils in the reference + position, i.e. chord line lies on the X-axis and the foil is not + rotated, since the measurements are based on the Y-values of the + airfoil coordinates, hence any measurements or scalings will be + inaccurate for the foils not in their reference position. + + :param float percent_change: percentage of change of the + maximum camber. Default value is None + :param bool interpolate: if True, the interpolated coordinates are + used to compute the camber line and foil's thickness, otherwise + the original discrete coordinates are used. Default value is False. + :param int n_interpolated_points: number of points to be used for the + equally-spaced sample computations. If None then there is no + interpolation, unless the arrays x_up != x_down elementwise which + implies that the corresponding y_up and y_down can not be + comparable, hence a uniform interpolation is required. Default + value is None + """ + # Updating camber line + self.compute_camber_line(n_interpolated_points=n_interpolated_points) + scaling_factor = percent_change / 100. + 1. + self.camber_line[1] *= scaling_factor + + if not (self.xup_coordinates == self.xdown_coordinates + ).all() and n_interpolated_points is None: + # If x_up != x_down element-wise, then the corresponding y_up and + # y_down can not be comparable, hence a uniform interpolation is + # required. Also in case the interpolated_points is None, + # then we assume a default number of interpolated points + n_interpolated_points = 500 + + # Evaluating half-thickness of the undeformed airfoil, + # which should hold same values for the deformed foil. + if n_interpolated_points: + (self.xup_coordinates, self.xdown_coordinates, self.yup_coordinates, + self.ydown_coordinates + ) = self.interpolate_coordinates(num=n_interpolated_points) + + half_thickness = 0.5 * np.fabs( + self.yup_coordinates - self.ydown_coordinates) + + self.yup_coordinates = self.camber_line[1] + half_thickness + self.ydown_coordinates = self.camber_line[1] - half_thickness
+ + @property + def reference_point(self): + """ + Return the coordinates of the chord's mid point. + + :return: reference point in 2D + :rtype: numpy.ndarray + """ + self._update_edges() + reference_point = [ + 0.5 * (self.leading_edge[0] + self.trailing_edge[0]), + 0.5 * (self.leading_edge[1] + self.trailing_edge[1]) + ] + return np.asarray(reference_point) + + @property + def chord_length(self): + """ + Measure the l2-norm (Euclidean distance) between the leading edge + and the trailing edge. + + :return: chord length + :rtype: float + """ + self._update_edges() + return np.linalg.norm(self.leading_edge - self.trailing_edge) + +
[docs] def max_thickness(self, n_interpolated_points=None): + """ + Return the airfoil's maximum thickness. + + Thickness is defined as the distnace between the upper and lower + surfaces of the airfoil, and can be measured in two different ways: + + - American convention: measures along the line perpendicular to \ + the mean camber line. + + - British convention: measures along the line perpendicular to \ + the chord line. + + In this implementation, the british convention is used to evaluate + the maximum thickness. + + References: + + Phillips, Warren F. (2010). Mechanics of Flight (2nd ed.). \ + Wiley & Sons. p. 27. ISBN 978-0-470-53975-0. + + Bertin, John J.; Cummings, Russel M. (2009). Pearson Prentice Hall, \ + ed. Aerodynamics for Engineers (5th ed.). \ + p. 199. ISBN 978-0-13-227268-1. + + :param bool interpolate: if True, the interpolated coordinates are used + to measure the thickness; otherwise, the original discrete + coordinates are used. Default value is False + :param int n_interpolated_points: number of points to be used for the + equally-spaced sample computations. If None then there is no + interpolation, unless the arrays x_up != x_down elementwise which + implies that the corresponding y_up and y_down can not be + comparable, hence a uniform interpolation is required. Default + value is None + :return: maximum thickness + :rtype: float + """ + if not (self.xup_coordinates == self.xdown_coordinates + ).all() and n_interpolated_points is None: + # If x_up != x_down element-wise, then the corresponding y_up and + # y_down can not be comparable, hence a uniform interpolation is + # required. Also in case the interpolated_points is None, + # then we assume a default number of interpolated points + n_interpolated_points = 500 + + if n_interpolated_points: + # Evaluation of the thickness requires comparing both y_up and + # y_down for the same x-section, (i.e. same x_coordinate), + # according to british convention. If x_up != x_down element-wise, + # then the corresponding y_up and y_down can not be comparable, + # hence a uniform interpolation is required. + yy_up, yy_down = self.interpolate_coordinates( + num=n_interpolated_points)[2:] + return np.fabs(yy_up - yy_down).max() + return np.fabs(self.yup_coordinates - self.ydown_coordinates).max()
+ +
[docs] def max_camber(self, n_interpolated_points=500): + """ + Return the magnitude of the airfoil's maximum camber. + + Camber is defined as the distance between the chord line and the mean + camber line, and is measured along the line perpendicular to the chord + line. + + :param bool interpolate: if True, the interpolated coordinates are used + to measure the camber; otherwise, the original discrete coordinates + are used. Default value is False + :param int n_interpolated_points: number of points to be used for the + equally-spaced sample computations. If None then there is no + interpolation, unless the arrays x_up != x_down elementwise which + implies that the corresponding y_up and y_down can not be + comparable, hence a uniform interpolation is required. Default + value is None + :return: maximum camber + :rtype: float + """ + self.compute_chord_line(n_interpolated_points=n_interpolated_points) + + self.compute_camber_line(n_interpolated_points=n_interpolated_points) + + n_points = self.camber_line[0].size + camber = np.zeros(n_points) + + for i in range(n_points): + camber[i] = np.linalg.norm( + self.chord_line[:, i] - self.camber_line[:, i]) + + max_camber = camber.max() + if (self.camber_line[1][camber.argmax()] < + self.chord_line[1][camber.argmax()]): + # Camber line is below the chord line, at the point of max camber + max_camber *= -1 + + return max_camber
+ +
[docs] def rotate(self, rad_angle=None, deg_angle=None): + """ + 2D counter clockwise rotation about the origin of the Cartesian + coordinate system. + + The rotation matrix, :math:`R(\\theta)`, is used to perform rotation + in the 2D Euclidean space about the origin, which is -- by default -- + the leading edge. + + :math:`R(\\theta)` is defined by: + + .. math:: + \\left(\\begin{matrix} cos (\\theta) & - sin (\\theta) \\\\ + sin (\\theta) & cos (\\theta) \\end{matrix}\\right) + + Given the coordinates of point :math:`P` such that + + .. math:: + P = \\left(\\begin{matrix} x \\\\ + y \\end{matrix}\\right), + + Then, the rotated coordinates will be: + + .. math:: + P^{'} = \\left(\\begin{matrix} x^{'} \\\\ + y^{'} \\end{matrix}\\right) + = R (\\theta) \\cdot P + + If a standard right-handed Cartesian coordinate system is used, with + the X-axis to the right and the Y-axis up, the rotation + :math:`R (\\theta)` is counterclockwise. If a left-handed Cartesian + coordinate system is used, with X-axis directed to the right and Y-axis + directed down, :math:`R (\\theta)` is clockwise. + + :param float rad_angle: angle in radians. Default value is None + :param float deg_angle: angle in degrees. Default value is None + :raises ValueError: if both rad_angle and deg_angle are inserted, + or if neither is inserted + """ + if rad_angle is not None and deg_angle is not None: + raise ValueError( + 'You have to pass either the angle in radians or in degrees,' \ + ' not both.') + if rad_angle is not None: + cosine = np.cos(rad_angle) + sine = np.sin(rad_angle) + elif deg_angle is not None: + cosine = np.cos(np.radians(deg_angle)) + sine = np.sin(np.radians(deg_angle)) + else: + raise ValueError( + 'You have to pass either the angle in radians or in degrees.') + + rot_matrix = np.array([cosine, -sine, sine, cosine]).reshape((2, 2)) + + coord_matrix_up = np.vstack((self.xup_coordinates, + self.yup_coordinates)) + coord_matrix_down = np.vstack((self.xdown_coordinates, + self.ydown_coordinates)) + + new_coord_matrix_up = np.zeros(coord_matrix_up.shape) + new_coord_matrix_down = np.zeros(coord_matrix_down.shape) + + for i in range(self.xup_coordinates.shape[0]): + new_coord_matrix_up[:, i] = np.dot(rot_matrix, + coord_matrix_up[:, i]) + new_coord_matrix_down[:, i] = np.dot(rot_matrix, + coord_matrix_down[:, i]) + + self.xup_coordinates = new_coord_matrix_up[0] + self.xdown_coordinates = new_coord_matrix_down[0] + self.yup_coordinates = new_coord_matrix_up[1] + self.ydown_coordinates = new_coord_matrix_down[1]
+ +
[docs] def translate(self, translation): + """ + Translate the airfoil coordinates according to a 2D translation vector. + + :param array_like translation: the translation vector in 2D + """ + self.xup_coordinates += translation[0] + self.xdown_coordinates += translation[0] + self.yup_coordinates += translation[1] + self.ydown_coordinates += translation[1]
+ +
[docs] def reflect(self): + """ + Reflect the airfoil coordinates about the origin, i.e. a mirror + transformation is performed about both the X-axis and the Y-axis. + """ + self.xup_coordinates *= -1 + self.xdown_coordinates *= -1 + self.yup_coordinates *= -1 + self.ydown_coordinates *= -1
+ +
[docs] def scale(self, factor): + """ + Scale the airfoil coordinates according to a scaling factor. + + In order to apply the scaling without affecting the position of the + reference point, the method translates the airfoil by its refernce + point to be centered in the origin, then the scaling is applied, and + finally the airfoil is translated back by its reference point to the + initial position. + + :param float factor: the scaling factor + """ + ref_point = self.reference_point + self.translate(-ref_point) + self.xup_coordinates *= factor + self.xdown_coordinates *= factor + self.yup_coordinates *= factor + self.ydown_coordinates *= factor + self.translate(ref_point)
+ +
[docs] def plot(self, + profile=True, + chord_line=False, + camber_line=False, + ref_point=False, + outfile=None): + """ + Plot the airfoil coordinates. + + :param bool profile: if True, then plot the profile coordinates. + Default value is True + :param bool chord_line: if True, then plot the chord line. Default + value is False + :param bool camber_line: if True, then plot the camber line. Default + value is False + :param bool ref_point: if True, then scatter plot the reference point. + Default value is False + :param str outfile: outfile name. If a string is provided then the + plot is saved with that name, otherwise the plot is not saved. + Default value is None + """ + plt.figure() + + if (self.xup_coordinates is None or self.yup_coordinates is None + or self.xdown_coordinates is None + or self.ydown_coordinates is None): + raise ValueError('One or all the coordinates have None value.') + + if profile: + plt.plot( + self.xup_coordinates, + self.yup_coordinates, + label='Upper profile') + plt.plot( + self.xdown_coordinates, + self.ydown_coordinates, + label='Lower profile') + + if chord_line: + if self.chord_line is None: + raise ValueError( + 'Chord line is None. You must compute it first') + plt.plot(self.chord_line[0], self.chord_line[1], label='Chord line') + + if camber_line: + if self.camber_line is None: + raise ValueError( + 'Camber line is None. You must compute it first') + plt.plot( + self.camber_line[0], self.camber_line[1], label='Camber line') + + if ref_point: + plt.scatter( + self.reference_point[0], + self.reference_point[1], + s=15, + label='Reference point') + + plt.grid(linestyle='dotted') + plt.axis('equal') + plt.legend() + + if outfile: + if not isinstance(outfile, str): + raise ValueError('Output file name must be string.') + plt.savefig(outfile) + else: + plt.show()
+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/bladex/profiles.html b/_modules/bladex/profiles.html new file mode 100644 index 0000000..fde24bd --- /dev/null +++ b/_modules/bladex/profiles.html @@ -0,0 +1,506 @@ + + + + + + + + + + + bladex.profiles — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+ +
+
+
+
+ +

Source code for bladex.profiles

+"""
+Derived module from profilebase.py to provide the airfoil coordinates.
+"""
+from scipy.interpolate import splev, splrep
+import numpy as np
+from .profilebase import ProfileBase
+
+
+
[docs]class CustomProfile(ProfileBase): + """ + Provide custom profile for the airfoil coordinates. + + :param numpy.ndarray xup: 1D array that contains the X-components of the + airfoil's upper surface + :param numpy.ndarray xdown: 1D array that contains the X-components of the + airfoil's lower surface + :param numpy.ndarray yup: 1D array that contains the Y-components of the + airfoil's upper surface + :param numpy.ndarray ydown: 1D array that contains the Y-components of the + airfoil's lower surface + """ + + def __init__(self, xup, yup, xdown, ydown): + super(CustomProfile, self).__init__() + self.xup_coordinates = xup + self.yup_coordinates = yup + self.xdown_coordinates = xdown + self.ydown_coordinates = ydown + self._check_coordinates() + +
[docs] def _check_coordinates(self): + """ + Private method that checks whether the airfoil coordinates defined + are provided correctly. + + We note that each array of coordinates must be consistent with the + other arrays. The upper and lower surfaces should start from exactly + the same point, the leading edge, and proceed on the way till the + trailing edge. The trailing edge might have a non-zero thickness as + in the case of some NACA-airfoils. In case of an open trailing edge, + the average coordinate between upper and lower part is taken as the + unique value. + + :raises ValueError: if either xup, xdown, yup, ydown is None + :raises ValueError: if the 1D arrays xup, yup or xdown, ydown do not + have the same length + :raises ValueError: if array yup not greater than or equal array ydown + element-wise + :raises ValueError: if xdown[0] != xup[0] or ydown[0] != yup[0] + or xdown[-1] != xup[-1] + """ + if self.xup_coordinates is None: + raise ValueError( + 'object "xup_coordinates" refers to an empty array.') + if self.xdown_coordinates is None: + raise ValueError( + 'object "xdown_coordinates" refers to an empty array.') + if self.yup_coordinates is None: + raise ValueError( + 'object "yup_coordinates" refers to an empty array.') + if self.ydown_coordinates is None: + raise ValueError( + 'object "ydown_coordinates" refers to an empty array.') + + if not isinstance(self.xup_coordinates, np.ndarray): + self.xup_coordinates = np.asarray(self.xup_coordinates, dtype=float) + if not isinstance(self.xdown_coordinates, np.ndarray): + self.xdown_coordinates = np.asarray( + self.xdown_coordinates, dtype=float) + if not isinstance(self.yup_coordinates, np.ndarray): + self.yup_coordinates = np.asarray(self.yup_coordinates, dtype=float) + if not isinstance(self.ydown_coordinates, np.ndarray): + self.ydown_coordinates = np.asarray( + self.ydown_coordinates, dtype=float) + + # Therefore the arrays xup_coordinates and yup_coordinates must have + # the same length = N, same holds for the arrays xdown_coordinates + # and ydown_coordinates. + if self.xup_coordinates.shape != self.yup_coordinates.shape: + raise ValueError( + 'xup_coordinates and yup_coordinates must have same shape.') + if self.xdown_coordinates.shape != self.ydown_coordinates.shape: + raise ValueError( + 'xdown_coordinates and ydown_coordinates must have same shape.') + + # The condition yup_coordinates >= ydown_coordinates must be satisfied + # element-wise to the whole elements in the mentioned arrays. + if not all( + np.greater_equal(self.yup_coordinates, self.ydown_coordinates)): + raise ValueError( + 'yup_coordinates is not >= ydown_coordinates elementwise.') + + if not self.xdown_coordinates[0] == self.xup_coordinates[0]: + raise ValueError( + '(xdown_coordinates[0]=xup_coordinates[0]) not satisfied.') + if not self.ydown_coordinates[0] == self.yup_coordinates[0]: + raise ValueError( + '(ydown_coordinates[0]=yup_coordinates[0]) not satisfied.') + if not self.xdown_coordinates[-1] == self.xup_coordinates[-1]: + raise ValueError( + '(xdown_coordinates[-1]=xup_coordinates[-1]) not satisfied.')
+ + +
[docs]class NacaProfile(ProfileBase): + """ + Generate 4- and 5-digit NACA profiles. + + The NACA airfoils are airfoil shapes for aircraft wings developed by the + National Advisory Committee for Aeronautics (NACA). The shape of the NACA + airfoils is described using a series of digits following the word "NACA". + The parameters in the numerical code can be entered into equations to + precisely generate the cross-section of the airfoil and calculate its + properties. + + The NACA four-digit series describes airfoil by the format MPTT, where: + + - M/100: indicates the maximum camber in percentage, with respect to the + chord length. + + - P/10: indicates the location of the maximum camber measured from the + leading edge. The location is normalized by the chord length. + + - TT/100: the maximum thickness as fraction of the chord length. + + The profile 00TT refers to a symmetrical NACA airfoil. + + The NACA five-digit series describes more complex airfoil shapes. + Its format is: LPSTT, where: + + - L: the theoretical optimum lift coefficient at ideal + angle-of-attack = 0.15*L + + - P: the x-coordinate of the point of maximum camber + (max camber at x = 0.05*P) + + - S: indicates whether the camber is simple (S=0) or reflex (S=1) + TT/100: the maximum thickness in percent of chord, as in a four-digit + NACA airfoil code + + References: + + - Moran, Jack (2003). An introduction to theoretical and computational + aerodynamics. Dover. p. 7. ISBN 0-486-42879-6. + + - Abbott, Ira (1959). Theory of Wing Sections: Including a Summary of + Airfoil Data. New York: Dover Publications. p. 115. ISBN 978-0486605869. + + :param str digits: 4 or 5 digits that describes the NACA profile + :param int n_points: number of discrete points that represents the + airfoil profile. Default value is 240 + :param bool cosine_spacing: if True, then a cosine spacing is used for the + airfoil coordinate distribution, otherwise linear spacing is used. + Default value is True + :raises ValueError: if n_points is not positive + :raises TypeError: if n_points is not of type int + :raises SyntaxError: if digits is not a string + :raises Exception: if digits is not of length 4 or 5 + """ + + def __init__(self, digits, n_points=240, cosine_spacing=True): + super(NacaProfile, self).__init__() + self.digits = digits + self.n_points = n_points + self.cosine_spacing = cosine_spacing + self._check_args() + self._generate_coordinates() + +
[docs] def _check_args(self): + """ + Private method to check that the number of the airfoil discrete points + is a positive integer. + """ + if not isinstance(self.digits, str): + raise TypeError('digits must be of type string.') + if isinstance(self.n_points, float): + self.n_points = int(self.n_points) + if not isinstance(self.n_points, int): + raise TypeError('n_points must be of type integer.') + if self.n_points < 0: + raise ValueError('n_points must be positive.')
+ +
[docs] def _generate_coordinates(self): + """ + Private method that generates the coordinates of the NACA 4 or 5 digits + airfoil profile. The method assumes a zero-thickness trailing edge, and + no half-cosine spacing. + """ + a0 = +0.2969 + a1 = -0.1260 + a2 = -0.3516 + a3 = +0.2843 + a4 = -0.1036 # zero thickness TE + + x = np.linspace(0.0, 1.0, num=self.n_points) + + if len(self.digits) == 4: + # Returns n+1 points in [0 1] for the given 4-digits NACA string + m = float(self.digits[0]) / 100.0 + p = float(self.digits[1]) / 10.0 + t = float(self.digits[2:]) / 100.0 + + # half-thickness distribution + yt = 5 * t * (a0 * np.sqrt(x) + a1 * x + a2 * np.power(x, 2) + + a3 * np.power(x, 3) + a4 * np.power(x, 4)) + + if p == 0: + # Symmetric foil + self.xup_coordinates = np.linspace(0.0, 1.0, num=self.n_points) + self.yup_coordinates = yt + self.xdown_coordinates = np.linspace( + 0.0, 1.0, num=self.n_points) + self.ydown_coordinates = -yt + else: + # Cambered foil + xc1 = np.asarray([xx for xx in x if xx <= p]) + xc2 = np.asarray([xx for xx in x if xx > p]) + yc1 = m / np.power(p, 2) * xc1 * (2 * p - xc1) + yc2 = m / np.power(1 - p, 2) * (1 - 2 * p + xc2) * (1 - xc2) + # Y-coordinates of camber line + yc = np.append(yc1, yc2) + + if self.cosine_spacing: + # points are generated according to cosine distribution of + # the X-coordinates of the chord + dyc1_dx = m / np.power(p, 2) * (2 * p - 2 * xc1) + dyc2_dx = m / np.power(1 - p, 2) * (2 * p - 2 * xc2) + dyc_dx = np.append(dyc1_dx, dyc2_dx) + theta = np.arctan(dyc_dx) + self.xup_coordinates = x - yt * np.sin(theta) + self.yup_coordinates = yc + yt * np.cos(theta) + self.xdown_coordinates = x + yt * np.sin(theta) + self.ydown_coordinates = yc - yt * np.cos(theta) + else: + # Linear spacing distribution of the foil coordinates + self.xup_coordinates = np.linspace( + 0.0, 1.0, num=self.n_points) + self.xdown_coordinates = np.linspace( + 0.0, 1.0, num=self.n_points) + self.yup_coordinates = yc + yt + self.ydown_coordinates = yc - yt + + elif len(self.digits) == 5: + # Returns n+1 points in [0 1] for the given 5-digits NACA string + cld = float(self.digits[0]) * 0.15 + p = 5.0 * float(self.digits[1]) / 100.0 + s = float(self.digits[2]) + t = float(self.digits[3:]) / 100.0 + + # half-thickness distribution + yt = 5 * t * (a0 * np.sqrt(x) + a1 * x + a2 * np.power(x, 2) + + a3 * np.power(x, 3) + a4 * np.power(x, 4)) + + if s == 1: + # Relfex camber + P = np.array([0.1, 0.15, 0.2, 0.25]) + M = np.array([0.13, 0.2170, 0.318, 0.441]) + K = np.array([51.99, 15.793, 6.520, 3.191]) + elif s == 0: + # Standard camber + P = np.array([0.05, 0.1, 0.15, 0.2, 0.25]) + M = np.array([0.0580, 0.1260, 0.2025, 0.2900, 0.3910]) + K = np.array([361.4, 51.64, 15.957, 6.643, 3.230]) + else: + raise ValueError( + 'For NACA "LPSTT" the value of "S" can be either 0 or 1.') + + if p == 0: + # Symmetric foil + self.xup_coordinates = np.linspace(0.0, 1.0, num=self.n_points) + self.yup_coordinates = yt + self.xdown_coordinates = np.linspace( + 0.0, 1.0, num=self.n_points) + self.ydown_coordinates = -yt + else: + # Cambered foil + spl_m = splrep(P, M) + spl_k = splrep(M, K) + m = splev(p, spl_m) + k1 = splev(m, spl_k) + xc1 = np.asarray([xx for xx in x if xx <= m]) + xc2 = np.asarray([xx for xx in x if xx > m]) + yc1 = k1 / 6.0 * (np.power(xc1, 3) - 3 * m * np.power(xc1, 2) + + np.power(m, 2) * (3 - m) * xc1) + yc2 = k1 / 6.0 * np.power(m, 3) * (1 - xc2) + yc = np.append(yc1, yc2) + + if self.cosine_spacing: + # points are generated according to cosine distribution of + # the X-coordinates of the chord + zc = cld / 0.3 * yc + dyc1_dx = 1.0 / 6.0 * k1 * ( + 3 * np.power(xc1, 2) - 6 * m * xc1 + np.power(m, 2) * + (3 - m)) + dyc2_dx = np.tile(-1.0 / 6.0 * k1 * np.power(m, 3), + len(xc2)) + dyc_dx = np.append(dyc1_dx, dyc2_dx) + theta = np.arctan(dyc_dx) + self.xup_coordinates = x - yt * np.sin(theta) + self.yup_coordinates = zc + yt * np.cos(theta) + self.xdown_coordinates = x + yt * np.sin(theta) + self.ydown_coordinates = zc - yt * np.cos(theta) + else: + # Linear spacing distribution of the foil coordinates + self.xup_coordinates = np.linspace( + 0.0, 1.0, num=self.n_points) + self.xdown_coordinates = np.linspace( + 0.0, 1.0, num=self.n_points) + self.yup_coordinates = yc + yt + self.ydown_coordinates = yc - yt + + else: + raise Exception
+
+ +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000..a19887c --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,197 @@ + + + + + + + + + + + Overview: module code — BladeX 0.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+ + + + + + +
+
    +
  • Docs »
  • + +
  • Overview: module code
  • +
  • + + + +
  • +
+
+
+
+
+ +

All modules for which code is available

+ + +
+
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/source/LICENSE.rst b/_sources/LICENSE.txt similarity index 100% rename from docs/source/LICENSE.rst rename to _sources/LICENSE.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._abs_to_norm.rst b/_sources/_summaries/bladex.blade.Blade._abs_to_norm.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._abs_to_norm.rst rename to _sources/_summaries/bladex.blade.Blade._abs_to_norm.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._check_errors.rst b/_sources/_summaries/bladex.blade.Blade._check_errors.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._check_errors.rst rename to _sources/_summaries/bladex.blade.Blade._check_errors.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._check_params.rst b/_sources/_summaries/bladex.blade.Blade._check_params.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._check_params.rst rename to _sources/_summaries/bladex.blade.Blade._check_params.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._check_string.rst b/_sources/_summaries/bladex.blade.Blade._check_string.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._check_string.rst rename to _sources/_summaries/bladex.blade.Blade._check_string.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._compute_pitch_angle.rst b/_sources/_summaries/bladex.blade.Blade._compute_pitch_angle.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._compute_pitch_angle.rst rename to _sources/_summaries/bladex.blade.Blade._compute_pitch_angle.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._generate_lower_face.rst b/_sources/_summaries/bladex.blade.Blade._generate_lower_face.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._generate_lower_face.rst rename to _sources/_summaries/bladex.blade.Blade._generate_lower_face.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._generate_tip.rst b/_sources/_summaries/bladex.blade.Blade._generate_tip.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._generate_tip.rst rename to _sources/_summaries/bladex.blade.Blade._generate_tip.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._generate_upper_face.rst b/_sources/_summaries/bladex.blade.Blade._generate_upper_face.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._generate_upper_face.rst rename to _sources/_summaries/bladex.blade.Blade._generate_upper_face.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._import_occ_libs.rst b/_sources/_summaries/bladex.blade.Blade._import_occ_libs.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._import_occ_libs.rst rename to _sources/_summaries/bladex.blade.Blade._import_occ_libs.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._induced_rake_from_skew.rst b/_sources/_summaries/bladex.blade.Blade._induced_rake_from_skew.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._induced_rake_from_skew.rst rename to _sources/_summaries/bladex.blade.Blade._induced_rake_from_skew.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._norm_to_abs.rst b/_sources/_summaries/bladex.blade.Blade._norm_to_abs.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._norm_to_abs.rst rename to _sources/_summaries/bladex.blade.Blade._norm_to_abs.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._planar_to_cylindrical.rst b/_sources/_summaries/bladex.blade.Blade._planar_to_cylindrical.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._planar_to_cylindrical.rst rename to _sources/_summaries/bladex.blade.Blade._planar_to_cylindrical.txt diff --git a/docs/source/_summaries/bladex.blade.Blade._write_blade_errors.rst b/_sources/_summaries/bladex.blade.Blade._write_blade_errors.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade._write_blade_errors.rst rename to _sources/_summaries/bladex.blade.Blade._write_blade_errors.txt diff --git a/docs/source/_summaries/bladex.blade.Blade.apply_transformations.rst b/_sources/_summaries/bladex.blade.Blade.apply_transformations.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade.apply_transformations.rst rename to _sources/_summaries/bladex.blade.Blade.apply_transformations.txt diff --git a/docs/source/_summaries/bladex.blade.Blade.export_ppg.rst b/_sources/_summaries/bladex.blade.Blade.export_ppg.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade.export_ppg.rst rename to _sources/_summaries/bladex.blade.Blade.export_ppg.txt diff --git a/docs/source/_summaries/bladex.blade.Blade.generate_iges.rst b/_sources/_summaries/bladex.blade.Blade.generate_iges.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade.generate_iges.rst rename to _sources/_summaries/bladex.blade.Blade.generate_iges.txt diff --git a/docs/source/_summaries/bladex.blade.Blade.generate_stl.rst b/_sources/_summaries/bladex.blade.Blade.generate_stl.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade.generate_stl.rst rename to _sources/_summaries/bladex.blade.Blade.generate_stl.txt diff --git a/docs/source/_summaries/bladex.blade.Blade.plot.rst b/_sources/_summaries/bladex.blade.Blade.plot.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade.plot.rst rename to _sources/_summaries/bladex.blade.Blade.plot.txt diff --git a/docs/source/_summaries/bladex.blade.Blade.rotate.rst b/_sources/_summaries/bladex.blade.Blade.rotate.txt similarity index 100% rename from docs/source/_summaries/bladex.blade.Blade.rotate.rst rename to _sources/_summaries/bladex.blade.Blade.rotate.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation._check_control_points.rst b/_sources/_summaries/bladex.deform.Deformation._check_control_points.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation._check_control_points.rst rename to _sources/_summaries/bladex.deform.Deformation._check_control_points.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation._check_deformed.rst b/_sources/_summaries/bladex.deform.Deformation._check_deformed.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation._check_deformed.rst rename to _sources/_summaries/bladex.deform.Deformation._check_deformed.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation._check_param.rst b/_sources/_summaries/bladex.deform.Deformation._check_param.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation._check_param.rst rename to _sources/_summaries/bladex.deform.Deformation._check_param.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation._check_spline.rst b/_sources/_summaries/bladex.deform.Deformation._check_spline.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation._check_spline.rst rename to _sources/_summaries/bladex.deform.Deformation._check_spline.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation._optimum_control_points.rst b/_sources/_summaries/bladex.deform.Deformation._optimum_control_points.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation._optimum_control_points.rst rename to _sources/_summaries/bladex.deform.Deformation._optimum_control_points.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation.compute_all.rst b/_sources/_summaries/bladex.deform.Deformation.compute_all.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation.compute_all.rst rename to _sources/_summaries/bladex.deform.Deformation.compute_all.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation.compute_control_points.rst b/_sources/_summaries/bladex.deform.Deformation.compute_control_points.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation.compute_control_points.rst rename to _sources/_summaries/bladex.deform.Deformation.compute_control_points.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation.compute_deformed_parameters.rst b/_sources/_summaries/bladex.deform.Deformation.compute_deformed_parameters.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation.compute_deformed_parameters.rst rename to _sources/_summaries/bladex.deform.Deformation.compute_deformed_parameters.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation.export_param_file.rst b/_sources/_summaries/bladex.deform.Deformation.export_param_file.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation.export_param_file.rst rename to _sources/_summaries/bladex.deform.Deformation.export_param_file.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation.generate_spline.rst b/_sources/_summaries/bladex.deform.Deformation.generate_spline.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation.generate_spline.rst rename to _sources/_summaries/bladex.deform.Deformation.generate_spline.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation.plot.rst b/_sources/_summaries/bladex.deform.Deformation.plot.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation.plot.rst rename to _sources/_summaries/bladex.deform.Deformation.plot.txt diff --git a/docs/source/_summaries/bladex.deform.Deformation.update_control_points.rst b/_sources/_summaries/bladex.deform.Deformation.update_control_points.txt similarity index 100% rename from docs/source/_summaries/bladex.deform.Deformation.update_control_points.rst rename to _sources/_summaries/bladex.deform.Deformation.update_control_points.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.RBF.beckert_wendland_c2_basis.rst b/_sources/_summaries/bladex.ndinterpolator.RBF.beckert_wendland_c2_basis.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.RBF.beckert_wendland_c2_basis.rst rename to _sources/_summaries/bladex.ndinterpolator.RBF.beckert_wendland_c2_basis.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.RBF.gaussian_spline.rst b/_sources/_summaries/bladex.ndinterpolator.RBF.gaussian_spline.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.RBF.gaussian_spline.rst rename to _sources/_summaries/bladex.ndinterpolator.RBF.gaussian_spline.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.RBF.inv_multi_quadratic_biharmonic_spline.rst b/_sources/_summaries/bladex.ndinterpolator.RBF.inv_multi_quadratic_biharmonic_spline.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.RBF.inv_multi_quadratic_biharmonic_spline.rst rename to _sources/_summaries/bladex.ndinterpolator.RBF.inv_multi_quadratic_biharmonic_spline.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.RBF.multi_quadratic_biharmonic_spline.rst b/_sources/_summaries/bladex.ndinterpolator.RBF.multi_quadratic_biharmonic_spline.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.RBF.multi_quadratic_biharmonic_spline.rst rename to _sources/_summaries/bladex.ndinterpolator.RBF.multi_quadratic_biharmonic_spline.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.RBF.thin_plate_spline.rst b/_sources/_summaries/bladex.ndinterpolator.RBF.thin_plate_spline.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.RBF.thin_plate_spline.rst rename to _sources/_summaries/bladex.ndinterpolator.RBF.thin_plate_spline.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.RBF.weights_matrix.rst b/_sources/_summaries/bladex.ndinterpolator.RBF.weights_matrix.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.RBF.weights_matrix.rst rename to _sources/_summaries/bladex.ndinterpolator.RBF.weights_matrix.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.reconstruct_f.rst b/_sources/_summaries/bladex.ndinterpolator.reconstruct_f.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.reconstruct_f.rst rename to _sources/_summaries/bladex.ndinterpolator.reconstruct_f.txt diff --git a/docs/source/_summaries/bladex.ndinterpolator.scipy_bspline.rst b/_sources/_summaries/bladex.ndinterpolator.scipy_bspline.txt similarity index 100% rename from docs/source/_summaries/bladex.ndinterpolator.scipy_bspline.rst rename to _sources/_summaries/bladex.ndinterpolator.scipy_bspline.txt diff --git a/docs/source/_summaries/bladex.params.ParamFile.__str__.rst b/_sources/_summaries/bladex.params.ParamFile.__str__.txt similarity index 100% rename from docs/source/_summaries/bladex.params.ParamFile.__str__.rst rename to _sources/_summaries/bladex.params.ParamFile.__str__.txt diff --git a/docs/source/_summaries/bladex.params.ParamFile._check_params.rst b/_sources/_summaries/bladex.params.ParamFile._check_params.txt similarity index 100% rename from docs/source/_summaries/bladex.params.ParamFile._check_params.rst rename to _sources/_summaries/bladex.params.ParamFile._check_params.txt diff --git a/docs/source/_summaries/bladex.params.ParamFile.read_parameters.rst b/_sources/_summaries/bladex.params.ParamFile.read_parameters.txt similarity index 100% rename from docs/source/_summaries/bladex.params.ParamFile.read_parameters.rst rename to _sources/_summaries/bladex.params.ParamFile.read_parameters.txt diff --git a/docs/source/_summaries/bladex.params.ParamFile.write_parameters.rst b/_sources/_summaries/bladex.params.ParamFile.write_parameters.txt similarity index 100% rename from docs/source/_summaries/bladex.params.ParamFile.write_parameters.rst rename to _sources/_summaries/bladex.params.ParamFile.write_parameters.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase._update_edges.rst b/_sources/_summaries/bladex.profilebase.ProfileBase._update_edges.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase._update_edges.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase._update_edges.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.chord_length.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.chord_length.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.chord_length.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.chord_length.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.compute_camber_line.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.compute_camber_line.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.compute_camber_line.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.compute_camber_line.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.compute_chord_line.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.compute_chord_line.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.compute_chord_line.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.compute_chord_line.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.deform_camber_line.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.deform_camber_line.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.deform_camber_line.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.deform_camber_line.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.interpolate_coordinates.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.interpolate_coordinates.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.interpolate_coordinates.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.interpolate_coordinates.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.max_camber.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.max_camber.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.max_camber.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.max_camber.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.max_thickness.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.max_thickness.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.max_thickness.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.max_thickness.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.plot.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.plot.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.plot.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.plot.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.reference_point.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.reference_point.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.reference_point.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.reference_point.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.reflect.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.reflect.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.reflect.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.reflect.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.rotate.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.rotate.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.rotate.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.rotate.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.scale.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.scale.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.scale.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.scale.txt diff --git a/docs/source/_summaries/bladex.profilebase.ProfileBase.translate.rst b/_sources/_summaries/bladex.profilebase.ProfileBase.translate.txt similarity index 100% rename from docs/source/_summaries/bladex.profilebase.ProfileBase.translate.rst rename to _sources/_summaries/bladex.profilebase.ProfileBase.translate.txt diff --git a/docs/source/_summaries/bladex.profiles.CustomProfile._check_coordinates.rst b/_sources/_summaries/bladex.profiles.CustomProfile._check_coordinates.txt similarity index 100% rename from docs/source/_summaries/bladex.profiles.CustomProfile._check_coordinates.rst rename to _sources/_summaries/bladex.profiles.CustomProfile._check_coordinates.txt diff --git a/docs/source/_summaries/bladex.profiles.NacaProfile._check_args.rst b/_sources/_summaries/bladex.profiles.NacaProfile._check_args.txt similarity index 100% rename from docs/source/_summaries/bladex.profiles.NacaProfile._check_args.rst rename to _sources/_summaries/bladex.profiles.NacaProfile._check_args.txt diff --git a/docs/source/_summaries/bladex.profiles.NacaProfile._generate_coordinates.rst b/_sources/_summaries/bladex.profiles.NacaProfile._generate_coordinates.txt similarity index 100% rename from docs/source/_summaries/bladex.profiles.NacaProfile._generate_coordinates.rst rename to _sources/_summaries/bladex.profiles.NacaProfile._generate_coordinates.txt diff --git a/docs/source/blade.rst b/_sources/blade.txt similarity index 100% rename from docs/source/blade.rst rename to _sources/blade.txt diff --git a/docs/source/code.rst b/_sources/code.txt similarity index 100% rename from docs/source/code.rst rename to _sources/code.txt diff --git a/docs/source/contact.rst b/_sources/contact.txt similarity index 100% rename from docs/source/contact.rst rename to _sources/contact.txt diff --git a/docs/source/contributing.rst b/_sources/contributing.txt similarity index 100% rename from docs/source/contributing.rst rename to _sources/contributing.txt diff --git a/docs/source/deform.rst b/_sources/deform.txt similarity index 100% rename from docs/source/deform.rst rename to _sources/deform.txt diff --git a/docs/source/index.rst b/_sources/index.txt similarity index 97% rename from docs/source/index.rst rename to _sources/index.txt index 0e1051e..0e8a271 100644 --- a/docs/source/index.rst +++ b/_sources/index.txt @@ -21,12 +21,12 @@ BladeX is compatible with Python 2.7 and Python 3.6. Moreover, some of the modul Python2.7 OCC installation: :: - conda install -c conda-forge -c dlr-sc -c pythonocc -c oce pythonocc-core==0.18.1 smesh=6.7.5 python=2.7 + conda install -c conda-forge -c dlr-sc -c pythonocc -c oce pythonocc-core==0.18.1 python=2.7 Python3.6 OCC installation: :: - conda install -c conda-forge -c dlr-sc -c pythonocc -c oce pythonocc-core==0.18.1 smesh=6.7.5 python=3.6 + conda install -c conda-forge -c dlr-sc -c pythonocc -c oce pythonocc-core==0.18.1 python=3.6 The `official distribution `_ is on GitHub, and you can clone the repository using diff --git a/docs/source/ndinterpolator.rst b/_sources/ndinterpolator.txt similarity index 100% rename from docs/source/ndinterpolator.rst rename to _sources/ndinterpolator.txt diff --git a/docs/source/params.rst b/_sources/params.txt similarity index 100% rename from docs/source/params.rst rename to _sources/params.txt diff --git a/docs/source/profilebase.rst b/_sources/profilebase.txt similarity index 100% rename from docs/source/profilebase.rst rename to _sources/profilebase.txt diff --git a/docs/source/profiles.rst b/_sources/profiles.txt similarity index 100% rename from docs/source/profiles.rst rename to _sources/profiles.txt diff --git a/_static/ajax-loader.gif b/_static/ajax-loader.gif new file mode 100644 index 0000000..61faf8c Binary files /dev/null and b/_static/ajax-loader.gif differ diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..65dfd7d --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,608 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + width: 30px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/comment-bright.png b/_static/comment-bright.png new file mode 100644 index 0000000..551517b Binary files /dev/null and b/_static/comment-bright.png differ diff --git a/_static/comment-close.png b/_static/comment-close.png new file mode 100644 index 0000000..09b54be Binary files /dev/null and b/_static/comment-close.png differ diff --git a/_static/comment.png b/_static/comment.png new file mode 100644 index 0000000..92feb52 Binary files /dev/null and b/_static/comment.png differ diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 0000000..7e17fb1 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1,2 @@ +.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-weight:normal;font-style:normal;src:url("../font/fontawesome_webfont.eot");src:url("../font/fontawesome_webfont.eot?#iefix") format("embedded-opentype"),url("../font/fontawesome_webfont.woff") format("woff"),url("../font/fontawesome_webfont.ttf") format("truetype"),url("../font/fontawesome_webfont.svg#FontAwesome") format("svg")}.fa:before{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa{display:inline-block;text-decoration:inherit}li .fa{display:inline-block}li .fa-large:before,li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-0.8em}ul.fas li .fa{width:0.8em}ul.fas li .fa-large:before,ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before{content:""}.icon-book:before{content:""}.fa-caret-down:before{content:""}.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.icon-caret-up:before{content:""}.fa-caret-left:before{content:""}.icon-caret-left:before{content:""}.fa-caret-right:before{content:""}.icon-caret-right:before{content:""}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}} +/*# sourceMappingURL=badge_only.css.map */ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 0000000..7be9339 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,5 @@ +*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}[hidden]{display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:hover,a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;color:#000;text-decoration:none}mark{background:#ff0;color:#000;font-style:italic;font-weight:bold}pre,code,.rst-content tt,.rst-content code,kbd,samp{font-family:monospace,serif;_font-family:"courier new",monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:before,q:after{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}ul,ol,dl{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:0;margin:0;padding:0}label{cursor:pointer}legend{border:0;*margin-left:-7px;padding:0;white-space:normal}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0;*width:13px;*height:13px}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top;resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:0.2em 0;background:#ccc;color:#000;padding:0.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{html,body,section{background:none !important}*{box-shadow:none !important;text-shadow:none !important;filter:none !important;-ms-filter:none !important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,.rst-content .toctree-wrapper p.caption,h3{orphans:3;widows:3}h2,.rst-content .toctree-wrapper p.caption,h3{page-break-after:avoid}}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo,.btn,input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"],select,textarea,.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a,.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a,.wy-nav-top a{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url("../fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.wy-menu-vertical li span.pull-left.toctree-expand,.wy-menu-vertical li.on a span.pull-left.toctree-expand,.wy-menu-vertical li.current>a span.pull-left.toctree-expand,.rst-content .pull-left.admonition-title,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content dl dt .pull-left.headerlink,.rst-content p.caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.rst-content code.download span.pull-left:first-child,.pull-left.icon{margin-right:.3em}.fa.pull-right,.wy-menu-vertical li span.pull-right.toctree-expand,.wy-menu-vertical li.on a span.pull-right.toctree-expand,.wy-menu-vertical li.current>a span.pull-right.toctree-expand,.rst-content .pull-right.admonition-title,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content dl dt .pull-right.headerlink,.rst-content p.caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.rst-content code.download span.pull-right:first-child,.pull-right.icon{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-remove:before,.fa-close:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-gear:before,.fa-cog:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-rotate-right:before,.fa-repeat:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.rst-content .admonition-title:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-warning:before,.fa-exclamation-triangle:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-gears:before,.fa-cogs:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-save:before,.fa-floppy-o:before{content:""}.fa-square:before{content:""}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.wy-dropdown .caret:before,.icon-caret-down:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-unsorted:before,.fa-sort:before{content:""}.fa-sort-down:before,.fa-sort-desc:before{content:""}.fa-sort-up:before,.fa-sort-asc:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-legal:before,.fa-gavel:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-flash:before,.fa-bolt:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-paste:before,.fa-clipboard:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-unlink:before,.fa-chain-broken:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:""}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:""}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:""}.fa-euro:before,.fa-eur:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-rupee:before,.fa-inr:before{content:""}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:""}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:""}.fa-won:before,.fa-krw:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-turkish-lira:before,.fa-try:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li span.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-institution:before,.fa-bank:before,.fa-university:before{content:""}.fa-mortar-board:before,.fa-graduation-cap:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:""}.fa-file-zip-o:before,.fa-file-archive-o:before{content:""}.fa-file-sound-o:before,.fa-file-audio-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before{content:""}.fa-ge:before,.fa-empire:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-send:before,.fa-paper-plane:before{content:""}.fa-send-o:before,.fa-paper-plane-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:""}.fa-meanpath:before{content:""}.fa,.wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,.rst-content .admonition-title,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink,.rst-content tt.download span:first-child,.rst-content code.download span:first-child,.icon,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context{font-family:inherit}.fa:before,.wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li.on a span.toctree-expand:before,.wy-menu-vertical li.current>a span.toctree-expand:before,.rst-content .admonition-title:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content dl dt .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before,.icon:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before{font-family:"FontAwesome";display:inline-block;font-style:normal;font-weight:normal;line-height:1;text-decoration:inherit}a .fa,a .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li a span.toctree-expand,.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand,a .rst-content .admonition-title,.rst-content a .admonition-title,a .rst-content h1 .headerlink,.rst-content h1 a .headerlink,a .rst-content h2 .headerlink,.rst-content h2 a .headerlink,a .rst-content h3 .headerlink,.rst-content h3 a .headerlink,a .rst-content h4 .headerlink,.rst-content h4 a .headerlink,a .rst-content h5 .headerlink,.rst-content h5 a .headerlink,a .rst-content h6 .headerlink,.rst-content h6 a .headerlink,a .rst-content dl dt .headerlink,.rst-content dl dt a .headerlink,a .rst-content p.caption .headerlink,.rst-content p.caption a .headerlink,a .rst-content tt.download span:first-child,.rst-content tt.download a span:first-child,a .rst-content code.download span:first-child,.rst-content code.download a span:first-child,a .icon{display:inline-block;text-decoration:inherit}.btn .fa,.btn .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .btn span.toctree-expand,.btn .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .btn span.toctree-expand,.btn .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .btn span.toctree-expand,.btn .rst-content .admonition-title,.rst-content .btn .admonition-title,.btn .rst-content h1 .headerlink,.rst-content h1 .btn .headerlink,.btn .rst-content h2 .headerlink,.rst-content h2 .btn .headerlink,.btn .rst-content h3 .headerlink,.rst-content h3 .btn .headerlink,.btn .rst-content h4 .headerlink,.rst-content h4 .btn .headerlink,.btn .rst-content h5 .headerlink,.rst-content h5 .btn .headerlink,.btn .rst-content h6 .headerlink,.rst-content h6 .btn .headerlink,.btn .rst-content dl dt .headerlink,.rst-content dl dt .btn .headerlink,.btn .rst-content p.caption .headerlink,.rst-content p.caption .btn .headerlink,.btn .rst-content tt.download span:first-child,.rst-content tt.download .btn span:first-child,.btn .rst-content code.download span:first-child,.rst-content code.download .btn span:first-child,.btn .icon,.nav .fa,.nav .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .nav span.toctree-expand,.nav .wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.on a .nav span.toctree-expand,.nav .wy-menu-vertical li.current>a span.toctree-expand,.wy-menu-vertical li.current>a .nav span.toctree-expand,.nav .rst-content .admonition-title,.rst-content .nav .admonition-title,.nav .rst-content h1 .headerlink,.rst-content h1 .nav .headerlink,.nav .rst-content h2 .headerlink,.rst-content h2 .nav .headerlink,.nav .rst-content h3 .headerlink,.rst-content h3 .nav .headerlink,.nav .rst-content h4 .headerlink,.rst-content h4 .nav .headerlink,.nav .rst-content h5 .headerlink,.rst-content h5 .nav .headerlink,.nav .rst-content h6 .headerlink,.rst-content h6 .nav .headerlink,.nav .rst-content dl dt .headerlink,.rst-content dl dt .nav .headerlink,.nav .rst-content p.caption .headerlink,.rst-content p.caption .nav .headerlink,.nav .rst-content tt.download span:first-child,.rst-content tt.download .nav span:first-child,.nav .rst-content code.download span:first-child,.rst-content code.download .nav span:first-child,.nav .icon{display:inline}.btn .fa.fa-large,.btn .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .btn span.fa-large.toctree-expand,.btn .rst-content .fa-large.admonition-title,.rst-content .btn .fa-large.admonition-title,.btn .rst-content h1 .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.btn .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .btn .fa-large.headerlink,.btn .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .btn .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .btn span.fa-large:first-child,.btn .rst-content code.download span.fa-large:first-child,.rst-content code.download .btn span.fa-large:first-child,.btn .fa-large.icon,.nav .fa.fa-large,.nav .wy-menu-vertical li span.fa-large.toctree-expand,.wy-menu-vertical li .nav span.fa-large.toctree-expand,.nav .rst-content .fa-large.admonition-title,.rst-content .nav .fa-large.admonition-title,.nav .rst-content h1 .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.nav .rst-content dl dt .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.nav .rst-content p.caption .fa-large.headerlink,.rst-content p.caption .nav .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.nav .rst-content code.download span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.nav .fa-large.icon{line-height:0.9em}.btn .fa.fa-spin,.btn .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .btn span.fa-spin.toctree-expand,.btn .rst-content .fa-spin.admonition-title,.rst-content .btn .fa-spin.admonition-title,.btn .rst-content h1 .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.btn .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .btn .fa-spin.headerlink,.btn .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .btn .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .btn span.fa-spin:first-child,.btn .rst-content code.download span.fa-spin:first-child,.rst-content code.download .btn span.fa-spin:first-child,.btn .fa-spin.icon,.nav .fa.fa-spin,.nav .wy-menu-vertical li span.fa-spin.toctree-expand,.wy-menu-vertical li .nav span.fa-spin.toctree-expand,.nav .rst-content .fa-spin.admonition-title,.rst-content .nav .fa-spin.admonition-title,.nav .rst-content h1 .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.nav .rst-content dl dt .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.nav .rst-content p.caption .fa-spin.headerlink,.rst-content p.caption .nav .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.nav .rst-content code.download span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.nav .fa-spin.icon{display:inline-block}.btn.fa:before,.wy-menu-vertical li span.btn.toctree-expand:before,.rst-content .btn.admonition-title:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content dl dt .btn.headerlink:before,.rst-content p.caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.rst-content code.download span.btn:first-child:before,.btn.icon:before{opacity:0.5;-webkit-transition:opacity 0.05s ease-in;-moz-transition:opacity 0.05s ease-in;transition:opacity 0.05s ease-in}.btn.fa:hover:before,.wy-menu-vertical li span.btn.toctree-expand:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content p.caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.rst-content code.download span.btn:first-child:hover:before,.btn.icon:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .wy-menu-vertical li span.toctree-expand:before,.wy-menu-vertical li .btn-mini span.toctree-expand:before,.btn-mini .rst-content .admonition-title:before,.rst-content .btn-mini .admonition-title:before,.btn-mini .rst-content h1 .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.btn-mini .rst-content dl dt .headerlink:before,.rst-content dl dt .btn-mini .headerlink:before,.btn-mini .rst-content p.caption .headerlink:before,.rst-content p.caption .btn-mini .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.rst-content tt.download .btn-mini span:first-child:before,.btn-mini .rst-content code.download span:first-child:before,.rst-content code.download .btn-mini span:first-child:before,.btn-mini .icon:before{font-size:14px;vertical-align:-15%}.wy-alert,.rst-content .note,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .warning,.rst-content .seealso,.rst-content .admonition-todo{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.wy-alert-title,.rst-content .admonition-title{color:#fff;font-weight:bold;display:block;color:#fff;background:#6ab0de;margin:-12px;padding:6px 12px;margin-bottom:12px}.wy-alert.wy-alert-danger,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.admonition-todo{background:#fdf3f2}.wy-alert.wy-alert-danger .wy-alert-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .danger .wy-alert-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .danger .admonition-title,.rst-content .error .admonition-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title{background:#f29f97}.wy-alert.wy-alert-warning,.rst-content .wy-alert-warning.note,.rst-content .attention,.rst-content .caution,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.tip,.rst-content .warning,.rst-content .wy-alert-warning.seealso,.rst-content .admonition-todo{background:#ffedcc}.wy-alert.wy-alert-warning .wy-alert-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .attention .wy-alert-title,.rst-content .caution .wy-alert-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .admonition-todo .wy-alert-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .attention .admonition-title,.rst-content .caution .admonition-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .warning .admonition-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .admonition-todo .admonition-title{background:#f0b37e}.wy-alert.wy-alert-info,.rst-content .note,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.rst-content .seealso,.rst-content .wy-alert-info.admonition-todo{background:#e7f2fa}.wy-alert.wy-alert-info .wy-alert-title,.rst-content .note .wy-alert-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.rst-content .note .admonition-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .seealso .admonition-title,.rst-content .wy-alert-info.admonition-todo .admonition-title{background:#6ab0de}.wy-alert.wy-alert-success,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.warning,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.admonition-todo{background:#dbfaf4}.wy-alert.wy-alert-success .wy-alert-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .hint .wy-alert-title,.rst-content .important .wy-alert-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .hint .admonition-title,.rst-content .important .admonition-title,.rst-content .tip .admonition-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.admonition-todo .admonition-title{background:#1abc9c}.wy-alert.wy-alert-neutral,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.admonition-todo{background:#f3f6f6}.wy-alert.wy-alert-neutral .wy-alert-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .admonition-title{color:#404040;background:#e1e4e5}.wy-alert.wy-alert-neutral a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.admonition-todo a{color:#2980B9}.wy-alert p:last-child,.rst-content .note p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.rst-content .seealso p:last-child,.rst-content .admonition-todo p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0px;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,0.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all 0.3s ease-in;-moz-transition:all 0.3s ease-in;transition:all 0.3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27AE60}.wy-tray-container li.wy-tray-item-info{background:#2980B9}.wy-tray-container li.wy-tray-item-warning{background:#E67E22}.wy-tray-container li.wy-tray-item-danger{background:#E74C3C}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width: 768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px 12px;color:#fff;border:1px solid rgba(0,0,0,0.1);background-color:#27AE60;text-decoration:none;font-weight:normal;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:0px 1px 2px -1px rgba(255,255,255,0.5) inset,0px -2px 0px 0px rgba(0,0,0,0.1) inset;outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all 0.1s linear;-moz-transition:all 0.1s linear;transition:all 0.1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:0px -1px 0px 0px rgba(0,0,0,0.05) inset,0px 2px 0px 0px rgba(0,0,0,0.1) inset;padding:8px 12px 6px 12px}.btn:visited{color:#fff}.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn-disabled:hover,.btn-disabled:focus,.btn-disabled:active{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:0.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980B9 !important}.btn-info:hover{background-color:#2e8ece !important}.btn-neutral{background-color:#f3f6f6 !important;color:#404040 !important}.btn-neutral:hover{background-color:#e5ebeb !important;color:#404040}.btn-neutral:visited{color:#404040 !important}.btn-success{background-color:#27AE60 !important}.btn-success:hover{background-color:#295 !important}.btn-danger{background-color:#E74C3C !important}.btn-danger:hover{background-color:#ea6153 !important}.btn-warning{background-color:#E67E22 !important}.btn-warning:hover{background-color:#e98b39 !important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f !important}.btn-link{background-color:transparent !important;color:#2980B9;box-shadow:none;border-color:transparent !important}.btn-link:hover{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:active{background-color:transparent !important;color:#409ad5 !important;box-shadow:none}.btn-link:visited{color:#9B59B6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:before,.wy-btn-group:after{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:solid 1px #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,0.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980B9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:solid 1px #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type="search"]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980B9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned input,.wy-form-aligned textarea,.wy-form-aligned select,.wy-form-aligned .wy-help-inline,.wy-form-aligned label{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{border:0;margin:0;padding:0}legend{display:block;width:100%;border:0;padding:0;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label{display:block;margin:0 0 0.3125em 0;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;*zoom:1;max-width:68em;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group:before,.wy-control-group:after{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#E74C3C}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full input[type="text"],.wy-control-group .wy-form-full input[type="password"],.wy-control-group .wy-form-full input[type="email"],.wy-control-group .wy-form-full input[type="url"],.wy-control-group .wy-form-full input[type="date"],.wy-control-group .wy-form-full input[type="month"],.wy-control-group .wy-form-full input[type="time"],.wy-control-group .wy-form-full input[type="datetime"],.wy-control-group .wy-form-full input[type="datetime-local"],.wy-control-group .wy-form-full input[type="week"],.wy-control-group .wy-form-full input[type="number"],.wy-control-group .wy-form-full input[type="search"],.wy-control-group .wy-form-full input[type="tel"],.wy-control-group .wy-form-full input[type="color"],.wy-control-group .wy-form-halves input[type="text"],.wy-control-group .wy-form-halves input[type="password"],.wy-control-group .wy-form-halves input[type="email"],.wy-control-group .wy-form-halves input[type="url"],.wy-control-group .wy-form-halves input[type="date"],.wy-control-group .wy-form-halves input[type="month"],.wy-control-group .wy-form-halves input[type="time"],.wy-control-group .wy-form-halves input[type="datetime"],.wy-control-group .wy-form-halves input[type="datetime-local"],.wy-control-group .wy-form-halves input[type="week"],.wy-control-group .wy-form-halves input[type="number"],.wy-control-group .wy-form-halves input[type="search"],.wy-control-group .wy-form-halves input[type="tel"],.wy-control-group .wy-form-halves input[type="color"],.wy-control-group .wy-form-thirds input[type="text"],.wy-control-group .wy-form-thirds input[type="password"],.wy-control-group .wy-form-thirds input[type="email"],.wy-control-group .wy-form-thirds input[type="url"],.wy-control-group .wy-form-thirds input[type="date"],.wy-control-group .wy-form-thirds input[type="month"],.wy-control-group .wy-form-thirds input[type="time"],.wy-control-group .wy-form-thirds input[type="datetime"],.wy-control-group .wy-form-thirds input[type="datetime-local"],.wy-control-group .wy-form-thirds input[type="week"],.wy-control-group .wy-form-thirds input[type="number"],.wy-control-group .wy-form-thirds input[type="search"],.wy-control-group .wy-form-thirds input[type="tel"],.wy-control-group .wy-form-thirds input[type="color"]{width:100%}.wy-control-group .wy-form-full{float:left;display:block;margin-right:2.35765%;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child{margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(2n+1){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child{margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control{margin:6px 0 0 0;font-size:90%}.wy-control-no-input{display:inline-block;margin:6px 0 0 0;font-size:90%}.wy-control-group.fluid-input input[type="text"],.wy-control-group.fluid-input input[type="password"],.wy-control-group.fluid-input input[type="email"],.wy-control-group.fluid-input input[type="url"],.wy-control-group.fluid-input input[type="date"],.wy-control-group.fluid-input input[type="month"],.wy-control-group.fluid-input input[type="time"],.wy-control-group.fluid-input input[type="datetime"],.wy-control-group.fluid-input input[type="datetime-local"],.wy-control-group.fluid-input input[type="week"],.wy-control-group.fluid-input input[type="number"],.wy-control-group.fluid-input input[type="search"],.wy-control-group.fluid-input input[type="tel"],.wy-control-group.fluid-input input[type="color"]{width:100%}.wy-form-message-inline{display:inline-block;padding-left:0.3em;color:#666;vertical-align:middle;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:0.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*overflow:visible}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="date"],input[type="month"],input[type="time"],input[type="datetime"],input[type="datetime-local"],input[type="week"],input[type="number"],input[type="search"],input[type="tel"],input[type="color"]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}input[type="datetime-local"]{padding:0.34375em 0.625em}input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;margin-right:0.3125em;*height:13px;*width:13px}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}input[type="text"]:focus,input[type="password"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus{outline:0;outline:thin dotted \9;border-color:#333}input.no-focus:focus{border-color:#ccc !important}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129FEA}input[type="text"][disabled],input[type="password"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="search"][disabled],input[type="tel"][disabled],input[type="color"][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#E74C3C;border:1px solid #E74C3C}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#E74C3C}input[type="file"]:focus:invalid:focus,input[type="radio"]:focus:invalid:focus,input[type="checkbox"]:focus:invalid:focus{outline-color:#E74C3C}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif}select,textarea{padding:0.5em 0.625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border 0.3s linear;-moz-transition:border 0.3s linear;transition:border 0.3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type="radio"][disabled],input[type="checkbox"][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:solid 1px #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{width:36px;height:12px;margin:12px 0;position:relative;border-radius:4px;background:#ccc;cursor:pointer;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:before{position:absolute;content:"";display:block;width:18px;height:18px;border-radius:4px;background:#999;left:-3px;top:-3px;-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.wy-switch:after{content:"false";position:absolute;left:48px;display:block;font-size:12px;color:#ccc}.wy-switch.active{background:#1e8449}.wy-switch.active:before{left:24px;background:#27AE60}.wy-switch.active:after{content:"true"}.wy-switch.disabled,.wy-switch.active.disabled{cursor:not-allowed}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#E74C3C}.wy-control-group.wy-control-group-error input[type="text"],.wy-control-group.wy-control-group-error input[type="password"],.wy-control-group.wy-control-group-error input[type="email"],.wy-control-group.wy-control-group-error input[type="url"],.wy-control-group.wy-control-group-error input[type="date"],.wy-control-group.wy-control-group-error input[type="month"],.wy-control-group.wy-control-group-error input[type="time"],.wy-control-group.wy-control-group-error input[type="datetime"],.wy-control-group.wy-control-group-error input[type="datetime-local"],.wy-control-group.wy-control-group-error input[type="week"],.wy-control-group.wy-control-group-error input[type="number"],.wy-control-group.wy-control-group-error input[type="search"],.wy-control-group.wy-control-group-error input[type="tel"],.wy-control-group.wy-control-group-error input[type="color"]{border:solid 1px #E74C3C}.wy-control-group.wy-control-group-error textarea{border:solid 1px #E74C3C}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:0.5em 0.625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27AE60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#E74C3C}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#E67E22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980B9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width: 480px){.wy-form button[type="submit"]{margin:0.7em 0 0}.wy-form input[type="text"],.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0.3em;display:block}.wy-form label{margin-bottom:0.3em;display:block}.wy-form input[type="password"],.wy-form input[type="email"],.wy-form input[type="url"],.wy-form input[type="date"],.wy-form input[type="month"],.wy-form input[type="time"],.wy-form input[type="datetime"],.wy-form input[type="datetime-local"],.wy-form input[type="week"],.wy-form input[type="number"],.wy-form input[type="search"],.wy-form input[type="tel"],.wy-form input[type="color"]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:0.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0 0}.wy-form .wy-help-inline,.wy-form-message-inline,.wy-form-message{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width: 768px){.tablet-hide{display:none}}@media screen and (max-width: 480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.wy-table,.rst-content table.docutils,.rst-content table.field-list{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.wy-table caption,.rst-content table.docutils caption,.rst-content table.field-list caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td,.wy-table th,.rst-content table.docutils th,.rst-content table.field-list th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.wy-table td:first-child,.rst-content table.docutils td:first-child,.rst-content table.field-list td:first-child,.wy-table th:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list th:first-child{border-left-width:0}.wy-table thead,.rst-content table.docutils thead,.rst-content table.field-list thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.wy-table thead th,.rst-content table.docutils thead th,.rst-content table.field-list thead th{font-weight:bold;border-bottom:solid 2px #e1e4e5}.wy-table td,.rst-content table.docutils td,.rst-content table.field-list td{background-color:transparent;vertical-align:middle}.wy-table td p,.rst-content table.docutils td p,.rst-content table.field-list td p{line-height:18px}.wy-table td p:last-child,.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child{margin-bottom:0}.wy-table .wy-table-cell-min,.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min{width:1%;padding-right:0}.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox],.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:gray;font-size:90%}.wy-table-tertiary{color:gray;font-size:80%}.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td,.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td{background-color:#f3f6f6}.wy-table-backed{background-color:#f3f6f6}.wy-table-bordered-all,.rst-content table.docutils{border:1px solid #e1e4e5}.wy-table-bordered-all td,.rst-content table.docutils td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.wy-table-bordered-all tbody>tr:last-child td,.rst-content table.docutils tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0 !important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980B9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9B59B6}html{height:100%;overflow-x:hidden}body{font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;font-weight:normal;color:#404040;min-height:100%;overflow-x:hidden;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#E67E22 !important}a.wy-text-warning:hover{color:#eb9950 !important}.wy-text-info{color:#2980B9 !important}a.wy-text-info:hover{color:#409ad5 !important}.wy-text-success{color:#27AE60 !important}a.wy-text-success:hover{color:#36d278 !important}.wy-text-danger{color:#E74C3C !important}a.wy-text-danger:hover{color:#ed7669 !important}.wy-text-neutral{color:#404040 !important}a.wy-text-neutral:hover{color:#595959 !important}h1,h2,.rst-content .toctree-wrapper p.caption,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif}p{line-height:24px;margin:0;font-size:16px;margin-bottom:24px}h1{font-size:175%}h2,.rst-content .toctree-wrapper p.caption{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}code,.rst-content tt,.rst-content code{white-space:nowrap;max-width:100%;background:#fff;border:solid 1px #e1e4e5;font-size:75%;padding:0 5px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;color:#E74C3C;overflow-x:auto}code.code-large,.rst-content tt.code-large{font-size:90%}.wy-plain-list-disc,.rst-content .section ul,.rst-content .toctree-wrapper ul,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.wy-plain-list-disc li,.rst-content .section ul li,.rst-content .toctree-wrapper ul li,article ul li{list-style:disc;margin-left:24px}.wy-plain-list-disc li p:last-child,.rst-content .section ul li p:last-child,.rst-content .toctree-wrapper ul li p:last-child,article ul li p:last-child{margin-bottom:0}.wy-plain-list-disc li ul,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li ul,article ul li ul{margin-bottom:0}.wy-plain-list-disc li li,.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,article ul li li{list-style:circle}.wy-plain-list-disc li li li,.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,article ul li li li{list-style:square}.wy-plain-list-disc li ol li,.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,article ul li ol li{list-style:decimal}.wy-plain-list-decimal,.rst-content .section ol,.rst-content ol.arabic,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.wy-plain-list-decimal li,.rst-content .section ol li,.rst-content ol.arabic li,article ol li{list-style:decimal;margin-left:24px}.wy-plain-list-decimal li p:last-child,.rst-content .section ol li p:last-child,.rst-content ol.arabic li p:last-child,article ol li p:last-child{margin-bottom:0}.wy-plain-list-decimal li ul,.rst-content .section ol li ul,.rst-content ol.arabic li ul,article ol li ul{margin-bottom:0}.wy-plain-list-decimal li ul li,.rst-content .section ol li ul li,.rst-content ol.arabic li ul li,article ol li ul li{list-style:disc}.codeblock-example{border:1px solid #e1e4e5;border-bottom:none;padding:24px;padding-top:48px;font-weight:500;background:#fff;position:relative}.codeblock-example:after{content:"Example";position:absolute;top:0px;left:0px;background:#9B59B6;color:#fff;padding:6px 12px}.codeblock-example.prettyprint-example-only{border:1px solid #e1e4e5;margin-bottom:24px}.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight']{border:1px solid #e1e4e5;padding:0px;overflow-x:auto;background:#fff;margin:1px 0 24px 0}.codeblock div[class^='highlight'],pre.literal-block div[class^='highlight'],.rst-content .literal-block div[class^='highlight'],div[class^='highlight'] div[class^='highlight']{border:none;background:none;margin:0}div[class^='highlight'] td.code{width:100%}.linenodiv pre{border-right:solid 1px #e6e9ea;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;color:#d9d9d9}div[class^='highlight'] pre{white-space:pre;margin:0;padding:12px 12px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:12px;line-height:1.5;display:block;overflow:auto;color:#404040}@media print{.codeblock,pre.literal-block,.rst-content .literal-block,.rst-content pre.literal-block,div[class^='highlight'],div[class^='highlight'] pre{white-space:pre-wrap}}.hll{background-color:#ffc;margin:0 -12px;padding:0 12px;display:block}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{font-weight:bold}.o{font-weight:bold}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:bold}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:bold;font-style:italic}.gd{color:#000;background-color:#fdd}.gd .x{color:#000;background-color:#faa}.ge{font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.gi .x{color:#000;background-color:#afa}.go{color:#888}.gp{color:#555}.gs{font-weight:bold}.gu{color:purple;font-weight:bold}.gt{color:#a00}.kc{font-weight:bold}.kd{font-weight:bold}.kn{font-weight:bold}.kp{font-weight:bold}.kr{font-weight:bold}.kt{color:#458;font-weight:bold}.m{color:#099}.s{color:#d14}.n{color:#333}.na{color:teal}.nb{color:#0086b3}.nc{color:#458;font-weight:bold}.no{color:teal}.ni{color:purple}.ne{color:#900;font-weight:bold}.nf{color:#900;font-weight:bold}.nn{color:#555}.nt{color:navy}.nv{color:teal}.ow{font-weight:bold}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d14}.sc{color:#d14}.sd{color:#d14}.s2{color:#d14}.se{color:#d14}.sh{color:#d14}.si{color:#d14}.sx{color:#d14}.sr{color:#009926}.s1{color:#d14}.ss{color:#990073}.bp{color:#999}.vc{color:teal}.vg{color:teal}.vi{color:teal}.il{color:#099}.gc{color:#999;background-color:#EAF2F5}.wy-breadcrumbs li{display:inline-block}.wy-breadcrumbs li.wy-breadcrumbs-aside{float:right}.wy-breadcrumbs li a{display:inline-block;padding:5px}.wy-breadcrumbs li a:first-child{padding-left:0}.wy-breadcrumbs li code,.wy-breadcrumbs li .rst-content tt,.rst-content .wy-breadcrumbs li tt{padding:5px;border:none;background:none}.wy-breadcrumbs li code.literal,.wy-breadcrumbs li .rst-content tt.literal,.rst-content .wy-breadcrumbs li tt.literal{color:#404040}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width: 480px){.wy-breadcrumbs-extra{display:none}.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:before,.wy-menu-horiz:after{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz ul,.wy-menu-horiz li{display:inline-block}.wy-menu-horiz li:hover{background:rgba(255,255,255,0.1)}.wy-menu-horiz li.divide-left{border-left:solid 1px #404040}.wy-menu-horiz li.divide-right{border-right:solid 1px #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{height:32px;display:inline-block;line-height:32px;padding:0 1.618em;margin-bottom:0;display:block;font-weight:bold;text-transform:uppercase;font-size:80%;color:#555;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:solid 1px #404040}.wy-menu-vertical li.divide-bottom{border-bottom:solid 1px #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:gray;border-right:solid 1px #c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.wy-menu-vertical li code,.wy-menu-vertical li .rst-content tt,.rst-content .wy-menu-vertical li tt{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li span.toctree-expand{display:block;float:left;margin-left:-1.2em;font-size:0.8em;line-height:1.6em;color:#4d4d4d}.wy-menu-vertical li.on a,.wy-menu-vertical li.current>a{color:#404040;padding:0.4045em 1.618em;font-weight:bold;position:relative;background:#fcfcfc;border:none;border-bottom:solid 1px #c9c9c9;border-top:solid 1px #c9c9c9;padding-left:1.618em -4px}.wy-menu-vertical li.on a:hover,.wy-menu-vertical li.current>a:hover{background:#fcfcfc}.wy-menu-vertical li.on a:hover span.toctree-expand,.wy-menu-vertical li.current>a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.on a span.toctree-expand,.wy-menu-vertical li.current>a span.toctree-expand{display:block;font-size:0.8em;line-height:1.6em;color:#333}.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul{display:none}.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul{display:block}.wy-menu-vertical li.toctree-l2.current>a{background:#c9c9c9;padding:0.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{display:block;background:#c9c9c9;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l2 span.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3{font-size:0.9em}.wy-menu-vertical li.toctree-l3.current>a{background:#bdbdbd;padding:0.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{display:block;background:#bdbdbd;padding:0.4045em 5.663em;border-top:none;border-bottom:none}.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand{color:gray}.wy-menu-vertical li.toctree-l3 span.toctree-expand{color:#969696}.wy-menu-vertical li.toctree-l4{font-size:0.9em}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical .local-toc li ul{display:block}.wy-menu-vertical li ul li a{margin-bottom:0;color:#b3b3b3;font-weight:normal}.wy-menu-vertical a{display:inline-block;line-height:18px;padding:0.4045em 1.618em;display:block;position:relative;font-size:90%;color:#b3b3b3}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover span.toctree-expand{color:#b3b3b3}.wy-menu-vertical a:active{background-color:#2980B9;cursor:pointer;color:#fff}.wy-menu-vertical a:active span.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:0.809em;margin-bottom:0.809em;z-index:200;background-color:#2980B9;text-align:center;padding:0.809em;display:block;color:#fcfcfc;margin-bottom:0.809em}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto 0.809em auto;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-side-nav-search>a,.wy-side-nav-search .wy-dropdown>a{color:#fcfcfc;font-size:100%;font-weight:bold;display:inline-block;padding:4px 6px;margin-bottom:0.809em}.wy-side-nav-search>a:hover,.wy-side-nav-search .wy-dropdown>a:hover{background:rgba(255,255,255,0.1)}.wy-side-nav-search>a img.logo,.wy-side-nav-search .wy-dropdown>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search>a.icon img.logo,.wy-side-nav-search .wy-dropdown>a.icon img.logo{margin-top:0.85em}.wy-side-nav-search>div.version{margin-top:-0.4045em;margin-bottom:0.809em;font-weight:normal;color:rgba(255,255,255,0.3)}.wy-nav .wy-menu-vertical header{color:#2980B9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980B9;color:#fff}[data-menu-wrap]{-webkit-transition:all 0.2s ease-in;-moz-transition:all 0.2s ease-in;transition:all 0.2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:left repeat-y #fcfcfc;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);background-size:300px 1px}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980B9;color:#fff;padding:0.4045em 0.809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:before,.wy-nav-top:after{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:bold}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980B9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,0.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:#999}footer p{margin-bottom:12px}footer span.commit code,footer span.commit .rst-content tt,.rst-content footer span.commit tt{padding:0px;font-family:Consolas,"Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;font-size:1em;background:none;border:none;color:#999}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:before,.rst-footer-buttons:after{display:table;content:""}.rst-footer-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:solid 1px #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:solid 1px #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:gray;font-size:90%}@media screen and (max-width: 768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-side-scroll{width:auto}.wy-side-nav-search{width:auto}.wy-menu.wy-menu-vertical{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width: 1400px){.wy-nav-content-wrap{background:rgba(0,0,0,0.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,footer,.wy-nav-side{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;border-top:solid 10px #343131;font-family:"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;z-index:400}.rst-versions a{color:#2980B9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27AE60;*zoom:1}.rst-versions .rst-current-version:before,.rst-versions .rst-current-version:after{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content p.caption .headerlink,.rst-content p.caption .rst-versions .rst-current-version .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .icon{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#E74C3C;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#F1C40F;color:#000}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:gray;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:solid 1px #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px}.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge .rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width: 768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}img{width:100%;height:auto}}.rst-content img{max-width:100%;height:auto !important}.rst-content div.figure{margin-bottom:24px}.rst-content div.figure p.caption{font-style:italic}.rst-content div.figure.align-center{text-align:center}.rst-content .section>img,.rst-content .section>a>img{margin-bottom:24px}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content .note .last,.rst-content .attention .last,.rst-content .caution .last,.rst-content .danger .last,.rst-content .error .last,.rst-content .hint .last,.rst-content .important .last,.rst-content .tip .last,.rst-content .warning .last,.rst-content .seealso .last,.rst-content .admonition-todo .last{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,0.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent !important;border-color:rgba(0,0,0,0.1) !important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha li{list-style:upper-alpha}.rst-content .section ol p,.rst-content .section ul p{margin-bottom:12px}.rst-content .line-block{margin-left:24px}.rst-content .topic-title{font-weight:bold;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0px 0px 24px 24px}.rst-content .align-left{float:left;margin:0px 24px 24px 0px}.rst-content .align-center{margin:auto;display:block}.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content .toctree-wrapper p.caption .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content dl dt .headerlink,.rst-content p.caption .headerlink{display:none;visibility:hidden;font-size:14px}.rst-content h1 .headerlink:after,.rst-content h2 .headerlink:after,.rst-content .toctree-wrapper p.caption .headerlink:after,.rst-content h3 .headerlink:after,.rst-content h4 .headerlink:after,.rst-content h5 .headerlink:after,.rst-content h6 .headerlink:after,.rst-content dl dt .headerlink:after,.rst-content p.caption .headerlink:after{visibility:visible;content:"";font-family:FontAwesome;display:inline-block}.rst-content h1:hover .headerlink,.rst-content h2:hover .headerlink,.rst-content .toctree-wrapper p.caption:hover .headerlink,.rst-content h3:hover .headerlink,.rst-content h4:hover .headerlink,.rst-content h5:hover .headerlink,.rst-content h6:hover .headerlink,.rst-content dl dt:hover .headerlink,.rst-content p.caption:hover .headerlink{display:inline-block}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:solid 1px #e1e4e5}.rst-content .sidebar p,.rst-content .sidebar ul,.rst-content .sidebar dl{font-size:90%}.rst-content .sidebar .last{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:"Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif;font-weight:bold;background:#e1e4e5;padding:6px 12px;margin:-24px;margin-bottom:24px;font-size:100%}.rst-content .highlighted{background:#F1C40F;display:inline-block;font-weight:bold;padding:0 6px}.rst-content .footnote-reference,.rst-content .citation-reference{vertical-align:super;font-size:90%}.rst-content table.docutils.citation,.rst-content table.docutils.footnote{background:none;border:none;color:#999}.rst-content table.docutils.citation td,.rst-content table.docutils.citation tr,.rst-content table.docutils.footnote td,.rst-content table.docutils.footnote tr{border:none;background-color:transparent !important;white-space:normal}.rst-content table.docutils.citation td.label,.rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}.rst-content table.docutils.citation tt,.rst-content table.docutils.citation code,.rst-content table.docutils.footnote tt,.rst-content table.docutils.footnote code{color:#555}.rst-content table.field-list{border:none}.rst-content table.field-list td{border:none;padding-top:5px}.rst-content table.field-list td>strong{display:inline-block;margin-top:3px}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left;padding-left:0}.rst-content tt,.rst-content tt,.rst-content code{color:#000;padding:2px 5px}.rst-content tt big,.rst-content tt em,.rst-content tt big,.rst-content code big,.rst-content tt em,.rst-content code em{font-size:100% !important;line-height:normal}.rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal{color:#E74C3C}.rst-content tt.xref,a .rst-content tt,.rst-content tt.xref,.rst-content code.xref,a .rst-content tt,a .rst-content code{font-weight:bold;color:#404040}.rst-content a tt,.rst-content a tt,.rst-content a code{color:#2980B9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:bold}.rst-content dl p,.rst-content dl table,.rst-content dl ul,.rst-content dl ol{margin-bottom:12px !important}.rst-content dl dd{margin:0 0 12px 24px}.rst-content dl:not(.docutils){margin-bottom:24px}.rst-content dl:not(.docutils) dt{display:inline-block;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980B9;border-top:solid 3px #6ab0de;padding:6px;position:relative}.rst-content dl:not(.docutils) dt:before{color:#6ab0de}.rst-content dl:not(.docutils) dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dl dt{margin-bottom:6px;border:none;border-left:solid 3px #ccc;background:#f0f0f0;color:#555}.rst-content dl:not(.docutils) dl dt .headerlink{color:#404040;font-size:100% !important}.rst-content dl:not(.docutils) dt:first-child{margin-top:0}.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) tt,.rst-content dl:not(.docutils) code{font-weight:bold}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname,.rst-content dl:not(.docutils) tt.descclassname,.rst-content dl:not(.docutils) code.descclassname{background-color:transparent;border:none;padding:0;font-size:100% !important}.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) tt.descname,.rst-content dl:not(.docutils) code.descname{font-weight:bold}.rst-content dl:not(.docutils) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:bold}.rst-content dl:not(.docutils) .property{display:inline-block;padding-right:8px}.rst-content .viewcode-link,.rst-content .viewcode-back{display:inline-block;color:#27AE60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:bold}.rst-content tt.download,.rst-content code.download{background:inherit;padding:inherit;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content tt.download span:first-child:before,.rst-content code.download span:first-child:before{margin-right:4px}@media screen and (max-width: 480px){.rst-content .sidebar{width:100%}}span[id*='MathJax-Span']{color:#404040}.math{text-align:center}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:400;src:local("Inconsolata"),local("Inconsolata-Regular"),url(../fonts/Inconsolata-Regular.ttf) format("truetype")}@font-face{font-family:"Inconsolata";font-style:normal;font-weight:700;src:local("Inconsolata Bold"),local("Inconsolata-Bold"),url(../fonts/Inconsolata-Bold.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:400;src:local("Lato Regular"),local("Lato-Regular"),url(../fonts/Lato-Regular.ttf) format("truetype")}@font-face{font-family:"Lato";font-style:normal;font-weight:700;src:local("Lato Bold"),local("Lato-Bold"),url(../fonts/Lato-Bold.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:400;src:local("Roboto Slab Regular"),local("RobotoSlab-Regular"),url(../fonts/RobotoSlab-Regular.ttf) format("truetype")}@font-face{font-family:"Roboto Slab";font-style:normal;font-weight:700;src:local("Roboto Slab Bold"),local("RobotoSlab-Bold"),url(../fonts/RobotoSlab-Bold.ttf) format("truetype")} +/*# sourceMappingURL=theme.css.map */ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..8163495 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,287 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/_static/down-pressed.png b/_static/down-pressed.png new file mode 100644 index 0000000..7c30d00 Binary files /dev/null and b/_static/down-pressed.png differ diff --git a/_static/down.png b/_static/down.png new file mode 100644 index 0000000..f48098a Binary files /dev/null and b/_static/down.png differ diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000..254c60b Binary files /dev/null and b/_static/file.png differ diff --git a/_static/fonts/Inconsolata-Bold.ttf b/_static/fonts/Inconsolata-Bold.ttf new file mode 100644 index 0000000..58c9fef Binary files /dev/null and b/_static/fonts/Inconsolata-Bold.ttf differ diff --git a/_static/fonts/Inconsolata-Regular.ttf b/_static/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000..a87ffba Binary files /dev/null and b/_static/fonts/Inconsolata-Regular.ttf differ diff --git a/_static/fonts/Lato-Bold.ttf b/_static/fonts/Lato-Bold.ttf new file mode 100644 index 0000000..7434369 Binary files /dev/null and b/_static/fonts/Lato-Bold.ttf differ diff --git a/_static/fonts/Lato-Regular.ttf b/_static/fonts/Lato-Regular.ttf new file mode 100644 index 0000000..04ea8ef Binary files /dev/null and b/_static/fonts/Lato-Regular.ttf differ diff --git a/_static/fonts/RobotoSlab-Bold.ttf b/_static/fonts/RobotoSlab-Bold.ttf new file mode 100644 index 0000000..df5d1df Binary files /dev/null and b/_static/fonts/RobotoSlab-Bold.ttf differ diff --git a/_static/fonts/RobotoSlab-Regular.ttf b/_static/fonts/RobotoSlab-Regular.ttf new file mode 100644 index 0000000..eb52a79 Binary files /dev/null and b/_static/fonts/RobotoSlab-Regular.ttf differ diff --git a/_static/fonts/fontawesome-webfont.eot b/_static/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..84677bc Binary files /dev/null and b/_static/fonts/fontawesome-webfont.eot differ diff --git a/_static/fonts/fontawesome-webfont.svg b/_static/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..d907b25 --- /dev/null +++ b/_static/fonts/fontawesome-webfont.svg @@ -0,0 +1,520 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_static/fonts/fontawesome-webfont.ttf b/_static/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..96a3639 Binary files /dev/null and b/_static/fonts/fontawesome-webfont.ttf differ diff --git a/_static/fonts/fontawesome-webfont.woff b/_static/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..628b6a5 Binary files /dev/null and b/_static/fonts/fontawesome-webfont.woff differ diff --git a/_static/jquery-1.11.1.js b/_static/jquery-1.11.1.js new file mode 100644 index 0000000..d4b67f7 --- /dev/null +++ b/_static/jquery-1.11.1.js @@ -0,0 +1,10308 @@ +/*! + * jQuery JavaScript Library v1.11.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-05-01T17:42Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper window is present, + // execute the factory and get jQuery + // For environments that do not inherently posses a window with a document + // (such as Node.js), expose a jQuery-making factory as module.exports + // This accentuates the need for the creation of a real window + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +// + +var deletedIds = []; + +var slice = deletedIds.slice; + +var concat = deletedIds.concat; + +var push = deletedIds.push; + +var indexOf = deletedIds.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + version = "1.11.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android<4.1, IE<9 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: deletedIds.sort, + splice: deletedIds.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( support.ownLast ) { + for ( key in obj ) { + return hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call(obj) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Support: Android<4.1, IE<9 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( indexOf ) { + return indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + while ( j < len ) { + first[ i++ ] = second[ j++ ]; + } + + // Support: IE<9 + // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) + if ( len !== len ) { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: function() { + return +( new Date() ); + }, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v1.10.19 + * http://sizzlejs.com/ + * + * Copyright 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-04-18 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + characterEncoding + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( documentIsHTML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document (jQuery #6963) + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== strundefined && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, + doc = node ? node.ownerDocument || node : preferredDoc, + parent = doc.defaultView; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsHTML = !isXML( doc ); + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent !== parent.top ) { + // IE11 does not have attachEvent, so all must suffer + if ( parent.addEventListener ) { + parent.addEventListener( "unload", function() { + setDocument(); + }, false ); + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", function() { + setDocument(); + }); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if getElementsByClassName can be trusted + support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { + div.innerHTML = "
"; + + // Support: Safari<4 + // Catch class over-caching + div.firstChild.className = "i"; + // Support: Opera<10 + // Catch gEBCN failure to find non-leading classes + return div.getElementsByClassName("i").length === 2; + }); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowclip^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (oldCache = outerCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + outerCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context !== document && context; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is no seed and only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome<14 +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; + }); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +}); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof rootjQuery.ready !== "undefined" ? + rootjQuery.ready( selector ) : + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.extend({ + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +jQuery.fn.extend({ + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.unique( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.unique( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +}); +var rnotwhite = (/\S+/g); + + + +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + + } else if ( !(--remaining) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend({ + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +}); + +/** + * Clean-up method for dom ready events + */ +function detach() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } +} + +/** + * The ready event handler and self cleanup method + */ +function completed() { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + + +var strundefined = typeof undefined; + + + +// Support: IE<9 +// Iteration over object's inherited properties before its own +var i; +for ( i in jQuery( support ) ) { + break; +} +support.ownLast = i !== "0"; + +// Note: most support tests are defined in their respective modules. +// false until the test is run +support.inlineBlockNeedsLayout = false; + +// Execute ASAP in case we need to set body.style.zoom +jQuery(function() { + // Minified: var a,b,c,d + var val, div, body, container; + + body = document.getElementsByTagName( "body" )[ 0 ]; + if ( !body || !body.style ) { + // Return for frameset docs that don't have a body + return; + } + + // Setup + div = document.createElement( "div" ); + container = document.createElement( "div" ); + container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; + body.appendChild( container ).appendChild( div ); + + if ( typeof div.style.zoom !== strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; + + support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; + if ( val ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); +}); + + + + +(function() { + var div = document.createElement( "div" ); + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +/** + * Determines whether an object can have data + */ +jQuery.acceptData = function( elem ) { + var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], + nodeType = +elem.nodeType || 1; + + // Do not set data on non-element DOM nodes because it will not be cleared (#8335). + return nodeType !== 1 && nodeType !== 9 ? + false : + + // Nodes accept data unless otherwise specified; rejection can be conditional + !noData || noData !== true && elem.getAttribute("classid") === noData; +}; + + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + +function internalData( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // The following elements (space-suffixed to avoid Object.prototype collisions) + // throw uncatchable exceptions if you attempt to set expando properties + noData: { + "applet ": true, + "embed ": true, + // ...but Flash objects (which have this classid) *can* handle expandos + "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var i, name, data, + elem = this[0], + attrs = elem && elem.attributes; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return arguments.length > 1 ? + + // Sets one value + this.each(function() { + jQuery.data( this, key, value ); + }) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + + +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; +}; +var rcheckableType = (/^(?:checkbox|radio)$/i); + + + +(function() { + // Minified: var a,b,c + var input = document.createElement( "input" ), + div = document.createElement( "div" ), + fragment = document.createDocumentFragment(); + + // Setup + div.innerHTML = "
a"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName( "tbody" ).length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = + document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + input.type = "checkbox"; + input.checked = true; + fragment.appendChild( input ); + support.appendChecked = input.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE6-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // #11217 - WebKit loses check when the name is after the checked attribute + fragment.appendChild( div ); + div.innerHTML = ""; + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + support.noCloneEvent = true; + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } +})(); + + +(function() { + var i, eventName, + div = document.createElement( "div" ); + + // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) + for ( i in { submit: true, change: true, focusin: true }) { + eventName = "on" + i; + + if ( !(support[ i + "Bubbles" ] = eventName in window) ) { + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + div.setAttribute( eventName, "t" ); + support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && jQuery.acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + // Support: IE < 9, Android < 4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + jQuery._removeData( doc, fix ); + } else { + jQuery._data( doc, fix, attaches ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + col: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
", "
" ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!support.noCloneEvent || !support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
" && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + deletedIds.push( id ); + } + } + } + } + } +}); + +jQuery.fn.extend({ + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + remove: function( selector, keepData /* Internal Use Only */ ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map(function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var arg = arguments[ 0 ]; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + arg = this.parentNode; + + jQuery.cleanData( getAll( this ) ); + + if ( arg ) { + arg.replaceChild( elem, this ); + } + }); + + // Force removal if there was no new content (e.g., from empty arguments) + return arg && (arg.length || arg.nodeType) ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, self.html() ); + } + self.domManip( args, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[i], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + + +var iframe, + elemdisplay = {}; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var style, + elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + // getDefaultComputedStyle might be reliably used only on attached element + display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? + + // Use of this method is a temporary fix (more like optmization) until something better comes along, + // since it was removed from specification and supported only in FF + style.display : jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = (iframe || jQuery( "