├── .gitignore ├── .travis.yml ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── complexity ├── __init__.py ├── conf.py ├── exceptions.py ├── generate.py ├── main.py ├── prep.py ├── serve.py └── utils.py ├── docs ├── Makefile ├── _themes │ ├── .gitignore │ ├── README.rst │ ├── complexity │ │ ├── layout.html │ │ ├── relations.html │ │ ├── static │ │ │ └── complexity.css_t │ │ └── theme.conf │ └── complexity_theme_support.py ├── advanced_usage.rst ├── authors.rst ├── complexity.rst ├── conf.py ├── contributing.rst ├── history.rst ├── index.rst ├── installation.rst ├── make.bat ├── modules.rst ├── readme.rst ├── troubleshooting.rst ├── tutorial.rst └── upgrading.rst ├── requirements ├── base_test.txt ├── test_26.txt ├── test_27.txt └── test_33.txt ├── setup.py ├── tests ├── __init__.py ├── conf_proj │ ├── complexity.yml │ └── templates │ │ ├── 404.html │ │ ├── 500.html │ │ ├── about.html │ │ ├── base.html │ │ └── index.html ├── conf_proj2 │ ├── assetz │ │ └── junk.txt │ ├── complexity.yml │ ├── contextz │ │ └── junk.json │ └── templatez │ │ ├── 404.html │ │ ├── about.html │ │ ├── base.html │ │ └── index.html ├── files │ ├── base.html │ ├── unicode.html │ ├── unicode.json │ ├── unicode.txt │ └── unicode2.html ├── project │ ├── assets │ │ ├── css │ │ │ ├── bootstrap-responsive.min.css │ │ │ └── bootstrap.min.css │ │ ├── img │ │ │ └── glyphicons-halflings.png │ │ ├── js │ │ │ └── bootstrap.min.js │ │ └── robots.txt │ ├── context │ │ └── test.json │ └── templates │ │ ├── 404.html │ │ ├── 500.html │ │ ├── about.html │ │ ├── art │ │ ├── color.html │ │ ├── cupcakes │ │ │ ├── chocolate.html │ │ │ └── index.html │ │ └── index.html │ │ ├── bad_templated_binary.png │ │ ├── base.html │ │ ├── base_design.html │ │ ├── index.html │ │ └── long │ │ └── path │ │ └── to │ │ └── folder │ │ └── dont-expand.html ├── test_conf.py ├── test_examples.py ├── test_generate.py ├── test_main.py └── test_utils.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | 37 | # Complexity 38 | output/*.html 39 | output/*/index.html 40 | 41 | # Sphinx 42 | docs/_build 43 | 44 | # Coverage 45 | htmlcov 46 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Config file for automatic testing at travis-ci.org 2 | 3 | language: python 4 | 5 | python: 6 | - "3.3" 7 | - "2.7" 8 | - "2.6" 9 | - "pypy" 10 | 11 | # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors 12 | install: 13 | - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install -r requirements/test_26.txt; fi 14 | - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install -r requirements/test_27.txt; fi 15 | - if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install -r requirements/test_27.txt; fi 16 | - if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install -r requirements/test_33.txt; fi 17 | 18 | # command to run tests, e.g. python setup.py test 19 | script: python setup.py test 20 | -------------------------------------------------------------------------------- /AUTHORS.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Credits 3 | ======= 4 | 5 | Development Lead 6 | ---------------- 7 | 8 | * Audrey Roy (`@audreyr`_) 9 | 10 | Contributors 11 | ------------ 12 | 13 | * Daniel Greenfeld (`@pydanny`_) 14 | * Marko Mrdjenovic (`@friedcell`_) 15 | * Alja Isakovic (`@ialja`_) 16 | 17 | Special Thanks 18 | -------------- 19 | 20 | * Daniel Greenfeld greatly helped during Complexity's initial development and 21 | came up with the name. 22 | * Complexity Sphinx theme is a heavily customized version of 23 | `Kenneth Reitz's Requests theme`_, which itself is a modified version of 24 | `Armin Ronacher's Flasky theme`_. 25 | 26 | .. _`@audreyr`: https://github.com/audreyr 27 | .. _`@pydanny`: https://github.com/pydanny 28 | .. _`@friedcell`: https://github.com/friedcell 29 | .. _`@ialja`: https://github.com/ialja 30 | .. _`Kenneth Reitz's Requests theme`: http://python-requests.org 31 | .. _`Armin Ronacher's Flasky theme`: http://flask.pocoo.org/ 32 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | You can contribute in many ways: 9 | 10 | Types of Contributions 11 | ---------------------- 12 | 13 | Report Bugs 14 | ~~~~~~~~~~~ 15 | 16 | Report bugs at https://github.com/audreyr/complexity/issues. 17 | 18 | If you are reporting a bug, please include: 19 | 20 | * Your operating system name and version. 21 | * Any details about your local setup that might be helpful in troubleshooting. 22 | * Detailed steps to reproduce the bug. 23 | 24 | Fix Bugs 25 | ~~~~~~~~ 26 | 27 | Look through the GitHub issues for bugs. Anything tagged with "bug" 28 | is open to whoever wants to implement it. 29 | 30 | Implement Features 31 | ~~~~~~~~~~~~~~~~~~ 32 | 33 | Look through the GitHub issues for features. Anything tagged with "enhancement" 34 | is open to whoever wants to implement it. 35 | 36 | Write Documentation 37 | ~~~~~~~~~~~~~~~~~~~ 38 | 39 | Complexity could always use more documentation, whether as part of the 40 | official Complexity docs, in docstrings, or even on the web in blog posts, 41 | articles, and such. 42 | 43 | Create Examples 44 | ~~~~~~~~~~~~~~~ 45 | 46 | Some examples of real Complexity sites, whether open-source or closed-source, 47 | would be awesome. 48 | 49 | If you create an example Complexity site, file an issue so that it can be 50 | linked from the docs. 51 | 52 | Submit Feedback 53 | ~~~~~~~~~~~~~~~ 54 | 55 | The best way to send feedback is to file an issue at https://github.com/audreyr/complexity/issues. 56 | 57 | If you are proposing a feature: 58 | 59 | * Explain in detail how it would work. 60 | * Keep the scope as narrow as possible, to make it easier to implement. 61 | * Remember that this is a volunteer-driven project, and that contributions 62 | are welcome :) 63 | 64 | Get Started! 65 | --------------- 66 | 67 | Ready to contribute? Here's how to set up `complexity` for local development. 68 | 69 | 1. Fork the `complexity` repo on GitHub. 70 | 2. Clone your fork locally:: 71 | 72 | $ git clone git@github.com:your_name_here/complexity.git 73 | 74 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 75 | 76 | $ mkvirtualenv complexity 77 | $ cd complexity/ 78 | $ python setup.py develop 79 | 80 | 4. Create a branch for local development:: 81 | 82 | $ git checkout -b name-of-your-bugfix-or-feature 83 | 84 | Now you can make your changes locally. 85 | 86 | 5. When you're done making changes, check that your changes pass flake8 and the 87 | tests, including testing other Python versions with tox:: 88 | 89 | $ flake8 complexity tests 90 | $ python setup.py test 91 | $ tox 92 | 93 | To get flake8 and tox, just pip install them into your virtualenv. 94 | 95 | 6. Commit your changes and push your branch to GitHub:: 96 | 97 | $ git add . 98 | $ git commit -m "Your detailed description of your changes." 99 | $ git push origin name-of-your-bugfix-or-feature 100 | 101 | 7. Submit a pull request through the GitHub website. 102 | 103 | Pull Request Guidelines 104 | ----------------------- 105 | 106 | Before you submit a pull request, check that it meets these guidelines: 107 | 108 | 1. The pull request should include tests. 109 | 2. If the pull request adds functionality, the docs should be updated. Put 110 | your new functionality into a function with a docstring, and add the 111 | feature to the list in README.rst. 112 | 3. The pull request should work for Python 2.6, 2.7, 3.3, and PyPy. Check 113 | https://travis-ci.org/audreyr/complexity/pull_requests and make sure that 114 | the tests pass for all supported Python versions. 115 | 116 | Tips 117 | ---- 118 | 119 | To run a particular test:: 120 | 121 | $ python -m unittest tests.test_complexity.TestComplexity.test_make_sure_path_exists 122 | 123 | To run a subset of tests:: 124 | 125 | $ python -m unittest tests.test_complexity 126 | -------------------------------------------------------------------------------- /HISTORY.rst: -------------------------------------------------------------------------------- 1 | .. :changelog: 2 | 3 | History 4 | ------- 5 | 6 | 0.9.1 (2013-12-02) 7 | ++++++++++++++++++ 8 | 9 | * Depend on Jinja2 >= 2.4, not == 2.7. 10 | 11 | 0.9.0 (2013-08-28) 12 | ++++++++++++++++++ 13 | 14 | * CONFIG CHANGE: Configuration is now via a `complexity.yml` file inside the 15 | project, instead of a `complexity.json` file. 16 | * Support for an `unexpanded_templates` config option (#23). 17 | * Support for non-HTML files in `templates/` (or whatever you set 18 | `templates_dir` to be). 19 | 20 | See http://complexity.readthedocs.org/en/latest/advanced_usage.html#config-using-complexity-yml 21 | for more info. 22 | 23 | 0.8.0 (2013-08-10) 24 | ++++++++++++++++++ 25 | 26 | * USAGE CHANGE: At the command line, Complexity no longer takes an output_dir 27 | argument. It now assumes that your output_dir is `www/` by default, but you 28 | can customize it in `complexity.json`. 29 | * Support for configuration via `complexity.json`: you can specify any or all 30 | of the following key/value pairs: 31 | 32 | - `output_dir` 33 | - `templates_dir` 34 | - `assets_dir` 35 | - `context_dir` 36 | 37 | See http://complexity.readthedocs.org/en/latest/advanced_usage.html#config-using-complexity-json 38 | for more info. 39 | 40 | 0.7 (2013-08-05) 41 | ++++++++++++++++ 42 | 43 | A couple of small but important renames. If you rely on either of the following 44 | defaults, you will need to rename them in your Complexity project. 45 | 46 | * Directory parameter for .json files to be turned into context data has been 47 | renamed from `json_dir` to `context_dir`. 48 | * Default context directory value `json/` has been changed to `context/`. 49 | 50 | Sometimes you want your .json files to be turned into context variables, and 51 | sometimes you don't. This rename alleviates confusion when working with 52 | non-context .json files. 53 | 54 | 0.6 (2013-07-26) 55 | ++++++++++++++++ 56 | 57 | * Support for multi-level template directories. (Upgrade to at least 0.6 if 58 | you want to have folders within folders and beyond in `templates/`.) 59 | * Skip non-HTML files in `templates/` rather than raising `NonHTMLFileException`. 60 | 61 | 0.5 (2013-07-25) 62 | ++++++++++++++++ 63 | 64 | * Improved static site generation API - better parameters are used. 65 | * Files in the root of `assets/` (or the asset directory) now get copied over to the output. 66 | * Much more documentation. 67 | 68 | 0.4.2 (2013-07-21) 69 | ++++++++++++++++++ 70 | 71 | * Make reading of JSON files from `json/` optional. 72 | 73 | 0.4.1 (2013-07-19) 74 | ++++++++++++++++++ 75 | 76 | * Fix reading of JSON files from `json/`. 77 | 78 | 0.4 (2013-07-19) 79 | ++++++++++++++++++ 80 | 81 | * Project layout is now:: 82 | 83 | my_repo/ 84 | ├── project/ <--------- input 85 | │ ├── assets/ 86 | │ │ ├── css/ 87 | │ │ ├── js/ 88 | │ │ └── img/ 89 | │ ├── json/ 90 | │ │ └── stuff.json 91 | │ └── templates/ 92 | │ ├── base.html 93 | │ ├── index.html 94 | │ └── about.html 95 | └── www/ <---------- output (generated) 96 | ├── index.html 97 | ├── about/ 98 | │ └── index.html 99 | ├── css/ 100 | ├── js/ 101 | └── img/ 102 | 103 | * Assets are copied over to `www/` during site generation. 104 | * If the `www/` directory was previously created, it prompts the user and then 105 | deletes it before site regeneration. 106 | * Templates starting with `base` are not generated as individual pages. They 107 | are meant to be extended in other templates. 108 | 109 | 0.3 (2013-07-18) 110 | ++++++++++++++++++ 111 | 112 | * Graceful shutdown/restart of dev server. 113 | * Required input and output dir arguments. 114 | * Optional port argument. 115 | * Improved server start/stop messages. 116 | * Major internal refactor. 117 | 118 | 0.2.1 (2013-07-15) 119 | +++++++++++++++++++ 120 | 121 | * Fixes to setup.py. 122 | 123 | 0.2.0 (2013-07-15) 124 | +++++++++++++++++++ 125 | 126 | * Data from .json files now gets read as template context data. 127 | * Tested (and passing!) on Python 2.6, 2.7, 3.3, PyPy. 128 | 129 | 0.1.1 (2013-07-10) 130 | ++++++++++++++++++ 131 | 132 | * First release on PyPI. 133 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Audrey Roy 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | * Neither the name of Complexity nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | 14 | ------------------------------------------------------------------ 15 | 16 | The Sphinx documentation theme for Complexity is a heavily-customized version 17 | of Kenneth Reitz's kr theme, which is a modified version of Armin Ronacher's 18 | flask theme. 19 | 20 | Complexity's theme modifications: 21 | 22 | Copyright (c) 2013 Audrey Roy. 23 | 24 | Modifications: 25 | 26 | Copyright (c) 2011 Kenneth Reitz. 27 | 28 | 29 | Original Project: 30 | 31 | Copyright (c) 2010 by Armin Ronacher. 32 | 33 | 34 | Some rights reserved. 35 | 36 | Redistribution and use in source and binary forms of the theme, with or 37 | without modification, are permitted provided that the following conditions 38 | are met: 39 | 40 | * Redistributions of source code must retain the above copyright 41 | notice, this list of conditions and the following disclaimer. 42 | 43 | * Redistributions in binary form must reproduce the above 44 | copyright notice, this list of conditions and the following 45 | disclaimer in the documentation and/or other materials provided 46 | with the distribution. 47 | 48 | * The names of the contributors may not be used to endorse or 49 | promote products derived from this software without specific 50 | prior written permission. 51 | 52 | We kindly ask you to only use these themes in an unmodified manner just 53 | for Flask and Flask-related products, not for unrelated projects. If you 54 | like the visual style and want to use it for your own projects, please 55 | consider making some larger changes to the themes (such as changing 56 | font faces, sizes, colors or margins). 57 | 58 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 59 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 62 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 64 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 65 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 66 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 67 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE 68 | POSSIBILITY OF SUCH DAMAGE. 69 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.rst 2 | include CONTRIBUTING.rst 3 | include HISTORY.rst 4 | include LICENSE 5 | include README.rst 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-build docs 2 | 3 | help: 4 | @echo "clean-build - remove build artifacts" 5 | @echo "clean-pyc - remove Python file artifacts" 6 | @echo "lint - check style with flake8" 7 | @echo "test - run tests quickly with the default Python" 8 | @echo "testall - run tests on every Python version with tox" 9 | @echo "coverage - check code coverage quickly with the default Python" 10 | @echo "docs - generate Sphinx HTML documentation, including API docs" 11 | @echo "release - package and upload a release" 12 | @echo "sdist - package" 13 | 14 | clean: clean-build clean-pyc 15 | 16 | clean-build: 17 | rm -fr build/ 18 | rm -fr dist/ 19 | rm -fr *.egg-info 20 | 21 | clean-pyc: 22 | find . -name '*.pyc' -exec rm -f {} + 23 | find . -name '*.pyo' -exec rm -f {} + 24 | find . -name '*~' -exec rm -f {} + 25 | 26 | lint: 27 | flake8 complexity tests 28 | 29 | test: 30 | python setup.py test 31 | 32 | test-all: 33 | tox 34 | 35 | coverage: 36 | coverage run --source complexity setup.py test 37 | coverage report -m 38 | coverage html 39 | open htmlcov/index.html 40 | 41 | docs: 42 | rm docs/complexity.rst 43 | rm docs/modules.rst 44 | sphinx-apidoc -o docs/ complexity 45 | $(MAKE) -C docs clean 46 | $(MAKE) -C docs html 47 | open docs/_build/html/index.html 48 | 49 | release: clean 50 | python setup.py sdist upload 51 | 52 | sdist: clean 53 | python setup.py sdist 54 | ls -l dist -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Complexity 3 | ========== 4 | 5 | .. image:: https://badge.fury.io/py/complexity.png 6 | :target: http://badge.fury.io/py/complexity 7 | 8 | .. image:: https://travis-ci.org/audreyr/complexity.png?branch=master 9 | :target: https://travis-ci.org/audreyr/complexity 10 | 11 | .. image:: https://pypip.in/d/complexity/badge.png 12 | :target: https://crate.io/packages/complexity?version=latest 13 | 14 | A refreshingly simple static site generator, for those who like to work in HTML. 15 | 16 | Documentation 17 | ------------- 18 | 19 | The full documentation is at http://complexity.rtfd.org. 20 | 21 | Quickstart 22 | ---------- 23 | 24 | Try it out:: 25 | 26 | $ pip install complexity 27 | $ git clone git@github.com:audreyr/complexity-example.git my_proj 28 | $ cd my_proj 29 | $ complexity project/ www/ 30 | 31 | Once you've done that, open a web browser to http://127.0.0.1:9090 to see the newly generated Complexity static site. 32 | 33 | Features 34 | -------- 35 | 36 | * Works on Python 2.6, 2.7, and 3.3, and on PyPy. 37 | * Takes simple HTML templates as input. 38 | * Data from .json files turns into template context data. 39 | * Template inheritance, filters, etc. (Brought to you by Jinja2.) 40 | * Auto-expands .html file URLs into cleaner URLs (e.g. about.html gets expanded to /about/) 41 | * Minifies .html files 42 | * Can optionally be used as a library instead of from the command line. See 43 | `Using Complexity as a Library`_ for details. 44 | 45 | .. _`Using Complexity as a Library`: http://complexity.readthedocs.org/en/latest/advanced_usage.html#using-complexity-as-a-library 46 | 47 | Best Used With 48 | -------------- 49 | 50 | Complexity is designed to be used with these packages: 51 | 52 | * `Simplicity`_: Converts ReStructuredText into JSON, which Complexity can use 53 | as input. 54 | * `A Lot of Effort`_: Deploys a static website (e.g. the output of Complexity) 55 | to Amazon S3. 56 | * `Cookiecutter`_: Creates projects from project templates. 57 | 58 | Sure, they could have all been built into Complexity, but decoupling them 59 | seemed like a nice thing to do. 60 | 61 | .. _`Simplicity`: https://github.com/pydanny/simplicity 62 | .. _`A Lot of Effort`: https://github.com/audreyr/alotofeffort 63 | .. _`Cookiecutter`: https://github.com/audreyr/cookiecutter 64 | 65 | Community 66 | --------- 67 | 68 | * Stuck? Don't know where to begin? File an issue and we'll help you. 69 | * We love contributions. Read about `how to contribute`_. 70 | 71 | .. _`how to contribute`: https://github.com/audreyr/complexity/blob/master/CONTRIBUTING.rst 72 | -------------------------------------------------------------------------------- /complexity/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity 6 | ---------- 7 | 8 | Main package for Complexity. 9 | """ 10 | 11 | __version__ = '0.9.1' 12 | -------------------------------------------------------------------------------- /complexity/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity.conf 6 | ------------------- 7 | 8 | Functions for reading a `complexity.yml` configuration file and doing various 9 | configuration-related things. 10 | """ 11 | 12 | import logging 13 | import os 14 | import yaml 15 | 16 | 17 | def read_conf(directory): 18 | """ 19 | Reads and parses the `complexity.yml` configuration file from a 20 | directory, if one is present. 21 | :param directory: Directory to look for a `complexity.yml` file. 22 | :returns: A conf dict, or False if no `complexity.yml` is present. 23 | """ 24 | 25 | logging.debug("About to look for a conf file in {0}".format(directory)) 26 | conf_file = os.path.join(directory, 'complexity.yml') 27 | 28 | if os.path.isfile(conf_file): 29 | with open(conf_file) as f: 30 | conf_dict = yaml.safe_load(f.read()) 31 | return conf_dict 32 | return False 33 | 34 | 35 | def get_unexpanded_list(conf_dict): 36 | """ 37 | Given a configuration dict, returns the list of templates that were 38 | specified as unexpanded. 39 | """ 40 | 41 | return conf_dict.get('unexpanded_templates', ()) 42 | -------------------------------------------------------------------------------- /complexity/exceptions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity.exceptions 6 | --------------------- 7 | 8 | All exceptions used in the Complexity code base are defined here. 9 | """ 10 | 11 | 12 | class ComplexityException(Exception): 13 | """ 14 | Base exception class. All Complexity-specific exceptions subclass 15 | `ComplexityException`. 16 | """ 17 | 18 | 19 | class MissingTemplateDirException(ComplexityException): 20 | """ 21 | Raised when a project is missing a `templates/` subdirectory. 22 | """ 23 | 24 | 25 | class NonHTMLFileException(ComplexityException): 26 | """ 27 | Raised when a project's `templates/` directory contains a non-HTML file. 28 | """ 29 | 30 | 31 | class OutputDirExistsException(ComplexityException): 32 | """ 33 | Raised when a project's output_dir exists and no_input=True. 34 | """ 35 | -------------------------------------------------------------------------------- /complexity/generate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity.generate 6 | ------------------- 7 | 8 | Functions for static site generation. 9 | """ 10 | 11 | import json 12 | import logging 13 | import os 14 | import shutil 15 | import re 16 | 17 | from binaryornot.check import is_binary 18 | from jinja2 import FileSystemLoader 19 | from jinja2.environment import Environment 20 | 21 | from .exceptions import MissingTemplateDirException 22 | from .utils import make_sure_path_exists, unicode_open 23 | 24 | 25 | def get_output_filename(template_filepath, output_dir, force_unexpanded): 26 | """ 27 | Given an input filename, return the corresponding output filename. 28 | 29 | :param template_filepath: Name of template file relative to template dir, 30 | e.g. art/index.html 31 | :param output_dir: The Complexity output directory, e.g. `www/`. 32 | :paramtype output_dir: directory 33 | """ 34 | 35 | template_filepath = os.path.normpath(template_filepath) 36 | 37 | basename = os.path.basename(template_filepath) 38 | dirname = os.path.dirname(template_filepath) 39 | 40 | # Base files don't have output. 41 | if basename.startswith('base'): 42 | return False 43 | # Put index and unexpanded templates in the root. 44 | elif force_unexpanded or basename == 'index.html': 45 | output_filename = os.path.join(output_dir, template_filepath) 46 | # Put other pages in page/index.html, for better URL formatting. 47 | else: 48 | stem = basename.split('.')[0] 49 | output_filename = os.path.join( 50 | output_dir, 51 | dirname, 52 | stem, 53 | 'index.html' 54 | ) 55 | return output_filename 56 | 57 | 58 | def minify_html(html): 59 | """ 60 | Removes spaces and new lines from a HTML file 61 | 62 | :param html: HTML that should be minified 63 | """ 64 | 65 | # Removes whitespaces, and new lines between tags using this RE 66 | return re.sub(r">\s+<", '><', html) 67 | 68 | 69 | def generate_html_file(template_filepath, 70 | output_dir, env, 71 | context, force_unexpanded=False, minify=False): 72 | """ 73 | Renders and writes a single HTML file to its corresponding output location. 74 | 75 | :param template_filepath: Name of template file to be rendered. Should be 76 | relative to template dir, e.g. art/index.html 77 | :param output_dir: The Complexity output directory, e.g. `www/`. 78 | :paramtype output_dir: directory 79 | :param env: Jinja2 environment with a loader already set up. 80 | :param context: Jinja2 context that holds template variables. See 81 | http://jinja.pocoo.org/docs/api/#the-context 82 | """ 83 | 84 | # Ignore templates starting with "base". They're treated as special cases. 85 | if template_filepath.startswith('base'): 86 | return False 87 | 88 | # Force fwd slashes on Windows for get_template 89 | # This is a by-design Jinja issue 90 | infile_fwd_slashes = template_filepath.replace(os.path.sep, '/') 91 | 92 | tmpl = env.get_template(infile_fwd_slashes) 93 | rendered_html = tmpl.render(**context) 94 | 95 | if minify: 96 | rendered_html = minify_html(rendered_html) 97 | 98 | output_filename = get_output_filename(template_filepath, 99 | output_dir, force_unexpanded) 100 | if output_filename: 101 | make_sure_path_exists(os.path.dirname(output_filename)) 102 | 103 | # Write the generated file 104 | with unicode_open(output_filename, 'w') as fh: 105 | fh.write(rendered_html) 106 | return True 107 | 108 | 109 | def generate_html(templates_dir, output_dir, context=None, 110 | unexpanded_templates=()): 111 | """ 112 | Renders the HTML templates from `templates_dir`, and writes them to 113 | `output_dir`. 114 | 115 | :param templates_dir: The Complexity templates directory, 116 | e.g. `project/templates/`. 117 | :paramtype templates_dir: directory 118 | :param output_dir: The Complexity output directory, e.g. `www/`. 119 | :paramtype output_dir: directory 120 | :param context: Jinja2 context that holds template variables. See 121 | http://jinja.pocoo.org/docs/api/#the-context 122 | """ 123 | 124 | logging.debug('Templates dir is {0}'.format(templates_dir)) 125 | if not os.path.exists(templates_dir): 126 | raise MissingTemplateDirException( 127 | 'Your project is missing a templates/ directory containing your \ 128 | HTML templates.' 129 | ) 130 | 131 | context = context or {} 132 | env = Environment() 133 | # os.chdir(templates_dir) 134 | env.loader = FileSystemLoader(templates_dir) 135 | 136 | # Create the output dir if it doesn't already exist 137 | make_sure_path_exists(output_dir) 138 | 139 | for root, dirs, files in os.walk(templates_dir): 140 | for f in files: 141 | # print(f) 142 | template_filepath = os.path.relpath( 143 | os.path.join(root, f), 144 | templates_dir 145 | ) 146 | 147 | force_unexpanded = template_filepath in unexpanded_templates 148 | logging.debug('Is {0} in {1}? {2}'.format( 149 | template_filepath, 150 | unexpanded_templates, 151 | force_unexpanded 152 | )) 153 | 154 | if is_binary(os.path.join(templates_dir, template_filepath)): 155 | print('Non-text file found: {0}. Skipping.'. 156 | format(template_filepath)) 157 | else: 158 | outfile = get_output_filename(template_filepath, output_dir, 159 | force_unexpanded) 160 | print('Copying {0} to {1}'.format(template_filepath, outfile)) 161 | generate_html_file(template_filepath, output_dir, env, context, 162 | force_unexpanded) 163 | 164 | 165 | def generate_context(context_dir): 166 | """ 167 | Generates the context for all Complexity pages. 168 | 169 | :param context_dir: Directory containing `.json` file(s) to be turned into 170 | context variables for Jinja2. 171 | 172 | Description: 173 | 174 | Iterates through the contents of `context_dir` and finds all JSON 175 | files. Loads the JSON file as a Python object with the key being the 176 | JSON file name. 177 | 178 | Example: 179 | 180 | Assume the following files exist:: 181 | 182 | context/ 183 | ├── names.json 184 | └── numbers.json 185 | 186 | Depending on their content, might generate a context as follows: 187 | 188 | .. code-block:: json 189 | 190 | context = { 191 | "names": ['Audrey', 'Danny'], 192 | "numbers": [1, 2, 3, 4] 193 | } 194 | """ 195 | context = {} 196 | 197 | json_files = os.listdir(context_dir) 198 | 199 | for file_name in json_files: 200 | 201 | if file_name.endswith('json'): 202 | 203 | # Open the JSON file and convert to Python object 204 | json_file = os.path.join(context_dir, file_name) 205 | with unicode_open(json_file) as f: 206 | obj = json.load(f) 207 | 208 | # Add the Python object to the context dictionary 209 | context[file_name[:-5]] = obj 210 | 211 | return context 212 | 213 | 214 | def copy_assets(assets_dir, output_dir): 215 | """ 216 | Copies static assets over from `assets_dir` to `output_dir`. 217 | 218 | :param assets_dir: The Complexity project assets directory, 219 | e.g. `project/assets/`. 220 | :paramtype assets_dir: directory 221 | :param output_dir: The Complexity output directory, e.g. `www/`. 222 | :paramtype output_dir: directory 223 | """ 224 | 225 | assets = os.listdir(assets_dir) 226 | for item in assets: 227 | item_path = os.path.join(assets_dir, item) 228 | 229 | # Only copy allowed dirs 230 | if os.path.isdir(item_path) and item != 'scss' and item != 'less': 231 | new_dir = os.path.join(output_dir, item) 232 | print('Copying directory {0} to {1}'.format(item, new_dir)) 233 | shutil.copytree(item_path, new_dir) 234 | 235 | # Copy over files in the root of assets_dir 236 | if os.path.isfile(item_path): 237 | new_file = os.path.join(output_dir, item) 238 | print('Copying file {0} to {1}'.format(item, new_file)) 239 | shutil.copyfile(item_path, new_file) 240 | -------------------------------------------------------------------------------- /complexity/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity.main 6 | --------------- 7 | 8 | Main entry point for the `complexity` command. 9 | 10 | The code in this module is also a good example of how to use Complexity as a 11 | library rather than a script. 12 | """ 13 | 14 | import argparse 15 | import logging 16 | import os 17 | import sys 18 | 19 | from .conf import read_conf, get_unexpanded_list 20 | from .exceptions import OutputDirExistsException 21 | from .generate import generate_context, copy_assets, generate_html 22 | from .prep import prompt_and_delete_cruft 23 | from .serve import serve_static_site 24 | 25 | 26 | logger = logging.getLogger(__name__) 27 | 28 | 29 | def complexity(project_dir, no_input=True): 30 | """ 31 | API equivalent to using complexity at the command line. 32 | 33 | :param project_dir: The Complexity project directory, e.g. `project/`. 34 | :paramtype project_dir: directory 35 | 36 | :param no_input: If true, don't prompt about whether to delete 37 | pre-existing `www/` directory. Instead, throw exception if one is 38 | found. 39 | 40 | .. note:: You must delete `output_dir` before calling this. This also does 41 | not start the Complexity development server; you can do that from your 42 | code if desired. 43 | """ 44 | 45 | # Get the configuration dictionary, if config exists 46 | defaults = { 47 | "templates_dir": "templates/", 48 | "assets_dir": "assets/", 49 | "context_dir": "context/", 50 | "output_dir": "../www/" 51 | } 52 | conf_dict = read_conf(project_dir) or defaults 53 | 54 | output_dir = os.path.normpath( 55 | os.path.join(project_dir, conf_dict['output_dir']) 56 | ) 57 | 58 | # If output_dir exists, prompt before deleting. 59 | # Abort if it can't be deleted. 60 | if no_input: 61 | if os.path.exists(output_dir): 62 | raise OutputDirExistsException( 63 | 'Please delete {0} manually and try again.' 64 | ) 65 | else: 66 | if not prompt_and_delete_cruft(output_dir): 67 | sys.exit() 68 | 69 | # Generate the context data 70 | context = None 71 | if 'context_dir' in conf_dict: 72 | context_dir = os.path.join(project_dir, conf_dict['context_dir']) 73 | if os.path.exists(context_dir): 74 | context = generate_context(context_dir) 75 | 76 | # Generate and serve the HTML site 77 | unexpanded_templates = get_unexpanded_list(conf_dict) 78 | templates_dir = os.path.join(project_dir, conf_dict['templates_dir']) 79 | generate_html(templates_dir, output_dir, context, unexpanded_templates) 80 | 81 | if 'assets_dir' in conf_dict: 82 | assets_dir = os.path.join(project_dir, conf_dict['assets_dir']) 83 | copy_assets(assets_dir, output_dir) 84 | 85 | return output_dir 86 | 87 | 88 | def get_complexity_args(): 89 | """ 90 | Get the command line input/output arguments passed in to Complexity. 91 | """ 92 | 93 | parser = argparse.ArgumentParser( 94 | description='A refreshingly simple static site generator, for those' 95 | 'who like to work in HTML.' 96 | ) 97 | parser.add_argument( 98 | 'project_dir', 99 | default='project/', 100 | help='Your project directory containing the files to be processed by' 101 | 'Complexity.' 102 | ) 103 | parser.add_argument( 104 | '--port', 105 | type=int, 106 | default=9090, 107 | help='Port number to serve files on.' 108 | ) 109 | parser.add_argument( 110 | '--noserver', 111 | action='store_true', 112 | help='Don\'t run the server.' 113 | ) 114 | args = parser.parse_args() 115 | return args 116 | 117 | 118 | def main(): 119 | """ Entry point for the package, as defined in `setup.py`. """ 120 | 121 | args = get_complexity_args() 122 | 123 | output_dir = complexity(project_dir=args.project_dir, no_input=False) 124 | if not args.noserver: 125 | serve_static_site(output_dir=output_dir, port=args.port) 126 | 127 | 128 | if __name__ == '__main__': 129 | main() 130 | -------------------------------------------------------------------------------- /complexity/prep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity.prep 6 | --------------- 7 | 8 | Functions for preparing a Complexity project for static site generation, 9 | before it actually happens. 10 | """ 11 | 12 | import os 13 | import shutil 14 | 15 | from . import utils 16 | 17 | 18 | def prompt_and_delete_cruft(output_dir): 19 | """ 20 | Asks if it's okay to delete `output_dir/`. 21 | If so, go ahead and delete it. 22 | 23 | :param output_dir: The Complexity output directory, e.g. `www/`. 24 | :paramtype output_dir: directory 25 | """ 26 | if not os.path.exists(output_dir): 27 | return True 28 | 29 | ok_to_delete = utils.query_yes_no( 30 | 'Is it okay to delete {0}?'.format(output_dir) 31 | ) 32 | if ok_to_delete: 33 | shutil.rmtree(output_dir) 34 | return True 35 | else: 36 | print( 37 | "Aborting. Please manually remove {0} and retry." 38 | .format(output_dir) 39 | ) 40 | return False 41 | -------------------------------------------------------------------------------- /complexity/serve.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity.serve 6 | ------------------- 7 | 8 | Functions for serving a static HTML website locally. 9 | """ 10 | 11 | import os 12 | import sys 13 | 14 | 15 | PY3 = sys.version > '3' 16 | if PY3: 17 | import http.server as httpserver 18 | import socketserver 19 | else: 20 | import SimpleHTTPServer as httpserver 21 | import SocketServer as socketserver 22 | 23 | 24 | def serve_static_site(output_dir, port=9090): 25 | """ 26 | Serve a directory containing static HTML files, on a specified port. 27 | 28 | :param output_dir: Output directory to be served. 29 | """ 30 | os.chdir(output_dir) 31 | Handler = httpserver.SimpleHTTPRequestHandler 32 | 33 | # See http://stackoverflow.com/questions/16433522/socketserver-getting-rid- 34 | # of-errno-98-address-already-in-use 35 | socketserver.TCPServer.allow_reuse_address = True 36 | 37 | httpd = socketserver.TCPServer(("", port), Handler) 38 | print("serving at port", port) 39 | 40 | try: 41 | httpd.serve_forever() 42 | except (KeyboardInterrupt, SystemExit): 43 | print("Shutting down...") 44 | httpd.socket.close() 45 | sys.exit() 46 | -------------------------------------------------------------------------------- /complexity/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | complexity.utils 6 | ---------------- 7 | 8 | Helper functions used throughout Complexity. 9 | """ 10 | 11 | import errno 12 | import os 13 | import sys 14 | 15 | PY3 = sys.version > '3' 16 | if PY3: 17 | pass 18 | else: 19 | import codecs 20 | input = raw_input 21 | 22 | 23 | def make_sure_path_exists(path): 24 | """ 25 | Ensures that a directory exists. 26 | 27 | :param path: A directory path. 28 | """ 29 | try: 30 | os.makedirs(path) 31 | except OSError as exception: 32 | if exception.errno != errno.EEXIST: 33 | return False 34 | return True 35 | 36 | 37 | def unicode_open(filename, *args, **kwargs): 38 | """ 39 | Opens a file as usual on Python 3, and with UTF-8 encoding on Python 2. 40 | 41 | :param filename: Name of file to open. 42 | """ 43 | if PY3: 44 | return open(filename, *args, **kwargs) 45 | kwargs['encoding'] = "utf-8" 46 | return codecs.open(filename, *args, **kwargs) 47 | 48 | 49 | def query_yes_no(question, default="yes"): 50 | """ 51 | Ask a yes/no question via `raw_input()` and return their answer. 52 | 53 | :param question: A string that is presented to the user. 54 | :param default: The presumed answer if the user just hits . 55 | It must be "yes" (the default), "no" or None (meaning 56 | an answer is required of the user). 57 | 58 | The "answer" return value is one of "yes" or "no". 59 | 60 | Adapted from 61 | http://stackoverflow.com/questions/3041986/python-command-line-yes-no-input 62 | http://code.activestate.com/recipes/577058/ 63 | 64 | """ 65 | valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} 66 | if default is None: 67 | prompt = " [y/n] " 68 | elif default == "yes": 69 | prompt = " [Y/n] " 70 | elif default == "no": 71 | prompt = " [y/N] " 72 | else: 73 | raise ValueError("invalid default answer: '%s'" % default) 74 | 75 | while True: 76 | sys.stdout.write(question + prompt) 77 | choice = input().lower() 78 | 79 | if default is not None and choice == '': 80 | return valid[default] 81 | elif choice in valid: 82 | return valid[choice] 83 | else: 84 | sys.stdout.write("Please respond with 'yes' or 'no' " 85 | "(or 'y' or 'n').\n") 86 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/complexity.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/complexity.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/complexity" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/complexity" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/_themes/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /docs/_themes/README.rst: -------------------------------------------------------------------------------- 1 | Complexity Sphinx Style 2 | ======================== 3 | 4 | This directory contains the Complexity Sphinx theme and styles. 5 | 6 | It is a derivative of the Sphinx styles that Kenneth Reitz uses in most of his 7 | projects, which is a derivative of Armin Ronacher's themes for Flask and Flask 8 | related projects. 9 | 10 | Out of respect to both Armin Ronacher and Kenneth Reitz, this theme has been 11 | heavily customized so as to present a very different look and feel. 12 | 13 | This theme may be used by Complexity-related projects without modification. 14 | 15 | If you use it for a project unrelated to Complexity, customize it heavily so 16 | that it looks substantially different. 17 | -------------------------------------------------------------------------------- /docs/_themes/complexity/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "basic/layout.html" %} 2 | {%- block extrahead %} 3 | {{ super() }} 4 | {% if theme_touch_icon %} 5 | 6 | {% endif %} 7 | 8 | {% endblock %} 9 | {%- block relbar2 %}{% endblock %} 10 | {%- block footer %} 11 | 14 | 15 | Fork me on GitHub 16 | 17 | 28 | 34 | 35 | 38 | 39 | 40 | 55 | 56 | 57 | 58 | {%- endblock %} 59 | -------------------------------------------------------------------------------- /docs/_themes/complexity/relations.html: -------------------------------------------------------------------------------- 1 |

