Repository: iancmcc/ouimeaux Branch: develop Commit: bc3c299dd275 Files: 86 Total size: 521.5 KB Directory structure: gitextract_v9i5cwgu/ ├── .gitignore ├── .travis.yml ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── client.py ├── docs/ │ ├── Makefile │ ├── api.rst │ ├── authors.rst │ ├── conf.py │ ├── configuration.rst │ ├── contributing.rst │ ├── history.rst │ ├── index.rst │ ├── installation.rst │ ├── make.bat │ ├── modules.rst │ ├── ouimeaux.device.api.rst │ ├── ouimeaux.device.api.xsd.rst │ ├── ouimeaux.device.rst │ ├── ouimeaux.examples.rst │ ├── ouimeaux.pysignals.rst │ ├── ouimeaux.rst │ ├── ouimeaux.server.rst │ ├── ouimeaux.xsd.rst │ ├── readme.rst │ ├── server.rst │ └── wemo.rst ├── ouimeaux/ │ ├── __init__.py │ ├── cli.py │ ├── config.py │ ├── device/ │ │ ├── __init__.py │ │ ├── api/ │ │ │ ├── __init__.py │ │ │ ├── service.py │ │ │ └── xsd/ │ │ │ ├── __init__.py │ │ │ ├── device.py │ │ │ ├── device.xsd │ │ │ ├── service.py │ │ │ └── service.xsd │ │ ├── bridge.py │ │ ├── insight.py │ │ ├── lightswitch.py │ │ ├── maker.py │ │ ├── motion.py │ │ └── switch.py │ ├── discovery.py │ ├── environment.py │ ├── examples/ │ │ ├── Randomize.py │ │ ├── __init__.py │ │ └── watch.py │ ├── pysignals/ │ │ ├── LICENSE.txt │ │ ├── __init__.py │ │ ├── dispatcher.py │ │ ├── inspect.py │ │ ├── license.python.txt │ │ └── weakref_backports.py │ ├── server/ │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── static/ │ │ │ ├── css/ │ │ │ │ ├── bootstrap-responsive.css │ │ │ │ ├── bootstrap-theme.css │ │ │ │ ├── bootstrap.css │ │ │ │ └── main.css │ │ │ ├── js/ │ │ │ │ ├── app.js │ │ │ │ ├── bootstrap.js │ │ │ │ ├── controllers.js │ │ │ │ ├── directives.js │ │ │ │ ├── filters.js │ │ │ │ ├── services.js │ │ │ │ └── socket.js │ │ │ └── partials/ │ │ │ ├── about.html │ │ │ └── landing.html │ │ └── templates/ │ │ ├── 404.html │ │ └── index.html │ ├── signals.py │ ├── subscribe.py │ └── utils.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests/ │ ├── __init__.py │ └── test_ouimeaux.py └── tox.ini ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # Complexity output/*.html output/*/index.html # Sphinx docs/_build .DS_Store *~ *.xcodeproj ================================================ FILE: .travis.yml ================================================ # Config file for automatic testing at travis-ci.org language: python python: - "2.7" - "3.5" - "3.6" # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors install: pip install -r requirements.txt # command to run tests, e.g. python setup.py test script: python setup.py test ================================================ FILE: AUTHORS.rst ================================================ ======= Credits ======= Development Lead ---------------- * Ian McCracken Contributors ------------ * `Aron Parsons `_ * `Brian Peiris `_ * `nschrenk `_ * `Gabriel M. Schuyler `_ * `Markus Stenberg `_ * `aktur `_ * `Justin Eldridge `_ * `logjames `_ * `jgstew `_ * `Bob Gardner `_ * `FRITZ|FRITZ `_ ================================================ FILE: CONTRIBUTING.rst ================================================ ============ Contributing ============ Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. You can contribute in many ways: Types of Contributions ---------------------- Report Bugs ~~~~~~~~~~~ Report bugs at https://github.com/iancmcc/ouimeaux/issues. If you are reporting a bug, please include: * Your operating system name and version. * Any details about your local setup that might be helpful in troubleshooting. * Detailed steps to reproduce the bug. Fix Bugs ~~~~~~~~ Look through the GitHub issues for bugs. Anything tagged with "bug" is open to whoever wants to implement it. Implement Features ~~~~~~~~~~~~~~~~~~ Look through the GitHub issues for features. Anything tagged with "feature" is open to whoever wants to implement it. Write Documentation ~~~~~~~~~~~~~~~~~~~ ouimeaux could always use more documentation, whether as part of the official ouimeaux docs, in docstrings, or even on the web in blog posts, articles, and such. Submit Feedback ~~~~~~~~~~~~~~~ The best way to send feedback is to file an issue at https://github.com/iancmcc/ouimeaux/issues. If you are proposing a feature: * Explain in detail how it would work. * Keep the scope as narrow as possible, to make it easier to implement. * Remember that this is a volunteer-driven project, and that contributions are welcome :) Get Started! ------------ Ready to contribute? Here's how to set up `ouimeaux` for local development. 1. Fork the `ouimeaux` repo on GitHub. 2. Clone your fork locally:: $ git clone git@github.com:your_name_here/ouimeaux.git 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: $ mkvirtualenv ouimeaux $ cd ouimeaux/ $ python setup.py develop 4. Create a branch for local development:: $ git checkout -b name-of-your-bugfix-or-feature Now you can make your changes locally. 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: $ flake8 ouimeaux tests $ python setup.py test $ tox To get flake8 and tox, just pip install them into your virtualenv. 6. Commit your changes and push your branch to GitHub:: $ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature 7. Submit a pull request through the GitHub website. Pull Request Guidelines ----------------------- Before you submit a pull request, check that it meets these guidelines: 1. The pull request should include tests. 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.md. 3. The pull request should work for Python 2.6, 2.7, and 3.3, and for PyPy. Check https://travis-ci.org/iancmcc/ouimeaux/pull_requests and make sure that the tests pass for all supported Python versions. Tips ---- To run a subset of tests:: $ python -m unittest tests.test_ouimeaux ================================================ FILE: HISTORY.rst ================================================ .. :changelog: History ------- Release 0.8.0 (July 30, 2016) +++++++++++++++++++++++++++++ - Randomize subscription ports to enable simultaneous ouimeaux scripts (thanks @bennytheshap) - Fix for WeMo LED Light support (thanks @sstangle73) - #32: Removed address cache, broke server out into optional feature - Fix for Maker state reporting (thanks @pavoni) - Filter by SSDP location, fixing case where multiple devices respond from the same IP (thanks @szakharchenko) - Fix Maker event handlers, which were being passed as bridges (thanks @maxlazarov) - Work around gevent-socketio bug by explicitly casting header value as string - Fix for inconsistent Light state (thanks @canduuk) - StateChange signals are now a separate class and do not fire if value is unchanged (thanks @esecules) - Python 3 support (thanks to @drock371) Release 0.7.9 (March 17, 2015) ++++++++++++++++++++++++++++++ - Command line support for WeMo LED Light (thanks @fritz-fritz) - Command line support for WeMo Maker (thanks @logjames) - Support for 2.0.0 firmware (thanks @fritz-fritz) - Bug fixes Release 0.7.3 (August 10, 2014) ++++++++++++++++++++++++++++++++ - Fixed #18: Error when run as root - Fixed #26: Evict devices from cache when unreachable - Fixed #29: GetPower stopped working for Insight devices - Fixed #31: Add blink method on switches, include in REST API - Fixed #33, #37: Handle invalid devices without dying - Fixed #35: Require requests >= 2.3.0 - Fixed #40: Retry requests in the event of failure - Fixed #47: Don't choke on invalid newlines in XML returned by switches (thanks to @fingon) Release 0.7.2 (January 28, 2014) ++++++++++++++++++++++++++++++++ - Fix a bug with using query parameters on /api/device Release 0.7 (January 27, 2014) ++++++++++++++++++++++++++++++ - Added REST API - Added Web app Release 0.6 (January 25, 2014) ++++++++++++++++++++++++++++++++ - Added signals framework - Fixed #16, #19, #22: Defensively resubscribe to events when device responds with an error - Fixed #15: Signals framework includes relevant device when sending signal - Refactored structure, added Sphinx docs Release 0.5.3 (January 25, 2014) ++++++++++++++++++++++++++++++++ - Fixed #20: Allow timeout in environment.wait() - Fixed #21: Add Insight support Release 0.5.2 (November 23, 2013) +++++++++++++++++++++++++++++++++ - Fixed #14: Indicate Connection:close header to avoid logging when WeMo sends invalid HTTP response. Release 0.5.1 (November 9, 2013) ++++++++++++++++++++++++++++++++ - Fixed #10: Updated subscriber listener to use more reliable method of retrieving non-loopback IP address; updated docs to fix typo in listener registration example (thanks to @benhoyle, @francxk) - Fixed #11: Remove instancemethod objects before attempting to pickle devices in the cache (thanks @piperde, @JonPenner, @tomtomau, @masilu77) Release 0.5 (October 14, 2013) +++++++++++++++++++++++++++++++ - Added fuzzy matching of device name when searching/toggling from command line - Added ``status`` mode to print status for all devices - Added ``switch status`` mode to print status for specific device - Added flags for all command-line options - Fixed #9: Removed unused fcntl import that precluded Windows usage (thanks to @deepseven) Release 0.4.3 (August 31, 2013) +++++++++++++++++++++++++++++++ - Used new method of obtaining local IP for discovery that is less likely to return loopback - Exit with failure and instructions for solution if loopback IP is used - Updated installation docs to include python-dev and pip instructions (patch by @fnaard) - Fixed README inclusion bug that occasionally broke installation via pip. - Added ``--debug`` option to enable debug logging to stdout Release 0.4 (August 17, 2013) +++++++++++++++++++++++++++++ - Fixed #7: Added support for light switch devices (patch by nschrenk). - Fixed #6: Added "wemo clear" command to clear the device cache. Release 0.3 (May 25, 2013) ++++++++++++++++++++++++++ - Fixed #4: Added ability to specify ip:port for discovery server binding. Removed documentation describing need to disable SSDP service on Windows. - Fixed #5: Added device cache for faster results. - Added configuration file. - Added ability to configure aliases for devices to avoid quoting strings on the command line. - Added 'toggle' command to command line switch control. Release 0.2 (April 21, 2013) ++++++++++++++++++++++++++++++ - Fixed #1: Added ability to subscribe to motion and switch state change events. - Added Windows installation details to README (patch by @brianpeiris) - Cleaned up UDP server lifecycle so rediscovery doesn't try to start it back up. Release 0.1 (February 2, 2013) ++++++++++++++++++++++++++++++ - Initial release. * First release on PyPI. ================================================ FILE: LICENSE ================================================ Copyright (c) 2014, Ian McCracken All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * Neither the name of ouimeaux nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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. ================================================ FILE: MANIFEST.in ================================================ include AUTHORS.rst include CONTRIBUTING.rst include HISTORY.rst include LICENSE include README.md include requirements.txt graft ouimeaux ================================================ FILE: Makefile ================================================ .PHONY: clean-pyc clean-build docs help: @echo "clean-build - remove build artifacts" @echo "clean-pyc - remove Python file artifacts" @echo "lint - check style with flake8" @echo "test - run tests quickly with the default Python" @echo "testall - run tests on every Python version with tox" @echo "coverage - check code coverage quickly with the default Python" @echo "docs - generate Sphinx HTML documentation, including API docs" @echo "release - package and upload a release" @echo "sdist - package" clean: clean-build clean-pyc clean-build: rm -fr build/ rm -fr dist/ rm -fr *.egg-info clean-pyc: find . -name '*.pyc' -exec rm -f {} + find . -name '*.pyo' -exec rm -f {} + find . -name '*~' -exec rm -f {} + lint: flake8 ouimeaux tests test: python setup.py test test-all: tox coverage: coverage run --source ouimeaux setup.py test coverage report -m coverage html open htmlcov/index.html docs: rm -f docs/ouimeaux.rst rm -f docs/modules.rst sphinx-apidoc -o docs/ ouimeaux $(MAKE) -C docs clean $(MAKE) -C docs html open docs/_build/html/index.html release: clean python setup.py sdist upload sdist: clean python setup.py sdist ls -l dist ================================================ FILE: README.md ================================================ # ouimeaux ⚠️ ⚠️ ⚠️ The ouimeaux project is no longer actively maintained. Please contact @iancmcc if you would like to be added to a list of maintained forks. ⚠️ ⚠️ ⚠️ Open source control for Belkin WeMo devices * Free software: BSD license * Documentation: http://ouimeaux.rtfd.org. ## Features * Supports WeMo Switch, Light Switch, Insight Switch and Motion * Command-line tool to discover and control devices in your environment * REST API to obtain information and perform actions on devices * Simple responsive Web app provides device control on mobile * Python API to interact with device at a low level ## About this fork The original repository can be found here: https://github.com/iancmcc/ouimeaux It doesn't appear to be maintained and it doesn't work with modern Python packages. It has been forked here so that I can include my modifications to `requirements.txt` as well as document how to use it. ## Installation ``` $ sudo pip install virtualenv $ mkdir ouimeaux-env $ virtualenv ouimeaux-env $ source ouimeaux-env/bin/activate $ cd ouimeaux-env $ pip install git+https://github.com/iancmcc/ouimeaux.git ``` At this point you should be able to use `wemo` and `wemo server` so long as you've activated your environment with `source ouimeaux-env/bin/activate`. **Note:** Ensure that the `pip` and `virtualenv` command you use belongs to a Python 2 installation. On some systems, there are multiple versions of Python installed. See below for an example from my Fedora system. ``` $ /bin/ls -1 "$(dirname $(which python))/virtualenv"{,-2} "$(dirname $(which python))/p"{ython,ip}[23] /usr/bin/pip2 /usr/bin/pip3 /usr/bin/python2 /usr/bin/python3 /usr/bin/virtualenv /usr/bin/virtualenv-2 $ pip --version pip 9.0.1 from /usr/lib/python3.5/site-packages (python 3.5) $ pip2 --version pip 9.0.1 from /usr/lib/python2.7/site-packages (python 2.7) ``` ## HTTP client version The `client.py` script provided by [BlackLight](https://github.com/BlackLight) allows the user to send simple commands to a device without the cumbersome (and [currently broken](https://github.com/iancmcc/ouimeaux/issues/193)) `Discoverer` object. Requirements: install requests: ``` pip install requests ``` You can run client.py in two modes: ### Scan mode Will scan for available WeMo Switch devices on the network. Example: ``` python client.py --scan --subnet 192.168.1.0/24 ``` ### Action mode Will run an action on a specified device. Example: ``` python client.py --device 192.168.1.19 --on ``` With no `--on|--off|--toggle` action specified the script will return a JSON with the device info: ```json { "device": "192.168.1.19", "name": "Lightbulbs", "state": false } ``` Run `python client.py --help` for more info about the available options. ## Troubleshooting #### Using a VPN The `wemo` command won't be able to communicate with your devices if you're connected to a VPN. It may be redirecting UDP traffic somewhere else. Disconnect from the VPN and the tool should work. Open an issue and I'll try to help. #### Docker You need to be on the same network as your device. To do this ensure you are using `host` network, see [https://docs.docker.com/network/host/](https://docs.docker.com/network/host/) for more info. ================================================ FILE: client.py ================================================ #!/usr/bin/env python # :author: Fabio "BlackLight" Manganiello # # Requirements: # - `requests` package (`pip install requests`) # - [Advised] static IP allocation for your WeMo devices import argparse import enum import ipaddress import json import multiprocessing import re import requests import socket import sys import textwrap from typing import Type from xml.dom.minidom import parseString default_port = 49153 class SwitchAction(enum.Enum): GET_STATE = 'GetBinaryState' SET_STATE = 'SetBinaryState' GET_NAME = 'GetFriendlyName' class Worker(multiprocessing.Process): _END_OF_STREAM = None def __init__(self, request_queue: multiprocessing.Queue, response_queue=multiprocessing.Queue): super().__init__() self.request_queue = request_queue self.response_queue = response_queue def send_stop(self): self.request_queue.put(self._END_OF_STREAM) def process_response(self, resp): self.response_queue.put(resp) class Workers: def __init__(self, n_workers: int, worker_type: Type[Worker], *args, **kwargs): self.request_queue = multiprocessing.Queue() self.response_queue = multiprocessing.Queue() self._workers = [worker_type(self.request_queue, self.response_queue, *args, **kwargs) for _ in range(n_workers)] def start(self): for wrk in self._workers: wrk.start() def put(self, msg): self.request_queue.put(msg) def wait(self) -> list: while self._workers: for i, wrk in enumerate(self._workers): if not self._workers[i].is_alive(): self._workers.pop(i) break ret = [] while not self.response_queue.empty(): ret.append(self.response_queue.get()) return ret def send_stop(self): for wrk in self._workers: wrk.send_stop() class ScanWorker(Worker): def __init__(self, request_queue: multiprocessing.Queue, response_queue: multiprocessing.Queue, scan_timeout: float, connect_timeout: float, port: int = default_port): super().__init__(request_queue, response_queue) self.scan_timeout = scan_timeout self.connect_timeout = connect_timeout self.port = port def run(self): while True: addr = self.request_queue.get() if addr == self._END_OF_STREAM: break try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(self.scan_timeout) sock.connect((addr, self.port)) sock.close() dev = get_device(addr, timeout=self.connect_timeout) print('Found WeMo device: {}'.format(dev)) self.process_response(dev) except OSError: pass def _exec(device: str, action: SwitchAction, value=None, port: int = default_port, timeout: float = None): state_name = action.value[3:] response = requests.post( 'http://{}:{}/upnp/control/basicevent1'.format(device, port), headers={ 'User-Agent': '', 'Accept': '', 'Content-Type': 'text/xml; charset="utf-8"', 'SOAPACTION': '\"urn:Belkin:service:basicevent:1#{}\"'.format(action.value), }, data=re.sub('\s+', ' ', textwrap.dedent( ''' <{state}>{value} '''.format(action=action.value, state=state_name, value=value if value is not None else '')))) dom = parseString(response.text) return dom.getElementsByTagName(state_name).item(0).firstChild.data def on(device: str, *args, **kwargs): return _exec(device, SwitchAction.SET_STATE, 1) def off(device: str, *args, **kwargs): return _exec(device, SwitchAction.SET_STATE, 0, *args, **kwargs) def get_state(device: str, *args, **kwargs): return bool(int(_exec(device, SwitchAction.GET_STATE, *args, **kwargs))) def get_name(device: str, *args, **kwargs): return _exec(device, SwitchAction.GET_NAME, *args, **kwargs) def get_device(device: str, *args, **kwargs): return { 'device': device, 'name': get_name(device, *args, **kwargs), 'state': get_state(device, *args, **kwargs), } def main(): global default_port parser = argparse.ArgumentParser() parser.add_argument('--scan', '-s', dest='scan', required=False, default=False, action='store_true', help="Run Switchbot in scan mode - scan devices to control") parser.add_argument('--subnet', '-n', dest='subnet', required=False, default=None, help="Set the network subnet for --scan mode (e.g. 192.168.1.0/24)") parser.add_argument('--port', '-p', dest='port', required=False, type=int, default=default_port, help="TCP port used by the WeMo device(s)") parser.add_argument('--scan-timeout', dest='scan_timeout', type=float, required=False, default=2.0, help="Device scan timeout (default: 2 seconds)") parser.add_argument('--connect-timeout', dest='connect_timeout', type=float, required=False, default=30.0, help="Device connection timeout (default: 30 seconds)") parser.add_argument('--device', '-d', dest='device', required=False, default=None, help="IP address of a device to control") parser.add_argument('--on', dest='on', required=False, default=False, action='store_true', help="Turn the device on") parser.add_argument('--off', dest='off', required=False, default=False, action='store_true', help="Turn the device off") parser.add_argument('--toggle', dest='toggle', required=False, default=False, action='store_true', help="Toggle the device") opts, args = parser.parse_known_args(sys.argv[1:]) if (opts.scan and opts.device) or not (opts.scan or opts.device): raise AttributeError('Please specify either --scan or --device') if opts.scan: if not opts.subnet: raise AttributeError('No --subnet specified for --scan mode') workers = Workers(10, ScanWorker, scan_timeout=opts.scan_timeout, connect_timeout=opts.connect_timeout, port=opts.port) workers.start() for addr in ipaddress.IPv4Network(opts.subnet): workers.put(addr.exploded) workers.send_stop() devices = workers.wait() print('\nFound {} WeMo devices'.format(len(devices))) print(json.dumps(devices, indent=2)) return _on = opts.on _off = opts.off if opts.toggle: if get_state(opts.device): _off = True else: _on = True if _on: on(opts.device, timeout=opts.connect_timeout) elif _off: off(opts.device, timeout=opts.connect_timeout) else: print(json.dumps( get_device(opts.device, timeout=opts.connect_timeout), indent=2)) if __name__ == '__main__': main() # vim:sw=4:ts=4:et: ================================================ FILE: docs/Makefile ================================================ # Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/complexity.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/complexity.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/complexity" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/complexity" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." ================================================ FILE: docs/api.rst ================================================ =========== Python API =========== Environment ----------- The main interface is presented by an ``Environment``, which optionally accepts functions called when a Switch or Motion device is identified:: >>> from ouimeaux.environment import Environment >>> >>> def on_switch(switch): ... print "Switch found!", switch.name ... >>> def on_motion(motion): ... print "Motion found!", motion.name ... >>> env = Environment(on_switch, on_motion) Start up the server to listen for responses to the discovery broadcast:: >>> env.start() Discovery of all WeMo devices in an environment is then straightforward; simply pass the length of time (in seconds) you want discovery to run:: >>> env.discover(seconds=3) Switch found! Living Room During that time, the ``Environment`` will continually broadcast search requests and parse responses. At any point, you can see the names of discovered devices:: >>> env.list_switches() ['Living Room', 'TV Room', 'Front Closet'] >>> env.list_motions() ['Front Hallway'] Devices can be retrieved by using ``get_switch`` and ``get_motion`` methods:: >>> switch = env.get_switch('TV Room') >>> switch Devices ------- All devices have an ``explain()`` method, which will print out a list of all available services, as well as the actions and arguments to those actions on each service:: >>> switch.explain() basicevent ---------- SetSmartDevInfo(SmartDevURL) SetServerEnvironment(ServerEnvironmentType, TurnServerEnvironment, ServerEnvironment) GetDeviceId() GetRuleOverrideStatus(RuleOverrideStatus) GetIconURL(URL) SetBinaryState(BinaryState) ... Services and actions are available via simple attribute access. Calling actions returns a dictionary of return values:: >>> switch.basicevent.SetBinaryState(BinaryState=0) {'BinaryState': 0} Events ------ .. warning:: This events framework is deprecated and will be removed prior to the 1.0 release. Please use the signals framework. By default, ouimeaux subscribes to property change events on discovered devices (this can be disabled by passing ``with_subscribers=False`` to the ``Environment`` constructor). You can register callbacks that will be called when switches and motions change state (on/off, or motion detected):: >>> def on_motion(value): ... print "Motion detected!" ... >>> env.get_motion('Front Hallway').register_listener(on_motion) >>> env.wait(timeout=60) Note the use of ``Environment.wait()`` to give control to the event loop for events to be detected. A timeout in seconds may optionally be specified; default is no timeout. Signals ------- A simple signals framework (using pysignals_) is included to replace the rudimentary events in earlier releases. These are found in the `ouimeaux.signals` module. Signal handlers may be registered using the ``receiver`` decorator and must have the signature ``sender, **kwargs``:: @receiver(devicefound) def handler(sender, **kwargs): print "Found device", sender Where ``sender`` is the relevant object (in most cases, the device). Signals may also have handlers registered using ``signal.connect(handler)``:: def handler(sender, **kwargs): pass statechange.connect(sender) Available signals: ``discovered`` Fires when a device responds to the broadcast request. Includes: - ``sender``: The UPnP broadcast component - ``address``: The address of the responding device - ``headers``: The response headers ``devicefound`` Sent when a device is found and registered into the environment. Includes: - ``sender``: The device found ``subscription`` Sent when a device sends an event as the result of a subscription. Includes: - ``sender``: The device that sent the event - ``type``: The type of the event send (e.g., ``BinaryState``) - ``value``: The value associated with the event ``statechange`` Sent when a device indicates it has detected a state change. Includes: - ``sender``: The device that changed state - ``state``: The resulting state (0 or 1) See the pysignals_ documentation for further information. Example: Registering a handler for when a Light Switch switches on or off:: from ouimeaux.signals import statechange, receiver env = Environment(); env.start() env.discover(5) switch = env.get_switch('Porch Light') @receiver(statechange, sender=switch) def switch_toggle(device, **kwargs): print device, kwargs['state'] env.wait() # Pass control to the event loop See the examples_ for a more detailed implementation. .. _pysignals: https://github.com/theojulienne/PySignals Switches -------- Switches have three shortcut methods defined: ``get_state``, ``on`` and ``off``. Switches also have a ``blink`` method, which accepts a number of seconds. This will toggle the device, wait the number of seconds, then toggle it again. Remember to call ``env.wait()`` to give control to the event loop. Motions ------- Motions have one shortcut method defined: ``get_state``. Insight ------- In addition to the normal Switch methods, Insight switches have several metrics exposed:: insight.today_kwh insight.current_power insight.today_on_time insight.on_for insight.today_standby_time Device Cache ------------ By default, device results are cached on the filesystem for quicker initialization. This can be disabled by passing ``with_cache=False`` to the ``Environment`` constructor. On a related note, if you want to use the cache exclusively, you can pass ``with_discovery=False`` to the ``Environment`` constructor to disable M-SEARCH requests. You can clear the device cache either by deleting the file ``~/.wemo/cache`` or by using the ``wemo clear`` command. Examples -------- Detailed examples_ are included in the source demonstrating common use cases. Suggestions (or implementations) for more are always welcome. .. _examples: https://github.com/iancmcc/ouimeaux/tree/develop/ouimeaux/examples ================================================ FILE: docs/authors.rst ================================================ .. include:: ../AUTHORS.rst ================================================ FILE: docs/conf.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- # # complexity documentation build configuration file, created by # sphinx-quickstart on Tue Jul 9 22:26:36 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # Get the project root dir, which is the parent dir of this cwd = os.getcwd() project_root = os.path.dirname(cwd) # Insert the project root dir as the first element in the PYTHONPATH. # This lets us ensure that the source package is imported, and that its # version is used. sys.path.insert(0, project_root) import ouimeaux # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'ouimeaux' copyright = u'2014, Ian McCracken' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = ouimeaux.__version__ # The full version, including alpha/beta/rc tags. release = ouimeaux.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'ouimeauxdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'ouimeaux.tex', u'ouimeaux Documentation', u'Ian McCracken', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'ouimeaux', u'ouimeaux Documentation', [u'Ian McCracken'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'ouimeaux', u'ouimeaux Documentation', u'Ian McCracken', 'ouimeaux', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False ================================================ FILE: docs/configuration.rst ================================================ ============= Configuration ============= A configuration file in YAML format will be created at ``~/.wemo/config.yml``:: # ip:port to bind to when receiving responses from discovery. # The default is first DNS resolution of local host, port 54321 # # bind: 10.1.2.3:9090 # Whether to use a device cache (stored at ~/.wemo/cache) # # cache: false aliases: # Shortcuts to longer device names. Uncommenting the following # line will allow you to execute 'wemo switch lr on' instead of # 'wemo switch "Living Room Lights" on' # # lr: Living Room Lights # Web app bind address # # listen: 0.0.0.0:5000 # Require basic authentication (username:password) for the web app # # auth: admin:password ================================================ FILE: docs/contributing.rst ================================================ .. include:: ../CONTRIBUTING.rst ================================================ FILE: docs/history.rst ================================================ .. include:: ../HISTORY.rst ================================================ FILE: docs/index.rst ================================================ .. complexity documentation master file, created by sphinx-quickstart on Tue Jul 9 22:26:36 2013. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Ouimeaux: Open Source WeMo Control ================================== Contents: .. toctree:: :maxdepth: 2 readme installation wemo server configuration api contributing authors history Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ================================================ FILE: docs/installation.rst ================================================ ============ Installation ============ Basic ----- At the command line:: $ easy_install ouimeaux Or, if you have virtualenvwrapper installed:: $ mkvirtualenv ouimeaux $ pip install ouimeaux If you want to enable ``wemo server`` functionality, specify the ``server`` feature to install the necessary dependencies:: $ pip install ouimeaux[server] Linux ----- ouimeaux requires Python header files to build some dependencies, and is installed normally using pip or easy_install. Debian/Ubuntu:: sudo apt-get install python-setuptools python-dev RHEL/CentOS/Fedora:: sudo yum -y install python-setuptools python-devel If you wish to build from a local copy of the source, you can of course always execute:: python setup.py install Windows ------- ouimeaux requires gevent version 1.0rc2 or higher. If you don't have the ability to compile gevent and greenlet (a sub-dependency) locally, you can find and download the binary installers for these packages here: - gevent: https://github.com/SiteSupport/gevent/downloads - greenlet: https://pypi.python.org/pypi/greenlet ================================================ FILE: docs/make.bat ================================================ @ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\complexity.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\complexity.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end ================================================ FILE: docs/modules.rst ================================================ ouimeaux ======== .. toctree:: :maxdepth: 4 ouimeaux ================================================ FILE: docs/ouimeaux.device.api.rst ================================================ ouimeaux.device.api package =========================== Subpackages ----------- .. toctree:: ouimeaux.device.api.xsd Submodules ---------- ouimeaux.device.api.service module ---------------------------------- .. automodule:: ouimeaux.device.api.service :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux.device.api :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/ouimeaux.device.api.xsd.rst ================================================ ouimeaux.device.api.xsd package =============================== Submodules ---------- ouimeaux.device.api.xsd.device module ------------------------------------- .. automodule:: ouimeaux.device.api.xsd.device :members: :undoc-members: :show-inheritance: ouimeaux.device.api.xsd.service module -------------------------------------- .. automodule:: ouimeaux.device.api.xsd.service :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux.device.api.xsd :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/ouimeaux.device.rst ================================================ ouimeaux.device package ======================= Subpackages ----------- .. toctree:: ouimeaux.device.api Submodules ---------- ouimeaux.device.insight module ------------------------------ .. automodule:: ouimeaux.device.insight :members: :undoc-members: :show-inheritance: ouimeaux.device.lightswitch module ---------------------------------- .. automodule:: ouimeaux.device.lightswitch :members: :undoc-members: :show-inheritance: ouimeaux.device.motion module ----------------------------- .. automodule:: ouimeaux.device.motion :members: :undoc-members: :show-inheritance: ouimeaux.device.switch module ----------------------------- .. automodule:: ouimeaux.device.switch :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux.device :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/ouimeaux.examples.rst ================================================ ouimeaux.examples package ========================= Submodules ---------- ouimeaux.examples.watch module ------------------------------ .. automodule:: ouimeaux.examples.watch :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux.examples :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/ouimeaux.pysignals.rst ================================================ ouimeaux.pysignals package ========================== Submodules ---------- ouimeaux.pysignals.dispatcher module ------------------------------------ .. automodule:: ouimeaux.pysignals.dispatcher :members: :undoc-members: :show-inheritance: ouimeaux.pysignals.inspect module --------------------------------- .. automodule:: ouimeaux.pysignals.inspect :members: :undoc-members: :show-inheritance: ouimeaux.pysignals.weakref_backports module ------------------------------------------- .. automodule:: ouimeaux.pysignals.weakref_backports :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux.pysignals :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/ouimeaux.rst ================================================ ouimeaux package ================ Subpackages ----------- .. toctree:: ouimeaux.device ouimeaux.examples ouimeaux.pysignals ouimeaux.server Submodules ---------- ouimeaux.cli module ------------------- .. automodule:: ouimeaux.cli :members: :undoc-members: :show-inheritance: ouimeaux.config module ---------------------- .. automodule:: ouimeaux.config :members: :undoc-members: :show-inheritance: ouimeaux.discovery module ------------------------- .. automodule:: ouimeaux.discovery :members: :undoc-members: :show-inheritance: ouimeaux.environment module --------------------------- .. automodule:: ouimeaux.environment :members: :undoc-members: :show-inheritance: ouimeaux.signals module ----------------------- .. automodule:: ouimeaux.signals :members: :undoc-members: :show-inheritance: ouimeaux.subscribe module ------------------------- .. automodule:: ouimeaux.subscribe :members: :undoc-members: :show-inheritance: ouimeaux.utils module --------------------- .. automodule:: ouimeaux.utils :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/ouimeaux.server.rst ================================================ ouimeaux.server package ======================= Submodules ---------- ouimeaux.server.settings module ------------------------------- .. automodule:: ouimeaux.server.settings :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux.server :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/ouimeaux.xsd.rst ================================================ ouimeaux.xsd package ==================== Submodules ---------- ouimeaux.xsd.device module -------------------------- .. automodule:: ouimeaux.xsd.device :members: :undoc-members: :show-inheritance: ouimeaux.xsd.service module --------------------------- .. automodule:: ouimeaux.xsd.service :members: :undoc-members: :show-inheritance: Module contents --------------- .. automodule:: ouimeaux.xsd :members: :undoc-members: :show-inheritance: ================================================ FILE: docs/readme.rst ================================================ .. include:: ../README.md ================================================ FILE: docs/server.rst ================================================ ======= Server ======= ``wemo server`` starts a process serving up both a Web app providing basic device control and a REST API allowing integration with any number of services. The necessary dependencies to run the server are not installed unless the ``server`` feature is specified at installation:: $ pip install ouimeaux[server] Configuration ------------- The IP and port to which the server will bind are specified by the ``listen`` parameter in the configuration file. Default: ``0.0.0.0:5000``. Optionally, basic authentication can be enabled for the web server by setting the ``auth`` parameter in the configuration file. Web App -------- The Web app very simply presents buttons allowing control of devices and indicating current state. Motions appear as disabled buttons but will turn green when activated. .. image:: webapp.png REST API --------- A vaguely RESTful API is provided to control devices. Arguments, where specified, may be passed either as query arguments or as JSON:: curl -X POST http://localhost:5000/api/environment -d '{"seconds":10}' is as valid as:: curl -X POST http://localhost:5000/api/environment?seconds=10 .. table:: ===================== ========================================= Resource Description ===================== ========================================= GET /api/environment Returns a JSON description of all devices in the environment POST /api/environment Initiates a discovery of the environment. Optional ``seconds`` argument (default: 5) determines length of discovery. GET /api/device/NAME Returns a JSON description of the device named NAME. NAME will be fuzzy-matched against device names, as on the command line (e.g., "closet" will match "Hall Closet"). POST /api/device/NAME Toggle switch state, specified by optional ``state`` argument (default: "toggle"). Valid values are "on", "off" or "toggle". ===================== ========================================= ================================================ FILE: docs/wemo.rst ================================================ ================ ``wemo`` Command ================ The ``wemo`` script will discover devices in your environment and turn switches on and off. To list devices:: $ wemo list Default is to search for 5 seconds; you can pass ``--timeout`` to change that. You can also print the status of every device found in your environment (the ``-v`` option is available to print on/off instead of 0/1):: $ wemo status To turn a switch on and off, you first have to know the name. Then:: $ wemo switch "TV Room" on $ wemo switch "TV Room" off You can also toggle the device:: $ wemo switch "TV Room" toggle Or check its current status (the ``-v`` option will print the word on/off instead of 0/1):: $ wemo -v switch "TV Room" status on WeMo LED Bulbs are supported on the command line as well. Control them like switches with ``wemo light``:: $ wemo light lamp on Or set them to a dimness level from 1 to 255:: $ wemo light lamp on 45 The ``wemo`` script will do fuzzy matching of the name you pass in (this can be disabled with the ``-e`` option):: $ wemo switch tvrm on Aliases configured in the file will be accessible on the command line as well:: aliases: tv: TV Room Lights $ wemo switch tv on Note: If an alias is used on the command line, fuzzy matching will not be attempted. The ``wemo`` script will obey configured settings; they can also be overridden on the command line: ``-b``, ``--bind IP:PORT`` Bind to this host and port when listening for responses ``-d``, ``--debug`` Enable debug logging to stdout ``-e``, ``--exact-match`` Disable fuzzy matching ``-v``, ``--human-readable`` Print statuses as human-readable words ``-t``, ``--timeout`` Time in seconds to allow for discovery ================================================ FILE: ouimeaux/__init__.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = 'Ian McCracken' __email__ = 'ian.mccracken@gmail.com' __version__ = '0.8.2' ================================================ FILE: ouimeaux/cli.py ================================================ import sys import logging import argparse from .discovery import UPnPLoopbackException from .environment import Environment from .config import WemoConfiguration from .utils import matcher reqlog = logging.getLogger("requests.packages.urllib3.connectionpool") reqlog.disabled = True NOOP = lambda *x: None def _state(device, readable=False): state = device.get_state(force_update=True) if readable: return "on" if state else "off" else: return state def scan(args, on_switch=NOOP, on_motion=NOOP, on_bridge=NOOP, on_maker=NOOP): try: env = Environment(on_switch, on_motion, on_bridge, on_maker, with_subscribers=False, bind=args.bind) env.start() env.discover(args.timeout) except KeyboardInterrupt: sys.exit(0) except UPnPLoopbackException: print(""" Loopback interface is being used! You will probably not receive any responses from devices. Use ifconfig to find your IP address, then either pass the --bind argument or edit ~/.wemo/config.yml to specify the IP to which devices should call back during discovery.""".strip()) sys.exit(1) def switch(args): if args.state.lower() in ("on", "1", "true"): state = "on" elif args.state.lower() in ("off", "0", "false"): state = "off" elif args.state.lower() == "toggle": state = "toggle" elif args.state.lower() == "status": state = "status" else: print("""No valid action specified. Usage: wemo switch NAME (on|off|toggle|status)""") sys.exit(1) matches = make_matcher(args.device) def on_switch(switch): if matches(switch.name): if state == "toggle": found_state = switch.get_state(force_update=True) switch.set_state(not found_state) elif state == "status": print(_state(switch, args.human_readable)) else: getattr(switch, state)() if args.device.lower() != 'all': sys.exit(0) scan(args, on_switch) if args.device != 'all': # If we got here, we didn't find anything print("No device found with that name.") sys.exit(1) def light(args): if args.state.lower() in ("on", "1", "true"): state = "on" elif args.state.lower() in ("off", "0", "false"): state = "off" elif args.state.lower() == "toggle": state = "toggle" elif args.state.lower() == "status": state = "status" else: print("""No valid action specified. Usage: wemo light NAME (on|off|toggle|status)""") sys.exit(1) matches = make_matcher(args.name) def on_switch(switch): pass def on_motion(motion): pass def on_bridge(bridge): bridge.bridge_get_lights() bridge.bridge_get_groups() for light in bridge.Lights: if matches(light): if args.state == "toggle": found_state = bridge.light_get_state(bridge.Lights[light]).get('state') bridge.light_set_state(bridge.Lights[light], state=not found_state) elif args.state == "status": print(bridge.light_get_state(bridge.Lights[light])) else: if args.state == "on": if args.dim is not None: if args.dim <= 255 and args.dim >= 0: dim = args.dim state = None else: print("""Invalid dim specified. Dim must be between 0 and 255""") sys.exit(1) else: dim = None state = 1 else: dim = None state = 0 bridge.light_set_state(bridge.Lights[light], state=state, dim=dim) if args.name != 'all': sys.exit(0) for group in bridge.Groups: if matches(group): if args.state == "toggle": found_state = bridge.group_get_state(bridge.Groups[group]).get('state') bridge.group_set_state(bridge.Groups[group], state=not found_state) elif args.state == "status": print(bridge.group_get_state(bridge.Groups[group])) else: if args.dim == None and args.state == "on": dim = bridge.group_get_state(bridge.Groups[group]).get('dim') state = 1 elif args.state == "off": dim = None state = 0 elif args.dim <= 255 and args.dim >= 0: dim = args.dim state = 1 else: print("""Invalid dim specified. Dim must be between 0 and 255""") sys.exit(1) bridge.group_set_state(bridge.Groups[group], state=state, dim=dim) sys.exit(0) scan(args, on_switch, on_motion, on_bridge) if args.name != 'all': # If we got here, we didn't find anything print("No device or group found with that name.") sys.exit(1) def make_matcher(device_name): alias = WemoConfiguration().aliases.get(device_name) if device_name.lower() in ('all', 'any'): matches = lambda x: True elif alias: matches = lambda x: x == alias elif device_name: matches = matcher(device_name) else: matches = NOOP return matches def maker(args): if args.state.lower() in ("on", "1", "true"): state = "on" elif args.state.lower() in ("off", "0", "false"): state = "off" elif args.state.lower() == "toggle": state = "toggle" elif args.state.lower() == "sensor": state = "sensor" elif args.state.lower() == "switch": state = "switch" else: print("""No valid action specified. Usage: wemo maker NAME (on|off|toggle|sensor|switch)""") sys.exit(1) matches = make_matcher(args.device) def on_switch(maker): return def on_motion(maker): return def on_bridge(maker): return def on_maker(maker): if matches(maker.name): if state == "toggle": found_state = maker.get_state(force_update=True) maker.set_state(not found_state) elif state == "sensor": if maker.has_sensor: if args.human_readable: if maker.sensor_state: sensorstate = 'Sensor not triggered' else: sensorstate = 'Sensor triggered' print(sensorstate) else: print(maker.sensor_state) else: print("Sensor not present") elif state == "switch": if maker.switch_mode: print("Momentary Switch") else: print(_state(maker, args.human_readable)) else: getattr(maker, state)() if args.device != 'all': sys.exit(0) scan(args, on_switch, on_motion, on_bridge, on_maker) if args.device != 'all': # If we got here, we didn't find anything print("No device found with that name.") sys.exit(1) def list_(args): def on_switch(switch): print("Switch:", switch.name) def on_motion(motion): print("Motion:", motion.name) def on_maker(maker): print("Maker:", maker.name) def on_bridge(bridge): print("Bridge:", bridge.name) bridge.bridge_get_lights() bridge.bridge_get_groups() for group in bridge.Groups: print("Group:", group) for light in bridge.Lights: print("Light:", light) scan(args, on_switch, on_motion, on_bridge, on_maker) def status(args): def on_switch(switch): print("Switch:", switch.name, '\t', _state(switch, args.human_readable)) def on_motion(motion): print("Motion:", motion.name, '\t', _state(motion, args.human_readable)) def on_maker(maker): if maker.switch_mode: print("Maker:", maker.name, '\t', "Momentary State:", _state(maker, args.human_readable)) else: print("Maker:", maker.name, '\t', "Persistent State:", _state(maker, args.human_readable)) if maker.has_sensor: if args.human_readable: if maker.sensor_state: sensorstate = 'Sensor not triggered' else: sensorstate = 'Sensor triggered' print('\t\t\t', "Sensor:", sensorstate) else: print('\t\t\t', "Sensor:", maker.sensor_state) else: print('\t\t\t' "Sensor not present") def on_bridge(bridge): print("Bridge:", bridge.name, '\t', _state(bridge, args.human_readable)) bridge.bridge_get_lights() for light in bridge.Lights: print("Light:", light, '\t', bridge.light_get_state(bridge.Lights[light])) for group in bridge.Groups: print("Group:", group, '\t', bridge.group_get_state(bridge.Groups[group])) scan(args, on_switch, on_motion, on_bridge, on_maker) def server(args): try: from socketio.server import SocketIOServer from ouimeaux.server import app, initialize except ImportError: print("ouimeaux server dependencies are not installed. Please run, e.g., 'pip install ouimeaux[server]'") sys.exit(1) initialize(bind=getattr(args, 'bind', None), auth=(WemoConfiguration().auth or None)) level = logging.INFO if getattr(args, 'debug', False): level = logging.DEBUG logging.basicConfig(level=level) try: # TODO: Move this to configuration listen = WemoConfiguration().listen or '0.0.0.0:5000' try: host, port = listen.split(':') except Exception: print("Invalid bind address configuration:", listen) sys.exit(1) SocketIOServer((host, int(port)), app, policy_server=False, namespace="socket.io").serve_forever() except (KeyboardInterrupt, SystemExit): sys.exit(0) def wemo(): import ouimeaux.utils ouimeaux.utils._RETRIES = 0 parser = argparse.ArgumentParser() parser.add_argument("-b", "--bind", default=None, help="ip:port to which to bind the response server." " Default is localhost:54321") parser.add_argument("-d", "--debug", action="store_true", default=False, help="Enable debug logging") parser.add_argument("-e", "--exact-match", action="store_true", default=False, help="Disable fuzzy matching for device names") parser.add_argument("-v", "--human-readable", dest="human_readable", action="store_true", default=False, help="Print statuses as human-readable words") parser.add_argument("-t", "--timeout", type=int, default=5, help="Time in seconds to allow for discovery") subparsers = parser.add_subparsers() statusparser = subparsers.add_parser("status", help="Print status of WeMo devices") statusparser.set_defaults(func=status) stateparser = subparsers.add_parser("switch", help="Turn a WeMo Switch on or off") stateparser.add_argument("device", help="Name or alias of the device") stateparser.add_argument("state", help="'on' or 'off'") stateparser.set_defaults(func=switch) makerparser = subparsers.add_parser("maker", help="Get sensor or switch state of a Maker or Turn on or off") makerparser.add_argument("device", help="Name or alias of the device") makerparser.add_argument("state", help="'on' or 'off' or 'toggle' or 'sensor' or 'switch'") makerparser.set_defaults(func=maker) stateparser = subparsers.add_parser("light", help="Turn a WeMo LED light on or off") stateparser.add_argument("name", help="Name or alias of the device or group") stateparser.add_argument("state", help="'on' or 'off'") stateparser.add_argument("dim", nargs='?', type=int, help="Dim value 0 to 255") stateparser.set_defaults(func=light) listparser = subparsers.add_parser("list", help="List all devices found in the environment") listparser.set_defaults(func=list_) serverparser = subparsers.add_parser("server", help="Run the API server and web app") serverparser.set_defaults(func=server) args = parser.parse_args() if getattr(args, 'debug', False): logging.basicConfig(level=logging.DEBUG) if hasattr(args, 'func'): args.func(args) else: parser.print_help(sys.stderr) ================================================ FILE: ouimeaux/config.py ================================================ import os import yaml def in_home(*path): try: from win32com.shell import shellcon, shell except ImportError: home = os.path.expanduser("~") else: home = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0) return os.path.join(home, *path) def ensure_directory(directory): if not os.path.exists(directory): os.makedirs(directory) return directory class WemoConfiguration(object): def __init__(self, filename=None): if filename is None: ensure_directory(in_home('.wemo')) filename = in_home('.wemo', 'config.yml') if not os.path.isfile(filename): with open(filename, 'w') as f: f.write(""" aliases: # Shortcuts to longer device names. Uncommenting the following # line will allow you to execute 'wemo switch lr on' instead of # 'wemo switch "Living Room Lights" on' # # lr: Living Room Lights # ip:port to bind to when receiving responses from discovery. # The default is first DNS resolution of local host, port 54321 # # bind: 10.1.2.3:9090 # Web app bind address # # listen: 0.0.0.0:5000 # Require basic authentication (username:password) for the web app # # auth: admin:password """) with open(filename, 'r') as cfg: self._parsed = yaml.load(cfg, Loader=yaml.FullLoader) @property def aliases(self): return self._parsed.get('aliases') or {} @property def bind(self): return self._parsed.get('bind', None) @property def listen(self): return self._parsed.get('listen', None) @property def auth(self): return self._parsed.get('auth', None) ================================================ FILE: ouimeaux/device/__init__.py ================================================ import logging from six.moves.urllib.parse import urlsplit from .api.service import Service from .api.xsd import device as deviceParser from ..utils import requests_get log = logging.getLogger(__name__) class DeviceUnreachable(Exception): pass class UnknownService(Exception): pass class Device(object): def __init__(self, url): self._state = None base_url = url.rsplit('/', 1)[0] self.host = urlsplit(url).hostname #self.port = urlsplit(url).port xml = requests_get(url) self._config = deviceParser.parseString(xml.content).device sl = self._config.serviceList self.services = {} for svc in sl.service: svcname = svc.get_serviceType().split(':')[-2] service = Service(svc, base_url) service.eventSubURL = base_url + svc.get_eventSubURL() self.services[svcname] = service setattr(self, svcname, service) def _update_state(self, value): self._state = int(value) def get_state(self, force_update=False): """ Returns 0 if off and 1 if on. """ if force_update or self._state is None: return int(self.basicevent.GetBinaryState()['BinaryState']) return self._state def __getstate__(self): odict = self.__dict__.copy() # copy the dict since we change it if 'register_listener' in odict: del odict['register_listener'] return odict def get_service(self, name): try: return self.services[name] except KeyError: raise UnknownService(name) def list_services(self): return self.services.keys() def ping(self): try: self.get_state() except Exception: raise DeviceUnreachable(self) def explain(self): for name, svc in self.services.items(): print(name) print('-' * len(name)) for aname, action in svc.actions.items(): print(" %s(%s)" % (aname, ', '.join(action.args))) print() @property def model(self): return self._config.get_modelDescription() @property def name(self): return self._config.get_friendlyName() @property def serialnumber(self): return self._config.get_serialNumber() def test(): device = Device("http://10.42.1.102:49152/setup.xml") print(device.get_service('basicevent').SetBinaryState(BinaryState=1)) if __name__ == "__main__": test() ================================================ FILE: ouimeaux/device/api/__init__.py ================================================ ================================================ FILE: ouimeaux/device/api/service.py ================================================ import logging from xml.etree import ElementTree as et from ...utils import requests_get, requests_post from .xsd import service as serviceParser log = logging.getLogger(__name__) REQUEST_TEMPLATE = """ {args} """ class Action(object): def __init__(self, service, action_config): self._action_config = action_config self.name = action_config.get_name() self.serviceType = service.serviceType self.controlURL = service.controlURL self.args = {} self.headers = { 'Content-Type': 'text/xml', 'SOAPACTION': '"%s#%s"' % (self.serviceType, self.name) } arglist = action_config.get_argumentList() if arglist is not None: for arg in arglist.get_argument(): name = arg.get_name() if name: # TODO: Get type instead of setting 0 self.args[arg.get_name()] = 0 def __call__(self, **kwargs): arglist = '\n'.join('<{0}>{1}'.format(arg, value) for arg, value in kwargs.items()) body = REQUEST_TEMPLATE.format( action=self.name, service=self.serviceType, args=arglist ) response = requests_post(self.controlURL, body.strip(), headers=self.headers) d = {} for r in list(list(list(et.fromstring(response.content))[0])[0]): d[r.tag] = r.text return d def __repr__(self): return "" % (self.name, ", ".join(self.args)) class Service(object): """ Represents an instance of a service on a device. """ def __init__(self, service, base_url): self._base_url = base_url.rstrip('/') self._config = service url = '%s/%s' % (base_url, service.get_SCPDURL().strip('/')) xml = requests_get(url) self.actions = {} self._svc_config = serviceParser.parseString(xml.content).actionList for action in self._svc_config.get_action(): act = Action(self, action) name = action.get_name() self.actions[name] = act setattr(self, name, act) @property def hostname(self): return self._base_url.split('/')[-1] @property def controlURL(self): return '%s/%s' % (self._base_url, self._config.get_controlURL().strip('/')) @property def serviceType(self): return self._config.get_serviceType() ================================================ FILE: ouimeaux/device/api/xsd/__init__.py ================================================ ================================================ FILE: ouimeaux/device/api/xsd/device.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- # # Generated Thu Jan 31 15:50:44 2013 by generateDS.py version 2.8b. # import sys import getopt import re as re_ import base64 from datetime import datetime, tzinfo, timedelta etree_ = None Verbose_import_ = False ( XMLParser_import_none, XMLParser_import_lxml, XMLParser_import_elementtree ) = range(3) XMLParser_import_library = None try: # lxml from lxml import etree as etree_ XMLParser_import_library = XMLParser_import_lxml if Verbose_import_: print("running with lxml.etree") except ImportError: try: # cElementTree from Python 2.5+ import xml.etree.cElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with cElementTree on Python 2.5+") except ImportError: try: # ElementTree from Python 2.5+ import xml.etree.ElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with ElementTree on Python 2.5+") except ImportError: try: # normal cElementTree install import cElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with cElementTree") except ImportError: try: # normal ElementTree install import elementtree.ElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with ElementTree") except ImportError: raise ImportError( "Failed to import ElementTree from any known place") def parsexml_(*args, **kwargs): if (XMLParser_import_library == XMLParser_import_lxml and 'parser' not in kwargs): # Use the lxml ElementTree compatible parser so that, e.g., # we ignore comments. kwargs['parser'] = etree_.ETCompatXMLParser() doc = etree_.parse(*args, **kwargs) return doc # # User methods # # Calls to the methods in these classes are generated by generateDS.py. # You can replace these methods by re-implementing the following class # in a module named generatedssuper.py. try: from generatedssuper import GeneratedsSuper except ImportError as exp: class GeneratedsSuper(object): tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') class _FixedOffsetTZ(tzinfo): def __init__(self, offset, name): self.__offset = timedelta(minutes = offset) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return None def gds_format_string(self, input_data, input_name=''): return input_data def gds_validate_string(self, input_data, node, input_name=''): return input_data def gds_format_base64(self, input_data, input_name=''): return base64.b64encode(input_data) def gds_validate_base64(self, input_data, node, input_name=''): return input_data def gds_format_integer(self, input_data, input_name=''): return '%d' % input_data def gds_validate_integer(self, input_data, node, input_name=''): return input_data def gds_format_integer_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_integer_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: try: fvalue = float(value) except (TypeError, ValueError) as exp: raise_parse_error(node, 'Requires sequence of integers') return input_data def gds_format_float(self, input_data, input_name=''): return '%f' % input_data def gds_validate_float(self, input_data, node, input_name=''): return input_data def gds_format_float_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_float_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: try: fvalue = float(value) except (TypeError, ValueError) as exp: raise_parse_error(node, 'Requires sequence of floats') return input_data def gds_format_double(self, input_data, input_name=''): return '%e' % input_data def gds_validate_double(self, input_data, node, input_name=''): return input_data def gds_format_double_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_double_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: try: fvalue = float(value) except (TypeError, ValueError) as exp: raise_parse_error(node, 'Requires sequence of doubles') return input_data def gds_format_boolean(self, input_data, input_name=''): return '%s' % input_data def gds_validate_boolean(self, input_data, node, input_name=''): return input_data def gds_format_boolean_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_boolean_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: if value not in ('true', '1', 'false', '0', ): raise_parse_error(node, 'Requires sequence of booleans ' '("true", "1", "false", "0")') return input_data def gds_validate_datetime(self, input_data, node, input_name=''): return input_data def gds_format_datetime(self, input_data, input_name=''): if input_data.microsecond == 0: _svalue = input_data.strftime('%Y-%m-%dT%H:%M:%S') else: _svalue = input_data.strftime('%Y-%m-%dT%H:%M:%S.%f') if input_data.tzinfo is not None: tzoff = input_data.tzinfo.utcoffset(input_data) if tzoff is not None: total_seconds = tzoff.seconds + (86400 * tzoff.days) if total_seconds == 0: _svalue += 'Z' else: if total_seconds < 0: _svalue += '-' total_seconds *= -1 else: _svalue += '+' hours = total_seconds // 3600 minutes = (total_seconds - (hours * 3600)) // 60 _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) return _svalue def gds_parse_datetime(self, input_data, node, input_name=''): tz = None if input_data[-1] == 'Z': tz = GeneratedsSuper._FixedOffsetTZ(0, 'GMT') input_data = input_data[:-1] else: results = GeneratedsSuper.tzoff_pattern.search(input_data) if results is not None: tzoff_parts = results.group(2).split(':') tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) if results.group(1) == '-': tzoff *= -1 tz = GeneratedsSuper._FixedOffsetTZ( tzoff, results.group(0)) input_data = input_data[:-6] if len(input_data.split('.')) > 1: dt = datetime.strptime( input_data, '%Y-%m-%dT%H:%M:%S.%f') else: dt = datetime.strptime( input_data, '%Y-%m-%dT%H:%M:%S') return dt.replace(tzinfo = tz) def gds_validate_date(self, input_data, node, input_name=''): return input_data def gds_format_date(self, input_data, input_name=''): _svalue = input_data.strftime('%Y-%m-%d') if input_data.tzinfo is not None: tzoff = input_data.tzinfo.utcoffset(input_data) if tzoff is not None: total_seconds = tzoff.seconds + (86400 * tzoff.days) if total_seconds == 0: _svalue += 'Z' else: if total_seconds < 0: _svalue += '-' total_seconds *= -1 else: _svalue += '+' hours = total_seconds // 3600 minutes = (total_seconds - (hours * 3600)) // 60 _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) return _svalue def gds_parse_date(self, input_data, node, input_name=''): tz = None if input_data[-1] == 'Z': tz = GeneratedsSuper._FixedOffsetTZ(0, 'GMT') input_data = input_data[:-1] else: results = GeneratedsSuper.tzoff_pattern.search(input_data) if results is not None: tzoff_parts = results.group(2).split(':') tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) if results.group(1) == '-': tzoff *= -1 tz = GeneratedsSuper._FixedOffsetTZ( tzoff, results.group(0)) input_data = input_data[:-6] return datetime.strptime(input_data, '%Y-%m-%d').replace(tzinfo = tz) def gds_str_lower(self, instring): return instring.lower() def get_path_(self, node): path_list = [] self.get_path_list_(node, path_list) path_list.reverse() path = '/'.join(path_list) return path Tag_strip_pattern_ = re_.compile(r'\{.*\}') def get_path_list_(self, node, path_list): if node is None: return tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) if tag: path_list.append(tag) self.get_path_list_(node.getparent(), path_list) def get_class_obj_(self, node, default_class=None): class_obj1 = default_class if 'xsi' in node.nsmap: classname = node.get('{%s}type' % node.nsmap['xsi']) if classname is not None: names = classname.split(':') if len(names) == 2: classname = names[1] class_obj2 = globals().get(classname) if class_obj2 is not None: class_obj1 = class_obj2 return class_obj1 def gds_build_any(self, node, type_name=None): return None # # If you have installed IPython you can uncomment and use the following. # IPython is available from http://ipython.scipy.org/. # ## from IPython.Shell import IPShellEmbed ## args = '' ## ipshell = IPShellEmbed(args, ## banner = 'Dropping into IPython', ## exit_msg = 'Leaving Interpreter, back to program.') # Then use the following line where and when you want to drop into the # IPython shell: # ipshell(' -- Entering ipshell.\nHit Ctrl-D to exit') # # Globals # ExternalEncoding = 'ascii' Tag_pattern_ = re_.compile(r'({.*})?(.*)') String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') # # Support/utility functions. # def showIndent(outfile, level, pretty_print=True): if pretty_print: for idx in range(level): outfile.write(' ') def quote_xml(inStr): if not inStr: return '' s1 = (isinstance(inStr, basestring) and inStr or '%s' % inStr) s1 = s1.replace('&', '&') s1 = s1.replace('<', '<') s1 = s1.replace('>', '>') return s1 def quote_attrib(inStr): s1 = (isinstance(inStr, basestring) and inStr or '%s' % inStr) s1 = s1.replace('&', '&') s1 = s1.replace('<', '<') s1 = s1.replace('>', '>') if '"' in s1: if "'" in s1: s1 = '"%s"' % s1.replace('"', """) else: s1 = "'%s'" % s1 else: s1 = '"%s"' % s1 return s1 def quote_python(inStr): s1 = inStr if s1.find("'") == -1: if s1.find('\n') == -1: return "'%s'" % s1 else: return "'''%s'''" % s1 else: if s1.find('"') != -1: s1 = s1.replace('"', '\\"') if s1.find('\n') == -1: return '"%s"' % s1 else: return '"""%s"""' % s1 def get_all_text_(node): if node.text is not None: text = node.text else: text = '' for child in node: if child.tail is not None: text += child.tail return text def find_attr_value_(attr_name, node): attrs = node.attrib attr_parts = attr_name.split(':') value = None if len(attr_parts) == 1: value = attrs.get(attr_name) elif len(attr_parts) == 2: prefix, name = attr_parts namespace = node.nsmap.get(prefix) if namespace is not None: value = attrs.get('{%s}%s' % (namespace, name, )) return value class GDSParseError(Exception): pass def raise_parse_error(node, msg): if XMLParser_import_library == XMLParser_import_lxml: msg = '%s (element %s/line %d)' % ( msg, node.tag, node.sourceline, ) else: msg = '%s (element %s)' % (msg, node.tag, ) raise GDSParseError(msg) class MixedContainer: # Constants for category: CategoryNone = 0 CategoryText = 1 CategorySimple = 2 CategoryComplex = 3 # Constants for content_type: TypeNone = 0 TypeText = 1 TypeString = 2 TypeInteger = 3 TypeFloat = 4 TypeDecimal = 5 TypeDouble = 6 TypeBoolean = 7 TypeBase64 = 8 def __init__(self, category, content_type, name, value): self.category = category self.content_type = content_type self.name = name self.value = value def getCategory(self): return self.category def getContenttype(self, content_type): return self.content_type def getValue(self): return self.value def getName(self): return self.name def export(self, outfile, level, name, namespace, pretty_print=True): if self.category == MixedContainer.CategoryText: # Prevent exporting empty content as empty lines. if self.value.strip(): outfile.write(self.value) elif self.category == MixedContainer.CategorySimple: self.exportSimple(outfile, level, name) else: # category == MixedContainer.CategoryComplex self.value.export(outfile, level, namespace, name, pretty_print) def exportSimple(self, outfile, level, name): if self.content_type == MixedContainer.TypeString: outfile.write('<%s>%s' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeInteger or \ self.content_type == MixedContainer.TypeBoolean: outfile.write('<%s>%d' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeFloat or \ self.content_type == MixedContainer.TypeDecimal: outfile.write('<%s>%f' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeDouble: outfile.write('<%s>%g' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeBase64: outfile.write('<%s>%s' % (self.name, base64.b64encode(self.value), self.name)) def exportLiteral(self, outfile, level, name): if self.category == MixedContainer.CategoryText: showIndent(outfile, level) outfile.write('model_.MixedContainer(%d, %d, "%s", "%s"),\n' % (self.category, self.content_type, self.name, self.value)) elif self.category == MixedContainer.CategorySimple: showIndent(outfile, level) outfile.write('model_.MixedContainer(%d, %d, "%s", "%s"),\n' % (self.category, self.content_type, self.name, self.value)) else: # category == MixedContainer.CategoryComplex showIndent(outfile, level) outfile.write('model_.MixedContainer(%d, %d, "%s",\n' % \ (self.category, self.content_type, self.name,)) self.value.exportLiteral(outfile, level + 1) showIndent(outfile, level) outfile.write(')\n') class MemberSpec_(object): def __init__(self, name='', data_type='', container=0): self.name = name self.data_type = data_type self.container = container def set_name(self, name): self.name = name def get_name(self): return self.name def set_data_type(self, data_type): self.data_type = data_type def get_data_type_chain(self): return self.data_type def get_data_type(self): if isinstance(self.data_type, list): if len(self.data_type) > 0: return self.data_type[-1] else: return 'xs:string' else: return self.data_type def set_container(self, container): self.container = container def get_container(self): return self.container def _cast(typ, value): if typ is None or value is None: return value return typ(value) # # Data representation classes. # class root(GeneratedsSuper): subclass = None superclass = None def __init__(self, specVersion=None, URLBase=None, device=None): self.specVersion = specVersion self.URLBase = URLBase self.device = device self.anyAttributes_ = {} def factory(*args_, **kwargs_): if root.subclass: return root.subclass(*args_, **kwargs_) else: return root(*args_, **kwargs_) factory = staticmethod(factory) def get_specVersion(self): return self.specVersion def set_specVersion(self, specVersion): self.specVersion = specVersion def get_URLBase(self): return self.URLBase def set_URLBase(self, URLBase): self.URLBase = URLBase def get_device(self): return self.device def set_device(self, device): self.device = device def get_anyAttributes_(self): return self.anyAttributes_ def set_anyAttributes_(self, anyAttributes_): self.anyAttributes_ = anyAttributes_ def export(self, outfile, level, namespace_='tns:', name_='root', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='root') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='root'): unique_counter = 0 for name, value in self.anyAttributes_.items(): xsinamespaceprefix = 'xsi' xsinamespace1 = 'http://www.w3.org/2001/XMLSchema-instance' xsinamespace2 = '{%s}' % (xsinamespace1, ) if name.startswith(xsinamespace2): name1 = name[len(xsinamespace2):] name2 = '%s:%s' % (xsinamespaceprefix, name1, ) if name2 not in already_processed: already_processed.append(name2) outfile.write(' %s=%s' % (name2, quote_attrib(value), )) else: mo = re_.match(Namespace_extract_pat_, name) if mo is not None: namespace, name = mo.group(1, 2) if name not in already_processed: already_processed.append(name) if namespace == 'http://www.w3.org/XML/1998/namespace': outfile.write(' %s=%s' % ( name, quote_attrib(value), )) else: unique_counter += 1 outfile.write(' xmlns:yyy%d="%s"' % ( unique_counter, namespace, )) outfile.write(' yyy%d:%s=%s' % ( unique_counter, name, quote_attrib(value), )) else: if name not in already_processed: already_processed.append(name) outfile.write(' %s=%s' % ( name, quote_attrib(value), )) pass def exportChildren(self, outfile, level, namespace_='tns:', name_='root', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.specVersion is not None: self.specVersion.export(outfile, level, namespace_, name_='specVersion', pretty_print=pretty_print) if self.URLBase is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sURLBase>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.URLBase).encode(ExternalEncoding), input_name='URLBase'), namespace_, eol_)) if self.device is not None: self.device.export(outfile, level, namespace_, name_='device', pretty_print=pretty_print) def hasContent_(self): if ( self.specVersion is not None or self.URLBase is not None or self.device is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='root'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): for name, value in self.anyAttributes_.items(): showIndent(outfile, level) outfile.write('%s = "%s",\n' % (name, value,)) def exportLiteralChildren(self, outfile, level, name_): if self.specVersion is not None: showIndent(outfile, level) outfile.write('specVersion=model_.SpecVersionType(\n') self.specVersion.exportLiteral(outfile, level, name_='specVersion') showIndent(outfile, level) outfile.write('),\n') if self.URLBase is not None: showIndent(outfile, level) outfile.write('URLBase=%s,\n' % quote_python(self.URLBase).encode(ExternalEncoding)) if self.device is not None: showIndent(outfile, level) outfile.write('device=model_.DeviceType(\n') self.device.exportLiteral(outfile, level, name_='device') showIndent(outfile, level) outfile.write('),\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): self.anyAttributes_ = {} for name, value in attrs.items(): if name not in already_processed: self.anyAttributes_[name] = value def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'specVersion': obj_ = SpecVersionType.factory() obj_.build(child_) self.set_specVersion(obj_) elif nodeName_ == 'URLBase': URLBase_ = child_.text URLBase_ = self.gds_validate_string(URLBase_, node, 'URLBase') self.URLBase = URLBase_ elif nodeName_ == 'device': obj_ = DeviceType.factory() obj_.build(child_) self.set_device(obj_) # end class root class SpecVersionType(GeneratedsSuper): subclass = None superclass = None def __init__(self, major=None, minor=None): self.major = major self.minor = minor def factory(*args_, **kwargs_): if SpecVersionType.subclass: return SpecVersionType.subclass(*args_, **kwargs_) else: return SpecVersionType(*args_, **kwargs_) factory = staticmethod(factory) def get_major(self): return self.major def set_major(self, major): self.major = major def get_minor(self): return self.minor def set_minor(self, minor): self.minor = minor def export(self, outfile, level, namespace_='tns:', name_='SpecVersionType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='SpecVersionType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='SpecVersionType'): pass def exportChildren(self, outfile, level, namespace_='tns:', name_='SpecVersionType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.major is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smajor>%s%s' % (namespace_, self.gds_format_integer(self.major, input_name='major'), namespace_, eol_)) if self.minor is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sminor>%s%s' % (namespace_, self.gds_format_integer(self.minor, input_name='minor'), namespace_, eol_)) def hasContent_(self): if ( self.major is not None or self.minor is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='SpecVersionType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.major is not None: showIndent(outfile, level) outfile.write('major=%d,\n' % self.major) if self.minor is not None: showIndent(outfile, level) outfile.write('minor=%d,\n' % self.minor) def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'major': sval_ = child_.text try: ival_ = int(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) ival_ = self.gds_validate_integer(ival_, node, 'major') self.major = ival_ elif nodeName_ == 'minor': sval_ = child_.text try: ival_ = int(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) ival_ = self.gds_validate_integer(ival_, node, 'minor') self.minor = ival_ # end class SpecVersionType class DeviceType(GeneratedsSuper): subclass = None superclass = None def __init__(self, deviceType=None, friendlyName=None, manufacturer=None, manufacturerURL=None, modelDescription=None, modelName=None, modelNumber=None, modelURL=None, serialNumber=None, UDN=None, UPC=None, iconList=None, serviceList=None, deviceList=None, presentationURL=None, anytypeobjs_=None): self.deviceType = deviceType self.friendlyName = friendlyName self.manufacturer = manufacturer self.manufacturerURL = manufacturerURL self.modelDescription = modelDescription self.modelName = modelName self.modelNumber = modelNumber self.modelURL = modelURL self.serialNumber = serialNumber self.UDN = UDN self.UPC = UPC self.iconList = iconList self.serviceList = serviceList self.deviceList = deviceList self.presentationURL = presentationURL if anytypeobjs_ is None: self.anytypeobjs_ = [] else: self.anytypeobjs_ = anytypeobjs_ def factory(*args_, **kwargs_): if DeviceType.subclass: return DeviceType.subclass(*args_, **kwargs_) else: return DeviceType(*args_, **kwargs_) factory = staticmethod(factory) def get_deviceType(self): return self.deviceType def set_deviceType(self, deviceType): self.deviceType = deviceType def get_friendlyName(self): return self.friendlyName def set_friendlyName(self, friendlyName): self.friendlyName = friendlyName def get_manufacturer(self): return self.manufacturer def set_manufacturer(self, manufacturer): self.manufacturer = manufacturer def get_manufacturerURL(self): return self.manufacturerURL def set_manufacturerURL(self, manufacturerURL): self.manufacturerURL = manufacturerURL def get_modelDescription(self): return self.modelDescription def set_modelDescription(self, modelDescription): self.modelDescription = modelDescription def get_modelName(self): return self.modelName def set_modelName(self, modelName): self.modelName = modelName def get_modelNumber(self): return self.modelNumber def set_modelNumber(self, modelNumber): self.modelNumber = modelNumber def get_modelURL(self): return self.modelURL def set_modelURL(self, modelURL): self.modelURL = modelURL def get_serialNumber(self): return self.serialNumber def set_serialNumber(self, serialNumber): self.serialNumber = serialNumber def get_UDN(self): return self.UDN def set_UDN(self, UDN): self.UDN = UDN def get_UPC(self): return self.UPC def set_UPC(self, UPC): self.UPC = UPC def get_iconList(self): return self.iconList def set_iconList(self, iconList): self.iconList = iconList def get_serviceList(self): return self.serviceList def set_serviceList(self, serviceList): self.serviceList = serviceList def get_deviceList(self): return self.deviceList def set_deviceList(self, deviceList): self.deviceList = deviceList def get_presentationURL(self): return self.presentationURL def set_presentationURL(self, presentationURL): self.presentationURL = presentationURL def get_anytypeobjs_(self): return self.anytypeobjs_ def set_anytypeobjs_(self, anytypeobjs_): self.anytypeobjs_ = anytypeobjs_ def add_anytypeobjs_(self, value): self.anytypeobjs_.append(value) def insert_anytypeobjs_(self, index, value): self._anytypeobjs_[index] = value def export(self, outfile, level, namespace_='tns:', name_='DeviceType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='DeviceType'): pass def exportChildren(self, outfile, level, namespace_='tns:', name_='DeviceType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.deviceType is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sdeviceType>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.deviceType).encode(ExternalEncoding), input_name='deviceType'), namespace_, eol_)) if self.friendlyName is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sfriendlyName>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.friendlyName).encode(ExternalEncoding), input_name='friendlyName'), namespace_, eol_)) if self.manufacturer is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smanufacturer>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.manufacturer).encode(ExternalEncoding), input_name='manufacturer'), namespace_, eol_)) if self.manufacturerURL is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smanufacturerURL>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.manufacturerURL).encode(ExternalEncoding), input_name='manufacturerURL'), namespace_, eol_)) if self.modelDescription is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smodelDescription>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.modelDescription).encode(ExternalEncoding), input_name='modelDescription'), namespace_, eol_)) if self.modelName is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smodelName>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.modelName).encode(ExternalEncoding), input_name='modelName'), namespace_, eol_)) if self.modelNumber is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smodelNumber>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.modelNumber).encode(ExternalEncoding), input_name='modelNumber'), namespace_, eol_)) if self.modelURL is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smodelURL>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.modelURL).encode(ExternalEncoding), input_name='modelURL'), namespace_, eol_)) if self.serialNumber is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sserialNumber>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.serialNumber).encode(ExternalEncoding), input_name='serialNumber'), namespace_, eol_)) if self.UDN is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sUDN>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.UDN).encode(ExternalEncoding), input_name='UDN'), namespace_, eol_)) if self.UPC is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sUPC>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.UPC).encode(ExternalEncoding), input_name='UPC'), namespace_, eol_)) if self.iconList is not None: self.iconList.export(outfile, level, namespace_, name_='iconList', pretty_print=pretty_print) if self.serviceList is not None: self.serviceList.export(outfile, level, namespace_, name_='serviceList', pretty_print=pretty_print) if self.deviceList is not None: self.deviceList.export(outfile, level, namespace_, name_='deviceList', pretty_print=pretty_print) if self.presentationURL is not None: showIndent(outfile, level, pretty_print) outfile.write('<%spresentationURL>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.presentationURL).encode(ExternalEncoding), input_name='presentationURL'), namespace_, eol_)) for obj_ in self.anytypeobjs_: obj_.export(outfile, level, namespace_, pretty_print=pretty_print) def hasContent_(self): if ( self.deviceType is not None or self.friendlyName is not None or self.manufacturer is not None or self.manufacturerURL is not None or self.modelDescription is not None or self.modelName is not None or self.modelNumber is not None or self.modelURL is not None or self.serialNumber is not None or self.UDN is not None or self.UPC is not None or self.iconList is not None or self.serviceList is not None or self.deviceList is not None or self.presentationURL is not None or self.anytypeobjs_ ): return True else: return False def exportLiteral(self, outfile, level, name_='DeviceType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.deviceType is not None: showIndent(outfile, level) outfile.write('deviceType=%s,\n' % quote_python(self.deviceType).encode(ExternalEncoding)) if self.friendlyName is not None: showIndent(outfile, level) outfile.write('friendlyName=%s,\n' % quote_python(self.friendlyName).encode(ExternalEncoding)) if self.manufacturer is not None: showIndent(outfile, level) outfile.write('manufacturer=%s,\n' % quote_python(self.manufacturer).encode(ExternalEncoding)) if self.manufacturerURL is not None: showIndent(outfile, level) outfile.write('manufacturerURL=%s,\n' % quote_python(self.manufacturerURL).encode(ExternalEncoding)) if self.modelDescription is not None: showIndent(outfile, level) outfile.write('modelDescription=%s,\n' % quote_python(self.modelDescription).encode(ExternalEncoding)) if self.modelName is not None: showIndent(outfile, level) outfile.write('modelName=%s,\n' % quote_python(self.modelName).encode(ExternalEncoding)) if self.modelNumber is not None: showIndent(outfile, level) outfile.write('modelNumber=%s,\n' % quote_python(self.modelNumber).encode(ExternalEncoding)) if self.modelURL is not None: showIndent(outfile, level) outfile.write('modelURL=%s,\n' % quote_python(self.modelURL).encode(ExternalEncoding)) if self.serialNumber is not None: showIndent(outfile, level) outfile.write('serialNumber=%s,\n' % quote_python(self.serialNumber).encode(ExternalEncoding)) if self.UDN is not None: showIndent(outfile, level) outfile.write('UDN=%s,\n' % quote_python(self.UDN).encode(ExternalEncoding)) if self.UPC is not None: showIndent(outfile, level) outfile.write('UPC=%s,\n' % quote_python(self.UPC).encode(ExternalEncoding)) if self.iconList is not None: showIndent(outfile, level) outfile.write('iconList=model_.IconListType(\n') self.iconList.exportLiteral(outfile, level, name_='iconList') showIndent(outfile, level) outfile.write('),\n') if self.serviceList is not None: showIndent(outfile, level) outfile.write('serviceList=model_.ServiceListType(\n') self.serviceList.exportLiteral(outfile, level, name_='serviceList') showIndent(outfile, level) outfile.write('),\n') if self.deviceList is not None: showIndent(outfile, level) outfile.write('deviceList=model_.DeviceListType(\n') self.deviceList.exportLiteral(outfile, level, name_='deviceList') showIndent(outfile, level) outfile.write('),\n') if self.presentationURL is not None: showIndent(outfile, level) outfile.write('presentationURL=%s,\n' % quote_python(self.presentationURL).encode(ExternalEncoding)) showIndent(outfile, level) outfile.write('anytypeobjs_=[\n') level += 1 for anytypeobjs_ in self.anytypeobjs_: anytypeobjs_.exportLiteral(outfile, level) level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'deviceType': deviceType_ = child_.text deviceType_ = self.gds_validate_string(deviceType_, node, 'deviceType') self.deviceType = deviceType_ elif nodeName_ == 'friendlyName': friendlyName_ = child_.text friendlyName_ = self.gds_validate_string(friendlyName_, node, 'friendlyName') self.friendlyName = friendlyName_ elif nodeName_ == 'manufacturer': manufacturer_ = child_.text manufacturer_ = self.gds_validate_string(manufacturer_, node, 'manufacturer') self.manufacturer = manufacturer_ elif nodeName_ == 'manufacturerURL': manufacturerURL_ = child_.text manufacturerURL_ = self.gds_validate_string(manufacturerURL_, node, 'manufacturerURL') self.manufacturerURL = manufacturerURL_ elif nodeName_ == 'modelDescription': modelDescription_ = child_.text modelDescription_ = self.gds_validate_string(modelDescription_, node, 'modelDescription') self.modelDescription = modelDescription_ elif nodeName_ == 'modelName': modelName_ = child_.text modelName_ = self.gds_validate_string(modelName_, node, 'modelName') self.modelName = modelName_ elif nodeName_ == 'modelNumber': modelNumber_ = child_.text modelNumber_ = self.gds_validate_string(modelNumber_, node, 'modelNumber') self.modelNumber = modelNumber_ elif nodeName_ == 'modelURL': modelURL_ = child_.text modelURL_ = self.gds_validate_string(modelURL_, node, 'modelURL') self.modelURL = modelURL_ elif nodeName_ == 'serialNumber': serialNumber_ = child_.text serialNumber_ = self.gds_validate_string(serialNumber_, node, 'serialNumber') self.serialNumber = serialNumber_ elif nodeName_ == 'UDN': UDN_ = child_.text UDN_ = self.gds_validate_string(UDN_, node, 'UDN') self.UDN = UDN_ elif nodeName_ == 'UPC': UPC_ = child_.text UPC_ = self.gds_validate_string(UPC_, node, 'UPC') self.UPC = UPC_ elif nodeName_ == 'iconList': obj_ = IconListType.factory() obj_.build(child_) self.set_iconList(obj_) elif nodeName_ == 'serviceList': obj_ = ServiceListType.factory() obj_.build(child_) self.set_serviceList(obj_) elif nodeName_ == 'deviceList': obj_ = DeviceListType.factory() obj_.build(child_) self.set_deviceList(obj_) elif nodeName_ == 'presentationURL': presentationURL_ = child_.text presentationURL_ = self.gds_validate_string(presentationURL_, node, 'presentationURL') self.presentationURL = presentationURL_ else: obj_ = self.gds_build_any(child_, 'DeviceType') if obj_ is not None: self.add_anytypeobjs_(obj_) # end class DeviceType class IconListType(GeneratedsSuper): subclass = None superclass = None def __init__(self, icon=None): if icon is None: self.icon = [] else: self.icon = icon def factory(*args_, **kwargs_): if IconListType.subclass: return IconListType.subclass(*args_, **kwargs_) else: return IconListType(*args_, **kwargs_) factory = staticmethod(factory) def get_icon(self): return self.icon def set_icon(self, icon): self.icon = icon def add_icon(self, value): self.icon.append(value) def insert_icon(self, index, value): self.icon[index] = value def export(self, outfile, level, namespace_='tns:', name_='IconListType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='IconListType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='IconListType'): pass def exportChildren(self, outfile, level, namespace_='tns:', name_='IconListType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' for icon_ in self.icon: icon_.export(outfile, level, namespace_, name_='icon', pretty_print=pretty_print) def hasContent_(self): if ( self.icon ): return True else: return False def exportLiteral(self, outfile, level, name_='IconListType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): showIndent(outfile, level) outfile.write('icon=[\n') level += 1 for icon_ in self.icon: showIndent(outfile, level) outfile.write('model_.iconType(\n') icon_.exportLiteral(outfile, level, name_='iconType') showIndent(outfile, level) outfile.write('),\n') level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'icon': obj_ = iconType.factory() obj_.build(child_) self.icon.append(obj_) # end class IconListType class ServiceListType(GeneratedsSuper): subclass = None superclass = None def __init__(self, service=None): if service is None: self.service = [] else: self.service = service def factory(*args_, **kwargs_): if ServiceListType.subclass: return ServiceListType.subclass(*args_, **kwargs_) else: return ServiceListType(*args_, **kwargs_) factory = staticmethod(factory) def get_service(self): return self.service def set_service(self, service): self.service = service def add_service(self, value): self.service.append(value) def insert_service(self, index, value): self.service[index] = value def export(self, outfile, level, namespace_='tns:', name_='ServiceListType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceListType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='ServiceListType'): pass def exportChildren(self, outfile, level, namespace_='tns:', name_='ServiceListType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' for service_ in self.service: service_.export(outfile, level, namespace_, name_='service', pretty_print=pretty_print) def hasContent_(self): if ( self.service ): return True else: return False def exportLiteral(self, outfile, level, name_='ServiceListType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): showIndent(outfile, level) outfile.write('service=[\n') level += 1 for service_ in self.service: showIndent(outfile, level) outfile.write('model_.serviceType(\n') service_.exportLiteral(outfile, level, name_='serviceType') showIndent(outfile, level) outfile.write('),\n') level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'service': obj_ = serviceType.factory() obj_.build(child_) self.service.append(obj_) # end class ServiceListType class DeviceListType(GeneratedsSuper): subclass = None superclass = None def __init__(self, device=None): if device is None: self.device = [] else: self.device = device def factory(*args_, **kwargs_): if DeviceListType.subclass: return DeviceListType.subclass(*args_, **kwargs_) else: return DeviceListType(*args_, **kwargs_) factory = staticmethod(factory) def get_device(self): return self.device def set_device(self, device): self.device = device def add_device(self, value): self.device.append(value) def insert_device(self, index, value): self.device[index] = value def export(self, outfile, level, namespace_='tns:', name_='DeviceListType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='DeviceListType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='DeviceListType'): pass def exportChildren(self, outfile, level, namespace_='tns:', name_='DeviceListType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' for device_ in self.device: device_.export(outfile, level, namespace_, name_='device', pretty_print=pretty_print) def hasContent_(self): if ( self.device ): return True else: return False def exportLiteral(self, outfile, level, name_='DeviceListType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): showIndent(outfile, level) outfile.write('device=[\n') level += 1 for device_ in self.device: showIndent(outfile, level) outfile.write('model_.DeviceType(\n') device_.exportLiteral(outfile, level, name_='DeviceType') showIndent(outfile, level) outfile.write('),\n') level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'device': obj_ = DeviceType.factory() obj_.build(child_) self.device.append(obj_) # end class DeviceListType class iconType(GeneratedsSuper): subclass = None superclass = None def __init__(self, mimetype=None, width=None, height=None, depth=None, url=None): self.mimetype = mimetype self.width = width self.height = height self.depth = depth self.url = url def factory(*args_, **kwargs_): if iconType.subclass: return iconType.subclass(*args_, **kwargs_) else: return iconType(*args_, **kwargs_) factory = staticmethod(factory) def get_mimetype(self): return self.mimetype def set_mimetype(self, mimetype): self.mimetype = mimetype def get_width(self): return self.width def set_width(self, width): self.width = width def get_height(self): return self.height def set_height(self, height): self.height = height def get_depth(self): return self.depth def set_depth(self, depth): self.depth = depth def get_url(self): return self.url def set_url(self, url): self.url = url def export(self, outfile, level, namespace_='tns:', name_='iconType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='iconType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='iconType'): pass def exportChildren(self, outfile, level, namespace_='tns:', name_='iconType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.mimetype is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smimetype>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.mimetype).encode(ExternalEncoding), input_name='mimetype'), namespace_, eol_)) if self.width is not None: showIndent(outfile, level, pretty_print) outfile.write('<%swidth>%s%s' % (namespace_, self.gds_format_integer(self.width, input_name='width'), namespace_, eol_)) if self.height is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sheight>%s%s' % (namespace_, self.gds_format_integer(self.height, input_name='height'), namespace_, eol_)) if self.depth is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sdepth>%s%s' % (namespace_, self.gds_format_integer(self.depth, input_name='depth'), namespace_, eol_)) if self.url is not None: showIndent(outfile, level, pretty_print) outfile.write('<%surl>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.url).encode(ExternalEncoding), input_name='url'), namespace_, eol_)) def hasContent_(self): if ( self.mimetype is not None or self.width is not None or self.height is not None or self.depth is not None or self.url is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='iconType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.mimetype is not None: showIndent(outfile, level) outfile.write('mimetype=%s,\n' % quote_python(self.mimetype).encode(ExternalEncoding)) if self.width is not None: showIndent(outfile, level) outfile.write('width=%d,\n' % self.width) if self.height is not None: showIndent(outfile, level) outfile.write('height=%d,\n' % self.height) if self.depth is not None: showIndent(outfile, level) outfile.write('depth=%d,\n' % self.depth) if self.url is not None: showIndent(outfile, level) outfile.write('url=%s,\n' % quote_python(self.url).encode(ExternalEncoding)) def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'mimetype': mimetype_ = child_.text mimetype_ = self.gds_validate_string(mimetype_, node, 'mimetype') self.mimetype = mimetype_ elif nodeName_ == 'width': sval_ = child_.text try: ival_ = int(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) ival_ = self.gds_validate_integer(ival_, node, 'width') self.width = ival_ elif nodeName_ == 'height': sval_ = child_.text try: ival_ = int(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) ival_ = self.gds_validate_integer(ival_, node, 'height') self.height = ival_ elif nodeName_ == 'depth': sval_ = child_.text try: ival_ = int(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) ival_ = self.gds_validate_integer(ival_, node, 'depth') self.depth = ival_ elif nodeName_ == 'url': url_ = child_.text url_ = self.gds_validate_string(url_, node, 'url') self.url = url_ # end class iconType class serviceType(GeneratedsSuper): subclass = None superclass = None def __init__(self, serviceType=None, serviceId=None, SCPDURL=None, controlURL=None, eventSubURL=None): self.serviceType = serviceType self.serviceId = serviceId self.SCPDURL = SCPDURL self.controlURL = controlURL self.eventSubURL = eventSubURL def factory(*args_, **kwargs_): if serviceType.subclass: return serviceType.subclass(*args_, **kwargs_) else: return serviceType(*args_, **kwargs_) factory = staticmethod(factory) def get_serviceType(self): return self.serviceType def set_serviceType(self, serviceType): self.serviceType = serviceType def get_serviceId(self): return self.serviceId def set_serviceId(self, serviceId): self.serviceId = serviceId def get_SCPDURL(self): return self.SCPDURL def set_SCPDURL(self, SCPDURL): self.SCPDURL = SCPDURL def get_controlURL(self): return self.controlURL def set_controlURL(self, controlURL): self.controlURL = controlURL def get_eventSubURL(self): return self.eventSubURL def set_eventSubURL(self, eventSubURL): self.eventSubURL = eventSubURL def export(self, outfile, level, namespace_='tns:', name_='serviceType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='serviceType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='tns:', name_='serviceType'): pass def exportChildren(self, outfile, level, namespace_='tns:', name_='serviceType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.serviceType is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sserviceType>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.serviceType).encode(ExternalEncoding), input_name='serviceType'), namespace_, eol_)) if self.serviceId is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sserviceId>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.serviceId).encode(ExternalEncoding), input_name='serviceId'), namespace_, eol_)) if self.SCPDURL is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sSCPDURL>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.SCPDURL).encode(ExternalEncoding), input_name='SCPDURL'), namespace_, eol_)) if self.controlURL is not None: showIndent(outfile, level, pretty_print) outfile.write('<%scontrolURL>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.controlURL).encode(ExternalEncoding), input_name='controlURL'), namespace_, eol_)) if self.eventSubURL is not None: showIndent(outfile, level, pretty_print) outfile.write('<%seventSubURL>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.eventSubURL).encode(ExternalEncoding), input_name='eventSubURL'), namespace_, eol_)) def hasContent_(self): if ( self.serviceType is not None or self.serviceId is not None or self.SCPDURL is not None or self.controlURL is not None or self.eventSubURL is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='serviceType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.serviceType is not None: showIndent(outfile, level) outfile.write('serviceType=%s,\n' % quote_python(self.serviceType).encode(ExternalEncoding)) if self.serviceId is not None: showIndent(outfile, level) outfile.write('serviceId=%s,\n' % quote_python(self.serviceId).encode(ExternalEncoding)) if self.SCPDURL is not None: showIndent(outfile, level) outfile.write('SCPDURL=%s,\n' % quote_python(self.SCPDURL).encode(ExternalEncoding)) if self.controlURL is not None: showIndent(outfile, level) outfile.write('controlURL=%s,\n' % quote_python(self.controlURL).encode(ExternalEncoding)) if self.eventSubURL is not None: showIndent(outfile, level) outfile.write('eventSubURL=%s,\n' % quote_python(self.eventSubURL).encode(ExternalEncoding)) def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'serviceType': serviceType_ = child_.text serviceType_ = self.gds_validate_string(serviceType_, node, 'serviceType') self.serviceType = serviceType_ elif nodeName_ == 'serviceId': serviceId_ = child_.text serviceId_ = self.gds_validate_string(serviceId_, node, 'serviceId') self.serviceId = serviceId_ elif nodeName_ == 'SCPDURL': SCPDURL_ = child_.text SCPDURL_ = self.gds_validate_string(SCPDURL_, node, 'SCPDURL') self.SCPDURL = SCPDURL_ elif nodeName_ == 'controlURL': controlURL_ = child_.text controlURL_ = self.gds_validate_string(controlURL_, node, 'controlURL') self.controlURL = controlURL_ elif nodeName_ == 'eventSubURL': eventSubURL_ = child_.text eventSubURL_ = self.gds_validate_string(eventSubURL_, node, 'eventSubURL') self.eventSubURL = eventSubURL_ # end class serviceType GDSClassesMapping = { 'serviceList': ServiceListType, 'service': serviceType, 'iconList': IconListType, 'deviceList': DeviceListType, 'device': DeviceType, 'specVersion': SpecVersionType, 'icon': iconType, } USAGE_TEXT = """ Usage: python .py [ -s ] """ def usage(): print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): tag = Tag_pattern_.match(node.tag).groups()[-1] rootClass = GDSClassesMapping.get(tag) if rootClass is None: rootClass = globals().get(tag) return tag, rootClass def parse(inFileName): doc = parsexml_(inFileName) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'root' rootClass = root rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None return rootObj def parseString(inString): from io import BytesIO doc = parsexml_(BytesIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'root' rootClass = root rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None return rootObj def parseLiteral(inFileName): doc = parsexml_(inFileName) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'root' rootClass = root rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None sys.stdout.write('#from device import *\n\n') sys.stdout.write('from datetime import datetime as datetime_\n\n') sys.stdout.write('import device as model_\n\n') sys.stdout.write('rootObj = model_.rootTag(\n') rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) sys.stdout.write(')\n') return rootObj def main(): args = sys.argv[1:] if len(args) == 1: parse(args[0]) else: usage() if __name__ == '__main__': #import pdb; pdb.set_trace() main() __all__ = [ "DeviceListType", "DeviceType", "IconListType", "ServiceListType", "SpecVersionType", "iconType", "root", "serviceType" ] ================================================ FILE: ouimeaux/device/api/xsd/device.xsd ================================================ XML Schema for UPnP device descriptions in real XSD format (not like the XDR one from Microsoft) Created by Michael Weinrich 2007 ================================================ FILE: ouimeaux/device/api/xsd/service.py ================================================ #!/usr/bin/env python # -*- coding: utf-8 -*- # # Generated Thu Jan 31 15:52:45 2013 by generateDS.py version 2.8b. # import sys import getopt import re as re_ import base64 from datetime import datetime, tzinfo, timedelta etree_ = None Verbose_import_ = False ( XMLParser_import_none, XMLParser_import_lxml, XMLParser_import_elementtree ) = range(3) XMLParser_import_library = None try: # lxml from lxml import etree as etree_ XMLParser_import_library = XMLParser_import_lxml if Verbose_import_: print("running with lxml.etree") except ImportError: try: # cElementTree from Python 2.5+ import xml.etree.cElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with cElementTree on Python 2.5+") except ImportError: try: # ElementTree from Python 2.5+ import xml.etree.ElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with ElementTree on Python 2.5+") except ImportError: try: # normal cElementTree install import cElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with cElementTree") except ImportError: try: # normal ElementTree install import elementtree.ElementTree as etree_ XMLParser_import_library = XMLParser_import_elementtree if Verbose_import_: print("running with ElementTree") except ImportError: raise ImportError( "Failed to import ElementTree from any known place") def parsexml_(*args, **kwargs): if (XMLParser_import_library == XMLParser_import_lxml and 'parser' not in kwargs): # Use the lxml ElementTree compatible parser so that, e.g., # we ignore comments. kwargs['parser'] = etree_.ETCompatXMLParser() doc = etree_.parse(*args, **kwargs) return doc # # User methods # # Calls to the methods in these classes are generated by generateDS.py. # You can replace these methods by re-implementing the following class # in a module named generatedssuper.py. try: from generatedssuper import GeneratedsSuper except ImportError as exp: class GeneratedsSuper(object): tzoff_pattern = re_.compile(r'(\+|-)((0\d|1[0-3]):[0-5]\d|14:00)$') class _FixedOffsetTZ(tzinfo): def __init__(self, offset, name): self.__offset = timedelta(minutes = offset) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return None def gds_format_string(self, input_data, input_name=''): return input_data def gds_validate_string(self, input_data, node, input_name=''): return input_data def gds_format_base64(self, input_data, input_name=''): return base64.b64encode(input_data) def gds_validate_base64(self, input_data, node, input_name=''): return input_data def gds_format_integer(self, input_data, input_name=''): return '%d' % input_data def gds_validate_integer(self, input_data, node, input_name=''): return input_data def gds_format_integer_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_integer_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: try: fvalue = float(value) except (TypeError, ValueError): raise_parse_error(node, 'Requires sequence of integers') return input_data def gds_format_float(self, input_data, input_name=''): return '%f' % input_data def gds_validate_float(self, input_data, node, input_name=''): return input_data def gds_format_float_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_float_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: try: fvalue = float(value) except (TypeError, ValueError): raise_parse_error(node, 'Requires sequence of floats') return input_data def gds_format_double(self, input_data, input_name=''): return '%e' % input_data def gds_validate_double(self, input_data, node, input_name=''): return input_data def gds_format_double_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_double_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: try: fvalue = float(value) except (TypeError, ValueError): raise_parse_error(node, 'Requires sequence of doubles') return input_data def gds_format_boolean(self, input_data, input_name=''): return '%s' % input_data def gds_validate_boolean(self, input_data, node, input_name=''): return input_data def gds_format_boolean_list(self, input_data, input_name=''): return '%s' % input_data def gds_validate_boolean_list(self, input_data, node, input_name=''): values = input_data.split() for value in values: if value not in ('true', '1', 'false', '0', ): raise_parse_error(node, 'Requires sequence of booleans ' '("true", "1", "false", "0")') return input_data def gds_validate_datetime(self, input_data, node, input_name=''): return input_data def gds_format_datetime(self, input_data, input_name=''): if input_data.microsecond == 0: _svalue = input_data.strftime('%Y-%m-%dT%H:%M:%S') else: _svalue = input_data.strftime('%Y-%m-%dT%H:%M:%S.%f') if input_data.tzinfo is not None: tzoff = input_data.tzinfo.utcoffset(input_data) if tzoff is not None: total_seconds = tzoff.seconds + (86400 * tzoff.days) if total_seconds == 0: _svalue += 'Z' else: if total_seconds < 0: _svalue += '-' total_seconds *= -1 else: _svalue += '+' hours = total_seconds // 3600 minutes = (total_seconds - (hours * 3600)) // 60 _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) return _svalue def gds_parse_datetime(self, input_data, node, input_name=''): tz = None if input_data[-1] == 'Z': tz = GeneratedsSuper._FixedOffsetTZ(0, 'GMT') input_data = input_data[:-1] else: results = GeneratedsSuper.tzoff_pattern.search(input_data) if results is not None: tzoff_parts = results.group(2).split(':') tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) if results.group(1) == '-': tzoff *= -1 tz = GeneratedsSuper._FixedOffsetTZ( tzoff, results.group(0)) input_data = input_data[:-6] if len(input_data.split('.')) > 1: dt = datetime.strptime( input_data, '%Y-%m-%dT%H:%M:%S.%f') else: dt = datetime.strptime( input_data, '%Y-%m-%dT%H:%M:%S') return dt.replace(tzinfo = tz) def gds_validate_date(self, input_data, node, input_name=''): return input_data def gds_format_date(self, input_data, input_name=''): _svalue = input_data.strftime('%Y-%m-%d') if input_data.tzinfo is not None: tzoff = input_data.tzinfo.utcoffset(input_data) if tzoff is not None: total_seconds = tzoff.seconds + (86400 * tzoff.days) if total_seconds == 0: _svalue += 'Z' else: if total_seconds < 0: _svalue += '-' total_seconds *= -1 else: _svalue += '+' hours = total_seconds // 3600 minutes = (total_seconds - (hours * 3600)) // 60 _svalue += '{0:02d}:{1:02d}'.format(hours, minutes) return _svalue def gds_parse_date(self, input_data, node, input_name=''): tz = None if input_data[-1] == 'Z': tz = GeneratedsSuper._FixedOffsetTZ(0, 'GMT') input_data = input_data[:-1] else: results = GeneratedsSuper.tzoff_pattern.search(input_data) if results is not None: tzoff_parts = results.group(2).split(':') tzoff = int(tzoff_parts[0]) * 60 + int(tzoff_parts[1]) if results.group(1) == '-': tzoff *= -1 tz = GeneratedsSuper._FixedOffsetTZ( tzoff, results.group(0)) input_data = input_data[:-6] return datetime.strptime(input_data, '%Y-%m-%d').replace(tzinfo = tz) def gds_str_lower(self, instring): return instring.lower() def get_path_(self, node): path_list = [] self.get_path_list_(node, path_list) path_list.reverse() path = '/'.join(path_list) return path Tag_strip_pattern_ = re_.compile(r'\{.*\}') def get_path_list_(self, node, path_list): if node is None: return tag = GeneratedsSuper.Tag_strip_pattern_.sub('', node.tag) if tag: path_list.append(tag) self.get_path_list_(node.getparent(), path_list) def get_class_obj_(self, node, default_class=None): class_obj1 = default_class if 'xsi' in node.nsmap: classname = node.get('{%s}type' % node.nsmap['xsi']) if classname is not None: names = classname.split(':') if len(names) == 2: classname = names[1] class_obj2 = globals().get(classname) if class_obj2 is not None: class_obj1 = class_obj2 return class_obj1 def gds_build_any(self, node, type_name=None): return None # # If you have installed IPython you can uncomment and use the following. # IPython is available from http://ipython.scipy.org/. # ## from IPython.Shell import IPShellEmbed ## args = '' ## ipshell = IPShellEmbed(args, ## banner = 'Dropping into IPython', ## exit_msg = 'Leaving Interpreter, back to program.') # Then use the following line where and when you want to drop into the # IPython shell: # ipshell(' -- Entering ipshell.\nHit Ctrl-D to exit') # # Globals # ExternalEncoding = 'ascii' Tag_pattern_ = re_.compile(r'({.*})?(.*)') String_cleanup_pat_ = re_.compile(r"[\n\r\s]+") Namespace_extract_pat_ = re_.compile(r'{(.*)}(.*)') # # Support/utility functions. # def showIndent(outfile, level, pretty_print=True): if pretty_print: for idx in range(level): outfile.write(' ') def quote_xml(inStr): if not inStr: return '' s1 = (isinstance(inStr, basestring) and inStr or '%s' % inStr) s1 = s1.replace('&', '&') s1 = s1.replace('<', '<') s1 = s1.replace('>', '>') return s1 def quote_attrib(inStr): s1 = (isinstance(inStr, basestring) and inStr or '%s' % inStr) s1 = s1.replace('&', '&') s1 = s1.replace('<', '<') s1 = s1.replace('>', '>') if '"' in s1: if "'" in s1: s1 = '"%s"' % s1.replace('"', """) else: s1 = "'%s'" % s1 else: s1 = '"%s"' % s1 return s1 def quote_python(inStr): s1 = inStr if s1.find("'") == -1: if s1.find('\n') == -1: return "'%s'" % s1 else: return "'''%s'''" % s1 else: if s1.find('"') != -1: s1 = s1.replace('"', '\\"') if s1.find('\n') == -1: return '"%s"' % s1 else: return '"""%s"""' % s1 def get_all_text_(node): if node.text is not None: text = node.text else: text = '' for child in node: if child.tail is not None: text += child.tail return text def find_attr_value_(attr_name, node): attrs = node.attrib attr_parts = attr_name.split(':') value = None if len(attr_parts) == 1: value = attrs.get(attr_name) elif len(attr_parts) == 2: prefix, name = attr_parts namespace = node.nsmap.get(prefix) if namespace is not None: value = attrs.get('{%s}%s' % (namespace, name, )) return value class GDSParseError(Exception): pass def raise_parse_error(node, msg): if XMLParser_import_library == XMLParser_import_lxml: msg = '%s (element %s/line %d)' % ( msg, node.tag, node.sourceline, ) else: msg = '%s (element %s)' % (msg, node.tag, ) raise GDSParseError(msg) class MixedContainer: # Constants for category: CategoryNone = 0 CategoryText = 1 CategorySimple = 2 CategoryComplex = 3 # Constants for content_type: TypeNone = 0 TypeText = 1 TypeString = 2 TypeInteger = 3 TypeFloat = 4 TypeDecimal = 5 TypeDouble = 6 TypeBoolean = 7 TypeBase64 = 8 def __init__(self, category, content_type, name, value): self.category = category self.content_type = content_type self.name = name self.value = value def getCategory(self): return self.category def getContenttype(self, content_type): return self.content_type def getValue(self): return self.value def getName(self): return self.name def export(self, outfile, level, name, namespace, pretty_print=True): if self.category == MixedContainer.CategoryText: # Prevent exporting empty content as empty lines. if self.value.strip(): outfile.write(self.value) elif self.category == MixedContainer.CategorySimple: self.exportSimple(outfile, level, name) else: # category == MixedContainer.CategoryComplex self.value.export(outfile, level, namespace, name, pretty_print) def exportSimple(self, outfile, level, name): if self.content_type == MixedContainer.TypeString: outfile.write('<%s>%s' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeInteger or \ self.content_type == MixedContainer.TypeBoolean: outfile.write('<%s>%d' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeFloat or \ self.content_type == MixedContainer.TypeDecimal: outfile.write('<%s>%f' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeDouble: outfile.write('<%s>%g' % (self.name, self.value, self.name)) elif self.content_type == MixedContainer.TypeBase64: outfile.write('<%s>%s' % (self.name, base64.b64encode(self.value), self.name)) def exportLiteral(self, outfile, level, name): if self.category == MixedContainer.CategoryText: showIndent(outfile, level) outfile.write('model_.MixedContainer(%d, %d, "%s", "%s"),\n' % (self.category, self.content_type, self.name, self.value)) elif self.category == MixedContainer.CategorySimple: showIndent(outfile, level) outfile.write('model_.MixedContainer(%d, %d, "%s", "%s"),\n' % (self.category, self.content_type, self.name, self.value)) else: # category == MixedContainer.CategoryComplex showIndent(outfile, level) outfile.write('model_.MixedContainer(%d, %d, "%s",\n' % \ (self.category, self.content_type, self.name,)) self.value.exportLiteral(outfile, level + 1) showIndent(outfile, level) outfile.write(')\n') class MemberSpec_(object): def __init__(self, name='', data_type='', container=0): self.name = name self.data_type = data_type self.container = container def set_name(self, name): self.name = name def get_name(self): return self.name def set_data_type(self, data_type): self.data_type = data_type def get_data_type_chain(self): return self.data_type def get_data_type(self): if isinstance(self.data_type, list): if len(self.data_type) > 0: return self.data_type[-1] else: return 'xs:string' else: return self.data_type def set_container(self, container): self.container = container def get_container(self): return self.container def _cast(typ, value): if typ is None or value is None: return value return typ(value) # # Data representation classes. # class scpd(GeneratedsSuper): subclass = None superclass = None def __init__(self, specVersion=None, actionList=None, serviceStateTable=None): self.specVersion = specVersion self.actionList = actionList self.serviceStateTable = serviceStateTable def factory(*args_, **kwargs_): if scpd.subclass: return scpd.subclass(*args_, **kwargs_) else: return scpd(*args_, **kwargs_) factory = staticmethod(factory) def get_specVersion(self): return self.specVersion def set_specVersion(self, specVersion): self.specVersion = specVersion def get_actionList(self): return self.actionList def set_actionList(self, actionList): self.actionList = actionList def get_serviceStateTable(self): return self.serviceStateTable def set_serviceStateTable(self, serviceStateTable): self.serviceStateTable = serviceStateTable def export(self, outfile, level, namespace_='', name_='scpd', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='scpd') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='scpd'): pass def exportChildren(self, outfile, level, namespace_='', name_='scpd', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.specVersion is not None: self.specVersion.export(outfile, level, namespace_, name_='specVersion', pretty_print=pretty_print) if self.actionList is not None: self.actionList.export(outfile, level, namespace_, name_='actionList', pretty_print=pretty_print) if self.serviceStateTable is not None: self.serviceStateTable.export(outfile, level, namespace_, name_='serviceStateTable', pretty_print=pretty_print) def hasContent_(self): if ( self.specVersion is not None or self.actionList is not None or self.serviceStateTable is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='scpd'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.specVersion is not None: showIndent(outfile, level) outfile.write('specVersion=model_.SpecVersionType(\n') self.specVersion.exportLiteral(outfile, level, name_='specVersion') showIndent(outfile, level) outfile.write('),\n') if self.actionList is not None: showIndent(outfile, level) outfile.write('actionList=model_.ActionListType(\n') self.actionList.exportLiteral(outfile, level, name_='actionList') showIndent(outfile, level) outfile.write('),\n') if self.serviceStateTable is not None: showIndent(outfile, level) outfile.write('serviceStateTable=model_.ServiceStateTableType(\n') self.serviceStateTable.exportLiteral(outfile, level, name_='serviceStateTable') showIndent(outfile, level) outfile.write('),\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'specVersion': obj_ = SpecVersionType.factory() obj_.build(child_) self.set_specVersion(obj_) elif nodeName_ == 'actionList': obj_ = ActionListType.factory() obj_.build(child_) self.set_actionList(obj_) elif nodeName_ == 'serviceStateTable': obj_ = ServiceStateTableType.factory() obj_.build(child_) self.set_serviceStateTable(obj_) # end class scpd class SpecVersionType(GeneratedsSuper): subclass = None superclass = None def __init__(self, major=None, minor=None): self.major = major self.minor = minor def factory(*args_, **kwargs_): if SpecVersionType.subclass: return SpecVersionType.subclass(*args_, **kwargs_) else: return SpecVersionType(*args_, **kwargs_) factory = staticmethod(factory) def get_major(self): return self.major def set_major(self, major): self.major = major def get_minor(self): return self.minor def set_minor(self, minor): self.minor = minor def export(self, outfile, level, namespace_='', name_='SpecVersionType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='SpecVersionType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='SpecVersionType'): pass def exportChildren(self, outfile, level, namespace_='', name_='SpecVersionType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.major is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smajor>%s%s' % (namespace_, self.gds_format_integer(self.major, input_name='major'), namespace_, eol_)) if self.minor is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sminor>%s%s' % (namespace_, self.gds_format_integer(self.minor, input_name='minor'), namespace_, eol_)) def hasContent_(self): if ( self.major is not None or self.minor is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='SpecVersionType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.major is not None: showIndent(outfile, level) outfile.write('major=%d,\n' % self.major) if self.minor is not None: showIndent(outfile, level) outfile.write('minor=%d,\n' % self.minor) def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'major': sval_ = child_.text try: ival_ = int(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) ival_ = self.gds_validate_integer(ival_, node, 'major') self.major = ival_ elif nodeName_ == 'minor': sval_ = child_.text try: ival_ = int(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires integer: %s' % exp) ival_ = self.gds_validate_integer(ival_, node, 'minor') self.minor = ival_ # end class SpecVersionType class ActionListType(GeneratedsSuper): subclass = None superclass = None def __init__(self, action=None): if action is None: self.action = [] else: self.action = action def factory(*args_, **kwargs_): if ActionListType.subclass: return ActionListType.subclass(*args_, **kwargs_) else: return ActionListType(*args_, **kwargs_) factory = staticmethod(factory) def get_action(self): return self.action def set_action(self, action): self.action = action def add_action(self, value): self.action.append(value) def insert_action(self, index, value): self.action[index] = value def export(self, outfile, level, namespace_='', name_='ActionListType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActionListType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActionListType'): pass def exportChildren(self, outfile, level, namespace_='', name_='ActionListType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' for action_ in self.action: action_.export(outfile, level, namespace_, name_='action', pretty_print=pretty_print) def hasContent_(self): if ( self.action ): return True else: return False def exportLiteral(self, outfile, level, name_='ActionListType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): showIndent(outfile, level) outfile.write('action=[\n') level += 1 for action_ in self.action: showIndent(outfile, level) outfile.write('model_.ActionType(\n') action_.exportLiteral(outfile, level, name_='ActionType') showIndent(outfile, level) outfile.write('),\n') level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'action': obj_ = ActionType.factory() obj_.build(child_) self.action.append(obj_) # end class ActionListType class ActionType(GeneratedsSuper): subclass = None superclass = None def __init__(self, name=None, argumentList=None): self.name = name self.argumentList = argumentList def factory(*args_, **kwargs_): if ActionType.subclass: return ActionType.subclass(*args_, **kwargs_) else: return ActionType(*args_, **kwargs_) factory = staticmethod(factory) def get_name(self): return self.name def set_name(self, name): self.name = name def get_argumentList(self): return self.argumentList def set_argumentList(self, argumentList): self.argumentList = argumentList def export(self, outfile, level, namespace_='', name_='ActionType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='ActionType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ActionType'): pass def exportChildren(self, outfile, level, namespace_='', name_='ActionType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.name is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sname>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_, eol_)) if self.argumentList is not None: self.argumentList.export(outfile, level, namespace_, name_='argumentList', pretty_print=pretty_print) def hasContent_(self): if ( self.name is not None or self.argumentList is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='ActionType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.name is not None: showIndent(outfile, level) outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) if self.argumentList is not None: showIndent(outfile, level) outfile.write('argumentList=model_.ArgumentListType(\n') self.argumentList.exportLiteral(outfile, level, name_='argumentList') showIndent(outfile, level) outfile.write('),\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'name': name_ = child_.text name_ = self.gds_validate_string(name_, node, 'name') self.name = name_ elif nodeName_ == 'argumentList': obj_ = ArgumentListType.factory() obj_.build(child_) self.set_argumentList(obj_) # end class ActionType class ArgumentListType(GeneratedsSuper): subclass = None superclass = None def __init__(self, argument=None): if argument is None: self.argument = [] else: self.argument = argument def factory(*args_, **kwargs_): if ArgumentListType.subclass: return ArgumentListType.subclass(*args_, **kwargs_) else: return ArgumentListType(*args_, **kwargs_) factory = staticmethod(factory) def get_argument(self): return self.argument def set_argument(self, argument): self.argument = argument def add_argument(self, value): self.argument.append(value) def insert_argument(self, index, value): self.argument[index] = value def export(self, outfile, level, namespace_='', name_='ArgumentListType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='ArgumentListType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ArgumentListType'): pass def exportChildren(self, outfile, level, namespace_='', name_='ArgumentListType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' for argument_ in self.argument: argument_.export(outfile, level, namespace_, name_='argument', pretty_print=pretty_print) def hasContent_(self): if ( self.argument ): return True else: return False def exportLiteral(self, outfile, level, name_='ArgumentListType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): showIndent(outfile, level) outfile.write('argument=[\n') level += 1 for argument_ in self.argument: showIndent(outfile, level) outfile.write('model_.ArgumentType(\n') argument_.exportLiteral(outfile, level, name_='ArgumentType') showIndent(outfile, level) outfile.write('),\n') level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'argument': obj_ = ArgumentType.factory() obj_.build(child_) self.argument.append(obj_) # end class ArgumentListType class ArgumentType(GeneratedsSuper): subclass = None superclass = None def __init__(self, name=None, direction=None, relatedStateVariable=None, retval=None): self.name = name self.direction = direction self.relatedStateVariable = relatedStateVariable self.retval = retval def factory(*args_, **kwargs_): if ArgumentType.subclass: return ArgumentType.subclass(*args_, **kwargs_) else: return ArgumentType(*args_, **kwargs_) factory = staticmethod(factory) def get_name(self): return self.name def set_name(self, name): self.name = name def get_direction(self): return self.direction def set_direction(self, direction): self.direction = direction def get_relatedStateVariable(self): return self.relatedStateVariable def set_relatedStateVariable(self, relatedStateVariable): self.relatedStateVariable = relatedStateVariable def get_retval(self): return self.retval def set_retval(self, retval): self.retval = retval def export(self, outfile, level, namespace_='', name_='ArgumentType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='ArgumentType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ArgumentType'): pass def exportChildren(self, outfile, level, namespace_='', name_='ArgumentType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.name is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sname>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_, eol_)) if self.direction is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sdirection>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.direction).encode(ExternalEncoding), input_name='direction'), namespace_, eol_)) if self.relatedStateVariable is not None: showIndent(outfile, level, pretty_print) outfile.write('<%srelatedStateVariable>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.relatedStateVariable).encode(ExternalEncoding), input_name='relatedStateVariable'), namespace_, eol_)) if self.retval is not None: self.retval.export(outfile, level, namespace_, name_='retval', pretty_print=pretty_print) def hasContent_(self): if ( self.name is not None or self.direction is not None or self.relatedStateVariable is not None or self.retval is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='ArgumentType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.name is not None: showIndent(outfile, level) outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) if self.direction is not None: showIndent(outfile, level) outfile.write('direction=%s,\n' % quote_python(self.direction).encode(ExternalEncoding)) if self.relatedStateVariable is not None: showIndent(outfile, level) outfile.write('relatedStateVariable=%s,\n' % quote_python(self.relatedStateVariable).encode(ExternalEncoding)) if self.retval is not None: showIndent(outfile, level) outfile.write('retval=model_.retvalType(\n') self.retval.exportLiteral(outfile, level, name_='retval') showIndent(outfile, level) outfile.write('),\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'name': name_ = child_.text name_ = self.gds_validate_string(name_, node, 'name') self.name = name_ elif nodeName_ == 'direction': direction_ = child_.text direction_ = self.gds_validate_string(direction_, node, 'direction') self.direction = direction_ elif nodeName_ == 'relatedStateVariable': relatedStateVariable_ = child_.text relatedStateVariable_ = self.gds_validate_string(relatedStateVariable_, node, 'relatedStateVariable') self.relatedStateVariable = relatedStateVariable_ elif nodeName_ == 'retval': obj_ = retvalType.factory() obj_.build(child_) self.set_retval(obj_) # end class ArgumentType class ServiceStateTableType(GeneratedsSuper): subclass = None superclass = None def __init__(self, stateVariable=None): if stateVariable is None: self.stateVariable = [] else: self.stateVariable = stateVariable def factory(*args_, **kwargs_): if ServiceStateTableType.subclass: return ServiceStateTableType.subclass(*args_, **kwargs_) else: return ServiceStateTableType(*args_, **kwargs_) factory = staticmethod(factory) def get_stateVariable(self): return self.stateVariable def set_stateVariable(self, stateVariable): self.stateVariable = stateVariable def add_stateVariable(self, value): self.stateVariable.append(value) def insert_stateVariable(self, index, value): self.stateVariable[index] = value def export(self, outfile, level, namespace_='', name_='ServiceStateTableType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='ServiceStateTableType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='ServiceStateTableType'): pass def exportChildren(self, outfile, level, namespace_='', name_='ServiceStateTableType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' for stateVariable_ in self.stateVariable: stateVariable_.export(outfile, level, namespace_, name_='stateVariable', pretty_print=pretty_print) def hasContent_(self): if ( self.stateVariable ): return True else: return False def exportLiteral(self, outfile, level, name_='ServiceStateTableType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): showIndent(outfile, level) outfile.write('stateVariable=[\n') level += 1 for stateVariable_ in self.stateVariable: showIndent(outfile, level) outfile.write('model_.StateVariableType(\n') stateVariable_.exportLiteral(outfile, level, name_='StateVariableType') showIndent(outfile, level) outfile.write('),\n') level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'stateVariable': obj_ = StateVariableType.factory() obj_.build(child_) self.stateVariable.append(obj_) # end class ServiceStateTableType class StateVariableType(GeneratedsSuper): subclass = None superclass = None def __init__(self, sendEvents='yes', name=None, dataType=None, defaultValue=None, allowedValueList=None, allowedValueRange=None): self.sendEvents = _cast(None, sendEvents) self.name = name self.dataType = dataType self.defaultValue = defaultValue self.allowedValueList = allowedValueList self.allowedValueRange = allowedValueRange def factory(*args_, **kwargs_): if StateVariableType.subclass: return StateVariableType.subclass(*args_, **kwargs_) else: return StateVariableType(*args_, **kwargs_) factory = staticmethod(factory) def get_name(self): return self.name def set_name(self, name): self.name = name def get_dataType(self): return self.dataType def set_dataType(self, dataType): self.dataType = dataType def get_defaultValue(self): return self.defaultValue def set_defaultValue(self, defaultValue): self.defaultValue = defaultValue def get_allowedValueList(self): return self.allowedValueList def set_allowedValueList(self, allowedValueList): self.allowedValueList = allowedValueList def get_allowedValueRange(self): return self.allowedValueRange def set_allowedValueRange(self, allowedValueRange): self.allowedValueRange = allowedValueRange def get_sendEvents(self): return self.sendEvents def set_sendEvents(self, sendEvents): self.sendEvents = sendEvents def export(self, outfile, level, namespace_='', name_='StateVariableType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='StateVariableType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='StateVariableType'): if self.sendEvents is not None and 'sendEvents' not in already_processed: already_processed.append('sendEvents') outfile.write(' sendEvents=%s' % (self.gds_format_string(quote_attrib(self.sendEvents).encode(ExternalEncoding), input_name='sendEvents'), )) def exportChildren(self, outfile, level, namespace_='', name_='StateVariableType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.name is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sname>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.name).encode(ExternalEncoding), input_name='name'), namespace_, eol_)) if self.dataType is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sdataType>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.dataType).encode(ExternalEncoding), input_name='dataType'), namespace_, eol_)) if self.defaultValue is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sdefaultValue>%s%s' % (namespace_, self.gds_format_string(quote_xml(self.defaultValue).encode(ExternalEncoding), input_name='defaultValue'), namespace_, eol_)) if self.allowedValueList is not None: self.allowedValueList.export(outfile, level, namespace_, name_='allowedValueList', pretty_print=pretty_print) if self.allowedValueRange is not None: self.allowedValueRange.export(outfile, level, namespace_, name_='allowedValueRange', pretty_print=pretty_print) def hasContent_(self): if ( self.name is not None or self.dataType is not None or self.defaultValue is not None or self.allowedValueList is not None or self.allowedValueRange is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='StateVariableType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): if self.sendEvents is not None and 'sendEvents' not in already_processed: already_processed.append('sendEvents') showIndent(outfile, level) outfile.write('sendEvents = "%s",\n' % (self.sendEvents,)) def exportLiteralChildren(self, outfile, level, name_): if self.name is not None: showIndent(outfile, level) outfile.write('name=%s,\n' % quote_python(self.name).encode(ExternalEncoding)) if self.dataType is not None: showIndent(outfile, level) outfile.write('dataType=%s,\n' % quote_python(self.dataType).encode(ExternalEncoding)) if self.defaultValue is not None: showIndent(outfile, level) outfile.write('defaultValue=%s,\n' % quote_python(self.defaultValue).encode(ExternalEncoding)) if self.allowedValueList is not None: showIndent(outfile, level) outfile.write('allowedValueList=model_.AllowedValueListType(\n') self.allowedValueList.exportLiteral(outfile, level, name_='allowedValueList') showIndent(outfile, level) outfile.write('),\n') if self.allowedValueRange is not None: showIndent(outfile, level) outfile.write('allowedValueRange=model_.AllowedValueRangeType(\n') self.allowedValueRange.exportLiteral(outfile, level, name_='allowedValueRange') showIndent(outfile, level) outfile.write('),\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): value = find_attr_value_('sendEvents', node) if value is not None and 'sendEvents' not in already_processed: already_processed.append('sendEvents') self.sendEvents = value def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'name': name_ = child_.text name_ = self.gds_validate_string(name_, node, 'name') self.name = name_ elif nodeName_ == 'dataType': dataType_ = child_.text dataType_ = self.gds_validate_string(dataType_, node, 'dataType') self.dataType = dataType_ elif nodeName_ == 'defaultValue': defaultValue_ = child_.text defaultValue_ = self.gds_validate_string(defaultValue_, node, 'defaultValue') self.defaultValue = defaultValue_ elif nodeName_ == 'allowedValueList': obj_ = AllowedValueListType.factory() obj_.build(child_) self.set_allowedValueList(obj_) elif nodeName_ == 'allowedValueRange': obj_ = AllowedValueRangeType.factory() obj_.build(child_) self.set_allowedValueRange(obj_) # end class StateVariableType class AllowedValueListType(GeneratedsSuper): subclass = None superclass = None def __init__(self, allowedValue=None): if allowedValue is None: self.allowedValue = [] else: self.allowedValue = allowedValue def factory(*args_, **kwargs_): if AllowedValueListType.subclass: return AllowedValueListType.subclass(*args_, **kwargs_) else: return AllowedValueListType(*args_, **kwargs_) factory = staticmethod(factory) def get_allowedValue(self): return self.allowedValue def set_allowedValue(self, allowedValue): self.allowedValue = allowedValue def add_allowedValue(self, value): self.allowedValue.append(value) def insert_allowedValue(self, index, value): self.allowedValue[index] = value def export(self, outfile, level, namespace_='', name_='AllowedValueListType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='AllowedValueListType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AllowedValueListType'): pass def exportChildren(self, outfile, level, namespace_='', name_='AllowedValueListType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' for allowedValue_ in self.allowedValue: showIndent(outfile, level, pretty_print) outfile.write('<%sallowedValue>%s%s' % (namespace_, self.gds_format_string(quote_xml(allowedValue_).encode(ExternalEncoding), input_name='allowedValue'), namespace_, eol_)) def hasContent_(self): if ( self.allowedValue ): return True else: return False def exportLiteral(self, outfile, level, name_='AllowedValueListType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): showIndent(outfile, level) outfile.write('allowedValue=[\n') level += 1 for allowedValue_ in self.allowedValue: showIndent(outfile, level) outfile.write('%s,\n' % quote_python(allowedValue_).encode(ExternalEncoding)) level -= 1 showIndent(outfile, level) outfile.write('],\n') def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'allowedValue': allowedValue_ = child_.text allowedValue_ = self.gds_validate_string(allowedValue_, node, 'allowedValue') self.allowedValue.append(allowedValue_) # end class AllowedValueListType class AllowedValueRangeType(GeneratedsSuper): subclass = None superclass = None def __init__(self, minimum=None, maximum=None, step=None): self.minimum = minimum self.maximum = maximum self.step = step def factory(*args_, **kwargs_): if AllowedValueRangeType.subclass: return AllowedValueRangeType.subclass(*args_, **kwargs_) else: return AllowedValueRangeType(*args_, **kwargs_) factory = staticmethod(factory) def get_minimum(self): return self.minimum def set_minimum(self, minimum): self.minimum = minimum def get_maximum(self): return self.maximum def set_maximum(self, maximum): self.maximum = maximum def get_step(self): return self.step def set_step(self, step): self.step = step def export(self, outfile, level, namespace_='', name_='AllowedValueRangeType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='AllowedValueRangeType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) showIndent(outfile, level, pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='AllowedValueRangeType'): pass def exportChildren(self, outfile, level, namespace_='', name_='AllowedValueRangeType', fromsubclass_=False, pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' if self.minimum is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sminimum>%s%s' % (namespace_, self.gds_format_float(self.minimum, input_name='minimum'), namespace_, eol_)) if self.maximum is not None: showIndent(outfile, level, pretty_print) outfile.write('<%smaximum>%s%s' % (namespace_, self.gds_format_float(self.maximum, input_name='maximum'), namespace_, eol_)) if self.step is not None: showIndent(outfile, level, pretty_print) outfile.write('<%sstep>%s%s' % (namespace_, self.gds_format_float(self.step, input_name='step'), namespace_, eol_)) def hasContent_(self): if ( self.minimum is not None or self.maximum is not None or self.step is not None ): return True else: return False def exportLiteral(self, outfile, level, name_='AllowedValueRangeType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): if self.minimum is not None: showIndent(outfile, level) outfile.write('minimum=%f,\n' % self.minimum) if self.maximum is not None: showIndent(outfile, level) outfile.write('maximum=%f,\n' % self.maximum) if self.step is not None: showIndent(outfile, level) outfile.write('step=%f,\n' % self.step) def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): if nodeName_ == 'minimum': sval_ = child_.text try: fval_ = float(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires float or double: %s' % exp) fval_ = self.gds_validate_float(fval_, node, 'minimum') self.minimum = fval_ elif nodeName_ == 'maximum': sval_ = child_.text try: fval_ = float(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires float or double: %s' % exp) fval_ = self.gds_validate_float(fval_, node, 'maximum') self.maximum = fval_ elif nodeName_ == 'step': sval_ = child_.text try: fval_ = float(sval_) except (TypeError, ValueError) as exp: raise_parse_error(child_, 'requires float or double: %s' % exp) fval_ = self.gds_validate_float(fval_, node, 'step') self.step = fval_ # end class AllowedValueRangeType class retvalType(GeneratedsSuper): subclass = None superclass = None def __init__(self): pass def factory(*args_, **kwargs_): if retvalType.subclass: return retvalType.subclass(*args_, **kwargs_) else: return retvalType(*args_, **kwargs_) factory = staticmethod(factory) def export(self, outfile, level, namespace_='', name_='retvalType', namespacedef_='', pretty_print=True): if pretty_print: eol_ = '\n' else: eol_ = '' showIndent(outfile, level, pretty_print) outfile.write('<%s%s%s' % (namespace_, name_, namespacedef_ and ' ' + namespacedef_ or '', )) already_processed = [] self.exportAttributes(outfile, level, already_processed, namespace_, name_='retvalType') if self.hasContent_(): outfile.write('>%s' % (eol_, )) self.exportChildren(outfile, level + 1, namespace_, name_, pretty_print=pretty_print) outfile.write('%s' % (namespace_, name_, eol_)) else: outfile.write('/>%s' % (eol_, )) def exportAttributes(self, outfile, level, already_processed, namespace_='', name_='retvalType'): pass def exportChildren(self, outfile, level, namespace_='', name_='retvalType', fromsubclass_=False, pretty_print=True): pass def hasContent_(self): if ( ): return True else: return False def exportLiteral(self, outfile, level, name_='retvalType'): level += 1 self.exportLiteralAttributes(outfile, level, [], name_) if self.hasContent_(): self.exportLiteralChildren(outfile, level, name_) def exportLiteralAttributes(self, outfile, level, already_processed, name_): pass def exportLiteralChildren(self, outfile, level, name_): pass def build(self, node): self.buildAttributes(node, node.attrib, []) for child in node: nodeName_ = Tag_pattern_.match(child.tag).groups()[-1] self.buildChildren(child, node, nodeName_) def buildAttributes(self, node, attrs, already_processed): pass def buildChildren(self, child_, node, nodeName_, fromsubclass_=False): pass # end class retvalType GDSClassesMapping = { 'argumentList': ArgumentListType, 'actionList': ActionListType, 'retval': retvalType, 'stateVariable': StateVariableType, 'argument': ArgumentType, 'action': ActionType, 'serviceStateTable': ServiceStateTableType, 'allowedValueRange': AllowedValueRangeType, 'specVersion': SpecVersionType, 'allowedValueList': AllowedValueListType, } USAGE_TEXT = """ Usage: python .py [ -s ] """ def usage(): print(USAGE_TEXT) sys.exit(1) def get_root_tag(node): tag = Tag_pattern_.match(node.tag).groups()[-1] rootClass = GDSClassesMapping.get(tag) if rootClass is None: rootClass = globals().get(tag) return tag, rootClass def parse(inFileName): doc = parsexml_(inFileName) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'scpd' rootClass = scpd rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None return rootObj def parseString(inString): from io import BytesIO doc = parsexml_(BytesIO(inString)) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'scpd' rootClass = scpd rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None return rootObj def parseLiteral(inFileName): doc = parsexml_(inFileName) rootNode = doc.getroot() rootTag, rootClass = get_root_tag(rootNode) if rootClass is None: rootTag = 'scpd' rootClass = scpd rootObj = rootClass.factory() rootObj.build(rootNode) # Enable Python to collect the space used by the DOM. doc = None sys.stdout.write('#from service import *\n\n') sys.stdout.write('from datetime import datetime as datetime_\n\n') sys.stdout.write('import service as model_\n\n') sys.stdout.write('rootObj = model_.rootTag(\n') rootObj.exportLiteral(sys.stdout, 0, name_=rootTag) sys.stdout.write(')\n') return rootObj def main(): args = sys.argv[1:] if len(args) == 1: parse(args[0]) else: usage() if __name__ == '__main__': #import pdb; pdb.set_trace() main() __all__ = [ "ActionListType", "ActionType", "AllowedValueListType", "AllowedValueRangeType", "ArgumentListType", "ArgumentType", "ServiceStateTableType", "SpecVersionType", "StateVariableType", "retvalType", "scpd" ] ================================================ FILE: ouimeaux/device/api/xsd/service.xsd ================================================ XML Schema for UPnP service descriptions in real XSD format (not like the XDR one from Microsoft) Created by Michael Weinrich 2007 ================================================ FILE: ouimeaux/device/bridge.py ================================================ from ouimeaux.device import Device from xml.etree import ElementTree as et class Bridge(Device): Lights = {} Groups = {} def __repr__(self): self.bridge_get_lights() self.bridge_get_groups() return ''.format(name=self.name, LightCount=len(self.Lights), GroupCount=len(self.Groups)) def bridge_get_lights(self): UDN = self.basicevent.GetMacAddr().get('PluginUDN') endDevices = self.bridge.GetEndDevices(DevUDN=UDN,ReqListType='PAIRED_LIST') endDeviceList = et.fromstring(endDevices.get('DeviceLists')) for light in endDeviceList.iter('DeviceInfo'): if self.light_name(light) in self.Lights: pass else: self.Lights[self.light_name(light)] = light return self.Lights def bridge_get_groups(self): UDN = self.basicevent.GetMacAddr().get('PluginUDN') endDevices = self.bridge.GetEndDevices(DevUDN=UDN,ReqListType='PAIRED_LIST') endDeviceList = et.fromstring(endDevices.get('DeviceLists')) for group in endDeviceList.iter('GroupInfo'): if self.group_name(group) in self.Groups: pass else: self.Groups[self.group_name(group)] = group return self.Groups def light_attributes(self, light): return { 'devIndex' : light.find('DeviceIndex').text, 'devID' : light.find('DeviceID').text, 'name' : light.find('FriendlyName').text, 'iconvalue' : light.find('IconVersion').text, 'firmware' : light.find('FirmwareVersion').text, 'capabilities' : light.find('CapabilityIDs').text, 'state' : light.find('CurrentState').text, 'manufacturer' : light.find('Manufacturer').text, 'model' : light.find('ModelCode').text, 'certified' : light.find('WeMoCertified').text } def group_attributes(self, group): return { 'GroupID' : group.find('GroupID').text, 'name' : group.find('GroupName').text, 'capabilities' : group.find('GroupCapabilityIDs').text, 'state': group.find('GroupCapabilityValues').text } def light_name(self, light): return self.light_attributes(light).get('name') def group_name(self, group): return self.group_attributes(group).get('name') def light_get_id(self, light): return self.light_attributes(light).get('devID') def group_get_id(self, group): return self.group_attributes(group).get('GroupID') def light_get_state(self, light): attr = self.light_attributes(light).get('state').split(':', 1)[0].split(',') state = attr[0] # 0 (off) or 1 (on) dim = attr[1] # 0-255 dark to bright return { 'state' : state, 'dim' : dim } def group_get_state(self, group): attr = self.group_attributes(group).get('state').split(':', 1)[0].split(',') state = attr[0] # 0 (off) or 1 (on) dim = attr[1] # 0-255 dark to bright return { 'state' : state, 'dim' : dim } # Specify either a state or dim - not both. When specifying dim you can also specify a transition duration to dim across. # This resolves issues that appear to have been caused by a firmware update ~ mid 2016. # Details at https://github.com/iancmcc/ouimeaux/issues/132. def light_set_state(self, light, state=None, dim=None, transition_duration=0): if not state == None: sendState = '<?xml version="1.0" encoding="UTF-8"?><DeviceStatus><IsGroupAction>NO</IsGroupAction><DeviceID available="YES">{devID}</DeviceID><CapabilityID>10006</CapabilityID><CapabilityValue>{state}</CapabilityValue></DeviceStatus>'.format(devID=self.light_get_id(light),state=state) elif not dim == None: sendState = '<?xml version="1.0" encoding="UTF-8"?><DeviceStatus><IsGroupAction>NO</IsGroupAction><DeviceID available="YES">{devID}</DeviceID><CapabilityID>10008</CapabilityID><CapabilityValue>{dim}:{duration}</CapabilityValue></DeviceStatus>'.format(devID=self.light_get_id(light),dim=dim,duration=transition_duration) return self.bridge.SetDeviceStatus(DeviceStatusList=sendState) def group_set_state(self, group, state=None, dim=None): if state == None: state = self.group_get_state(group).get('state') if dim == None: dim = self.group_get_state(group).get('dim') sendState = '<?xml version="1.0" encoding="UTF-8"?><DeviceStatus><IsGroupAction>YES</IsGroupAction><DeviceID available="YES">{groupID}</DeviceID><CapabilityID>10006</CapabilityID><CapabilityValue>{state}</CapabilityValue><CapabilityID>10008</CapabilityID><CapabilityValue>{dim}</CapabilityValue></DeviceStatus>'.format(groupID=self.group_get_id(group),state=state,dim=dim) return self.bridge.SetDeviceStatus(DeviceStatusList=sendState) ================================================ FILE: ouimeaux/device/insight.py ================================================ from datetime import datetime from .switch import Switch class Insight(Switch): def __repr__(self): return ''.format(name=self.name) @property def insight_params(self): params = self.insight.GetInsightParams().get('InsightParams') ( state, # 0 if off, 1 if on, 8 if on but load is off lastchange, onfor, # seconds ontoday, # seconds ontotal, # seconds timeperiod, # The period over which averages are calculated _x, # This one is always 19 for me; what is it? currentmw, todaymw, totalmw, powerthreshold ) = params.split('|') return {'state': state, 'lastchange': datetime.fromtimestamp(int(lastchange)), 'onfor': int(onfor), 'ontoday': int(ontoday), 'ontotal': int(ontotal), 'todaymw': int(float(todaymw)), 'totalmw': int(float(totalmw)), 'currentpower': int(float(currentmw))} @property def today_kwh(self): return self.insight_params['todaymw'] * 1.6666667e-8 @property def current_power(self): """ Returns the current power usage in mW. """ return self.insight_params['currentpower'] @property def today_on_time(self): return self.insight_params['ontoday'] @property def on_for(self): return self.insight_params['onfor'] @property def last_change(self): return self.insight_params['lastchange'] @property def today_standby_time(self): return self.insight_params['ontoday'] @property def ontotal(self): return self.insight_params['ontotal'] @property def totalmw(self): return self.insight_params['totalmw'] ================================================ FILE: ouimeaux/device/lightswitch.py ================================================ from .switch import Switch class LightSwitch(Switch): def __repr__(self): return ''.format(name=self.name) ================================================ FILE: ouimeaux/device/maker.py ================================================ from datetime import datetime from ouimeaux.device import Device from xml.etree import ElementTree as et class Maker(Device): def __repr__(self): return ''.format(name=self.name) def get_state(self, force_update=False): """ Returns 0 if off and 1 if on. """ # The base implementation using GetBinaryState doesn't work for Maker (always returns 0). # So pull the switch state from the atrributes instead if force_update or self._state is None: return(int(self.maker_attribs.get('switchstate',0))) return self._state def set_state(self, state): """ Set the state of this device to on or off. """ self.basicevent.SetBinaryState(BinaryState=int(state)) self._state = int(state) def off(self): """ Turn this device off. If already off, will return "Error". """ return self.set_state(0) def on(self): """ Turn this device on. If already on, will return "Error". """ return self.set_state(1) @property def maker_attribs(self): makerresp = self.deviceevent.GetAttributes().get('attributeList') makerresp = "" + makerresp + "" makerresp = makerresp.replace(">",">") makerresp = makerresp.replace("<","<") attributes = et.fromstring(makerresp) for attribute in attributes: if attribute[0].text == "Switch": switchstate = attribute[1].text elif attribute[0].text == "Sensor": sensorstate = attribute[1].text elif attribute[0].text == "SwitchMode": switchmode = attribute[1].text elif attribute[0].text == "SensorPresent": hassensor = attribute[1].text return { 'switchstate' : int(switchstate), 'sensorstate' : int(sensorstate), 'switchmode' : int(switchmode), 'hassensor' : int(hassensor)} @property def switch_state(self): return self.maker_attribs['switchstate'] @property def sensor_state(self): return self.maker_attribs['sensorstate'] @property def switch_mode(self): return self.maker_attribs['switchmode'] @property def has_sensor(self): return self.maker_attribs['hassensor'] ================================================ FILE: ouimeaux/device/motion.py ================================================ from ouimeaux.device import Device class Motion(Device): def __repr__(self): return ''.format(name=self.name) ================================================ FILE: ouimeaux/device/switch.py ================================================ import gevent from ouimeaux.device import Device class Switch(Device): def set_state(self, state): """ Set the state of this device to on or off. """ self.basicevent.SetBinaryState(BinaryState=int(state)) self._state = int(state) def off(self): """ Turn this device off. If already off, will return "Error". """ return self.set_state(0) def on(self): """ Turn this device on. If already on, will return "Error". """ return self.set_state(1) def toggle(self): """ Toggle the switch's state. """ return self.set_state(not self.get_state()) def blink(self, delay=1): """ Toggle the switch once, then again after a delay (in seconds). """ self.toggle() gevent.spawn_later(delay, self.toggle) def __repr__(self): return ''.format(name=self.name) ================================================ FILE: ouimeaux/discovery.py ================================================ import logging import gevent from gevent import socket from gevent.server import DatagramServer from ouimeaux.utils import get_ip_address from ouimeaux.pysignals import receiver from ouimeaux.signals import discovered log = logging.getLogger(__name__) class UPnPLoopbackException(Exception): """ Using loopback interface as callback IP. """ class UPnP(object): """ Makes M-SEARCH requests, filters out non-WeMo responses, and dispatches signals with the results. """ def __init__(self, mcast_ip='239.255.255.250', mcast_port=1900, bind=None): if bind is None: host = get_ip_address() if host.startswith('127.'): raise UPnPLoopbackException("Using %s as a callback IP for " "discovery will not be successful.") port = 54321 bind = '{0}:{1}'.format(host, port) self.bind = bind self.mcast_ip = mcast_ip self.mcast_port = mcast_port self.clients = {} def _response_received(self, message, address): log.debug("Received a response from {0}:{1}".format(*address)) lines = [x.decode() for x in message.splitlines()] lines.pop(0) # HTTP status headers = {} for line in lines: try: header, value = line.split(":", 1) headers[header.lower()] = value.strip() except ValueError: continue if (headers.get('x-user-agent', None) == 'redsonic'): location=headers.get('location',None) if location is not None and location not in self.clients: log.debug("Found WeMo at {0}".format(location)) self.clients[location] = headers gevent.spawn(discovered.send, self, address=address, headers=headers) @property def server(self): """ UDP server to listen for responses. """ server = getattr(self, "_server", None) if server is None: log.debug("Binding datagram server to %s", self.bind) server = DatagramServer(self.bind, self._response_received) self._server = server return server def broadcast(self): """ Send a multicast M-SEARCH request asking for devices to report in. """ log.debug("Broadcasting M-SEARCH to %s:%s", self.mcast_ip, self.mcast_port) request = '\r\n'.join(("M-SEARCH * HTTP/1.1", "HOST:{mcast_ip}:{mcast_port}", "ST:upnp:rootdevice", "MX:2", 'MAN:"ssdp:discover"', "", "")).format(**self.__dict__) self.server.sendto(request.encode(), (self.mcast_ip, self.mcast_port)) def test(): logging.basicConfig(level=logging.DEBUG) @receiver(discovered) def handler(sender, **kwargs): print("I GOT ONE") print(kwargs['address'], kwargs['headers']) upnp = UPnP() upnp.server.set_spawn(1) upnp.server.start() log.debug("Started server, listening for responses") with gevent.Timeout(2, KeyboardInterrupt): while True: try: upnp.broadcast() gevent.sleep(2) except KeyboardInterrupt: break if __name__ == "__main__": test() ================================================ FILE: ouimeaux/environment.py ================================================ import logging import gevent import requests from ouimeaux.config import WemoConfiguration from ouimeaux.device import DeviceUnreachable from ouimeaux.device.switch import Switch from ouimeaux.device.insight import Insight from ouimeaux.device.maker import Maker from ouimeaux.device.lightswitch import LightSwitch from ouimeaux.device.motion import Motion from ouimeaux.device.bridge import Bridge from ouimeaux.discovery import UPnP from ouimeaux.signals import discovered, devicefound from ouimeaux.subscribe import SubscriptionRegistry from ouimeaux.utils import matcher _MARKER = object() _NOOP = lambda *x: None log = logging.getLogger(__name__) reqlog = logging.getLogger("requests") reqlog.disabled = True class StopBroadcasting(Exception): pass class UnknownDevice(Exception): pass class Environment(object): def __init__(self, switch_callback=_NOOP, motion_callback=_NOOP, bridge_callback=_NOOP, maker_callback=_NOOP, with_discovery=True, with_subscribers=True, with_cache=_MARKER, bind=None, config_filename=None): """ Create a WeMo environment. @param switch_callback: A function to be called when a new switch is discovered. @type switch_callback: function @param motion_callback: A function to be called when a new motion is discovered. @type motion_callback: function @param with_subscribers: Whether to register for events with discovered devices. @type with_subscribers: bool @param bind: ip:port to which to bind the response server. @type bind: str """ if with_cache is not _MARKER: log.warn("with_cache argument is deprecated (and nonfunctional)") self._config = WemoConfiguration(filename=config_filename) self.upnp = UPnP(bind=bind or self._config.bind) discovered.connect(self._found_device, self.upnp) self.registry = SubscriptionRegistry() self._with_discovery = with_discovery self._with_subscribers = with_subscribers self._switch_callback = switch_callback self._motion_callback = motion_callback self._bridge_callback = bridge_callback self._maker_callback = maker_callback self._switches = {} self._motions = {} self._bridges = {} self._makers = {} self.devices = {} def __iter__(self): return self.devices.itervalues() def start(self): """ Start the server(s) necessary to receive information from devices. """ if self._with_discovery: # Start the server to listen to new devices self.upnp.server.set_spawn(2) self.upnp.server.start() if self._with_subscribers: # Start the server to listen to events self.registry.server.set_spawn(2) self.registry.server.start() def wait(self, timeout=None): """ Wait for events. """ try: if timeout: gevent.sleep(timeout) else: while True: gevent.sleep(1000) except (KeyboardInterrupt, SystemExit, Exception): pass def discover(self, seconds=2): """ Discover devices in the environment. @param seconds: Number of seconds to broadcast requests. @type seconds: int """ log.info("Discovering devices") with gevent.Timeout(seconds, StopBroadcasting) as timeout: try: try: while True: self.upnp.broadcast() gevent.sleep(1) except Exception as e: raise StopBroadcasting(e) except StopBroadcasting: return def _found_device(self, sender, **kwargs): address = kwargs['address'] headers = kwargs['headers'] usn = headers['usn'] if usn.startswith('uuid:Socket'): klass = Switch elif usn.startswith('uuid:Lightswitch'): klass = LightSwitch elif usn.startswith('uuid:Insight'): klass = Insight elif usn.startswith('uuid:Sensor'): klass = Motion elif usn.startswith('uuid:Bridge'): klass = Bridge elif usn.startswith('uuid:Maker'): klass = Maker else: log.info("Unrecognized device type. USN={0}".format(usn)) return device = klass(headers['location']) log.info("Found device %r at %s" % (device, address)) self._process_device(device) def _process_device(self, device): if isinstance(device, Switch): callback = self._switch_callback registry = self._switches elif isinstance(device, Motion): callback = self._motion_callback registry = self._motions elif isinstance(device, Bridge): callback = self._bridge_callback registry = self._bridges for light in device.Lights: log.info("Found light \"%s\" connected to \"%s\"" % (light, device.name)) for group in device.Groups: log.info("Found group \"%s\" connected to \"%s\"" % (group, device.name)) elif isinstance(device, Maker): callback = self._maker_callback registry = self._makers else: return self.devices[device.name] = device registry[device.name] = device if self._with_subscribers: self.registry.register(device) self.registry.on(device, 'BinaryState', device._update_state) try: if isinstance(device, Bridge): pass else: device.ping() except DeviceUnreachable: return devicefound.send(device) callback(device) def list_switches(self): """ List switches discovered in the environment. """ return self._switches.keys() def list_motions(self): """ List motions discovered in the environment. """ return self._motions.keys() def list_makers(self): """ List makers discovered in the environment. """ return self._makers.keys() def list_bridges(self): """ List bridges discovered in the environment. """ return self._bridges.keys() def get(self, name): alias = self._config.aliases.get(name) if alias: matches = lambda x: x == alias elif name: matches = matcher(name) else: matches = _NOOP for k in self.devices: if matches(k): return self.devices[k] else: raise UnknownDevice(name) def get_switch(self, name): """ Get a switch by name. """ try: return self._switches[name] except KeyError: raise UnknownDevice(name) def get_motion(self, name): """ Get a motion by name. """ try: return self._motions[name] except KeyError: raise UnknownDevice(name) def get_bridge(self, name): """ Get a bridge by name. """ try: return self._bridges[name] except KeyError: raise UnknownDevice(name) def get_maker(self, name): """ Get a maker by name. """ try: return self._makers[name] except KeyError: raise UnknownDevice(name) if __name__ == "__main__": # Use with python -i environment = Environment() ================================================ FILE: ouimeaux/examples/Randomize.py ================================================ import random import datetime import time import ouimeaux from ouimeaux.environment import Environment # http://pydoc.net/Python/ouimeaux/0.7.3/ouimeaux.examples.watch/ if __name__ == "__main__": print("") print("WeMo Randomizer") print("---------------") env = Environment() # TODO: run from 10am to 10pm try: env.start() env.discover(100) print(env.list_switches()) print(env.list_motions()) print("---------------") while True: # http://stackoverflow.com/questions/306400/how-do-i-randomly-select-an-item-from-a-list-using-python switchRND = env.get_switch( random.choice( env.list_switches() ) ) print(switchRND) switchRND.toggle() env.wait( random.randint(20,50) ) except (KeyboardInterrupt, SystemExit): print("---------------") print("Goodbye!") print("---------------") # Turn off all switches for switch in ( env.list_switches() ): print("Turning Off: " + switch) env.get_switch( switch ).off() ================================================ FILE: ouimeaux/examples/__init__.py ================================================ ================================================ FILE: ouimeaux/examples/watch.py ================================================ #!/usr/bin/env python import argparse import sys from ouimeaux.environment import Environment from ouimeaux.utils import matcher from ouimeaux.signals import receiver, statechange, devicefound def mainloop(name): matches = matcher(name) @receiver(devicefound) def found(sender, **kwargs): if matches(sender.name): print("Found device:", sender.name) @receiver(statechange) def motion(sender, **kwargs): if matches(sender.name): print("{} state is {state}".format( sender.name, state="on" if kwargs.get('state') else "off")) env = Environment() try: env.start() env.discover(10) env.wait() except (KeyboardInterrupt, SystemExit): print("Goodbye!") sys.exit(0) if __name__ == "__main__": parser = argparse.ArgumentParser("Motion notifier") parser.add_argument("name", metavar="NAME", help="Name (fuzzy matchable)" " of the Motion to detect") args = parser.parse_args() mainloop(args.name) ================================================ FILE: ouimeaux/pysignals/LICENSE.txt ================================================ pysignals was originally forked from django.dispatch. Copyright (c) Django Software Foundation and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of Django nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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 OWNER 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. django.dispatch was originally forked from PyDispatcher. PyDispatcher License: Copyright (c) 2001-2003, Patrick K. O'Brien and Contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 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. The name of Patrick K. O'Brien, or the name of any Contributor, may not be used to endorse or promote products derived from this software without specific prior written permission. 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 HOLDERS AND 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. ================================================ FILE: ouimeaux/pysignals/__init__.py ================================================ """Multi-consumer multi-producer dispatching mechanism Originally based on pydispatch (BSD) http://pypi.python.org/pypi/PyDispatcher/2.0.1 See license.txt for original license. Heavily modified for Django's purposes. """ from .dispatcher import Signal, StateChange, receiver # NOQA ================================================ FILE: ouimeaux/pysignals/dispatcher.py ================================================ from __future__ import absolute_import import sys import threading import weakref import logging from future.builtins import range import six from .inspect import func_accepts_kwargs if six.PY2: from .weakref_backports import WeakMethod else: from weakref import WeakMethod pysignals_debug = False def set_debug( val ): pysignals_debug = val def _make_id(target): if hasattr(target, '__func__'): return (id(target.__self__), id(target.__func__)) return id(target) NONE_ID = _make_id(None) # A marker for caching NO_RECEIVERS = object() class Signal(object): """ Base class for all signals Internal attributes: receivers { receiverkey (id) : weakref(receiver) } """ def __init__(self, providing_args=None, use_caching=False): """ Create a new signal. providing_args A list of the arguments this signal can pass along in a send() call. """ self.receivers = [] if providing_args is None: providing_args = [] self.providing_args = set(providing_args) self.lock = threading.Lock() self.use_caching = use_caching # For convenience we create empty caches even if they are not used. # A note about caching: if use_caching is defined, then for each # distinct sender we cache the receivers that sender has in # 'sender_receivers_cache'. The cache is cleaned when .connect() or # .disconnect() is called and populated on send(). self.sender_receivers_cache = weakref.WeakKeyDictionary() if use_caching else {} self._dead_receivers = False def connect(self, receiver, sender=None, weak=True, dispatch_uid=None): """ Connect receiver to sender for signal. Arguments: receiver A function or an instance method which is to receive signals. Receivers must be hashable objects. If weak is True, then receiver must be weak referenceable. Receivers must be able to accept keyword arguments. If a receiver is connected with a dispatch_uid argument, it will not be added if another receiver was already connected with that dispatch_uid. sender The sender to which the receiver should respond. Must either be of type Signal, or None to receive events from any sender. weak Whether to use weak references to the receiver. By default, the module will attempt to use weak references to the receiver objects. If this parameter is false, then strong references will be used. dispatch_uid An identifier used to uniquely identify a particular instance of a receiver. This will usually be a string, though it may be anything hashable. """ #from django.conf import settings # If DEBUG is on, check that we got a good receiver if pysignals_debug: import inspect assert callable(receiver), "Signal receivers must be callable." # Check for **kwargs if not func_accepts_kwargs(receiver): raise ValueError("Signal receivers must accept keyword arguments (**kwargs).") if dispatch_uid: lookup_key = (dispatch_uid, _make_id(sender)) else: lookup_key = (_make_id(receiver), _make_id(sender)) if weak: ref = weakref.ref receiver_object = receiver # Check for bound methods if hasattr(receiver, '__self__') and hasattr(receiver, '__func__'): ref = WeakMethod receiver_object = receiver.__self__ if six.PY3: receiver = ref(receiver) weakref.finalize(receiver_object, self._remove_receiver) else: receiver = ref(receiver, self._remove_receiver) with self.lock: self._clear_dead_receivers() for r_key, _ in self.receivers: if r_key == lookup_key: break else: self.receivers.append((lookup_key, receiver)) self.sender_receivers_cache.clear() def disconnect(self, receiver=None, sender=None, weak=None, dispatch_uid=None): """ Disconnect receiver from sender for signal. If weak references are used, disconnect need not be called. The receiver will be remove from dispatch automatically. Arguments: receiver The registered receiver to disconnect. May be none if dispatch_uid is specified. sender The registered sender to disconnect dispatch_uid the unique identifier of the receiver to disconnect """ if weak is not None: logging.WARNING("Passing `weak` to disconnect has no effect.") if dispatch_uid: lookup_key = (dispatch_uid, _make_id(sender)) else: lookup_key = (_make_id(receiver), _make_id(sender)) disconnected = False with self.lock: self._clear_dead_receivers() for index in range(len(self.receivers)): (r_key, _) = self.receivers[index] if r_key == lookup_key: disconnected = True del self.receivers[index] break self.sender_receivers_cache.clear() return disconnected def has_listeners(self, sender=None): return bool(self._live_receivers(sender)) def send(self, sender, **named): """ Send signal from sender to all connected receivers. If any receiver raises an error, the error propagates back through send, terminating the dispatch loop. So it's possible that all receivers won't be called if an error is raised. Arguments: sender The sender of the signal. Either a specific object or None. named Named arguments which will be passed to receivers. Returns a list of tuple pairs [(receiver, response), ... ]. """ responses = [] if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS: return responses for receiver in self._live_receivers(sender): response = receiver(signal=self, sender=sender, **named) responses.append((receiver, response)) return responses def send_robust(self, sender, **named): """ Send signal from sender to all connected receivers catching errors. Arguments: sender The sender of the signal. Can be any python object (normally one registered with a connect if you actually want something to occur). named Named arguments which will be passed to receivers. These arguments must be a subset of the argument names defined in providing_args. Return a list of tuple pairs [(receiver, response), ... ]. May raise DispatcherKeyError. If any receiver raises an error (specifically any subclass of Exception), the error instance is returned as the result for that receiver. The traceback is always attached to the error at ``__traceback__``. """ responses = [] if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS: return responses # Call each receiver with whatever arguments it can accept. # Return a list of tuple pairs [(receiver, response), ... ]. for receiver in self._live_receivers(sender): try: response = receiver(signal=self, sender=sender, **named) except Exception as err: if not hasattr(err, '__traceback__'): err.__traceback__ = sys.exc_info()[2] responses.append((receiver, err)) else: responses.append((receiver, response)) return responses def _clear_dead_receivers(self): # Note: caller is assumed to hold self.lock. if self._dead_receivers: self._dead_receivers = False new_receivers = [] for r in self.receivers: if isinstance(r[1], weakref.ReferenceType) and r[1]() is None: continue new_receivers.append(r) self.receivers = new_receivers def _live_receivers(self, sender): """ Filter sequence of receivers to get resolved, live receivers. This checks for weak references and resolves them, then returning only live receivers. """ receivers = None if self.use_caching and not self._dead_receivers: receivers = self.sender_receivers_cache.get(sender) # We could end up here with NO_RECEIVERS even if we do check this case in # .send() prior to calling _live_receivers() due to concurrent .send() call. if receivers is NO_RECEIVERS: return [] if receivers is None: with self.lock: self._clear_dead_receivers() senderkey = _make_id(sender) receivers = [] for (receiverkey, r_senderkey), receiver in self.receivers: if r_senderkey == NONE_ID or r_senderkey == senderkey: receivers.append(receiver) if self.use_caching: if not receivers: self.sender_receivers_cache[sender] = NO_RECEIVERS else: # Note, we must cache the weakref versions. self.sender_receivers_cache[sender] = receivers non_weak_receivers = [] for receiver in receivers: if isinstance(receiver, weakref.ReferenceType): # Dereference the weak reference. receiver = receiver() if receiver is not None: non_weak_receivers.append(receiver) else: non_weak_receivers.append(receiver) return non_weak_receivers def _remove_receiver(self, receiver=None): # Mark that the self.receivers list has dead weakrefs. If so, we will # clean those up in connect, disconnect and _live_receivers while # holding self.lock. Note that doing the cleanup here isn't a good # idea, _remove_receiver() will be called as side effect of garbage # collection, and so the call can happen while we are already holding # self.lock. self._dead_receivers = True def receive(self, **kwargs): """ A decorator for connecting receivers to this signal. Used by passing in the keyword arguments to connect:: @post_save.receive(sender=MyModel) def signal_receiver(sender, **kwargs): ... """ def _decorator(func): self.connect(func, **kwargs) return func return _decorator class StateChange( Signal ): def __init__(self, providing_args=None): super(StateChange, self).__init__(providing_args) self.sender_status = {} def send(self, sender, **named): """ Send signal from sender to all connected receivers *only if* the signal's contents has changed. If any receiver raises an error, the error propagates back through send, terminating the dispatch loop, so it is quite possible to not have all receivers called if a raises an error. Arguments: sender The sender of the signal Either a specific object or None. named Named arguments which will be passed to receivers. Returns a list of tuple pairs [(receiver, response), ... ]. """ responses = [] if not self.receivers: return responses sender_id = _make_id(sender) if sender_id not in self.sender_status: self.sender_status[sender_id] = {} if self.sender_status[sender_id] == named: return responses self.sender_status[sender_id] = named for receiver in self._live_receivers(sender_id): response = receiver(signal=self, sender=sender, **named) responses.append((receiver, response)) return responses def receiver(signal, **kwargs): """ A decorator for connecting receivers to signals. Used by passing in the signal (or list of signals) and keyword arguments to connect:: @receiver(post_save, sender=MyModel) def signal_receiver(sender, **kwargs): ... @receiver([post_save, post_delete], sender=MyModel) def signals_receiver(sender, **kwargs): ... """ def _decorator(func): if isinstance(signal, (list, tuple)): for s in signal: s.connect(func, **kwargs) else: signal.connect(func, **kwargs) return func return _decorator ================================================ FILE: ouimeaux/pysignals/inspect.py ================================================ from __future__ import absolute_import import inspect import six def getargspec(func): if six.PY2: return inspect.getargspec(func) sig = inspect.signature(func) args = [ p.name for p in sig.parameters.values() if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD ] varargs = [ p.name for p in sig.parameters.values() if p.kind == inspect.Parameter.VAR_POSITIONAL ] varargs = varargs[0] if varargs else None varkw = [ p.name for p in sig.parameters.values() if p.kind == inspect.Parameter.VAR_KEYWORD ] varkw = varkw[0] if varkw else None defaults = [ p.default for p in sig.parameters.values() if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD and p.default is not p.empty ] or None return args, varargs, varkw, defaults def get_func_args(func): if six.PY2: argspec = inspect.getargspec(func) return argspec.args[1:] # ignore 'self' sig = inspect.signature(func) return [ arg_name for arg_name, param in sig.parameters.items() if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD ] def get_func_full_args(func): """ Return a list of (argument name, default value) tuples. If the argument does not have a default value, omit it in the tuple. Arguments such as *args and **kwargs are also included. """ if six.PY2: argspec = inspect.getargspec(func) args = argspec.args[1:] # ignore 'self' defaults = argspec.defaults or [] # Split args into two lists depending on whether they have default value no_default = args[:len(args) - len(defaults)] with_default = args[len(args) - len(defaults):] # Join the two lists and combine it with default values args = [(arg,) for arg in no_default] + zip(with_default, defaults) # Add possible *args and **kwargs and prepend them with '*' or '**' varargs = [('*' + argspec.varargs,)] if argspec.varargs else [] kwargs = [('**' + argspec.keywords,)] if argspec.keywords else [] return args + varargs + kwargs sig = inspect.signature(func) args = [] for arg_name, param in sig.parameters.items(): name = arg_name # Ignore 'self' if name == 'self': continue if param.kind == inspect.Parameter.VAR_POSITIONAL: name = '*' + name elif param.kind == inspect.Parameter.VAR_KEYWORD: name = '**' + name if param.default != inspect.Parameter.empty: args.append((name, param.default)) else: args.append((name,)) return args def func_accepts_kwargs(func): if six.PY2: # Not all callables are inspectable with getargspec, so we'll # try a couple different ways but in the end fall back on assuming # it is -- we don't want to prevent registration of valid but weird # callables. try: argspec = inspect.getargspec(func) except TypeError: try: argspec = inspect.getargspec(func.__call__) except (TypeError, AttributeError): argspec = None return not argspec or argspec[2] is not None return any( p for p in inspect.signature(func).parameters.values() if p.kind == p.VAR_KEYWORD ) def func_accepts_var_args(func): """ Return True if function 'func' accepts positional arguments *args. """ if six.PY2: return inspect.getargspec(func)[1] is not None return any( p for p in inspect.signature(func).parameters.values() if p.kind == p.VAR_POSITIONAL ) def func_has_no_args(func): args = inspect.getargspec(func)[0] if six.PY2 else [ p for p in inspect.signature(func).parameters.values() if p.kind == p.POSITIONAL_OR_KEYWORD ] return len(args) == 1 def func_supports_parameter(func, parameter): if six.PY3: return parameter in inspect.signature(func).parameters else: args, varargs, varkw, defaults = inspect.getargspec(func) return parameter in args ================================================ FILE: ouimeaux/pysignals/license.python.txt ================================================ A. HISTORY OF THE SOFTWARE ========================== Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software. In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation, see http://www.zope.com). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF. All Python releases are Open Source (see http://www.opensource.org for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases. Release Derived Year Owner GPL- from compatible? (1) 0.9.0 thru 1.2 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes 1.6 1.5.2 2000 CNRI no 2.0 1.6 2000 BeOpen.com no 1.6.1 1.6 2001 CNRI yes (2) 2.1 2.0+1.6.1 2001 PSF no 2.0.1 2.0+1.6.1 2001 PSF yes 2.1.1 2.1+2.0.1 2001 PSF yes 2.1.2 2.1.1 2002 PSF yes 2.1.3 2.1.2 2002 PSF yes 2.2 and above 2.1.1 2001-now PSF yes Footnotes: (1) GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't. (2) According to Richard Stallman, 1.6.1 is not GPL-compatible, because its license has a choice of law clause. According to CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 is "not incompatible" with the GPL. Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible. B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON =============================================================== PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: ouimeaux/pysignals/weakref_backports.py ================================================ """ weakref_backports is a partial backport of the weakref module for python versions below 3.4. Copyright (C) 2013 Python Software Foundation, see license.python.txt for details. The following changes were made to the original sources during backporting: * Added `self` to `super` calls. * Removed `from None` when raising exceptions. """ from weakref import ref class WeakMethod(ref): """ A custom `weakref.ref` subclass which simulates a weak reference to a bound method, working around the lifetime problem of bound methods. """ __slots__ = "_func_ref", "_meth_type", "_alive", "__weakref__" def __new__(cls, meth, callback=None): try: obj = meth.__self__ func = meth.__func__ except AttributeError: raise TypeError("argument should be a bound method, not {}" .format(type(meth))) def _cb(arg): # The self-weakref trick is needed to avoid creating a reference # cycle. self = self_wr() if self._alive: self._alive = False if callback is not None: callback(self) self = ref.__new__(cls, obj, _cb) self._func_ref = ref(func, _cb) self._meth_type = type(meth) self._alive = True self_wr = ref(self) return self def __call__(self): obj = super(WeakMethod, self).__call__() func = self._func_ref() if obj is None or func is None: return None return self._meth_type(func, obj) def __eq__(self, other): if isinstance(other, WeakMethod): if not self._alive or not other._alive: return self is other return ref.__eq__(self, other) and self._func_ref == other._func_ref return False def __ne__(self, other): if isinstance(other, WeakMethod): if not self._alive or not other._alive: return self is not other return ref.__ne__(self, other) or self._func_ref != other._func_ref return True __hash__ = ref.__hash__ ================================================ FILE: ouimeaux/server/__init__.py ================================================ import os import json import gevent from flask import Flask, request, Response from flask import render_template, send_from_directory, url_for from flask import send_file, make_response, abort from flask.ext.restful import reqparse, abort, Api, Resource from flask.ext.basicauth import BasicAuth # add support for CORS - https://flask-cors.readthedocs.io/en/latest/ from flask_cors import CORS, cross_origin from ouimeaux.signals import statechange from ouimeaux.device.switch import Switch from ouimeaux.device.insight import Insight from ouimeaux.device.maker import Maker from ouimeaux.environment import Environment, UnknownDevice from socketio import socketio_manage from socketio.namespace import BaseNamespace from socketio.mixins import BroadcastMixin here = lambda *x: os.path.join(os.path.dirname(__file__), *x) app = Flask(__name__) api = Api(app) #add support for CORS CORS(app) ENV = None def initialize(bind=None, auth=None): global ENV if ENV is None: ENV = Environment(bind=bind) ENV.start() gevent.spawn(ENV.discover, 10) if auth is not None: elems = auth.split(':', 1) username = elems[0] password = elems[1] print("Protected server with basic auth username/password: ", username, password) app.config['BASIC_AUTH_USERNAME'] = username app.config['BASIC_AUTH_PASSWORD'] = password app.config['BASIC_AUTH_FORCE'] = True basic_auth = BasicAuth(app) def serialize(device): if isinstance(device, Insight): return {'name': device.name, 'type': device.__class__.__name__, 'serialnumber': device.serialnumber, 'state': device.get_state(), 'model': device.model, 'host': device.host, 'lastchange': str(device.last_change), 'onfor': device.on_for, 'ontoday': device.today_on_time, 'ontotal': device.ontotal, 'todaymw': device.today_kwh, 'totalmw': device.totalmw, 'currentpower': device.current_power } elif isinstance(device, Maker): return {'name': device.name, 'type': device.__class__.__name__, 'serialnumber': device.serialnumber, 'state': device.get_state(), 'model': device.model, 'host': device.host, 'hassensor' : device.has_sensor, 'switchmode' : device.switch_mode, 'sensor' : device.sensor_state } return {'name': device.name, 'type': device.__class__.__name__, 'serialnumber': device.serialnumber, 'state': device.get_state(), 'model': device.model, 'host': device.host} def get_device(name, should_abort=True): try: return ENV.get(name) except UnknownDevice: if not should_abort: raise abort(404, error='No device matching {}'.format(name)) # First, the REST API class EnvironmentResource(Resource): def get(self): result = {} for dev in ENV: result[dev.name] = serialize(dev) return result def post(self): seconds = (request.json or {}).get('seconds', ( request.values or {}).get('seconds', 5)) ENV.discover(int(seconds)) return self.get() class DeviceResource(Resource): def get(self, name): return serialize(get_device(name)) def post(self, name): dev = get_device(name) if not isinstance(dev, Switch): abort(405, error='Only switches can have their state changed') action = (request.json or {}).get('state', ( request.values or {}).get('state', 'toggle')) if action not in ('on', 'off', 'toggle', 'blink'): abort(400, error='{} is not a valid state'.format(action)) if action == 'blink': delay = (request.json or {}).get('delay', ( request.values or {}).get('delay', '1')) getattr(dev, action)(delay=int(delay)) else: getattr(dev, action)() return serialize(dev) api.add_resource(EnvironmentResource, '/api/environment') api.add_resource(DeviceResource, '/api/device/') class SocketNamespace(BaseNamespace): def update_state(self, sender, **kwargs): data = serialize(sender) data['state'] = kwargs.get('state', data['state']) self.emit("send:devicestate", data) def on_statechange(self, data): ENV.get(data['name']).set_state(data['state']) def on_join(self, data): statechange.connect(self.update_state, dispatch_uid=id(self)) for device in ENV: self.update_state(device) def __del__(self): statechange.disconnect(dispatch_uid=id(self)) # Now for the WebSocket api @app.route("/socket.io/") def run_socketio(**kwargs): socketio_manage(request.environ, {'': SocketNamespace}) # routing for basic pages (pass routing onto the Angular app) @app.route('/') def basic_pages(**kwargs): return make_response(open(here('templates/index.html')).read()) # special file handlers and error handlers @app.route('/favicon.ico') def favicon(): return send_from_directory(os.path.join(app.root_path, 'static'), 'img/favicon.ico') @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404 app.config.from_object('ouimeaux.server.settings') app.url_map.strict_slashes = False if __name__ == "__main__": app.run() ================================================ FILE: ouimeaux/server/settings.py ================================================ DEBUG = True SECRET_KEY = 'temporary_secret_key' # make sure to change this ================================================ FILE: ouimeaux/server/static/css/bootstrap-responsive.css ================================================ /*! * Bootstrap Responsive v2.3.2 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */ .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: #777777; text-shadow: none; } .nav-collapse .nav > li > a, .nav-collapse .dropdown-menu a { padding: 9px 15px; font-weight: bold; color: #777777; -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: #999999; } .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: #111111; } .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: none; -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: #111111; border-bottom-color: #111111; } .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; } } ================================================ FILE: ouimeaux/server/static/css/bootstrap-theme.css ================================================ /*! * Bootstrap v3.0.3 (http://getbootstrap.com) * Copyright 2013 Twitter, Inc. * Licensed under http://www.apache.org/licenses/LICENSE-2.0 */ .btn-default, .btn-primary, .btn-success, .btn-info, .btn-warning, .btn-danger { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); } .btn-default:active, .btn-primary:active, .btn-success:active, .btn-info:active, .btn-warning:active, .btn-danger:active, .btn-default.active, .btn-primary.active, .btn-success.active, .btn-info.active, .btn-warning.active, .btn-danger.active { -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } .btn:active, .btn.active { background-image: none; } .btn-default { text-shadow: 0 1px 0 #fff; background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%); background-repeat: repeat-x; border-color: #dbdbdb; border-color: #ccc; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-default:hover, .btn-default:focus { background-color: #e0e0e0; background-position: 0 -15px; } .btn-default:active, .btn-default.active { background-color: #e0e0e0; border-color: #dbdbdb; } .btn-primary { background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); background-repeat: repeat-x; border-color: #2b669a; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-primary:hover, .btn-primary:focus { background-color: #2d6ca2; background-position: 0 -15px; } .btn-primary:active, .btn-primary.active { background-color: #2d6ca2; border-color: #2b669a; } .btn-success { background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); background-repeat: repeat-x; border-color: #3e8f3e; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-success:hover, .btn-success:focus { background-color: #419641; background-position: 0 -15px; } .btn-success:active, .btn-success.active { background-color: #419641; border-color: #3e8f3e; } .btn-warning { background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); background-repeat: repeat-x; border-color: #e38d13; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-warning:hover, .btn-warning:focus { background-color: #eb9316; background-position: 0 -15px; } .btn-warning:active, .btn-warning.active { background-color: #eb9316; border-color: #e38d13; } .btn-danger { background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); background-repeat: repeat-x; border-color: #b92c28; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-danger:hover, .btn-danger:focus { background-color: #c12e2a; background-position: 0 -15px; } .btn-danger:active, .btn-danger.active { background-color: #c12e2a; border-color: #b92c28; } .btn-info { background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); background-repeat: repeat-x; border-color: #28a4c9; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-info:hover, .btn-info:focus { background-color: #2aabd2; background-position: 0 -15px; } .btn-info:active, .btn-info.active { background-color: #2aabd2; border-color: #28a4c9; } .thumbnail, .img-thumbnail { -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); } .dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus { background-color: #e8e8e8; background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); } .dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus { background-color: #357ebd; background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); } .navbar-default { background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); background-repeat: repeat-x; border-radius: 4px; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); } .navbar-default .navbar-nav > .active > a { background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); } .navbar-brand, .navbar-nav > li > a { text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); } .navbar-inverse { background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .navbar-inverse .navbar-nav > .active > a { background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); } .navbar-inverse .navbar-brand, .navbar-inverse .navbar-nav > li > a { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .navbar-static-top, .navbar-fixed-top, .navbar-fixed-bottom { border-radius: 0; } .alert { text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); } .alert-success { background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); background-repeat: repeat-x; border-color: #b2dba1; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); } .alert-info { background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); background-repeat: repeat-x; border-color: #9acfea; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); } .alert-warning { background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); background-repeat: repeat-x; border-color: #f5e79e; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); } .alert-danger { background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); background-repeat: repeat-x; border-color: #dca7a7; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); } .progress { background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); } .progress-bar { background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); } .progress-bar-success { background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); } .progress-bar-info { background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); } .progress-bar-warning { background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); } .progress-bar-danger { background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); } .list-group { border-radius: 4px; -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); } .list-group-item.active, .list-group-item.active:hover, .list-group-item.active:focus { text-shadow: 0 -1px 0 #3071a9; background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); background-repeat: repeat-x; border-color: #3278b3; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); } .panel { -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .panel-default > .panel-heading { background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); } .panel-primary > .panel-heading { background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); } .panel-success > .panel-heading { background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); } .panel-info > .panel-heading { background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); } .panel-warning > .panel-heading { background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); } .panel-danger > .panel-heading { background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); } .well { background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); background-repeat: repeat-x; border-color: #dcdcdc; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); } ================================================ FILE: ouimeaux/server/static/css/bootstrap.css ================================================ /*! * Bootstrap v3.0.3 (http://getbootstrap.com) * Copyright 2013 Twitter, Inc. * Licensed under http://www.apache.org/licenses/LICENSE-2.0 */ /*! normalize.css v2.1.3 | MIT License | git.io/normalize */ article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; } audio, canvas, video { display: inline-block; } audio:not([controls]) { display: none; height: 0; } [hidden], template { display: none; } html { font-family: sans-serif; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } body { margin: 0; } a { background: transparent; } a:focus { outline: thin dotted; } a:active, a:hover { outline: 0; } h1 { margin: 0.67em 0; font-size: 2em; } abbr[title] { border-bottom: 1px dotted; } b, strong { font-weight: bold; } dfn { font-style: italic; } hr { height: 0; -moz-box-sizing: content-box; box-sizing: content-box; } mark { color: #000; background: #ff0; } code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; } pre { white-space: pre-wrap; } q { quotes: "\201C" "\201D" "\2018" "\2019"; } small { font-size: 80%; } sub, sup { position: relative; font-size: 75%; line-height: 0; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } img { border: 0; } svg:not(:root) { overflow: hidden; } figure { margin: 0; } fieldset { padding: 0.35em 0.625em 0.75em; margin: 0 2px; border: 1px solid #c0c0c0; } legend { padding: 0; border: 0; } button, input, select, textarea { margin: 0; font-family: inherit; font-size: 100%; } button, input { line-height: normal; } button, select { text-transform: none; } button, html input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } button[disabled], html input[disabled] { cursor: default; } input[type="checkbox"], input[type="radio"] { padding: 0; box-sizing: border-box; } input[type="search"] { -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; -webkit-appearance: textfield; } input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; } textarea { overflow: auto; vertical-align: top; } table { border-collapse: collapse; border-spacing: 0; } @media print { * { color: #000 !important; text-shadow: none !important; background: transparent !important; box-shadow: none !important; } a, a:visited { text-decoration: underline; } a[href]:after { content: " (" attr(href) ")"; } abbr[title]:after { content: " (" attr(title) ")"; } a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } pre, blockquote { border: 1px solid #999; page-break-inside: avoid; } thead { display: table-header-group; } tr, img { page-break-inside: avoid; } img { max-width: 100% !important; } @page { margin: 2cm .5cm; } p, h2, h3 { orphans: 3; widows: 3; } h2, h3 { page-break-after: avoid; } select { background: #fff !important; } .navbar { display: none; } .table td, .table th { background-color: #fff !important; } .btn > .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px solid #000; } .table { border-collapse: collapse !important; } .table-bordered th, .table-bordered td { border: 1px solid #ddd !important; } } *, *:before, *:after { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } html { font-size: 62.5%; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; line-height: 1.428571429; color: #333333; background-color: #ffffff; } input, button, select, textarea { font-family: inherit; font-size: inherit; line-height: inherit; } a { color: #428bca; text-decoration: none; } a:hover, a:focus { color: #2a6496; text-decoration: underline; } a:focus { outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } img { vertical-align: middle; } .img-responsive { display: block; height: auto; max-width: 100%; } .img-rounded { border-radius: 6px; } .img-thumbnail { display: inline-block; height: auto; max-width: 100%; padding: 4px; line-height: 1.428571429; background-color: #ffffff; border: 1px solid #dddddd; border-radius: 4px; -webkit-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } .img-circle { border-radius: 50%; } hr { margin-top: 20px; margin-bottom: 20px; border: 0; border-top: 1px solid #eeeeee; } .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; } h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-weight: 500; line-height: 1.1; color: inherit; } h1 small, h2 small, h3 small, h4 small, h5 small, h6 small, .h1 small, .h2 small, .h3 small, .h4 small, .h5 small, .h6 small, h1 .small, h2 .small, h3 .small, h4 .small, h5 .small, h6 .small, .h1 .small, .h2 .small, .h3 .small, .h4 .small, .h5 .small, .h6 .small { font-weight: normal; line-height: 1; color: #999999; } h1, h2, h3 { margin-top: 20px; margin-bottom: 10px; } h1 small, h2 small, h3 small, h1 .small, h2 .small, h3 .small { font-size: 65%; } h4, h5, h6 { margin-top: 10px; margin-bottom: 10px; } h4 small, h5 small, h6 small, h4 .small, h5 .small, h6 .small { font-size: 75%; } h1, .h1 { font-size: 36px; } h2, .h2 { font-size: 30px; } h3, .h3 { font-size: 24px; } h4, .h4 { font-size: 18px; } h5, .h5 { font-size: 14px; } h6, .h6 { font-size: 12px; } p { margin: 0 0 10px; } .lead { margin-bottom: 20px; font-size: 16px; font-weight: 200; line-height: 1.4; } @media (min-width: 768px) { .lead { font-size: 21px; } } small, .small { font-size: 85%; } cite { font-style: normal; } .text-muted { color: #999999; } .text-primary { color: #428bca; } .text-primary:hover { color: #3071a9; } .text-warning { color: #8a6d3b; } .text-warning:hover { color: #66512c; } .text-danger { color: #a94442; } .text-danger:hover { color: #843534; } .text-success { color: #3c763d; } .text-success:hover { color: #2b542c; } .text-info { color: #31708f; } .text-info:hover { color: #245269; } .text-left { text-align: left; } .text-right { text-align: right; } .text-center { text-align: center; } .page-header { padding-bottom: 9px; margin: 40px 0 20px; border-bottom: 1px solid #eeeeee; } ul, ol { margin-top: 0; margin-bottom: 10px; } ul ul, ol ul, ul ol, ol ol { margin-bottom: 0; } .list-unstyled { padding-left: 0; list-style: none; } .list-inline { padding-left: 0; list-style: none; } .list-inline > li { display: inline-block; padding-right: 5px; padding-left: 5px; } .list-inline > li:first-child { padding-left: 0; } dl { margin-top: 0; margin-bottom: 20px; } dt, dd { line-height: 1.428571429; } dt { font-weight: bold; } dd { margin-left: 0; } @media (min-width: 768px) { .dl-horizontal dt { float: left; width: 160px; overflow: hidden; clear: left; text-align: right; text-overflow: ellipsis; white-space: nowrap; } .dl-horizontal dd { margin-left: 180px; } .dl-horizontal dd:before, .dl-horizontal dd:after { display: table; content: " "; } .dl-horizontal dd:after { clear: both; } .dl-horizontal dd:before, .dl-horizontal dd:after { display: table; content: " "; } .dl-horizontal dd:after { clear: both; } } abbr[title], abbr[data-original-title] { cursor: help; border-bottom: 1px dotted #999999; } .initialism { font-size: 90%; text-transform: uppercase; } blockquote { padding: 10px 20px; margin: 0 0 20px; border-left: 5px solid #eeeeee; } blockquote p { font-size: 17.5px; font-weight: 300; line-height: 1.25; } blockquote p:last-child { margin-bottom: 0; } blockquote small, blockquote .small { display: block; line-height: 1.428571429; color: #999999; } blockquote small:before, blockquote .small:before { content: '\2014 \00A0'; } blockquote.pull-right { padding-right: 15px; padding-left: 0; border-right: 5px solid #eeeeee; border-left: 0; } blockquote.pull-right p, blockquote.pull-right small, blockquote.pull-right .small { text-align: right; } blockquote.pull-right small:before, blockquote.pull-right .small:before { content: ''; } blockquote.pull-right small:after, blockquote.pull-right .small:after { content: '\00A0 \2014'; } blockquote:before, blockquote:after { content: ""; } address { margin-bottom: 20px; font-style: normal; line-height: 1.428571429; } code, kbd, pre, samp { font-family: Menlo, Monaco, Consolas, "Courier New", monospace; } code { padding: 2px 4px; font-size: 90%; color: #c7254e; white-space: nowrap; background-color: #f9f2f4; border-radius: 4px; } pre { display: block; padding: 9.5px; margin: 0 0 10px; font-size: 13px; line-height: 1.428571429; color: #333333; word-break: break-all; word-wrap: break-word; background-color: #f5f5f5; border: 1px solid #cccccc; border-radius: 4px; } pre code { padding: 0; font-size: inherit; color: inherit; white-space: pre-wrap; background-color: transparent; border-radius: 0; } .pre-scrollable { max-height: 340px; overflow-y: scroll; } .container { padding-right: 15px; padding-left: 15px; margin-right: auto; margin-left: auto; } .container:before, .container:after { display: table; content: " "; } .container:after { clear: both; } .container:before, .container:after { display: table; content: " "; } .container:after { clear: both; } @media (min-width: 768px) { .container { width: 750px; } } @media (min-width: 992px) { .container { width: 970px; } } @media (min-width: 1200px) { .container { width: 1170px; } } .row { margin-right: -15px; margin-left: -15px; } .row:before, .row:after { display: table; content: " "; } .row:after { clear: both; } .row:before, .row:after { display: table; content: " "; } .row:after { clear: both; } .col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { position: relative; min-height: 1px; padding-right: 15px; padding-left: 15px; } .col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { float: left; } .col-xs-12 { width: 100%; } .col-xs-11 { width: 91.66666666666666%; } .col-xs-10 { width: 83.33333333333334%; } .col-xs-9 { width: 75%; } .col-xs-8 { width: 66.66666666666666%; } .col-xs-7 { width: 58.333333333333336%; } .col-xs-6 { width: 50%; } .col-xs-5 { width: 41.66666666666667%; } .col-xs-4 { width: 33.33333333333333%; } .col-xs-3 { width: 25%; } .col-xs-2 { width: 16.666666666666664%; } .col-xs-1 { width: 8.333333333333332%; } .col-xs-pull-12 { right: 100%; } .col-xs-pull-11 { right: 91.66666666666666%; } .col-xs-pull-10 { right: 83.33333333333334%; } .col-xs-pull-9 { right: 75%; } .col-xs-pull-8 { right: 66.66666666666666%; } .col-xs-pull-7 { right: 58.333333333333336%; } .col-xs-pull-6 { right: 50%; } .col-xs-pull-5 { right: 41.66666666666667%; } .col-xs-pull-4 { right: 33.33333333333333%; } .col-xs-pull-3 { right: 25%; } .col-xs-pull-2 { right: 16.666666666666664%; } .col-xs-pull-1 { right: 8.333333333333332%; } .col-xs-pull-0 { right: 0; } .col-xs-push-12 { left: 100%; } .col-xs-push-11 { left: 91.66666666666666%; } .col-xs-push-10 { left: 83.33333333333334%; } .col-xs-push-9 { left: 75%; } .col-xs-push-8 { left: 66.66666666666666%; } .col-xs-push-7 { left: 58.333333333333336%; } .col-xs-push-6 { left: 50%; } .col-xs-push-5 { left: 41.66666666666667%; } .col-xs-push-4 { left: 33.33333333333333%; } .col-xs-push-3 { left: 25%; } .col-xs-push-2 { left: 16.666666666666664%; } .col-xs-push-1 { left: 8.333333333333332%; } .col-xs-push-0 { left: 0; } .col-xs-offset-12 { margin-left: 100%; } .col-xs-offset-11 { margin-left: 91.66666666666666%; } .col-xs-offset-10 { margin-left: 83.33333333333334%; } .col-xs-offset-9 { margin-left: 75%; } .col-xs-offset-8 { margin-left: 66.66666666666666%; } .col-xs-offset-7 { margin-left: 58.333333333333336%; } .col-xs-offset-6 { margin-left: 50%; } .col-xs-offset-5 { margin-left: 41.66666666666667%; } .col-xs-offset-4 { margin-left: 33.33333333333333%; } .col-xs-offset-3 { margin-left: 25%; } .col-xs-offset-2 { margin-left: 16.666666666666664%; } .col-xs-offset-1 { margin-left: 8.333333333333332%; } .col-xs-offset-0 { margin-left: 0; } @media (min-width: 768px) { .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { float: left; } .col-sm-12 { width: 100%; } .col-sm-11 { width: 91.66666666666666%; } .col-sm-10 { width: 83.33333333333334%; } .col-sm-9 { width: 75%; } .col-sm-8 { width: 66.66666666666666%; } .col-sm-7 { width: 58.333333333333336%; } .col-sm-6 { width: 50%; } .col-sm-5 { width: 41.66666666666667%; } .col-sm-4 { width: 33.33333333333333%; } .col-sm-3 { width: 25%; } .col-sm-2 { width: 16.666666666666664%; } .col-sm-1 { width: 8.333333333333332%; } .col-sm-pull-12 { right: 100%; } .col-sm-pull-11 { right: 91.66666666666666%; } .col-sm-pull-10 { right: 83.33333333333334%; } .col-sm-pull-9 { right: 75%; } .col-sm-pull-8 { right: 66.66666666666666%; } .col-sm-pull-7 { right: 58.333333333333336%; } .col-sm-pull-6 { right: 50%; } .col-sm-pull-5 { right: 41.66666666666667%; } .col-sm-pull-4 { right: 33.33333333333333%; } .col-sm-pull-3 { right: 25%; } .col-sm-pull-2 { right: 16.666666666666664%; } .col-sm-pull-1 { right: 8.333333333333332%; } .col-sm-pull-0 { right: 0; } .col-sm-push-12 { left: 100%; } .col-sm-push-11 { left: 91.66666666666666%; } .col-sm-push-10 { left: 83.33333333333334%; } .col-sm-push-9 { left: 75%; } .col-sm-push-8 { left: 66.66666666666666%; } .col-sm-push-7 { left: 58.333333333333336%; } .col-sm-push-6 { left: 50%; } .col-sm-push-5 { left: 41.66666666666667%; } .col-sm-push-4 { left: 33.33333333333333%; } .col-sm-push-3 { left: 25%; } .col-sm-push-2 { left: 16.666666666666664%; } .col-sm-push-1 { left: 8.333333333333332%; } .col-sm-push-0 { left: 0; } .col-sm-offset-12 { margin-left: 100%; } .col-sm-offset-11 { margin-left: 91.66666666666666%; } .col-sm-offset-10 { margin-left: 83.33333333333334%; } .col-sm-offset-9 { margin-left: 75%; } .col-sm-offset-8 { margin-left: 66.66666666666666%; } .col-sm-offset-7 { margin-left: 58.333333333333336%; } .col-sm-offset-6 { margin-left: 50%; } .col-sm-offset-5 { margin-left: 41.66666666666667%; } .col-sm-offset-4 { margin-left: 33.33333333333333%; } .col-sm-offset-3 { margin-left: 25%; } .col-sm-offset-2 { margin-left: 16.666666666666664%; } .col-sm-offset-1 { margin-left: 8.333333333333332%; } .col-sm-offset-0 { margin-left: 0; } } @media (min-width: 992px) { .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { float: left; } .col-md-12 { width: 100%; } .col-md-11 { width: 91.66666666666666%; } .col-md-10 { width: 83.33333333333334%; } .col-md-9 { width: 75%; } .col-md-8 { width: 66.66666666666666%; } .col-md-7 { width: 58.333333333333336%; } .col-md-6 { width: 50%; } .col-md-5 { width: 41.66666666666667%; } .col-md-4 { width: 33.33333333333333%; } .col-md-3 { width: 25%; } .col-md-2 { width: 16.666666666666664%; } .col-md-1 { width: 8.333333333333332%; } .col-md-pull-12 { right: 100%; } .col-md-pull-11 { right: 91.66666666666666%; } .col-md-pull-10 { right: 83.33333333333334%; } .col-md-pull-9 { right: 75%; } .col-md-pull-8 { right: 66.66666666666666%; } .col-md-pull-7 { right: 58.333333333333336%; } .col-md-pull-6 { right: 50%; } .col-md-pull-5 { right: 41.66666666666667%; } .col-md-pull-4 { right: 33.33333333333333%; } .col-md-pull-3 { right: 25%; } .col-md-pull-2 { right: 16.666666666666664%; } .col-md-pull-1 { right: 8.333333333333332%; } .col-md-pull-0 { right: 0; } .col-md-push-12 { left: 100%; } .col-md-push-11 { left: 91.66666666666666%; } .col-md-push-10 { left: 83.33333333333334%; } .col-md-push-9 { left: 75%; } .col-md-push-8 { left: 66.66666666666666%; } .col-md-push-7 { left: 58.333333333333336%; } .col-md-push-6 { left: 50%; } .col-md-push-5 { left: 41.66666666666667%; } .col-md-push-4 { left: 33.33333333333333%; } .col-md-push-3 { left: 25%; } .col-md-push-2 { left: 16.666666666666664%; } .col-md-push-1 { left: 8.333333333333332%; } .col-md-push-0 { left: 0; } .col-md-offset-12 { margin-left: 100%; } .col-md-offset-11 { margin-left: 91.66666666666666%; } .col-md-offset-10 { margin-left: 83.33333333333334%; } .col-md-offset-9 { margin-left: 75%; } .col-md-offset-8 { margin-left: 66.66666666666666%; } .col-md-offset-7 { margin-left: 58.333333333333336%; } .col-md-offset-6 { margin-left: 50%; } .col-md-offset-5 { margin-left: 41.66666666666667%; } .col-md-offset-4 { margin-left: 33.33333333333333%; } .col-md-offset-3 { margin-left: 25%; } .col-md-offset-2 { margin-left: 16.666666666666664%; } .col-md-offset-1 { margin-left: 8.333333333333332%; } .col-md-offset-0 { margin-left: 0; } } @media (min-width: 1200px) { .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { float: left; } .col-lg-12 { width: 100%; } .col-lg-11 { width: 91.66666666666666%; } .col-lg-10 { width: 83.33333333333334%; } .col-lg-9 { width: 75%; } .col-lg-8 { width: 66.66666666666666%; } .col-lg-7 { width: 58.333333333333336%; } .col-lg-6 { width: 50%; } .col-lg-5 { width: 41.66666666666667%; } .col-lg-4 { width: 33.33333333333333%; } .col-lg-3 { width: 25%; } .col-lg-2 { width: 16.666666666666664%; } .col-lg-1 { width: 8.333333333333332%; } .col-lg-pull-12 { right: 100%; } .col-lg-pull-11 { right: 91.66666666666666%; } .col-lg-pull-10 { right: 83.33333333333334%; } .col-lg-pull-9 { right: 75%; } .col-lg-pull-8 { right: 66.66666666666666%; } .col-lg-pull-7 { right: 58.333333333333336%; } .col-lg-pull-6 { right: 50%; } .col-lg-pull-5 { right: 41.66666666666667%; } .col-lg-pull-4 { right: 33.33333333333333%; } .col-lg-pull-3 { right: 25%; } .col-lg-pull-2 { right: 16.666666666666664%; } .col-lg-pull-1 { right: 8.333333333333332%; } .col-lg-pull-0 { right: 0; } .col-lg-push-12 { left: 100%; } .col-lg-push-11 { left: 91.66666666666666%; } .col-lg-push-10 { left: 83.33333333333334%; } .col-lg-push-9 { left: 75%; } .col-lg-push-8 { left: 66.66666666666666%; } .col-lg-push-7 { left: 58.333333333333336%; } .col-lg-push-6 { left: 50%; } .col-lg-push-5 { left: 41.66666666666667%; } .col-lg-push-4 { left: 33.33333333333333%; } .col-lg-push-3 { left: 25%; } .col-lg-push-2 { left: 16.666666666666664%; } .col-lg-push-1 { left: 8.333333333333332%; } .col-lg-push-0 { left: 0; } .col-lg-offset-12 { margin-left: 100%; } .col-lg-offset-11 { margin-left: 91.66666666666666%; } .col-lg-offset-10 { margin-left: 83.33333333333334%; } .col-lg-offset-9 { margin-left: 75%; } .col-lg-offset-8 { margin-left: 66.66666666666666%; } .col-lg-offset-7 { margin-left: 58.333333333333336%; } .col-lg-offset-6 { margin-left: 50%; } .col-lg-offset-5 { margin-left: 41.66666666666667%; } .col-lg-offset-4 { margin-left: 33.33333333333333%; } .col-lg-offset-3 { margin-left: 25%; } .col-lg-offset-2 { margin-left: 16.666666666666664%; } .col-lg-offset-1 { margin-left: 8.333333333333332%; } .col-lg-offset-0 { margin-left: 0; } } table { max-width: 100%; background-color: transparent; } th { text-align: left; } .table { width: 100%; margin-bottom: 20px; } .table > thead > tr > th, .table > tbody > tr > th, .table > tfoot > tr > th, .table > thead > tr > td, .table > tbody > tr > td, .table > tfoot > tr > td { padding: 8px; line-height: 1.428571429; vertical-align: top; border-top: 1px solid #dddddd; } .table > thead > tr > th { vertical-align: bottom; border-bottom: 2px solid #dddddd; } .table > caption + thead > tr:first-child > th, .table > colgroup + thead > tr:first-child > th, .table > thead:first-child > tr:first-child > th, .table > caption + thead > tr:first-child > td, .table > colgroup + thead > tr:first-child > td, .table > thead:first-child > tr:first-child > td { border-top: 0; } .table > tbody + tbody { border-top: 2px solid #dddddd; } .table .table { background-color: #ffffff; } .table-condensed > thead > tr > th, .table-condensed > tbody > tr > th, .table-condensed > tfoot > tr > th, .table-condensed > thead > tr > td, .table-condensed > tbody > tr > td, .table-condensed > tfoot > tr > td { padding: 5px; } .table-bordered { border: 1px solid #dddddd; } .table-bordered > thead > tr > th, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > tbody > tr > td, .table-bordered > tfoot > tr > td { border: 1px solid #dddddd; } .table-bordered > thead > tr > th, .table-bordered > thead > tr > td { border-bottom-width: 2px; } .table-striped > tbody > tr:nth-child(odd) > td, .table-striped > tbody > tr:nth-child(odd) > th { background-color: #f9f9f9; } .table-hover > tbody > tr:hover > td, .table-hover > tbody > tr:hover > th { background-color: #f5f5f5; } table col[class*="col-"] { position: static; display: table-column; float: none; } table td[class*="col-"], table th[class*="col-"] { display: table-cell; float: none; } .table > thead > tr > .active, .table > tbody > tr > .active, .table > tfoot > tr > .active, .table > thead > .active > td, .table > tbody > .active > td, .table > tfoot > .active > td, .table > thead > .active > th, .table > tbody > .active > th, .table > tfoot > .active > th { background-color: #f5f5f5; } .table-hover > tbody > tr > .active:hover, .table-hover > tbody > .active:hover > td, .table-hover > tbody > .active:hover > th { background-color: #e8e8e8; } .table > thead > tr > .success, .table > tbody > tr > .success, .table > tfoot > tr > .success, .table > thead > .success > td, .table > tbody > .success > td, .table > tfoot > .success > td, .table > thead > .success > th, .table > tbody > .success > th, .table > tfoot > .success > th { background-color: #dff0d8; } .table-hover > tbody > tr > .success:hover, .table-hover > tbody > .success:hover > td, .table-hover > tbody > .success:hover > th { background-color: #d0e9c6; } .table > thead > tr > .danger, .table > tbody > tr > .danger, .table > tfoot > tr > .danger, .table > thead > .danger > td, .table > tbody > .danger > td, .table > tfoot > .danger > td, .table > thead > .danger > th, .table > tbody > .danger > th, .table > tfoot > .danger > th { background-color: #f2dede; } .table-hover > tbody > tr > .danger:hover, .table-hover > tbody > .danger:hover > td, .table-hover > tbody > .danger:hover > th { background-color: #ebcccc; } .table > thead > tr > .warning, .table > tbody > tr > .warning, .table > tfoot > tr > .warning, .table > thead > .warning > td, .table > tbody > .warning > td, .table > tfoot > .warning > td, .table > thead > .warning > th, .table > tbody > .warning > th, .table > tfoot > .warning > th { background-color: #fcf8e3; } .table-hover > tbody > tr > .warning:hover, .table-hover > tbody > .warning:hover > td, .table-hover > tbody > .warning:hover > th { background-color: #faf2cc; } @media (max-width: 767px) { .table-responsive { width: 100%; margin-bottom: 15px; overflow-x: scroll; overflow-y: hidden; border: 1px solid #dddddd; -ms-overflow-style: -ms-autohiding-scrollbar; -webkit-overflow-scrolling: touch; } .table-responsive > .table { margin-bottom: 0; } .table-responsive > .table > thead > tr > th, .table-responsive > .table > tbody > tr > th, .table-responsive > .table > tfoot > tr > th, .table-responsive > .table > thead > tr > td, .table-responsive > .table > tbody > tr > td, .table-responsive > .table > tfoot > tr > td { white-space: nowrap; } .table-responsive > .table-bordered { border: 0; } .table-responsive > .table-bordered > thead > tr > th:first-child, .table-responsive > .table-bordered > tbody > tr > th:first-child, .table-responsive > .table-bordered > tfoot > tr > th:first-child, .table-responsive > .table-bordered > thead > tr > td:first-child, .table-responsive > .table-bordered > tbody > tr > td:first-child, .table-responsive > .table-bordered > tfoot > tr > td:first-child { border-left: 0; } .table-responsive > .table-bordered > thead > tr > th:last-child, .table-responsive > .table-bordered > tbody > tr > th:last-child, .table-responsive > .table-bordered > tfoot > tr > th:last-child, .table-responsive > .table-bordered > thead > tr > td:last-child, .table-responsive > .table-bordered > tbody > tr > td:last-child, .table-responsive > .table-bordered > tfoot > tr > td:last-child { border-right: 0; } .table-responsive > .table-bordered > tbody > tr:last-child > th, .table-responsive > .table-bordered > tfoot > tr:last-child > th, .table-responsive > .table-bordered > tbody > tr:last-child > td, .table-responsive > .table-bordered > tfoot > tr:last-child > td { border-bottom: 0; } } fieldset { padding: 0; margin: 0; border: 0; } legend { display: block; width: 100%; padding: 0; margin-bottom: 20px; font-size: 21px; line-height: inherit; color: #333333; border: 0; border-bottom: 1px solid #e5e5e5; } label { display: inline-block; margin-bottom: 5px; font-weight: bold; } input[type="search"] { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } input[type="radio"], input[type="checkbox"] { margin: 4px 0 0; margin-top: 1px \9; /* IE8-9 */ line-height: normal; } input[type="file"] { display: block; } select[multiple], select[size] { height: auto; } select optgroup { font-family: inherit; font-size: inherit; font-style: inherit; } input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button { height: auto; } output { display: block; padding-top: 7px; font-size: 14px; line-height: 1.428571429; color: #555555; vertical-align: middle; } .form-control { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.428571429; color: #555555; vertical-align: middle; background-color: #ffffff; background-image: none; border: 1px solid #cccccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; } .form-control:focus { border-color: #66afe9; outline: 0; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6); } .form-control:-moz-placeholder { color: #999999; } .form-control::-moz-placeholder { color: #999999; opacity: 1; } .form-control:-ms-input-placeholder { color: #999999; } .form-control::-webkit-input-placeholder { color: #999999; } .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { cursor: not-allowed; background-color: #eeeeee; } textarea.form-control { height: auto; } .form-group { margin-bottom: 15px; } .radio, .checkbox { display: block; min-height: 20px; padding-left: 20px; margin-top: 10px; margin-bottom: 10px; vertical-align: middle; } .radio label, .checkbox label { display: inline; margin-bottom: 0; font-weight: normal; cursor: pointer; } .radio input[type="radio"], .radio-inline input[type="radio"], .checkbox input[type="checkbox"], .checkbox-inline input[type="checkbox"] { float: left; margin-left: -20px; } .radio + .radio, .checkbox + .checkbox { margin-top: -5px; } .radio-inline, .checkbox-inline { display: inline-block; padding-left: 20px; margin-bottom: 0; font-weight: normal; vertical-align: middle; cursor: pointer; } .radio-inline + .radio-inline, .checkbox-inline + .checkbox-inline { margin-top: 0; margin-left: 10px; } input[type="radio"][disabled], input[type="checkbox"][disabled], .radio[disabled], .radio-inline[disabled], .checkbox[disabled], .checkbox-inline[disabled], fieldset[disabled] input[type="radio"], fieldset[disabled] input[type="checkbox"], fieldset[disabled] .radio, fieldset[disabled] .radio-inline, fieldset[disabled] .checkbox, fieldset[disabled] .checkbox-inline { cursor: not-allowed; } .input-sm { height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 3px; } select.input-sm { height: 30px; line-height: 30px; } textarea.input-sm { height: auto; } .input-lg { height: 46px; padding: 10px 16px; font-size: 18px; line-height: 1.33; border-radius: 6px; } select.input-lg { height: 46px; line-height: 46px; } textarea.input-lg { height: auto; } .has-warning .help-block, .has-warning .control-label, .has-warning .radio, .has-warning .checkbox, .has-warning .radio-inline, .has-warning .checkbox-inline { color: #8a6d3b; } .has-warning .form-control { border-color: #8a6d3b; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .has-warning .form-control:focus { border-color: #66512c; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; } .has-warning .input-group-addon { color: #8a6d3b; background-color: #fcf8e3; border-color: #8a6d3b; } .has-error .help-block, .has-error .control-label, .has-error .radio, .has-error .checkbox, .has-error .radio-inline, .has-error .checkbox-inline { color: #a94442; } .has-error .form-control { border-color: #a94442; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .has-error .form-control:focus { border-color: #843534; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; } .has-error .input-group-addon { color: #a94442; background-color: #f2dede; border-color: #a94442; } .has-success .help-block, .has-success .control-label, .has-success .radio, .has-success .checkbox, .has-success .radio-inline, .has-success .checkbox-inline { color: #3c763d; } .has-success .form-control { border-color: #3c763d; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .has-success .form-control:focus { border-color: #2b542c; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; } .has-success .input-group-addon { color: #3c763d; background-color: #dff0d8; border-color: #3c763d; } .form-control-static { margin-bottom: 0; } .help-block { display: block; margin-top: 5px; margin-bottom: 10px; color: #737373; } @media (min-width: 768px) { .form-inline .form-group { display: inline-block; margin-bottom: 0; vertical-align: middle; } .form-inline .form-control { display: inline-block; } .form-inline select.form-control { width: auto; } .form-inline .radio, .form-inline .checkbox { display: inline-block; padding-left: 0; margin-top: 0; margin-bottom: 0; } .form-inline .radio input[type="radio"], .form-inline .checkbox input[type="checkbox"] { float: none; margin-left: 0; } } .form-horizontal .control-label, .form-horizontal .radio, .form-horizontal .checkbox, .form-horizontal .radio-inline, .form-horizontal .checkbox-inline { padding-top: 7px; margin-top: 0; margin-bottom: 0; } .form-horizontal .radio, .form-horizontal .checkbox { min-height: 27px; } .form-horizontal .form-group { margin-right: -15px; margin-left: -15px; } .form-horizontal .form-group:before, .form-horizontal .form-group:after { display: table; content: " "; } .form-horizontal .form-group:after { clear: both; } .form-horizontal .form-group:before, .form-horizontal .form-group:after { display: table; content: " "; } .form-horizontal .form-group:after { clear: both; } .form-horizontal .form-control-static { padding-top: 7px; } @media (min-width: 768px) { .form-horizontal .control-label { text-align: right; } } .btn { display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: normal; line-height: 1.428571429; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; background-image: none; border: 1px solid transparent; border-radius: 4px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none; } .btn:focus { outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .btn:hover, .btn:focus { color: #333333; text-decoration: none; } .btn:active, .btn.active { background-image: none; outline: 0; -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } .btn.disabled, .btn[disabled], fieldset[disabled] .btn { pointer-events: none; cursor: not-allowed; opacity: 0.65; filter: alpha(opacity=65); -webkit-box-shadow: none; box-shadow: none; } .btn-default { color: #333333; background-color: #ffffff; border-color: #cccccc; } .btn-default:hover, .btn-default:focus, .btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default { color: #333333; background-color: #ebebeb; border-color: #adadad; } .btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default { background-image: none; } .btn-default.disabled, .btn-default[disabled], fieldset[disabled] .btn-default, .btn-default.disabled:hover, .btn-default[disabled]:hover, fieldset[disabled] .btn-default:hover, .btn-default.disabled:focus, .btn-default[disabled]:focus, fieldset[disabled] .btn-default:focus, .btn-default.disabled:active, .btn-default[disabled]:active, fieldset[disabled] .btn-default:active, .btn-default.disabled.active, .btn-default[disabled].active, fieldset[disabled] .btn-default.active { background-color: #ffffff; border-color: #cccccc; } .btn-default .badge { color: #ffffff; background-color: #fff; } .btn-primary { color: #ffffff; background-color: #428bca; border-color: #357ebd; } .btn-primary:hover, .btn-primary:focus, .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary { color: #ffffff; background-color: #3276b1; border-color: #285e8e; } .btn-primary:active, .btn-primary.active, .open .dropdown-toggle.btn-primary { background-image: none; } .btn-primary.disabled, .btn-primary[disabled], fieldset[disabled] .btn-primary, .btn-primary.disabled:hover, .btn-primary[disabled]:hover, fieldset[disabled] .btn-primary:hover, .btn-primary.disabled:focus, .btn-primary[disabled]:focus, fieldset[disabled] .btn-primary:focus, .btn-primary.disabled:active, .btn-primary[disabled]:active, fieldset[disabled] .btn-primary:active, .btn-primary.disabled.active, .btn-primary[disabled].active, fieldset[disabled] .btn-primary.active { background-color: #428bca; border-color: #357ebd; } .btn-primary .badge { color: #428bca; background-color: #fff; } .btn-warning { color: #ffffff; background-color: #f0ad4e; border-color: #eea236; } .btn-warning:hover, .btn-warning:focus, .btn-warning:active, .btn-warning.active, .open .dropdown-toggle.btn-warning { color: #ffffff; background-color: #ed9c28; border-color: #d58512; } .btn-warning:active, .btn-warning.active, .open .dropdown-toggle.btn-warning { background-image: none; } .btn-warning.disabled, .btn-warning[disabled], fieldset[disabled] .btn-warning, .btn-warning.disabled:hover, .btn-warning[disabled]:hover, fieldset[disabled] .btn-warning:hover, .btn-warning.disabled:focus, .btn-warning[disabled]:focus, fieldset[disabled] .btn-warning:focus, .btn-warning.disabled:active, .btn-warning[disabled]:active, fieldset[disabled] .btn-warning:active, .btn-warning.disabled.active, .btn-warning[disabled].active, fieldset[disabled] .btn-warning.active { background-color: #f0ad4e; border-color: #eea236; } .btn-warning .badge { color: #f0ad4e; background-color: #fff; } .btn-danger { color: #ffffff; background-color: #d9534f; border-color: #d43f3a; } .btn-danger:hover, .btn-danger:focus, .btn-danger:active, .btn-danger.active, .open .dropdown-toggle.btn-danger { color: #ffffff; background-color: #d2322d; border-color: #ac2925; } .btn-danger:active, .btn-danger.active, .open .dropdown-toggle.btn-danger { background-image: none; } .btn-danger.disabled, .btn-danger[disabled], fieldset[disabled] .btn-danger, .btn-danger.disabled:hover, .btn-danger[disabled]:hover, fieldset[disabled] .btn-danger:hover, .btn-danger.disabled:focus, .btn-danger[disabled]:focus, fieldset[disabled] .btn-danger:focus, .btn-danger.disabled:active, .btn-danger[disabled]:active, fieldset[disabled] .btn-danger:active, .btn-danger.disabled.active, .btn-danger[disabled].active, fieldset[disabled] .btn-danger.active { background-color: #d9534f; border-color: #d43f3a; } .btn-danger .badge { color: #d9534f; background-color: #fff; } .btn-success { color: #ffffff; background-color: #5cb85c; border-color: #4cae4c; } .btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success { color: #ffffff; background-color: #47a447; border-color: #398439; } .btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success { background-image: none; } .btn-success.disabled, .btn-success[disabled], fieldset[disabled] .btn-success, .btn-success.disabled:hover, .btn-success[disabled]:hover, fieldset[disabled] .btn-success:hover, .btn-success.disabled:focus, .btn-success[disabled]:focus, fieldset[disabled] .btn-success:focus, .btn-success.disabled:active, .btn-success[disabled]:active, fieldset[disabled] .btn-success:active, .btn-success.disabled.active, .btn-success[disabled].active, fieldset[disabled] .btn-success.active { background-color: #5cb85c; border-color: #4cae4c; } .btn-success .badge { color: #5cb85c; background-color: #fff; } .btn-info { color: #ffffff; background-color: #5bc0de; border-color: #46b8da; } .btn-info:hover, .btn-info:focus, .btn-info:active, .btn-info.active, .open .dropdown-toggle.btn-info { color: #ffffff; background-color: #39b3d7; border-color: #269abc; } .btn-info:active, .btn-info.active, .open .dropdown-toggle.btn-info { background-image: none; } .btn-info.disabled, .btn-info[disabled], fieldset[disabled] .btn-info, .btn-info.disabled:hover, .btn-info[disabled]:hover, fieldset[disabled] .btn-info:hover, .btn-info.disabled:focus, .btn-info[disabled]:focus, fieldset[disabled] .btn-info:focus, .btn-info.disabled:active, .btn-info[disabled]:active, fieldset[disabled] .btn-info:active, .btn-info.disabled.active, .btn-info[disabled].active, fieldset[disabled] .btn-info.active { background-color: #5bc0de; border-color: #46b8da; } .btn-info .badge { color: #5bc0de; background-color: #fff; } .btn-link { font-weight: normal; color: #428bca; cursor: pointer; border-radius: 0; } .btn-link, .btn-link:active, .btn-link[disabled], fieldset[disabled] .btn-link { background-color: transparent; -webkit-box-shadow: none; box-shadow: none; } .btn-link, .btn-link:hover, .btn-link:focus, .btn-link:active { border-color: transparent; } .btn-link:hover, .btn-link:focus { color: #2a6496; text-decoration: underline; background-color: transparent; } .btn-link[disabled]:hover, fieldset[disabled] .btn-link:hover, .btn-link[disabled]:focus, fieldset[disabled] .btn-link:focus { color: #999999; text-decoration: none; } .btn-lg { padding: 10px 16px; font-size: 18px; line-height: 1.33; border-radius: 6px; } .btn-sm { padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 3px; } .btn-xs { padding: 1px 5px; font-size: 12px; line-height: 1.5; border-radius: 3px; } .btn-block { display: block; width: 100%; padding-right: 0; padding-left: 0; } .btn-block + .btn-block { margin-top: 5px; } input[type="submit"].btn-block, input[type="reset"].btn-block, input[type="button"].btn-block { width: 100%; } .fade { opacity: 0; -webkit-transition: opacity 0.15s linear; transition: opacity 0.15s linear; } .fade.in { opacity: 1; } .collapse { display: none; } .collapse.in { display: block; } .collapsing { position: relative; height: 0; overflow: hidden; -webkit-transition: height 0.35s ease; transition: height 0.35s ease; } @font-face { font-family: 'Glyphicons Halflings'; src: url('../fonts/glyphicons-halflings-regular.eot'); src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg'); } .glyphicon { position: relative; top: 1px; display: inline-block; font-family: 'Glyphicons Halflings'; -webkit-font-smoothing: antialiased; font-style: normal; font-weight: normal; line-height: 1; -moz-osx-font-smoothing: grayscale; } .glyphicon:empty { width: 1em; } .glyphicon-asterisk:before { content: "\2a"; } .glyphicon-plus:before { content: "\2b"; } .glyphicon-euro:before { content: "\20ac"; } .glyphicon-minus:before { content: "\2212"; } .glyphicon-cloud:before { content: "\2601"; } .glyphicon-envelope:before { content: "\2709"; } .glyphicon-pencil:before { content: "\270f"; } .glyphicon-glass:before { content: "\e001"; } .glyphicon-music:before { content: "\e002"; } .glyphicon-search:before { content: "\e003"; } .glyphicon-heart:before { content: "\e005"; } .glyphicon-star:before { content: "\e006"; } .glyphicon-star-empty:before { content: "\e007"; } .glyphicon-user:before { content: "\e008"; } .glyphicon-film:before { content: "\e009"; } .glyphicon-th-large:before { content: "\e010"; } .glyphicon-th:before { content: "\e011"; } .glyphicon-th-list:before { content: "\e012"; } .glyphicon-ok:before { content: "\e013"; } .glyphicon-remove:before { content: "\e014"; } .glyphicon-zoom-in:before { content: "\e015"; } .glyphicon-zoom-out:before { content: "\e016"; } .glyphicon-off:before { content: "\e017"; } .glyphicon-signal:before { content: "\e018"; } .glyphicon-cog:before { content: "\e019"; } .glyphicon-trash:before { content: "\e020"; } .glyphicon-home:before { content: "\e021"; } .glyphicon-file:before { content: "\e022"; } .glyphicon-time:before { content: "\e023"; } .glyphicon-road:before { content: "\e024"; } .glyphicon-download-alt:before { content: "\e025"; } .glyphicon-download:before { content: "\e026"; } .glyphicon-upload:before { content: "\e027"; } .glyphicon-inbox:before { content: "\e028"; } .glyphicon-play-circle:before { content: "\e029"; } .glyphicon-repeat:before { content: "\e030"; } .glyphicon-refresh:before { content: "\e031"; } .glyphicon-list-alt:before { content: "\e032"; } .glyphicon-lock:before { content: "\e033"; } .glyphicon-flag:before { content: "\e034"; } .glyphicon-headphones:before { content: "\e035"; } .glyphicon-volume-off:before { content: "\e036"; } .glyphicon-volume-down:before { content: "\e037"; } .glyphicon-volume-up:before { content: "\e038"; } .glyphicon-qrcode:before { content: "\e039"; } .glyphicon-barcode:before { content: "\e040"; } .glyphicon-tag:before { content: "\e041"; } .glyphicon-tags:before { content: "\e042"; } .glyphicon-book:before { content: "\e043"; } .glyphicon-bookmark:before { content: "\e044"; } .glyphicon-print:before { content: "\e045"; } .glyphicon-camera:before { content: "\e046"; } .glyphicon-font:before { content: "\e047"; } .glyphicon-bold:before { content: "\e048"; } .glyphicon-italic:before { content: "\e049"; } .glyphicon-text-height:before { content: "\e050"; } .glyphicon-text-width:before { content: "\e051"; } .glyphicon-align-left:before { content: "\e052"; } .glyphicon-align-center:before { content: "\e053"; } .glyphicon-align-right:before { content: "\e054"; } .glyphicon-align-justify:before { content: "\e055"; } .glyphicon-list:before { content: "\e056"; } .glyphicon-indent-left:before { content: "\e057"; } .glyphicon-indent-right:before { content: "\e058"; } .glyphicon-facetime-video:before { content: "\e059"; } .glyphicon-picture:before { content: "\e060"; } .glyphicon-map-marker:before { content: "\e062"; } .glyphicon-adjust:before { content: "\e063"; } .glyphicon-tint:before { content: "\e064"; } .glyphicon-edit:before { content: "\e065"; } .glyphicon-share:before { content: "\e066"; } .glyphicon-check:before { content: "\e067"; } .glyphicon-move:before { content: "\e068"; } .glyphicon-step-backward:before { content: "\e069"; } .glyphicon-fast-backward:before { content: "\e070"; } .glyphicon-backward:before { content: "\e071"; } .glyphicon-play:before { content: "\e072"; } .glyphicon-pause:before { content: "\e073"; } .glyphicon-stop:before { content: "\e074"; } .glyphicon-forward:before { content: "\e075"; } .glyphicon-fast-forward:before { content: "\e076"; } .glyphicon-step-forward:before { content: "\e077"; } .glyphicon-eject:before { content: "\e078"; } .glyphicon-chevron-left:before { content: "\e079"; } .glyphicon-chevron-right:before { content: "\e080"; } .glyphicon-plus-sign:before { content: "\e081"; } .glyphicon-minus-sign:before { content: "\e082"; } .glyphicon-remove-sign:before { content: "\e083"; } .glyphicon-ok-sign:before { content: "\e084"; } .glyphicon-question-sign:before { content: "\e085"; } .glyphicon-info-sign:before { content: "\e086"; } .glyphicon-screenshot:before { content: "\e087"; } .glyphicon-remove-circle:before { content: "\e088"; } .glyphicon-ok-circle:before { content: "\e089"; } .glyphicon-ban-circle:before { content: "\e090"; } .glyphicon-arrow-left:before { content: "\e091"; } .glyphicon-arrow-right:before { content: "\e092"; } .glyphicon-arrow-up:before { content: "\e093"; } .glyphicon-arrow-down:before { content: "\e094"; } .glyphicon-share-alt:before { content: "\e095"; } .glyphicon-resize-full:before { content: "\e096"; } .glyphicon-resize-small:before { content: "\e097"; } .glyphicon-exclamation-sign:before { content: "\e101"; } .glyphicon-gift:before { content: "\e102"; } .glyphicon-leaf:before { content: "\e103"; } .glyphicon-fire:before { content: "\e104"; } .glyphicon-eye-open:before { content: "\e105"; } .glyphicon-eye-close:before { content: "\e106"; } .glyphicon-warning-sign:before { content: "\e107"; } .glyphicon-plane:before { content: "\e108"; } .glyphicon-calendar:before { content: "\e109"; } .glyphicon-random:before { content: "\e110"; } .glyphicon-comment:before { content: "\e111"; } .glyphicon-magnet:before { content: "\e112"; } .glyphicon-chevron-up:before { content: "\e113"; } .glyphicon-chevron-down:before { content: "\e114"; } .glyphicon-retweet:before { content: "\e115"; } .glyphicon-shopping-cart:before { content: "\e116"; } .glyphicon-folder-close:before { content: "\e117"; } .glyphicon-folder-open:before { content: "\e118"; } .glyphicon-resize-vertical:before { content: "\e119"; } .glyphicon-resize-horizontal:before { content: "\e120"; } .glyphicon-hdd:before { content: "\e121"; } .glyphicon-bullhorn:before { content: "\e122"; } .glyphicon-bell:before { content: "\e123"; } .glyphicon-certificate:before { content: "\e124"; } .glyphicon-thumbs-up:before { content: "\e125"; } .glyphicon-thumbs-down:before { content: "\e126"; } .glyphicon-hand-right:before { content: "\e127"; } .glyphicon-hand-left:before { content: "\e128"; } .glyphicon-hand-up:before { content: "\e129"; } .glyphicon-hand-down:before { content: "\e130"; } .glyphicon-circle-arrow-right:before { content: "\e131"; } .glyphicon-circle-arrow-left:before { content: "\e132"; } .glyphicon-circle-arrow-up:before { content: "\e133"; } .glyphicon-circle-arrow-down:before { content: "\e134"; } .glyphicon-globe:before { content: "\e135"; } .glyphicon-wrench:before { content: "\e136"; } .glyphicon-tasks:before { content: "\e137"; } .glyphicon-filter:before { content: "\e138"; } .glyphicon-briefcase:before { content: "\e139"; } .glyphicon-fullscreen:before { content: "\e140"; } .glyphicon-dashboard:before { content: "\e141"; } .glyphicon-paperclip:before { content: "\e142"; } .glyphicon-heart-empty:before { content: "\e143"; } .glyphicon-link:before { content: "\e144"; } .glyphicon-phone:before { content: "\e145"; } .glyphicon-pushpin:before { content: "\e146"; } .glyphicon-usd:before { content: "\e148"; } .glyphicon-gbp:before { content: "\e149"; } .glyphicon-sort:before { content: "\e150"; } .glyphicon-sort-by-alphabet:before { content: "\e151"; } .glyphicon-sort-by-alphabet-alt:before { content: "\e152"; } .glyphicon-sort-by-order:before { content: "\e153"; } .glyphicon-sort-by-order-alt:before { content: "\e154"; } .glyphicon-sort-by-attributes:before { content: "\e155"; } .glyphicon-sort-by-attributes-alt:before { content: "\e156"; } .glyphicon-unchecked:before { content: "\e157"; } .glyphicon-expand:before { content: "\e158"; } .glyphicon-collapse-down:before { content: "\e159"; } .glyphicon-collapse-up:before { content: "\e160"; } .glyphicon-log-in:before { content: "\e161"; } .glyphicon-flash:before { content: "\e162"; } .glyphicon-log-out:before { content: "\e163"; } .glyphicon-new-window:before { content: "\e164"; } .glyphicon-record:before { content: "\e165"; } .glyphicon-save:before { content: "\e166"; } .glyphicon-open:before { content: "\e167"; } .glyphicon-saved:before { content: "\e168"; } .glyphicon-import:before { content: "\e169"; } .glyphicon-export:before { content: "\e170"; } .glyphicon-send:before { content: "\e171"; } .glyphicon-floppy-disk:before { content: "\e172"; } .glyphicon-floppy-saved:before { content: "\e173"; } .glyphicon-floppy-remove:before { content: "\e174"; } .glyphicon-floppy-save:before { content: "\e175"; } .glyphicon-floppy-open:before { content: "\e176"; } .glyphicon-credit-card:before { content: "\e177"; } .glyphicon-transfer:before { content: "\e178"; } .glyphicon-cutlery:before { content: "\e179"; } .glyphicon-header:before { content: "\e180"; } .glyphicon-compressed:before { content: "\e181"; } .glyphicon-earphone:before { content: "\e182"; } .glyphicon-phone-alt:before { content: "\e183"; } .glyphicon-tower:before { content: "\e184"; } .glyphicon-stats:before { content: "\e185"; } .glyphicon-sd-video:before { content: "\e186"; } .glyphicon-hd-video:before { content: "\e187"; } .glyphicon-subtitles:before { content: "\e188"; } .glyphicon-sound-stereo:before { content: "\e189"; } .glyphicon-sound-dolby:before { content: "\e190"; } .glyphicon-sound-5-1:before { content: "\e191"; } .glyphicon-sound-6-1:before { content: "\e192"; } .glyphicon-sound-7-1:before { content: "\e193"; } .glyphicon-copyright-mark:before { content: "\e194"; } .glyphicon-registration-mark:before { content: "\e195"; } .glyphicon-cloud-download:before { content: "\e197"; } .glyphicon-cloud-upload:before { content: "\e198"; } .glyphicon-tree-conifer:before { content: "\e199"; } .glyphicon-tree-deciduous:before { content: "\e200"; } .caret { display: inline-block; width: 0; height: 0; margin-left: 2px; vertical-align: middle; border-top: 4px solid; border-right: 4px solid transparent; border-left: 4px solid transparent; } .dropdown { position: relative; } .dropdown-toggle:focus { outline: 0; } .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: 1000; display: none; float: left; min-width: 160px; padding: 5px 0; margin: 2px 0 0; font-size: 14px; list-style: none; background-color: #ffffff; border: 1px solid #cccccc; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 4px; -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); background-clip: padding-box; } .dropdown-menu.pull-right { right: 0; left: auto; } .dropdown-menu .divider { height: 1px; margin: 9px 0; overflow: hidden; background-color: #e5e5e5; } .dropdown-menu > li > a { display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: 1.428571429; color: #333333; white-space: nowrap; } .dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus { color: #262626; text-decoration: none; background-color: #f5f5f5; } .dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus { color: #ffffff; text-decoration: none; background-color: #428bca; outline: 0; } .dropdown-menu > .disabled > a, .dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus { color: #999999; } .dropdown-menu > .disabled > a:hover, .dropdown-menu > .disabled > a:focus { text-decoration: none; cursor: not-allowed; background-color: transparent; background-image: none; filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .open > .dropdown-menu { display: block; } .open > a { outline: 0; } .dropdown-header { display: block; padding: 3px 20px; font-size: 12px; line-height: 1.428571429; color: #999999; } .dropdown-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 990; } .pull-right > .dropdown-menu { right: 0; left: auto; } .dropup .caret, .navbar-fixed-bottom .dropdown .caret { border-top: 0; border-bottom: 4px solid; content: ""; } .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { top: auto; bottom: 100%; margin-bottom: 1px; } @media (min-width: 768px) { .navbar-right .dropdown-menu { right: 0; left: auto; } } .btn-group, .btn-group-vertical { position: relative; display: inline-block; vertical-align: middle; } .btn-group > .btn, .btn-group-vertical > .btn { position: relative; float: left; } .btn-group > .btn:hover, .btn-group-vertical > .btn:hover, .btn-group > .btn:focus, .btn-group-vertical > .btn:focus, .btn-group > .btn:active, .btn-group-vertical > .btn:active, .btn-group > .btn.active, .btn-group-vertical > .btn.active { z-index: 2; } .btn-group > .btn:focus, .btn-group-vertical > .btn:focus { outline: none; } .btn-group .btn + .btn, .btn-group .btn + .btn-group, .btn-group .btn-group + .btn, .btn-group .btn-group + .btn-group { margin-left: -1px; } .btn-toolbar:before, .btn-toolbar:after { display: table; content: " "; } .btn-toolbar:after { clear: both; } .btn-toolbar:before, .btn-toolbar:after { display: table; content: " "; } .btn-toolbar:after { clear: both; } .btn-toolbar .btn-group { float: left; } .btn-toolbar > .btn + .btn, .btn-toolbar > .btn-group + .btn, .btn-toolbar > .btn + .btn-group, .btn-toolbar > .btn-group + .btn-group { margin-left: 5px; } .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { border-radius: 0; } .btn-group > .btn:first-child { margin-left: 0; } .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { border-top-right-radius: 0; border-bottom-right-radius: 0; } .btn-group > .btn:last-child:not(:first-child), .btn-group > .dropdown-toggle:not(:first-child) { border-bottom-left-radius: 0; border-top-left-radius: 0; } .btn-group > .btn-group { float: left; } .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { border-radius: 0; } .btn-group > .btn-group:first-child > .btn:last-child, .btn-group > .btn-group:first-child > .dropdown-toggle { border-top-right-radius: 0; border-bottom-right-radius: 0; } .btn-group > .btn-group:last-child > .btn:first-child { border-bottom-left-radius: 0; border-top-left-radius: 0; } .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; } .btn-group-xs > .btn { padding: 1px 5px; font-size: 12px; line-height: 1.5; border-radius: 3px; } .btn-group-sm > .btn { padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 3px; } .btn-group-lg > .btn { padding: 10px 16px; font-size: 18px; line-height: 1.33; border-radius: 6px; } .btn-group > .btn + .dropdown-toggle { padding-right: 8px; padding-left: 8px; } .btn-group > .btn-lg + .dropdown-toggle { padding-right: 12px; padding-left: 12px; } .btn-group.open .dropdown-toggle { -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } .btn-group.open .dropdown-toggle.btn-link { -webkit-box-shadow: none; box-shadow: none; } .btn .caret { margin-left: 0; } .btn-lg .caret { border-width: 5px 5px 0; border-bottom-width: 0; } .dropup .btn-lg .caret { border-width: 0 5px 5px; } .btn-group-vertical > .btn, .btn-group-vertical > .btn-group, .btn-group-vertical > .btn-group > .btn { display: block; float: none; width: 100%; max-width: 100%; } .btn-group-vertical > .btn-group:before, .btn-group-vertical > .btn-group:after { display: table; content: " "; } .btn-group-vertical > .btn-group:after { clear: both; } .btn-group-vertical > .btn-group:before, .btn-group-vertical > .btn-group:after { display: table; content: " "; } .btn-group-vertical > .btn-group:after { clear: both; } .btn-group-vertical > .btn-group > .btn { float: none; } .btn-group-vertical > .btn + .btn, .btn-group-vertical > .btn + .btn-group, .btn-group-vertical > .btn-group + .btn, .btn-group-vertical > .btn-group + .btn-group { margin-top: -1px; margin-left: 0; } .btn-group-vertical > .btn:not(:first-child):not(:last-child) { border-radius: 0; } .btn-group-vertical > .btn:first-child:not(:last-child) { border-top-right-radius: 4px; border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .btn-group-vertical > .btn:last-child:not(:first-child) { border-top-right-radius: 0; border-bottom-left-radius: 4px; border-top-left-radius: 0; } .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { border-radius: 0; } .btn-group-vertical > .btn-group:first-child > .btn:last-child, .btn-group-vertical > .btn-group:first-child > .dropdown-toggle { border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .btn-group-vertical > .btn-group:last-child > .btn:first-child { border-top-right-radius: 0; border-top-left-radius: 0; } .btn-group-justified { display: table; width: 100%; border-collapse: separate; table-layout: fixed; } .btn-group-justified > .btn, .btn-group-justified > .btn-group { display: table-cell; float: none; width: 1%; } .btn-group-justified > .btn-group .btn { width: 100%; } [data-toggle="buttons"] > .btn > input[type="radio"], [data-toggle="buttons"] > .btn > input[type="checkbox"] { display: none; } .input-group { position: relative; display: table; border-collapse: separate; } .input-group[class*="col-"] { float: none; padding-right: 0; padding-left: 0; } .input-group .form-control { width: 100%; margin-bottom: 0; } .input-group-lg > .form-control, .input-group-lg > .input-group-addon, .input-group-lg > .input-group-btn > .btn { height: 46px; padding: 10px 16px; font-size: 18px; line-height: 1.33; border-radius: 6px; } select.input-group-lg > .form-control, select.input-group-lg > .input-group-addon, select.input-group-lg > .input-group-btn > .btn { height: 46px; line-height: 46px; } textarea.input-group-lg > .form-control, textarea.input-group-lg > .input-group-addon, textarea.input-group-lg > .input-group-btn > .btn { height: auto; } .input-group-sm > .form-control, .input-group-sm > .input-group-addon, .input-group-sm > .input-group-btn > .btn { height: 30px; padding: 5px 10px; font-size: 12px; line-height: 1.5; border-radius: 3px; } select.input-group-sm > .form-control, select.input-group-sm > .input-group-addon, select.input-group-sm > .input-group-btn > .btn { height: 30px; line-height: 30px; } textarea.input-group-sm > .form-control, textarea.input-group-sm > .input-group-addon, textarea.input-group-sm > .input-group-btn > .btn { height: auto; } .input-group-addon, .input-group-btn, .input-group .form-control { display: table-cell; } .input-group-addon:not(:first-child):not(:last-child), .input-group-btn:not(:first-child):not(:last-child), .input-group .form-control:not(:first-child):not(:last-child) { border-radius: 0; } .input-group-addon, .input-group-btn { width: 1%; white-space: nowrap; vertical-align: middle; } .input-group-addon { padding: 6px 12px; font-size: 14px; font-weight: normal; line-height: 1; color: #555555; text-align: center; background-color: #eeeeee; border: 1px solid #cccccc; border-radius: 4px; } .input-group-addon.input-sm { padding: 5px 10px; font-size: 12px; border-radius: 3px; } .input-group-addon.input-lg { padding: 10px 16px; font-size: 18px; border-radius: 6px; } .input-group-addon input[type="radio"], .input-group-addon input[type="checkbox"] { margin-top: 0; } .input-group .form-control:first-child, .input-group-addon:first-child, .input-group-btn:first-child > .btn, .input-group-btn:first-child > .dropdown-toggle, .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { border-top-right-radius: 0; border-bottom-right-radius: 0; } .input-group-addon:first-child { border-right: 0; } .input-group .form-control:last-child, .input-group-addon:last-child, .input-group-btn:last-child > .btn, .input-group-btn:last-child > .dropdown-toggle, .input-group-btn:first-child > .btn:not(:first-child) { border-bottom-left-radius: 0; border-top-left-radius: 0; } .input-group-addon:last-child { border-left: 0; } .input-group-btn { position: relative; white-space: nowrap; } .input-group-btn:first-child > .btn { margin-right: -1px; } .input-group-btn:last-child > .btn { margin-left: -1px; } .input-group-btn > .btn { position: relative; } .input-group-btn > .btn + .btn { margin-left: -4px; } .input-group-btn > .btn:hover, .input-group-btn > .btn:active { z-index: 2; } .nav { padding-left: 0; margin-bottom: 0; list-style: none; } .nav:before, .nav:after { display: table; content: " "; } .nav:after { clear: both; } .nav:before, .nav:after { display: table; content: " "; } .nav:after { clear: both; } .nav > li { position: relative; display: block; } .nav > li > a { position: relative; display: block; padding: 10px 15px; } .nav > li > a:hover, .nav > li > a:focus { text-decoration: none; background-color: #eeeeee; } .nav > li.disabled > a { color: #999999; } .nav > li.disabled > a:hover, .nav > li.disabled > a:focus { color: #999999; text-decoration: none; cursor: not-allowed; background-color: transparent; } .nav .open > a, .nav .open > a:hover, .nav .open > a:focus { background-color: #eeeeee; border-color: #428bca; } .nav .nav-divider { height: 1px; margin: 9px 0; overflow: hidden; background-color: #e5e5e5; } .nav > li > a > img { max-width: none; } .nav-tabs { border-bottom: 1px solid #dddddd; } .nav-tabs > li { float: left; margin-bottom: -1px; } .nav-tabs > li > a { margin-right: 2px; line-height: 1.428571429; border: 1px solid transparent; border-radius: 4px 4px 0 0; } .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #dddddd; } .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus { color: #555555; cursor: default; background-color: #ffffff; border: 1px solid #dddddd; border-bottom-color: transparent; } .nav-tabs.nav-justified { width: 100%; border-bottom: 0; } .nav-tabs.nav-justified > li { float: none; } .nav-tabs.nav-justified > li > a { margin-bottom: 5px; text-align: center; } .nav-tabs.nav-justified > .dropdown .dropdown-menu { top: auto; left: auto; } @media (min-width: 768px) { .nav-tabs.nav-justified > li { display: table-cell; width: 1%; } .nav-tabs.nav-justified > li > a { margin-bottom: 0; } } .nav-tabs.nav-justified > li > a { margin-right: 0; border-radius: 4px; } .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus { border: 1px solid #dddddd; } @media (min-width: 768px) { .nav-tabs.nav-justified > li > a { border-bottom: 1px solid #dddddd; border-radius: 4px 4px 0 0; } .nav-tabs.nav-justified > .active > a, .nav-tabs.nav-justified > .active > a:hover, .nav-tabs.nav-justified > .active > a:focus { border-bottom-color: #ffffff; } } .nav-pills > li { float: left; } .nav-pills > li > a { border-radius: 4px; } .nav-pills > li + li { margin-left: 2px; } .nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus { color: #ffffff; background-color: #428bca; } .nav-stacked > li { float: none; } .nav-stacked > li + li { margin-top: 2px; margin-left: 0; } .nav-justified { width: 100%; } .nav-justified > li { float: none; } .nav-justified > li > a { margin-bottom: 5px; text-align: center; } .nav-justified > .dropdown .dropdown-menu { top: auto; left: auto; } @media (min-width: 768px) { .nav-justified > li { display: table-cell; width: 1%; } .nav-justified > li > a { margin-bottom: 0; } } .nav-tabs-justified { border-bottom: 0; } .nav-tabs-justified > li > a { margin-right: 0; border-radius: 4px; } .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, .nav-tabs-justified > .active > a:focus { border: 1px solid #dddddd; } @media (min-width: 768px) { .nav-tabs-justified > li > a { border-bottom: 1px solid #dddddd; border-radius: 4px 4px 0 0; } .nav-tabs-justified > .active > a, .nav-tabs-justified > .active > a:hover, .nav-tabs-justified > .active > a:focus { border-bottom-color: #ffffff; } } .tab-content > .tab-pane { display: none; } .tab-content > .active { display: block; } .nav-tabs .dropdown-menu { margin-top: -1px; border-top-right-radius: 0; border-top-left-radius: 0; } .navbar { position: relative; min-height: 50px; margin-bottom: 20px; border: 1px solid transparent; } .navbar:before, .navbar:after { display: table; content: " "; } .navbar:after { clear: both; } .navbar:before, .navbar:after { display: table; content: " "; } .navbar:after { clear: both; } @media (min-width: 768px) { .navbar { border-radius: 4px; } } .navbar-header:before, .navbar-header:after { display: table; content: " "; } .navbar-header:after { clear: both; } .navbar-header:before, .navbar-header:after { display: table; content: " "; } .navbar-header:after { clear: both; } @media (min-width: 768px) { .navbar-header { float: left; } } .navbar-collapse { max-height: 340px; padding-right: 15px; padding-left: 15px; overflow-x: visible; border-top: 1px solid transparent; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); -webkit-overflow-scrolling: touch; } .navbar-collapse:before, .navbar-collapse:after { display: table; content: " "; } .navbar-collapse:after { clear: both; } .navbar-collapse:before, .navbar-collapse:after { display: table; content: " "; } .navbar-collapse:after { clear: both; } .navbar-collapse.in { overflow-y: auto; } @media (min-width: 768px) { .navbar-collapse { width: auto; border-top: 0; box-shadow: none; } .navbar-collapse.collapse { display: block !important; height: auto !important; padding-bottom: 0; overflow: visible !important; } .navbar-collapse.in { overflow-y: visible; } .navbar-fixed-top .navbar-collapse, .navbar-static-top .navbar-collapse, .navbar-fixed-bottom .navbar-collapse { padding-right: 0; padding-left: 0; } } .container > .navbar-header, .container > .navbar-collapse { margin-right: -15px; margin-left: -15px; } @media (min-width: 768px) { .container > .navbar-header, .container > .navbar-collapse { margin-right: 0; margin-left: 0; } } .navbar-static-top { z-index: 1000; border-width: 0 0 1px; } @media (min-width: 768px) { .navbar-static-top { border-radius: 0; } } .navbar-fixed-top, .navbar-fixed-bottom { position: fixed; right: 0; left: 0; z-index: 1030; } @media (min-width: 768px) { .navbar-fixed-top, .navbar-fixed-bottom { border-radius: 0; } } .navbar-fixed-top { top: 0; border-width: 0 0 1px; } .navbar-fixed-bottom { bottom: 0; margin-bottom: 0; border-width: 1px 0 0; } .navbar-brand { float: left; padding: 15px 15px; font-size: 18px; line-height: 20px; } .navbar-brand:hover, .navbar-brand:focus { text-decoration: none; } @media (min-width: 768px) { .navbar > .container .navbar-brand { margin-left: -15px; } } .navbar-toggle { position: relative; float: right; padding: 9px 10px; margin-top: 8px; margin-right: 15px; margin-bottom: 8px; background-color: transparent; background-image: none; border: 1px solid transparent; border-radius: 4px; } .navbar-toggle .icon-bar { display: block; width: 22px; height: 2px; border-radius: 1px; } .navbar-toggle .icon-bar + .icon-bar { margin-top: 4px; } @media (min-width: 768px) { .navbar-toggle { display: none; } } .navbar-nav { margin: 7.5px -15px; } .navbar-nav > li > a { padding-top: 10px; padding-bottom: 10px; line-height: 20px; } @media (max-width: 767px) { .navbar-nav .open .dropdown-menu { position: static; float: none; width: auto; margin-top: 0; background-color: transparent; border: 0; box-shadow: none; } .navbar-nav .open .dropdown-menu > li > a, .navbar-nav .open .dropdown-menu .dropdown-header { padding: 5px 15px 5px 25px; } .navbar-nav .open .dropdown-menu > li > a { line-height: 20px; } .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-nav .open .dropdown-menu > li > a:focus { background-image: none; } } @media (min-width: 768px) { .navbar-nav { float: left; margin: 0; } .navbar-nav > li { float: left; } .navbar-nav > li > a { padding-top: 15px; padding-bottom: 15px; } .navbar-nav.navbar-right:last-child { margin-right: -15px; } } @media (min-width: 768px) { .navbar-left { float: left !important; } .navbar-right { float: right !important; } } .navbar-form { padding: 10px 15px; margin-top: 8px; margin-right: -15px; margin-bottom: 8px; margin-left: -15px; border-top: 1px solid transparent; border-bottom: 1px solid transparent; -webkit-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); } @media (min-width: 768px) { .navbar-form .form-group { display: inline-block; margin-bottom: 0; vertical-align: middle; } .navbar-form .form-control { display: inline-block; } .navbar-form select.form-control { width: auto; } .navbar-form .radio, .navbar-form .checkbox { display: inline-block; padding-left: 0; margin-top: 0; margin-bottom: 0; } .navbar-form .radio input[type="radio"], .navbar-form .checkbox input[type="checkbox"] { float: none; margin-left: 0; } } @media (max-width: 767px) { .navbar-form .form-group { margin-bottom: 5px; } } @media (min-width: 768px) { .navbar-form { width: auto; padding-top: 0; padding-bottom: 0; margin-right: 0; margin-left: 0; border: 0; -webkit-box-shadow: none; box-shadow: none; } .navbar-form.navbar-right:last-child { margin-right: -15px; } } .navbar-nav > li > .dropdown-menu { margin-top: 0; border-top-right-radius: 0; border-top-left-radius: 0; } .navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .navbar-nav.pull-right > li > .dropdown-menu, .navbar-nav > li > .dropdown-menu.pull-right { right: 0; left: auto; } .navbar-btn { margin-top: 8px; margin-bottom: 8px; } .navbar-btn.btn-sm { margin-top: 10px; margin-bottom: 10px; } .navbar-btn.btn-xs { margin-top: 14px; margin-bottom: 14px; } .navbar-text { margin-top: 15px; margin-bottom: 15px; } @media (min-width: 768px) { .navbar-text { float: left; margin-right: 15px; margin-left: 15px; } .navbar-text.navbar-right:last-child { margin-right: 0; } } .navbar-default { background-color: #f8f8f8; border-color: #e7e7e7; } .navbar-default .navbar-brand { color: #777777; } .navbar-default .navbar-brand:hover, .navbar-default .navbar-brand:focus { color: #5e5e5e; background-color: transparent; } .navbar-default .navbar-text { color: #777777; } .navbar-default .navbar-nav > li > a { color: #777777; } .navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus { color: #333333; background-color: transparent; } .navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover, .navbar-default .navbar-nav > .active > a:focus { color: #555555; background-color: #e7e7e7; } .navbar-default .navbar-nav > .disabled > a, .navbar-default .navbar-nav > .disabled > a:hover, .navbar-default .navbar-nav > .disabled > a:focus { color: #cccccc; background-color: transparent; } .navbar-default .navbar-toggle { border-color: #dddddd; } .navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus { background-color: #dddddd; } .navbar-default .navbar-toggle .icon-bar { background-color: #cccccc; } .navbar-default .navbar-collapse, .navbar-default .navbar-form { border-color: #e7e7e7; } .navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:hover, .navbar-default .navbar-nav > .open > a:focus { color: #555555; background-color: #e7e7e7; } @media (max-width: 767px) { .navbar-default .navbar-nav .open .dropdown-menu > li > a { color: #777777; } .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { color: #333333; background-color: transparent; } .navbar-default .navbar-nav .open .dropdown-menu > .active > a, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { color: #555555; background-color: #e7e7e7; } .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { color: #cccccc; background-color: transparent; } } .navbar-default .navbar-link { color: #777777; } .navbar-default .navbar-link:hover { color: #333333; } .navbar-inverse { background-color: #222222; border-color: #080808; } .navbar-inverse .navbar-brand { color: #999999; } .navbar-inverse .navbar-brand:hover, .navbar-inverse .navbar-brand:focus { color: #ffffff; background-color: transparent; } .navbar-inverse .navbar-text { color: #999999; } .navbar-inverse .navbar-nav > li > a { color: #999999; } .navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > a:focus { color: #ffffff; background-color: transparent; } .navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus { color: #ffffff; background-color: #080808; } .navbar-inverse .navbar-nav > .disabled > a, .navbar-inverse .navbar-nav > .disabled > a:hover, .navbar-inverse .navbar-nav > .disabled > a:focus { color: #444444; background-color: transparent; } .navbar-inverse .navbar-toggle { border-color: #333333; } .navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus { background-color: #333333; } .navbar-inverse .navbar-toggle .icon-bar { background-color: #ffffff; } .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { border-color: #101010; } .navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > a:hover, .navbar-inverse .navbar-nav > .open > a:focus { color: #ffffff; background-color: #080808; } @media (max-width: 767px) { .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { border-color: #080808; } .navbar-inverse .navbar-nav .open .dropdown-menu .divider { background-color: #080808; } .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { color: #999999; } .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { color: #ffffff; background-color: transparent; } .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { color: #ffffff; background-color: #080808; } .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { color: #444444; background-color: transparent; } } .navbar-inverse .navbar-link { color: #999999; } .navbar-inverse .navbar-link:hover { color: #ffffff; } .breadcrumb { padding: 8px 15px; margin-bottom: 20px; list-style: none; background-color: #f5f5f5; border-radius: 4px; } .breadcrumb > li { display: inline-block; } .breadcrumb > li + li:before { padding: 0 5px; color: #cccccc; content: "/\00a0"; } .breadcrumb > .active { color: #999999; } .pagination { display: inline-block; padding-left: 0; margin: 20px 0; border-radius: 4px; } .pagination > li { display: inline; } .pagination > li > a, .pagination > li > span { position: relative; float: left; padding: 6px 12px; margin-left: -1px; line-height: 1.428571429; text-decoration: none; background-color: #ffffff; border: 1px solid #dddddd; } .pagination > li:first-child > a, .pagination > li:first-child > span { margin-left: 0; border-bottom-left-radius: 4px; border-top-left-radius: 4px; } .pagination > li:last-child > a, .pagination > li:last-child > span { border-top-right-radius: 4px; border-bottom-right-radius: 4px; } .pagination > li > a:hover, .pagination > li > span:hover, .pagination > li > a:focus, .pagination > li > span:focus { background-color: #eeeeee; } .pagination > .active > a, .pagination > .active > span, .pagination > .active > a:hover, .pagination > .active > span:hover, .pagination > .active > a:focus, .pagination > .active > span:focus { z-index: 2; color: #ffffff; cursor: default; background-color: #428bca; border-color: #428bca; } .pagination > .disabled > span, .pagination > .disabled > span:hover, .pagination > .disabled > span:focus, .pagination > .disabled > a, .pagination > .disabled > a:hover, .pagination > .disabled > a:focus { color: #999999; cursor: not-allowed; background-color: #ffffff; border-color: #dddddd; } .pagination-lg > li > a, .pagination-lg > li > span { padding: 10px 16px; font-size: 18px; } .pagination-lg > li:first-child > a, .pagination-lg > li:first-child > span { border-bottom-left-radius: 6px; border-top-left-radius: 6px; } .pagination-lg > li:last-child > a, .pagination-lg > li:last-child > span { border-top-right-radius: 6px; border-bottom-right-radius: 6px; } .pagination-sm > li > a, .pagination-sm > li > span { padding: 5px 10px; font-size: 12px; } .pagination-sm > li:first-child > a, .pagination-sm > li:first-child > span { border-bottom-left-radius: 3px; border-top-left-radius: 3px; } .pagination-sm > li:last-child > a, .pagination-sm > li:last-child > span { border-top-right-radius: 3px; border-bottom-right-radius: 3px; } .pager { padding-left: 0; margin: 20px 0; text-align: center; list-style: none; } .pager:before, .pager:after { display: table; content: " "; } .pager:after { clear: both; } .pager:before, .pager:after { display: table; content: " "; } .pager:after { clear: both; } .pager li { display: inline; } .pager li > a, .pager li > span { display: inline-block; padding: 5px 14px; background-color: #ffffff; border: 1px solid #dddddd; border-radius: 15px; } .pager li > a:hover, .pager li > a:focus { text-decoration: none; background-color: #eeeeee; } .pager .next > a, .pager .next > span { float: right; } .pager .previous > a, .pager .previous > span { float: left; } .pager .disabled > a, .pager .disabled > a:hover, .pager .disabled > a:focus, .pager .disabled > span { color: #999999; cursor: not-allowed; background-color: #ffffff; } .label { display: inline; padding: .2em .6em .3em; font-size: 75%; font-weight: bold; line-height: 1; color: #ffffff; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: .25em; } .label[href]:hover, .label[href]:focus { color: #ffffff; text-decoration: none; cursor: pointer; } .label:empty { display: none; } .btn .label { position: relative; top: -1px; } .label-default { background-color: #999999; } .label-default[href]:hover, .label-default[href]:focus { background-color: #808080; } .label-primary { background-color: #428bca; } .label-primary[href]:hover, .label-primary[href]:focus { background-color: #3071a9; } .label-success { background-color: #5cb85c; } .label-success[href]:hover, .label-success[href]:focus { background-color: #449d44; } .label-info { background-color: #5bc0de; } .label-info[href]:hover, .label-info[href]:focus { background-color: #31b0d5; } .label-warning { background-color: #f0ad4e; } .label-warning[href]:hover, .label-warning[href]:focus { background-color: #ec971f; } .label-danger { background-color: #d9534f; } .label-danger[href]:hover, .label-danger[href]:focus { background-color: #c9302c; } .badge { display: inline-block; min-width: 10px; padding: 3px 7px; font-size: 12px; font-weight: bold; line-height: 1; color: #ffffff; text-align: center; white-space: nowrap; vertical-align: baseline; background-color: #999999; border-radius: 10px; } .badge:empty { display: none; } .btn .badge { position: relative; top: -1px; } a.badge:hover, a.badge:focus { color: #ffffff; text-decoration: none; cursor: pointer; } a.list-group-item.active > .badge, .nav-pills > .active > a > .badge { color: #428bca; background-color: #ffffff; } .nav-pills > li > a > .badge { margin-left: 3px; } .jumbotron { padding: 30px; margin-bottom: 30px; font-size: 21px; font-weight: 200; line-height: 2.1428571435; color: inherit; background-color: #eeeeee; } .jumbotron h1, .jumbotron .h1 { line-height: 1; color: inherit; } .jumbotron p { line-height: 1.4; } .container .jumbotron { border-radius: 6px; } .jumbotron .container { max-width: 100%; } @media screen and (min-width: 768px) { .jumbotron { padding-top: 48px; padding-bottom: 48px; } .container .jumbotron { padding-right: 60px; padding-left: 60px; } .jumbotron h1, .jumbotron .h1 { font-size: 63px; } } .thumbnail { display: block; padding: 4px; margin-bottom: 20px; line-height: 1.428571429; background-color: #ffffff; border: 1px solid #dddddd; border-radius: 4px; -webkit-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } .thumbnail > img, .thumbnail a > img { display: block; height: auto; max-width: 100%; margin-right: auto; margin-left: auto; } a.thumbnail:hover, a.thumbnail:focus, a.thumbnail.active { border-color: #428bca; } .thumbnail .caption { padding: 9px; color: #333333; } .alert { padding: 15px; margin-bottom: 20px; border: 1px solid transparent; border-radius: 4px; } .alert h4 { margin-top: 0; color: inherit; } .alert .alert-link { font-weight: bold; } .alert > p, .alert > ul { margin-bottom: 0; } .alert > p + p { margin-top: 5px; } .alert-dismissable { padding-right: 35px; } .alert-dismissable .close { position: relative; top: -2px; right: -21px; color: inherit; } .alert-success { color: #3c763d; background-color: #dff0d8; border-color: #d6e9c6; } .alert-success hr { border-top-color: #c9e2b3; } .alert-success .alert-link { color: #2b542c; } .alert-info { color: #31708f; background-color: #d9edf7; border-color: #bce8f1; } .alert-info hr { border-top-color: #a6e1ec; } .alert-info .alert-link { color: #245269; } .alert-warning { color: #8a6d3b; background-color: #fcf8e3; border-color: #faebcc; } .alert-warning hr { border-top-color: #f7e1b5; } .alert-warning .alert-link { color: #66512c; } .alert-danger { color: #a94442; background-color: #f2dede; border-color: #ebccd1; } .alert-danger hr { border-top-color: #e4b9c0; } .alert-danger .alert-link { color: #843534; } @-webkit-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } .progress { height: 20px; margin-bottom: 20px; overflow: hidden; background-color: #f5f5f5; border-radius: 4px; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } .progress-bar { float: left; width: 0; height: 100%; font-size: 12px; line-height: 20px; color: #ffffff; text-align: center; background-color: #428bca; -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -webkit-transition: width 0.6s ease; transition: width 0.6s ease; } .progress-striped .progress-bar { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-size: 40px 40px; } .progress.active .progress-bar { -webkit-animation: progress-bar-stripes 2s linear infinite; animation: progress-bar-stripes 2s linear infinite; } .progress-bar-success { background-color: #5cb85c; } .progress-striped .progress-bar-success { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-bar-info { background-color: #5bc0de; } .progress-striped .progress-bar-info { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-bar-warning { background-color: #f0ad4e; } .progress-striped .progress-bar-warning { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-bar-danger { background-color: #d9534f; } .progress-striped .progress-bar-danger { background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .media, .media-body { overflow: hidden; zoom: 1; } .media, .media .media { margin-top: 15px; } .media:first-child { margin-top: 0; } .media-object { display: block; } .media-heading { margin: 0 0 5px; } .media > .pull-left { margin-right: 10px; } .media > .pull-right { margin-left: 10px; } .media-list { padding-left: 0; list-style: none; } .list-group { padding-left: 0; margin-bottom: 20px; } .list-group-item { position: relative; display: block; padding: 10px 15px; margin-bottom: -1px; background-color: #ffffff; border: 1px solid #dddddd; } .list-group-item:first-child { border-top-right-radius: 4px; border-top-left-radius: 4px; } .list-group-item:last-child { margin-bottom: 0; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; } .list-group-item > .badge { float: right; } .list-group-item > .badge + .badge { margin-right: 5px; } a.list-group-item { color: #555555; } a.list-group-item .list-group-item-heading { color: #333333; } a.list-group-item:hover, a.list-group-item:focus { text-decoration: none; background-color: #f5f5f5; } a.list-group-item.active, a.list-group-item.active:hover, a.list-group-item.active:focus { z-index: 2; color: #ffffff; background-color: #428bca; border-color: #428bca; } a.list-group-item.active .list-group-item-heading, a.list-group-item.active:hover .list-group-item-heading, a.list-group-item.active:focus .list-group-item-heading { color: inherit; } a.list-group-item.active .list-group-item-text, a.list-group-item.active:hover .list-group-item-text, a.list-group-item.active:focus .list-group-item-text { color: #e1edf7; } .list-group-item-heading { margin-top: 0; margin-bottom: 5px; } .list-group-item-text { margin-bottom: 0; line-height: 1.3; } .panel { margin-bottom: 20px; background-color: #ffffff; border: 1px solid transparent; border-radius: 4px; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); } .panel-body { padding: 15px; } .panel-body:before, .panel-body:after { display: table; content: " "; } .panel-body:after { clear: both; } .panel-body:before, .panel-body:after { display: table; content: " "; } .panel-body:after { clear: both; } .panel > .list-group { margin-bottom: 0; } .panel > .list-group .list-group-item { border-width: 1px 0; } .panel > .list-group .list-group-item:first-child { border-top-right-radius: 0; border-top-left-radius: 0; } .panel > .list-group .list-group-item:last-child { border-bottom: 0; } .panel-heading + .list-group .list-group-item:first-child { border-top-width: 0; } .panel > .table, .panel > .table-responsive > .table { margin-bottom: 0; } .panel > .panel-body + .table, .panel > .panel-body + .table-responsive { border-top: 1px solid #dddddd; } .panel > .table > tbody:first-child th, .panel > .table > tbody:first-child td { border-top: 0; } .panel > .table-bordered, .panel > .table-responsive > .table-bordered { border: 0; } .panel > .table-bordered > thead > tr > th:first-child, .panel > .table-responsive > .table-bordered > thead > tr > th:first-child, .panel > .table-bordered > tbody > tr > th:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, .panel > .table-bordered > tfoot > tr > th:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, .panel > .table-bordered > thead > tr > td:first-child, .panel > .table-responsive > .table-bordered > thead > tr > td:first-child, .panel > .table-bordered > tbody > tr > td:first-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, .panel > .table-bordered > tfoot > tr > td:first-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { border-left: 0; } .panel > .table-bordered > thead > tr > th:last-child, .panel > .table-responsive > .table-bordered > thead > tr > th:last-child, .panel > .table-bordered > tbody > tr > th:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, .panel > .table-bordered > tfoot > tr > th:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, .panel > .table-bordered > thead > tr > td:last-child, .panel > .table-responsive > .table-bordered > thead > tr > td:last-child, .panel > .table-bordered > tbody > tr > td:last-child, .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, .panel > .table-bordered > tfoot > tr > td:last-child, .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { border-right: 0; } .panel > .table-bordered > thead > tr:last-child > th, .panel > .table-responsive > .table-bordered > thead > tr:last-child > th, .panel > .table-bordered > tbody > tr:last-child > th, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, .panel > .table-bordered > tfoot > tr:last-child > th, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, .panel > .table-bordered > thead > tr:last-child > td, .panel > .table-responsive > .table-bordered > thead > tr:last-child > td, .panel > .table-bordered > tbody > tr:last-child > td, .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, .panel > .table-bordered > tfoot > tr:last-child > td, .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { border-bottom: 0; } .panel > .table-responsive { margin-bottom: 0; border: 0; } .panel-heading { padding: 10px 15px; border-bottom: 1px solid transparent; border-top-right-radius: 3px; border-top-left-radius: 3px; } .panel-heading > .dropdown .dropdown-toggle { color: inherit; } .panel-title { margin-top: 0; margin-bottom: 0; font-size: 16px; color: inherit; } .panel-title > a { color: inherit; } .panel-footer { padding: 10px 15px; background-color: #f5f5f5; border-top: 1px solid #dddddd; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; } .panel-group .panel { margin-bottom: 0; overflow: hidden; border-radius: 4px; } .panel-group .panel + .panel { margin-top: 5px; } .panel-group .panel-heading { border-bottom: 0; } .panel-group .panel-heading + .panel-collapse .panel-body { border-top: 1px solid #dddddd; } .panel-group .panel-footer { border-top: 0; } .panel-group .panel-footer + .panel-collapse .panel-body { border-bottom: 1px solid #dddddd; } .panel-default { border-color: #dddddd; } .panel-default > .panel-heading { color: #333333; background-color: #f5f5f5; border-color: #dddddd; } .panel-default > .panel-heading + .panel-collapse .panel-body { border-top-color: #dddddd; } .panel-default > .panel-footer + .panel-collapse .panel-body { border-bottom-color: #dddddd; } .panel-primary { border-color: #428bca; } .panel-primary > .panel-heading { color: #ffffff; background-color: #428bca; border-color: #428bca; } .panel-primary > .panel-heading + .panel-collapse .panel-body { border-top-color: #428bca; } .panel-primary > .panel-footer + .panel-collapse .panel-body { border-bottom-color: #428bca; } .panel-success { border-color: #d6e9c6; } .panel-success > .panel-heading { color: #3c763d; background-color: #dff0d8; border-color: #d6e9c6; } .panel-success > .panel-heading + .panel-collapse .panel-body { border-top-color: #d6e9c6; } .panel-success > .panel-footer + .panel-collapse .panel-body { border-bottom-color: #d6e9c6; } .panel-warning { border-color: #faebcc; } .panel-warning > .panel-heading { color: #8a6d3b; background-color: #fcf8e3; border-color: #faebcc; } .panel-warning > .panel-heading + .panel-collapse .panel-body { border-top-color: #faebcc; } .panel-warning > .panel-footer + .panel-collapse .panel-body { border-bottom-color: #faebcc; } .panel-danger { border-color: #ebccd1; } .panel-danger > .panel-heading { color: #a94442; background-color: #f2dede; border-color: #ebccd1; } .panel-danger > .panel-heading + .panel-collapse .panel-body { border-top-color: #ebccd1; } .panel-danger > .panel-footer + .panel-collapse .panel-body { border-bottom-color: #ebccd1; } .panel-info { border-color: #bce8f1; } .panel-info > .panel-heading { color: #31708f; background-color: #d9edf7; border-color: #bce8f1; } .panel-info > .panel-heading + .panel-collapse .panel-body { border-top-color: #bce8f1; } .panel-info > .panel-footer + .panel-collapse .panel-body { border-bottom-color: #bce8f1; } .well { min-height: 20px; padding: 19px; margin-bottom: 20px; background-color: #f5f5f5; border: 1px solid #e3e3e3; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); } .well blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } .well-lg { padding: 24px; border-radius: 6px; } .well-sm { padding: 9px; border-radius: 3px; } .close { float: right; font-size: 21px; font-weight: bold; line-height: 1; color: #000000; text-shadow: 0 1px 0 #ffffff; opacity: 0.2; filter: alpha(opacity=20); } .close:hover, .close:focus { color: #000000; text-decoration: none; cursor: pointer; opacity: 0.5; filter: alpha(opacity=50); } button.close { padding: 0; cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; } .modal-open { overflow: hidden; } .modal { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1040; display: none; overflow: auto; overflow-y: scroll; } .modal.fade .modal-dialog { -webkit-transform: translate(0, -25%); -ms-transform: translate(0, -25%); transform: translate(0, -25%); -webkit-transition: -webkit-transform 0.3s ease-out; -moz-transition: -moz-transform 0.3s ease-out; -o-transition: -o-transform 0.3s ease-out; transition: transform 0.3s ease-out; } .modal.in .modal-dialog { -webkit-transform: translate(0, 0); -ms-transform: translate(0, 0); transform: translate(0, 0); } .modal-dialog { position: relative; z-index: 1050; width: auto; margin: 10px; } .modal-content { position: relative; background-color: #ffffff; border: 1px solid #999999; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 6px; outline: none; -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); background-clip: padding-box; } .modal-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1030; background-color: #000000; } .modal-backdrop.fade { opacity: 0; filter: alpha(opacity=0); } .modal-backdrop.in { opacity: 0.5; filter: alpha(opacity=50); } .modal-header { min-height: 16.428571429px; padding: 15px; border-bottom: 1px solid #e5e5e5; } .modal-header .close { margin-top: -2px; } .modal-title { margin: 0; line-height: 1.428571429; } .modal-body { position: relative; padding: 20px; } .modal-footer { padding: 19px 20px 20px; margin-top: 15px; text-align: right; border-top: 1px solid #e5e5e5; } .modal-footer:before, .modal-footer:after { display: table; content: " "; } .modal-footer:after { clear: both; } .modal-footer:before, .modal-footer:after { display: table; content: " "; } .modal-footer:after { clear: both; } .modal-footer .btn + .btn { margin-bottom: 0; margin-left: 5px; } .modal-footer .btn-group .btn + .btn { margin-left: -1px; } .modal-footer .btn-block + .btn-block { margin-left: 0; } @media screen and (min-width: 768px) { .modal-dialog { width: 600px; margin: 30px auto; } .modal-content { -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); } } .tooltip { position: absolute; z-index: 1030; display: block; font-size: 12px; line-height: 1.4; opacity: 0; filter: alpha(opacity=0); visibility: visible; } .tooltip.in { opacity: 0.9; filter: alpha(opacity=90); } .tooltip.top { padding: 5px 0; margin-top: -3px; } .tooltip.right { padding: 0 5px; margin-left: 3px; } .tooltip.bottom { padding: 5px 0; margin-top: 3px; } .tooltip.left { padding: 0 5px; margin-left: -3px; } .tooltip-inner { max-width: 200px; padding: 3px 8px; color: #ffffff; text-align: center; text-decoration: none; background-color: #000000; border-radius: 4px; } .tooltip-arrow { position: absolute; width: 0; height: 0; border-color: transparent; border-style: solid; } .tooltip.top .tooltip-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-color: #000000; border-width: 5px 5px 0; } .tooltip.top-left .tooltip-arrow { bottom: 0; left: 5px; border-top-color: #000000; border-width: 5px 5px 0; } .tooltip.top-right .tooltip-arrow { right: 5px; bottom: 0; border-top-color: #000000; border-width: 5px 5px 0; } .tooltip.right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; border-right-color: #000000; border-width: 5px 5px 5px 0; } .tooltip.left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; border-left-color: #000000; border-width: 5px 0 5px 5px; } .tooltip.bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; border-bottom-color: #000000; border-width: 0 5px 5px; } .tooltip.bottom-left .tooltip-arrow { top: 0; left: 5px; border-bottom-color: #000000; border-width: 0 5px 5px; } .tooltip.bottom-right .tooltip-arrow { top: 0; right: 5px; border-bottom-color: #000000; border-width: 0 5px 5px; } .popover { position: absolute; top: 0; left: 0; z-index: 1010; display: none; max-width: 276px; padding: 1px; text-align: left; white-space: normal; background-color: #ffffff; border: 1px solid #cccccc; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); background-clip: padding-box; } .popover.top { margin-top: -10px; } .popover.right { margin-left: 10px; } .popover.bottom { margin-top: 10px; } .popover.left { margin-left: -10px; } .popover-title { padding: 8px 14px; margin: 0; font-size: 14px; font-weight: normal; line-height: 18px; background-color: #f7f7f7; border-bottom: 1px solid #ebebeb; border-radius: 5px 5px 0 0; } .popover-content { padding: 9px 14px; } .popover .arrow, .popover .arrow:after { position: absolute; display: block; width: 0; height: 0; border-color: transparent; border-style: solid; } .popover .arrow { border-width: 11px; } .popover .arrow:after { border-width: 10px; content: ""; } .popover.top .arrow { bottom: -11px; left: 50%; margin-left: -11px; border-top-color: #999999; border-top-color: rgba(0, 0, 0, 0.25); border-bottom-width: 0; } .popover.top .arrow:after { bottom: 1px; margin-left: -10px; border-top-color: #ffffff; border-bottom-width: 0; content: " "; } .popover.right .arrow { top: 50%; left: -11px; margin-top: -11px; border-right-color: #999999; border-right-color: rgba(0, 0, 0, 0.25); border-left-width: 0; } .popover.right .arrow:after { bottom: -10px; left: 1px; border-right-color: #ffffff; border-left-width: 0; content: " "; } .popover.bottom .arrow { top: -11px; left: 50%; margin-left: -11px; border-bottom-color: #999999; border-bottom-color: rgba(0, 0, 0, 0.25); border-top-width: 0; } .popover.bottom .arrow:after { top: 1px; margin-left: -10px; border-bottom-color: #ffffff; border-top-width: 0; content: " "; } .popover.left .arrow { top: 50%; right: -11px; margin-top: -11px; border-left-color: #999999; border-left-color: rgba(0, 0, 0, 0.25); border-right-width: 0; } .popover.left .arrow:after { right: 1px; bottom: -10px; border-left-color: #ffffff; border-right-width: 0; content: " "; } .carousel { position: relative; } .carousel-inner { position: relative; width: 100%; overflow: hidden; } .carousel-inner > .item { position: relative; display: none; -webkit-transition: 0.6s ease-in-out left; transition: 0.6s ease-in-out left; } .carousel-inner > .item > img, .carousel-inner > .item > a > img { display: block; height: auto; max-width: 100%; line-height: 1; } .carousel-inner > .active, .carousel-inner > .next, .carousel-inner > .prev { display: block; } .carousel-inner > .active { left: 0; } .carousel-inner > .next, .carousel-inner > .prev { position: absolute; top: 0; width: 100%; } .carousel-inner > .next { left: 100%; } .carousel-inner > .prev { left: -100%; } .carousel-inner > .next.left, .carousel-inner > .prev.right { left: 0; } .carousel-inner > .active.left { left: -100%; } .carousel-inner > .active.right { left: 100%; } .carousel-control { position: absolute; top: 0; bottom: 0; left: 0; width: 15%; font-size: 20px; color: #ffffff; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); opacity: 0.5; filter: alpha(opacity=50); } .carousel-control.left { background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%)); background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); } .carousel-control.right { right: 0; left: auto; background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.5) 100%)); background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); } .carousel-control:hover, .carousel-control:focus { color: #ffffff; text-decoration: none; outline: none; opacity: 0.9; filter: alpha(opacity=90); } .carousel-control .icon-prev, .carousel-control .icon-next, .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right { position: absolute; top: 50%; z-index: 5; display: inline-block; } .carousel-control .icon-prev, .carousel-control .glyphicon-chevron-left { left: 50%; } .carousel-control .icon-next, .carousel-control .glyphicon-chevron-right { right: 50%; } .carousel-control .icon-prev, .carousel-control .icon-next { width: 20px; height: 20px; margin-top: -10px; margin-left: -10px; font-family: serif; } .carousel-control .icon-prev:before { content: '\2039'; } .carousel-control .icon-next:before { content: '\203a'; } .carousel-indicators { position: absolute; bottom: 10px; left: 50%; z-index: 15; width: 60%; padding-left: 0; margin-left: -30%; text-align: center; list-style: none; } .carousel-indicators li { display: inline-block; width: 10px; height: 10px; margin: 1px; text-indent: -999px; cursor: pointer; background-color: #000 \9; background-color: rgba(0, 0, 0, 0); border: 1px solid #ffffff; border-radius: 10px; } .carousel-indicators .active { width: 12px; height: 12px; margin: 0; background-color: #ffffff; } .carousel-caption { position: absolute; right: 15%; bottom: 20px; left: 15%; z-index: 10; padding-top: 20px; padding-bottom: 20px; color: #ffffff; text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); } .carousel-caption .btn { text-shadow: none; } @media screen and (min-width: 768px) { .carousel-control .glyphicons-chevron-left, .carousel-control .glyphicons-chevron-right, .carousel-control .icon-prev, .carousel-control .icon-next { width: 30px; height: 30px; margin-top: -15px; margin-left: -15px; font-size: 30px; } .carousel-caption { right: 20%; left: 20%; padding-bottom: 30px; } .carousel-indicators { bottom: 20px; } } .clearfix:before, .clearfix:after { display: table; content: " "; } .clearfix:after { clear: both; } .center-block { display: block; margin-right: auto; margin-left: auto; } .pull-right { float: right !important; } .pull-left { float: left !important; } .hide { display: none !important; } .show { display: block !important; } .invisible { visibility: hidden; } .text-hide { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; } .hidden { display: none !important; visibility: hidden !important; } .affix { position: fixed; } @-ms-viewport { width: device-width; } .visible-xs, tr.visible-xs, th.visible-xs, td.visible-xs { display: none !important; } @media (max-width: 767px) { .visible-xs { display: block !important; } table.visible-xs { display: table; } tr.visible-xs { display: table-row !important; } th.visible-xs, td.visible-xs { display: table-cell !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-xs.visible-sm { display: block !important; } table.visible-xs.visible-sm { display: table; } tr.visible-xs.visible-sm { display: table-row !important; } th.visible-xs.visible-sm, td.visible-xs.visible-sm { display: table-cell !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-xs.visible-md { display: block !important; } table.visible-xs.visible-md { display: table; } tr.visible-xs.visible-md { display: table-row !important; } th.visible-xs.visible-md, td.visible-xs.visible-md { display: table-cell !important; } } @media (min-width: 1200px) { .visible-xs.visible-lg { display: block !important; } table.visible-xs.visible-lg { display: table; } tr.visible-xs.visible-lg { display: table-row !important; } th.visible-xs.visible-lg, td.visible-xs.visible-lg { display: table-cell !important; } } .visible-sm, tr.visible-sm, th.visible-sm, td.visible-sm { display: none !important; } @media (max-width: 767px) { .visible-sm.visible-xs { display: block !important; } table.visible-sm.visible-xs { display: table; } tr.visible-sm.visible-xs { display: table-row !important; } th.visible-sm.visible-xs, td.visible-sm.visible-xs { display: table-cell !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-sm { display: block !important; } table.visible-sm { display: table; } tr.visible-sm { display: table-row !important; } th.visible-sm, td.visible-sm { display: table-cell !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-sm.visible-md { display: block !important; } table.visible-sm.visible-md { display: table; } tr.visible-sm.visible-md { display: table-row !important; } th.visible-sm.visible-md, td.visible-sm.visible-md { display: table-cell !important; } } @media (min-width: 1200px) { .visible-sm.visible-lg { display: block !important; } table.visible-sm.visible-lg { display: table; } tr.visible-sm.visible-lg { display: table-row !important; } th.visible-sm.visible-lg, td.visible-sm.visible-lg { display: table-cell !important; } } .visible-md, tr.visible-md, th.visible-md, td.visible-md { display: none !important; } @media (max-width: 767px) { .visible-md.visible-xs { display: block !important; } table.visible-md.visible-xs { display: table; } tr.visible-md.visible-xs { display: table-row !important; } th.visible-md.visible-xs, td.visible-md.visible-xs { display: table-cell !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-md.visible-sm { display: block !important; } table.visible-md.visible-sm { display: table; } tr.visible-md.visible-sm { display: table-row !important; } th.visible-md.visible-sm, td.visible-md.visible-sm { display: table-cell !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-md { display: block !important; } table.visible-md { display: table; } tr.visible-md { display: table-row !important; } th.visible-md, td.visible-md { display: table-cell !important; } } @media (min-width: 1200px) { .visible-md.visible-lg { display: block !important; } table.visible-md.visible-lg { display: table; } tr.visible-md.visible-lg { display: table-row !important; } th.visible-md.visible-lg, td.visible-md.visible-lg { display: table-cell !important; } } .visible-lg, tr.visible-lg, th.visible-lg, td.visible-lg { display: none !important; } @media (max-width: 767px) { .visible-lg.visible-xs { display: block !important; } table.visible-lg.visible-xs { display: table; } tr.visible-lg.visible-xs { display: table-row !important; } th.visible-lg.visible-xs, td.visible-lg.visible-xs { display: table-cell !important; } } @media (min-width: 768px) and (max-width: 991px) { .visible-lg.visible-sm { display: block !important; } table.visible-lg.visible-sm { display: table; } tr.visible-lg.visible-sm { display: table-row !important; } th.visible-lg.visible-sm, td.visible-lg.visible-sm { display: table-cell !important; } } @media (min-width: 992px) and (max-width: 1199px) { .visible-lg.visible-md { display: block !important; } table.visible-lg.visible-md { display: table; } tr.visible-lg.visible-md { display: table-row !important; } th.visible-lg.visible-md, td.visible-lg.visible-md { display: table-cell !important; } } @media (min-width: 1200px) { .visible-lg { display: block !important; } table.visible-lg { display: table; } tr.visible-lg { display: table-row !important; } th.visible-lg, td.visible-lg { display: table-cell !important; } } .hidden-xs { display: block !important; } table.hidden-xs { display: table; } tr.hidden-xs { display: table-row !important; } th.hidden-xs, td.hidden-xs { display: table-cell !important; } @media (max-width: 767px) { .hidden-xs, tr.hidden-xs, th.hidden-xs, td.hidden-xs { display: none !important; } } @media (min-width: 768px) and (max-width: 991px) { .hidden-xs.hidden-sm, tr.hidden-xs.hidden-sm, th.hidden-xs.hidden-sm, td.hidden-xs.hidden-sm { display: none !important; } } @media (min-width: 992px) and (max-width: 1199px) { .hidden-xs.hidden-md, tr.hidden-xs.hidden-md, th.hidden-xs.hidden-md, td.hidden-xs.hidden-md { display: none !important; } } @media (min-width: 1200px) { .hidden-xs.hidden-lg, tr.hidden-xs.hidden-lg, th.hidden-xs.hidden-lg, td.hidden-xs.hidden-lg { display: none !important; } } .hidden-sm { display: block !important; } table.hidden-sm { display: table; } tr.hidden-sm { display: table-row !important; } th.hidden-sm, td.hidden-sm { display: table-cell !important; } @media (max-width: 767px) { .hidden-sm.hidden-xs, tr.hidden-sm.hidden-xs, th.hidden-sm.hidden-xs, td.hidden-sm.hidden-xs { display: none !important; } } @media (min-width: 768px) and (max-width: 991px) { .hidden-sm, tr.hidden-sm, th.hidden-sm, td.hidden-sm { display: none !important; } } @media (min-width: 992px) and (max-width: 1199px) { .hidden-sm.hidden-md, tr.hidden-sm.hidden-md, th.hidden-sm.hidden-md, td.hidden-sm.hidden-md { display: none !important; } } @media (min-width: 1200px) { .hidden-sm.hidden-lg, tr.hidden-sm.hidden-lg, th.hidden-sm.hidden-lg, td.hidden-sm.hidden-lg { display: none !important; } } .hidden-md { display: block !important; } table.hidden-md { display: table; } tr.hidden-md { display: table-row !important; } th.hidden-md, td.hidden-md { display: table-cell !important; } @media (max-width: 767px) { .hidden-md.hidden-xs, tr.hidden-md.hidden-xs, th.hidden-md.hidden-xs, td.hidden-md.hidden-xs { display: none !important; } } @media (min-width: 768px) and (max-width: 991px) { .hidden-md.hidden-sm, tr.hidden-md.hidden-sm, th.hidden-md.hidden-sm, td.hidden-md.hidden-sm { display: none !important; } } @media (min-width: 992px) and (max-width: 1199px) { .hidden-md, tr.hidden-md, th.hidden-md, td.hidden-md { display: none !important; } } @media (min-width: 1200px) { .hidden-md.hidden-lg, tr.hidden-md.hidden-lg, th.hidden-md.hidden-lg, td.hidden-md.hidden-lg { display: none !important; } } .hidden-lg { display: block !important; } table.hidden-lg { display: table; } tr.hidden-lg { display: table-row !important; } th.hidden-lg, td.hidden-lg { display: table-cell !important; } @media (max-width: 767px) { .hidden-lg.hidden-xs, tr.hidden-lg.hidden-xs, th.hidden-lg.hidden-xs, td.hidden-lg.hidden-xs { display: none !important; } } @media (min-width: 768px) and (max-width: 991px) { .hidden-lg.hidden-sm, tr.hidden-lg.hidden-sm, th.hidden-lg.hidden-sm, td.hidden-lg.hidden-sm { display: none !important; } } @media (min-width: 992px) and (max-width: 1199px) { .hidden-lg.hidden-md, tr.hidden-lg.hidden-md, th.hidden-lg.hidden-md, td.hidden-lg.hidden-md { display: none !important; } } @media (min-width: 1200px) { .hidden-lg, tr.hidden-lg, th.hidden-lg, td.hidden-lg { display: none !important; } } .visible-print, tr.visible-print, th.visible-print, td.visible-print { display: none !important; } @media print { .visible-print { display: block !important; } table.visible-print { display: table; } tr.visible-print { display: table-row !important; } th.visible-print, td.visible-print { display: table-cell !important; } .hidden-print, tr.hidden-print, th.hidden-print, td.hidden-print { display: none !important; } } ================================================ FILE: ouimeaux/server/static/css/main.css ================================================ .navbar { padding-left: 25px; } .header-section { padding: 30px 30px; background: #222; position: absolute; top: 50px; left: 0px; width: 100%; margin-left: 0; color: #FFF; } .main { padding-top: 20px; min-height: 370px; } .footer-left { padding-left: 30px; float: left; } .btn { text-align: left; } .btn-icon { margin-left: 15px; margin-right: 15px; } ================================================ FILE: ouimeaux/server/static/js/app.js ================================================ 'use strict'; angular.module('Ouimeaux', ['Ouimeaux.controllers', 'btford.socket-io']) .config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) { $routeProvider .when('/', { templateUrl: 'static/partials/landing.html', controller: 'IndexCtrl' }); $locationProvider.html5Mode(true); } ]); ================================================ FILE: ouimeaux/server/static/js/bootstrap.js ================================================ /*! * Bootstrap v3.0.3 (http://getbootstrap.com) * Copyright 2013 Twitter, Inc. * Licensed under http://www.apache.org/licenses/LICENSE-2.0 */ if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") } /* ======================================================================== * Bootstrap: transition.js v3.0.3 * http://getbootstrap.com/javascript/#transitions * ======================================================================== * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ======================================================================== */ +function ($) { "use strict"; // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) // ============================================================ function transitionEnd() { var el = document.createElement('bootstrap') var transEndEventNames = { 'WebkitTransition' : 'webkitTransitionEnd' , 'MozTransition' : 'transitionend' , 'OTransition' : 'oTransitionEnd otransitionend' , 'transition' : 'transitionend' } for (var name in transEndEventNames) { if (el.style[name] !== undefined) { return { end: transEndEventNames[name] } } } } // http://blog.alexmaccaw.com/css-transitions $.fn.emulateTransitionEnd = function (duration) { var called = false, $el = this $(this).one($.support.transition.end, function () { called = true }) var callback = function () { if (!called) $($el).trigger($.support.transition.end) } setTimeout(callback, duration) return this } $(function () { $.support.transition = transitionEnd() }) }(jQuery); /* ======================================================================== * Bootstrap: alert.js v3.0.3 * http://getbootstrap.com/javascript/#alerts * ======================================================================== * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ======================================================================== */ +function ($) { "use strict"; // ALERT CLASS DEFINITION // ====================== var dismiss = '[data-dismiss="alert"]' var Alert = function (el) { $(el).on('click', dismiss, this.close) } Alert.prototype.close = function (e) { var $this = $(this) var selector = $this.attr('data-target') if (!selector) { selector = $this.attr('href') selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 } var $parent = $(selector) if (e) e.preventDefault() if (!$parent.length) { $parent = $this.hasClass('alert') ? $this : $this.parent() } $parent.trigger(e = $.Event('close.bs.alert')) if (e.isDefaultPrevented()) return $parent.removeClass('in') function removeElement() { $parent.trigger('closed.bs.alert').remove() } $.support.transition && $parent.hasClass('fade') ? $parent .one($.support.transition.end, removeElement) .emulateTransitionEnd(150) : removeElement() } // ALERT PLUGIN DEFINITION // ======================= var old = $.fn.alert $.fn.alert = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.alert') if (!data) $this.data('bs.alert', (data = new Alert(this))) if (typeof option == 'string') data[option].call($this) }) } $.fn.alert.Constructor = Alert // ALERT NO CONFLICT // ================= $.fn.alert.noConflict = function () { $.fn.alert = old return this } // ALERT DATA-API // ============== $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) }(jQuery); /* ======================================================================== * Bootstrap: button.js v3.0.3 * http://getbootstrap.com/javascript/#buttons * ======================================================================== * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ======================================================================== */ +function ($) { "use strict"; // BUTTON PUBLIC CLASS DEFINITION // ============================== var Button = function (element, options) { this.$element = $(element) this.options = $.extend({}, Button.DEFAULTS, options) } Button.DEFAULTS = { loadingText: 'loading...' } Button.prototype.setState = function (state) { var d = 'disabled' var $el = this.$element var val = $el.is('input') ? 'val' : 'html' var data = $el.data() state = state + 'Text' if (!data.resetText) $el.data('resetText', $el[val]()) $el[val](data[state] || this.options[state]) // push to event loop to allow forms to submit setTimeout(function () { state == 'loadingText' ? $el.addClass(d).attr(d, d) : $el.removeClass(d).removeAttr(d); }, 0) } Button.prototype.toggle = function () { var $parent = this.$element.closest('[data-toggle="buttons"]') var changed = true if ($parent.length) { var $input = this.$element.find('input') if ($input.prop('type') === 'radio') { // see if clicking on current one if ($input.prop('checked') && this.$element.hasClass('active')) changed = false else $parent.find('.active').removeClass('active') } if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') } if (changed) this.$element.toggleClass('active') } // BUTTON PLUGIN DEFINITION // ======================== var old = $.fn.button $.fn.button = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.button') var options = typeof option == 'object' && option if (!data) $this.data('bs.button', (data = new Button(this, options))) if (option == 'toggle') data.toggle() else if (option) data.setState(option) }) } $.fn.button.Constructor = Button // BUTTON NO CONFLICT // ================== $.fn.button.noConflict = function () { $.fn.button = old return this } // BUTTON DATA-API // =============== $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { var $btn = $(e.target) if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') $btn.button('toggle') e.preventDefault() }) }(jQuery); /* ======================================================================== * Bootstrap: carousel.js v3.0.3 * http://getbootstrap.com/javascript/#carousel * ======================================================================== * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ======================================================================== */ +function ($) { "use strict"; // CAROUSEL CLASS DEFINITION // ========================= var Carousel = function (element, options) { this.$element = $(element) this.$indicators = this.$element.find('.carousel-indicators') this.options = options this.paused = this.sliding = this.interval = this.$active = this.$items = null this.options.pause == 'hover' && this.$element .on('mouseenter', $.proxy(this.pause, this)) .on('mouseleave', $.proxy(this.cycle, this)) } Carousel.DEFAULTS = { interval: 5000 , pause: 'hover' , wrap: true } Carousel.prototype.cycle = function (e) { e || (this.paused = false) this.interval && clearInterval(this.interval) this.options.interval && !this.paused && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) return this } Carousel.prototype.getActiveIndex = function () { this.$active = this.$element.find('.item.active') this.$items = this.$active.parent().children() return this.$items.index(this.$active) } Carousel.prototype.to = function (pos) { var that = this var activeIndex = this.getActiveIndex() if (pos > (this.$items.length - 1) || pos < 0) return if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) if (activeIndex == pos) return this.pause().cycle() return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) } Carousel.prototype.pause = function (e) { e || (this.paused = true) if (this.$element.find('.next, .prev').length && $.support.transition.end) { this.$element.trigger($.support.transition.end) this.cycle(true) } this.interval = clearInterval(this.interval) return this } Carousel.prototype.next = function () { if (this.sliding) return return this.slide('next') } Carousel.prototype.prev = function () { if (this.sliding) return return this.slide('prev') } Carousel.prototype.slide = function (type, next) { var $active = this.$element.find('.item.active') var $next = next || $active[type]() var isCycling = this.interval var direction = type == 'next' ? 'left' : 'right' var fallback = type == 'next' ? 'first' : 'last' var that = this if (!$next.length) { if (!this.options.wrap) return $next = this.$element.find('.item')[fallback]() } this.sliding = true isCycling && this.pause() var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) if ($next.hasClass('active')) return if (this.$indicators.length) { this.$indicators.find('.active').removeClass('active') this.$element.one('slid.bs.carousel', function () { var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) $nextIndicator && $nextIndicator.addClass('active') }) } if ($.support.transition && this.$element.hasClass('slide')) { this.$element.trigger(e) if (e.isDefaultPrevented()) return $next.addClass(type) $next[0].offsetWidth // force reflow $active.addClass(direction) $next.addClass(direction) $active .one($.support.transition.end, function () { $next.removeClass([type, direction].join(' ')).addClass('active') $active.removeClass(['active', direction].join(' ')) that.sliding = false setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) }) .emulateTransitionEnd(600) } else { this.$element.trigger(e) if (e.isDefaultPrevented()) return $active.removeClass('active') $next.addClass('active') this.sliding = false this.$element.trigger('slid.bs.carousel') } isCycling && this.cycle() return this } // CAROUSEL PLUGIN DEFINITION // ========================== var old = $.fn.carousel $.fn.carousel = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.carousel') var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) var action = typeof option == 'string' ? option : options.slide if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) if (typeof option == 'number') data.to(option) else if (action) data[action]() else if (options.interval) data.pause().cycle() }) } $.fn.carousel.Constructor = Carousel // CAROUSEL NO CONFLICT // ==================== $.fn.carousel.noConflict = function () { $.fn.carousel = old return this } // CAROUSEL DATA-API // ================= $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { var $this = $(this), href var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 var options = $.extend({}, $target.data(), $this.data()) var slideIndex = $this.attr('data-slide-to') if (slideIndex) options.interval = false $target.carousel(options) if (slideIndex = $this.attr('data-slide-to')) { $target.data('bs.carousel').to(slideIndex) } e.preventDefault() }) $(window).on('load', function () { $('[data-ride="carousel"]').each(function () { var $carousel = $(this) $carousel.carousel($carousel.data()) }) }) }(jQuery); /* ======================================================================== * Bootstrap: collapse.js v3.0.3 * http://getbootstrap.com/javascript/#collapse * ======================================================================== * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ======================================================================== */ +function ($) { "use strict"; // COLLAPSE PUBLIC CLASS DEFINITION // ================================ var Collapse = function (element, options) { this.$element = $(element) this.options = $.extend({}, Collapse.DEFAULTS, options) this.transitioning = null if (this.options.parent) this.$parent = $(this.options.parent) if (this.options.toggle) this.toggle() } Collapse.DEFAULTS = { toggle: true } Collapse.prototype.dimension = function () { var hasWidth = this.$element.hasClass('width') return hasWidth ? 'width' : 'height' } Collapse.prototype.show = function () { if (this.transitioning || this.$element.hasClass('in')) return var startEvent = $.Event('show.bs.collapse') this.$element.trigger(startEvent) if (startEvent.isDefaultPrevented()) return var actives = this.$parent && this.$parent.find('> .panel > .in') if (actives && actives.length) { var hasData = actives.data('bs.collapse') if (hasData && hasData.transitioning) return actives.collapse('hide') hasData || actives.data('bs.collapse', null) } var dimension = this.dimension() this.$element .removeClass('collapse') .addClass('collapsing') [dimension](0) this.transitioning = 1 var complete = function () { this.$element .removeClass('collapsing') .addClass('in') [dimension]('auto') this.transitioning = 0 this.$element.trigger('shown.bs.collapse') } if (!$.support.transition) return complete.call(this) var scrollSize = $.camelCase(['scroll', dimension].join('-')) this.$element .one($.support.transition.end, $.proxy(complete, this)) .emulateTransitionEnd(350) [dimension](this.$element[0][scrollSize]) } Collapse.prototype.hide = function () { if (this.transitioning || !this.$element.hasClass('in')) return var startEvent = $.Event('hide.bs.collapse') this.$element.trigger(startEvent) if (startEvent.isDefaultPrevented()) return var dimension = this.dimension() this.$element [dimension](this.$element[dimension]()) [0].offsetHeight this.$element .addClass('collapsing') .removeClass('collapse') .removeClass('in') this.transitioning = 1 var complete = function () { this.transitioning = 0 this.$element .trigger('hidden.bs.collapse') .removeClass('collapsing') .addClass('collapse') } if (!$.support.transition) return complete.call(this) this.$element [dimension](0) .one($.support.transition.end, $.proxy(complete, this)) .emulateTransitionEnd(350) } Collapse.prototype.toggle = function () { this[this.$element.hasClass('in') ? 'hide' : 'show']() } // COLLAPSE PLUGIN DEFINITION // ========================== var old = $.fn.collapse $.fn.collapse = function (option) { return this.each(function () { var $this = $(this) var data = $this.data('bs.collapse') var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.collapse.Constructor = Collapse // COLLAPSE NO CONFLICT // ==================== $.fn.collapse.noConflict = function () { $.fn.collapse = old return this } // COLLAPSE DATA-API // ================= $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { var $this = $(this), href var target = $this.attr('data-target') || e.preventDefault() || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 var $target = $(target) var data = $target.data('bs.collapse') var option = data ? 'toggle' : $this.data() var parent = $this.attr('data-parent') var $parent = parent && $(parent) if (!data || !data.transitioning) { if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') } $target.collapse(option) }) }(jQuery); /* ======================================================================== * Bootstrap: dropdown.js v3.0.3 * http://getbootstrap.com/javascript/#dropdowns * ======================================================================== * Copyright 2013 Twitter, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ======================================================================== */ +function ($) { "use strict"; // DROPDOWN CLASS DEFINITION // ========================= var backdrop = '.dropdown-backdrop' var toggle = '[data-toggle=dropdown]' var Dropdown = function (element) { $(element).on('click.bs.dropdown', this.toggle) } Dropdown.prototype.toggle = function (e) { var $this = $(this) if ($this.is('.disabled, :disabled')) return var $parent = getParent($this) var isActive = $parent.hasClass('open') clearMenus() if (!isActive) { if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { // if mobile we use a backdrop because click events don't delegate $('