Related Topics

2 | 20 | -------------------------------------------------------------------------------- /docs/_themes/complexity/static/complexity.css_t: -------------------------------------------------------------------------------- 1 | /* 2 | * complexity.css_t 3 | * ~~~~~~~~~~~~ 4 | * 5 | * :copyright: Copyright 2013 by Audrey Roy. Derived from flasky.css_t by 6 | * Armin Ronacher. Modifications by Kenneth Reitz. 7 | * :license: Flask Design License, see LICENSE for details. 8 | */ 9 | 10 | {% set page_width = '960px' %} 11 | {% set sidebar_width = '200px' %} 12 | 13 | @import url("basic.css"); 14 | @import url(http://fonts.googleapis.com/css?family=Lato:700); 15 | 16 | /* -- page layout ----------------------------------------------------------- */ 17 | 18 | body { 19 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 20 | font-size: 16px; 21 | background-color: white; 22 | color: #000; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | 27 | div.document { 28 | width: {{ page_width }}; 29 | margin: 30px auto 0 auto; 30 | } 31 | 32 | div.documentwrapper { 33 | float: left; 34 | width: 100%; 35 | } 36 | 37 | div.bodywrapper { 38 | margin: 0 0 0 {{ sidebar_width }}; 39 | } 40 | 41 | div.sphinxsidebar { 42 | width: {{ sidebar_width }}; 43 | } 44 | 45 | hr { 46 | border: 1px solid #B1B4B6; 47 | } 48 | 49 | div.body { 50 | background-color: #ffffff; 51 | color: #3E4349; 52 | padding: 0 30px 0 30px; 53 | } 54 | 55 | img.floatingflask { 56 | padding: 0 0 10px 10px; 57 | float: right; 58 | } 59 | 60 | div.footer { 61 | width: {{ page_width }}; 62 | margin: 20px auto 30px auto; 63 | font-size: 14px; 64 | color: #888; 65 | text-align: right; 66 | } 67 | 68 | div.footer a { 69 | color: #888; 70 | } 71 | 72 | div.related { 73 | display: none; 74 | } 75 | 76 | div.sphinxsidebar a { 77 | color: #444; 78 | text-decoration: none; 79 | border-bottom: 1px dotted #999; 80 | } 81 | 82 | div.sphinxsidebar a:hover { 83 | border-bottom: 1px solid #999; 84 | } 85 | 86 | div.sphinxsidebar { 87 | font-size: 14px; 88 | line-height: 1.5; 89 | } 90 | 91 | div.sphinxsidebarwrapper { 92 | padding: 18px 10px; 93 | } 94 | 95 | div.sphinxsidebarwrapper p.logo { 96 | padding: 0; 97 | margin: -10px 0 0 -20px; 98 | text-align: center; 99 | } 100 | 101 | div.sphinxsidebar h3, 102 | div.sphinxsidebar h4 { 103 | font-family: 'Lato', serif; 104 | color: #444; 105 | font-size: 24px; 106 | font-weight: normal; 107 | margin: 0 0 5px 0; 108 | padding: 0; 109 | } 110 | 111 | div.sphinxsidebar h4 { 112 | font-size: 20px; 113 | } 114 | 115 | div.sphinxsidebar h3 a { 116 | color: #444; 117 | } 118 | 119 | div.sphinxsidebar p.logo a, 120 | div.sphinxsidebar h3 a, 121 | div.sphinxsidebar p.logo a:hover, 122 | div.sphinxsidebar h3 a:hover { 123 | border: none; 124 | } 125 | 126 | div.sphinxsidebar p { 127 | color: #555; 128 | margin: 10px 0; 129 | } 130 | 131 | div.sphinxsidebar ul { 132 | margin: 10px 0; 133 | padding: 0; 134 | color: #000; 135 | } 136 | 137 | div.sphinxsidebar input { 138 | border: 1px solid #ccc; 139 | font-family: 'Lato', serif; 140 | font-size: 1em; 141 | } 142 | 143 | /* -- body styles ----------------------------------------------------------- */ 144 | 145 | a { 146 | color: #004B6B; 147 | text-decoration: underline; 148 | } 149 | 150 | a:hover { 151 | color: #6D4100; 152 | text-decoration: underline; 153 | } 154 | 155 | div.body h1, 156 | div.body h2, 157 | div.body h3, 158 | div.body h4, 159 | div.body h5, 160 | div.body h6 { 161 | font-family: 'Lato', serif; 162 | font-weight: 700; 163 | margin: 30px 0px 10px 0px; 164 | padding: 0; 165 | } 166 | 167 | div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } 168 | div.body h2 { font-size: 180%; } 169 | div.body h3 { font-size: 150%; } 170 | div.body h4 { font-size: 130%; } 171 | div.body h5 { font-size: 100%; } 172 | div.body h6 { font-size: 100%; } 173 | 174 | a.headerlink { 175 | color: #ddd; 176 | padding: 0 4px; 177 | text-decoration: none; 178 | } 179 | 180 | a.headerlink:hover { 181 | color: #444; 182 | background: #eaeaea; 183 | } 184 | 185 | div.body p, div.body dd, div.body li { 186 | line-height: 1.4em; 187 | } 188 | 189 | div.admonition { 190 | background: #fafafa; 191 | margin: 20px -30px; 192 | padding: 10px 30px; 193 | border-top: 1px solid #ccc; 194 | border-bottom: 1px solid #ccc; 195 | } 196 | 197 | div.admonition tt.xref, div.admonition a tt { 198 | border-bottom: 1px solid #fafafa; 199 | } 200 | 201 | dd div.admonition { 202 | margin-left: -60px; 203 | padding-left: 60px; 204 | } 205 | 206 | div.admonition p.admonition-title { 207 | font-family: 'Garamond', 'Georgia', serif; 208 | font-weight: normal; 209 | font-size: 24px; 210 | margin: 0 0 10px 0; 211 | padding: 0; 212 | line-height: 1; 213 | } 214 | 215 | div.admonition p.last { 216 | margin-bottom: 0; 217 | } 218 | 219 | div.highlight { 220 | background-color: white; 221 | } 222 | 223 | dt:target, .highlight { 224 | background: #FAF3E8; 225 | } 226 | 227 | div.note { 228 | background-color: #FFFCD6; 229 | border: 1px solid #ccc; 230 | } 231 | 232 | div.seealso { 233 | background-color: #ffc; 234 | border: 1px solid #ff6; 235 | } 236 | 237 | div.topic { 238 | background-color: #eee; 239 | } 240 | 241 | p.admonition-title { 242 | display: inline; 243 | } 244 | 245 | p.admonition-title:after { 246 | content: ":"; 247 | } 248 | 249 | pre, tt { 250 | font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 251 | font-size: 0.9em; 252 | } 253 | 254 | img.screenshot { 255 | } 256 | 257 | tt.descname, tt.descclassname { 258 | font-size: 0.95em; 259 | } 260 | 261 | tt.descname { 262 | padding-right: 0.08em; 263 | } 264 | 265 | img.screenshot { 266 | -moz-box-shadow: 2px 2px 4px #eee; 267 | -webkit-box-shadow: 2px 2px 4px #eee; 268 | box-shadow: 2px 2px 4px #eee; 269 | } 270 | 271 | table.docutils { 272 | border: 1px solid #888; 273 | -moz-box-shadow: 2px 2px 4px #eee; 274 | -webkit-box-shadow: 2px 2px 4px #eee; 275 | box-shadow: 2px 2px 4px #eee; 276 | } 277 | 278 | table.docutils td, table.docutils th { 279 | border: 1px solid #888; 280 | padding: 0.25em 0.7em; 281 | } 282 | 283 | table.field-list, table.footnote { 284 | border: none; 285 | -moz-box-shadow: none; 286 | -webkit-box-shadow: none; 287 | box-shadow: none; 288 | } 289 | 290 | table.footnote { 291 | margin: 15px 0; 292 | width: 100%; 293 | border: 1px solid #eee; 294 | background: #fdfdfd; 295 | font-size: 0.9em; 296 | } 297 | 298 | table.footnote + table.footnote { 299 | margin-top: -15px; 300 | border-top: none; 301 | } 302 | 303 | table.field-list th { 304 | padding: 0 0.8em 0 0; 305 | } 306 | 307 | table.field-list td { 308 | padding: 0; 309 | } 310 | 311 | table.footnote td.label { 312 | width: 0px; 313 | padding: 0.3em 0 0.3em 0.5em; 314 | } 315 | 316 | table.footnote td { 317 | padding: 0.3em 0.5em; 318 | } 319 | 320 | dl { 321 | margin: 0; 322 | padding: 0; 323 | } 324 | 325 | dl dd { 326 | margin-left: 30px; 327 | } 328 | 329 | blockquote { 330 | margin: 0 0 0 30px; 331 | padding: 0; 332 | } 333 | 334 | ul, ol { 335 | margin: 10px 0 10px 30px; 336 | padding: 0; 337 | } 338 | 339 | pre { 340 | background: #D6FBFF; 341 | padding: 7px 30px; 342 | margin: 15px -30px; 343 | line-height: 1.3em; 344 | } 345 | 346 | dl pre, blockquote pre, li pre { 347 | margin-left: -60px; 348 | padding-left: 60px; 349 | } 350 | 351 | dl dl pre { 352 | margin-left: -90px; 353 | padding-left: 90px; 354 | } 355 | 356 | tt { 357 | background-color: #ecf0f3; 358 | color: #222; 359 | /* padding: 1px 2px; */ 360 | } 361 | 362 | tt.xref, a tt { 363 | background-color: #FBFBFB; 364 | border-bottom: 1px solid white; 365 | } 366 | 367 | a.reference { 368 | text-decoration: none; 369 | border-bottom: 1px dotted #004B6B; 370 | } 371 | 372 | a.reference:hover { 373 | border-bottom: 1px solid #6D4100; 374 | } 375 | 376 | a.footnote-reference { 377 | text-decoration: none; 378 | font-size: 0.7em; 379 | vertical-align: top; 380 | border-bottom: 1px dotted #004B6B; 381 | } 382 | 383 | a.footnote-reference:hover { 384 | border-bottom: 1px solid #6D4100; 385 | } 386 | 387 | a:hover tt { 388 | background: #EEE; 389 | } 390 | 391 | 392 | @media screen and (max-width: 870px) { 393 | 394 | div.sphinxsidebar { 395 | display: none; 396 | } 397 | 398 | div.document { 399 | width: 100%; 400 | 401 | } 402 | 403 | div.documentwrapper { 404 | margin-left: 0; 405 | margin-top: 0; 406 | margin-right: 0; 407 | margin-bottom: 0; 408 | } 409 | 410 | div.bodywrapper { 411 | margin-top: 0; 412 | margin-right: 0; 413 | margin-bottom: 0; 414 | margin-left: 0; 415 | } 416 | 417 | ul { 418 | margin-left: 0; 419 | } 420 | 421 | .document { 422 | width: auto; 423 | } 424 | 425 | .footer { 426 | width: auto; 427 | } 428 | 429 | .bodywrapper { 430 | margin: 0; 431 | } 432 | 433 | .footer { 434 | width: auto; 435 | } 436 | 437 | .github { 438 | display: none; 439 | } 440 | 441 | 442 | 443 | } 444 | 445 | 446 | 447 | @media screen and (max-width: 875px) { 448 | 449 | body { 450 | margin: 0; 451 | padding: 20px 30px; 452 | } 453 | 454 | div.documentwrapper { 455 | float: none; 456 | background: white; 457 | } 458 | 459 | div.sphinxsidebar { 460 | display: block; 461 | float: none; 462 | width: 102.5%; 463 | margin: 50px -30px -20px -30px; 464 | padding: 10px 20px; 465 | background: #333; 466 | color: white; 467 | } 468 | 469 | div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, 470 | div.sphinxsidebar h3 a { 471 | color: white; 472 | } 473 | 474 | div.sphinxsidebar a { 475 | color: #aaa; 476 | } 477 | 478 | div.sphinxsidebar p.logo { 479 | display: none; 480 | } 481 | 482 | div.document { 483 | width: 100%; 484 | margin: 0; 485 | } 486 | 487 | div.related { 488 | display: block; 489 | margin: 0; 490 | padding: 10px 0 20px 0; 491 | } 492 | 493 | div.related ul, 494 | div.related ul li { 495 | margin: 0; 496 | padding: 0; 497 | } 498 | 499 | div.footer { 500 | display: none; 501 | } 502 | 503 | div.bodywrapper { 504 | margin: 0; 505 | } 506 | 507 | div.body { 508 | min-height: 0; 509 | padding: 0; 510 | } 511 | 512 | .rtd_doc_footer { 513 | display: none; 514 | } 515 | 516 | .document { 517 | width: auto; 518 | } 519 | 520 | .footer { 521 | width: auto; 522 | } 523 | 524 | .footer { 525 | width: auto; 526 | } 527 | 528 | .github { 529 | display: none; 530 | } 531 | } 532 | 533 | 534 | /* misc. */ 535 | 536 | .revsys-inline { 537 | display: none!important; 538 | } -------------------------------------------------------------------------------- /docs/_themes/complexity/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = complexity.css 4 | pygments_style = complexity_theme_support.ComplexityStyle 5 | 6 | [options] 7 | touch_icon = 8 | -------------------------------------------------------------------------------- /docs/_themes/complexity_theme_support.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Complexity Pygments styles. 5 | Heavily customized for Complexity. 6 | Based on Armin Ronacher's flasky extensions. flasky pygments style based on tango style. 7 | """ 8 | from pygments.style import Style 9 | from pygments.token import Keyword, Name, Comment, String, Error, \ 10 | Number, Operator, Generic, Whitespace, Punctuation, Other, Literal 11 | 12 | 13 | class ComplexityStyle(Style): 14 | # background_color = "#D6FBFF" Actually defined in complexity.css_t 15 | default_style = "" 16 | 17 | styles = { 18 | # No corresponding class for the following: 19 | #Text: "", # class: '' 20 | Whitespace: "underline #f8f8f8", # class: 'w' 21 | Error: "#a40000 border:#ef2929", # class: 'err' 22 | Other: "#000000", # class 'x' 23 | 24 | Comment: "italic #8f5902", # class: 'c' 25 | Comment.Preproc: "noitalic", # class: 'cp' 26 | 27 | Keyword: "bold #004461", # class: 'k' 28 | Keyword.Constant: "bold #004461", # class: 'kc' 29 | Keyword.Declaration: "bold #004461", # class: 'kd' 30 | Keyword.Namespace: "bold #004461", # class: 'kn' 31 | Keyword.Pseudo: "bold #004461", # class: 'kp' 32 | Keyword.Reserved: "bold #004461", # class: 'kr' 33 | Keyword.Type: "bold #004461", # class: 'kt' 34 | 35 | Operator: "#582800", # class: 'o' 36 | Operator.Word: "bold #004461", # class: 'ow' - like keywords 37 | 38 | Punctuation: "bold #000000", # class: 'p' 39 | 40 | # because special names such as Name.Class, Name.Function, etc. 41 | # are not recognized as such later in the parsing, we choose them 42 | # to look the same as ordinary variables. 43 | Name: "#000000", # class: 'n' 44 | Name.Attribute: "#c4a000", # class: 'na' - to be revised 45 | Name.Builtin: "#004461", # class: 'nb' 46 | Name.Builtin.Pseudo: "#3465a4", # class: 'bp' 47 | Name.Class: "#000000", # class: 'nc' - to be revised 48 | Name.Constant: "#000000", # class: 'no' - to be revised 49 | Name.Decorator: "#888", # class: 'nd' - to be revised 50 | Name.Entity: "#ce5c00", # class: 'ni' 51 | Name.Exception: "bold #cc0000", # class: 'ne' 52 | Name.Function: "#000000", # class: 'nf' 53 | Name.Property: "#000000", # class: 'py' 54 | Name.Label: "#f57900", # class: 'nl' 55 | Name.Namespace: "#000000", # class: 'nn' - to be revised 56 | Name.Other: "#000000", # class: 'nx' 57 | Name.Tag: "bold #004461", # class: 'nt' - like a keyword 58 | Name.Variable: "#000000", # class: 'nv' - to be revised 59 | Name.Variable.Class: "#000000", # class: 'vc' - to be revised 60 | Name.Variable.Global: "#000000", # class: 'vg' - to be revised 61 | Name.Variable.Instance: "#000000", # class: 'vi' - to be revised 62 | 63 | Number: "#990000", # class: 'm' 64 | 65 | Literal: "#000000", # class: 'l' 66 | Literal.Date: "#000000", # class: 'ld' 67 | 68 | String: "#4e9a06", # class: 's' 69 | String.Backtick: "#4e9a06", # class: 'sb' 70 | String.Char: "#4e9a06", # class: 'sc' 71 | String.Doc: "italic #8f5902", # class: 'sd' - like a comment 72 | String.Double: "#4e9a06", # class: 's2' 73 | String.Escape: "#4e9a06", # class: 'se' 74 | String.Heredoc: "#4e9a06", # class: 'sh' 75 | String.Interpol: "#4e9a06", # class: 'si' 76 | String.Other: "#4e9a06", # class: 'sx' 77 | String.Regex: "#4e9a06", # class: 'sr' 78 | String.Single: "#4e9a06", # class: 's1' 79 | String.Symbol: "#4e9a06", # class: 'ss' 80 | 81 | Generic: "#000000", # class: 'g' 82 | Generic.Deleted: "#a40000", # class: 'gd' 83 | Generic.Emph: "italic #000000", # class: 'ge' 84 | Generic.Error: "#ef2929", # class: 'gr' 85 | Generic.Heading: "bold #000080", # class: 'gh' 86 | Generic.Inserted: "#00A000", # class: 'gi' 87 | Generic.Output: "#888", # class: 'go' 88 | Generic.Prompt: "#745334", # class: 'gp' 89 | Generic.Strong: "bold #000000", # class: 'gs' 90 | Generic.Subheading: "bold #800080", # class: 'gu' 91 | Generic.Traceback: "bold #a40000", # class: 'gt' 92 | } 93 | -------------------------------------------------------------------------------- /docs/advanced_usage.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Advanced Usage 3 | =============== 4 | 5 | In the tutorial, you saw an example of a minimal Complexity project layout. 6 | Now here is an example of a more advanced Complexity site:: 7 | 8 | my_repo/ 9 | ├── project/ <--------- input 10 | │ ├── assets/ 11 | │ │ ├── css/ 12 | │ │ ├── js/ 13 | │ │ ├── img/ 14 | │ │ ├── ico/ 15 | │ │ └── robots.txt 16 | │ ├── context/ 17 | │ │ ├── books.json 18 | │ │ └── movies.json 19 | │ ├── templates/ 20 | │ │ ├── base.html 21 | │ │ ├── index.html 22 | │ │ └── about.html 23 | │ └── complexity.yml 24 | │ 25 | └── www/ <---------- output 26 | ├── index.html 27 | ├── about/ 28 | │ └── index.html 29 | ├── css/ 30 | ├── js/ 31 | ├── img/ 32 | └── ico/ 33 | 34 | Let's explore some of Complexity's advanced features. 35 | 36 | Config Using complexity.yml 37 | ---------------------------- 38 | 39 | You can configure a Complexity project with a `complexity.yml` file like 40 | this: 41 | 42 | .. code-block:: yaml 43 | 44 | # Config file for a Complexity project 45 | 46 | # Directories are relative to current (project) dir 47 | templates_dir: "templates" 48 | assets_dir: "assets" 49 | context_dir: "context" 50 | output_dir: "../www" 51 | 52 | # List of templates that should not be expanded to pretty-format URLs 53 | unexpanded_templates: 54 | - "404.html" 55 | - "500.html" 56 | 57 | Put `complexity.yml` in your project root (e.g. in project/). 58 | 59 | Here is what you can configure: 60 | 61 | * `templates_dir`: Directory containing templates. Anything that needs to be 62 | templated goes here. 63 | * `assets_dir`: Directory containing static assets (to be copied over without 64 | templating). 65 | * `context_dir`: Directory containing `.json` files to be turned into context 66 | variables for the templates. 67 | * `output_dir`: Directory where the generated website will be output. 68 | * `unexpanded_templates`: List of HTML templates for which you want to keep 69 | the URLs unexpanded (e.g. `404.html` instead of `404/index.html`). 70 | 71 | All of the above are optional. 72 | 73 | Complexity uses sensible defaults. If you don't specify a `complexity.yml`, 74 | this is the assumed default config: 75 | 76 | .. code-block:: yaml 77 | 78 | templates_dir: "templates" 79 | assets_dir: "assets" 80 | context_dir: "context" 81 | output_dir: "../www" 82 | 83 | JSON Auto-Loading 84 | ---------------------- 85 | 86 | Data from .json files in your context directory automatically turns into 87 | template context data. 88 | 89 | For example, suppose you have this in `context/books.json`: 90 | 91 | .. code-block:: javascript 92 | 93 | [ 94 | { 95 | "url": "http://www.amazon.com/Two-Scoops-Django-Best-Practices/dp/1481879707/", 96 | "title": "Two Scoops of Django" 97 | }, 98 | { 99 | "url": "http://www.amazon.com/Very-Magical-Caterpillar-Tale-Butterfly/dp/1453714081/", 100 | "title": "A Very Magical Caterpillar Tale" 101 | } 102 | ] 103 | 104 | Then you can refer to the books in a template like this: 105 | 106 | .. code-block:: html+jinja 107 | 108 | {% extends 'base.html' %} 109 | 110 | {% block title %}Index{% endblock %} 111 | 112 | {% block content %} 113 |

Here are my books:

114 | {% for book in books %} 115 | {{ book.title }} 116 | {% endfor %} 117 | {% endblock %} 118 | 119 | The contents of `books.json` get turned into `{{ books }}`, which in this case 120 | is a list that you can iterate over. 121 | 122 | What About Static JSON Files? 123 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 124 | 125 | If you have .json files that you want served as static assets rather than 126 | turned into context data, that's fine. 127 | 128 | Just put them in `assets/js/` (or anywhere in `assets/`), and they'll get 129 | copied over to the output directory like any other static asset. 130 | 131 | Other Asset Directories and Files 132 | --------------------------------- 133 | 134 | You can create any type of asset directory or file that you want in `assets/` 135 | (or your desired assets directory). 136 | 137 | All assets will get copied over to `www/` when you generate your site. 138 | 139 | .. note:: Better handling/processing of assets will be implemented in an 140 | upcoming release, including CSS/JS minification, image optimization, 141 | and SASS and/or LESS compilation. 142 | 143 | Using Complexity as a Library 144 | ------------------------------ 145 | 146 | Complexity can be used just like any other Python package. 147 | 148 | You can simply call the Complexity API like this: 149 | 150 | .. code-block:: python 151 | 152 | from complexity.main import complexity 153 | 154 | complexity('project/', 'www/') 155 | 156 | Calling other Complexity API functions is just as straightforward: 157 | 158 | .. code-block:: python 159 | 160 | from complexity import generate 161 | 162 | # Optionally generate context if you need to 163 | context = generate_context(context_dir='project/context/') 164 | 165 | # Generate HTML from your templates (and context, if you have it) 166 | generate.generate_html(templates_dir='project/templates/', output_dir='www/', context=context) 167 | 168 | # Copy assets over 169 | generate.copy_assets(assets_dir='project/assets/', output_dir='www/') 170 | 171 | This allows you to use Complexity as a dependency in your own Python projects. 172 | 173 | .. note:: As of this release, the API works, but it is subject to change. 174 | Please pin your dependencies if you need this to be stable, and keep an eye 175 | on this section for changes when you upgrade. 176 | -------------------------------------------------------------------------------- /docs/authors.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../AUTHORS.rst 2 | -------------------------------------------------------------------------------- /docs/complexity.rst: -------------------------------------------------------------------------------- 1 | complexity Package 2 | ================== 3 | 4 | :mod:`complexity` Package 5 | ------------------------- 6 | 7 | .. automodule:: complexity.__init__ 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | :mod:`conf` Module 13 | ------------------ 14 | 15 | .. automodule:: complexity.conf 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | 20 | :mod:`exceptions` Module 21 | ------------------------ 22 | 23 | .. automodule:: complexity.exceptions 24 | :members: 25 | :undoc-members: 26 | :show-inheritance: 27 | 28 | :mod:`generate` Module 29 | ---------------------- 30 | 31 | .. automodule:: complexity.generate 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | 36 | :mod:`main` Module 37 | ------------------ 38 | 39 | .. automodule:: complexity.main 40 | :members: 41 | :undoc-members: 42 | :show-inheritance: 43 | 44 | :mod:`prep` Module 45 | ------------------ 46 | 47 | .. automodule:: complexity.prep 48 | :members: 49 | :undoc-members: 50 | :show-inheritance: 51 | 52 | :mod:`serve` Module 53 | ------------------- 54 | 55 | .. automodule:: complexity.serve 56 | :members: 57 | :undoc-members: 58 | :show-inheritance: 59 | 60 | :mod:`utils` Module 61 | ------------------- 62 | 63 | .. automodule:: complexity.utils 64 | :members: 65 | :undoc-members: 66 | :show-inheritance: 67 | 68 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # complexity documentation build configuration file, created by 4 | # sphinx-quickstart on Tue Jul 9 22:26:36 2013. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # Append parent dir 22 | cwd = os.getcwd() 23 | parent = os.path.dirname(cwd) 24 | sys.path.append(parent) 25 | 26 | # Append docs/_themes/ dir 27 | sys.path.append(os.path.abspath('_themes')) 28 | 29 | import complexity 30 | 31 | # -- General configuration ----------------------------------------------------- 32 | 33 | # If your documentation needs a minimal Sphinx version, state it here. 34 | #needs_sphinx = '1.0' 35 | 36 | # Add any Sphinx extension module names here, as strings. They can be extensions 37 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 38 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] 39 | 40 | # Add any paths that contain templates here, relative to this directory. 41 | templates_path = ['_templates'] 42 | 43 | # The suffix of source filenames. 44 | source_suffix = '.rst' 45 | 46 | # The encoding of source files. 47 | #source_encoding = 'utf-8-sig' 48 | 49 | # The master toctree document. 50 | master_doc = 'index' 51 | 52 | # General information about the project. 53 | project = u'complexity' 54 | copyright = u'2013, Audrey Roy' 55 | 56 | # The version info for the project you're documenting, acts as replacement for 57 | # |version| and |release|, also used in various other places throughout the 58 | # built documents. 59 | # 60 | # The short X.Y version. 61 | version = complexity.__version__ 62 | # The full version, including alpha/beta/rc tags. 63 | release = complexity.__version__ 64 | 65 | # The language for content autogenerated by Sphinx. Refer to documentation 66 | # for a list of supported languages. 67 | #language = None 68 | 69 | # There are two options for replacing |today|: either, you set today to some 70 | # non-false value, then it is used: 71 | #today = '' 72 | # Else, today_fmt is used as the format for a strftime call. 73 | #today_fmt = '%B %d, %Y' 74 | 75 | # List of patterns, relative to source directory, that match files and 76 | # directories to ignore when looking for source files. 77 | exclude_patterns = ['_build'] 78 | 79 | # The reST default role (used for this markup: `text`) to use for all documents. 80 | #default_role = None 81 | 82 | # If true, '()' will be appended to :func: etc. cross-reference text. 83 | #add_function_parentheses = True 84 | 85 | # If true, the current module name will be prepended to all description 86 | # unit titles (such as .. function::). 87 | #add_module_names = True 88 | 89 | # If true, sectionauthor and moduleauthor directives will be shown in the 90 | # output. They are ignored by default. 91 | #show_authors = False 92 | 93 | # The name of the Pygments (syntax highlighting) style to use. 94 | pygments_style = 'sphinx' 95 | 96 | # A list of ignored prefixes for module index sorting. 97 | #modindex_common_prefix = [] 98 | 99 | # If true, keep warnings as "system message" paragraphs in the built documents. 100 | #keep_warnings = False 101 | 102 | 103 | # -- Options for HTML output --------------------------------------------------- 104 | 105 | # The theme to use for HTML and HTML Help pages. See the documentation for 106 | # a list of builtin themes. 107 | html_theme = 'complexity' 108 | 109 | # Theme options are theme-specific and customize the look and feel of a theme 110 | # further. For a list of options available for each theme, see the 111 | # documentation. 112 | #html_theme_options = {} 113 | 114 | # Add any paths that contain custom themes here, relative to this directory. 115 | html_theme_path = ['_themes'] 116 | 117 | # The name for this set of Sphinx documents. If None, it defaults to 118 | # " v documentation". 119 | #html_title = None 120 | 121 | # A shorter title for the navigation bar. Default is the same as html_title. 122 | #html_short_title = None 123 | 124 | # The name of an image file (relative to this directory) to place at the top 125 | # of the sidebar. 126 | #html_logo = None 127 | 128 | # The name of an image file (within the static path) to use as favicon of the 129 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 130 | # pixels large. 131 | #html_favicon = None 132 | 133 | # Add any paths that contain custom static files (such as style sheets) here, 134 | # relative to this directory. They are copied after the builtin static files, 135 | # so a file named "default.css" will overwrite the builtin "default.css". 136 | html_static_path = ['_static'] 137 | 138 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 139 | # using the given strftime format. 140 | #html_last_updated_fmt = '%b %d, %Y' 141 | 142 | # If true, SmartyPants will be used to convert quotes and dashes to 143 | # typographically correct entities. 144 | #html_use_smartypants = True 145 | 146 | # Custom sidebar templates, maps document names to template names. 147 | #html_sidebars = {} 148 | 149 | # Additional templates that should be rendered to pages, maps page names to 150 | # template names. 151 | #html_additional_pages = {} 152 | 153 | # If false, no module index is generated. 154 | #html_domain_indices = True 155 | 156 | # If false, no index is generated. 157 | #html_use_index = True 158 | 159 | # If true, the index is split into individual pages for each letter. 160 | #html_split_index = False 161 | 162 | # If true, links to the reST sources are added to the pages. 163 | #html_show_sourcelink = True 164 | 165 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 166 | #html_show_sphinx = True 167 | 168 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 169 | #html_show_copyright = True 170 | 171 | # If true, an OpenSearch description file will be output, and all pages will 172 | # contain a tag referring to it. The value of this option must be the 173 | # base URL from which the finished HTML is served. 174 | #html_use_opensearch = '' 175 | 176 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 177 | #html_file_suffix = None 178 | 179 | # Output file base name for HTML help builder. 180 | htmlhelp_basename = 'complexitydoc' 181 | 182 | 183 | # -- Options for LaTeX output -------------------------------------------------- 184 | 185 | latex_elements = { 186 | # The paper size ('letterpaper' or 'a4paper'). 187 | #'papersize': 'letterpaper', 188 | 189 | # The font size ('10pt', '11pt' or '12pt'). 190 | #'pointsize': '10pt', 191 | 192 | # Additional stuff for the LaTeX preamble. 193 | #'preamble': '', 194 | } 195 | 196 | # Grouping the document tree into LaTeX files. List of tuples 197 | # (source start file, target name, title, author, documentclass [howto/manual]). 198 | latex_documents = [ 199 | ('index', 'complexity.tex', u'Complexity Documentation', 200 | u'Audrey Roy', 'manual'), 201 | ] 202 | 203 | # The name of an image file (relative to this directory) to place at the top of 204 | # the title page. 205 | #latex_logo = None 206 | 207 | # For "manual" documents, if this is true, then toplevel headings are parts, 208 | # not chapters. 209 | #latex_use_parts = False 210 | 211 | # If true, show page references after internal links. 212 | #latex_show_pagerefs = False 213 | 214 | # If true, show URL addresses after external links. 215 | #latex_show_urls = False 216 | 217 | # Documents to append as an appendix to all manuals. 218 | #latex_appendices = [] 219 | 220 | # If false, no module index is generated. 221 | #latex_domain_indices = True 222 | 223 | 224 | # -- Options for manual page output -------------------------------------------- 225 | 226 | # One entry per manual page. List of tuples 227 | # (source start file, name, description, authors, manual section). 228 | man_pages = [ 229 | ('index', 'complexity', u'Complexity Documentation', 230 | [u'Audrey Roy'], 1) 231 | ] 232 | 233 | # If true, show URL addresses after external links. 234 | #man_show_urls = False 235 | 236 | 237 | # -- Options for Texinfo output ------------------------------------------------ 238 | 239 | # Grouping the document tree into Texinfo files. List of tuples 240 | # (source start file, target name, title, author, 241 | # dir menu entry, description, category) 242 | texinfo_documents = [ 243 | ('index', 'complexity', u'Complexity Documentation', 244 | u'Audrey Roy', 'complexity', 'One line description of project.', 245 | 'Miscellaneous'), 246 | ] 247 | 248 | # Documents to append as an appendix to all manuals. 249 | #texinfo_appendices = [] 250 | 251 | # If false, no module index is generated. 252 | #texinfo_domain_indices = True 253 | 254 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 255 | #texinfo_show_urls = 'footnote' 256 | 257 | # If true, do not generate a @detailmenu in the "Top" node's menu. 258 | #texinfo_no_detailmenu = False 259 | -------------------------------------------------------------------------------- /docs/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.rst 2 | -------------------------------------------------------------------------------- /docs/history.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../HISTORY.rst 2 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. complexity documentation master file, created by 2 | sphinx-quickstart on Tue Jul 9 22:26:36 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Complexity 7 | ========== 8 | 9 | A refreshingly simple static site generator, for those who like to work in HTML. 10 | -------------------------------------------------------------------------------- 11 | 12 | This friendly guide contains everything you need to know to create and publish 13 | static HTML websites with Complexity. 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | 18 | readme 19 | installation 20 | upgrading 21 | tutorial 22 | advanced_usage 23 | troubleshooting 24 | 25 | API Reference 26 | ------------- 27 | 28 | .. toctree:: 29 | :maxdepth: 2 30 | 31 | complexity 32 | 33 | Project Info 34 | ------------ 35 | 36 | .. toctree:: 37 | :maxdepth: 2 38 | 39 | contributing 40 | authors 41 | history 42 | 43 | Index 44 | ----- 45 | 46 | * :ref:`genindex` 47 | * :ref:`modindex` 48 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | .. note:: Mac and Linux users may need to use "sudo" before the install commands. But 6 | use `virtualenv`_ if you don't want to sudo -- it's great. 7 | 8 | .. _`virtualenv`: http://www.virtualenv.org/en/latest/ 9 | 10 | Best Method: Pip 11 | ----------------- 12 | 13 | This will download and install Complexity:: 14 | 15 | $ pip install complexity 16 | 17 | This method requires an installer tool called `pip`, which you can get from 18 | http://www.pip-installer.org/. 19 | 20 | Don't worry, you can later uninstall Complexity like this:: 21 | 22 | $ pip uninstall complexity 23 | 24 | Alternate Method 1: Setup.py 25 | ------------------------------- 26 | 27 | If you can't use `pip` to install Complexity, download the latest Complexity 28 | release from https://pypi.python.org/pypi/complexity. 29 | 30 | Then unzip and install Complexity:: 31 | 32 | $ tar xzvf 33 | $ cd 34 | $ python setup.py install 35 | 36 | 37 | Alternate Method 2: Easy Install 38 | -------------------------------- 39 | 40 | If neither of the above methods work for some reason, try this:: 41 | 42 | $ easy_install complexity 43 | 44 | And if that doesn't work, see :doc:`troubleshooting`. 45 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\complexity.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\complexity.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | complexity 2 | ========== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | complexity 8 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | -------------------------------------------------------------------------------- /docs/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Troubleshooting 3 | =============== 4 | 5 | Installation Problems 6 | --------------------- 7 | 8 | Problem: Pip Fails 9 | ~~~~~~~~~~~~~~~~~~~~ 10 | 11 | Don't worry if `pip` fails like this:: 12 | 13 | $ pip install complexity 14 | ... 15 | error: could not create '/Library/Python/2.7/site-packages/complexity': 16 | Permission denied 17 | 18 | We've got a couple of solutions for that. 19 | 20 | Best Solution: Use Virtualenv 21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | 1. Install virtualenv systemwide with `pip`:: 24 | 25 | $ sudo pip install virtualenv 26 | 27 | 2. Create a virtualenv for Complexity:: 28 | 29 | $ virtualenv complexity-env 30 | $ source complexity-env/bin/activate 31 | (or complexity-env/Scripts/activate.bat on Windows) 32 | (complexity-env) $ 33 | 34 | 3. Install Complexity into the virtualenv:: 35 | 36 | (complexity-env) $ pip install complexity 37 | 38 | Alternate Solution: Install Systemwide 39 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 | 41 | 1. Install Complexity systemwide with `pip`:: 42 | 43 | $ sudo pip install complexity 44 | 45 | 2. If that doesn't work, you can use `easy_install` instead:: 46 | 47 | $ sudo easy_install complexity 48 | 49 | Site Generation Problems 50 | ------------------------ 51 | 52 | Problem: Site Generation Fails 53 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 54 | 55 | If you get an error like this:: 56 | 57 | jinja2.exceptions.TemplateSyntaxError: Unexpected end of template. Jinja 58 | was looking for the following tags: 'endblock'. The innermost block that 59 | needs to be closed is 'block'. 60 | 61 | Then check your templates carefully and make sure that you've closed all 62 | blocks properly with `{% endblock %}`. 63 | 64 | Still Having Problems? 65 | ---------------------- 66 | 67 | `File an issue here`_ with the following info: 68 | 69 | * Your operating system name and version. 70 | * Any details about your local setup that might be helpful in troubleshooting. 71 | * Detailed steps to reproduce the problems. 72 | 73 | .. _`File an issue here`: https://github.com/audreyr/complexity/issues/new 74 | -------------------------------------------------------------------------------- /docs/tutorial.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Tutorial 3 | ======== 4 | 5 | Part 0: Overview 6 | ---------------- 7 | 8 | Complexity is a refreshingly simple static site generator, for those who like to 9 | work in HTML. It allows you to quickly see how your changes affect your site. 10 | 11 | This quick tutorial will show you how to run this generator on your own using the 12 | most basic structure possible. Just type the given instructions into your terminal. 13 | 14 | If you have any specific questions you may find help in the documentation: 15 | http://complexity.readthedocs.org/en/latest/ 16 | 17 | Or on the Github page: https://github.com/audreyr/complexity 18 | 19 | This is the directory structure for a minimal Complexity site:: 20 | 21 | my_repo/ 22 | ├── project/ <--------- input 23 | │ ├── assets/ 24 | │ │ ├── css/ 25 | │ │ ├── js/ 26 | │ │ └── img/ 27 | │ │ 28 | │ └── templates/ 29 | │ ├── base.html 30 | │ ├── index.html 31 | │ └── about.html 32 | │ 33 | └── www/ <---------- output 34 | ├── index.html 35 | ├── about/ 36 | │ └── index.html 37 | ├── css/ 38 | ├── js/ 39 | └── img/ 40 | 41 | Part 1: Setup 42 | ------------- 43 | 44 | First, grab a copy of the example Complexity site:: 45 | 46 | git clone https://github.com/audreyr/complexity-example.git 47 | 48 | Open everything in a text editor. You should see a main `project/` directory 49 | with subfolders for your work: 50 | 51 | * Study the template files in `templates/`. We'll go over them shortly. 52 | 53 | * Notice the `assets/` directory. That is where you put your static files. 54 | 55 | * Creating additional directories in `assets/` (e.g. `ico/`) is fine; they'll get 56 | copied over to `www/` without modification. 57 | 58 | At the same level as `project/`, a `www/` directory will be auto-generated. 59 | It will contain your final rendered templates and optimized static assets. 60 | 61 | When you're done, you should have a project structure like that in 62 | https://github.com/audreyr/complexity-example. 63 | 64 | Part 2: What's in a Complexity Site? 65 | ------------------------------------ 66 | 67 | Here's what a very simple Complexity site looks like: 68 | 69 | `project/templates/base.html`: 70 | 71 | .. code-block:: html+jinja 72 | 73 | 74 | 75 | 76 | {% block title %}{% endblock %} - Built with Complexity 77 | 78 | 79 | 80 | 81 | 82 |
83 | 92 | 93 | {% block content %} 94 | {% endblock %} 95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | `project/templates/index.html`: 103 | 104 | .. code-block:: html+jinja 105 | 106 | {% extends "base.html" %} 107 | 108 | {% block title %}Home{% endblock %} 109 | 110 | {% block content %} 111 |
112 |
113 |

Home

114 |

This is the Home page of your website.

115 |
116 |
117 | {% endblock %} 118 | 119 | `project/templates/about.html`: 120 | 121 | .. code-block:: html+jinja 122 | 123 | {% extends "base.html" %} 124 | 125 | {% block title %}About{% endblock %} 126 | 127 | {% block content %} 128 |
129 |
130 |

About

131 |

This is the About page of your website.

132 |
133 |
134 | {% endblock %} 135 | 136 | Notice how `index.html` and `about.html` both share a common parent template, 137 | `base.html`. 138 | 139 | Part 3: Generate the Site and Serve It Locally 140 | ---------------------------------------------- 141 | 142 | Run the `complexity` command, passing it input and output directories:: 143 | 144 | $ complexity project/ 145 | 146 | This results in the following: 147 | 148 | * A `www/` directory gets created, containing your generated static HTML site. 149 | 150 | * Templates are rendered and output to files smartly: 151 | 152 | * Any templates starting with "base" are assumed to be parent templates 153 | and not rendered on their own (e.g. `base.html`, `base_section.html`) 154 | * Templates named `index.html` are output to the same corresponding 155 | locations in `www/`. 156 | * Other templates are expanded in order to hide the ".html" extension. 157 | For example, `about.html` is expanded to `about/index.html`. 158 | 159 | * A lightweight server starts up locally, serving your site so that you can see 160 | how it looks and check that everything works. 161 | 162 | Open a web browser to http://127.0.0.1:9090. You should see your newly generated site! 163 | 164 | In an upcoming release, the following will also occur during Complexity's 165 | generation process: 166 | 167 | * CSS will be minified and concatenated. 168 | * SCSS and/or LESS will compiled to CSS, then minified and concatenated. 169 | * JS will be minified, concatenated, and obfuscated. 170 | 171 | Development is happening at a rapid pace, so stay tuned. To keep updated, watch 172 | and star https://github.com/audreyr/complexity on GitHub. 173 | 174 | Part 4: Upload the Site to Amazon S3 175 | ------------------------------------- 176 | 177 | For site deployment we'll use the "alotofeffort" tool. It is designed for 178 | use with Complexity, but it works with non-Complexity sites just as well. 179 | 180 | Install it:: 181 | 182 | $ pip install alotofeffort 183 | 184 | Save the following in `~/.boto`:: 185 | 186 | [Credentials] 187 | aws_access_key_id = ... 188 | aws_secret_access_key = ... 189 | 190 | Replace `...` with your AWS access credentials, of course. 191 | 192 | Then deploy the `www/` directory to any S3 bucket that you own:: 193 | 194 | $ alotofeffort www/ your-s3-bucketname 195 | 196 | Your site is now live! Go to the URL that `alotofeffort` prints out after 197 | it finishes uploading. 198 | 199 | Point your domain name at that URL, and you'll be done! 200 | -------------------------------------------------------------------------------- /docs/upgrading.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | Upgrading 3 | ========= 4 | 5 | .. note:: Mac users may need to use "sudo", but try it without the "sudo" 6 | first. (Or was that "sussudio"? "Su-su-sussudiooo!!" But use `virtualenv`_ 7 | if you don't want to sudo.) 8 | 9 | .. _`virtualenv`: http://www.virtualenv.org/en/latest/ 10 | 11 | How to Upgrade From an Earlier Version 12 | -------------------------------------- 13 | 14 | To upgrade Complexity:: 15 | 16 | $ pip install -U complexity 17 | 18 | Or if using easy_install:: 19 | 20 | $ easy_install --upgrade complexity 21 | 22 | Things to Know Before Upgrading 23 | ------------------------------- 24 | 25 | Some releases may require you to make changes on your end; if so, instructions 26 | will be described in :doc:`history`. 27 | 28 | Of course, if you run into any problems and need help, file an issue with 29 | details so someone can help. 30 | -------------------------------------------------------------------------------- /requirements/base_test.txt: -------------------------------------------------------------------------------- 1 | coverage 2 | tox 3 | -------------------------------------------------------------------------------- /requirements/test_26.txt: -------------------------------------------------------------------------------- 1 | # Requirements for testing Complexity on Python 2.6. 2 | 3 | -r base_test.txt 4 | unittest2 5 | -------------------------------------------------------------------------------- /requirements/test_27.txt: -------------------------------------------------------------------------------- 1 | # Requirements for testing Complexity on Python 2.7. 2 | 3 | -r base_test.txt 4 | -------------------------------------------------------------------------------- /requirements/test_33.txt: -------------------------------------------------------------------------------- 1 | # Requirements for testing Complexity on Python 3.3. 2 | 3 | -r base_test.txt 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | 6 | try: 7 | from setuptools import setup 8 | except ImportError: 9 | from distutils.core import setup 10 | 11 | if sys.argv[-1] == 'publish': 12 | os.system('python setup.py sdist upload') 13 | sys.exit() 14 | 15 | with open('README.rst') as f: 16 | readme = f.read() 17 | 18 | with open('HISTORY.rst') as f: 19 | history = f.read() 20 | history = history.replace(".. :changelog:", "") 21 | 22 | requirements = [ 23 | 'jinja2>=2.4', 24 | 'binaryornot>=0.1.1', 25 | 'PyYAML>=3.10' 26 | ] 27 | test_requirements = [] 28 | 29 | if sys.version_info[:2] < (2, 7): 30 | requirements.append('argparse') 31 | test_requirements.append('unittest2') 32 | 33 | setup( 34 | name='complexity', 35 | version='0.9.1', 36 | description='A refreshingly simple static site generator, for those who like to work in HTML.', 37 | long_description=readme + '\n\n' + history, 38 | author='Audrey Roy', 39 | author_email='audreyr@gmail.com', 40 | url='https://github.com/audreyr/complexity', 41 | packages=[ 42 | 'complexity', 43 | ], 44 | package_dir={'complexity': 'complexity'}, 45 | entry_points={ 46 | 'console_scripts': [ 47 | 'complexity = complexity.main:main', 48 | ] 49 | }, 50 | include_package_data=True, 51 | install_requires=requirements, 52 | license="BSD", 53 | zip_safe=False, 54 | keywords='complexity,static site generator,HTML,Jinja2,templates,S3', 55 | classifiers=[ 56 | 'Development Status :: 2 - Pre-Alpha', 57 | "Environment :: Console", 58 | 'Intended Audience :: Developers', 59 | 'License :: OSI Approved :: BSD License', 60 | 'Natural Language :: English', 61 | 'Programming Language :: Python :: 2.6', 62 | 'Programming Language :: Python :: 2.7', 63 | 'Programming Language :: Python :: 3.3', 64 | 'Topic :: Internet :: WWW/HTTP :: Site Management', 65 | ], 66 | test_suite='tests', 67 | tests_require=test_requirements 68 | ) 69 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/__init__.py -------------------------------------------------------------------------------- /tests/conf_proj/complexity.yml: -------------------------------------------------------------------------------- 1 | # Config file for a Complexity project 2 | 3 | # Directories are relative to current (project) dir 4 | templates_dir: "templates" 5 | output_dir: "../www" 6 | 7 | # List of templates that should not be expanded to pretty-format URLs 8 | unexpanded_templates: 9 | - "404.html" 10 | - "500.html" 11 | -------------------------------------------------------------------------------- /tests/conf_proj/templates/404.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj/templates/404.html -------------------------------------------------------------------------------- /tests/conf_proj/templates/500.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj/templates/500.html -------------------------------------------------------------------------------- /tests/conf_proj/templates/about.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj/templates/about.html -------------------------------------------------------------------------------- /tests/conf_proj/templates/base.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj/templates/base.html -------------------------------------------------------------------------------- /tests/conf_proj/templates/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj/templates/index.html -------------------------------------------------------------------------------- /tests/conf_proj2/assetz/junk.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj2/assetz/junk.txt -------------------------------------------------------------------------------- /tests/conf_proj2/complexity.yml: -------------------------------------------------------------------------------- 1 | # Config file for a Complexity project 2 | 3 | # Directories are relative to current (project) dir 4 | templates_dir: "templatez" 5 | assets_dir: "assetz" 6 | context_dir: "contextz" 7 | output_dir: "wwwz" -------------------------------------------------------------------------------- /tests/conf_proj2/contextz/junk.json: -------------------------------------------------------------------------------- 1 | { 2 | "hello": "world" 3 | } 4 | -------------------------------------------------------------------------------- /tests/conf_proj2/templatez/404.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj2/templatez/404.html -------------------------------------------------------------------------------- /tests/conf_proj2/templatez/about.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj2/templatez/about.html -------------------------------------------------------------------------------- /tests/conf_proj2/templatez/base.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj2/templatez/base.html -------------------------------------------------------------------------------- /tests/conf_proj2/templatez/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/conf_proj2/templatez/index.html -------------------------------------------------------------------------------- /tests/files/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block content %}{% endblock %} 5 | 6 | -------------------------------------------------------------------------------- /tests/files/unicode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

This is the unicode test page.

4 |

Polish: Ą Ł Ż

5 |

Chinese: 倀 倁 倂 倃 倄 倅 倆 倇 倈

6 |

Musical Notes: ♬ ♫ ♯

7 |

Croatian: š š

8 | -------------------------------------------------------------------------------- /tests/files/unicode.json: -------------------------------------------------------------------------------- 1 | { 2 | "Polish": "Ą Ł Ż", 3 | "Chinese": "倀 倁 倂 倃 倄 倅 倆 倇 倈", 4 | "Musical Notes": "♬ ♫ ♯" 5 | } 6 | -------------------------------------------------------------------------------- /tests/files/unicode.txt: -------------------------------------------------------------------------------- 1 | Polish: Ą Ł Ż 2 | Chinese: 倀 倁 倂 倃 倄 倅 倆 倇 倈 3 | Musical Notes: ♬ ♫ ♯ -------------------------------------------------------------------------------- /tests/files/unicode2.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |

This is the unicode test page.

5 |

Polish: Ą Ł Ż

6 |

Chinese: 倀 倁 倂 倃 倄 倅 倆 倇 倈

7 |

Musical Notes: ♬ ♫ ♯

8 |

Paški sir

9 |

Croatian: š š

10 | {% endblock %} -------------------------------------------------------------------------------- /tests/project/assets/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.2 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /tests/project/assets/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/audreyfeldroy/complexity/710dc771b11c65fb65820cfb2a519dd749c65419/tests/project/assets/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /tests/project/assets/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap.js by @fat & @mdo 3 | * Copyright 2012 Twitter, Inc. 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(".dropdown-backdrop").remove(),e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||("ontouchstart"in document.documentElement&&e('