diff --git a/.github/workflows/build_backend.yml b/.github/workflows/build_backend.yml
new file mode 100644
index 00000000..0331b4c8
--- /dev/null
+++ b/.github/workflows/build_backend.yml
@@ -0,0 +1,119 @@
+# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
+
+name: Build CoderBot backend
+
+on: push
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ container: coderbot/coderbot-ci:3.9-bullseye-slim
+ steps:
+ - uses: actions/checkout@v3 # Checking out the repo
+ - run: pip install -r docker/stub/requirements.txt
+ - run: |
+ export PYTHONPATH=./coderbot:./stub:./test
+ mkdir test-reports
+ python3 -m unittest test/coderbot_test.py 2>&1 | tee test-reports/test_report.txt
+ python3 -m unittest test/camera_test.py 2>&1 | tee test-reports/test_report.txt
+ #python3 -m unittest test/cnn_test.py 2>&1 | tee test-reports/test_report.txt
+ echo "test complete"
+ - run: |
+ export PYTHONPATH=./stub:./coderbot:./test
+ python3 coderbot/main.py > coderbot.log &
+ sleep 30
+ apt-get install -y python3-venv
+ mkdir -p schemathesis
+ python3 -m venv schemathesis
+ . schemathesis/bin/activate
+ pip install schemathesis
+ st run --endpoint 'activities' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json
+ #st run --endpoint 'media' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json
+ st run --endpoint 'control/speak' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json
+ st run --endpoint 'control/stop' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json
+ st run --endpoint 'music' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json
+ st run --endpoint 'programs' --hypothesis-max-examples=10 --request-timeout=20 http://localhost:5000/api/v1/openapi.json
+ echo "openapi test complete"
+
+ release-backend:
+ needs: [test]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Docker meta
+ id: meta
+ uses: docker/metadata-action@v4
+ with:
+ # list of Docker images to use as base name for tags
+ images: ghcr.io/coderbotorg/backend
+ # generate Docker tags based on the following events/attributes
+ tags: |
+ # always latest
+ type=raw,value=latest
+ # branch event
+ type=ref,event=branch
+ # tag event
+ type=ref,event=tag
+ # pull request event
+ type=ref,event=pr
+ # push event
+ type=sha,enable=true,prefix=git-,format=short
+ - uses: actions/checkout@v3 # Checking out the repo
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+ - name: Set up Docker Buildx
+ id: buildx
+ uses: docker/setup-buildx-action@v2
+ - name: Login to DockerHub
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build and push
+ uses: docker/build-push-action@v3
+ with:
+ push: true
+ build-args: CODERBOT_VERSION=${{github.ref_name}}-${{github.sha}}
+ platforms: linux/arm/v7
+ tags: ${{ steps.meta.outputs.tags }}
+ context: .
+ file: docker/Dockerfile
+ cache-from: type=registry,ref=ghcr.io/coderbotorg/backend:latest
+ cache-to: type=inline
+
+ release-stub:
+ needs: [test]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Docker meta
+ id: meta
+ uses: docker/metadata-action@v4
+ with:
+ # list of Docker images to use as base name for tags
+ images: ghcr.io/coderbotorg/backend
+ # generate Docker tags based on the following events/attributes
+ tags: |
+ # always latest
+ type=raw,value=stub-latest
+ - uses: actions/checkout@v3 # Checking out the repo
+ - name: Set up Docker Buildx
+ id: buildx
+ uses: docker/setup-buildx-action@v2
+ - name: Login to DockerHub
+ uses: docker/login-action@v2
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build and push
+ uses: docker/build-push-action@v3
+ with:
+ push: true
+ build-args: CODERBOT_VERSION=${{github.ref_name}}-${{github.sha}}
+ platforms: linux/amd64
+ tags: ${{ steps.meta.outputs.tags }}
+ context: .
+ file: docker/stub/Dockerfile
+ cache-from: type=registry,ref=ghcr.io/coderbotorg/backend:stub-latest
+ cache-to: type=inline
diff --git a/.gitignore b/.gitignore
index 0981524c..4a3ebb11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,9 +28,27 @@
# Logs and databases #
######################
*.log
+*.log.*
*.sql
*.sqlite
+# Pictures taken
+media/*.jpeg
+media/*.mp4
+saved_photos
+
+#cnn models
+cnn_models/*
+
+# Sounds recorded
+sounds/*.wav
+
+# Logs
+logs/*.log
+
+# User programs
+data/*.json
+
# OS generated files #
######################
.DS_Store
@@ -40,3 +58,35 @@
.Trashes
ehthumbs.db
Thumbs.db
+.vscode
+
+# Swap files
+*.swp
+
+# Python3 Virtual Environment folders
+
+bin/
+lib/
+lib64/
+lib64
+share/
+pyvenv.cfg
+
+# Vue build
+dist/
+# Docs
+cb_docs/
+
+coderbot.cfg
+
+swagger-ui/
+
+# Uploaded updates folder
+updatePackages
+
+# firmware
+firmware/
+
+# test
+cassette.yaml
+.hypothesis
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..31ed3caa
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,336 @@
+That's correct, at least for linking existing material and, overall, providing and overview of the project and the (now many) components.
+
+As for the "CONTRIBUTING" document, I will prepare something inspired by [this](), according to these [general guidelines](https://mozillascience.github.io/working-open-workshop/contributing/).
+
+# Contributing to CoderBot
+
+:+1::robot: Thanks for your interest in the CoderBot project! :robot::+1:
+
+The following is a set of guidelines for contributing to CoderBot and its modules, which are hosted in the [CoderBot Organization](https://github.com/CoderBotOrg) on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
+
+#### Table Of Contents
+
+[Code of Conduct](#code-of-conduct)
+
+[What should I know before I get started?](#what-should-i-know-before-i-get-started)
+ * [CoderBot project description](#coderbot-project-description)
+ * [CoderBot architecture](#coderbot-architecture)
+
+[How Can I Contribute?](#how-can-i-contribute)
+ * [Reporting Bugs](#reporting-bugs)
+ * [Suggesting Enhancements](#suggesting-enhancements)
+ * [Your First Code Contribution](#your-first-code-contribution)
+ * [Pull Requests](#pull-requests)
+
+[Styleguides](#styleguides)
+ * [Git Commit Messages](#git-commit-messages)
+ * [JavaScript Styleguide](#javascript-styleguide)
+ * [CoffeeScript Styleguide](#coffeescript-styleguide)
+ * [Specs Styleguide](#specs-styleguide)
+ * [Documentation Styleguide](#documentation-styleguide)
+
+[Additional Notes](#additional-notes)
+ * [Issue and Pull Request Labels](#issue-and-pull-request-labels)
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by the [CoderBot Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [info@coderbot.org](info@coderbot.org).
+
+## What should I know before I get started?
+
+### CoderBot project description
+
+CoderBot is an open source project with the objective of providing the hardware and software used in the educational robot with the same name.
+
+It is composed by several [repositories](https://github.com/CoderBotOrg). When you initially consider contributing to CoderBot, you might be unsure about which of those repositories implements the functionality you want to change or report a bug for. This section should help you with that.
+
+#### Package Conventions
+
+### CoderBot architecture
+
+## How Can I Contribute?
+
+### Reporting Bugs
+
+This section guides you through submitting a bug report for CoderBot. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:.
+
+Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as many details as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](https://github.com/CoderBotOrg/.github/blob/master/.github/ISSUE_TEMPLATE/bug_report.md), the information it asks for helps us resolve issues faster.
+
+> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
+
+#### Before Submitting A Bug Report
+
+* TODO
+
+#### How Do I Submit A (Good) Bug Report?
+
+Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](#coderbot-and-repos) your bug is related to, create an issue on that repository and provide the following information by filling in [the template](https://github.com/CoderBotOrg/.github/blob/master/.github/ISSUE_TEMPLATE/bug_report.md).
+
+Explain the problem and include additional details to help maintainers reproduce the problem:
+
+* **Use a clear and descriptive title** for the issue to identify the problem.
+* **Describe the exact steps which reproduce the problem** in as many details as possible.
+
+Provide more context by answering these questions:
+
+° TODO
+
+### Suggesting Enhancements
+
+This section guides you through submitting an enhancement suggestion for CoderBot, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion :pencil: and find related suggestions :mag_right:.
+
+Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-a-good-enhancement-suggestion). Fill in [the template](https://github.com/CoderBotOrg/.github/blob/master/.github/ISSUE_TEMPLATE/feature_request.md), including the steps that you imagine you would take if the feature you're requesting existed.
+
+#### Before Submitting An Enhancement Suggestion
+
+#### How Do I Submit A (Good) Enhancement Suggestion?
+
+Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/). After you've determined [which repository](#coderbot-and-repos) your enhancement suggestion is related to, create an issue on that repository and provide the following information:
+
+* **Use a clear and descriptive title** for the issue to identify the suggestion.
+* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
+* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
+* **Describe the current behavior** and **explain which behavior you expected to see instead** and why.
+* **Explain why this enhancement would be useful** to most CoderBot users and isn't something that can or should be implemented as a [community package](#coderbot-and-repos).
+* **List some other text editors or applications where this enhancement exists.**
+
+### Your First Code Contribution
+
+Unsure where to begin contributing to CoderBot? You can start by looking through these `beginner` and `help-wanted` issues:
+
+* [Beginner issues][beginner] - issues which should only require a few lines of code, and a test or two.
+* [Help wanted issues][help-wanted] - issues which should be a bit more involved than `beginner` issues.
+
+Both issue lists are sorted by total number of comments. While not perfect, number of comments is a reasonable proxy for impact a given change will have.
+
+#### Local development
+
+* TODO
+
+### Pull Requests
+
+The process described here has several goals:
+
+- Maintain CoderBot's quality
+- Fix problems that are important to users
+- Engage the community in working toward the best possible CoderBot
+- Enable a sustainable system for CoderBot's maintainers to review contributions
+
+Please follow these steps to have your contribution considered by the maintainers:
+
+1. Follow all instructions in [the template](PULL_REQUEST_TEMPLATE.md)
+2. Follow the [styleguides](#styleguides)
+3. After you submit your pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) are passing What if the status checks are failing?
If a status check is failing, and you believe that the failure is unrelated to your change, please leave a comment on the pull request explaining why you believe the failure is unrelated. A maintainer will re-run the status check for you. If we conclude that the failure was a false positive, then we will open an issue to track that problem with our status check suite.
+
+While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted.
+
+## Styleguides
+
+### Git Commit Messages
+
+* Use the present tense ("Add feature" not "Added feature")
+* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
+* Limit the first line to 72 characters or less
+* Reference issues and pull requests liberally after the first line
+* When only changing documentation, include `[ci skip]` in the commit title
+
+### JavaScript Styleguide
+
+All JavaScript code is linted with [Prettier](https://prettier.io/).
+
+* Prefer the object spread operator (`{...anotherObj}`) to `Object.assign()`
+* Inline `export`s with expressions whenever possible
+ ```js
+ // Use this:
+ export default class ClassName {
+
+ }
+
+ // Instead of:
+ class ClassName {
+
+ }
+ export default ClassName
+ ```
+* Place requires in the following order:
+ * Built in Node Modules (such as `path`)
+ * Local Modules (using relative paths)
+* Place class properties in the following order:
+ * Class methods and properties (methods starting with `static`)
+ * Instance methods and properties
+
+### Documentation Styleguide
+
+* Use [Markdown](https://daringfireball.net/projects/markdown).
+* Reference methods and classes in markdown with the custom `{}` notation:
+ * Reference classes with `{ClassName}`
+ * Reference instance methods with `{ClassName::methodName}`
+ * Reference class methods with `{ClassName.methodName}`
+
+#### Example
+
+* TODO
+
+## Additional Notes
+
+### Issue and Pull Request Labels
+
+This section lists the labels we use to help us track and manage issues and pull requests. Most labels are used across all CoderBot repositories.
+
+[GitHub search](https://help.github.com/articles/searching-issues/) makes it easy to use labels for finding groups of issues or pull requests you're interested in.
+The labels are loosely grouped by their purpose, but it's not required that every issue has a label from every group or that an issue can't have more than one label from the same group.
+
+#### Type of Issue and Issue State
+
+| Label name | `CoderBotOrg` :mag_right: | `CoderBot`‑org :mag_right: | Description |
+| --- | --- | --- | --- |
+| `enhancement` | [search][search-coderbot-repo-label-enhancement] | [search][search-coderbot-org-label-enhancement] | Feature requests. |
+| `bug` | [search][search-coderbot-repo-label-bug] | [search][search-coderbot-org-label-bug] | Confirmed bugs or reports that are very likely to be bugs. |
+| `question` | [search][search-coderbot-repo-label-question] | [search][search-coderbot-org-label-question] | Questions more than bug reports or feature requests (e.g. how do I do X). |
+| `feedback` | [search][search-coderbot-repo-label-feedback] | [search][search-coderbot-org-label-feedback] | General feedback more than bug reports or feature requests. |
+| `help-wanted` | [search][search-coderbot-repo-label-help-wanted] | [search][search-coderbot-org-label-help-wanted] | The CoderBot core team would appreciate help from the community in resolving these issues. |
+| `beginner` | [search][search-coderbot-repo-label-beginner] | [search][search-coderbot-org-label-beginner] | Less complex issues which would be good first issues to work on for users who want to contribute to CoderBot. |
+| `more-information-needed` | [search][search-coderbot-repo-label-more-information-needed] | [search][search-coderbot-org-label-more-information-needed] | More information needs to be collected about these problems or feature requests (e.g. steps to reproduce). |
+| `needs-reproduction` | [search][search-coderbot-repo-label-needs-reproduction] | [search][search-coderbot-org-label-needs-reproduction] | Likely bugs, but haven't been reliably reproduced. |
+| `blocked` | [search][search-coderbot-repo-label-blocked] | [search][search-coderbot-org-label-blocked] | Issues blocked on other issues. |
+| `duplicate` | [search][search-coderbot-repo-label-duplicate] | [search][search-coderbot-org-label-duplicate] | Issues which are duplicates of other issues, i.e. they have been reported before. |
+| `wontfix` | [search][search-coderbot-repo-label-wontfix] | [search][search-coderbot-org-label-wontfix] | The CoderBot core team has decided not to fix these issues for now, either because they're working as intended or for some other reason. |
+| `invalid` | [search][search-coderbot-repo-label-invalid] | [search][search-coderbot-org-label-invalid] | Issues which aren't valid (e.g. user errors). |
+| `package-idea` | [search][search-coderbot-repo-label-package-idea] | [search][search-coderbot-org-label-package-idea] | Feature request which might be good candidates for new packages, instead of extending CoderBot or core CoderBot packages. |
+| `wrong-repo` | [search][search-coderbot-repo-label-wrong-repo] | [search][search-coderbot-org-label-wrong-repo] | |
+
+#### Topic Categories
+
+| Label name | `CoderBotOrg/backend` :mag_right: | `CoderBotOrg`‑org :mag_right: | Description |
+| --- | --- | --- | --- |
+| `windows` | [search][search-coderbot-repo-label-windows] | [search][search-coderbot-org-label-windows] | Related to CoderBot running on Windows. |
+| `linux` | [search][search-coderbot-repo-label-linux] | [search][search-coderbot-org-label-linux] | Related to CoderBot running on Linux. |
+| `mac` | [search][search-coderbot-repo-label-mac] | [search][search-coderbot-org-label-mac] | Related to CoderBot running on macOS. |
+| `documentation` | [search][search-coderbot-repo-label-documentation] | [search][search-coderbot-org-label-documentation] | Related to any type of documentation (e.g. [API documentation]() and the [flight manual]()). |
+| `performance` | [search][search-coderbot-repo-label-performance] | [search][search-coderbot-org-label-performance] | Related to performance. |
+| `security` | [search][search-coderbot-repo-label-security] | [search][search-coderbot-org-label-security] | Related to security. |
+| `ui` | [search][search-coderbot-repo-label-ui] | [search][search-coderbot-org-label-ui] | Related to visual design. |
+| `api` | [search][search-coderbot-repo-label-api] | [search][search-coderbot-org-label-api] | Related to CoderBot's public APIs. |
+| `uncaught-exception` | [search][search-coderbot-repo-label-uncaught-exception] | [search][search-coderbot-org-label-uncaught-exception] | Issues about uncaught exceptions. |
+| `crash` | [search][search-coderbot-repo-label-crash] | [search][search-coderbot-org-label-crash] | Reports of CoderBot completely crashing. |
+| `auto-indent` | [search][search-coderbot-repo-label-auto-indent] | [search][search-coderbot-org-label-auto-indent] | Related to auto-indenting text. |
+| `encoding` | [search][search-coderbot-repo-label-encoding] | [search][search-coderbot-org-label-encoding] | Related to character encoding. |
+| `network` | [search][search-coderbot-repo-label-network] | [search][search-coderbot-org-label-network] | Related to network problems or working with remote files (e.g. on network drives). |
+| `git` | [search][search-coderbot-repo-label-git] | [search][search-coderbot-org-label-git] | Related to Git functionality (e.g. problems with gitignore files or with showing the correct file status). |
+
+#### `CoderBotOrg/backend` Topic Categories
+
+| Label name | `CoderBotOrg/backend` :mag_right: | `CoderBotOrg`‑org :mag_right: | Description |
+| --- | --- | --- | --- |
+| `editor-rendering` | [search][search-coderbot-repo-label-editor-rendering] | [search][search-coderbot-org-label-editor-rendering] | Related to language-independent aspects of rendering text (e.g. scrolling, soft wrap, and font rendering). |
+| `build-error` | [search][search-coderbot-repo-label-build-error] | [search][search-coderbot-org-label-build-error] | Related to problems with building CoderBot from source. |
+| `error-from-pathwatcher` | [search][search-coderbot-repo-label-error-from-pathwatcher] | [search][search-coderbot-org-label-error-from-pathwatcher] | |
+| `error-from-save` | [search][search-coderbot-repo-label-error-from-save] | [search][search-coderbot-org-label-error-from-save] | Related to errors thrown when saving files. |
+| `error-from-open` | [search][search-coderbot-repo-label-error-from-open] | [search][search-coderbot-org-label-error-from-open] | Related to errors thrown when opening files. |
+| `installer` | [search][search-coderbot-repo-label-installer] | [search][search-coderbot-org-label-installer] | Related to the CoderBot installers for different OSes. |
+| `auto-updater` | [search][search-coderbot-repo-label-auto-updater] | [search][search-coderbot-org-label-auto-updater] | Related to the auto-updater for different OSes. |
+| `deprecation-help` | [search][search-coderbot-repo-label-deprecation-help] | [search][search-coderbot-org-label-deprecation-help] | Issues for helping package authors remove usage of deprecated APIs in packages. |
+| `electron` | [search][search-coderbot-repo-label-electron] | [search][search-coderbot-org-label-electron] | |
+
+#### Pull Request Labels
+
+| Label name | `CoderBotOrg/backend` :mag_right: | `CoderBotOrg`‑org :mag_right: | Description
+| --- | --- | --- | --- |
+| `work-in-progress` | [search][search-coderbot-repo-label-work-in-progress] | [search][search-coderbot-org-label-work-in-progress] | Pull requests which are still being worked on, more changes will follow. |
+| `needs-review` | [search][search-coderbot-repo-label-needs-review] | [search][search-coderbot-org-label-needs-review] | Pull requests which need code review, and approval from maintainers or CoderBot core team. |
+| `under-review` | [search][search-coderbot-repo-label-under-review] | [search][search-coderbot-org-label-under-review] | Pull requests being reviewed by maintainers or CoderBot core team. |
+| `requires-changes` | [search][search-coderbot-repo-label-requires-changes] | [search][search-coderbot-org-label-requires-changes] | Pull requests which need to be updated based on review comments and then reviewed again. |
+| `needs-testing` | [search][search-coderbot-repo-label-needs-testing] | [search][search-coderbot-org-label-needs-testing] | Pull requests which need manual testing. |
+
+[search-coderbot-repo-label-enhancement]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aenhancement
+[search-coderbot-org-label-enhancement]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aenhancement
+[search-coderbot-repo-label-bug]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Abug
+[search-coderbot-org-label-bug]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Abug
+[search-coderbot-repo-label-question]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aquestion
+[search-coderbot-org-label-question]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aquestion
+[search-coderbot-repo-label-feedback]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Afeedback
+[search-coderbot-org-label-feedback]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Afeedback
+[search-coderbot-repo-label-help-wanted]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Ahelp-wanted
+[search-coderbot-org-label-help-wanted]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Ahelp-wanted
+[search-coderbot-repo-label-beginner]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Abeginner
+[search-coderbot-org-label-beginner]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Abeginner
+[search-coderbot-repo-label-more-information-needed]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Amore-information-needed
+[search-coderbot-org-label-more-information-needed]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Amore-information-needed
+[search-coderbot-repo-label-needs-reproduction]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aneeds-reproduction
+[search-coderbot-org-label-needs-reproduction]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aneeds-reproduction
+[search-coderbot-repo-label-triage-help-needed]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Atriage-help-needed
+[search-coderbot-org-label-triage-help-needed]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Atriage-help-needed
+[search-coderbot-repo-label-windows]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Awindows
+[search-coderbot-org-label-windows]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Awindows
+[search-coderbot-repo-label-linux]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Alinux
+[search-coderbot-org-label-linux]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Alinux
+[search-coderbot-repo-label-mac]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Amac
+[search-coderbot-org-label-mac]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Amac
+[search-coderbot-repo-label-documentation]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Adocumentation
+[search-coderbot-org-label-documentation]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Adocumentation
+[search-coderbot-repo-label-performance]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aperformance
+[search-coderbot-org-label-performance]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aperformance
+[search-coderbot-repo-label-security]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Asecurity
+[search-coderbot-org-label-security]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Asecurity
+[search-coderbot-repo-label-ui]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aui
+[search-coderbot-org-label-ui]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aui
+[search-coderbot-repo-label-api]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aapi
+[search-coderbot-org-label-api]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aapi
+[search-coderbot-repo-label-crash]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Acrash
+[search-coderbot-org-label-crash]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Acrash
+[search-coderbot-repo-label-auto-indent]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aauto-indent
+[search-coderbot-org-label-auto-indent]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aauto-indent
+[search-coderbot-repo-label-encoding]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aencoding
+[search-coderbot-org-label-encoding]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aencoding
+[search-coderbot-repo-label-network]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Anetwork
+[search-coderbot-org-label-network]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Anetwork
+[search-coderbot-repo-label-uncaught-exception]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Auncaught-exception
+[search-coderbot-org-label-uncaught-exception]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Auncaught-exception
+[search-coderbot-repo-label-git]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Agit
+[search-coderbot-org-label-git]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Agit
+[search-coderbot-repo-label-blocked]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Ablocked
+[search-coderbot-org-label-blocked]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Ablocked
+[search-coderbot-repo-label-duplicate]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aduplicate
+[search-coderbot-org-label-duplicate]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aduplicate
+[search-coderbot-repo-label-wontfix]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Awontfix
+[search-coderbot-org-label-wontfix]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Awontfix
+[search-coderbot-repo-label-invalid]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Ainvalid
+[search-coderbot-org-label-invalid]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Ainvalid
+[search-coderbot-repo-label-package-idea]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Apackage-idea
+[search-coderbot-org-label-package-idea]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Apackage-idea
+[search-coderbot-repo-label-wrong-repo]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Awrong-repo
+[search-coderbot-org-label-wrong-repo]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Awrong-repo
+[search-coderbot-repo-label-editor-rendering]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aeditor-rendering
+[search-coderbot-org-label-editor-rendering]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aeditor-rendering
+[search-coderbot-repo-label-build-error]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Abuild-error
+[search-coderbot-org-label-build-error]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Abuild-error
+[search-coderbot-repo-label-error-from-pathwatcher]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aerror-from-pathwatcher
+[search-coderbot-org-label-error-from-pathwatcher]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aerror-from-pathwatcher
+[search-coderbot-repo-label-error-from-save]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aerror-from-save
+[search-coderbot-org-label-error-from-save]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aerror-from-save
+[search-coderbot-repo-label-error-from-open]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aerror-from-open
+[search-coderbot-org-label-error-from-open]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aerror-from-open
+[search-coderbot-repo-label-installer]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Ainstaller
+[search-coderbot-org-label-installer]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Ainstaller
+[search-coderbot-repo-label-auto-updater]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Aauto-updater
+[search-coderbot-org-label-auto-updater]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aauto-updater
+[search-coderbot-repo-label-deprecation-help]: https://github.com/search?q=is%3Aopen+is%3Aissue+repo%3ACoderBotOrg%2Fbackend+label%3Adeprecation-help
+[search-coderbot-org-label-deprecation-help]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Adeprecation-help
+[search-coderbot-repo-label-electron]: https://github.com/search?q=is%3Aissue+repo%3ACoderBotOrg%2Fbackend+is%3Aopen+label%3Aelectron
+[search-coderbot-org-label-electron]: https://github.com/search?q=is%3Aopen+is%3Aissue+user%3ACoderBotOrg+label%3Aelectron
+[search-coderbot-repo-label-work-in-progress]: https://github.com/search?q=is%3Aopen+is%3Apr+repo%3ACoderBotOrg%2Fbackend+label%3Awork-in-progress
+[search-coderbot-org-label-work-in-progress]: https://github.com/search?q=is%3Aopen+is%3Apr+user%3ACoderBotOrg+label%3Awork-in-progress
+[search-coderbot-repo-label-needs-review]: https://github.com/search?q=is%3Aopen+is%3Apr+repo%3ACoderBotOrg%2Fbackend+label%3Aneeds-review
+[search-coderbot-org-label-needs-review]: https://github.com/search?q=is%3Aopen+is%3Apr+user%3ACoderBotOrg+label%3Aneeds-review
+[search-coderbot-repo-label-under-review]: https://github.com/search?q=is%3Aopen+is%3Apr+repo%3ACoderBotOrg%2Fbackend+label%3Aunder-review
+[search-coderbot-org-label-under-review]: https://github.com/search?q=is%3Aopen+is%3Apr+user%3ACoderBotOrg+label%3Aunder-review
+[search-coderbot-repo-label-requires-changes]: https://github.com/search?q=is%3Aopen+is%3Apr+repo%3ACoderBotOrg%2Fbackend+label%3Arequires-changes
+[search-coderbot-org-label-requires-changes]: https://github.com/search?q=is%3Aopen+is%3Apr+user%3ACoderBotOrg+label%3Arequires-changes
+[search-coderbot-repo-label-needs-testing]: https://github.com/search?q=is%3Aopen+is%3Apr+repo%3ACoderBotOrg%2Fbackend+label%3Aneeds-testing
+[search-coderbot-org-label-needs-testing]: https://github.com/search?q=is%3Aopen+is%3Apr+user%3ACoderBotOrg+label%3Aneeds-testing
+
+[beginner]:https://github.com/search?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3Abeginner+label%3Ahelp-wanted+user%3ACoderBotOrg+sort%3Acomments-desc
+[help-wanted]:https://github.com/search?q=is%3Aopen+is%3Aissue+label%3Ahelp-wanted+user%3ACoderBotOrg+sort%3Acomments-desc+-label%3Abeginner
+[contributing-to-official-coderbot-packages]: todo
+[hacking-on-coderbot-core]: todo
+
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 00000000..ade73b06
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,281 @@
+(C) 2014 - 2019 Roberto Previtera, Antonio Vivace, CoderBot contributors.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
diff --git a/README.md b/README.md
index fbd00713..5d803f11 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,48 @@
-CoderBot
-========
+# backend
+
-A RaspberryPI-based bot controller
+> CoderBot is a RaspberryPI-based programmable robot for educational purposes. Check the [project website](https://www.coderbot.org) for more information.
+>
+> For further information about development and technical documentation, see the [Wiki](https://github.com/CoderBotOrg/coderbot/wiki).
-The module provide a simple web interface to a raspberry py "robot".
+This repository contains the backend, exposing the [CoderBot API](https://github.com/CoderBotOrg/backend/wiki/API-v2).
-See the wiki https://github.com/previ/coderbot/wiki for the documentation
+### Quickstart
+Prerequisites:
+```bash
+sudo apt install python3 python3-venv
+```
+
+Be sure you have Python **3.6**. You may need to use `python3.6` and `python3.6-venv` packages on some repositories with python3 already pointing to **3.7** (e.g. debian unstable/sid).
+
+
+
+```bash
+git clone https://github.com/CoderBotOrg/coderbot.git
+cd coderbot
+python3 -m venv .
+source bin/activate
+
+# Install the basic requirements
+pip3 install -r requirements_stub.txt
+# Additional packages if you are running the real thing
+pip3 install -r requirements.txt
+
+# Start the backend in stub mode
+PYTHONPATH=stub:test python3 init.py
+
+# or, run the real thing if you're on a physical RPi
+python3 init.py
+```
+
+Once started, the backend will expose a number of endpoints:
+
+- Legacy API: [localhost:5000/``](http://localhost:5000/);
+- Legacy JQuery web application: [localhost:5000/old](http://localhost:5000/old);
+- API v2: [localhost:5000/v2](http://localhost:5000/v2);
+- New Vue web application: [localhost:5000/](http://localhost:5000/) (assuming a [vue-app](https://github.com/coderbotorg/vue-app) build is placed in the `dist/` folder);
+- Documentation: [localhost:5000/docs](http://localhost:5000/docs) assuming a [docs](https://github.com/coderbotorg/docs) build is placed in the `cb_docs/` folder);
+- Swagger UI dynamic documentation of the API v2: [localhost:5000/v2/ui/index.html](http://localhost:5000/v2/ui/index.html) (once you cloned the [swagger-ui](https://github.com/coderbotorg/swagger-ui) repository inside the backend folder).
diff --git a/bin/start.sh b/bin/start.sh
new file mode 100755
index 00000000..f22ba735
--- /dev/null
+++ b/bin/start.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+python3 coderbot/main.py
diff --git a/bin/stop.sh b/bin/stop.sh
new file mode 100755
index 00000000..66a5db5c
--- /dev/null
+++ b/bin/stop.sh
@@ -0,0 +1,3 @@
+#/usr/bin/bash
+sudo pkill -9 python
+sudo pkill -9 dbus-daemon
diff --git a/camera.py b/camera.py
deleted file mode 100644
index ae9372dc..00000000
--- a/camera.py
+++ /dev/null
@@ -1,259 +0,0 @@
-import time
-import copy
-from threading import Thread, Lock
-
-import SimpleCV
-
-CAMERA_REFRESH_INTERVAL=0.3
-CAMERA_DELAY_INTERVAL=0.3
-MAX_IMAGE_AGE = 0.0
-
-class Camera(Thread):
-
- _instance = None
- _cam_props = {"width":640, "height":480}
- _cam_off_img = SimpleCV.Image("coderdojo-logo.png")
- _warp_corners_1 = [(0, -120), (640, -120), (380, 480), (260, 480)]
- _warp_corners_2 = [(0, -60), (320, -60), (190, 240), (130, 240)]
- _warp_corners_4 = [(0, -30), (160, -30), (95, 120), (65, 120)]
- stream_port = 8090
-
- @classmethod
- def get_instance(cls):
- if not cls._instance:
- cls._instance = Camera()
- cls._instance.start()
- return cls._instance
-
- def __init__(self):
- print "starting camera"
- self._camera = SimpleCV.Camera(prop_set=self._cam_props)
- self._streamer = SimpleCV.JpegStreamer("0.0.0.0:"+str(self.stream_port), st=0.1)
- self._cam_off_img.save(self._streamer)
- self._run = True
- self._image_time = 0
- self._image_lock = Lock()
- super(Camera, self).__init__()
-
- def run(self):
- while self._run:
- ts = time.time()
- #print "run.1"
- self._image_lock.acquire()
- self._image = self._camera.getImage()
- #print "run.2: " + str(time.time()-ts)
- if time.time() - self._image_time > CAMERA_REFRESH_INTERVAL:
- self.save_image(self._image)
- #print "run.3: " + str(time.time()-ts)
- self._image_lock.release()
- time.sleep(CAMERA_REFRESH_INTERVAL)
-
- def get_image(self, maxage = MAX_IMAGE_AGE):
- return self._camera.getImage()
-
- def save_image(self, image):
- image.save(self._streamer)
- self._image_time=time.time()
-
- def exit(self):
- self._run = False
- self.join()
-
- def calibrate(self):
- img = self._camera.getImage()
- self._background = img.hueHistogram()[-1]
-
- def find_line(self):
- self._image_lock.acquire()
- img = self.get_image(0)
- img.drawRectangle(0,200,640,40)
- img.drawRectangle(240,200,160,40, color=(0,0,255))
- cropped = img.crop(0, 200, 640, 40)
- blobs = cropped.findBlobs(minsize=800, maxsize=4000)
- coordX = 50
- if blobs and len(blobs):
- line = blobs[-1]
- img.drawRectangle(line.minRect()[0][0], 200, line.width(), line.height(), color=(0,255,0))
- coordX = (line.coordinates()[0] * 100) / cropped.width
-
- self._image_lock.release()
- return coordX
-
-
- def find_signal(self):
- #print "signal"
- angle = None
- ts = time.time()
- self._image_lock.acquire()
- img = self.get_image(0)
- #print "signal.get_image: " + str(time.time() - ts)
- warped = img.resize(320).warp(self._warp_corners_2).resize(640)
- #print "signal.warp: " + str(time.time() - ts)
- cropped = warped.crop(260, 160, 120, 320)
-
- binarized = cropped.binarize()
-
- blobs = binarized.findBlobs(minsize=3000, maxsize=4000)
- #print blobs
- print "signal.blobs: " + str(time.time() - ts)
- signal = binarized
- coordY = 60
- if blobs and len(blobs):
- blobs.draw()
- signals = blobs.filter([b.isSquare() for b in blobs])
- #print signals
- if signals:
- signal = signals.sortDistance((320, 480))[0].crop().crop(8,8,46,46)
- #print "found signal: " + str(signal)
- lines = signal.findLines(threshold=10, minlinelength=10, maxlinegap=2, cannyth1=50, cannyth2=100)
- #print "lines: " + str(lines)
- if lines and len(lines):
- lines = lines.sortLength()
-
- center_line = lines[-1]
- center_line.draw()
-
- #print "center_line: " + str(center_line.length())
-
- angle = center_line.angle()
- #print "angle raw: " + str(angle)
- if angle < 0.0:
- angle = angle + 360
- if (((angle < 45.0 or angle > 315.0) and (center_line.coordinates()[0] < (signal.width / 2))) or
- ((angle > 45.0 and angle < 135.0) and (center_line.coordinates()[1] > (signal.height / 2))) or
- ((angle > 135.0 and angle < 225.0) and (center_line.coordinates()[0] > (signal.width / 2))) or
- ((angle > 225.0 and angle < 315.0) and (center_line.coordinates()[1] < (signal.height / 2)))):
- angle = angle + 180
- if angle > 360.0:
- angle = angle - 360
-
- img.drawText("signal found pointing at " + str(angle), 0, 0, fontsize=32 )
- #print "angle final: " + str(angle)
- else:
- angle = -1
- img.drawText("stop signal found", 0, 0, fontsize=32 )
-
- self.save_image(img)
- self._image_lock.release()
- #print "signal: " + str(time.time() - ts)
- return angle
-
- def find_face(self):
- print "face"
- faceX = None
- ts = time.time()
- self._image_lock.acquire()
- img = self.get_image(0)
- faces = img.resize(160).findHaarFeatures('face.xml')
- print "face.findHaar: " + str(time.time() - ts)
- if faces is not None and len(faces):
- # Get the largest face
- faces = faces.sortArea()
- bigFace = faces[-1]
- # Draw a green box around the face
- #bigFace.draw()
- faceX = (bigFace.coordinates()[0] * 100) / 80
-
- self.save_image(img)
- self._image_lock.release()
- print "face: " + str(time.time() - ts)
- return faceX
-
- def path_ahead(self):
- print "path ahead"
- ts = time.time()
- self._image_lock.acquire()
- img = self.get_image(0)
- print "path_ahead.get_image: " + str(time.time() - ts)
- warped = img.resize(160).warp(self._warp_corners_4).resize(640)
- print "path_ahead.warp: " + str(time.time() - ts)
- #ar_layer = SimpleCV.DrawingLayer((warped.width, warped.height))
- #ar_layer.rectangle((260,120),(120,320), color=(0,255,0))
- cropped = warped.crop(260, 160, 120, 320)
- control = cropped.crop(0, 280, 160, 40)
-
- control_color = control.meanColor()
- color_distance = cropped.dilate().colorDistance(control_color)
-
- control_hue = control.getNumpy().mean()
- #hue_distance = cropped.dilate().hueDistance(control_hue)
-
- print "path_ahead.crop: " + str(time.time() - ts)
- #control_hue = control_hue - 20 if control_hue > 127 else control_hue + 20
- #binarized = cropped.dilate().binarize(control_hue)
- #binarized = cropped.dilate().binarize().invert()
- control_hue = control_hue - 10
- binarized = color_distance.binarize(control_hue).invert()
- print "path_ahead.binarize: " + str(time.time() - ts)
- blobs = binarized.findBlobs(minsize=1000, maxsize=(cropped.width*cropped.height)-2000)
- print "path_ahead.blobs: " + str(time.time() - ts)
- coordY = 60
- if blobs and len(blobs):
- print blobs
- obstacle = blobs.sortDistance(point=(60,320))[0]
- print "path_ahead.sortdistnace: " + str(time.time() - ts)
- #dw_x = 260 + obstacle.coordinates()[0] - (obstacle.width()/2)
- #dw_y = 160 + obstacle.coordinates()[1] - (obstacle.height()/2)
- #img.drawRectangle(dw_x, dw_y, obstacle.width(), obstacle.height(), color=(255,0,0))
- coordY = 60 - (((obstacle.coordinates()[1]+(obstacle.height()/2)) * 48) / cropped.height)
- #print obstacle.coordinates()[1]+(obstacle.height()/2)
- #ar_layer.centeredRectangle(obstacle.coordinates(), (obstacle.width(), obstacle.height()))
- #warped.addDrawingLayer(ar_layer)
- #warped.applyLayers()
- #self.save_image(warped.warp(self._unwarp_corners), expire=10)
-
- img.drawText("path ahead clear for " + str(coordY) + " cm", 0, 0, fontsize=32 )
- print "path_ahead.drawtext: " + str(time.time() - ts)
- self.save_image(img)
- print "path_ahead.save_image: " + str(time.time() - ts)
- self._image_lock.release()
- print "path_ahead: " + str(time.time() - ts)
- return coordY
-
- def find_code(self):
- #print "code"
- code_data = None
- ts = time.time()
- self._image_lock.acquire()
- img = self.get_image(0)
- #print "signal.get_image: " + str(time.time() - ts)
- warped = img.resize(320).warp(self._warp_corners_2).resize(640)
- #print "code.warp: " + str(time.time() - ts)
- cropped = warped.crop(260, 160, 120, 320)
-
- barcode = cropped.findBarcode()
- if barcode:
- code_data = barcode.data
- img.drawText("code found: " + data, 0, 0, fontsize=32 )
- self.save_image(img)
- self._image_lock.release()
- #print "code: " + str(time.time() - ts)
- return code_data
-
- def find_logo(self):
- #print "logo"
- logo_y = None
- ts = time.time()
- self._image_lock.acquire()
- img = self.get_image(0)
- #print "logo.get_image: " + str(time.time() - ts)
- warped = img.resize(320).warp(self._warp_corners_2).resize(640)
- #print "logo.warp: " + str(time.time() - ts)
- cropped = warped.crop(260, 160, 120, 320)
-
- logo = img.findKeypointMatch(self._cam_off_img)
- if logo:
- #logo = logos[-1]
- x, y = logo.coordinates()
- print "found logo at: " + str(x) + " " + str(y)
- logo_y = 60 - ((y * 48) / cropped.height)
- img.drawText("logo found at: " + str(logo.coordinates()), 0, 0, fontsize=32 )
- self.save_image(img)
- self._image_lock.release()
- #print "code: " + str(time.time() - ts)
- return logo_y
-
- def sleep(self, elapse):
- print "sleep"
- time.sleep(elapse)
-
diff --git a/cnn_models/models.json b/cnn_models/models.json
new file mode 100644
index 00000000..47b9b270
--- /dev/null
+++ b/cnn_models/models.json
@@ -0,0 +1,20 @@
+{
+ "generic_fast_low": {
+ "status": 1.0,
+ "image_height": "224",
+ "image_width": "224",
+ "output_layer": ""
+ },
+ "generic_slow_high": {
+ "status": 1.0,
+ "image_height": "224",
+ "image_width": "224",
+ "output_layer": ""
+ },
+ "generic_object_detect": {
+ "status": 1.0,
+ "image_height": "224",
+ "image_width": "224",
+ "output_layer": ""
+ }
+}
\ No newline at end of file
diff --git a/coderbot.py b/coderbot.py
deleted file mode 100644
index fb1d5cc5..00000000
--- a/coderbot.py
+++ /dev/null
@@ -1,130 +0,0 @@
-import os
-import time
-import pigpio
-
-PIN_MOTOR_ENABLE = 22
-PIN_LEFT_FORWARD = 25
-PIN_LEFT_BACKWARD = 24
-PIN_RIGHT_FORWARD = 4
-PIN_RIGHT_BACKWARD = 17
-
-class CoderBot:
- def __init__(self):
- pigpio.start('localhost')
- self.stop()
- self._is_moving = False
-
- the_bot = None
-
- @classmethod
- def get_instance(cls):
- if not cls.the_bot:
- cls.the_bot = CoderBot()
- return cls.the_bot
-
- def forward(self, speed=100, elapse=-1):
- self._is_moving = True
- speed = (255 * speed) / 100
- pigpio.write(PIN_RIGHT_FORWARD, 1)
- pigpio.write(PIN_LEFT_FORWARD, 1)
- pigpio.write(PIN_RIGHT_BACKWARD, 0)
- pigpio.write(PIN_LEFT_BACKWARD, 0)
- pigpio.set_PWM_frequency(PIN_MOTOR_ENABLE, 100)
- pigpio.set_PWM_dutycycle(PIN_MOTOR_ENABLE, speed)
- if elapse > 0:
- time.sleep(elapse)
- self.stop()
-
- def backward(self, speed=100, elapse=-1):
- self._is_moving = True
- speed = (255 * speed) / 100
- pigpio.write(PIN_RIGHT_FORWARD, 0)
- pigpio.write(PIN_LEFT_FORWARD, 0)
- pigpio.write(PIN_RIGHT_BACKWARD, 1)
- pigpio.write(PIN_LEFT_BACKWARD, 1)
- pigpio.set_PWM_frequency(PIN_MOTOR_ENABLE, 100)
- pigpio.set_PWM_dutycycle(PIN_MOTOR_ENABLE, speed)
- if elapse > 0:
- time.sleep(elapse)
- self.stop()
-
- def left(self, speed=100, elapse=-1):
- self._is_moving = True
- speed = (255 * speed) / 100
- pigpio.write(PIN_RIGHT_FORWARD, 1)
- pigpio.write(PIN_LEFT_FORWARD, 0)
- pigpio.write(PIN_RIGHT_BACKWARD, 0)
- pigpio.write(PIN_LEFT_BACKWARD, 1)
- pigpio.set_PWM_frequency(PIN_MOTOR_ENABLE, 100)
- pigpio.set_PWM_dutycycle(PIN_MOTOR_ENABLE, speed)
- if elapse > 0:
- time.sleep(elapse)
- self.stop()
-
- def right(self, speed=100, elapse=-1):
- self._is_moving = True
- speed = (255 * speed) / 100
- pigpio.write(PIN_RIGHT_FORWARD, 0)
- pigpio.write(PIN_LEFT_FORWARD, 1)
- pigpio.write(PIN_RIGHT_BACKWARD, 1)
- pigpio.write(PIN_LEFT_BACKWARD, 0)
- pigpio.set_PWM_frequency(PIN_MOTOR_ENABLE, 100)
- pigpio.set_PWM_dutycycle(PIN_MOTOR_ENABLE, speed)
- if elapse > 0:
- time.sleep(elapse)
- self.stop()
-
- def forward_old(self, seconds=-1):
- pigpio.write(PIN_LEFT_FORWARD, 1)
- pigpio.write(PIN_RIGHT_FORWARD, 1)
- pigpio.write(PIN_MOTOR_ENABLE, 1)
- if seconds > 0:
- time.sleep(seconds)
- self.stop()
-
- def backward_old(self, seconds=-1):
- pigpio.write(PIN_LEFT_BACKWARD, 1)
- pigpio.write(PIN_RIGHT_BACKWARD, 1)
- pigpio.write(PIN_MOTOR_ENABLE, 1)
- if seconds > 0:
- time.sleep(seconds)
- self.stop()
-
- def left_old(self, seconds=-1):
- pigpio.write(PIN_LEFT_BACKWARD, 1)
- pigpio.write(PIN_RIGHT_FORWARD, 1)
- pigpio.write(PIN_MOTOR_ENABLE, 1)
- if seconds > 0:
- time.sleep(seconds)
- self.stop()
-
- def right_old(self, seconds=-1):
- pigpio.write(PIN_LEFT_FORWARD, 1)
- pigpio.write(PIN_RIGHT_BACKWARD, 1)
- pigpio.write(PIN_MOTOR_ENABLE, 1)
- if seconds > 0:
- time.sleep(seconds)
- self.stop()
-
- def stop(self):
- pigpio.write(PIN_MOTOR_ENABLE, 0)
- pigpio.write(PIN_LEFT_FORWARD, 0)
- pigpio.write(PIN_LEFT_BACKWARD, 0)
- pigpio.write(PIN_RIGHT_FORWARD, 0)
- pigpio.write(PIN_RIGHT_BACKWARD, 0)
- self._is_moving = False
-
- def is_moving(self):
- return self._is_moving
-
- def say(self, what):
- if "$" in what:
- os.system ('omxplayer sounds/' + what[1:])
- else:
- os.system ('espeak -vit -p 90 -a 200 -s 150 -g 10 "' + what + '" 2>>/dev/null')
-
- def halt(self):
- os.system ('sudo halt')
-
-
-
diff --git a/coderbot/activity.py b/coderbot/activity.py
new file mode 100644
index 00000000..19e3d102
--- /dev/null
+++ b/coderbot/activity.py
@@ -0,0 +1,51 @@
+from tinydb import TinyDB, Query
+from threading import Lock
+# Programs and Activities databases
+class Activities():
+ _instance = None
+
+ @classmethod
+ def get_instance(cls):
+ if cls._instance is None:
+ cls._instance = Activities()
+ return cls._instance
+
+ def __init__(self):
+ self.activities = TinyDB("data/activities.json")
+ self.query = Query()
+ self.lock = Lock()
+
+ def load(self, name, default):
+ with self.lock:
+ if name and default is None:
+ activities = self.activities.search(self.query.name == name)
+ if len(activities) > 0:
+ return activities[0]
+ elif default is not None:
+ if len(self.activities.search(self.query.default == True)) > 0:
+ return self.activities.search(self.query.default == True)[0]
+ return None
+ return None
+
+ def save(self, name, activity):
+ with self.lock:
+ # if saved activity is "default", reset existing default activity to "non-default"
+ if activity.get("default", False) is True:
+ self.activities.update({'default': False})
+ if self.activities.search(self.query.name == name) == []:
+ self.activities.insert(activity)
+ else:
+ self.activities.update(activity, self.query.name == activity["name"])
+
+ def delete(self, name):
+ with self.lock:
+ activities = self.activities.search(self.query.name == name)
+ if len(activities) > 0:
+ activity = activities[0]
+ if activity.get("default", False) is True:
+ self.activities.update({'default': True}, self.query.stock == True)
+ self.activities.remove(self.query.name == activity["name"])
+
+ def list(self):
+ with self.lock:
+ return self.activities.all()
diff --git a/coderbot/api.py b/coderbot/api.py
new file mode 100644
index 00000000..70164c49
--- /dev/null
+++ b/coderbot/api.py
@@ -0,0 +1,398 @@
+"""
+API methods implementation
+This file contains every method called by the API defined in v2.yml
+"""
+
+import logging
+import os
+import subprocess
+import urllib
+
+import connexion
+import picamera
+from flask import Response, request, send_file
+from werkzeug.datastructures import Headers
+
+from config import Config
+from activity import Activities
+from audio import Audio
+from camera import Camera
+from cnn.cnn_manager import CNNManager
+from runtime_test import run_test
+from musicPackages import MusicPackageManager
+from program import Program, ProgramEngine
+
+from balena import Balena
+from coderbot import CoderBot
+
+BUTTON_PIN = 16
+
+config = Config.get()
+bot = CoderBot.get_instance()
+audio_device = Audio.get_instance()
+cam = Camera.get_instance()
+
+def get_serial():
+ """
+ Extract serial from cpuinfo file
+ """
+ cpuserial = "0000000000000000"
+ try:
+ f = open('/proc/cpuinfo', 'r')
+ for line in f:
+ if line[0:6] == 'Serial':
+ cpuserial = line[10:26]
+ f.close()
+ except Exception:
+ cpuserial = "ERROR000000000"
+
+ return cpuserial
+
+def get_status():
+ """
+ Expose CoderBot status:
+ temperature, uptime, and internet connectivity status.
+ (Cached method)
+ """
+
+ temp = "undefined"
+ try:
+ temp = os.popen("vcgencmd measure_temp").readline().replace("temp=", "")
+ except Exception:
+ pass
+
+ uptime = 0
+ try:
+ uptime = subprocess.check_output(["uptime"]).decode('utf-8').replace('\n', '')
+ except Exception:
+ pass
+
+ internet_status = False
+ try:
+ urllib.request.urlopen("https://coderbot.org/")
+ internet_status = True
+ except Exception:
+ pass
+
+ return {'internet_status': internet_status,
+ 'temp': temp,
+ 'uptime': uptime}
+
+def get_info():
+ """
+ Expose informations about the CoderBot system.
+ (Cached method)
+ """
+ device = {}
+ serial = get_serial()
+
+ try:
+ device = Balena.get_instance().device()
+ logging.info("device: %s", str(device))
+ except Exception:
+ pass
+
+ return { 'release_commit': device.get("commit"),
+ 'coderbot_version': os.getenv("CODERBOT_VERSION"),
+ 'update_status': device.get("status"),
+ 'kernel': device.get("os_version"),
+ 'serial': serial }
+
+prog = None
+prog_engine = ProgramEngine.get_instance()
+
+activities = Activities.get_instance()
+
+## Robot control
+
+def stop():
+ bot.stop()
+ return 200
+
+def move(body):
+ speed=body.get("speed")
+ elapse=body.get("elapse")
+ distance=body.get("distance")
+ if (speed is None or speed == 0) or (elapse is not None and distance is not None):
+ return 400
+ bot.move(speed=speed, elapse=elapse, distance=distance)
+ return 200
+
+def turn(body):
+ speed=body.get("speed")
+ elapse=body.get("elapse")
+ distance=body.get("distance")
+ if (speed is None or speed == 0) or (elapse is not None and distance is not None):
+ return 400
+ bot.turn(speed=speed, elapse=elapse, distance=distance)
+ return 200
+
+def takePhoto():
+ try:
+ cam.photo_take()
+ audio_device.say(config.get("sound_shutter"))
+ return 200
+ except Exception as e:
+ logging.warning("Error: %s", e)
+
+def recVideo():
+ try:
+ cam.video_rec()
+ audio_device.say(config.get("sound_shutter"))
+ return 200
+ except Exception as e:
+ logging.warning("Error: %s", e)
+
+def stopVideo():
+ try:
+ cam.video_stop()
+ audio_device.say(config.get("sound_shutter"))
+ return 200
+ except Exception as e:
+ logging.warning("Error: %s", e)
+
+def speak(body):
+ text = body.get("text", "")
+ locale = body.get("locale", "")
+ logging.debug("say: " + text + " in: " + locale)
+ audio_device.say(text, locale)
+ return 200
+
+def reset():
+ Balena.get_instance().purge()
+ return 200
+
+def halt():
+ audio_device.say(what=config.get("sound_stop"))
+ Balena.get_instance().shutdown()
+ return 200
+
+def restart():
+ Balena.get_instance().restart()
+
+def reboot():
+ audio_device.say(what=config.get("sound_stop"))
+ Balena.get_instance().reboot()
+ return 200
+
+def video_stream(a_cam):
+ while True:
+ frame = a_cam.get_image_jpeg()
+ yield ("--BOUNDARYSTRING\r\n" +
+ "Content-type: image/jpeg\r\n" +
+ "Content-Length: " + str(len(frame)) + "\r\n\r\n")
+ yield frame
+ yield "\r\n"
+
+def streamVideo():
+ try:
+ h = Headers()
+ h.add('Age', 0)
+ h.add('Cache-Control', 'no-cache, private')
+ h.add('Pragma', 'no-cache')
+ return Response(video_stream(cam), headers=h, mimetype="multipart/x-mixed-replace; boundary=--BOUNDARYSTRING")
+ except Exception:
+ pass
+
+def listPhotos():
+ """
+ Expose the list of taken photos
+ """
+ return cam.get_photo_list()
+
+def getPhoto(name):
+ mimetype = {'jpg': 'image/jpeg', 'mp4': 'video/mp4'}
+ try:
+ media_file = cam.get_photo_file(name)
+ return send_file(media_file, mimetype=mimetype.get(name[:-3], 'image/jpeg'), max_age=0)
+ except picamera.exc.PiCameraError as e:
+ logging.error("Error: %s", str(e))
+ return 503
+ except FileNotFoundError:
+ return 404
+
+def savePhoto(name, body):
+ try:
+ cam.update_photo({"name": name, "tag": body.get("tag")})
+ except FileNotFoundError:
+ return 404
+
+def deletePhoto(name):
+ logging.debug("photo delete")
+ try:
+ cam.delete_photo(name)
+ except FileNotFoundError:
+ return 404
+
+def restoreSettings():
+ Config.restore()
+ return restart()
+
+def loadSettings():
+ return Config.get()
+
+def saveSettings(body):
+ Config.write(body)
+ return 200
+
+def updateFromPackage():
+ os.system('sudo bash /home/pi/clean-update.sh')
+ file_to_upload = connexion.request.files['file_to_upload']
+ file_to_upload.save(os.path.join('/home/pi/', 'update.tar'))
+ os.system('sudo reboot')
+ return 200
+
+def listMusicPackages():
+ """
+ list available music packages
+ """
+ musicPkg = MusicPackageManager.get_instance()
+ response = musicPkg.listPackages()
+ return response
+
+def addMusicPackage():
+ """
+ Add a musical package an save the list of available packages on disk
+ also add sounds and directory
+ zipName = request.args.get("zipname")
+ """
+ try:
+ file_to_upload = connexion.request.files['file_to_upload']
+ logging.info("adding " + file_to_upload.filename)
+ file_to_upload.save(os.path.join('/tmp/', file_to_upload.filename))
+ music_pkg = MusicPackageManager.get_instance()
+ music_pkg.addPackage(file_to_upload.filename)
+ return "{}", 200
+ except ValueError:
+ return "{}", 409
+ except Exception:
+ return "{}", 400
+
+def deleteMusicPackage(name):
+ """
+ Delete a musical package an save the list of available packages on disk
+ also delete package sounds and directory
+ """
+ musicPkg = MusicPackageManager.get_instance()
+ musicPkg.deletePackage(name)
+ return 200
+
+## Programs
+
+def saveProgram(name, body):
+ overwrite = body.get("overwrite")
+ existing_program = prog_engine.load(name)
+ logging.info("saving - name: %s, body: %s", name, str(existing_program))
+ if existing_program is not None and not overwrite:
+ return "askOverwrite"
+ elif existing_program is not None and existing_program.is_default() == True:
+ return "defaultCannotOverwrite", 400
+ program = Program(name=body.get("name"), code=body.get("code"), dom_code=body.get("dom_code"))
+ prog_engine.save(program)
+ return 200
+
+def loadProgram(name):
+ existing_program = prog_engine.load(name)
+ if existing_program:
+ return existing_program.as_dict(), 200
+ else:
+ return 404
+
+def deleteProgram(name):
+ prog_engine.delete(name)
+
+def listPrograms():
+ return prog_engine.prog_list()
+
+def runProgram(name, body):
+ """
+ Execute the given program
+ """
+ logging.debug("program_exec")
+ code = body.get('code')
+ prog = prog_engine.create(name, code)
+ return prog.execute()
+
+def stopProgram(name):
+ """
+ Stop the program execution
+ """
+ logging.debug("program_end")
+ prog = prog_engine.get_current_program()
+ if prog:
+ prog.stop()
+ return "ok"
+
+def statusProgram(name):
+ """
+ Expose the program status
+ """
+ logging.debug("program_status")
+ prog = prog_engine.get_current_program()
+ if prog is None:
+ prog = Program("")
+ return {'name': prog.name, "running": prog.is_running(), "log": prog_engine.get_log()}
+
+
+## Activities
+
+def saveActivity(name, body):
+ activity = body
+ activities.save(activity.get("name"), activity)
+
+def saveAsNewActivity(body):
+ activity = body
+ activities.save(activity.get("name"), activity)
+
+def loadActivity(name=None, default=None):
+ return activities.load(name, default)
+
+def deleteActivity(name):
+ activities.delete(name), 200
+
+def listActivities():
+ return activities.list()
+
+def resetDefaultPrograms():
+ """
+ Delete everything but the default programs
+ """
+ programs.purge()
+ for filename in os.listdir("data/defaults/programs/"):
+ if filename.endswith(".json"):
+ with open("data/defaults/programs/" + filename) as p:
+ q = p.read()
+ programs.insert(json.loads(q))
+
+## Test
+def testCoderbot(body):
+ return run_test(body.get("tests", []))
+
+def listCNNModels():
+ cnn = CNNManager.get_instance()
+ return cnn.get_models()
+
+def trainCNNModel(body):
+ cam = Camera.get_instance()
+ cnn = CNNManager.get_instance()
+ logging.info("cnn_models_new")
+ cnn.train_new_model(model_name=body.get("model_name"),
+ architecture=body.get("architecture"),
+ image_tags=body.get("image_tags"),
+ photos_meta=cam.get_photo_list(),
+ training_steps=body.get("training_steps"),
+ learning_rate=body.get("learning_rate"))
+
+ return {"name": body.get("model_name"), "status": 0}
+
+def getCNNModel(name):
+ cnn = CNNManager.get_instance()
+ model_status = cnn.get_models().get(name)
+
+ return model_status
+
+def deleteCNNModel(name):
+ cnn = CNNManager.get_instance()
+ model_status = cnn.delete_model(model_name=name)
+
+ return model_status
\ No newline at end of file
diff --git a/coderbot/audio.py b/coderbot/audio.py
new file mode 100644
index 00000000..42a4eeca
--- /dev/null
+++ b/coderbot/audio.py
@@ -0,0 +1,229 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+import os
+from array import array
+import time
+import logging
+import wave
+import audioop
+import pyaudio
+import alsaaudio
+
+import queue
+# [END import_libraries]
+
+# Audio recording parameters
+RATE = 44100
+CHUNK = int(RATE / 10) # 100ms
+FORMAT = pyaudio.paInt16
+
+MODELDIR = "/home/pi/coderbot/psmodels/"
+SOUNDDIR = "./sounds/"
+SOUNDEXT = ".wav"
+
+SOURCE_OUTPUT = 0
+SOURCE_INPUT = 1
+
+class Audio:
+
+ _instance = None
+
+ @classmethod
+ def get_instance(cls):
+ if cls._instance is None:
+ cls._instance = Audio()
+ return cls._instance
+
+ def __init__(self):
+ self.pa = pyaudio.PyAudio()
+ try:
+ self.stream_in = self.MicrophoneStream(FORMAT, RATE, CHUNK)
+ except Exception:
+ logging.info("Audio: input stream not available")
+
+ def exit(self):
+ pass
+
+ def say(self, what, locale='en'):
+ if what and "$" in what:
+ self.play(what[1:] + SOUNDEXT)
+ elif what and what:
+ os.system('espeak --stdout -v' + locale + ' -p 90 -a 200 -s 150 -g 10 "' + what + '" 2>>/dev/null | aplay -q')
+
+ def normalize(self, snd_data):
+ "Average the volume out"
+ MAXIMUM = 16384
+ times = float(MAXIMUM) / max(abs(i) for i in snd_data)
+
+ r = array('h', snd_data)
+ c = 0
+ for i in snd_data:
+ r[c] = int(i*times)
+ c += 1
+ return r
+
+ def record(self, elapse):
+ r = bytearray()
+ t = time.time()
+ with self.stream_in as stream:
+ audio_generator = stream.generator()
+ for content in audio_generator:
+ r.extend(content)
+ if time.time() - t >= elapse:
+ return r
+ return r
+
+ def record_to_file(self, filename, elapse):
+ data = self.record(elapse)
+ #data = pack('<' + ('h'*len(data)), *data)
+
+ wf = wave.open(SOUNDDIR + filename, 'wb')
+ wf.setnchannels(1)
+ wf.setsampwidth(self.stream_in.get_sample_size(FORMAT))
+ wf.setframerate(RATE)
+ wf.writeframes(data)
+ wf.close()
+
+ def play(self, filename):
+
+ f = wave.open(SOUNDDIR + filename, 'rb')
+
+ format = None
+
+ # 8bit is unsigned in wav files
+ if f.getsampwidth() == 1:
+ format = alsaaudio.PCM_FORMAT_U8
+ # Otherwise we assume signed data, little endian
+ elif f.getsampwidth() == 2:
+ format = alsaaudio.PCM_FORMAT_S16_LE
+ elif f.getsampwidth() == 3:
+ format = alsaaudio.PCM_FORMAT_S24_3LE
+ elif f.getsampwidth() == 4:
+ format = alsaaudio.PCM_FORMAT_S32_LE
+ else:
+ raise ValueError('Unsupported format')
+
+ periodsize = f.getframerate() // 8
+
+ logging.info('%d channels, %d sampling rate, format %d, periodsize %d\n' % (f.getnchannels(),
+ f.getframerate(),
+ format,
+ periodsize))
+
+ device = alsaaudio.PCM(channels=f.getnchannels(), rate=f.getframerate(), format=format, periodsize=periodsize)
+
+ data = f.readframes(periodsize)
+ while data:
+ # Read data from stdin
+ device.write(data)
+ data = f.readframes(periodsize)
+
+ def hear(self, level, elapse=1.0):
+ t = time.time()
+ with self.stream_in as stream:
+ audio_generator = stream.generator()
+ for content in audio_generator:
+ snd_rms = audioop.rms(content, 2)
+ if snd_rms > level:
+ return True
+ if time.time() - t >= elapse:
+ return False
+ return False
+
+ def get_volume(self):
+ volume = alsaaudio.Mixer('Headphone', cardindex=0).getvolume()
+ logging.info(volume) # list of per-channel values (floats)
+ return volume
+
+ def set_volume(self, volume_output, volume_input):
+ alsaaudio.Mixer('Headphone', cardindex=0).setvolume(volume_output)
+ alsaaudio.Mixer('Mic', cardindex=1).setvolume(volume_input)
+
+ class MicrophoneStream(object):
+ """Opens a recording stream as a generator yielding the audio chunks."""
+ def __init__(self, fmt, rate, chunk):
+ self._audio_interface = None
+ self._format = fmt
+ self._rate = rate
+ self._chunk = chunk
+
+ # Create a thread-safe buffer of audio data
+ self._buff = None
+ self.closed = True
+
+ def __enter__(self):
+ self._audio_interface = pyaudio.PyAudio()
+ self._buff = queue.Queue()
+ self._audio_stream = self._audio_interface.open(
+ format=self._format,
+ # The API currently only supports 1-channel (mono) audio
+ # https://goo.gl/z757pE
+ channels=1, rate=self._rate,
+ input=True, frames_per_buffer=self._chunk,
+ input_device_index=1,
+ # Run the audio stream asynchronously to fill the buffer object.
+ # This is necessary so that the input device's buffer doesn't
+ # overflow while the calling thread makes network requests, etc.
+ stream_callback=self._fill_buffer,
+ )
+ self.closed = False
+
+ return self
+
+ def __exit__(self, atype, value, traceback):
+ self._audio_stream.stop_stream()
+ self._audio_stream.close()
+ self._audio_interface.terminate()
+ self.closed = True
+ self._buff.put(None)
+
+ def close(self):
+ pass
+
+ def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
+ """Continuously collect data from the audio stream, into the buffer."""
+ self._buff.put(in_data)
+ return None, pyaudio.paContinue
+
+ def get_sample_size(self, fmt):
+ return self._audio_interface.get_sample_size(fmt)
+
+ def generator(self):
+ while not self.closed:
+ # Use a blocking get() to ensure there's at least one chunk of
+ # data, and stop iteration if the chunk is None, indicating the
+ # end of the audio stream.
+ chunk = self._buff.get()
+ if chunk is None:
+ return
+ data = [chunk]
+
+ # Now consume whatever other data's still buffered.
+ while True:
+ try:
+ chunk = self._buff.get(block=False)
+ if chunk is None:
+ return
+ data.append(chunk)
+ except queue.Empty:
+ break
+
+ yield b''.join(data)
+# [END audio_stream]
diff --git a/coderbot/balena/__init__.py b/coderbot/balena/__init__.py
new file mode 100644
index 00000000..9df7c43f
--- /dev/null
+++ b/coderbot/balena/__init__.py
@@ -0,0 +1,44 @@
+import os
+from urllib.request import urlopen, Request
+import json
+import logging
+
+class Balena():
+ _instance = None
+
+ @classmethod
+ def get_instance(cls):
+ if cls._instance is None:
+ cls._instance = Balena()
+ return cls._instance
+
+ def __init__(self):
+ self.supervisor_address = os.environ["BALENA_SUPERVISOR_ADDRESS"]
+ self.supervisor_key = os.environ["BALENA_SUPERVISOR_API_KEY"]
+ self.app_id_data = json.dumps({ "appId": os.environ["BALENA_APP_ID"] }).encode("utf-8")
+ self.headers = { 'Content-Type': 'application/json' }
+
+ def purge(self):
+ logging.debug("reset bot")
+ req = Request(f'{self.supervisor_address}/v1/purge?apikey={self.supervisor_key}', data=self.app_id_data, headers=self.headers, method='POST')
+ return json.load(urlopen(req))
+
+ def shutdown(self):
+ logging.debug("shutdown bot")
+ req = Request(f'{self.supervisor_address}/v1/shutdown?apikey={self.supervisor_key}', headers=self.headers, method='POST')
+ return json.load(urlopen(req))
+
+ def restart(self):
+ logging.debug("restarting bot")
+ req = Request(f'{self.supervisor_address}/v1/restart?apikey={self.supervisor_key}', data=self.app_id_data, headers=self.headers, method='POST')
+ return json.load(urlopen(req))
+
+ def reboot(self):
+ logging.debug("reboot bot")
+ req = Request(f'{self.supervisor_address}/v1/reboot?apikey={self.supervisor_key}', headers=self.headers, method='POST')
+ return json.load(urlopen(req))
+
+ def device(self):
+ logging.debug("reboot bot", f'{self.supervisor_address}get?apikey={self.supervisor_key}')
+ req = Request(f'{self.supervisor_address}/v1/device?apikey={self.supervisor_key}', headers=self.headers, method='GET')
+ return json.load(urlopen(req))
diff --git a/coderbot/camera.py b/coderbot/camera.py
new file mode 100644
index 00000000..8866b9fd
--- /dev/null
+++ b/coderbot/camera.py
@@ -0,0 +1,388 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+import time
+import os
+import math
+import json
+import logging
+import pathlib
+from PIL import Image as PILImage
+try:
+ from BytesIO import BytesIO
+except ImportError:
+ from io import BytesIO
+
+from cv import camera, image, blob
+
+from cnn.cnn_manager import CNNManager
+
+import config
+
+MAX_IMAGE_AGE = 0.0
+PHOTO_PATH = "data/media"
+PHOTO_METADATA_FILE = "data/media/metadata.json"
+PHOTO_PREFIX = "DSC"
+VIDEO_PREFIX = "VID"
+PHOTO_THUMB_SUFFIX = "_thumb"
+PHOTO_THUMB_SIZE = (240, 180)
+VIDEO_ELAPSE_MAX = 900
+
+class Camera(object):
+
+ # pylint: disable=too-many-instance-attributes
+ # pylint: disable=too-many-public-methods
+
+ _instance = None
+
+ @classmethod
+ def get_instance(cls):
+ if cls._instance is None:
+ cls._instance = Camera()
+ #cls._instance.start()
+ return cls._instance
+
+ def __init__(self):
+ logging.info("starting camera")
+ cam_props = {"width":640, "height":512,
+ "cv_image_factor": config.Config.get().get("cv_image_factor"),
+ "exposure_mode": config.Config.get().get("camera_exposure_mode"),
+ "framerate": config.Config.get().get("camera_framerate"),
+ "bitrate": config.Config.get().get("camera_jpeg_bitrate"),
+ "jpeg_quality": int(config.Config.get().get("camera_jpeg_quality"))}
+ self._camera = camera.Camera(props=cam_props)
+ self.recording = False
+ self.video_start_time = time.time() + 8640000
+ self._image_time = 0
+ self._cv_image_factor = int(config.Config.get().get("cv_image_factor", 4))
+ self._image_refresh_timeout = float(config.Config.get().get("camera_refresh_timeout", 0.1))
+ self._color_object_size_min = int(config.Config.get().get("camera_color_object_size_min", 80)) / (self._cv_image_factor * self._cv_image_factor)
+ self._color_object_size_max = int(config.Config.get().get("camera_color_object_size_max", 32000)) / (self._cv_image_factor * self._cv_image_factor)
+ self._path_object_size_min = int(config.Config.get().get("camera_path_object_size_min", 80)) / (self._cv_image_factor * self._cv_image_factor)
+ self._path_object_size_max = int(config.Config.get().get("camera_path_object_size_max", 32000)) / (self._cv_image_factor * self._cv_image_factor)
+ self.load_photo_metadata()
+ if not self._photos:
+ self._photos = []
+ for filenames in os.walk(PHOTO_PATH):
+ for filename in filenames[2]:
+ if (PHOTO_PREFIX in filename or VIDEO_PREFIX in filename) and PHOTO_THUMB_SUFFIX not in filename:
+ self._photos.append({'name': filename})
+ self.save_photo_metadata()
+
+ self._cnn_classifiers = {}
+ cnn_model = config.Config.get().get("cnn_default_model", "")
+ if cnn_model != "":
+ try:
+ self._cnn_classifiers[cnn_model] = CNNManager.get_instance().load_model(cnn_model)
+ self._cnn_classifier_default = self._cnn_classifiers[cnn_model]
+ logging.info("loaded: " + cnn_model + " " + str(self._cnn_classifier_default))
+ except Exception:
+ logging.warning("model not found: %s", cnn_model)
+
+ self._camera.grab_start()
+ self._image_cv = self.get_image()
+
+ super(Camera, self).__init__()
+
+ def get_image(self):
+ return image.Image(self._camera.get_image_bgr())
+
+ def get_image_cv_jpeg(self):
+ return self._image_cv.to_jpeg()
+
+ def set_image_cv(self, an_image):
+ self._image_cv = an_image
+
+ def get_image_jpeg(self):
+ return self._camera.get_image_jpeg()
+
+ def set_text(self, text):
+ self._camera.set_overlay_text(str(text))
+
+ def load_photo_metadata(self):
+ try:
+ with open(PHOTO_METADATA_FILE, "rt") as f:
+ self._photos = json.load(f)
+ f.close()
+ except Exception:
+ logging.warning("no metadata file, starting from empty")
+ pathlib.Path(PHOTO_PATH).mkdir(parents=True, exist_ok=True)
+ self._photos = []
+ self.save_photo_metadata()
+
+ def save_photo_metadata(self):
+ f = open(PHOTO_METADATA_FILE, "wt")
+ json.dump(self._photos, f)
+ f.close()
+
+ def update_photo(self, photo):
+ for p in self._photos:
+ if p["name"] == photo["name"]:
+ p["tag"] = photo["tag"]
+ self.save_photo_metadata()
+
+ def get_next_photo_index(self):
+ last_photo_index = 0
+ for p in self._photos:
+ try:
+ index = int(p["name"][len(PHOTO_PREFIX):-len(self._camera.PHOTO_FILE_EXT)])
+ if index > last_photo_index:
+ last_photo_index = index
+ except Exception:
+ pass
+ return last_photo_index + 1
+
+ def photo_take(self):
+ photo_index = self.get_next_photo_index()
+ filename = PHOTO_PREFIX + str(photo_index) + self._camera.PHOTO_FILE_EXT
+ filename_thumb = PHOTO_PREFIX + str(photo_index) + PHOTO_THUMB_SUFFIX + self._camera.PHOTO_FILE_EXT
+ of = open(PHOTO_PATH + "/" + filename, "wb+")
+ oft = open(PHOTO_PATH + "/" + filename_thumb, "wb+")
+ im_str = self.get_image_jpeg()
+ of.write(im_str)
+ # thumb
+ im_pil = PILImage.open(BytesIO(im_str))
+ im_pil.resize(PHOTO_THUMB_SIZE).save(oft)
+ self._photos.append({"name":filename})
+ self.save_photo_metadata()
+ of.close()
+ oft.close()
+
+ def is_recording(self):
+ return self.recording
+
+ def video_rec(self, video_name=None):
+ if self.is_recording():
+ return
+ self.recording = True
+
+ if video_name is None:
+ video_index = self.get_next_photo_index()
+ filename = VIDEO_PREFIX + str(video_index) + self._camera.VIDEO_FILE_EXT
+ filename_thumb = VIDEO_PREFIX + str(video_index) + PHOTO_THUMB_SUFFIX + self._camera.PHOTO_FILE_EXT
+ else:
+ filename = VIDEO_PREFIX + video_name + self._camera.VIDEO_FILE_EXT
+ filename_thumb = VIDEO_PREFIX + video_name + PHOTO_THUMB_SUFFIX + self._camera.PHOTO_FILE_EXT
+ try:
+ #remove previous file and reference in album
+ os.remove(PHOTO_PATH + "/" + filename)
+ self._photos.remove({"name":filename})
+ except Exception:
+ pass
+
+ oft = open(PHOTO_PATH + "/" + filename_thumb, "wb")
+ im_str = self._camera.get_image_jpeg()
+ im_pil = PILImage.open(BytesIO(im_str))
+ im_pil.resize(PHOTO_THUMB_SIZE).save(oft)
+ self._photos.append({"name":filename})
+ self.save_photo_metadata()
+ self._camera.video_rec(PHOTO_PATH + "/" + filename)
+ self.video_start_time = time.time()
+ oft.close()
+
+ def video_stop(self):
+ if self.recording:
+ self._camera.video_stop()
+ self.recording = False
+
+ def get_photo_list(self):
+ return self._photos
+
+ def get_photo_file(self, filename):
+ return open(PHOTO_PATH + "/" + filename, "rb")
+
+ def get_photo_thumb_file(self, filename):
+ return open(PHOTO_PATH + "/" + filename[:-len(self._camera.PHOTO_FILE_EXT)] + PHOTO_THUMB_SUFFIX + self._camera.PHOTO_FILE_EXT, "rb")
+
+ def delete_photo(self, filename):
+ logging.info("delete photo: %s", filename)
+ os.remove(PHOTO_PATH + "/" + filename)
+ os.remove(PHOTO_PATH + "/" + filename[:filename.rfind(".")] + PHOTO_THUMB_SUFFIX + self._camera.PHOTO_FILE_EXT)
+ for photo in self._photos:
+ if photo["name"] == filename:
+ self._photos.remove(photo)
+ self.save_photo_metadata()
+
+ def exit(self):
+ #self.join()
+ self.video_stop()
+ self._camera.grab_stop()
+
+ def get_average(self):
+ avg = self.get_image().get_average()
+ return avg
+
+ def find_line(self):
+ img = self.get_image()
+ avg = img.get_average()
+ img = img.binarize(int((avg[0]+avg[2])/2))
+ img = img.erode().dilate()
+ if int(img._data.mean()) > 127:
+ img = img.invert()
+ slices = [0, 0, 0]
+ blobs = [0, 0, 0]
+ slices[0] = img.crop(0, int(self._camera.out_rgb_resolution[1]/1.2), self._camera.out_rgb_resolution[0], self._camera.out_rgb_resolution[1])
+ slices[1] = img.crop(0, int(self._camera.out_rgb_resolution[1]/1.5), self._camera.out_rgb_resolution[0], int(self._camera.out_rgb_resolution[1]/1.2))
+ slices[2] = img.crop(0, int(self._camera.out_rgb_resolution[1]/2.0), self._camera.out_rgb_resolution[0], int(self._camera.out_rgb_resolution[1]/1.5))
+ y_offset = [int(self._camera.out_rgb_resolution[1]/1.2),
+ int(self._camera.out_rgb_resolution[1]/1.5),
+ int(self._camera.out_rgb_resolution[1]/2.0)]
+ coords = [-1, -1, -1]
+ for idx, slc in enumerate(slices):
+ blobs[idx] = slc.find_blobs(minsize=2000/(self._cv_image_factor * self._cv_image_factor), maxsize=16000/(self._cv_image_factor * self._cv_image_factor))
+ if blobs[idx]:
+ coords[idx] = (blobs[idx][0].center[0] * 100) / self._camera.out_rgb_resolution[0]
+ blb = blobs[idx][0]
+ img.draw_rect(blb.left, y_offset[idx] + blb.top, blb.right, y_offset[idx] + blb.bottom, (0, 255, 0), 5)
+ self.set_image_cv(img)
+ return coords
+
+ def find_face(self):
+ face_x = face_y = face_size = None
+ img = self.get_image()
+ faces = img.grayscale().find_faces()
+ if len(faces):
+ # Get the largest face, face is a rectangle
+ x, y, w, h = faces[0]
+ center_x = x + (w/2)
+ face_x = ((center_x * 100) / self._camera.out_rgb_resolution[0]) - 50 #center = 0
+ center_y = y + (h/2)
+ face_y = 50 - (center_y * 100) / self._camera.out_rgb_resolution[1] #center = 0
+ size = h
+ face_size = (size * 100) / self._camera.out_rgb_resolution[1]
+ logging.info("face found, x: " + str(face_x) + " y: " + str(face_y) + " size: " + str(face_size))
+ return [face_x, face_y, face_size]
+
+ def path_ahead(self):
+ image_size = self._camera.out_rgb_resolution
+ img = self.get_image()
+
+ size_y = img._data.shape[0]
+ size_x = img._data.shape[1]
+ threshold = img.crop(0, size_y - int(size_y/12), size_x, size_y)._data.mean() / 2
+
+ blobs = img.binarize(threshold).dilate().find_blobs(minsize=self._path_object_size_min, maxsize=self._path_object_size_max)
+ coordY = 60
+ if blobs:
+ obstacle = blob.Blob.sort_distance((image_size[0]/2, image_size[1]), blobs)[0]
+
+ coords = img.transform([(obstacle.center[0], obstacle.bottom)], img.get_transform(img.size()[1]))
+ x = coords[0][0]
+ y = coords[0][1]
+ coordY = 60 - ((y * 48) / (480 / self._cv_image_factor))
+ logging.info("x: %s y: %s coordY: %s", str(x), str(y), str(coordY))
+
+ return coordY
+
+ def find_color(self, s_color):
+ image_size = self._camera.out_rgb_resolution
+ color = (int(s_color[1:3], 16), int(s_color[3:5], 16), int(s_color[5:7], 16))
+ #ts = time.time()
+ img = self.get_image()
+ bw = img.filter_color(color)
+ objects = bw.find_blobs(minsize=self._color_object_size_min, maxsize=self._color_object_size_max)
+ logging.debug("objects: %s", str(objects))
+ dist = -1
+ angle = 180
+ fov_offset = 12 #cm
+ fov_total_y = 68 #cm
+ fov_total_x = 60 #cm
+
+ if objects:
+ obj = objects[-1]
+ logging.info("bottom: " + str(obj.center[0]) + " " + str(obj.bottom))
+ coords = bw.transform([(obj.center[0], obj.bottom)], bw.get_transform(bw.size()[1]))
+ logging.info("coordinates: %s", str(coords))
+ x = coords[0][0]
+ y = coords[0][1]
+ dist = math.sqrt(math.pow(fov_offset + (fov_total_y * (image_size[1] - y) / (image_size[1]/1.2)), 2) + (math.pow((x-(image_size[0]/2)) * fov_total_x / image_size[0], 2)))
+ angle = math.atan2(x - (image_size[0]/2), image_size[1] - y) * 180 / math.pi
+ logging.info("object found, dist: " + str(dist) + " angle: " + str(angle))
+ #self.save_image(img.to_jpeg())
+ #print "object: " + str(time.time() - ts)
+ return [dist, angle]
+
+ def find_text(self, lang="en", timeout=0):
+ t1 = time.time()
+ text = None
+ #color = (int(back_color[1:3], 16), int(back_color[3:5], 16), int(back_color[5:7], 16))
+ img = self.get_image()
+ #rec_image = img.find_rect(color=color)
+ text = img.find_text(lang, timeout)
+ logging.info("find_text fps: " + str(1.0/(time.time() - t1)))
+ #if rec_image:
+ # logging.info("image: %s", str(rec_image))
+ # bin_image = rec_image.binarize().invert()
+ # text = bin_image.find_text(accept)
+ return text
+
+ def find_qr_code(self):
+ img = self.get_image()
+ return img.find_qr_code()
+
+ def find_ar_code(self):
+ img = self.get_image()
+ return img.find_ar_code()
+
+ def cnn_classify(self, model_name=None, top_results=3):
+ classifier = None
+ if model_name:
+ classifier = self._cnn_classifiers.get(model_name)
+ if classifier is None:
+ classifier = CNNManager.get_instance().load_model(model_name)
+ self._cnn_classifiers[model_name] = classifier
+ else:
+ classifier = self._cnn_classifier_default
+
+ t0 = time.time()
+ classes = None
+ try:
+ img = self.get_image()
+ classes = classifier.classify_image(img.mat(), top_results=top_results)
+ except Exception:
+ logging.warning("classifier not available")
+ classes = [("None", 1.0)]
+ raise
+ logging.info("fps: %f", 1.0/(time.time()-t0))
+ return classes
+
+ def find_class(self):
+ return self.cnn_classify(top_results=1)[0][0]
+
+ def cnn_detect_objects(self, model_name=None, top_results=3):
+ classifier = None
+ if model_name:
+ classifier = self._cnn_classifiers.get(model_name)
+ if classifier is None:
+ classifier = CNNManager.get_instance().load_model(model_name)
+ self._cnn_classifiers[model_name] = classifier
+ else:
+ classifier = self._cnn_classifier_default
+
+ t0 = time.time()
+ classes = None
+ try:
+ img = self.get_image()
+ classes = classifier.detect_objects(img.mat(), top_results=top_results)
+ except Exception:
+ logging.warning("classifier not available")
+ classes = [("None", 100)]
+ raise
+ logging.info("fps: %f", 1.0/(time.time()-t0))
+ return classes
diff --git a/coderbot/cnn/__init__.py b/coderbot/cnn/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/coderbot/cnn/cnn_classifier.py b/coderbot/cnn/cnn_classifier.py
new file mode 100644
index 00000000..d8e61ce8
--- /dev/null
+++ b/coderbot/cnn/cnn_classifier.py
@@ -0,0 +1,143 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2017 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+"""
+This module implements the CNNClassifier class, which is the interface for
+using an existing and trained CNN model.
+"""
+import logging
+
+import numpy as np
+try:
+ from tensorflow.lite.python.interpreter import Interpreter
+except:
+ logging.warning("tensorflow not available (for inference)")
+try:
+ from tflite_runtime.interpreter import Interpreter
+except:
+ logging.warning("tflite not available")
+
+import cv2
+
+logger = logging.getLogger(__name__)
+
+class CNNClassifier(object):
+ def __init__(self, model_file, label_file):
+ logger.info(model_file)
+ self._interpreter = Interpreter(model_path=model_file, num_threads=4)
+ self._interpreter.allocate_tensors()
+ self._labels = self.load_labels(label_file)
+ self._input_details = self._interpreter.get_input_details()
+ self._output_details = self._interpreter.get_output_details()
+ self._input_height=self._input_details[0]['shape'][1]
+ self._input_width=self._input_details[0]['shape'][2]
+ self._floating_model = (self._input_details[0]['dtype'] == np.float32)
+
+ def close(self):
+ pass
+
+ def read_tensor_from_image_file(self, file_name):
+ image = cv2.imread(file_name)
+ return self.read_tensor_from_image_mat(image)
+
+ def read_tensor_from_image_mat(self, image_mat):
+ frame_rgb = cv2.cvtColor(image_mat, cv2.COLOR_BGR2RGB)
+ frame_resized = cv2.resize(frame_rgb, (self._input_width, self._input_height))
+ input_data = np.expand_dims(frame_resized, axis=0)
+
+ # Normalize pixel values if using a floating model (i.e. if model is non-quantized)
+ if self._floating_model:
+ input_mean = 127.5
+ input_std = 127.5
+ input_data = (np.float32(input_data) - input_mean) / input_std
+
+ return input_data
+
+ def load_labels(self, label_file):
+ labels = []
+ with open(label_file, 'r') as f:
+ labels = [line.strip() for line in f.readlines()]
+ return labels
+
+ def classify_image(self,
+ image_file_or_mat,
+ top_results=3):
+ input_image = None
+ if isinstance(image_file_or_mat, str):
+ input_image = self.read_tensor_from_image_file(file_name=image_file_or_mat)
+ else:
+ input_image = self.read_tensor_from_image_mat(image_file_or_mat)
+
+ self._interpreter.set_tensor(self._input_details[0]['index'], input_image)
+ self._interpreter.invoke()
+ scores = self._interpreter.get_tensor(self._output_details[0]['index'])[0]
+
+ #print("scores: " + str(scores))
+ confidence = 0.4
+ base = 1
+ # normalize to int8 for quantized models
+ if len(scores)>0 and (scores[0] == int(scores[0])):
+ confidence = 128
+ base = 256
+ pairs = []
+ for i in range(0, len(scores)):
+ if scores[i] > confidence:
+ object_name = self._labels[i]
+ pairs.append((object_name, int(100*scores[i]/base)))
+
+ pairs = sorted(pairs, key=lambda x: x[1], reverse=True)[:top_results]
+ return pairs
+
+ def detect_objects(self,
+ image_file_or_mat,
+ top_results=3):
+ input_image = None
+ if isinstance(image_file_or_mat, str):
+ input_image = self.read_tensor_from_image_file(file_name=image_file_or_mat)
+ else:
+ input_image = self.read_tensor_from_image_mat(image_file_or_mat)
+
+ self._interpreter.set_tensor(self._input_details[0]['index'], input_image)
+ self._interpreter.invoke()
+
+ # Retrieve detection results
+ boxes = self._interpreter.get_tensor(self._output_details[0]['index'])[0] # Bounding box coordinates of detected objects
+ classes = self._interpreter.get_tensor(self._output_details[1]['index'])[0] # Class index of detected objects
+ scores = self._interpreter.get_tensor(self._output_details[2]['index'])[0] # Confidence of detected objects
+
+ # Loop over all detections and draw detection box if confidence is above minimum threshold
+ min_conf_threshold=0.1
+ imH=100
+ imW=100
+ pairs = []
+ for i in range(len(scores)):
+ if ((scores[i] > min_conf_threshold) and (scores[i] <= 1.0)):
+
+ # Get bounding box coordinates and draw box
+ # Interpreter can return coordinates that are outside of image dimensions, need to force them to be within image using max() and min()
+ ymin = int(max(1,(boxes[i][0] * imH)))
+ xmin = int(max(1,(boxes[i][1] * imW)))
+ ymax = int(min(imH,(boxes[i][2] * imH)))
+ xmax = int(min(imW,(boxes[i][3] * imW)))
+
+ object_name = self._labels[int(classes[i])+1]
+ pairs.append((object_name, int(100*scores[i]), (xmin, ymin, xmax, ymax)))
+
+ pairs = sorted(pairs, key=lambda x: x[1], reverse=True)[:top_results]
+ logger.info(str(pairs))
+ return pairs
diff --git a/coderbot/cnn/cnn_manager.py b/coderbot/cnn/cnn_manager.py
new file mode 100644
index 00000000..5ed012d2
--- /dev/null
+++ b/coderbot/cnn/cnn_manager.py
@@ -0,0 +1,172 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2017 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+"""
+This module implements the class CNNManager, a singleton which exposes
+methods used to create (retrain), list and use existing CNN models.
+"""
+import os
+import shutil
+import logging
+import json
+import threading
+
+try:
+ from cnn.cnn_train import CNNTrainer
+except:
+ logging.warning("tensorflow not available (for training)")
+
+from cnn.cnn_classifier import CNNClassifier
+
+MODEL_PATH = "./cnn_models"
+MODEL_TMP_PATH = "/tmp/images"
+MODEL_METADATA = "./cnn_models/models.json"
+PHOTO_PATH = "./media"
+
+logger = logging.getLogger(__name__)
+
+class CNNManager(object):
+ instance = None
+
+ @classmethod
+ def get_instance(cls):
+ if cls.instance is None:
+ cls.instance = CNNManager()
+ return cls.instance
+
+
+ def __init__(self):
+ try:
+ f = open(MODEL_METADATA, "r")
+ self._models = json.load(f)
+ f.close()
+ except IOError:
+ self._models = {}
+ self._save_model_meta()
+
+ self._trainers = {}
+
+ def get_models(self):
+ return self._models
+
+ def get_model_status(self, model_name):
+ return self._models[model_name]
+
+ @classmethod
+ def get_model_info(cls, architecture):
+ model_info = architecture.split("/")[1].split("_")
+ return model_info
+
+ @classmethod
+ def get_model_shape(cls, architecture):
+ model_info = cls.get_model_info(architecture)
+ size = int(model_info[3])
+ return (size, size)
+
+ def _save_model_meta(self):
+ f = open(MODEL_METADATA, "w")
+ json.dump(self._models, f)
+ f.close()
+
+ def delete_model(self, model_name):
+ if self._models.get(model_name):
+ try:
+ os.remove(MODEL_PATH + "/" + model_name + ".tflite")
+ os.remove(MODEL_PATH + "/" + model_name + ".txt")
+ except Exception:
+ logging.warning("model files not found: %s", model_name)
+ del self._models[model_name]
+ self._save_model_meta()
+
+ def train_new_model(self,
+ model_name,
+ architecture,
+ image_tags,
+ photos_meta,
+ training_steps,
+ learning_rate):
+ try:
+ CNNManager
+ logging.info("starting")
+ trainer = self.TrainThread(self, model_name, architecture, image_tags, photos_meta, training_steps, learning_rate)
+ trainer.start()
+ self._trainers[model_name] = trainer
+ except NameError:
+ logging.warning("tensorflow not available (for training)")
+
+ def save_model_status(self, model_name, architecture, status):
+ model_info = self.get_model_info(architecture)
+ self._models[model_name] = {"status": status, "image_height": model_info[3], "image_width": model_info[3], "output_layer": "final_result"}
+ self._save_model_meta()
+
+ def wait_train_jobs(self):
+ for t in self._trainers:
+ t.join()
+
+ def load_model(self, model_name):
+ model_info = self._models.get(model_name)
+ if model_info:
+ return CNNClassifier(model_file=MODEL_PATH + "/" + model_name + ".tflite",
+ label_file=MODEL_PATH + "/" + model_name + ".txt")
+ return None
+
+ class TrainThread(threading.Thread):
+
+ def __init__(self, manager, model_name, architecture, image_tags, photos_metadata, training_steps, learning_rate):
+ super(CNNManager.TrainThread, self).__init__()
+ self.manager = manager
+ self.model_name = model_name
+ self.architecture = architecture
+ self.image_tags = image_tags
+ self.photos_metadata = photos_metadata
+ self.learning_rate = learning_rate
+ self.training_steps = training_steps
+ self.trainer = None
+
+ def update_train_status(self, model_name, status):
+ model = self.manager._models.get(model_name)
+ model["status"] = status
+
+ def run(self):
+ self.trainer = CNNTrainer(self.manager, self.architecture, CNNManager.get_model_shape(self.architecture))
+ self.manager.save_model_status(self.model_name, self.architecture, 0)
+ image_dir = self.prepare_images()
+ logging.info("retrain")
+ self.trainer.retrain(image_dir, MODEL_PATH + "/" + self.model_name, self.training_steps, self.learning_rate, flip_left_right=False, random_crop=0, random_scale=0)
+ self.manager.save_model_status(self.model_name, self.architecture, 1)
+ self.clear_filesystem()
+ logging.info("finish")
+
+ def prepare_images(self):
+ logging.info("prepare_images")
+ photo_abs_path = os.path.abspath(PHOTO_PATH)
+ model_image_path = MODEL_TMP_PATH + "/" + self.model_name
+ os.makedirs(model_image_path)
+ for t in self.image_tags:
+ tag_path = model_image_path + "/" + t
+ os.makedirs(tag_path)
+ for p in self.photos_metadata:
+ if p.get("tag", "---") == t:
+ os.symlink(photo_abs_path + "/" + p["name"], tag_path + "/" + p["name"])
+
+ return model_image_path
+
+ def clear_filesystem(self):
+ shutil.rmtree(MODEL_TMP_PATH + "/" + self.model_name)
+ #shutil.rmtree(MODEL_TMP_PATH + "/bottleneck")
+ #shutil.rmtree(MODEL_TMP_PATH + "/retrain_logs")
diff --git a/coderbot/cnn/cnn_train.py b/coderbot/cnn/cnn_train.py
new file mode 100644
index 00000000..e3105686
--- /dev/null
+++ b/coderbot/cnn/cnn_train.py
@@ -0,0 +1,142 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2017 Roberto Previtera
+# The code contained in this file is mostly derived from TensorFlow
+# "retrain.py" exmple from main tensorflow repository.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+"""Simple transfer learning with Inception v3 or Mobilenet models.
+
+With support for TensorBoard.
+
+This example shows how to take a Inception v3 or Mobilenet model trained on
+ImageNet images, and train a new top layer that can recognize other classes of
+images.
+
+The top layer receives as input a 2048-dimensional vector (1001-dimensional for
+Mobilenet) for each image. We train a softmax layer on top of this
+representation. Assuming the softmax layer contains N labels, this corresponds
+to learning N + 2048*N (or 1001*N) model parameters corresponding to the
+learned biases and weights.
+
+Here's an example, which assumes you have a folder containing class-named
+subfolders, each full of images for each label. The example folder flower_photos
+should have a structure like this:
+
+~/flower_photos/daisy/photo1.jpg
+~/flower_photos/daisy/photo2.jpg
+...
+~/flower_photos/rose/anotherphoto77.jpg
+...
+~/flower_photos/sunflower/somepicture.jpg
+"""
+
+import time
+import tempfile
+import numpy as np
+import tensorflow as tf
+import tensorflow_hub as hub
+from tensorflow_hub.tools.make_image_classifier import make_image_classifier_lib as lib
+
+class CNNTrainer(object):
+ # pylint: disable=too-many-instance-attributes
+ # pylint: disable=too-many-locals
+ # pylint: disable=too-many-arguments
+ # pylint: disable=too-many-boolean-expressions
+
+ def __init__(self, manager, architecture, shape):
+ self.manager = manager
+ self.architecture = architecture
+ self.shape = shape
+
+ def retrain(self,
+ image_dir,
+ output_graph,
+ training_steps,
+ learning_rate,
+ desired_training_accuracy=100.0,
+ desired_validation_accuracy=100.0,
+ flip_left_right=True,
+ random_crop=30,
+ random_scale=30,
+ random_brightness=30):
+
+ _check_keras_dependencies()
+ hparams = _get_hparams(train_epochs=training_steps,
+ learning_rate=learning_rate)
+
+ image_size=self.shape[0]
+ tfhub_module="https://tfhub.dev/google/"+self.architecture
+ model, labels, train_result = lib.make_image_classifier(
+ tfhub_module, image_dir, hparams, image_size)
+ print("Done with training.")
+
+ labels_output_file=output_graph+".txt"
+ with tf.io.gfile.GFile(labels_output_file, "w") as f:
+ f.write("\n".join(labels + ("",)))
+ print("Labels written to", labels_output_file)
+
+ saved_model_dir = tempfile.mkdtemp()
+ tf.saved_model.save(model, saved_model_dir)
+ print("SavedModel model exported to", saved_model_dir)
+
+ tflite_output_file = output_graph+".tflite"
+ converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
+ converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_LATENCY]
+ lite_model_content = converter.convert()
+ with tf.io.gfile.GFile(tflite_output_file, "wb") as f:
+ f.write(lite_model_content)
+ print("TFLite model exported to", tflite_output_file)
+
+
+def _get_hparams(train_epochs=1, learning_rate=0.005):
+ "Creates dict of hyperparameters from flags."""
+ return lib.HParams(
+ train_epochs=train_epochs,
+ do_fine_tuning=False,
+ batch_size=2,
+ learning_rate=learning_rate,
+ momentum=0.9)
+
+def _check_keras_dependencies():
+ """Checks dependencies of tf.keras.preprocessing.image are present.
+ This function may come to depend on flag values that determine the kind
+ of preprocessing being done.
+ Raises:
+ ImportError: If dependencies are missing.
+ """
+ try:
+ tf.keras.preprocessing.image.load_img(six.BytesIO())
+ except ImportError:
+ print("\n*** Unsatisfied dependencies of keras_preprocessing.image. ***\n"
+ "To install them, use your system's equivalent of\n"
+ "pip install tensorflow_hub[make_image_classifier]\n")
+ raise
+ except Exception as e: # pylint: disable=broad-except
+ # Loading from dummy content as above is expected to fail in other ways.
+ pass
+
+
+def _assert_accuracy(train_result, assert_accuracy_at_least):
+ # Fun fact: With TF1 behavior, the key was called "val_acc".
+ val_accuracy = train_result.history["val_accuracy"][-1]
+ accuracy_message = "found {:f}, expected at least {:f}".format(
+ val_accuracy, assert_accuracy_at_least)
+ if val_accuracy >= assert_accuracy_at_least:
+ print("ACCURACY PASSED:", accuracy_message)
+ else:
+ raise AssertionError("ACCURACY FAILED:", accuracy_message)
+
diff --git a/coderbot/coderbot.py b/coderbot/coderbot.py
new file mode 100644
index 00000000..89c0de1c
--- /dev/null
+++ b/coderbot/coderbot.py
@@ -0,0 +1,277 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+import os
+import sys
+import time
+from math import copysign
+import logging
+import pigpio
+import sonar
+from hw import mpu
+from rotary_encoder.wheelsaxel import WheelsAxel
+
+# GPIO
+class GPIO_CODERBOT_V_4():
+ # motors
+ PIN_MOTOR_ENABLE = 22
+ PIN_LEFT_FORWARD = 25
+ PIN_LEFT_BACKWARD = 24
+ PIN_RIGHT_FORWARD = 4
+ PIN_RIGHT_BACKWARD = 17
+
+ PIN_PUSHBUTTON = 11
+ # servo
+ PIN_SERVO_1 = 9
+ PIN_SERVO_2 = 10
+ # sonar
+ PIN_SONAR_1_TRIGGER = 18
+ PIN_SONAR_1_ECHO = 7
+ PIN_SONAR_2_TRIGGER = 18
+ PIN_SONAR_2_ECHO = 8
+ PIN_SONAR_3_TRIGGER = 18
+ PIN_SONAR_3_ECHO = 23
+ PIN_SONAR_4_TRIGGER = 18
+ PIN_SONAR_4_ECHO = 13
+
+ # encoder
+ PIN_ENCODER_LEFT_A = 14
+ PIN_ENCODER_LEFT_B = 6
+ PIN_ENCODER_RIGHT_A = 15
+ PIN_ENCODER_RIGHT_B = 12
+
+ HAS_ENCODER = False
+
+class GPIO_CODERBOT_V_5():
+ # motors
+ PIN_MOTOR_ENABLE = None #22
+ PIN_LEFT_FORWARD = 17 #25
+ PIN_LEFT_BACKWARD = 18 # 24
+ PIN_RIGHT_FORWARD = 22 # 4
+ PIN_RIGHT_BACKWARD = 23 #17
+
+ PIN_PUSHBUTTON = 16 #11
+ # servo
+ PIN_SERVO_1 = 19 #9
+ PIN_SERVO_2 = 26 #10
+ # sonar
+ PIN_SONAR_1_TRIGGER = 5 #18
+ PIN_SONAR_1_ECHO = 27 #7
+ PIN_SONAR_2_TRIGGER = 5 #18
+ PIN_SONAR_2_ECHO = 6 #8
+ PIN_SONAR_3_TRIGGER = 5 #18
+ PIN_SONAR_3_ECHO = 12 #23
+ PIN_SONAR_4_TRIGGER = 5 #18
+ PIN_SONAR_4_ECHO = 13 #23
+
+ # encoder
+ PIN_ENCODER_LEFT_A = 14
+ PIN_ENCODER_LEFT_B = 15 #6
+ PIN_ENCODER_RIGHT_A = 24 #15
+ PIN_ENCODER_RIGHT_B = 25 #12
+
+ HAS_ENCODER = True
+
+# PWM
+PWM_FREQUENCY = 100 #Hz
+PWM_RANGE = 100 #0-100
+
+HW_VERSIONS = {
+ "4": GPIO_CODERBOT_V_4(),
+ "5": GPIO_CODERBOT_V_5()
+}
+
+class CoderBot(object):
+
+ # pylint: disable=too-many-instance-attributes
+
+ def __init__(self, motor_trim_factor=1.0, motor_min_power=0, motor_max_power=100, hw_version="5", pid_params=(0.8, 0.1, 0.01, 200, 0.01)):
+ try:
+ self._mpu = mpu.AccelGyroMag()
+ logging.info("MPU available")
+ except:
+ logging.info("MPU not available")
+
+ self.GPIOS = HW_VERSIONS.get(hw_version, GPIO_CODERBOT_V_5())
+ self._pin_out = [self.GPIOS.PIN_LEFT_FORWARD, self.GPIOS.PIN_RIGHT_FORWARD, self.GPIOS.PIN_LEFT_BACKWARD, self.GPIOS.PIN_RIGHT_BACKWARD, self.GPIOS.PIN_SERVO_1, self.GPIOS.PIN_SERVO_2]
+ self.pi = pigpio.pi('localhost')
+ self.pi.set_mode(self.GPIOS.PIN_PUSHBUTTON, pigpio.INPUT)
+ self._cb = dict()
+ self._cb_last_tick = dict()
+ self._cb_elapse = dict()
+ self._encoder = self.GPIOS.HAS_ENCODER
+ self._motor_trim_factor = motor_trim_factor
+ self._motor_min_power = motor_min_power
+ self._motor_max_power = motor_max_power
+ self._twin_motors_enc = WheelsAxel(
+ self.pi,
+ enable_pin=self.GPIOS.PIN_MOTOR_ENABLE,
+ left_forward_pin=self.GPIOS.PIN_LEFT_FORWARD,
+ left_backward_pin=self.GPIOS.PIN_LEFT_BACKWARD,
+ left_encoder_feedback_pin_A=self.GPIOS.PIN_ENCODER_LEFT_A,
+ left_encoder_feedback_pin_B=self.GPIOS.PIN_ENCODER_LEFT_B,
+ right_forward_pin=self.GPIOS.PIN_RIGHT_FORWARD,
+ right_backward_pin=self.GPIOS.PIN_RIGHT_BACKWARD,
+ right_encoder_feedback_pin_A=self.GPIOS.PIN_ENCODER_RIGHT_A,
+ right_encoder_feedback_pin_B=self.GPIOS.PIN_ENCODER_RIGHT_B,
+ pid_params=pid_params)
+ self.motor_control = self._dc_enc_motor
+
+ self._cb1 = self.pi.callback(self.GPIOS.PIN_PUSHBUTTON, pigpio.EITHER_EDGE, self._cb_button)
+
+ for pin in self._pin_out:
+ self.pi.set_PWM_frequency(pin, PWM_FREQUENCY)
+ self.pi.set_PWM_range(pin, PWM_RANGE)
+
+ self.sonar = [sonar.Sonar(self.pi, self.GPIOS.PIN_SONAR_1_TRIGGER, self.GPIOS.PIN_SONAR_1_ECHO),
+ sonar.Sonar(self.pi, self.GPIOS.PIN_SONAR_2_TRIGGER, self.GPIOS.PIN_SONAR_2_ECHO),
+ sonar.Sonar(self.pi, self.GPIOS.PIN_SONAR_3_TRIGGER, self.GPIOS.PIN_SONAR_3_ECHO),
+ sonar.Sonar(self.pi, self.GPIOS.PIN_SONAR_4_TRIGGER, self.GPIOS.PIN_SONAR_4_ECHO)]
+ self._servos = [self.GPIOS.PIN_SERVO_1, self.GPIOS.PIN_SERVO_2]
+
+ self.stop()
+
+ the_bot = None
+
+ def exit(self):
+ self._cb1.cancel()
+ if self._encoder:
+ self._twin_motors_enc.cancel_callback()
+ for s in self.sonar:
+ s.cancel()
+
+ @classmethod
+ def get_instance(cls, motor_trim_factor=1.0, motor_max_power=100, motor_min_power=0, hw_version="5", pid_params=(0.8, 0.1, 0.01, 200, 0.01), from_defaults=True):
+ if not cls.the_bot:
+ if from_defaults:
+ raise ValueError("incorrect CoderBot initialisation")
+ cls.the_bot = CoderBot(motor_trim_factor=motor_trim_factor, motor_max_power= motor_max_power, motor_min_power=motor_min_power, hw_version=hw_version, pid_params=pid_params)
+ return cls.the_bot
+
+ def get_motor_power(self, speed):
+ return int(copysign(min(max(((self._motor_max_power - self._motor_min_power) * abs(speed) / 100) + self._motor_min_power, self._motor_min_power), self._motor_max_power), speed))
+
+ def move(self, speed=100, elapse=None, distance=None):
+ speed_left = speed * self._motor_trim_factor
+ speed_right = speed / self._motor_trim_factor
+ self.motor_control(speed_left=speed_left, speed_right=speed_right, time_elapse=elapse, target_distance=distance)
+
+ def turn(self, speed=100, elapse=None, distance=None):
+ speed_left = speed * self._motor_trim_factor
+ speed_right = -speed / self._motor_trim_factor
+ self.motor_control(speed_left=speed_left, speed_right=speed_right, time_elapse=elapse, target_distance=distance)
+
+ def turn_angle(self, speed=100, angle=0):
+ z = self._mpu.get_gyro()[2]
+ self.turn(speed, elapse=0)
+ while abs(z - self._mpu.get_gyro()[2]) < angle:
+ time.sleep(0.05)
+ logging.info(self._mpu.get_gyro()[2])
+ self.stop()
+
+ def forward(self, speed=100, elapse=None, distance=None):
+ self.move(speed=speed, elapse=elapse, distance=distance)
+
+ def backward(self, speed=100, elapse=None, distance=None):
+ self.move(speed=-speed, elapse=elapse, distance=distance)
+
+ def left(self, speed=100, elapse=-1):
+ self.turn(speed=-speed, elapse=elapse)
+
+ def right(self, speed=100, elapse=-1):
+ self.turn(speed=speed, elapse=elapse)
+
+ def servo(self, servo, angle):
+ self._servo_control(self._servos[servo], angle)
+
+ def get_sonar_distance(self, sonar_id=0):
+ return self.sonar[sonar_id].get_distance()
+
+ def get_mpu_accel(self, axis=None):
+ acc = self._mpu.get_acc()
+ if axis is None:
+ return acc
+ else:
+ return int(acc[axis]*100.0)/100.0
+
+ def get_mpu_gyro(self, axis=None):
+ gyro = self._mpu.get_gyro()
+ if axis is None:
+ return gyro
+ else:
+ return int(gyro[axis]*100.0)/200.0
+
+ def get_mpu_heading(self):
+ hdg = self._mpu.get_hdg()
+ return int(hdg)
+
+ def get_mpu_temp(self):
+ temp = self._mpu.get_temp()
+ return int(temp*100.0)/100.0
+
+ def _servo_control(self, pin, angle):
+ duty = ((angle + 90) * 100 / 180) + 25
+
+ self.pi.set_PWM_range(pin, 1000)
+ self.pi.set_PWM_frequency(pin, 50)
+ self.pi.set_PWM_dutycycle(pin, duty)
+
+ def _dc_enc_motor(self, speed_left=100, speed_right=100, time_elapse=None, target_distance=None):
+ self._twin_motors_enc.control(power_left=self.get_motor_power(speed_left),
+ power_right=self.get_motor_power(speed_right),
+ time_elapse=time_elapse,
+ target_distance=target_distance)
+
+ def stop(self):
+ self._twin_motors_enc.stop()
+
+ def is_moving(self):
+ return self._twin_motors_enc._is_moving
+
+ # Distance travelled getter
+ def distance(self):
+ return self._twin_motors_enc.distance()
+
+ # CoderBot velocity getter
+ def speed(self):
+ return self._twin_motors_enc.speed()
+
+ # CoderBot direction getter
+ def direction(self):
+ return self._twin_motors_enc.speed()
+
+ def set_callback(self, gpio, callback, elapse):
+ self._cb_elapse[gpio] = elapse * 1000
+ self._cb[gpio] = callback
+ self._cb_last_tick[gpio] = 0
+
+ def sleep(self, elapse):
+ logging.debug("sleep: %s", str(elapse))
+ time.sleep(elapse)
+
+ def _cb_button(self, gpio, level, tick):
+ cb = self._cb.get(gpio)
+ if cb:
+ elapse = self._cb_elapse.get(gpio)
+ if level == 0:
+ self._cb_last_tick[gpio] = tick
+ elif tick - self._cb_last_tick[gpio] > elapse:
+ self._cb_last_tick[gpio] = tick
+ logging.info("pushed: %d, %d", level, tick)
+ cb()
\ No newline at end of file
diff --git a/coderbot/config.py b/coderbot/config.py
new file mode 100644
index 00000000..071dd7da
--- /dev/null
+++ b/coderbot/config.py
@@ -0,0 +1,54 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+import os
+import json
+
+CONFIG_FILE = "data/config.json"
+CONFIG_DEFAULT_FILE = "defaults/config.json"
+
+class Config(object):
+
+ _config = {}
+
+ @classmethod
+ def get(cls):
+ return cls._config
+
+ @classmethod
+ def read(cls):
+ if not os.path.exists(CONFIG_FILE):
+ cls.restore()
+ with open(CONFIG_FILE, 'r') as f:
+ cls._config = json.load(f)
+ f.close()
+ return cls._config
+
+ @classmethod
+ def write(cls, config):
+ cls._config = config
+ f = open(CONFIG_FILE, 'w')
+ json.dump(cls._config, f)
+ return cls._config
+
+ @classmethod
+ def restore(cls):
+ with open(CONFIG_DEFAULT_FILE) as f:
+ cls.write(json.loads(f.read()))
+
diff --git a/coderbot/cv/__init__.py b/coderbot/cv/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/coderbot/cv/blob.py b/coderbot/cv/blob.py
new file mode 100644
index 00000000..c45a2d40
--- /dev/null
+++ b/coderbot/cv/blob.py
@@ -0,0 +1,58 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+import cv2
+
+class Blob():
+
+ def __init__(self, contour):
+ self._contour = contour
+
+ @property
+ def bottom(self):
+ return self._contour[self._contour[:, :, 1].argmax()][0][1]
+
+ @property
+ def top(self):
+ return self._contour[self._contour[:, :, 1].argmin()][0][1]
+
+ @property
+ def left(self):
+ return self._contour[self._contour[:, :, 0].argmin()][0][0]
+
+ @property
+ def right(self):
+ return self._contour[self._contour[:, :, 0].argmax()][0][0]
+
+ @property
+ def center(self):
+ return ((self.right + self.left) / 2, (self.top + self.bottom) / 2)
+
+ def area(self):
+ return cv2.contourArea(self._contour)
+
+ def minAreaRect(self):
+ return cv2.minAreaRect(self._contour)
+
+ def contour(self):
+ return self._contour
+
+ @classmethod
+ def sort_distance(cls, point, blobs):
+ return sorted(blobs, key=lambda blob: (point[0] - blob.bottom))
diff --git a/coderbot/cv/camera.py b/coderbot/cv/camera.py
new file mode 100644
index 00000000..f2b1b68f
--- /dev/null
+++ b/coderbot/cv/camera.py
@@ -0,0 +1,129 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2017 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+"""
+The Camera module implements the Camera class, which is the abstraction
+from the lower lever PiCamera (RPI specific)
+"""
+import io
+import os
+import logging
+from threading import Condition
+import numpy as np
+import picamera
+
+class Camera(object):
+
+ FFMPEG_CMD = 'ffmpeg'
+ PHOTO_FILE_EXT = ".jpg"
+ VIDEO_FILE_EXT = ".mp4"
+ VIDEO_FILE_EXT_H264 = '.h264'
+
+ class StreamingOutputMJPEG(object):
+ def __init__(self):
+ self.frame = None
+ self.buffer = io.BytesIO()
+ self.condition = Condition()
+
+ def write(self, buf):
+ if buf.startswith(b'\xff\xd8'):
+ # New frame, copy the existing buffer's content and notify all
+ # clients it's available
+ self.buffer.truncate()
+ with self.condition:
+ self.frame = self.buffer.getvalue()
+ self.condition.notify_all()
+ self.buffer.seek(0)
+ return self.buffer.write(buf)
+
+ class StreamingOutputBGR(object):
+ def __init__(self, resolution):
+ self.frame = None
+ self.condition = Condition()
+ self.resolution = resolution
+ self.count = 0
+
+ def write(self, buf):
+ with self.condition:
+ frame = np.frombuffer(buf, dtype=np.uint8)
+ self.frame = frame.reshape(self.resolution[1], self.resolution[0], 4)
+ self.frame = np.delete(self.frame, 3, 2)
+ self.condition.notify_all()
+ return len(buf)
+
+ def __init__(self, props):
+ logging.info("camera init")
+ self.camera = picamera.PiCamera()
+ self.camera.resolution = (props.get('width', 640), props.get('height', 512))
+ self.out_rgb_resolution = (int(self.camera.resolution[0] / int(props.get('cv_image_factor', 4))), int(self.camera.resolution[1] / int(props.get('cv_image_factor', 4))))
+ self.camera.framerate = float(props.get('framerate', 20))
+ self.camera.exposure_mode = props.get('exposure_mode', "auto")
+ self.output_mjpeg = self.StreamingOutputMJPEG()
+ self.output_bgr = self.StreamingOutputBGR(self.out_rgb_resolution)
+ self.h264_encoder = None
+ self.recording = None
+ self.video_filename = None
+ self._jpeg_quality = props.get('jpeg_quality', 20)
+ self._jpeg_bitrate = props.get('jpeg_bitrate', 5000000)
+
+ def video_rec(self, filename):
+ self.video_filename = filename[:filename.rfind(".")]
+ self.camera.start_recording(self.video_filename + self.VIDEO_FILE_EXT_H264, format="h264", quality=23, splitter_port=2)
+
+ def video_stop(self):
+ logging.debug("video_stop")
+ self.camera.stop_recording(2)
+
+ # pack in mp4 container
+ params = " -loglevel quiet -stats -framerate " + str(self.camera.framerate) + \
+ " -i " + self.video_filename + self.VIDEO_FILE_EXT_H264 + \
+ " -c copy " + self.video_filename + self.VIDEO_FILE_EXT
+
+ os.system(self.FFMPEG_CMD + params)
+ # remove h264 file
+ os.remove(self.video_filename + self.VIDEO_FILE_EXT_H264)
+
+ def grab_start(self):
+ logging.debug("grab_start")
+ self.camera.start_recording(self.output_mjpeg, format="mjpeg", splitter_port=0, bitrate=self._jpeg_bitrate)
+ self.camera.start_recording(self.output_bgr, format="bgra", splitter_port=1, resize=self.out_rgb_resolution)
+
+ def grab_stop(self):
+ logging.debug("grab_stop")
+
+ self.camera.stop_recording(0)
+ self.camera.stop_recording(1)
+
+ def get_image_jpeg(self):
+ with self.output_mjpeg.condition:
+ self.output_mjpeg.condition.wait()
+ return self.output_mjpeg.frame
+
+ def get_image_bgr(self):
+ with self.output_bgr.condition:
+ self.output_bgr.condition.wait()
+ return self.output_bgr.frame
+
+ def set_overlay_text(self, text):
+ try:
+ self.camera.annotate_text = text
+ except picamera.PiCameraValueError:
+ logging.info("PiCameraValueError")
+
+ def close(self):
+ self.camera.close()
diff --git a/coderbot/cv/image.py b/coderbot/cv/image.py
new file mode 100644
index 00000000..3c602379
--- /dev/null
+++ b/coderbot/cv/image.py
@@ -0,0 +1,281 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+import logging
+import colorsys
+import numpy as np
+import cv2
+import cv2.aruco
+import cv.blob as blob
+import pytesseract
+
+MIN_MATCH_COUNT = 10
+
+try:
+ from pyzbar.pyzbar import decode
+except:
+ logging.info("zbar not availabe")
+
+class Image():
+ r_from = np.float32([[0, 0], [640, 0], [640, 480], [0, 480]])
+ r_dest = np.float32([[0, -120], [640, -120], [380, 480], [260, 480]])
+
+ _aruco_dict = cv2.aruco.Dictionary_get(cv2.aruco.DICT_ARUCO_ORIGINAL)
+ _aruco_parameters = cv2.aruco.DetectorParameters_create()
+
+ _face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
+
+ def __init__(self, array):
+ self._data = array
+ img_size_y = self._data.shape[0]
+ kernel_size = int(img_size_y / 40)
+ self._kernel = np.ones((kernel_size, kernel_size), np.uint8)
+
+ def size(self):
+ return self._data.shape
+
+ def mat(self):
+ return self._data
+
+ @classmethod
+ def load(cls, filename):
+ return Image(cv2.imread(filename))
+
+ def resize(self, width, heigth):
+ return Image(cv2.resize(self._data, (width, heigth)))
+
+ def crop(self, x1, y1, x2, y2):
+ return Image(self._data[y1:y2, x1:x2])
+
+ def warp(self, r_from, r_dest):
+ tx = cv2.getPerspectiveTransform(r_from, r_dest)
+ dest = cv2.warpPerspective(self._data, tx, (640, 480))
+ return Image(dest)
+
+ @classmethod
+ def transform(cls, vector, tx):
+ v = np.array(vector, dtype='float32')
+ v = np.array([v])
+ dest = cv2.perspectiveTransform(v, tx)
+ return dest[0]
+
+ @classmethod
+ def get_transform(cls, image_size_x):
+ k = 640 / image_size_x
+ rfrom = cls.r_from / k
+ rdest = cls.r_dest / k
+ tx = cv2.getPerspectiveTransform(rfrom, rdest)
+ return tx
+
+ def find_faces(self):
+ faces = self._face_cascade.detectMultiScale(self._data)
+ return faces
+
+ def filter_color(self, color):
+ h, s, v = colorsys.rgb_to_hsv(color[0]/255.0, color[1]/255.0, color[2]/255.0)
+ image_hsv = cv2.cvtColor(self._data, cv2.COLOR_BGR2HSV)
+ h = h * 180
+ s = s * 255
+ v = v * 255
+ logging.debug("color_hsv: " + str(h) + " " + str(s) + " " + str(v))
+ #lower_color = np.array([h-10 if h>=10 else 0.0, 0, 0])
+ #upper_color = np.array([h+10 if h<=170 else 179.0, 255, 255])
+ lower_color = np.array([h-5, 50, 50])
+ upper_color = np.array([h+5, 255, 255])
+ logging.debug("lower: " + str(lower_color) + " upper: " + str(upper_color))
+ mask = cv2.inRange(image_hsv, lower_color, upper_color)
+ return Image(mask)
+
+ def dilate(self):
+ data = cv2.dilate(self._data, self._kernel)
+ return Image(data)
+
+ def erode(self):
+ data = cv2.erode(self._data, self._kernel)
+ return Image(data)
+
+ def open(self):
+ data = cv2.morphologyEx(self._data, cv2.MORPH_OPEN, self._kernel)
+ return Image(data)
+
+ def close(self):
+ data = cv2.morphologyEx(self._data, cv2.MORPH_CLOSE, self._kernel)
+ return Image(data)
+
+ def grayscale(self):
+ data = cv2.cvtColor(self._data, cv2.COLOR_BGR2GRAY)
+ return Image(data)
+
+ def blackwhite(self):
+ data = cv2.threshold(self._data, 128, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
+ return Image(data)
+
+ def invert(self):
+ data = cv2.bitwise_not(self._data)
+ return Image(data)
+
+ def binarize(self, threshold=-1):
+ data = cv2.cvtColor(self._data, cv2.COLOR_BGR2GRAY)
+ if threshold < 0:
+ data = cv2.adaptiveThreshold(data, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, max((self._kernel.shape[0]/2*2)+1, 3), 3)
+ else:
+ ret, data = cv2.threshold(data, threshold, 255, cv2.THRESH_BINARY_INV)
+ return Image(data)
+
+ def get_average(self):
+ data = cv2.cvtColor(self._data, cv2.COLOR_BGR2HSV)
+ logging.info("shape: " + str(data.shape))
+ h = np.average(data[:, :, 0])
+ s = np.average(data[:, :, 1])
+ v = np.average(data[:, :, 2])
+ return [h, s, v]
+
+ def find_blobs(self, minsize=0, maxsize=10000000):
+ blobs = []
+ image = contours = hyerarchy = None
+ contours, hyerarchy = cv2.findContours(self._data, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
+
+ for c in contours:
+ area = cv2.contourArea(c)
+ if area > minsize and area < maxsize:
+ if len(blobs) and area > blobs[0].area():
+ blobs.insert(0, blob.Blob(c))
+ else:
+ blobs.append(blob.Blob(c))
+
+ return blobs
+
+ def find_template(self, img_template):
+ # Initiate SIFT detector
+ sift = cv2.SIFT()
+
+ # find the keypoints and descriptors with SIFT
+ kp1, des1 = sift.detectAndCompute(img_template._data, None)
+ kp2, des2 = sift.detectAndCompute(self._data, None)
+
+ FLANN_INDEX_KDTREE = 0
+ index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
+ search_params = dict(checks=50)
+
+ flann = cv2.FlannBasedMatcher(index_params, search_params)
+
+ matches = flann.knnMatch(des1, des2, k=2)
+
+ # store all the good matches as per Lowe's ratio test.
+ good = []
+ templates = []
+ for m, n in matches:
+ if m.distance < 0.7 * n.distance:
+ good.append(m)
+
+ if len(good) > MIN_MATCH_COUNT:
+ src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
+ dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
+
+ M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
+ matchesMask = mask.ravel().tolist()
+
+ h, w = img_template.shape
+ pts = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)
+ dst = cv2.perspectiveTransform(pts, M)
+ logging.info("found template: %s", dst)
+ templates[0] = dst
+
+ else:
+ logging.info("Not enough matches are found - %d/%d", len(good), MIN_MATCH_COUNT)
+ matchesMask = None
+
+ return templates
+
+ def find_rect(self, color):
+ rect_image = None
+ filtered_image = self.filter_color(color)
+ blobs = filtered_image.find_blobs(minsize=1000)
+ image_size = self.size()
+ logging.info("blobs: " + str(blobs))
+ if len(blobs):
+ blob = blobs[0]
+ b_area = blob.area()
+ for b in blobs:
+ if b.area() > b_area:
+ blob = b
+ b_area = blob.area()
+ rect = blob.minAreaRect()
+ center = rect[0]
+ size = rect[1]
+ angle = rect[2]
+ if size[0] < size[1]:
+ angle = angle + 90
+ size = (size[1], size[0])
+
+ rot_matrix = cv2.getRotationMatrix2D(center, angle, 1)
+ logging.info("center: " + str(center) + " size: " + str(size) + " angle: " + str(angle))
+ rect_image = Image(cv2.warpAffine(self._data, rot_matrix, (image_size[1], image_size[0])))
+ border = 5
+ rect_image = rect_image.crop(int(max(0, border+center[0]-(size[0])/2)),
+ int(max(0, border+center[1]-(size[1]+5)/2)),
+ int(min(image_size[1], -border+center[0]+(size[0])/2)),
+ int(min(image_size[0], -border+center[1]+(size[1]-5)/2)))
+ return rect_image
+
+ def find_text(self, lang, timeout):
+ text = '?'
+ try:
+ text = pytesseract.image_to_string(self._data, lang, timeout)
+ except RuntimeError as e:
+ pass
+ return text
+
+ def find_qr_code(self):
+ text_found = None
+ img_size = self._data.shape
+ gray = cv2.cvtColor(self._data, cv2.COLOR_BGR2GRAY)
+ image_code = decode(gray)
+ for symbol in image_code:
+ text_found = symbol.data.decode("utf-8")
+ break
+ return text_found
+
+ def find_ar_code(self):
+ gray = cv2.cvtColor(self._data, cv2.COLOR_BGR2GRAY)
+ corners, ids, rejectedImgPoints = cv2.aruco.detectMarkers(gray, self._aruco_dict, parameters=self._aruco_parameters)
+ codes = []
+ positions = []
+ if ids is not None:
+ for i in range(0, len(ids)):
+ if ids[i][0] != 1023:
+ codes.append(ids[i][0])
+ rect = corners[i][0]
+ positions.append([(rect[0][0]+rect[1][0]+rect[2][0]+rect[3][0])/4,
+ (rect[0][1]+rect[1][1]+rect[2][1]+rect[3][1])/4])
+ return {"codes": codes, "positions": positions}
+
+ def draw_blob(self, blob):
+ cv2.drawContours(self._data, blob.contour(), -1, (0, 255, 0))
+
+ def draw_rect(self, x1, y1, x2, y2, color, thickness):
+ cv2.rectangle(self._data, (x1, y1), (x2, y2), color, thickness)
+
+ def to_jpeg(self):
+ ret, jpeg_array = cv2.imencode('.jpeg', self._data)
+ return np.array(jpeg_array).tostring()
+
+ def to_rgb(self):
+ rgb_img = cv2.cvtColor(self._data, cv2.COLOR_BGR2RGB)
+ return rgb_img
diff --git a/coderbot/event.py b/coderbot/event.py
new file mode 100644
index 00000000..2ca0bedd
--- /dev/null
+++ b/coderbot/event.py
@@ -0,0 +1,48 @@
+import threading
+from event_channel.threaded_event_channel import ThreadedEventChannel
+
+class EventManager(object):
+ _instance = None
+ @classmethod
+ def get_instance(cls, node_name=None):
+ if cls._instance is None and node_name is not None:
+ cls._instance = EventManager(node_name)
+ return cls._instance
+
+ def __init__(self, node_name):
+ self._channel = ThreadedEventChannel(blocking=False)
+ self._publisher_threads = None
+ self._subscribers = []
+ self._node_name = node_name
+ self._event_generators = []
+
+ def publish(self, topic, msg):
+ self._publisher_threads = self._channel.publish(topic, msg)
+
+ def register_event_listener(self, topic, callback):
+ self._channel.subscribe(topic, callback)
+ self._subscribers.append((topic, callback))
+
+ def register_event_generator(self, generator_func):
+ generator = threading.Thread(target=generator_func)
+ self._event_generators.append(generator)
+ generator.start()
+
+ def unregister_listeners(self):
+ for l in self._subscribers:
+ self._channel.unsubscribe(l[0], l[1])
+ self._subscribers = []
+
+ def unregister_publishers(self):
+ if self._publisher_threads:
+ for t in self._publisher_threads:
+ t.join()
+
+ def start_event_generators(self):
+ for g in self._event_generators:
+ g.start()
+
+ def wait_event_generators(self):
+ for g in self._event_generators:
+ g.join()
+ self._event_generators = []
diff --git a/coderbot/hw/__init__.py b/coderbot/hw/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/coderbot/hw/atmega328p.py b/coderbot/hw/atmega328p.py
new file mode 100644
index 00000000..76c3965b
--- /dev/null
+++ b/coderbot/hw/atmega328p.py
@@ -0,0 +1,84 @@
+# RPi PINOUTS
+# MOSI -> GPIO10
+# MISO -> GPIO9
+# SCK -> GPIO11
+# CE1 -> GPIO7
+# CE1 -> GPIO8
+
+# get the GPIO Library and SPI Library
+import spidev
+import time
+
+BAUDRATE_MAX = 250000
+BAUDRATE = 10000
+
+START = 0xff
+CMD_RESET = 0x00
+CMD_SET_DATA = 0x01
+CMD_GET_DATA = 0x02
+CMD_SET_MODE = 0x03
+CMD_SET_LED = 0x04
+
+ADDR_AI_FIRST = 0x00
+ADDR_AI_LAST = 0x01
+ADDR_DI_FIRST = 0x02
+ADDR_DI_LAST = 0x05
+ADDR_DO_FIRST = 0x00
+ADDR_DO_LAST = 0x0a
+
+class ATMega328():
+
+ _instance = None
+
+ @classmethod
+ def get_instance(cls):
+ if cls._instance is None:
+ cls._instance = ATMega328()
+ return cls._instance
+
+ def __init__(self):
+ # Initialze the SPI
+ self.spi = spidev.SpiDev()
+ self.spi.open(0,0)
+ self.spi.max_speed_hz = BAUDRATE_MAX
+
+ def close(self):
+ self.spi.close()
+
+ def digitalWrite(self, addr, value):
+ resp = self.spi.xfer([START, CMD_SET_DATA, addr, value, 0], BAUDRATE)
+
+ def digitalRead(self, addr):
+ resp = self.spi.xfer([START, CMD_GET_DATA, addr, 0, 0], BAUDRATE)
+ return resp[3]
+
+ def analogRead(self, addr):
+ resp = self.spi.xfer([START, CMD_GET_DATA, addr, 0, 0], BAUDRATE)
+ return resp[3]
+
+ def setLed(self, begin_led, end_led, red, green, blue):
+ resp = self.spi.xfer([START, CMD_SET_LED,
+ min(max(begin_led, 0), 60),
+ min(max(end_led, 0), 60),
+ min(max(red, 0), 254),
+ min(max(green, 0), 254),
+ min(max(blue, 0), 254)], BAUDRATE)
+ return resp[3]
+
+ def set_led(self, begin_led, end_led, red, green, blue):
+ begin = begin_led - 1
+ end = end_led - 1
+ red = int(red * 255 / 100)
+ green = int(green * 255 / 100)
+ blue = int(blue * 255 / 100)
+ return self.setLed(begin, end, red, green, blue)
+
+ def get_input(self, addr):
+ if addr >= ADDR_AI_FIRST and addr <= ADDR_AI_LAST:
+ return self.analogRead(addr)
+ elif addr >= ADDR_DI_FIRST and addr <= ADDR_DI_LAST:
+ return self.digitalRead(addr)
+
+ def set_output(self, addr, value):
+ if addr >= ADDR_DO_FIRST and addr <= ADDR_DO_LAST:
+ self.digitalWrite(addr, value)
diff --git a/coderbot/hw/lsm9ds1.py b/coderbot/hw/lsm9ds1.py
new file mode 100644
index 00000000..101b7daf
--- /dev/null
+++ b/coderbot/hw/lsm9ds1.py
@@ -0,0 +1,431 @@
+import os
+import time
+import math
+import json
+import spidev
+import threading
+
+from smbus2 import SMBus
+
+MAX_INVALID_MAG = 99.0
+
+# Hardware Constants
+#
+# from LSM9DS1_Datasheet.pdf
+class Register:
+ """Register constants"""
+ WHO_AM_I = 0x0F
+ CTRL_REG1_G = 0x10
+ CTRL_REG2_G = 0x11
+ CTRL_REG3_G = 0x12
+ OUT_TEMP_L = 0x15
+ STATUS_REG = 0x17
+ OUT_X_G = 0x18
+ CTRL_REG4 = 0x1E
+ CTRL_REG5_XL = 0x1F
+ CTRL_REG6_XL = 0x20
+ CTRL_REG7_XL = 0x21
+ CTRL_REG8 = 0x22
+ CTRL_REG9 = 0x23
+ CTRL_REG10 = 0x24
+ OUT_X_XL = 0x28
+ REFERENCE_G = 0x0B
+ INT1_CTRL = 0x0C
+ INT2_CTRL = 0x0D
+ WHO_AM_I_M = 0x0F
+ CTRL_REG1_M = 0x20
+ CTRL_REG2_M = 0x21
+ CTRL_REG3_M = 0x22
+ CTRL_REG4_M = 0x23
+ CTRL_REG5_M = 0x24
+ STATUS_REG_M = 0x27
+ OUT_X_L_M = 0x28
+
+
+class MagCalibration:
+ def __init__(self, xmin=MAX_INVALID_MAG, xmax=-MAX_INVALID_MAG, ymin=MAX_INVALID_MAG, ymax=-MAX_INVALID_MAG,
+ heading_offset=0.0):
+ self.xmax = xmax
+ self.xmin = xmin
+ self.ymax = ymax
+ self.ymin = ymin
+ self.heading_offset = heading_offset
+
+ def to_json(self):
+ obj = self.to_dict()
+ return json.dumps(obj)
+
+ def to_dict(self):
+ obj = {"xmin": self.xmin, "xmax": self.xmax, "ymin": self.ymin, "ymax": self.ymax,
+ "heading_offset": self.heading_offset}
+ return obj
+
+ @staticmethod
+ def from_dict(obj):
+ return MagCalibration(xmin=obj['xmin'], xmax=obj['xmax'], ymin=obj['ymin'], ymax=obj['ymax'],
+ heading_offset=obj['heading_offset'])
+
+
+#
+# Status Classes
+#
+class AGStatus:
+ def __init__(self, status):
+ self.status = status
+
+ @property
+ def accelerometer_interrupt(self):
+ return (self.status & 0x40) != 0
+
+ @property
+ def gyroscope_interrupt(self):
+ return (self.status & 0x20) != 0
+
+ @property
+ def inactivity_interrupt(self):
+ return (self.status & 0x10) != 0
+
+ @property
+ def boot_status(self):
+ return (self.status & 0x08) != 0
+
+ @property
+ def temperature_data_available(self):
+ return (self.status & 0x04) != 0
+
+ @property
+ def gyroscope_data_available(self):
+ return (self.status & 0x02) != 0
+
+ @property
+ def accelerometer_data_available(self):
+ return (self.status & 0x01) != 0
+
+
+class MagnetometerStatus:
+ def __init__(self, status):
+ self.status = status
+
+ @property
+ def overrun(self):
+ """data overrun on all axes"""
+ return (self.status & 0x80) != 0
+
+ @property
+ def z_overrun(self):
+ """Z axis data overrun"""
+ return (self.status & 0x40) != 0
+
+ @property
+ def y_overrun(self):
+ """Y axis data overrun"""
+ return (self.status & 0x20) != 0
+
+ @property
+ def x_overrun(self):
+ """X axis data overrun"""
+ return (self.status & 0x10) != 0
+
+ @property
+ def data_available(self):
+ """There's new data available for all axes."""
+ return (self.status & 0x08) != 0
+
+ @property
+ def z_axis_data_available(self):
+ return (self.status & 0x04) != 0
+
+ @property
+ def y_axis_data_available(self):
+ return (self.status & 0x02) != 0
+
+ @property
+ def x_axis_data_available(self):
+ return (self.status & 0x01) != 0
+
+class I2CTransport():
+ I2C_AG_ADDRESS = 0x6B
+ I2C_MAG_ADDRESS = 0x1E
+
+ def __init__(self, port, i2c_address, data_ready_pin=None):
+ super().__init__()
+ self.port = port
+ self.i2c_device = i2c_address
+ self.data_ready_interrupt = None
+
+ def write_byte(self, address, value):
+ with SMBus(self.port) as bus:
+ bus.write_byte_data(self.i2c_device, address, value)
+
+ def read_byte(self, address):
+ with SMBus(self.port) as bus:
+ bus.write_byte(self.i2c_device, address)
+ return bus.read_byte(self.i2c_device)
+
+ def read_bytes(self, address, length):
+ with SMBus(self.port) as bus:
+ bus.write_byte(self.i2c_device, address)
+ result = bus.read_i2c_block_data(self.i2c_device, address, length)
+ return result
+
+#
+# Main Interface: lsm9ds1
+#
+def make_i2c(i2cbus_no):
+ return lsm9ds1(
+ I2CTransport(i2cbus_no, I2CTransport.I2C_AG_ADDRESS),
+ I2CTransport(i2cbus_no, I2CTransport.I2C_MAG_ADDRESS))
+
+
+class lsm9ds1:
+ AG_ID = 0b01101000
+ MAG_ID = 0b00111101
+
+ # from LSM9DS1_Datasheet.pdf
+ ACC_SENSOR_SCALE = 0.061 / 1000.0
+ GAUSS_SENSOR_SCALE = 0.14 / 1000.0
+ DPS_SENSOR_SCALE = 8.75 / 1000.0
+ TEMP_SENSOR_SCALE = 59.5 / 1000.0
+ TEMPC_0 = 25
+ YMAG_IND = 1
+ XMAG_IND = 0
+
+ def __init__(self, ag_protocol, magnetometer_protocol, high_priority=False):
+ self.ag = ag_protocol
+ self.mag = magnetometer_protocol
+ self.mag_calibration = None
+ # Needs to be a high priority process or it'll drop samples
+ # when other processes are under heavy load.
+ if high_priority:
+ priority = os.sched_get_priority_max(os.SCHED_FIFO)
+ param = os.sched_param(priority)
+ os.sched_setscheduler(0, os.SCHED_FIFO, param)
+
+ def set_mag_calibration(self, mag_calibration):
+ self.mag_calibration = mag_calibration
+
+ def configure(self, mag_calibration=None):
+ """Resets the device and configures it. Optionally pass in the mag calibration info"""
+
+ self.set_mag_calibration(mag_calibration)
+
+ ###################################################
+ # - Bit 0 - SW_RESET - software reset for accelerometer and gyro - default 0
+ # - Bit 2 - IF_ADD_INC - automatic register increment for multibyte access - default 1
+ # - Bit 6 - BDU - Block data update . Ensures high and low bytes come from
+ # the same sample. Not necessary if waiting for data ready - default 0
+ self.ag.write_byte(Register.CTRL_REG8, 0x05)
+ # 0x08 - reboot magnetometer, +/- 4 Gauss full scale - fixes occasional magnetometer hang
+ # 0x04 - soft reset magnetometer, +/- 4 Gauss full scale
+ self.mag.write_byte(Register.CTRL_REG2_M, 0x08)
+ time.sleep(0.01) # Wait for reset
+ ###################################################
+ # Confirm that we're connected to the device
+ if self.ag.read_byte(Register.WHO_AM_I) != lsm9ds1.AG_ID:
+ raise RuntimeError('Could not find LSM9DS1 Acceleromter/Gyro. Check wiring and port numbers.')
+ if self.mag.read_byte(Register.WHO_AM_I_M) != lsm9ds1.MAG_ID:
+ raise RuntimeError('Could not find LSM9DS1 Magnetometer. Check wiring and port numbers.')
+ ###################################################
+ # Set up output data rate for Accelerometer and Gyro if using both
+ # Use CTRL_REG2_G and CTRL_REG3_G to control the optional additional filters
+ # 0x6A - 500 dps, 119 Hz ODR, 38Hz cut off (31 Hz Cut off if HP filter is enabled)
+ # 0x8A - 500 dps, 238 Hz ODR, 76Hz cut off (63 Hz Cut off if HP filter is enabled)
+ # 0xAA - 500 dps, 476 Hz ODR, 100Hz cut off (57 Hz Cut off if HP filter is enabled)
+ # 0x00 - disabled
+ self.ag.write_byte(Register.CTRL_REG1_G, 0x8A)
+ # 0x03 - Enable LPF2 - Frequency set by REG1 (2nd Low Pass Filter)
+ # self.ag.write_byte(Register.CTRL_REG2_G, 0x03)
+ # 0x45 - Enable High Pass Filter at (0.2 Hz @ 119 ODR) or (0.5 Hz @ 238 ODR)
+ # self.ag.write_byte(Register.CTRL_REG3_G, 0x45)
+ ###################################################
+ # Set up Accelerometer
+ # 0xC0 - Set to +- 2G, 119 Hz ODR, 50 Hz BW (Frequency is ignored if Gryo is enabled)
+ # 0x87 - Set to +- 2G, 238 Hz ODR, 50 Hz BW (Frequency is ignored if Gryo is enabled)
+ self.ag.write_byte(Register.CTRL_REG6_XL, 0x87)
+ # 0x01 INT1_A/G pin set by accelerometer data ready
+ self.ag.write_byte(Register.INT1_CTRL, 0x01)
+ ###################################################
+ # Set up magnetometer
+ # MSB enables temperature compensation
+ # 0x98 - 40 Hz ODR, Enable Temp Comp
+ # 0x9C - 80 Hz ODR, Enable Temp Comp
+ # 0x18 - 40 Hz ODR, Disable Temp Comp
+ # 0x1C - 80 Hz ODR, Enable Temp Comp
+ # 0xE2 - 155 Hz ODR, Enable Temp Comp, x and y ultra high performance
+ # 0xC2 - 300 Hz ODR, Enable Temp Comp, x and y high performance
+ # 0xA2 - 560 Hz ODR, Enable Temp Comp, x and y medium performance
+ # 0x82 - 1000 Hz ODR, Enable Temp Comp, x and y low performance
+ self.mag.write_byte(Register.CTRL_REG1_M, 0xC2)
+ # 0x00 - Magnetometer continuous operation - I2C enabled
+ # 0x80 - Magnetometer continuous operation - I2C disabled
+ self.mag.write_byte(Register.CTRL_REG3_M, 0x00)
+ # 0x08 - z axi high performance mode - doesn't seem to do anything
+ self.mag.write_byte(Register.CTRL_REG4_M, 0x08)
+ # Enable BDU (block data update) to ensure high and low bytes come from the same sample
+ self.mag.write_byte(Register.CTRL_REG5_M, 0x40)
+
+ def close(self):
+ """Closes the I2C/SPI connection. This must be called on shutdown."""
+ self.ag.close()
+ self.mag.close()
+
+ #
+ # Simplified scaled interface
+ #
+ def mag_heading(self):
+ """Returns the heading in 360°"""
+ values = self.mag_values()
+ y = values[lsm9ds1.YMAG_IND]
+ x = values[lsm9ds1.XMAG_IND]
+ if self.mag_calibration is not None:
+ mc = self.mag_calibration
+ # scale these samples between -1:1
+ if mc.xmax != mc.xmin:
+ x = ((x - mc.xmin) / (mc.xmax - mc.xmin)) * 2 - 1
+ if mc.ymax != mc.ymin:
+ y = ((y - mc.ymin) / (mc.ymax - mc.ymin)) * 2 - 1
+ heading = math.atan2(y, x)
+ heading = (heading / (2 * math.pi)) * 360.0
+ if self.mag_calibration is not None:
+ heading = (heading + self.mag_calibration.heading_offset) % 360.0
+ return heading
+
+ def read_values(self):
+ """Returns scaled values of temp, accel, gyro"""
+ temp, acc, gyro = self.read_ag_data()
+ tempc = lsm9ds1.TEMPC_0 + temp * lsm9ds1.TEMP_SENSOR_SCALE
+ tempf = (tempc * 9/5) + 32
+ acc = [c * lsm9ds1.ACC_SENSOR_SCALE for c in acc]
+ gyro = [g * lsm9ds1.DPS_SENSOR_SCALE for g in gyro]
+ return tempc, acc, gyro
+
+ #
+ # Raw interface
+ #
+ def ag_data_ready(self, timeout_millis):
+ return self.ag.data_ready(timeout_millis)
+
+ def read_ag_status(self):
+ """Returns the status byte for the accelerometer and gyroscope."""
+ data = self.ag.read_byte(Register.STATUS_REG)
+ return AGStatus(data)
+
+ def read_ag_data(self):
+ """Returns the current temperature, acceleration and angular velocity
+ values in one go. This is faster than fetching them independently.
+ These values can be invalid unless they're read when the data is ready."""
+ data = self.ag.read_bytes(Register.OUT_TEMP_L, 14)
+ temp = lsm9ds1.to_int16(data[0:2])
+ gyro = lsm9ds1.to_vector_left_to_right_hand_rule(data[2:8])
+ acc = lsm9ds1.to_vector_left_to_right_hand_rule(data[8:14])
+ return temp, acc, gyro
+
+ def read_temperature(self):
+ """Reads the temperature. See also read_ag_data()"""
+ data = self.ag.read_bytes(Register.OUT_TEMP_L, 2)
+ return lsm9ds1.to_int16(data)
+
+ def read_acceleration(self):
+ """Reads the accelerations. See also read_ag_data()"""
+ data = self.ag.read_bytes(Register.OUT_X_XL, 6)
+ return lsm9ds1.to_vector_left_to_right_hand_rule(data)
+
+ def read_gyroscope(self):
+ """Reads the angular velocities. See also read_ag_data()"""
+ data = self.ag.read_bytes(Register.OUT_X_G, 6)
+ return lsm9ds1.to_vector_left_to_right_hand_rule(data)
+
+ def magnetometer_data_ready(self, timout_millis: int) -> bool:
+ return self.mag.data_ready(timout_millis)
+
+ def read_magnetometer_status(self):
+ """Returns the status byte for the magnetometer"""
+ data = self.mag.read_byte(Register.STATUS_REG_M)
+ return MagnetometerStatus(data)
+
+ def mag_values(self):
+ mag = self.read_magnetometer()
+ mag = [m * lsm9ds1.GAUSS_SENSOR_SCALE for m in mag]
+ return mag
+
+ def read_magnetometer(self):
+ """Reads the magnetometer field strengths"""
+ data = self.mag.read_bytes(Register.OUT_X_L_M, 6)
+ return lsm9ds1.to_vector(data)
+
+ @staticmethod
+ def to_vector(data):
+ return [lsm9ds1.to_int16(data[0:2]), lsm9ds1.to_int16(data[2:4]), lsm9ds1.to_int16(data[4:6])]
+
+ @staticmethod
+ def to_vector_left_to_right_hand_rule(data):
+ """Like to_vector except it converts from the left to the right hand rule
+ by negating the x-axis."""
+ return [-lsm9ds1.to_int16(data[0:2]), lsm9ds1.to_int16(data[2:4]), lsm9ds1.to_int16(data[4:6])]
+
+ @staticmethod
+ def to_int16(data):
+ """
+ Converts little endian bytes into a signed 16-bit integer
+ :param data: 16bit int in little endian, two's complement form
+ :return: an integer
+ """
+ return int.from_bytes(data, byteorder='little', signed=True)
+
+
+#
+# Run me as an application to get calibration info:
+# python -m lsm9ds1.lsm9ds1
+#
+def poll_mag_calibration(imu, mc, evt, verbose=True):
+ """
+ Will poll the x, y mag gauss values in order to establish min, max
+ """
+ samples = 0
+ while not evt.is_set():
+ m = imu.mag_values()
+ samples += 1
+ x = m[lsm9ds1.XMAG_IND]
+ y = m[lsm9ds1.YMAG_IND]
+ if x < mc.xmin:
+ mc.xmin = x
+ if x > mc.xmax:
+ mc.xmax = x
+ if y < mc.ymin:
+ mc.ymin = y
+ if y > mc.ymax:
+ mc.ymax = y
+
+ if verbose:
+ print("%d samples." % samples)
+
+
+def run_interactive_calibration(i2cbus_no):
+ mc = MagCalibration()
+ evt = threading.Event()
+ imu = make_i2c(i2cbus_no)
+ calibration__thread = threading.Thread(target=poll_mag_calibration, args=[imu, mc, evt])
+ calibration__thread.start()
+
+ input("Rotate device for 2 revolutions at approximately 10 seconds per revolution press enter when done >")
+ evt.set()
+ calibration__thread.join()
+
+ while True:
+ current = input("What direction am I currently facing (in 360°) >")
+ try:
+ current = float(current)
+ break
+ except Exception:
+ print("I need a floating point number for the heading")
+
+ imu.set_mag_calibration(mc)
+ observed = imu.mag_heading()
+
+ mc.heading_offset = current - observed
+ return mc
+
+
+if __name__ == '__main__':
+ mc = run_interactive_calibration(1)
+ print(mc.to_json())
diff --git a/coderbot/hw/mpu.py b/coderbot/hw/mpu.py
new file mode 100644
index 00000000..702dab45
--- /dev/null
+++ b/coderbot/hw/mpu.py
@@ -0,0 +1,59 @@
+from . import lsm9ds1
+import time
+
+class AccelGyroMag:
+ X_IND = 0
+ Y_IND = 1
+ Z_IND = 2
+
+ PITCH_IND = 0
+ ROLL_IND = 1
+ YAW_IND = 2
+
+ """This example shows how to poll the sensor for new data.
+ It queries the sensor to discover when the accelerometer/gyro
+ has new data and then reads all the sensors."""
+ def __init__(self):
+ self.driver = lsm9ds1.make_i2c(1)
+ mc = lsm9ds1.MagCalibration(xmin=0.03234, xmax=0.25718,
+ ymin=0.036120000000000006, ymax=0.19138000000000002,
+ heading_offset=-130.29698965718163)
+ self.driver.configure(mc)
+
+
+ GYRO_THRESHOLD = 1.5
+
+ def read_ag(self):
+ temp, acc, gyro = self.driver.read_values()
+ print("Temp: %.1f °f" % temp)
+ print("Gyro Roll: %.4f, Pitch: %.4f, Yaw: %.4f" % (gyro[AccelGyroMag.ROLL_IND],
+ gyro[AccelGyroMag.PITCH_IND],
+ gyro[AccelGyroMag.YAW_IND]))
+ print("X: %.4f, Y: %.4f, Z: %.4f" % (acc[AccelGyroMag.X_IND],
+ acc[AccelGyroMag.Y_IND],
+ acc[AccelGyroMag.Z_IND]))
+
+ def read_magnetometer(self):
+ hdg = self.driver.mag_heading()
+ print("Heading: " + str(hdg))
+
+
+ def get_gyro(self):
+ temp, acc, gyro = self.driver.read_values()
+ return (gyro[AccelGyroMag.ROLL_IND],
+ gyro[AccelGyroMag.PITCH_IND],
+ gyro[AccelGyroMag.YAW_IND])
+
+ def get_acc(self):
+ temp, acc, gyro = self.driver.read_values()
+ return (acc[AccelGyroMag.X_IND],
+ acc[AccelGyroMag.Y_IND],
+ acc[AccelGyroMag.Z_IND])
+
+ def get_hdg(self):
+ hdg = self.driver.mag_heading()
+ return hdg
+
+ def get_temp(self):
+ temp, acc, gyro = self.driver.read_values()
+ return temp
diff --git a/coderbot/hw/mpu2.py b/coderbot/hw/mpu2.py
new file mode 100644
index 00000000..d7a3278d
--- /dev/null
+++ b/coderbot/hw/mpu2.py
@@ -0,0 +1,56 @@
+import time
+
+from hw import lsm9ds1
+
+class SimpleExample:
+ X_IND = 0
+ Y_IND = 1
+ Z_IND = 2
+
+ PITCH_IND = 0
+ ROLL_IND = 1
+ YAW_IND = 2
+
+ """This example shows how to poll the sensor for new data.
+ It queries the sensor to discover when the accelerometer/gyro
+ has new data and then reads all the sensors."""
+ def __init__(self):
+ self.driver = lsm9ds1.make_i2c(1)
+ mc = lsm9ds1.MagCalibration(xmin=0.03234, xmax=0.25718,
+ ymin=0.036120000000000006, ymax=0.19138000000000002,
+ heading_offset=-130.29698965718163)
+ self.driver.configure(mc)
+
+ def main(self):
+ try:
+ count = 0
+ while True:
+ ag_data_ready = self.driver.read_ag_status().accelerometer_data_available
+ if ag_data_ready:
+ self.read_ag()
+ print("")
+ #self.read_magnetometer()
+ count += 1
+ time.sleep(0.05)
+ finally:
+ self.driver.close()
+
+ def read_ag(self):
+ temp, acc, gyro = self.driver.read_values()
+ #print("Temp: %.1f °f" % temp, end='')
+ #print("Gyro Roll: %.4f, Pitch: %.4f, Yaw: %.4f" % (gyro[SimpleExample.ROLL_IND],
+ # gyro[SimpleExample.PITCH_IND],
+ # gyro[SimpleExample.YAW_IND]), end='')
+ print("X: %.4f, Y: %.4f, Z: %.4f" % (acc[SimpleExample.X_IND],
+ acc[SimpleExample.Y_IND],
+ acc[SimpleExample.Z_IND]), end='')
+
+ def read_magnetometer(self):
+ hdg = self.driver.mag_heading()
+ print("headind: %f ", hdg, end='')
+ mag = self.driver.read_magnetometer()
+ print('Mag {}'.format(mag))
+
+
+if __name__ == '__main__':
+ SimpleExample().main()
diff --git a/coderbot/main.py b/coderbot/main.py
new file mode 100644
index 00000000..36383240
--- /dev/null
+++ b/coderbot/main.py
@@ -0,0 +1,117 @@
+"""
+This module provides the http web server exposing the
+CoderBot REST API and static resources
+"""
+import os
+import logging
+import logging.handlers
+import picamera
+import connexion
+
+from connexion.options import SwaggerUIOptions
+from connexion.middleware import MiddlewarePosition
+from starlette.middleware.cors import CORSMiddleware
+
+from camera import Camera
+from motion import Motion
+from audio import Audio
+from program import ProgramEngine
+from config import Config
+from cnn.cnn_manager import CNNManager
+from event import EventManager
+from coderbot import CoderBot
+
+# Logging configuration
+logger = logging.getLogger()
+logger.setLevel(os.environ.get("LOGLEVEL", "INFO"))
+
+## (Connexion) Flask app configuration
+
+# Serve a custom version of the swagger ui (Jinja2 templates) based on the default one
+# from the folder 'swagger-ui'. Clone the 'swagger-ui' repository inside the backend folder
+swagger_ui_options = SwaggerUIOptions(swagger_ui=True)
+app = connexion.App(__name__, swagger_ui_options=swagger_ui_options)
+app.add_middleware(
+ CORSMiddleware,
+ position=MiddlewarePosition.BEFORE_EXCEPTION,
+ allow_origins=["*"],
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+app.prog_engine = ProgramEngine.get_instance()
+
+## New API and web application
+
+# API v1 is defined in v1.yml and its methods are in api.py
+app.add_api('v1.yml')
+
+def button_pushed():
+ if app.bot_config.get('button_func') == "startstop":
+ prog = app.prog_engine.get_current_prog()
+ if prog and prog.is_running():
+ prog.end()
+ elif prog and not prog.is_running():
+ prog.execute()
+
+def remove_doreset_file():
+ try:
+ os.remove("/home/pi/doreset")
+ except OSError:
+ pass
+
+# Finally, get the server running
+def run_server():
+ bot = None
+ cam = None
+ try:
+ try:
+ app.bot_config = Config.read()
+ bot = CoderBot.get_instance(motor_trim_factor=float(app.bot_config.get('move_motor_trim', 1.0)),
+ motor_max_power=int(app.bot_config.get('motor_max_power', 100)),
+ motor_min_power=int(app.bot_config.get('motor_min_power', 0)),
+ hw_version=app.bot_config.get('hardware_version'),
+ pid_params=(float(app.bot_config.get('pid_kp', 1.0)),
+ float(app.bot_config.get('pid_kd', 0.1)),
+ float(app.bot_config.get('pid_ki', 0.01)),
+ float(app.bot_config.get('pid_max_speed', 200)),
+ float(app.bot_config.get('pid_sample_time', 0.01))),
+ from_defaults=False)
+
+ try:
+ audio_device = Audio.get_instance()
+ audio_device.set_volume(int(app.bot_config.get('audio_volume_level')), 100)
+ audio_device.say(app.bot_config.get("sound_start"))
+ except Exception:
+ logging.warning("Audio not present")
+
+ try:
+ logging.info("starting camera")
+ cam = Camera.get_instance()
+ Motion.get_instance()
+ except picamera.exc.PiCameraError:
+ logging.warning("Camera not present")
+
+ CNNManager.get_instance()
+ EventManager.get_instance("coderbot")
+
+ if app.bot_config.get('load_at_start') and app.bot_config.get('load_at_start'):
+ prog = app.prog_engine.load(app.bot_config.get('load_at_start'))
+ prog.execute()
+ except ValueError as e:
+ app.bot_config = {}
+ logging.error(e)
+
+ bot.set_callback(bot.GPIOS.PIN_PUSHBUTTON, button_pushed, 100)
+
+ remove_doreset_file()
+
+ app.run(host="0.0.0.0", port=5000)
+ finally:
+ if cam:
+ cam.exit()
+ if bot:
+ bot.exit()
+
+if __name__ == "__main__":
+ run_server()
\ No newline at end of file
diff --git a/coderbot/motion.py b/coderbot/motion.py
new file mode 100644
index 00000000..95d66563
--- /dev/null
+++ b/coderbot/motion.py
@@ -0,0 +1,241 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+from time import time
+import logging
+import numpy as np
+import cv2
+from cv import image
+
+from coderbot import CoderBot
+from camera import Camera
+from config import Config
+
+lk_params = dict(winSize=(15, 15),
+ maxLevel=2,
+ criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
+
+feature_params = dict(maxCorners=500,
+ qualityLevel=0.3,
+ minDistance=7,
+ blockSize=7)
+
+
+PI_CAM_FOV_H_DEG = 53.0
+PI_CAM_FOV_V_CM = 100.0
+
+class Motion:
+ # pylint: disable=too-many-instance-attributes
+
+ def __init__(self):
+ self.bot = CoderBot.get_instance()
+ self.cam = Camera.get_instance()
+ self.track_len = 2
+ self.detect_interval = 5
+ self.tracks = []
+ self.frame_idx = 0
+ self.ts = time()
+ self.frame_gray = None
+ self.prev_gray = None
+ self.running = False
+ self.delta_power = 0.0
+ self.delta_dist = 0.0
+ self.target_dist = 0.0
+ self.delta_angle = 0.0
+ self.target_angle = 0.0
+ cfg = Config.get()
+ self.power_angles = [[15, (int(cfg.get("move_power_angle_1")), -1)],
+ [4, (int(cfg.get("move_power_angle_2")), 0.05)],
+ [1, (int(cfg.get("move_power_angle_3")), 0.02)],
+ [0, (0, 0)]]
+ self.image_width = 640 / int(cfg.get("cv_image_factor"))
+ self.image_heigth = 480 / int(cfg.get("cv_image_factor"))
+ self.transform = image.Image.get_transform(self.image_width)
+ _motion = None
+
+ @classmethod
+ def get_instance(cls):
+ if not cls._motion:
+ cls._motion = Motion()
+ return cls._motion
+
+ def move(self, dist):
+ self.delta_dist = 0.0
+ self.delta_angle = 0.0
+ self.target_dist = dist
+ self.target_angle = 0.0
+ self.delta_power = 0.0
+ self.loop_move()
+
+ def turn(self, angle):
+ self.delta_dist = 0.0
+ self.delta_angle = 0.0
+ self.target_dist = 0.0
+ self.target_angle = angle
+ self.loop_turn()
+
+ def stop(self):
+ self.running = False
+
+ def loop_move(self):
+ self.running = True
+ while self.running:
+ frame = self.cam.get_image()
+ self.frame_gray = frame.grayscale()
+
+ if len(self.tracks) < 2 or self.frame_idx % self.detect_interval == 0:
+ self.find_keypoints(self.frame_gray, self.tracks)
+
+ if self.tracks and self.prev_gray is not None:
+ self.track_keypoints(self.prev_gray, self.frame_gray, self.tracks)
+
+ if self.tracks:
+ delta_angle, delta_dist = self.calc_motion()
+ self.running = self.running and self.bot_move(self.target_dist, delta_dist, delta_angle)
+
+ self.frame_idx += 1
+ self.prev_gray = self.frame_gray
+ self.bot.stop()
+
+ def loop_turn(self):
+ self.running = True
+ while self.running:
+ frame = self.cam.get_image()
+ self.frame_gray = frame.grayscale()
+
+ if len(self.tracks) < 2 or self.frame_idx % self.detect_interval == 0:
+ self.find_keypoints(self.frame_gray, self.tracks)
+
+ if self.tracks and self.prev_gray is not None:
+ self.track_keypoints(self.prev_gray, self.frame_gray, self.tracks)
+
+ if self.tracks:
+ delta_angle, delta_dist = self.calc_motion()
+ self.running = self.running and self.bot_turn(self.target_angle, delta_angle)
+
+ self.frame_idx += 1
+ self.prev_gray = self.frame_gray
+
+ self.bot.stop()
+
+ def find_keypoints(self, image_gray, tracks):
+ #print "find_keypoints"
+ ts = time()
+ mask = np.zeros_like(image_gray._data)
+ mask[:] = 255
+ #for x, y in [np.int32(tr[-1]) for tr in tracks]:
+ # cv2.circle(mask, (x, y), 5, 0, -1)
+ p = cv2.goodFeaturesToTrack(image_gray._data, mask=mask, **feature_params)
+ if p is not None:
+ for x, y in np.float32(p).reshape(-1, 2):
+ tracks.append([(x, y)])
+ #print "fk: ", str(time() - ts)
+
+ def track_keypoints(self, prev_image, cur_image, tracks):
+ #print "track_keypoints"
+ #ts = time()
+ img0, img1 = prev_image._data, cur_image._data
+ p0 = np.float32([tr[-1] for tr in tracks]).reshape(-1, 1, 2)
+ p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
+ p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
+ d = abs(p0-p0r).reshape(-1, 2).max(-1)
+ good = d < 1
+ #good = st
+ #print "tk: ", str(time() - ts)
+ new_tracks = []
+ for tr, (x, y), good_flag in zip(tracks, p1.reshape(-1, 2), good):
+ if not good_flag:
+ continue
+ tr.append((x, y))
+ if len(tr) > self.track_len:
+ del tr[0]
+ new_tracks.append(tr)
+ #cv2.circle(self.vis, (x, y), 2, (0, 255, 0), -1)
+ #print "initial tp: ", len(self.tracks), " current tp: ", len(new_tracks)
+ #print len(new_tracks), len(tracks)
+ tracks[:] = new_tracks[:]
+ if tracks is False:
+ logging.warning("lost ALL tp!")
+ self.bot.stop()
+ #exit(0)
+ #cv2.polylines(self.vis, [np.int32(tr) for tr in self.tracks], False, (0, 255, 0))
+
+ def calc_motion(self):
+ vectors = self.tracks
+
+ avg_delta_x = 0.0
+ avg_delta_y = 0.0
+ count = 0
+ vectors_t = []
+ for vect in vectors:
+ if len(vect) > 1:
+ count += 1
+ vectors_t.append(vect[-2])
+ vectors_t.append(vect[-1])
+ avg_delta_x += (vect[-1][0] - vect[-2][0])
+
+ vectors_t = vectors_t[:min(len(vectors_t), 20)] #max 10 keypoints
+
+ #avg_delta_x_t = 0.0
+ if vectors_t:
+ vectors_t = image.Image.transform(vectors_t, self.transform)
+ for v in vectors_t.reshape(-1, 2, 2):
+ avg_delta_y += (v[1][1] - v[0][1])
+ #avg_delta_x_t += v[1][0] - v[0][0]
+ #avg_delta_x_t = avg_delta_x_t / (vectors_t.shape[0] / 2)
+ #for v in vectors_t.reshape(-1, 2, 2):
+ #if abs(v[1][0] - v[0][0] - avg_delta_x_t) > 2:
+ #print "this is an obstacle: ", str(v[1]), " delta_x: ", v[1][0] - v[0][0]
+
+ if count > 0:
+ avg_delta_x = (avg_delta_x / count)
+ avg_delta_y = (avg_delta_y / (vectors_t.shape[0] / 2))
+
+ self.delta_angle -= (avg_delta_x * PI_CAM_FOV_H_DEG) / self.image_width
+ self.delta_dist += (avg_delta_y * PI_CAM_FOV_V_CM) / self.image_heigth
+ #print "count: ", count, "delta_a: ", self.delta_angle, " avg_delta_x: ", avg_delta_x, " delta_y: ", self.delta_dist, " avg_delta_y: ", avg_delta_y
+
+ #cv2.line(self.vis, (int(80+deltaAngle),20), (80,20), (0, 0, 255))
+ #cv2.putText(self.vis, "delta: " + str(int((self.deltaAngle*53.0)/160.0)) + " avg_delta: " + str(int(((avg_delta_x*53.0)/160.0))),
+ #(0,20), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0, 0, 255))
+
+ return self.delta_angle, self.delta_dist
+
+ def bot_turn(self, target_angle, delta_angle):
+ run = True
+ sign = (target_angle - delta_angle) / abs(target_angle - delta_angle)
+ logging.info("abs delta: %s sign delta: %s", str(abs(target_angle - delta_angle)), str(sign))
+ for p_a in self.power_angles:
+ if abs(target_angle - delta_angle) > p_a[0] and self.running:
+ #print "pow: ", p_a[1][0], " duration: ", p_a[1][1]
+ self.bot.motor_control(sign * p_a[1][0], -1 * sign * p_a[1][0], p_a[1][1])
+ run = p_a[1][0] > 0 #stopped
+ break
+
+ return run
+
+ def bot_move(self, target_dist, delta_dist, delta_angle):
+ base_power = 100 * (target_dist/abs(target_dist))
+ self.delta_power += (delta_angle * 0.01)
+ logging.info("base power: %s delta power: %s delta_dist: %s target_dist: %s", str(base_power), str(self.delta_power), str(delta_dist), str(target_dist))
+ if abs(delta_dist) < abs(target_dist):
+ self.bot.motor_control(min(max(base_power - self.delta_power, -100), 100), min(max(base_power + self.delta_power, -100), 100), -1)
+ else:
+ self.bot.stop()
+ return abs(delta_dist) < abs(target_dist)
diff --git a/coderbot/music.py b/coderbot/music.py
new file mode 100644
index 00000000..0544b468
--- /dev/null
+++ b/coderbot/music.py
@@ -0,0 +1,152 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# MUSICAL EXTENTION for CoderBot
+# This extention is develop by:
+# Michele Carbonera - miki_992@hotmail.it - m.carbonera@campus.unimib.it - michele.carbonera@unimib.it
+# Antonino Tramontana - a.tramontana1@campus.unimib.it
+# Copyright (C) 2020
+############################################################################
+
+import os
+import sox
+import time
+
+class Music:
+ _instance = None
+ managerPackage = None
+
+ noteDict = {
+ 'C2': -7.0, 'D2' : -5.0, 'E2' : -3.0, 'F2' : -2.0, 'F#2' : -1.0, 'G2' : 0.0,
+ 'A2' : 2.0, 'Bb2' : 3.0, 'B2' : 4.0, 'C3' : 5.0, 'D3' : 7.0, 'E3' : 9.0,
+ 'F3' : 10.0, 'G3' : 12.0
+ }
+
+
+ @classmethod
+ def get_instance(cls,managerPackage):
+ if cls._instance is None:
+ cls._instance = Music(managerPackage)
+ return cls._instance
+
+ def __init__(self,managerPackage):
+
+ #os.putenv('AUDIODRIVER', 'alsa')
+ #os.putenv('AUDIODEV', 'hw:1,0')
+ self.managerPackage = managerPackage
+ print("We have create a class: MUSICAL")
+
+ def test(self):
+ tfm = sox.Transformer()
+ tfm.preview('cat.wav')
+ tfm.build('cat.wav', 'outMusicDemo.wav')
+
+ #play a pause
+ # @param duration: duration of the pause in seconds
+ def play_pause(self, duration):
+ duration = float(duration)
+ time.sleep(duration)
+
+ #play a given note for a given instrument
+ # @param instrument: name of the instrument to be used
+ # @param note: name of the note in the following format "A2"
+ # @para alteration: if it is a diesis or a bemolle
+ # @param time: duration of the note in seconds
+ def play_note(self, note, instrument='piano', alteration='none', duration=1.0):
+ print(note)
+ tfm = sox.Transformer()
+
+ duration = float(duration)
+
+ alt = 0.0
+ if alteration == 'bmolle':
+ alt = -1.0
+ elif alteration == 'diesis':
+ alt = 1.0
+
+ if note in self.noteDict :
+ shift = self.noteDict[note]+ alt
+ else:
+ print('note not exist')
+ return
+
+ tfm.pitch(shift, quick=False)
+ tfm.trim(0.0, end_time=0.5*duration)
+ if self.managerPackage.isPackageAvailable(instrument):
+ tfm.preview('./sounds/notes/' + instrument + '/audio.wav')
+ else:
+ print("no instrument:"+str(instrument)+" present in this coderbot!")
+
+ def play_animal(self, instrument, note='G2', alteration='none', duration=1.0):
+ tfm = sox.Transformer()
+
+ duration = float(duration)
+
+ alt = 0.0
+ if alteration == 'bmolle':
+ alt = -1.0
+ elif alteration == 'diesis':
+ alt = 1.0
+
+ if note == 'C2':
+ shift = -7.0 + alt
+ elif note == 'D2':
+ shift = -5.0 + alt
+ elif note == 'E2':
+ shift = -3.0 + alt
+ elif note == 'F2':
+ shift = -2.0 + alt
+ elif note == 'F#2':
+ shift = -1.0 + alt
+ elif note == 'G2':
+ shift = 0.0 + alt
+ elif note == 'A2':
+ shift = 2.0 + alt
+ elif note == 'Bb2':
+ shift = 3.0 + alt
+ elif note == 'B2':
+ shift = 4.0 + alt
+ elif note == 'C3':
+ shift = 5.0 + alt
+ elif note == 'D3':
+ shift = 7.0 + alt
+ elif note == 'E3':
+ shift = 9.0 + alt
+ elif note == 'F3':
+ shift = 10.0 + alt
+ elif note == 'G3':
+ shift = 12.0 + alt
+
+ if note in self.noteDict :
+ shift = self.noteDict[note]+ alt
+ else:
+ print('note not exist')
+ return
+
+ if self.managerPackage.isPackageAvailable(instrument):
+ tfm.preview('./sounds/notes/' + instrument + '/audio.wav')
+ else:
+ print("no animal verse:"+str(instrument)+" present in this coderbot!")
+ return
+ tfm.pitch(shift, quick=False)
+ tfm.trim(0.0, end_time=0.5*duration)
+ #tfm.stretch(time, window=20)
+ tfm.preview('./sounds/notes/' + instrument + '/audio.wav')
diff --git a/coderbot/musicPackages.py b/coderbot/musicPackages.py
new file mode 100644
index 00000000..e671b7e7
--- /dev/null
+++ b/coderbot/musicPackages.py
@@ -0,0 +1,218 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# MUSICAL EXTENTION for CoderBot
+# This extention is develop by:
+# Michele Carbonera - miki_992@hotmail.it - m.carbonera@campus.unimib.it - michele.carbonera@unimib.it
+# Antonino Tramontana - a.tramontana1@campus.unimib.it
+# Copyright (C) 2020
+############################################################################
+
+import json
+import os
+import logging
+import copy
+
+class MusicPackage:
+
+ def __init__(self, nameID, category, name_IT, name_EN, version, date):
+ self.nameID = nameID
+ self.category = category
+ self.name_IT = name_IT
+ self.name_EN = name_EN
+ self.version = version
+ self.date = date
+ self.interfaces = list()
+
+ def getNameID(self):
+ return self.nameID
+
+ def getCategory(self):
+ return self.category
+
+ def getNameIT(self):
+ return self.name_IT
+
+ def getNameEN(self):
+ return self.name_EN
+
+ def getVersion(self):
+ return self.version
+
+ def getDate(self):
+ return self.date
+
+ def getInterfaces(self):
+ return self.interfaces
+
+ def addInterface(self, musicPackageInterface):
+ self.interfaces.append(musicPackageInterface)
+
+class MusicPackageInterface:
+
+ def __init__(self,interfaceName,available,icon):
+ self.interfaceName = interfaceName
+ self.available = available
+ self.icon = icon
+
+ def getInterfaceName(self):
+ return self.interfaceName
+
+ def getAvailable(self):
+ return self.available
+
+ def getIcon(self):
+ return self.icon
+
+class MusicPackageManager:
+ _instance = None
+
+ @classmethod
+ def get_instance(cls):
+ if cls._instance is None:
+ cls._instance = MusicPackageManager()
+ return cls._instance
+
+ def __init__(self):
+ self.packages = dict()
+ with open('./sounds/notes/music_package.json') as json_file:
+ data = json.load(json_file)
+ for p in data['packages']:
+
+ package = data['packages'][p]
+ mp = MusicPackage(p,package['category'],package['name_IT'],package['name_EN'],package['version'],package['date'])
+ for i in package['interface']:
+ interfaceItem = package['interface'][i]
+ mpi = MusicPackageInterface(i,interfaceItem['available'],interfaceItem['icon'])
+ mp.addInterface(mpi)
+
+ if p not in self.packages:
+ self.packages[p] = mp
+
+ def listPackages(self):
+ packages_serializable = dict()
+ for name, package in self.packages.items():
+ package_copy = copy.deepcopy(package)
+ packages_serializable[name] = package_copy.__dict__
+ packages_serializable[name]['interfaces'] = []
+ for i in package.interfaces:
+ packages_serializable[name]['interfaces'].append(i.__dict__)
+ return packages_serializable
+
+ def updatePackages(self):
+ newdict = { 'packages': {} }
+ for element in self.packages:
+ nameID = self.packages[element].getNameID()
+ newdict['packages'][nameID] = { }
+ newdict['packages'][nameID]['category']= self.packages[element].getCategory()
+ newdict['packages'][nameID]['name_IT']= self.packages[element].getNameIT()
+ newdict['packages'][nameID]['name_EN']= self.packages[element].getNameEN()
+ newdict['packages'][nameID]['version']= self.packages[element].getVersion()
+ newdict['packages'][nameID]['date']= self.packages[element].getDate()
+ newdict['packages'][nameID]['interface']= {'base':{}, 'intermediate':{}, 'advanced': {}}
+ newdict['packages'][nameID]['interface']['base']['available'] = self.packages[element].getInterfaces()[0].getAvailable()
+ newdict['packages'][nameID]['interface']['base']['icon'] = self.packages[element].getInterfaces()[0].getIcon()
+ newdict['packages'][nameID]['interface']['intermediate']['available'] = self.packages[element].getInterfaces()[1].getAvailable()
+ newdict['packages'][nameID]['interface']['intermediate']['icon'] = self.packages[element].getInterfaces()[1].getIcon()
+ newdict['packages'][nameID]['interface']['advanced']['available'] = self.packages[element].getInterfaces()[2].getAvailable()
+ newdict['packages'][nameID]['interface']['advanced']['icon'] = self.packages[element].getInterfaces()[2].getIcon()
+
+ #json_packages = json.dumps(newdict)
+ with open('sounds/notes/music_package.json', 'w', encoding='utf-8') as json_file:
+ json.dump(newdict, json_file, ensure_ascii=False, indent=4)
+
+
+ def deletePackage(self, packageName):
+ logging.info("packageName: " + packageName)
+ if packageName in self.packages:
+ del self.packages[packageName]
+ self.updatePackages()
+ else:
+ logging.error("errore, il pacchetto " + packageName + " non è stato trovato")
+ return 2
+
+ if os.path.exists('./sounds/notes/' + packageName):
+ os.system('rm -rf ./sounds/notes/' + packageName)
+ return 1
+
+
+ def verifyVersion(self, packageName, version):
+ logging.info("verifica pacchetto")
+ #newversionList = version.split('.')
+ if packageName not in self.packages:
+ return True
+
+ newVersionList = [int(x) for x in version.split('.')]
+ #for i in ragen(0,len(newversionList) -1):
+ #newversionList[i] = int(newLversionList[i])
+
+ oldVersion = self.packages[packageName].getVersion()
+ oldVersionList = [int(x) for x in oldVersion.split('.')]
+
+ for i in range(0,len(newVersionList) -1):
+ if(newVersionList[i] > oldVersionList[i] ):
+ return True
+ elif(newVersionList[i] < oldVersionList[i] ):
+ return False
+
+ return False
+
+ def addPackage(self, filename):
+ pkgnames = filename.split('_')
+ version = pkgnames[1].replace('.zip', '')
+ logging.info("Music Package version: " + version)
+ pkgname = pkgnames[0]
+ pkgpath = './sounds/notes/' + pkgname
+ if not self.verifyVersion(pkgname, version):
+ if (version == self.packages[pkgname].getVersion()):
+ logging.error("errore, il pacchetto " + pkgname + " ha versione identica a quello attualmente installato")
+ raise ValueError()
+ else:
+ logging.info("errore, il pacchetto " + pkgname + " ha versione precendente a quello attualmente installato")
+ raise ValueError()
+ else:
+ os.system('unzip -o ' + '/tmp/' + filename + " -d /tmp")
+ os.system('mkdir ' + pkgpath)
+ os.system('mv /tmp/' + pkgname + "/" + 'audio.wav ' + pkgpath + '/')
+
+ with open('/tmp/' + pkgname + '/' + pkgname + '.json') as json_file:
+ logging.info("adding " + pkgname + " package")
+ data = json.load(json_file)
+ for p in data['packages']:
+ package = data['packages'][p]
+ mp = MusicPackage(p,package['category'],package['name_IT'],package['name_EN'],package['version'],package['date'])
+ for i in package['interface']:
+ interfaceItem = package['interface'][i]
+ mpi = MusicPackageInterface(i,interfaceItem['available'],interfaceItem['icon'])
+ mp.addInterface(mpi)
+
+ self.packages[p] = mp
+
+ self.updatePackages()
+
+ os.system('rm -rf /tmp/' + pkgname)
+
+
+ def isPackageAvailable(self,namePackage):
+ if namePackage in self.packages:
+ return True
+ else:
+ return False
diff --git a/coderbot/program.py b/coderbot/program.py
new file mode 100644
index 00000000..bc66fc3e
--- /dev/null
+++ b/coderbot/program.py
@@ -0,0 +1,250 @@
+############################################################################
+# CoderBot, a didactical programmable robot.
+# Copyright (C) 2014, 2015 Roberto Previtera
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+############################################################################
+
+import os
+import threading
+import json
+import shutil
+import logging
+
+import math
+from tinydb import TinyDB, Query
+from threading import Lock
+
+import coderbot
+import camera
+import motion
+import config
+import audio
+import event
+import music
+import musicPackages
+from hw.atmega328p import ATMega328
+
+PROGRAM_PATH = "./data/"
+PROGRAM_PREFIX = "program_"
+PROGRAM_SUFFIX = ".json"
+PROGRAMS_DB = "data/programs.json"
+PROGRAMS_PATH_DEFAULTS = "defaults/programs/"
+
+musicPackageManager = musicPackages.MusicPackageManager.get_instance()
+
+def get_cam():
+ return camera.Camera.get_instance()
+
+def get_bot():
+ return coderbot.CoderBot.get_instance()
+
+def get_motion():
+ return motion.Motion.get_instance()
+
+def get_audio():
+ return audio.Audio.get_instance()
+
+def get_prog_eng():
+ return ProgramEngine.get_instance()
+
+def get_event():
+ return event.EventManager.get_instance()
+
+def get_music():
+ return music.Music.get_instance(musicPackageManager)
+
+def get_atmega():
+ return ATMega328.get_instance()
+
+class ProgramEngine:
+
+ # pylint: disable=exec-used
+
+ _instance = None
+
+ def __init__(self):
+ self._program = None
+ self._log = ""
+ self._programs = TinyDB(PROGRAMS_DB)
+ # initialise DB from default programs
+ query = Query()
+ self.lock = Lock()
+ for dirname, dirnames, filenames, in os.walk(PROGRAMS_PATH_DEFAULTS):
+ dirnames
+ for filename in filenames:
+ if PROGRAM_PREFIX in filename:
+ program_name = filename[len(PROGRAM_PREFIX):-len(PROGRAM_SUFFIX)]
+ if self._programs.search(query.name == program_name) == []:
+ logging.info("adding program %s in path %s as default %r", program_name, dirname, ("default" in dirname))
+ with open(os.path.join(dirname, filename), "r") as f:
+ program_dict = json.load(f)
+ program_dict["default"] = "default" in dirname
+ program = Program.from_dict(program_dict)
+ self.save(program)
+
+ @classmethod
+ def get_instance(cls):
+ if not cls._instance:
+ cls._instance = ProgramEngine()
+ return cls._instance
+
+ def prog_list(self):
+ return self._programs.all()
+
+ def save(self, program):
+ with self.lock:
+ query = Query()
+ self._program = program
+ program_db_entry = self._program.as_dict()
+ if self._programs.search(query.name == program.name) != []:
+ self._programs.update(program_db_entry, query.name == program.name)
+ else:
+ self._programs.insert(program_db_entry)
+
+ def load(self, name):
+ with self.lock:
+ query = Query()
+ program_db_entries = self._programs.search(query.name == name)
+ if len(program_db_entries) > 0:
+ prog_db_entry = program_db_entries[0]
+ logging.debug(prog_db_entry)
+ self._program = Program.from_dict(prog_db_entry)
+ return self._program
+ return None
+
+ def delete(self, name):
+ with self.lock:
+ query = Query()
+ program_db_entries = self._programs.search(query.name == name)
+ self._programs.remove(query.name == name)
+
+ def create(self, name, code):
+ self._program = Program(name, code)
+ return self._program
+
+ def is_running(self, name):
+ return self._program.is_running() and self._program.name == name
+
+ def check_end(self):
+ return self._program.check_end()
+
+ def log(self, text):
+ self._log += text + "\n"
+
+ def get_log(self):
+ return self._log
+
+ def set_log(self, log):
+ self._log = ""
+
+ def get_current_program(self):
+ return self._program
+
+class Program:
+ _running = False
+
+ @property
+ def dom_code(self):
+ return self._dom_code
+
+ def __init__(self, name, code=None, dom_code=None, default=False):
+ self._thread = None
+ self.name = name
+ self._dom_code = dom_code
+ self._code = code
+ self._default = default
+
+ def execute(self, options={}):
+ if self._running:
+ raise RuntimeError('already running')
+
+ ProgramEngine.get_instance().set_log("")
+ self._running = True
+ try:
+ self._thread = threading.Thread(target=self.run, args=(options,))
+ self._thread.start()
+ except RuntimeError as re:
+ logging.error("RuntimeError: %s", str(re))
+ except Exception as e:
+ logging.error("Exception: %s", str(e))
+
+ return "ok"
+
+ def stop(self):
+ if self._running:
+ self._running = False
+ self._thread.join()
+
+ def check_end(self):
+ if self._running is False:
+ raise RuntimeError('stop requested')
+ return None
+
+ def is_running(self):
+ return self._running
+
+ def is_default(self):
+ return self._default
+
+ def run(self, *args):
+ options = args[0]
+ try:
+ program = self
+ try:
+ if options.get("autoRecVideo") == True:
+ get_cam().video_rec(program.name.replace(" ", "_"))
+ logging.debug("starting video")
+ except Exception as e:
+ logging.error("Camera not available: " + str(e))
+
+ self._log = "" #clear log
+ imports = "import json\n"
+ code = imports + self._code
+ env = globals()
+ logging.debug("** start code **\n"+str(code)+ "\n** end code **")
+ exec(code, env, env)
+ except RuntimeError as re:
+ logging.info("quit: %s", str(re))
+ get_prog_eng().log(str(re))
+ except Exception as e:
+ logging.info("quit: %s", str(e))
+ get_prog_eng().log(str(e))
+ finally:
+ try:
+ get_event().wait_event_generators()
+ get_event().unregister_listeners()
+ get_event().unregister_publishers()
+ except Exception as e:
+ logging.error("error polishing event system: %s", str(e))
+ try:
+ get_bot().stop()
+ get_cam().video_stop() #if video is running, stop it
+ get_cam().set_text("") #clear overlay text (if any)
+ get_motion().stop()
+ except Exception:
+ logging.error("Camera not available")
+ self._running = False
+
+
+ def as_dict(self):
+ return {'name': self.name,
+ 'dom_code': self._dom_code,
+ 'code': self._code,
+ 'default': self._default}
+
+ @classmethod
+ def from_dict(cls, amap):
+ return Program(name=amap['name'], dom_code=amap['dom_code'], code=amap['code'], default=amap.get('default', False))
diff --git a/coderbot/rotary_encoder/motorencoder.py b/coderbot/rotary_encoder/motorencoder.py
new file mode 100644
index 00000000..2b2ad82a
--- /dev/null
+++ b/coderbot/rotary_encoder/motorencoder.py
@@ -0,0 +1,183 @@
+import pigpio
+import threading
+from time import sleep, time
+
+from rotary_encoder.rotarydecoder import RotaryDecoder
+
+
+class MotorEncoder:
+ """ Class that handles rotary decoder motors modelisation
+
+ The support class RotaryDecoder decodes mechanical rotary encoder
+ pulses. See the file for more.
+
+ Every movement method must acquire lock in order not to have
+ concurrency problems on GPIO READ/WRITE """
+
+ # default constructor
+ def __init__(self, pi, enable_pin, forward_pin, backward_pin, feedback_pin_A, feedback_pin_B):
+ # setting pin variables
+ self._pi = pi
+ self._enable_pin = enable_pin
+ self._forward_pin = forward_pin
+ self._backward_pin = backward_pin
+ self._feedback_pin_A = feedback_pin_A
+ self._feedback_pin_B = feedback_pin_B
+
+ # setting movement variables
+ self._direction = 0
+ self._distance_per_tick = 0.06 #(mm)
+ self._ticks = 0
+ self._power = 0
+ self._encoder_speed = 0
+ self._is_moving = False
+
+ # quadrature encoder variables
+ self._start_timer = 0
+ self._current_timer = 0
+ self._ticks_threshold = 100
+ self._ticks_counter = 0
+
+ # other
+ self._encoder_lock = threading.RLock()
+ self._rotary_decoder = RotaryDecoder(pi, feedback_pin_A, feedback_pin_B, self.rotary_callback)
+
+ # GETTERS
+ # ticks
+ def ticks(self):
+ return self._ticks
+
+ # distance
+ def distance(self):
+ #return self._distance
+ return self._ticks * self._distance_per_tick
+
+ # direction
+ def direction(self):
+ return self._direction
+
+ # speed
+ def speed(self):
+ return self._encoder_speed
+
+ # is_moving
+ def is_moving(self):
+ return self._is_moving
+
+ # MOVEMENT
+ """ The stop function acquires the lock to operate on motor
+ then writes a 0 on movement pins to stop the motor
+ and releases the lock afterwards
+ Motor speed on range 0 - 100 already set on PWM_set_range(100)
+ if a time_elapse parameter value is provided, motion is locked
+ for a certain amount of time """
+
+ def control(self, power=100.0, time_elapse=0):
+ # resetting distance and ticks before new movement
+ self._distance = 0 # resetting distance travelled
+ self._ticks = 0 # resetting ticks
+
+ self._direction = 1 if power > 0 else -1 # setting direction according to speed
+ self._power = abs(power) # setting current power
+
+ if self._enable_pin is not None:
+ self._pi.write(self._enable_pin, True) # enabling motors
+
+ # going forward
+ if (self._direction == 1):
+ self._pi.write(self._backward_pin, 0)
+ self._pi.set_PWM_dutycycle(self._forward_pin, self._power)
+ # going bacakward
+ else:
+ self._pi.write(self._forward_pin, 0)
+ self._pi.set_PWM_dutycycle(self._backward_pin, self._power)
+
+ self._is_moving = True
+
+ # movement time elapse
+ if (time_elapse > 0):
+ sleep(time_elapse)
+ self.stop()
+
+ """ The stop function acquires the lock to operate on motor
+ then writes a 0 on movement pins to stop the motor
+ and releases the lock afterwards """
+
+ def stop(self):
+ # stopping motor
+ self._pi.write(self._backward_pin, 0)
+ self._pi.write(self._forward_pin, 0)
+
+ # resetting wheel state
+ self.reset_state()
+
+ # stop auxiliary function, resets wheel state
+ def reset_state(self):
+ # returning state variables to consistent state
+ # after stopping, values of distance and ticks remains until
+ # next movement
+ self._ticks = 0 # resetting ticks
+ self._power = 0 # resetting PWM power
+ self._encoder_speed = 0 # resetting encoder speed
+ self._direction = 0 # resetting direction
+ self._start_timer = 0
+ self._current_timer = 0
+ self._ticks_counter = 0
+ self._is_moving = False # resetting moving flag
+
+ # adjust power for velocity control loop
+ def adjust_power(self, power):
+ self._power = power # setting current power
+
+ # adjusting power forward
+ if (self._direction == 1):
+ self._pi.set_PWM_dutycycle(self._forward_pin, abs(power))
+ # adjusting power bacakward
+ else:
+ self._pi.set_PWM_dutycycle(self._backward_pin, abs(power))
+
+ # CALLBACK
+ """ The callback function rotary_callback is called on EITHER_EDGE by the
+ rotary_decoder with a parameter value of 1 (1 new tick)
+ - Gearbox ratio: 120:1 (1 wheel revolution = 120 motor revolution)
+ - Encoder ratio: 16:1 encoder ticks for 1 motor revolution
+ - 1 wheel revolution = 120 * 16 = 1920 ticks
+ - R = 32.5mm
+ - 1 wheel revolution = 2πR = 2 * π * 32.5mm = 204.2mm
+ - 3840 ticks = 204.2mm
+ - 1 tick = 0.053mm
+ - 1 tick : 0.053mm = x : 1000mm -> x = 18867 ticks approximately
+ So 0.053 is the ticks->distance(mm) conversion coefficient
+ The callback function calculates current velocity by taking groups of
+ ticks_threshold ticks"""
+ # callback function
+ def rotary_callback(self, tick):
+ self._encoder_lock.acquire()
+
+ # taking groups of n ticks each
+ if (self._ticks_counter == 0):
+ self._start_timer = tick # clock started
+ elif (abs(self._ticks_counter) == self._ticks_threshold):
+ self._current_timer = tick
+ elapse = (self._current_timer - self._start_timer) / 1000000.0 # calculating time elapse
+ # calculating current speed
+ self._encoder_speed = self._ticks_threshold * self._distance_per_tick / elapse # (mm/s)
+
+ self._ticks += 1 # updating ticks
+
+ if(abs(self._ticks_counter) < self._ticks_threshold):
+ self._ticks_counter += 1
+ else:
+ self._start_timer = tick # clock started
+ self._ticks_counter = 0
+
+ # updating ticks counter using module
+ # 0, 1, 2, ... 8, 9, 10, 0, 1, 2, ...
+ # not ideal, module on ticks counter not precise, may miss an interrupt
+ #self._ticks_counter += 1 % (self._ticks_threshold + 1)
+
+ self._encoder_lock.release() # releasing lock
+
+ # callback cancelling
+ def cancel_callback(self):
+ self._rotary_decoder.cancel()
diff --git a/coderbot/rotary_encoder/rotarydecoder.py b/coderbot/rotary_encoder/rotarydecoder.py
new file mode 100644
index 00000000..99fd8766
--- /dev/null
+++ b/coderbot/rotary_encoder/rotarydecoder.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+
+import pigpio
+import threading
+
+class RotaryDecoder:
+
+ """ Class to decode mechanical rotary encoder pulses """
+
+ def __init__(self, pi, feedback_pin_A, feedback_pin_B, callback):
+
+ self._pi = pi
+ self._feedback_pin_A = feedback_pin_A # encoder feedback pin A
+ self._feedback_pin_B = feedback_pin_B # encoder feedback pin B
+ self._callback = callback # callback function on event
+ self._direction = 0 # direction, forward = 1, backward = -1, steady = 0
+
+ self._levelA = 0 # value of encoder feedback pin A
+ self._levelB = 0 # value of encoder feedback pin B
+
+ self._lock = threading.RLock()
+
+ # setting up GPIO
+ self._pi.set_mode(feedback_pin_A, pigpio.INPUT)
+ self._pi.set_mode(feedback_pin_B, pigpio.INPUT)
+ self._pi.set_pull_up_down(feedback_pin_A, pigpio.PUD_UP)
+ self._pi.set_pull_up_down(feedback_pin_B, pigpio.PUD_UP)
+
+ # callback function on EITHER_EDGE for each pin
+ self._callback_triggerA = self._pi.callback(feedback_pin_A, pigpio.EITHER_EDGE, self._pulseA)
+ self._callback_triggerB = self._pi.callback(feedback_pin_B, pigpio.EITHER_EDGE, self._pulseA)
+
+ self._lastGpio = None
+
+ """ pulse is the callback function on EITHER_EDGE
+ We have two feedback input from pin A and B (two train waves)
+ it returns a 1 if the square waves have A leading B because we're moving forward
+ It returns a -1 if the square waves have B leading A because we're moving backwards
+ In either case, A is staggered from B by (+-)pi/2 radiants
+ Note: level = 0 falling edge
+ 1 raising edge
+ 2 from watchdog
+
+ +---------+ +---------+ 0
+ | | | |
+ B | | | |
+ | | | |
+ +---------+ +---------+ +----- 1 # B leading A
+ +---------+ +---------+ 0 # forward
+ | | | |
+ A | | | |
+ | | | |
+ ----+ +---------+ +----------+ 1
+
+
+ +---------+ +---------+ 0
+ | | | |
+ A | | | |
+ | | | |
+ ----+ +---------+ +----------+ 1 # A leading B
+ +---------+ +---------+ 0 # backward
+ | | | |
+ B | | | |
+ | | | |
+ +---------+ +---------+ +----- 1
+ """
+ def _pulse(self, gpio, level, tick):
+ self._lock.acquire()
+ # interrupt comes from pin A
+ if (gpio == self._feedback_pin_A):
+ self._levelA = level # set level of squared wave (0, 1) on A
+ # interrupt comes from pin B
+ else:
+ self._levelB = level # set level of squared wave (0, 1) on B
+
+ if (gpio != self._lastGpio): # debounce
+ self._lastGpio = gpio
+
+ # forward (A leading B)
+ if (gpio == self._feedback_pin_A and
+ ((level == 1 and self._levelB == 0) or
+ (level == 0 and self._levelB == 1))):
+ self._direction = 1 # forward
+ # backward (B leading A)
+ elif (gpio == self._feedback_pin_B and
+ ((level == 1 and self._levelA == 0) or
+ (level == 0 and self._levelA == 1))):
+ self._direction = -1 # forward
+
+ direction = self._direction
+ self._lock.release()
+ self._callback(direction)
+
+ def _pulseA(self, gpio, level, tick):
+ self._callback(tick)
+
+ def cancel(self):
+
+ """
+ Cancel the rotary encoder decoder callbacks.
+ """
+ self._callback_triggerA.cancel()
+ self._callback_triggerB.cancel()
+
+
diff --git a/coderbot/rotary_encoder/wheelsaxel.py b/coderbot/rotary_encoder/wheelsaxel.py
new file mode 100644
index 00000000..abfef001
--- /dev/null
+++ b/coderbot/rotary_encoder/wheelsaxel.py
@@ -0,0 +1,319 @@
+import pigpio
+import threading
+from time import sleep, time
+import logging
+
+from rotary_encoder.motorencoder import MotorEncoder
+
+class WheelsAxel:
+ """ Class that handles both motor encoders, left and right
+
+ This class works like a wheels axle, coordinating left and right
+ wheels at the same time
+
+ It also tries to handle the inconsistent tension on wheels
+ that makes one wheel go slower than the other """
+
+ def __init__(self, pi, enable_pin,
+ left_forward_pin, left_backward_pin, left_encoder_feedback_pin_A, left_encoder_feedback_pin_B,
+ right_forward_pin, right_backward_pin, right_encoder_feedback_pin_A, right_encoder_feedback_pin_B,
+ pid_params):
+
+ # state variables
+ self._is_moving = False
+
+ # left motor
+ self._left_motor = MotorEncoder(pi,
+ enable_pin,
+ left_forward_pin,
+ left_backward_pin,
+ left_encoder_feedback_pin_A,
+ left_encoder_feedback_pin_B)
+ # right motor
+ self._right_motor = MotorEncoder(pi,
+ enable_pin,
+ right_backward_pin,
+ right_forward_pin,
+ right_encoder_feedback_pin_A,
+ right_encoder_feedback_pin_B)
+
+ self.pid_kp = pid_params[0]
+ self.pid_kd = pid_params[1]
+ self.pid_ki = pid_params[2]
+ self.pid_max_speed = pid_params[3]
+ self.pid_sample_time = pid_params[4]
+
+ # other
+ #self._wheelsAxle_lock = threading.RLock() # race condition lock
+
+ # STATE GETTERS
+ """ Distance and speed are calculated by a mean of the feedback
+ from the two motors """
+
+ def is_moving(self):
+ return self._left_motor.is_moving() or self._right_motor.is_moving()
+
+ # distance
+ def distance(self):
+ l_dist = self._left_motor.distance()
+ r_dist = self._right_motor.distance()
+ return (l_dist + r_dist) * 0.5
+
+ #speed
+ def speed(self):
+ l_speed = self._left_motor.speed()
+ r_speed = self._right_motor.speed()
+ return (l_speed + r_speed) * 0.5
+
+ #direction
+ def direction(self):
+ l_dir = self._left_motor.direction()
+ r_dir = self._right_motor.direction()
+ if(l_dir == r_dir):
+ return l_dir
+ else:
+ return 0
+
+ # MOVEMENT
+ """ Movement wrapper method
+ if time is specified and distance is not, control_time is called
+ if distance is specified and time is not, control_distance is called
+ if both distance and time are specified, control_velocity is called """
+ def control(self, power_left=100, power_right=100, time_elapse=None, target_distance=None):
+ if(time_elapse is not None and target_distance is None): # time
+ self.control_time(power_left, power_right, time_elapse)
+ elif(time_elapse is None and target_distance is not None): # distance
+ self.control_distance(power_left, power_right, target_distance)
+ else: # velocity
+ self.control_velocity(time_elapse, target_distance)
+
+ """ Motor time control allows the motors
+ to run for a certain amount of time """
+ def control_time(self, power_left=100, power_right=100, time_elapse=-1):
+ if time_elapse > 0:
+ return self.control_time_encoder(power_left, power_right, time_elapse)
+
+ # applying tension to motors
+ self._left_motor.control(power_left, -1)
+ self._right_motor.control(power_right, -1)
+ self._is_moving = True
+
+ # moving for desired time
+ # fixed for direct control that uses time_elapse -1 and stops manually
+ if(time_elapse > 0):
+ sleep(time_elapse)
+ self.stop()
+
+ """ Motor time control allows the motors
+ to run for a certain amount of time """
+ def control_time_encoder(self, power_left=100, power_right=100, time_elapse=-1):
+ #self._wheelsAxle_lock.acquire() # wheelsAxle lock acquire
+ self._is_moving = True
+
+ # get desired direction from power, then normalize on power > 0
+ left_direction = power_left/abs(power_left)
+ right_direction = power_right/abs(power_right)
+ power_left = abs(power_left)
+ power_right = abs(power_right)
+
+ self._left_motor.reset_state()
+ self._right_motor.reset_state()
+
+ # applying tension to motors
+ self._left_motor.control(power_left * left_direction)
+ self._right_motor.control(power_right * right_direction)
+
+ #PID parameters
+ # assuming that power_right is equal to power_left and that coderbot
+ # moves at 11.5mm/s at full PWM duty cycle
+
+ target_speed_left = (self.pid_max_speed / 100) * power_left #velocity [mm/s]
+ target_speed_right = (self.pid_max_speed / 100) * power_right # velocity [mm/s]
+
+ left_derivative_error = 0
+ right_derivative_error = 0
+ left_integral_error = 0
+ right_integral_error = 0
+ left_prev_error = 0
+ right_prev_error = 0
+ time_init = time()
+
+ # moving for certaing amount of distance
+ logging.info("moving? " + str(self._is_moving) + " distance: " + str(self.distance()) + " target: " + str(time_elapse))
+ while(time() - time_init < time_elapse and self._is_moving == True):
+ # PI controller
+ logging.debug("speed.left: " + str(self._left_motor.speed()) + " speed.right: " + str(self._right_motor.speed()))
+ if(abs(self._left_motor.speed()) > 10 and abs(self._right_motor.speed()) > 10):
+ # relative error
+ left_error = float(target_speed_left - self._left_motor.speed()) / target_speed_left
+ right_error = float(target_speed_right - self._right_motor.speed()) / target_speed_right
+
+ left_correction = (left_error * self.pid_kp) + (left_derivative_error * self.pid_kd) + (left_integral_error * self.pid_ki)
+ right_correction = (right_error * self.pid_kp) + (right_derivative_error * self.pid_kd) + (right_integral_error * self.pid_ki)
+
+ corrected_power_left = power_left + (left_correction * power_left)
+ corrected_power_right = power_right + (right_correction * power_right)
+
+ #print("LEFT correction: %f" % (left_error * KP + left_derivative_error * KD + left_integral_error * KI))
+ #print("RIGHT correction: %f" % (right_error * KP + right_derivative_error * KD + right_integral_error * KI))
+
+ # conrispondent new power
+ power_left_norm = max(min(corrected_power_left, power_left), 0)
+ power_right_norm = max(min(corrected_power_right, power_right), 0)
+
+ logging.debug("ls:" + str(int(self._left_motor.speed())) + " rs: " + str(int(self._right_motor.speed())) +
+ " le:" + str(left_error) + " re: " + str(right_error) +
+ " ld:" + str(left_derivative_error) + " rd: " + str(right_derivative_error) +
+ " li:" + str(left_integral_error) + " ri: " + str(right_integral_error) +
+ " lc: " + str(int(left_correction)) + " rc: " + str(int(right_correction)) +
+ " lp: " + str(int(power_left_norm)) + " rp: " + str(int(power_right_norm)))
+
+ # adjusting power on each motors
+ self._left_motor.adjust_power(power_left_norm * left_direction )
+ self._right_motor.adjust_power(power_right_norm * right_direction)
+
+ left_derivative_error = (left_error - left_prev_error) / self.pid_sample_time
+ right_derivative_error = (right_error - right_prev_error) / self.pid_sample_time
+ left_integral_error += (left_error * self.pid_sample_time)
+ right_integral_error += (right_error * self.pid_sample_time)
+
+ left_prev_error = left_error
+ right_prev_error = right_error
+
+ # checking each SAMPLETIME seconds
+ sleep(self.pid_sample_time)
+
+ logging.info("control_distance.stop, target elapse: " + str(time_elapse) +
+ " actual distance: " + str(self.distance()) +
+ " l ticks: " + str(self._left_motor.ticks()) +
+ " r ticks: " + str(self._right_motor.ticks()))
+ # robot arrived
+ self.stop()
+
+ """ Motor distance control allows the motors
+ to run for a certain amount of distance (mm) """
+ def control_distance(self, power_left=100, power_right=100, target_distance=0):
+ #self._wheelsAxle_lock.acquire() # wheelsAxle lock acquire
+ self._is_moving = True
+
+ # get desired direction from power, then normalize on power > 0
+ left_direction = power_left/abs(power_left)
+ right_direction = power_right/abs(power_right)
+ power_left = abs(power_left)
+ power_right = abs(power_right)
+
+ self._left_motor.reset_state()
+ self._right_motor.reset_state()
+
+ # applying tension to motors
+ self._left_motor.control(power_left * left_direction)
+ self._right_motor.control(power_right * right_direction)
+
+ #PID parameters
+ # assuming that power_right is equal to power_left and that coderbot
+ # moves at 11.5mm/s at full PWM duty cycle
+
+ target_speed_left = (self.pid_max_speed / 100) * power_left #velocity [mm/s]
+ target_speed_right = (self.pid_max_speed / 100) * power_right # velocity [mm/s]
+
+ # SOFT RESPONSE
+ # KP = 0.04 #proportional coefficient
+ # KD = 0.02 # derivative coefficient
+ # KI = 0.005 # integral coefficient
+
+ # MEDIUM RESPONSE
+ # KP = 0.9 # proportional coefficient
+ # KD = 0.1 # derivative coefficient
+ # KI = 0.05 # integral coefficient
+
+ # STRONG RESPONSE
+ # KP = 0.9 # proportional coefficient
+ # KD = 0.05 # derivative coefficient
+ # KI = 0.03 # integral coefficient
+
+ left_derivative_error = 0
+ right_derivative_error = 0
+ left_integral_error = 0
+ right_integral_error = 0
+ left_prev_error = 0
+ right_prev_error = 0
+ # moving for certaing amount of distance
+ logging.info("moving? " + str(self._is_moving) + " distance: " + str(self.distance()) + " target: " + str(target_distance))
+ while(abs(self.distance()) < abs(target_distance) and self._is_moving == True):
+ # PI controller
+ logging.debug("speed.left: " + str(self._left_motor.speed()) + " speed.right: " + str(self._right_motor.speed()))
+ if(abs(self._left_motor.speed()) > 10 and abs(self._right_motor.speed()) > 10):
+ # relative error
+ left_error = float(target_speed_left - self._left_motor.speed()) / target_speed_left
+ right_error = float(target_speed_right - self._right_motor.speed()) / target_speed_right
+
+ left_correction = (left_error * self.pid_kp) + (left_derivative_error * self.pid_kd) + (left_integral_error * self.pid_ki)
+ right_correction = (right_error * self.pid_kp) + (right_derivative_error * self.pid_kd) + (right_integral_error * self.pid_ki)
+
+ corrected_power_left = power_left + (left_correction * power_left)
+ corrected_power_right = power_right + (right_correction * power_right)
+
+ #print("LEFT correction: %f" % (left_error * KP + left_derivative_error * KD + left_integral_error * KI))
+ #print("RIGHT correction: %f" % (right_error * KP + right_derivative_error * KD + right_integral_error * KI))
+
+ # conrispondent new power
+ power_left_norm = max(min(corrected_power_left, power_left), 0)
+ power_right_norm = max(min(corrected_power_right, power_right), 0)
+
+ logging.debug("ls:" + str(int(self._left_motor.speed())) + " rs: " + str(int(self._right_motor.speed())) +
+ " le:" + str(left_error) + " re: " + str(right_error) +
+ " ld:" + str(left_derivative_error) + " rd: " + str(right_derivative_error) +
+ " li:" + str(left_integral_error) + " ri: " + str(right_integral_error) +
+ " lc: " + str(int(left_correction)) + " rc: " + str(int(right_correction)) +
+ " lp: " + str(int(power_left_norm)) + " rp: " + str(int(power_right_norm)))
+
+ # adjusting power on each motors
+ self._left_motor.adjust_power(power_left_norm * left_direction )
+ self._right_motor.adjust_power(power_right_norm * right_direction)
+
+ left_derivative_error = (left_error - left_prev_error) / self.pid_sample_time
+ right_derivative_error = (right_error - right_prev_error) / self.pid_sample_time
+ left_integral_error += (left_error * self.pid_sample_time)
+ right_integral_error += (right_error * self.pid_sample_time)
+
+ left_prev_error = left_error
+ right_prev_error = right_error
+
+ # checking each SAMPLETIME seconds
+ sleep(self.pid_sample_time)
+
+ logging.info("control_distance.stop, target dist: " + str(target_distance) +
+ " actual distance: " + str(self.distance()) +
+ " l ticks: " + str(self._left_motor.ticks()) +
+ " r ticks: " + str(self._right_motor.ticks()))
+ # robot arrived
+ self.stop()
+
+ """ Motor speed control to travel given distance
+ in given time adjusting power on motors
+ NOT very intuitive, idea has been postponed"""
+ def control_velocity(self, time_elapse=0, target_distance=0):
+ pass
+
+ """ The stop function calls the two stop functions of the two
+ correspondent motors.
+ Locks are automatically obtained """
+ def stop(self):
+ # stopping left and right motors
+ self._left_motor.stop()
+ self._right_motor.stop()
+
+ # trying to fix distance different than zero after
+ # wheels has stopped by re-resetting state after 0.5s
+
+ #self._left_motor.reset_state()
+ #self._right_motor.reset_state()
+
+ # updating state
+ logging.info("stopping")
+ self._is_moving = False
+
+ # CALLBACK
+ def cancel_callback(self):
+ self._right_motor.cancel_callback()
+ self._left_motor.cancel_callback()
diff --git a/coderbot/runtime_test.py b/coderbot/runtime_test.py
new file mode 100644
index 00000000..4a6260a5
--- /dev/null
+++ b/coderbot/runtime_test.py
@@ -0,0 +1,142 @@
+"""
+ This file defines base tests for CoderBot
+ in order to test its functionality
+
+ The function run_test(varargin) lanuches tests
+ according to required test from the front-end.
+ e.g. varagrin = ["motor_test", "sonar_test"]
+ __test_encoder() and __test_sonar() will be launched.
+
+ If something goes wrong a -1 is returned for the correspondent failed test.
+ If a test passes for correspondent component, a 1 is returned.
+ If no test was executed on that component, 0 is preserved.
+"""
+import logging
+from coderbot import CoderBot
+
+# Single components tests
+
+# encoder motors
+def __test_encoder():
+ try:
+ c = CoderBot.get_instance()
+ # moving both wheels at speed 100 clockwise
+ logging.info("moving both wheels at speed 100 clockwise")
+ assert(c.speed() == 0)
+ c.move(speed=100, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # moving both wheels at speed 40 clockwise
+ logging.info("moving both wheels at speed 40 clockwise")
+ assert(c.speed() == 0)
+ c.move(speed=40, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # moving both wheels at speed 100 counter-clockwise
+ logging.info("moving both wheels at speed 100 counter-clockwise")
+ assert(c.speed() == 0)
+ c.move(speed=-100, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # moving both wheels at speed 40 counter-clockwise
+ logging.info("moving both wheels at speed 40 counter-clockwise")
+ assert(c.speed() == 0)
+ c.move(speed=-40, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # moving forward
+ logging.info("moving forward")
+ assert(c.speed() == 0)
+ c.forward(speed=100, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # moving backwards
+ logging.info("moving backwards")
+ assert(c.speed() == 0)
+ c.backward(speed=100, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # moving forward for 1 meter
+ logging.info("moving forward for 1 meter")
+ assert(c.speed() == 0)
+ c.forward(speed=100, distance=1000)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # moving backwards for 1 meter
+ logging.info("moving backwards for 1 meter")
+ assert(c.speed() == 0)
+ c.backward(speed=100, distance=1000)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # turning left
+ logging.info("turning left")
+ assert(c.speed() == 0)
+ c.left(speed=100, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ # turning right
+ logging.info("turning right")
+ assert(c.speed() == 0)
+ c.right(speed=100, elapse=2)
+ assert(c.distance() != 0)
+ assert (c.speed() == 0)
+
+ return 1
+ except:
+ return -1
+
+# sonar
+def __testSonar():
+ return 1
+
+# speaker
+def __test_speaker():
+ return 1
+
+# OCR
+def __test_OCR():
+ return 1
+
+# add more tests here
+
+""" Main test function
+ it launches tests to test single components individually.
+ A dictionary is returned monitoring the state of the
+ tests for each component.
+ Varargin is a list of strings that indicates which test
+ to run. """
+def run_test(varargin):
+ # state for each executed test
+ # 0 = component not tested
+ # 1 = test passed
+ # -1 = test failed
+ tests_state = {
+ "motors": 0,
+ "sonar": 0,
+ "speaker": 0,
+ "OCR": 0
+ # add more tests state here
+ }
+
+ # running chosen tests
+ for test in varargin:
+ if(test == 'motors'):
+ tests_state[test] = __test_encoder()
+ elif(test == 'sonar'):
+ tests_state[test] = __testSonar()
+ elif (test == 'speaker'):
+ tests_state[test] = __test_speaker()
+ elif(test == 'ocr'):
+ tests_state[test] = __test_OCR()
+ #add more test cases here
+
+ return tests_state
diff --git a/coderbot/sonar.py b/coderbot/sonar.py
new file mode 100644
index 00000000..e54f7a19
--- /dev/null
+++ b/coderbot/sonar.py
@@ -0,0 +1,94 @@
+import time
+import pigpio
+import logging
+
+class Sonar:
+ """
+ This class encapsulates a type of acoustic ranger. In particular
+ the type of ranger with separate trigger and echo pins.
+
+ A pulse on the trigger initiates the sonar ping and shortly
+ afterwards a sonar pulse is transmitted and the echo pin
+ goes high. The echo pins stays high until a sonar echo is
+ received (or the response times-out). The time between
+ the high and low edges indicates the sonar round trip time.
+ """
+
+ MICROSECONDS = 1000000.0
+ SOUND_SPEED = 34030.0
+ ECHO_TIMEOUT = 0.1
+
+ def __init__(self, pi, trigger, echo):
+ """
+ The class is instantiated with the Pi to use and the
+ gpios connected to the trigger and echo pins.
+ """
+ self.pi = pi
+ self._trig = trigger
+ self._echo = echo
+
+ self._ping = False
+ self._high = None
+ self._time = None
+
+ self._triggered = False
+
+ self._trig_mode = pi.get_mode(self._trig)
+ self._echo_mode = pi.get_mode(self._echo)
+
+ pi.set_mode(self._trig, pigpio.OUTPUT)
+ pi.set_mode(self._echo, pigpio.INPUT)
+
+ self._cb = pi.callback(self._trig, pigpio.EITHER_EDGE, self._cbf)
+ self._cb = pi.callback(self._echo, pigpio.EITHER_EDGE, self._cbf)
+
+ self._inited = True
+
+ def _cbf(self, gpio, level, tick):
+ if gpio == self._trig and self._triggered == False:
+ if level == 0: # trigger sent
+ self._triggered = True
+ self._high = None
+ else:
+ if self._triggered:
+ if level == 1:
+ self._high = tick
+ else:
+ if self._high is not None:
+ self._time = tick - self._high
+ self._high = None
+ self._ping = True
+ self._triggered = False
+ def read(self):
+ """
+ Triggers a reading. The returned reading is the number
+ of microseconds for the sonar round-trip.
+
+ round trip cms = round trip time / 1000000.0 * 34030
+ """
+ if self._inited:
+ self._ping = False
+ self.pi.gpio_trigger(self._trig)
+ start = time.time()
+ while not self._ping:
+ if (time.time()-start) > self.ECHO_TIMEOUT:
+ return 20000
+ time.sleep(0.001)
+ return self._time
+ else:
+ return None
+
+ def get_distance(self):
+ time.sleep(0.05)
+ return round(self.read() / self.MICROSECONDS * self.SOUND_SPEED / 2, 1) # seconds / microseconds * sound speed / 2 (half trip)
+
+ def cancel(self):
+ """
+ Cancels the sonars and returns the gpios to their
+ original mode.
+ """
+ if self._inited:
+ self._inited = False
+ self._cb.cancel()
+ self.pi.set_mode(self._trig, self._trig_mode)
+ self.pi.set_mode(self._echo, self._echo_mode)
diff --git a/coderbot/v1.yml b/coderbot/v1.yml
new file mode 100644
index 00000000..37142724
--- /dev/null
+++ b/coderbot/v1.yml
@@ -0,0 +1,765 @@
+openapi: "3.0.0"
+info:
+ version: "1.0"
+ title: OpenAPI 3.0 definition of Coderbot API v3
+
+servers:
+ - url: http://coderbot.local/api/v1
+
+# Paths supported by the server application
+paths:
+ /settings:
+ get:
+ operationId: "api.loadSettings"
+ summary: "Load settings"
+ responses:
+ 200:
+ description: "ok"
+ tags:
+ - CoderBot configuration
+ put:
+ operationId: "api.saveSettings"
+ summary: "Save settings"
+ requestBody:
+ description: Save Settings
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Settings'
+ responses:
+ 200:
+ description: "ok"
+ tags:
+ - CoderBot configuration
+ /settings/restore:
+ post:
+ operationId: "api.restoreSettings"
+ summary: "Restore settings to default"
+ responses:
+ 200:
+ description: "ok"
+ tags:
+ - CoderBot configuration
+ /media:
+ get:
+ operationId: "api.listPhotos"
+ summary: "Get the list of all photos"
+ tags:
+ - Photos management
+ responses:
+ 200:
+ description: "ok"
+ post:
+ operationId: "api.takePhoto"
+ summary: "take a new photo"
+ tags:
+ - Photos management
+ responses:
+ 200:
+ description: "ok"
+ /media/{name}:
+ get:
+ operationId: "api.getPhoto"
+ summary: "Get photo by name"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 16
+ pattern: '^(DSC|VID)+[0-9]+(_thumb)?\.?(jpg|mp4)?$'
+ tags:
+ - Photos management
+ responses:
+ 200:
+ description: Image in JPEG format
+ content:
+ image/jpeg:
+ schema:
+ type: string
+ format: binary
+ put:
+ operationId: "api.savePhoto"
+ summary: "Save photo by name"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 16
+ pattern: '^(DSC|VID)+[0-9]+(_thumb)?\.?(jpg|mp4)?$'
+ requestBody:
+ description: Save Photo metadata
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Photo'
+ tags:
+ - Photos management
+ responses:
+ 200:
+ description: "ok"
+ delete:
+ operationId: "api.deletePhoto"
+ summary: "Delete photo by name"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 16
+ pattern: '^(DSC|VID)+[0-9]+(_thumb)?\.?(jpg|mp4)?$'
+ tags:
+ - Photos management
+ responses:
+ 200:
+ description: "ok"
+ /video/stream:
+ get:
+ operationId: "api.streamVideo"
+ summary: "Stream video"
+ tags:
+ - Video management
+ responses:
+ 200:
+ description: "ok"
+ /video/rec:
+ post:
+ operationId: "api.recVideo"
+ summary: "Rec video"
+ tags:
+ - Video management
+ responses:
+ 200:
+ description: "ok"
+ /video/stop:
+ post:
+ operationId: "api.stopVideo"
+ summary: "Stop rec video"
+ tags:
+ - Video management
+ responses:
+ 200:
+ description: "ok"
+
+ /programs:
+ get:
+ operationId: "api.listPrograms"
+ summary: "Get the list of all the saved programs"
+ tags:
+ - Program management
+ responses:
+ 200:
+ description: "ok"
+
+ /programs/{name}:
+ get:
+ operationId: "api.loadProgram"
+ summary: "Get the program with the specified name"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+
+ tags:
+ - Program management
+ responses:
+ 200:
+ description: "ok"
+ delete:
+ operationId: "api.deleteProgram"
+ summary: "Delete a program"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ responses:
+ 200:
+ description: "ok"
+ tags:
+ - Program management
+ put:
+ operationId: "api.saveProgram"
+ summary: "Save an existing program"
+ tags:
+ - Program management
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ requestBody:
+ description: Program object
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Program'
+ responses:
+ 200:
+ description: "ok"
+ 400:
+ description: "Failed to save the program"
+
+ /programs/{name}/run:
+ post:
+ operationId: "api.runProgram"
+ summary: "Execute the given program"
+ tags:
+ - Program management
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ requestBody:
+ description: Program object
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Program'
+ responses:
+ 200:
+ description: "ok"
+
+ /programs/{name}/status:
+ get:
+ operationId: "api.statusProgram"
+ summary: "Get the status of the given program"
+ tags:
+ - Program management
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ responses:
+ 200:
+ description: "ok"
+
+ /programs/{name}/stop:
+ patch:
+ operationId: "api.stopProgram"
+ summary: "Stop the given program"
+ tags:
+ - Program management
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ responses:
+ 200:
+ description: "ok"
+
+ /activities:
+ get:
+ operationId: "api.listActivities"
+ summary: "Get the list of all the saved activities"
+ tags:
+ - Activity management
+ responses:
+ 200:
+ description: "ok"
+ post:
+ operationId: "api.saveAsNewActivity"
+ summary: "Save a new activity"
+ tags:
+ - Activity management
+ requestBody:
+ description: Create new Activity
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Activity'
+ responses:
+ 200:
+ description: "ok"
+ 400:
+ description: "Failed to save the activity"
+ /activities/{name}:
+ get:
+ operationId: "api.loadActivity"
+ summary: "Get the activity with the specified name"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ - name: default
+ in: query
+ schema:
+ type: string
+ required: false
+ tags:
+ - Activity management
+ responses:
+ 200:
+ description: "ok"
+ put:
+ operationId: "api.saveActivity"
+ summary: "Save the activity with the specified name"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ requestBody:
+ description: Update Activity
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Activity'
+ tags:
+ - Activity management
+ responses:
+ 200:
+ description: "ok"
+ delete:
+ operationId: "api.deleteActivity"
+ summary: "Delete an activity"
+ tags:
+ - Activity management
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ responses:
+ 200:
+ description: "ok"
+
+ /music/packages:
+ get:
+ operationId: "api.listMusicPackages"
+ summary: "List Music Packages"
+ responses:
+ 200:
+ description: "ok"
+ tags:
+ - Music extensions
+ post:
+ operationId: "api.addMusicPackage"
+ summary: "Add Music Package"
+ requestBody:
+ description: Add a Music Package
+ required: true
+ content:
+ application/x-www-form-urlencoded:
+ schema:
+ type: object
+ tags:
+ - System operations
+ responses:
+ 200:
+ description: "ok"
+ 400:
+ description: "upload failed"
+ /music/packages/{name}:
+ delete:
+ operationId: "api.deleteMusicPackage"
+ summary: "Delete Music Package"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ tags:
+ - Music extensions
+ responses:
+ 200:
+ description: "ok"
+ 400:
+ description: "not found"
+
+ /system/status:
+ get:
+ operationId: "api.get_status"
+ summary: "Bot general informations, execution status and reset log file"
+ tags:
+ - System operations
+ responses:
+ 200:
+ description: "Bot status"
+
+ /system/test:
+ post:
+ summary: Tests CoderBot components.
+ operationId: "api.testCoderbot"
+ tags:
+ - System operations
+ requestBody:
+ description: Performs onboard tests
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ tests:
+ type: array
+ items:
+ type: string
+ responses:
+ 200:
+ description: Test ended.
+ 400:
+ description: Invalid input.
+
+ /system/info:
+ get:
+ operationId: "api.get_info"
+ summary: "Bot general informations and execution status"
+ tags:
+ - System operations
+ responses:
+ 200:
+ description: "Bot status"
+
+ /control/stop:
+ post:
+ operationId: "api.stop"
+ summary: Stops the bot motors
+ tags:
+ - Direct control
+ responses:
+ 200:
+ description: "Successfully stopped the motors"
+
+ /control/move:
+ post:
+ summary: Moves the bot forward or backward.
+ operationId: "api.move"
+ tags:
+ - Direct control
+ requestBody:
+ description: Movement speed and duration or distance
+ required: true
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/MoveParamsElapse'
+ - $ref: '#/components/schemas/MoveParamsDistance'
+ responses:
+ 200:
+ description: Sent command to the bot GPIO.
+ /control/turn:
+ post:
+ summary: Make a turn with the motors
+ operationId: "api.turn"
+ tags:
+ - Direct control
+ requestBody:
+ description: Movement Speed and duration or distance
+ required: true
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/TurnParamsElapse'
+ - $ref: '#/components/schemas/TurnParamsDistance'
+ responses:
+ 200:
+ description: Sent command to the bot GPIO.
+ /control/speak:
+ post:
+ operationId: "api.speak"
+ summary: Pronounce a phrase
+ tags:
+ - Direct control
+ requestBody:
+ description: Movement Speed and duration
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ text:
+ type: string
+ minLength: 1
+ maxLength: 256
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ description: text to be "spoken"
+ locale:
+ type: string
+ minLength: 1
+ maxLength: 2
+ pattern: '^[a-zA-Z]+$'
+ description: locale of text to be "spoken"
+ required:
+ - text
+ - locale
+ responses:
+ 200:
+ description: "phrase received"
+ /system/halt:
+ post:
+ operationId: "api.halt"
+ summary: Halt system (system shutdown)
+ tags:
+ - System operations
+ responses:
+ 200:
+ description: "accepted"
+ /system/reset:
+ post:
+ operationId: "api.reset"
+ summary: Reset all local configuration to factory state
+ tags:
+ - System operations
+ responses:
+ 200:
+ description: ""
+ /system/restart:
+ post:
+ operationId: "api.restart"
+ summary: Restart backend
+ tags:
+ - System operations
+ responses:
+ 200:
+ description: "accepted"
+ /system/reboot:
+ post:
+ operationId: "api.reboot"
+ summary: Reboot all device
+ tags:
+ - System operations
+ responses:
+ 200:
+ description: "accepted"
+
+ /cnnmodels:
+ get:
+ operationId: "api.listCNNModels"
+ summary: "list of CNN Models"
+ tags:
+ - CNN Models
+ responses:
+ 200:
+ description: "CNN Models as JSON Object"
+ post:
+ operationId: "api.trainCNNModel"
+ summary: "train new CNN Model"
+ requestBody:
+ description: CNN Model parameters
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ tags:
+ - CNN Models
+ responses:
+ 200:
+ description: "CNN Models as JSON Object"
+ /cnnmodels/{name}:
+ get:
+ operationId: "api.getCNNModel"
+ summary: "get CNN Model"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ tags:
+ - CNN Models
+ responses:
+ 200:
+ description: "CNN Model as JSON Object"
+ delete:
+ operationId: "api.deleteCNNModel"
+ summary: "delete CNN Model"
+ parameters:
+ - name: name
+ in: path
+ required: true
+ schema:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ tags:
+ - CNN Models
+ responses:
+ 200:
+ description: "CNN Model deleted"
+
+components:
+ schemas:
+ MoveParamsElapse:
+ type: object
+ properties:
+ speed:
+ type: number
+ minimum: -100.0
+ maximum: 100.0
+ description: 0 to 100 represent a forward movement (100 being the maximum speed), while 0 to -100 is a backward movement (-100 being the maximu speed)
+ elapse:
+ type: number
+ minimum: -1.0
+ maximum: 10.0
+ description: Duration of the movement. 0 doesn't move the coderbot.
+ required:
+ - speed
+ - elapse
+ MoveParamsDistance:
+ type: object
+ properties:
+ speed:
+ type: number
+ minimum: -100.0
+ maximum: 100.0
+ description: 0 to 100 represent a forward movement (100 being the maximum speed), while 0 to -100 is a backward movement (-100 being the maximu speed)
+ distance:
+ type: number
+ minimum: 0.0
+ maximum: 1000.0
+ description: Target distqnce in mm.
+ required:
+ - speed
+ - distance
+ TurnParamsElapse:
+ type: object
+ properties:
+ speed:
+ type: number
+ minimum: -100.0
+ maximum: 100.0
+ description: 0 to 100 represent a forward movement (100 being the maximum speed), while 0 to -100 is a backward movement (-100 being the maximu speed)
+ elapse:
+ type: number
+ minimum: -1.0
+ maximum: 1.0
+ description: Duration of the movement. 0 doesn't move the coderbot.
+ required:
+ - speed
+ - elapse
+ TurnParamsDistance:
+ type: object
+ properties:
+ speed:
+ type: number
+ minimum: -100.0
+ maximum: 100.0
+ description: 0 to 100 represent a forward movement (100 being the maximum speed), while 0 to -100 is a backward movement (-100 being the maximu speed)
+ distance:
+ type: number
+ minimum: 0.0
+ maximum: 100000.0
+ description: Target distqnce in mm.
+ required:
+ - speed
+ - distance
+ Settings:
+ type: object
+ Photo:
+ type: object
+ properties:
+ name:
+ type: string
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ tag:
+ type: string
+ Program:
+ type: object
+ properties:
+ name:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ code:
+ type: string
+ minLength: 1
+ dom_code:
+ type: string
+ default:
+ type: boolean
+ overwrite:
+ type: boolean
+ required:
+ - name
+ - code
+
+ Activity:
+ type: object
+ properties:
+ name:
+ type: string
+ minLength: 1
+ maxLength: 128
+ pattern: '^[a-zA-ZA-zÀ-ú0-9-_ ]+$'
+ description:
+ type: string
+ minLength: 0
+ maxLength: 256
+ default:
+ type: boolean
+ stock:
+ type: boolean
+ required:
+ - name
+ - description
+ - default
+ - stock
+
\ No newline at end of file
diff --git a/coderdojo-logo.png b/coderdojo-logo.png
deleted file mode 100644
index 93a07e8d..00000000
Binary files a/coderdojo-logo.png and /dev/null differ
diff --git a/data/.gitkeep b/data/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/data/media/.gitkeep b/data/media/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/data/media/metadata.json b/data/media/metadata.json
new file mode 100644
index 00000000..0637a088
--- /dev/null
+++ b/data/media/metadata.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/data/program_David.data b/data/program_David.data
deleted file mode 100644
index ad57ecd9..00000000
--- a/data/program_David.data
+++ /dev/null
@@ -1 +0,0 @@
-3232423
\ No newline at end of file
diff --git a/data/program_Rob.data b/data/program_Rob.data
deleted file mode 100644
index 56129165..00000000
--- a/data/program_Rob.data
+++ /dev/null
@@ -1 +0,0 @@
-FORWARD701RIGHT700.35FORWARD701LEFT700.35FORWARD701
\ No newline at end of file
diff --git a/data/program_camera.data b/data/program_camera.data
deleted file mode 100644
index 0dfe58ed..00000000
--- a/data/program_camera.data
+++ /dev/null
@@ -1 +0,0 @@
-WHILETRUEGTE16FORWARD800.10.3WHILELT16RIGHT700.10.3WHILELT16LEFT700.10.3
\ No newline at end of file
diff --git a/data/program_davide.data b/data/program_davide.data
deleted file mode 100644
index 376c911f..00000000
--- a/data/program_davide.data
+++ /dev/null
@@ -1 +0,0 @@
-4242525
\ No newline at end of file
diff --git a/data/program_facefinder.data b/data/program_facefinder.data
deleted file mode 100644
index 3cb9d36c..00000000
--- a/data/program_facefinder.data
+++ /dev/null
@@ -1 +0,0 @@
-WHILETRUE
\ No newline at end of file
diff --git a/data/program_jacop35.data b/data/program_jacop35.data
deleted file mode 100644
index 97e42982..00000000
--- a/data/program_jacop35.data
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/data/program_line_follower.data b/data/program_line_follower.data
deleted file mode 100644
index 76b2ce73..00000000
--- a/data/program_line_follower.data
+++ /dev/null
@@ -1 +0,0 @@
-WHILETRUEline_positionLTline_position30LEFT500.2GTline_position70RIGHT500.2FORWARD1000.2
\ No newline at end of file
diff --git a/data/program_ludo25.data b/data/program_ludo25.data
deleted file mode 100644
index 6e5e480d..00000000
--- a/data/program_ludo25.data
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/data/program_move_square.data b/data/program_move_square.data
deleted file mode 100644
index aa5b8499..00000000
--- a/data/program_move_square.data
+++ /dev/null
@@ -1 +0,0 @@
-ora mi muovo in un quadrato4LEFT500.4FORWARD1001
\ No newline at end of file
diff --git a/data/program_one.data b/data/program_one.data
deleted file mode 100644
index ea2358fe..00000000
--- a/data/program_one.data
+++ /dev/null
@@ -1 +0,0 @@
-WHILETRUE
\ No newline at end of file
diff --git a/data/program_pathfinder.data b/data/program_pathfinder.data
deleted file mode 100644
index d0686c33..00000000
--- a/data/program_pathfinder.data
+++ /dev/null
@@ -1 +0,0 @@
-WHILETRUE0.3path_aheadGTpath_ahead30FORWARD600.2RIGHT500.10.3LTADDpath_ahead0LEFT500.2
\ No newline at end of file
diff --git a/data/program_prova.data b/data/program_prova.data
deleted file mode 100644
index 56568529..00000000
--- a/data/program_prova.data
+++ /dev/null
@@ -1 +0,0 @@
-WHILETRUEspazioGTEspazio30FORWARD800.2UNTILORGTspazio_2spazioLTspazio_230spaziospazio_2RIGHT800.2spazio_2UNTILORGTspazio_2spazioLTspazio_230spaziospazio_2LEFT800.2spazio_2
\ No newline at end of file
diff --git a/data/program_test.data b/data/program_test.data
deleted file mode 100644
index 0b5dd6d0..00000000
--- a/data/program_test.data
+++ /dev/null
@@ -1 +0,0 @@
-100
\ No newline at end of file
diff --git a/data/program_wcap_labirinto_1.data b/data/program_wcap_labirinto_1.data
deleted file mode 100644
index e1b86976..00000000
--- a/data/program_wcap_labirinto_1.data
+++ /dev/null
@@ -1 +0,0 @@
-Si parteSono arrivato
\ No newline at end of file
diff --git a/defaults/config.json b/defaults/config.json
new file mode 100644
index 00000000..c206cc0a
--- /dev/null
+++ b/defaults/config.json
@@ -0,0 +1,54 @@
+{
+ "move_power_angle_3":"60",
+ "cnn_default_model":"generic_fast_low",
+ "prog_maxblocks":"-1",
+ "camera_jpeg_quality":"5",
+ "show_page_control":"true",
+ "camera_framerate":"30",
+ "prog_scrollbars":"true",
+ "move_fw_speed":"100",
+ "motor_min_power":"0",
+ "motor_max_power":"100",
+ "prog_level":"adv",
+ "move_motor_trim":"1",
+ "cv_image_factor":"2",
+ "move_power_angle_1":"45",
+ "camera_path_object_size_min":"4000",
+ "button_func":"none",
+ "camera_color_object_size_min":"4000",
+ "camera_jpeg_bitrate":"1000000",
+ "move_fw_elapse":"1",
+ "show_control_move_commands":"true",
+ "camera_color_object_size_max":"160000",
+ "show_page_prefs":"true",
+ "camera_exposure_mode":"auto",
+ "ctrl_tr_elapse":"-1",
+ "show_page_program":"true",
+ "move_tr_elapse":"0.5",
+ "camera_path_object_size_max":"160000",
+ "sound_shutter":"$shutter",
+ "ctrl_fw_elapse":"-1",
+ "sound_stop":"$shutdown",
+ "ctrl_tr_speed":"80",
+ "ctrl_fw_speed":"100",
+ "move_tr_speed":"85",
+ "move_power_angle_2":"60",
+ "ctrl_hud_image":"",
+ "load_at_start":"",
+ "sound_start":"$startup",
+ "hardware_version":"5",
+ "audio_volume_level":"100",
+ "wifi_mode":"ap",
+ "wifi_ssid":"coderbot",
+ "wifi_psk":"coderbot",
+ "packages_installed":"",
+ "admin_password":"",
+ "pid_kp":"8.0",
+ "pid_kd":"0.0",
+ "pid_ki":"0.0",
+ "pid_max_speed":"200",
+ "pid_sample_time":"0.05",
+ "movement_use_mpu": "false",
+ "movement_use_motion": "false",
+ "movement_use_encoder": "true"
+}
diff --git a/defaults/manifest.json b/defaults/manifest.json
new file mode 100644
index 00000000..1273d397
--- /dev/null
+++ b/defaults/manifest.json
@@ -0,0 +1,4 @@
+{
+ "coderbot_version": "undefined",
+ "coderbot_commit": "12345678"
+}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_ar_tags.json b/defaults/programs/program_demo_ar_tags.json
new file mode 100644
index 00000000..329f45d9
--- /dev/null
+++ b/defaults/programs/program_demo_ar_tags.json
@@ -0,0 +1 @@
+{"dom_code": "tag_mapcodelistacodespositionsWHILETRUEtag_mapcodescodestag_mappositionspositionstag_mapGTcodes0GTGETLASTGETFIRSTpositions150codeGETFIRSTcodescodesEQcode1FORWARD1001LEFT1001EQcode2FORWARD1003EQcode3FORWARD1001RIGHT1001EQcode42RIGHT1000.5LEFT1000.5itSono arrivato!EQcode5itAttenzione!", "code": "tag_map = None\ncode = None\nlista = None\ncodes = None\npositions = None\n\n\nwhile True:\n get_prog_eng().check_end()\n tag_map = get_cam().find_ar_code()\n codes = tag_map.get('codes')\n positions = tag_map.get('positions')\n if len(codes) > 0:\n if positions[0][-1] > 150:\n code = codes[0]\n get_cam().set_text(codes)\n if code == 1:\n get_bot().forward(speed=100, elapse=1)\n get_bot().left(speed=100, elapse=1)\n elif code == 2:\n get_bot().forward(speed=100, elapse=3)\n elif code == 3:\n get_bot().forward(speed=100, elapse=1)\n get_bot().right(speed=100, elapse=1)\n elif code == 4:\n for count in range(2):\n get_prog_eng().check_end()\n get_bot().right(speed=100, elapse=0.5)\n get_bot().left(speed=100, elapse=0.5)\n get_audio().say('Sono arrivato!', locale=\"it\")\n elif code == 5:\n get_audio().say('Attenzione!', locale=\"it\")\n get_cam().set_text('')\n", "name": "ar_bot"}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_cat_follower.json b/defaults/programs/program_demo_cat_follower.json
new file mode 100644
index 00000000..2c744cc5
--- /dev/null
+++ b/defaults/programs/program_demo_cat_follower.json
@@ -0,0 +1 @@
+{"name": "cat_follower", "dom_code": "objectclasspositionpos_xWHILETRUEobjectGETFIRSTgeneric_object_detectclassGETFIRSTobjectEQclasscatpositionGETFROM_STARTobject3pos_xDIVIDEADDGETFROM_STARTposition1GETFROM_STARTposition32classLTpos_x40LEFT600.1GTpos_x60RIGHT600.1FORWARD1000.2object", "code": "object2 = None\nclass2 = None\nposition = None\npos_x = None\n\n\nwhile True:\n get_prog_eng().check_end()\n object2 = get_cam().cnn_detect_objects(\"generic_object_detect\")[0]\n class2 = object2[0]\n if class2 == 'cat':\n position = object2[2]\n pos_x = (position[0] + position[2]) / 2\n get_cam().set_text(class2)\n if pos_x < 40:\n get_bot().left(speed=60, elapse=0.1)\n elif pos_x > 60:\n get_bot().right(speed=60, elapse=0.1)\n else:\n get_bot().forward(speed=100, elapse=0.2)\n else:\n get_cam().set_text(object2)\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_color_seeker.json b/defaults/programs/program_demo_color_seeker.json
new file mode 100644
index 00000000..75c14d28
--- /dev/null
+++ b/defaults/programs/program_demo_color_seeker.json
@@ -0,0 +1 @@
+{"dom_code": "WHILETRUEdistDIST#96b73cangleANGLE#96b73cDistance: dist angle: angleGTdist32FORWARD1000.1ANDLTdist28GTEdist0BACKWARD1000.1GTangle5RIGHT300.1LTangle-5LEFT300.1", "code": "dist = None\nangle = None\n\n\nwhile True:\n get_prog_eng().check_end()\n dist = get_cam().find_color('#96b73c')[0]\n angle = get_cam().find_color('#96b73c')[1]\n get_cam().set_text(''.join([str(temp_value) for temp_value in ['Distance: ', dist, ' angle: ', angle]]))\n if dist > 32:\n get_bot().forward(speed=100, elapse=0.1)\n elif dist < 28 and dist >= 0:\n get_bot().backward(speed=100, elapse=0.1)\n if angle > 5:\n get_bot().right(speed=30, elapse=0.1)\n elif angle < -5:\n get_bot().left(speed=30, elapse=0.1)\n", "name": "colour_seeker"}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_io_ext.json b/defaults/programs/program_demo_io_ext.json
new file mode 100644
index 00000000..3265bfcb
--- /dev/null
+++ b/defaults/programs/program_demo_io_ext.json
@@ -0,0 +1 @@
+{"name": "test_io_ext", "dom_code": "Analog_Input_1WHILETRUEAnalog_Input_10Analog Input 1: Analog_Input_1GTAnalog_Input_11000TRUE0FALSE", "code": "Analog_Input_1 = None\n\n\nwhile True:\n get_prog_eng().check_end()\n Analog_Input_1 = get_atmega().get_input(0)\n get_cam().set_text('Analog Input 1: ' + str(Analog_Input_1))\n if Analog_Input_1 > 100:\n get_atmega().set_output(0, True)\n else:\n get_atmega().set_output(0, False)\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_line_follower.json b/defaults/programs/program_demo_line_follower.json
new file mode 100644
index 00000000..da7ba861
--- /dev/null
+++ b/defaults/programs/program_demo_line_follower.json
@@ -0,0 +1 @@
+{"dom_code": "line_x_1listaline_x_listline_x_2ar_codear_code_listWHILETRUEline_x_listline_x_1GETFIRSTline_x_listar_code_listcodesar_code_listar_codeGETFIRSTar_code_listar_code0ar_codeEQar_code18080-110001000EQar_code26060-120001550EQar_code66060-115502000GTEline_x_10GTline_x_16040-40-1MINUSline_x_150MINUSline_x_150LTline_x_140-4040-1MINUS50line_x_1MINUS50line_x_15050-1150150", "code": "line_x_1 = None\nlista = None\nline_x_list = None\nline_x_2 = None\nar_code = None\nar_code_list = None\n\n\nwhile True:\n get_prog_eng().check_end()\n line_x_list = get_cam().find_line()\n line_x_1 = line_x_list[0]\n ar_code_list = get_cam().find_ar_code().get('codes')\n if not not len(ar_code_list):\n ar_code = ar_code_list[0]\n else:\n ar_code = 0\n get_cam().set_text(ar_code)\n if ar_code == 1:\n get_bot().motor_control(speed_left=80, speed_right=80, elapse=-1, steps_left=1000, steps_right=1000)\n elif ar_code == 2:\n get_bot().motor_control(speed_left=60, speed_right=60, elapse=-1, steps_left=2000, steps_right=1550)\n elif ar_code == 6:\n get_bot().motor_control(speed_left=60, speed_right=60, elapse=-1, steps_left=1550, steps_right=2000)\n else:\n if line_x_1 >= 0:\n if line_x_1 > 60:\n get_bot().motor_control(speed_left=40, speed_right=-40, elapse=-1, steps_left=line_x_1 - 50, steps_right=line_x_1 - 50)\n elif line_x_1 < 40:\n get_bot().motor_control(speed_left=-40, speed_right=40, elapse=-1, steps_left=50 - line_x_1, steps_right=50 - line_x_1)\n else:\n get_bot().motor_control(speed_left=50, speed_right=50, elapse=-1, steps_left=150, steps_right=150)\n", "name": "line_follower"}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_obstacle_avoidance.json b/defaults/programs/program_demo_obstacle_avoidance.json
new file mode 100644
index 00000000..ab3e4a8e
--- /dev/null
+++ b/defaults/programs/program_demo_obstacle_avoidance.json
@@ -0,0 +1 @@
+{"name": "demo_obstacle_avoidance", "code": "while True:\n get_prog_eng().check_end()\n if get_bot().get_sonar_distance(0) < 15:\n get_bot().right(speed=100, elapse=0.5)\n else:\n get_bot().forward(speed=100, elapse=1)\n", "dom_code": "WHILETRUELT015RIGHT1000.5FORWARD1001"}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_roboetologist.json b/defaults/programs/program_demo_roboetologist.json
new file mode 100644
index 00000000..b53ba7e2
--- /dev/null
+++ b/defaults/programs/program_demo_roboetologist.json
@@ -0,0 +1 @@
+{"name":"roboetologia","dom_code":"attesavelocita_maxvar_marciaIndietrovar_giravoltevar_ritiratavelocitastancoScodinzolaDescrivi questa funzione...3RIGHT50MULTIPLY100velocita1100velocita_max0.30.2attesaLEFT50MULTIPLY100velocita1100velocita_max0.50.2attesaRIGHT50MULTIPLY100velocita1100velocita_max0.30.2attesaEvita_OstacoliDescrivi questa funzione...15LT020BACKWARD50MULTIPLY100velocita1100velocita_max0.50.2attesaRIGHT50MULTIPLY100velocita1100velocita_max0.50.2attesaLT120LEFT50MULTIPLY100velocita1100velocita_max0.50.2attesaLT220RIGHT50MULTIPLY100velocita1100velocita_max0.50.2attesaFORWARD50MULTIPLY100velocita1100velocita_max0.50.2attesaattesa0.2velocita_max80var_marciaIndietro0var_giravolte0var_ritirata0stanco0velocita1WHILETRUEstanco1var_marciaIndietro1var_giravolte1var_ritirata1EQstanco5stanco0velocita1GTstanco3velocita0.5EQvar_ritirata4var_ritirata0EQvar_giravolte8var_giravolte05EQvar_marciaIndietro6var_marciaIndietro0GiravolteDescrivi questa funzione...RIGHT50MULTIPLY100velocita1100velocita_max20.2attesaPatugliamentoDescrivi questa funzione...3RIGHT50MULTIPLY100velocita1100velocita_max10.5Ritirata_e_fugaDescrivi questa funzione...BACKWARD50MULTIPLY100velocita1100velocita_max10.2attesaLEFT50MULTIPLY100velocita1100velocita_max30.2attesaFORWARD50MULTIPLY100velocita1100velocita_max10.2attesaMarciaIndietro_e_ScartoDescrivi questa funzione...BACKWARD50MULTIPLY100velocita1100velocita_max10.2attesaRIGHT50MULTIPLY100velocita1100velocita_max10.2attesa","code":"from numbers import Number\n\nattesa = None\nvelocita_max = None\nvar_marciaIndietro = None\nvar_giravolte = None\nvar_ritirata = None\nvelocita = None\nstanco = None\n\n# Descrivi questa funzione...\ndef Scodinzola():\n global attesa, velocita_max, var_marciaIndietro, var_giravolte, var_ritirata, velocita, stanco\n get_prog_eng().check_end()\n for count in range(3):\n get_prog_eng().check_end()\n get_bot().right(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.3)\n get_bot().sleep(attesa)\n get_bot().left(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.5)\n get_bot().sleep(attesa)\n get_bot().right(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.3)\n get_bot().sleep(attesa)\n\n# Descrivi questa funzione...\ndef Evita_Ostacoli():\n global attesa, velocita_max, var_marciaIndietro, var_giravolte, var_ritirata, velocita, stanco\n get_prog_eng().check_end()\n for count2 in range(15):\n get_prog_eng().check_end()\n if get_bot().get_sonar_distance(0) < 20:\n get_bot().backward(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.5)\n get_bot().sleep(attesa)\n get_bot().right(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.5)\n get_bot().sleep(attesa)\n elif get_bot().get_sonar_distance(1) < 20:\n get_bot().left(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.5)\n get_bot().sleep(attesa)\n elif get_bot().get_sonar_distance(2) < 20:\n get_bot().right(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.5)\n get_bot().sleep(attesa)\n else:\n get_bot().forward(speed=min(max(100 * velocita, 1), velocita_max), elapse=0.5)\n get_bot().sleep(attesa)\n\n# Descrivi questa funzione...\ndef Giravolte():\n global attesa, velocita_max, var_marciaIndietro, var_giravolte, var_ritirata, velocita, stanco\n get_prog_eng().check_end()\n get_bot().right(speed=min(max(100 * velocita, 1), velocita_max), elapse=2)\n get_bot().sleep(attesa)\n\n# Descrivi questa funzione...\ndef Patugliamento():\n global attesa, velocita_max, var_marciaIndietro, var_giravolte, var_ritirata, velocita, stanco\n get_prog_eng().check_end()\n for count3 in range(3):\n get_prog_eng().check_end()\n get_bot().right(speed=min(max(100 * velocita, 1), velocita_max), elapse=1)\n get_bot().sleep(0.5)\n\n# Descrivi questa funzione...\ndef Ritirata_e_fuga():\n global attesa, velocita_max, var_marciaIndietro, var_giravolte, var_ritirata, velocita, stanco\n get_prog_eng().check_end()\n get_bot().backward(speed=min(max(100 * velocita, 1), velocita_max), elapse=1)\n get_bot().sleep(attesa)\n get_bot().left(speed=min(max(100 * velocita, 1), velocita_max), elapse=3)\n get_bot().sleep(attesa)\n get_bot().forward(speed=min(max(100 * velocita, 1), velocita_max), elapse=1)\n get_bot().sleep(attesa)\n\n# Descrivi questa funzione...\ndef MarciaIndietro_e_Scarto():\n global attesa, velocita_max, var_marciaIndietro, var_giravolte, var_ritirata, velocita, stanco\n get_prog_eng().check_end()\n get_bot().backward(speed=min(max(100 * velocita, 1), velocita_max), elapse=1)\n get_bot().sleep(attesa)\n get_bot().right(speed=min(max(100 * velocita, 1), velocita_max), elapse=1)\n get_bot().sleep(attesa)\n\n\nattesa = 0.2\nvelocita_max = 80\nvar_marciaIndietro = 0\nvar_giravolte = 0\nvar_ritirata = 0\nstanco = 0\nvelocita = 1\nwhile True:\n get_prog_eng().check_end()\n stanco = (stanco if isinstance(stanco, Number) else 0) + 1\n var_marciaIndietro = (var_marciaIndietro if isinstance(var_marciaIndietro, Number) else 0) + 1\n var_giravolte = (var_giravolte if isinstance(var_giravolte, Number) else 0) + 1\n var_ritirata = (var_ritirata if isinstance(var_ritirata, Number) else 0) + 1\n if stanco == 5:\n stanco = 0\n velocita = 1\n elif stanco > 3:\n velocita = 0.5\n Scodinzola()\n Evita_Ostacoli()\n Patugliamento()\n if var_ritirata == 4:\n var_ritirata = 0\n Ritirata_e_fuga()\n if var_giravolte == 8:\n var_giravolte = 0\n Giravolte()\n get_bot().sleep(5)\n if var_marciaIndietro == 6:\n var_marciaIndietro = 0\n MarciaIndietro_e_Scarto()\n","default":""}
\ No newline at end of file
diff --git a/defaults/programs/program_demo_sound_clap_control.json b/defaults/programs/program_demo_sound_clap_control.json
new file mode 100644
index 00000000..29f377f3
--- /dev/null
+++ b/defaults/programs/program_demo_sound_clap_control.json
@@ -0,0 +1 @@
+{"dom_code": "WHILETRUEnoise10000.2noiseEQnoiseFALSEFORWARD100-1RIGHT1000.5", "code": "noise = None\n\n\nwhile True:\n get_prog_eng().check_end()\n noise = get_audio().hear(level=1000, elapse=0.2)\n get_cam().set_text(noise)\n if noise == False:\n get_bot().forward(speed=100, elapse=-1)\n else:\n get_bot().right(speed=100, elapse=0.5)\nget_bot().stop()\n", "name": "clap_control"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_cnn_classifier.json b/defaults/programs/program_test_cnn_classifier.json
new file mode 100644
index 00000000..e79a8329
--- /dev/null
+++ b/defaults/programs/program_test_cnn_classifier.json
@@ -0,0 +1 @@
+{"name": "test_cnn_classifier", "dom_code": "WHILETRUEgeneric_fast_low", "code": "while True:\n get_prog_eng().check_end()\n get_cam().set_text(get_cam().cnn_classify(\"generic_fast_low\"))\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_cnn_object_detect.json b/defaults/programs/program_test_cnn_object_detect.json
new file mode 100644
index 00000000..9723235d
--- /dev/null
+++ b/defaults/programs/program_test_cnn_object_detect.json
@@ -0,0 +1 @@
+{"name": "test_cnn_object_detect", "dom_code": "WHILETRUEgeneric_object_detect", "code": "while True:\n get_prog_eng().check_end()\n get_cam().set_text(get_cam().cnn_detect_objects(\"generic_object_detect\"))\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_find_code.json b/defaults/programs/program_test_find_code.json
new file mode 100644
index 00000000..0f16e779
--- /dev/null
+++ b/defaults/programs/program_test_find_code.json
@@ -0,0 +1 @@
+{"dom_code": "WHILETRUE", "code": "while True:\n get_prog_eng().check_end()\n get_cam().set_text(get_cam().find_qr_code())\n", "name": "find_code_test"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_find_color.json b/defaults/programs/program_test_find_color.json
new file mode 100644
index 00000000..68bc4586
--- /dev/null
+++ b/defaults/programs/program_test_find_color.json
@@ -0,0 +1 @@
+{"dom_code": "WHILETRUEdistDIST#96b73cangleANGLE#96b73cDistance: dist angle: angle", "code": "dist = None\nangle = None\n\n\nwhile True:\n get_prog_eng().check_end()\n dist = get_cam().find_color('#96b73c')[0]\n angle = get_cam().find_color('#96b73c')[1]\n get_cam().set_text(''.join([str(temp_value) for temp_value in ['Distance: ', dist, ' angle: ', angle]]))\n", "name": "find_color"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_find_face.json b/defaults/programs/program_test_find_face.json
new file mode 100644
index 00000000..ace65032
--- /dev/null
+++ b/defaults/programs/program_test_find_face.json
@@ -0,0 +1 @@
+{"dom_code": "faceface_xface_sizeWHILETRUEfaceALLface_xGETFROM_STARTface1face_sizeGETFROM_STARTface2face: face_xface_xLTface_x-10LEFT800.1GTface_x10RIGHT800.1", "code": "face = None\nface_x = None\nface_size = None\n\n\nwhile True:\n get_prog_eng().check_end()\n face = get_cam().find_face()\n face_x = face[0]\n face_size = face[1]\n get_cam().set_text(str('face: ') + str(face_x))\n if face_x:\n if face_x < -10:\n get_bot().left(speed=80, elapse=0.1)\n elif face_x > 10:\n get_bot().right(speed=80, elapse=0.1)\n else:\n get_bot().stop()\n", "name": "face_find"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_find_path_ahead.json b/defaults/programs/program_test_find_path_ahead.json
new file mode 100644
index 00000000..c494a2d2
--- /dev/null
+++ b/defaults/programs/program_test_find_path_ahead.json
@@ -0,0 +1 @@
+{"dom_code": "spazio_liberoWHILETRUEspazio_liberospazio_liberoANDGTspazio_libero30NEQspazio_libero60FORWARD1000.2RIGHT1000.2", "code": "spazio_libero = None\n\n\nwhile True:\n get_prog_eng().check_end()\n spazio_libero = get_cam().path_ahead()\n get_cam().set_text(spazio_libero)\n if spazio_libero > 30 and spazio_libero != 60:\n get_bot().forward(speed=100, elapse=0.2)\n else:\n get_bot().right(speed=100, elapse=0.2)\n", "name": "path_ahead"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_img_average.json b/defaults/programs/program_test_img_average.json
new file mode 100644
index 00000000..90bacb94
--- /dev/null
+++ b/defaults/programs/program_test_img_average.json
@@ -0,0 +1 @@
+{"dom_code": "WHILETRUEV", "code": "while True:\n get_prog_eng().check_end()\n get_cam().set_text(get_cam().get_average()[2])\n", "name": "img_average_test"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_input.json b/defaults/programs/program_test_input.json
new file mode 100644
index 00000000..781dc25a
--- /dev/null
+++ b/defaults/programs/program_test_input.json
@@ -0,0 +1 @@
+{"name": "test_input", "dom_code": "WHILETRUEanalog 1: 0 analog 2: 1 digital 1: 2", "code": "while True:\n get_prog_eng().check_end()\n get_cam().set_text(''.join([str(x) for x in ['analog 1: ', get_atmega().get_input(0), ' analog 2: ', get_atmega().get_input(1), ' digital 1: ', get_atmega().get_input(2)]]))\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_led.json b/defaults/programs/program_test_led.json
new file mode 100644
index 00000000..7246e80d
--- /dev/null
+++ b/defaults/programs/program_test_led.json
@@ -0,0 +1 @@
+{"name": "test_led", "dom_code": "ledsicleds6031leds000i1leds11MINUSi1000ADDi5leds000c11005iADDi5MULTIPLYc0MULTIPLYc0MULTIPLYc31leds000", "code": "leds = None\ni = None\nc = None\n\ndef upRange(start, stop, step):\n while start <= stop:\n yield start\n start += abs(step)\n\ndef downRange(start, stop, step):\n while start >= stop:\n yield start\n start -= abs(step)\n\n\nleds = 60\nfor count in range(3):\n get_prog_eng().check_end()\n get_atmega().set_led(1, leds, 0, 0, 0)\n for i in (1 <= float(leds)) and upRange(1, float(leds), 1) or downRange(1, float(leds), 1):\n get_prog_eng().check_end()\n get_atmega().set_led(1, i - 1, 0, 0, 0)\n get_atmega().set_led(i + 5, leds, 0, 0, 0)\n for c in range(1, 101, 5):\n get_prog_eng().check_end()\n get_atmega().set_led(i, i + 5, c * 0, c * 0, c * 3)\n get_atmega().set_led(1, leds, 0, 0, 0)\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_music.json b/defaults/programs/program_test_music.json
new file mode 100644
index 00000000..a3d0f3fd
--- /dev/null
+++ b/defaults/programs/program_test_music.json
@@ -0,0 +1 @@
+{"name": "test_music", "dom_code": "C2nonedog1D2nonecat1E2nonepig1F2noneelephant1G2nonesnake1A2noneduck1B2nonecat1", "code": "get_music().play_note(note=\"C2\", alteration=\"none\" ,instrument=\"dog\" ,duration=1)\nget_music().play_note(note=\"D2\", alteration=\"none\" ,instrument=\"cat\" ,duration=1)\nget_music().play_note(note=\"E2\", alteration=\"none\" ,instrument=\"pig\" ,duration=1)\nget_music().play_note(note=\"F2\", alteration=\"none\" ,instrument=\"elephant\" ,duration=1)\nget_music().play_note(note=\"G2\", alteration=\"none\" ,instrument=\"snake\" ,duration=1)\nget_music().play_note(note=\"A2\", alteration=\"none\" ,instrument=\"duck\" ,duration=1)\nget_music().play_note(note=\"B2\", alteration=\"none\" ,instrument=\"cat\" ,duration=1)\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_output.json b/defaults/programs/program_test_output.json
new file mode 100644
index 00000000..dbd31e04
--- /dev/null
+++ b/defaults/programs/program_test_output.json
@@ -0,0 +1 @@
+{"name": "test_output", "dom_code": "WHILETRUE0TRUE0.11TRUE0.12TRUE0.10FALSE0.11FALSE0.12FALSE0.1", "code": "while True:\n get_prog_eng().check_end()\n get_atmega().set_output(0, True)\n get_bot().sleep(0.1)\n get_atmega().set_output(1, True)\n get_bot().sleep(0.1)\n get_atmega().set_output(2, True)\n get_bot().sleep(0.1)\n get_atmega().set_output(0, False)\n get_bot().sleep(0.1)\n get_atmega().set_output(1, False)\n get_bot().sleep(0.1)\n get_atmega().set_output(2, False)\n get_bot().sleep(0.1)\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_sonars.json b/defaults/programs/program_test_sonars.json
new file mode 100644
index 00000000..6664424a
--- /dev/null
+++ b/defaults/programs/program_test_sonars.json
@@ -0,0 +1 @@
+{"name": "test_sonars", "dom_code": "WHILETRUEFront: 0 Right: 1 Left: 2", "code": "while True:\n get_prog_eng().check_end()\n get_cam().set_text(''.join([str(x) for x in ['Front: ', get_bot().get_sonar_distance(0), ' Right: ', get_bot().get_sonar_distance(1), ' Left: ', get_bot().get_sonar_distance(2)]]))\n"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_sound_hear.json b/defaults/programs/program_test_sound_hear.json
new file mode 100644
index 00000000..31ff1247
--- /dev/null
+++ b/defaults/programs/program_test_sound_hear.json
@@ -0,0 +1 @@
+{"dom_code": "WHILETRUE1001.0", "code": "while True:\n get_prog_eng().check_end()\n get_cam().set_text(get_audio().hear(level=100, elapse=1))\n", "name": "hear_test"}
\ No newline at end of file
diff --git a/defaults/programs/program_test_sound_rec.json b/defaults/programs/program_test_sound_rec.json
new file mode 100644
index 00000000..de267400
--- /dev/null
+++ b/defaults/programs/program_test_sound_rec.json
@@ -0,0 +1 @@
+{"dom_code": "test01.wav5", "code": "get_audio().record_to_file(filename='test01.wav', elapse=5)\n", "name": "sound_rec_test"}
\ No newline at end of file
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 00000000..40a5fafa
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,71 @@
+FROM coderbot/rpi-debian:bullseye-20240227
+
+ENV QEMU_CPU=max
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN install_packages \
+ libraspberrypi0 \
+ procps \
+ sudo \
+ wget \
+ unzip \
+ xz-utils \
+ ffmpeg \
+ portaudio19-dev \
+ python3 \
+ python3-pip \
+ libopenjp2-7-dev \
+ libtiff5 \
+ libatlas-base-dev \
+ libhdf5-dev \
+ alsa-utils \
+ espeak
+RUN install_packages \
+ libharfbuzz-bin \
+ libwebp6 \
+ libjasper1 \
+ libilmbase25 \
+ libgstreamer1.0-0 \
+ libavcodec-extra58 \
+ libavformat58
+RUN install_packages \
+ libopencv-dev \
+ zbar-tools \
+ libzbar0 \
+ sox \
+ libsox-fmt-all \
+ libopenblas-dev
+RUN install_packages \
+ avrdude \
+ tesseract-ocr \
+ tesseract-ocr-eng \
+ tesseract-ocr-ita \
+ tesseract-ocr-fra \
+ tesseract-ocr-spa \
+ tesseract-ocr-deu
+
+ENV READTHEDOCS=True
+ADD requirements.txt /tmp/.
+RUN pip install --no-cache-dir -r /tmp/requirements.txt
+
+RUN mkdir -p /coderbot && \
+mkdir -p /coderbot/data && \
+mkdir -p /coderbot/logs && \
+mkdir -p /coderbot/cnn_modules && \
+mkdir -p /coderbot/coderbot && \
+mkdir -p /coderbot/defaults && \
+mkdir -p /coderbot/sounds
+
+ADD coderbot /coderbot/coderbot/.
+ADD defaults /coderbot/defaults/.
+ADD sounds /coderbot/sounds/.
+
+ADD docker/scripts/*.sh /tmp/.
+RUN /tmp/install_generic_cnn_models.sh
+RUN /tmp/install_lib_firmware.sh
+ADD docker/start.sh /coderbot/.
+
+ARG CODERBOT_VERSION
+ENV CODERBOT_VERSION=${CODERBOT_VERSION}
+
+ENTRYPOINT /coderbot/start.sh
diff --git a/docker/scripts/install_generic_cnn_models.sh b/docker/scripts/install_generic_cnn_models.sh
new file mode 100755
index 00000000..8b0bfe0e
--- /dev/null
+++ b/docker/scripts/install_generic_cnn_models.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+CUR_DIR=$(pwd)
+cd /coderbot
+wget -nc https://github.com/CoderBotOrg/net-models/raw/master/archive/cnn_models.tar.xz
+tar xJf cnn_models.tar.xz
+rm cnn_models.tar.xz
+echo '{"generic_fast_low":{"status":1.0, "image_height": "128", "image_width":"128", "output_layer": "MobilenetV2/Predictions/Reshape_1"}, "generic_slow_high":{"status":1.0, "image_height":"224", "image_width": "224", "output_layer": "MobilenetV2/Predictions/Reshape_1"}}' > models.json
+cd $CUR_DIR
\ No newline at end of file
diff --git a/docker/scripts/install_lib_firmware.sh b/docker/scripts/install_lib_firmware.sh
new file mode 100755
index 00000000..50650608
--- /dev/null
+++ b/docker/scripts/install_lib_firmware.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+CUR_DIR=$(pwd)
+cd /usr/lib/arm-linux-gnueabihf
+ln -s libbcm_host.so.0 libbcm_host.so
+ln -s libmmal.so.0 libmmal.so
+ln -s libmmal_core.so.0 libmmal_core.so
+ln -s libmmal_util.so.0 libmmal_util.so
+ln -s libmmal_vc_client.so.0 libmmal_vc_client.so
+ln -s libbcm_host.so.0 libbcm_host.so
+ln -s libvcsm.so.0 libvcsm.so
+ln -s libvchiq_arm.so.0 libvchiq_arm.so
+ln -s libvcos.so.0 libvcos.so
+cd $CUR_DIR
\ No newline at end of file
diff --git a/docker/start.sh b/docker/start.sh
new file mode 100755
index 00000000..dda61b36
--- /dev/null
+++ b/docker/start.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# disable ethernet, usb
+[ "$CODERBOT_disable_eth_usb" = "true" ] && echo '1-1' | tee /sys/bus/usb/drivers/usb/unbind
+# disable HDMI output
+/usr/bin/tvservice -o
+# enable i2c driver
+modprobe i2c-dev
+# set home
+cd /coderbot
+# start coderbot
+python3 coderbot/main.py
diff --git a/docker/stub/Dockerfile b/docker/stub/Dockerfile
new file mode 100644
index 00000000..66281565
--- /dev/null
+++ b/docker/stub/Dockerfile
@@ -0,0 +1,66 @@
+FROM debian:bullseye-slim
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update -y && apt-get install -y \
+ procps \
+ sudo \
+ wget \
+ unzip \
+ xz-utils \
+ ffmpeg \
+ portaudio19-dev \
+ python3 \
+ python3-pip \
+ libopenjp2-7-dev \
+ libtiff5 \
+ libatlas-base-dev \
+ libhdf5-dev \
+ alsa-utils \
+ espeak \
+ libharfbuzz-bin \
+ libwebp6 \
+ libilmbase25 \
+ libgstreamer1.0-0 \
+ libavcodec-extra58 \
+ libavformat58 \
+ libopencv-dev \
+ zbar-tools \
+ libzbar0 \
+ sox \
+ libsox-fmt-all \
+ libopenblas-dev \
+ avrdude \
+ tesseract-ocr \
+ tesseract-ocr-eng \
+ tesseract-ocr-ita \
+ tesseract-ocr-fra \
+ tesseract-ocr-spa \
+ tesseract-ocr-deu
+
+ADD docker/stub/requirements.txt /tmp/.
+RUN pip install --no-cache-dir -r /tmp/requirements.txt
+
+RUN mkdir -p /coderbot && \
+mkdir -p /coderbot/data && \
+mkdir -p /coderbot/logs && \
+mkdir -p /coderbot/updatePackages && \
+mkdir -p /coderbot/cnn_modules && \
+mkdir -p /coderbot/coderbot && \
+mkdir -p /coderbot/defaults && \
+mkdir -p /coderbot/sounds
+
+ADD coderbot /coderbot/coderbot/.
+ADD stub /coderbot/stub/.
+ADD test /coderbot/test/.
+ADD defaults /coderbot/defaults/.
+ADD sounds /coderbot/sounds/.
+
+ADD docker/scripts/*.sh /tmp/.
+RUN /tmp/install_generic_cnn_models.sh
+ADD docker/stub/start.sh /coderbot/.
+
+ARG CODERBOT_VERSION
+ENV CODERBOT_VERSION=${CODERBOT_VERSION}
+
+ENTRYPOINT /coderbot/start.sh
diff --git a/docker/stub/requirements.txt b/docker/stub/requirements.txt
new file mode 100644
index 00000000..d937b268
--- /dev/null
+++ b/docker/stub/requirements.txt
@@ -0,0 +1,23 @@
+# API framework
+connexion[uvicorn,flask,swagger-ui]==3.0.5
+tinydb==4.8.0
+
+# Misc utils
+setuptools==69.2.0
+event-channel==0.4.3
+
+# IO extensions
+spidev==3.6
+
+# Audio
+sox==1.4.1
+
+# Computer Vision
+grpcio==1.62.1
+numpy==1.26.4
+Pillow==10.2.0
+protobuf==4.25.2
+opencv-contrib-python==4.5.5.62
+tflite-runtime==2.11.0
+pytesseract==0.3.10
+pyzbar==0.1.9
diff --git a/docker/stub/start.sh b/docker/stub/start.sh
new file mode 100755
index 00000000..f28cc766
--- /dev/null
+++ b/docker/stub/start.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+export PYTHONPATH=./stub:./test:./coderbot
+cd /coderbot
+python3 coderbot/main.py & python3 stub/wifi/main.py
\ No newline at end of file
diff --git a/init.py b/init.py
deleted file mode 100755
index e96a7915..00000000
--- a/init.py
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/python
-
-#from handler import camera, signal, logo
-import coderbot
-import main
-
-#cam_h = camera.CameraHandler.get_instance()
-#cam_h.add_handler(camera.SimpleHandler())
-#cam_h.add_handler(signal.SignalHandler(coderbot.CoderBot.get_instance()))
-#cam_h.add_handler(logo.LogoHandler("coderdojo-logo.png", coderbot.CoderBot.get_instance()))
-#cam_h.set_active_handler(None)
-
-if __name__=="__main__":
- #cam_h.start()
- main.run_server()
diff --git a/line.py b/line.py
deleted file mode 100644
index 0637fd2c..00000000
--- a/line.py
+++ /dev/null
@@ -1,41 +0,0 @@
-import time
-import SimpleCV
-
-import coderbot
-
-def main():
- c = SimpleCV.Camera()
- s = SimpleCV.JpegStreamer("0.0.0.0:8090")
- bot = coderbot.CoderBot()
-
- frame = 0
- while True:
- i = c.getImage()
- i.drawRectangle(0,200,640,40)
- i.drawRectangle(240,200,160,40, color=(0,0,255))
- cropped = i.crop(0, 200, 640, 40)
- blobs = cropped.findBlobs(minsize=800, maxsize=4000)
- if blobs and len(blobs):
- line = blobs[-1]
- i.drawRectangle(line.minRect()[0][0], 200, line.width(), line.height(), color=(0,255,0))
- coordX = line.coordinates()[0]
- if coordX > 400:
- print "going right"
- bot.right(0.04)
- elif coordX < 240:
- print "going left"
- bot.left(0.04)
- else:
- print "going straight"
- bot.forward(0.2)
- else:
- bot.backward(0.1)
-
- frame += 1
- if frame % 4 == 0:
- i.save(s)
- time.sleep(0.05)
-
-
-if __name__ == "__main__":
- main()
diff --git a/main.py b/main.py
deleted file mode 100644
index 0f866a5f..00000000
--- a/main.py
+++ /dev/null
@@ -1,145 +0,0 @@
-import os
-import json
-
-from coderbot import CoderBot
-from camera import Camera
-from program import ProgramEngine, Program
-
-from flask import Flask, render_template, request
-#from flask_sockets import Sockets
-
-bot = CoderBot.get_instance()
-cam = Camera.get_instance()
-
-app = Flask(__name__,static_url_path="")
-app.debug = True
-#sockets = Sockets(app)
-
-app.prog_engine = ProgramEngine.get_instance()
-
-@app.route("/")
-def handle_home():
- return render_template('control.html', host=request.host[:request.host.find(':')], stream_port=cam.stream_port)
-
-@app.route("/program")
-def handle_program():
- return render_template('program.html', host=request.host[:request.host.find(':')], stream_port=cam.stream_port)
-
-@app.route("/bot", methods=["GET"])
-def handle_bot():
- cmd = request.args.get('cmd')
- param1 = request.args.get('param1')
- param2 = request.args.get('param2')
-
- if cmd == "forward":
- bot.forward(speed=int(param1), elapse=float(param2))
- elif cmd == "left":
- bot.left(speed=int(param1), elapse=float(param2))
- elif cmd == "right":
- bot.right(speed=int(param1), elapse=float(param2))
- elif cmd == "backward":
- bot.backward(speed=int(param1), elapse=float(param2))
- elif cmd == "stop":
- bot.stop()
- elif cmd == "set_handler":
- print "param: " + str(param1)
- try:
- handler = int(param1) if int(param1) >= 0 else None
- cam_h.set_active_handler(handler)
- except e:
- print e
-
- elif cmd == "say":
- print "say: " + str(param1)
- bot.say(param1)
-
- elif cmd == "halt":
- print "shutting down"
- bot.say("$shutdown.mp3")
- bot.halt()
-
- return "ok"
-
-
-@app.route("/program/list", methods=["GET"])
-def handle_program_list():
- print "program_list"
- return json.dumps(app.prog_engine.list())
-
-@app.route("/program/load", methods=["GET"])
-def handle_program_load():
- print "program_load"
- name = request.args.get('name')
- return app.prog_engine.load(name).dom_code
-
-@app.route("/program/save", methods=["POST"])
-def handle_program_save():
- print "program_save"
- name = request.form.get('name')
- dom_code = request.form.get('dom_code')
- prog = Program(name, dom_code = dom_code)
- app.prog_engine.save(prog)
- return "ok"
-
-@app.route("/program/delete", methods=["POST"])
-def handle_program_delete():
- print "program_delete"
- name = request.form.get('name')
- app.prog_engine.delete(name)
- return "ok"
-
-@app.route("/program/exec", methods=["POST"])
-def handle_program_exec():
- print "program_exec"
- name = request.form.get('name')
- code = request.form.get('code')
- app.prog = Program(name, code)
- return json.dumps(app.prog.execute())
-
-@app.route("/program/end", methods=["POST"])
-def handle_program_end():
- print "program_end"
- app.prog.end()
- app.prog = None
- return "ok"
-
-@app.route("/program/status", methods=["GET"])
-def handle_program_status():
- print "program_status"
- prog = Program("")
- if app.prog:
- prog = app.prog
- return json.dumps({'name': prog.name, "running": prog.is_running()})
-
-"""
-@sockets.route('/bot_ws')
-def bot_ws(ws):
- while True:
- m = ws.receive()
- print m
- if m == "forward":
- bot.forward()
- if m == "backward":
- bot.backward()
- if m == "left":
- bot.left()
- if m == "right":
- bot.right()
- elif m == "stop":
- bot.stop()
-
-cam_h = camera.CameraHandler.get_instance()
-
-def init():
- cam_h.add_handler(camera.SimpleHandler())
- cam_h.add_handler(signal.SignalHandler(coderbot.CoderBot.get_instance()))
- cam_h.add_handler(logo.LogoHandler("coderdojo-logo.png", coderbot.CoderBot.get_instance()))
- cam_h.set_active_handler(None)
- cam_h.start()
-
-init()
-"""
-
-def run_server():
- bot.say("$startup.mp3")
- app.run(host="0.0.0.0", port=8080, debug=True, use_reloader=False)
diff --git a/program.py b/program.py
deleted file mode 100644
index ead2b003..00000000
--- a/program.py
+++ /dev/null
@@ -1,102 +0,0 @@
-import os
-import sys
-import threading
-
-import coderbot
-import camera
-
-PROGRAM_PATH = "./data/"
-PROGRAM_PREFIX = "program_"
-PROGRAM_SUFFIX = ".data"
-
-class ProgramEngine:
-
- _instance = None
-
- def __init__(self):
- self._program = None
- self._repository = {}
- for dirname, dirnames, filenames, in os.walk("./data"):
- for filename in filenames:
- if PROGRAM_PREFIX in filename:
- program_name = filename[len(PROGRAM_PREFIX):-len(PROGRAM_SUFFIX)]
- self._repository[program_name] = filename
-
- @classmethod
- def get_instance(cls):
- if not cls._instance:
- cls._instance = ProgramEngine()
- return cls._instance
-
- def list(self):
- return self._repository.keys()
-
- def save(self, program):
- program = self._repository[program.name] = program
- f = open(PROGRAM_PATH + PROGRAM_PREFIX + program.name + PROGRAM_SUFFIX, 'w')
- f.write(program.dom_code)
-
- def load(self, name):
- #return self._repository[name]
- f = open(PROGRAM_PATH + PROGRAM_PREFIX + name + PROGRAM_SUFFIX, 'r')
- dom_code = f.read()
- return Program(name=name, dom_code=dom_code)
-
- def delete(self, name):
- del self._repository[name]
- os.remove(PROGRAM_PATH + PROGRAM_PREFIX + name + PROGRAM_SUFFIX)
- return "ok"
-
- def is_running(self, name):
- return self._repository[name].is_running()
-
-class Program(threading.Thread):
-
- _running = False
-
- @property
- def dom_code(self):
- return self._dom_code
-
- def __init__(self, name, code=None, dom_code=None):
- super(Program, self).__init__()
- self.name = name
- self._dom_code = dom_code
- self._code = code
-
- def execute(self):
- if self._running:
- raise RuntimeError('already running')
-
- print "execute.1"
- self._running = True
-
- try:
- self.start()
- except RuntimeError as re:
- print "RuntimeError:" + str(re)
- print "execute.2"
- return "ok"
-
- def end(self):
- self._running = False
- self.join()
-
- def check_end(self):
- if self._running == False:
- raise RuntimeError('end requested')
-
- def is_running(self):
- return self._running
-
- def run(self):
- try:
- print "run.1"
- bot = coderbot.CoderBot.get_instance()
- cam = camera.Camera.get_instance()
- program = self
- exec(self._code)
- print "run.2"
- except RuntimeError as re:
- print "quit: " + str(re)
- self._running = False
diff --git a/pylintrc b/pylintrc
new file mode 100644
index 00000000..6b6d5a4b
--- /dev/null
+++ b/pylintrc
@@ -0,0 +1,371 @@
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=CVS
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Use multiple processes to speed up Pylint.
+jobs=1
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
+
+[MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time. See also the "--disable" option for examples.
+#enable=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+
+disable=
+ attribute-defined-outside-init,
+ duplicate-code,
+ fixme,
+ invalid-name,
+ missing-docstring,
+ protected-access,
+ too-few-public-methods,
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html. You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
+output-format=text
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells whether to display a full report or only the messages
+reports=yes
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+
+[LOGGING]
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=_$|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,_cb
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=180
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )??$
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+# List of optional constructs for which whitespace checking is disabled
+no-space-check=trailing-comma,dict-separator
+
+# Maximum number of lines in a module
+max-module-lines=2000
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+
+[BASIC]
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,input
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# Regular expression matching correct function names
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for function names
+function-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct variable names
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for variable names
+variable-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct constant names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Naming hint for constant names
+const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression matching correct attribute names
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for attribute names
+attr-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct argument names
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for argument names
+argument-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression matching correct class attribute names
+class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Naming hint for class attribute names
+class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
+
+# Regular expression matching correct inline iteration names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Naming hint for inline iteration names
+inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
+
+# Regular expression matching correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Naming hint for class names
+class-name-hint=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression matching correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Naming hint for module names
+module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression matching correct method names
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Naming hint for method names
+method-name-hint=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=__.*__
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# List of decorators that define properties, such as abc.abstractproperty.
+property-classes=abc.abstractproperty
+
+
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis
+ignored-modules=
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set).
+ignored-classes=SQLObject, optparse.Values, thread._local, _thread._local
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=REQUEST,acl_users,aq_parent
+
+# List of decorators that create context managers from functions, such as
+# contextlib.contextmanager.
+contextmanager-decorators=contextlib.contextmanager
+
+
+[SPELLING]
+
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=10
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=25
+
+# Maximum number of return / yield for function / method body
+max-returns=11
+
+# Maximum number of branch for function / method body
+max-branches=26
+
+# Maximum number of statements in function / method body
+max-statements=100
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=11
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=25
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,_fields,_replace,_source,_make
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
+
+
+[EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "Exception"
+overgeneral-exceptions=Exception
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..d2085ec9
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,28 @@
+# API framework
+connexion[uvicorn,flask,swagger-ui]==3.0.5
+tinydb==4.8.0
+
+# Misc utils
+setuptools==69.2.0
+event-channel==0.4.3
+
+# IO extensions
+pigpio==1.78
+smbus2==0.4.3
+spidev==3.6
+
+# Audio
+sox==1.4.1
+PyAudio==0.2.14
+pyalsaaudio==0.10.0
+
+# Computer Vision
+grpcio==1.62.1
+numpy==1.26.4
+Pillow==10.2.0
+protobuf==4.25.2
+opencv-contrib-python==4.5.5.62
+tflite-runtime==2.11.0
+pytesseract==0.3.10
+picamera==1.13
+pyzbar==0.1.9
diff --git a/sounds/buzz.mp3 b/sounds/buzz.mp3
deleted file mode 100644
index e28d0f69..00000000
Binary files a/sounds/buzz.mp3 and /dev/null differ
diff --git a/sounds/buzz.wav b/sounds/buzz.wav
new file mode 100644
index 00000000..dae05b95
Binary files /dev/null and b/sounds/buzz.wav differ
diff --git a/sounds/i-see-you.wav b/sounds/i-see-you.wav
new file mode 100644
index 00000000..a3ab3021
Binary files /dev/null and b/sounds/i-see-you.wav differ
diff --git a/sounds/notes/cat/audio.wav b/sounds/notes/cat/audio.wav
new file mode 100644
index 00000000..eb20db75
Binary files /dev/null and b/sounds/notes/cat/audio.wav differ
diff --git a/sounds/notes/dinosaur.wav b/sounds/notes/dinosaur.wav
new file mode 100644
index 00000000..4fe28f48
Binary files /dev/null and b/sounds/notes/dinosaur.wav differ
diff --git a/sounds/notes/dog/audio.wav b/sounds/notes/dog/audio.wav
new file mode 100644
index 00000000..fa3e4e67
Binary files /dev/null and b/sounds/notes/dog/audio.wav differ
diff --git a/sounds/notes/duck/audio.wav b/sounds/notes/duck/audio.wav
new file mode 100644
index 00000000..ee416bc0
Binary files /dev/null and b/sounds/notes/duck/audio.wav differ
diff --git a/sounds/notes/elephant/audio.wav b/sounds/notes/elephant/audio.wav
new file mode 100644
index 00000000..7d313846
Binary files /dev/null and b/sounds/notes/elephant/audio.wav differ
diff --git a/sounds/notes/flute/audio.wav b/sounds/notes/flute/audio.wav
new file mode 100644
index 00000000..1e14fa57
Binary files /dev/null and b/sounds/notes/flute/audio.wav differ
diff --git a/sounds/notes/guitar/audio.wav b/sounds/notes/guitar/audio.wav
new file mode 100644
index 00000000..673b5127
Binary files /dev/null and b/sounds/notes/guitar/audio.wav differ
diff --git a/sounds/notes/music_package.json b/sounds/notes/music_package.json
new file mode 100644
index 00000000..d876c5c3
--- /dev/null
+++ b/sounds/notes/music_package.json
@@ -0,0 +1,193 @@
+{
+ "packages": {
+ "piano": {
+ "category": "instrument",
+ "name_IT": "pianoforte",
+ "name_EN": "piano",
+ "version": "0.1",
+ "date": "2020-04-08",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "piano.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "piano.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "piano.png"
+ }
+ }
+ },
+ "guitar": {
+ "category": "instrument",
+ "name_IT": "chitarra",
+ "name_EN": "guitar",
+ "version": "0.1",
+ "date": "2020-04-08",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "guitar.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "guitar.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "guitar.png"
+ }
+ }
+ },
+ "flute": {
+ "category": "instrument",
+ "name_IT": "flauto",
+ "name_EN": "flute",
+ "version": "0.1",
+ "date": "2020-04-08",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "flute.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "flute.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "flute.png"
+ }
+ }
+ },
+ "cat": {
+ "category": "animal",
+ "name_IT": "gatto",
+ "name_EN": "cat",
+ "version": "0.1",
+ "date": "2020-04-08",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "cat.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "cat.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "cat.png"
+ }
+ }
+ },
+ "dog": {
+ "category": "animal",
+ "name_IT": "cane",
+ "name_EN": "dog",
+ "version": "0.1",
+ "date": "2020-04-08",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "dog.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "dog.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "dog.png"
+ }
+ }
+ },
+ "pig": {
+ "category": "animal",
+ "name_IT": "maiale",
+ "name_EN": "pig",
+ "version": "0.1",
+ "date": "2020-06-01",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "pig.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "pig.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "pig.png"
+ }
+ }
+ },
+ "elephant": {
+ "category": "animal",
+ "name_IT": "elefante",
+ "name_EN": "elephant",
+ "version": "0.1",
+ "date": "2020-06-01",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "elephant.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "elephant.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "elephant.png"
+ }
+ }
+ },
+ "snake": {
+ "category": "animal",
+ "name_IT": "serpente",
+ "name_EN": "snake",
+ "version": "0.1",
+ "date": "2020-06-01",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "snake.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "snake.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "snake.png"
+ }
+ }
+ },
+ "duck": {
+ "category": "animal",
+ "name_IT": "anatra",
+ "name_EN": "duck",
+ "version": "0.1",
+ "date": "2020-06-01",
+ "interface": {
+ "base": {
+ "available": "TRUE",
+ "icon": "duck.png"
+ },
+ "intermediate": {
+ "available": "TRUE",
+ "icon": "duck.png"
+ },
+ "advanced": {
+ "available": "TRUE",
+ "icon": "duck.png"
+ }
+ }
+ }
+ }
+}
diff --git a/sounds/notes/piano/audio.wav b/sounds/notes/piano/audio.wav
new file mode 100644
index 00000000..5eaabb67
Binary files /dev/null and b/sounds/notes/piano/audio.wav differ
diff --git a/sounds/notes/pig/audio.wav b/sounds/notes/pig/audio.wav
new file mode 100644
index 00000000..63ddcf4c
Binary files /dev/null and b/sounds/notes/pig/audio.wav differ
diff --git a/sounds/notes/snake/audio.wav b/sounds/notes/snake/audio.wav
new file mode 100644
index 00000000..39775e14
Binary files /dev/null and b/sounds/notes/snake/audio.wav differ
diff --git a/sounds/phaser.mp3 b/sounds/phaser.mp3
deleted file mode 100644
index 632a307b..00000000
Binary files a/sounds/phaser.mp3 and /dev/null differ
diff --git a/sounds/phaser.wav b/sounds/phaser.wav
new file mode 100644
index 00000000..bc3a59ff
Binary files /dev/null and b/sounds/phaser.wav differ
diff --git a/sounds/scanner.mp3 b/sounds/scanner.mp3
deleted file mode 100644
index 534647f3..00000000
Binary files a/sounds/scanner.mp3 and /dev/null differ
diff --git a/sounds/scanner.wav b/sounds/scanner.wav
new file mode 100644
index 00000000..9212f29a
Binary files /dev/null and b/sounds/scanner.wav differ
diff --git a/sounds/shutdown.mp3 b/sounds/shutdown.mp3
deleted file mode 100644
index 0039e395..00000000
Binary files a/sounds/shutdown.mp3 and /dev/null differ
diff --git a/sounds/shutdown.wav b/sounds/shutdown.wav
new file mode 100644
index 00000000..73627427
Binary files /dev/null and b/sounds/shutdown.wav differ
diff --git a/sounds/shutter.wav b/sounds/shutter.wav
new file mode 100644
index 00000000..96bc89c6
Binary files /dev/null and b/sounds/shutter.wav differ
diff --git a/sounds/startup.mp3 b/sounds/startup.mp3
deleted file mode 100644
index a33852fe..00000000
Binary files a/sounds/startup.mp3 and /dev/null differ
diff --git a/sounds/startup.wav b/sounds/startup.wav
new file mode 100644
index 00000000..707ace6b
Binary files /dev/null and b/sounds/startup.wav differ
diff --git a/sounds/still-there.wav b/sounds/still-there.wav
new file mode 100644
index 00000000..35c2f01b
Binary files /dev/null and b/sounds/still-there.wav differ
diff --git a/sounds/there-you-are.wav b/sounds/there-you-are.wav
new file mode 100644
index 00000000..bf18c808
Binary files /dev/null and b/sounds/there-you-are.wav differ
diff --git a/static/.DS_Store b/static/.DS_Store
deleted file mode 100644
index eb3d484a..00000000
Binary files a/static/.DS_Store and /dev/null differ
diff --git a/static/css/.DS_Store b/static/css/.DS_Store
deleted file mode 100644
index 5008ddfc..00000000
Binary files a/static/css/.DS_Store and /dev/null differ
diff --git a/static/css/bootstrap.min.css b/static/css/bootstrap.min.css
deleted file mode 100755
index c547283b..00000000
--- a/static/css/bootstrap.min.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * 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:.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:.35em .625em .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:#333;background-color:#fff}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:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.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:#999}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:#999}.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 #eee}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 #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}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:#999}blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;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:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;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 #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.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 #ddd}.table .table{background-color:#fff}.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 #ddd}.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 #ddd}.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 #ddd;-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:#333;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;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:#555;vertical-align:middle}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;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 .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .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:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}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:#333;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:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;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:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#fff}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;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:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;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:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;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:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;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:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;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:#999;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 .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('http://github.com/fonts/glyphicons-halflings-regular.eot');src:url('http://github.com/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('http://github.com/fonts/glyphicons-halflings-regular.woff') format('woff'),url('http://github.com/fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('http://github.com/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:#fff;border:1px solid #ccc;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:#333;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:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.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:#999}.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:0}.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:#555;text-align:center;background-color:#eee;border:1px solid #ccc;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:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;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 #ddd}.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:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;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 #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;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:#fff}}.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:#fff;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 #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;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:#fff}}.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:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#ccc}.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:#555;background-color:#e7e7e7}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;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:#555;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:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.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:#fff;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:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;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:#fff;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:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.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:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.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:#fff;border:1px solid #ddd}.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:#eee}.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:#fff;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:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.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:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.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:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.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:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.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:#eee}.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:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .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:#333}.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:#fff;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 .6s ease;transition:width .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:#fff;border:1px solid #ddd}.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:#555}a.list-group-item .list-group-item-heading{color:#333}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:#fff;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:#fff;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 #ddd}.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 #ddd;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 #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;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:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.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 .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .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:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-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:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.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:.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:#fff;text-align:center;text-decoration:none;background-color:#000;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:#000;border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:#000;border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:#000;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:#fff;border:1px solid #ccc;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:#999;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:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;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:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;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:.6s ease-in-out left;transition:.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:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.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:#fff;text-decoration:none;outline:0;opacity:.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 #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;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}}
\ No newline at end of file
diff --git a/static/css/images/ajax-loader.gif b/static/css/images/ajax-loader.gif
deleted file mode 100755
index 57f5624e..00000000
Binary files a/static/css/images/ajax-loader.gif and /dev/null differ
diff --git a/static/css/images/icons-png/action-black.png b/static/css/images/icons-png/action-black.png
deleted file mode 100755
index d10dc792..00000000
Binary files a/static/css/images/icons-png/action-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/action-white.png b/static/css/images/icons-png/action-white.png
deleted file mode 100755
index 1daddabf..00000000
Binary files a/static/css/images/icons-png/action-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/alert-black.png b/static/css/images/icons-png/alert-black.png
deleted file mode 100755
index 784cd062..00000000
Binary files a/static/css/images/icons-png/alert-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/alert-white.png b/static/css/images/icons-png/alert-white.png
deleted file mode 100755
index 5c00e0aa..00000000
Binary files a/static/css/images/icons-png/alert-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-d-black.png b/static/css/images/icons-png/arrow-d-black.png
deleted file mode 100755
index 358f0e82..00000000
Binary files a/static/css/images/icons-png/arrow-d-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-d-l-black.png b/static/css/images/icons-png/arrow-d-l-black.png
deleted file mode 100755
index c7f6c9da..00000000
Binary files a/static/css/images/icons-png/arrow-d-l-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-d-l-white.png b/static/css/images/icons-png/arrow-d-l-white.png
deleted file mode 100755
index d103c06a..00000000
Binary files a/static/css/images/icons-png/arrow-d-l-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-d-r-black.png b/static/css/images/icons-png/arrow-d-r-black.png
deleted file mode 100755
index 648d7686..00000000
Binary files a/static/css/images/icons-png/arrow-d-r-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-d-r-white.png b/static/css/images/icons-png/arrow-d-r-white.png
deleted file mode 100755
index 713d3c81..00000000
Binary files a/static/css/images/icons-png/arrow-d-r-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-d-white.png b/static/css/images/icons-png/arrow-d-white.png
deleted file mode 100755
index 460cf4a5..00000000
Binary files a/static/css/images/icons-png/arrow-d-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-l-black.png b/static/css/images/icons-png/arrow-l-black.png
deleted file mode 100755
index 8083f945..00000000
Binary files a/static/css/images/icons-png/arrow-l-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-l-white.png b/static/css/images/icons-png/arrow-l-white.png
deleted file mode 100755
index 09d1ca5b..00000000
Binary files a/static/css/images/icons-png/arrow-l-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-r-black.png b/static/css/images/icons-png/arrow-r-black.png
deleted file mode 100755
index 2adc5f18..00000000
Binary files a/static/css/images/icons-png/arrow-r-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-r-white.png b/static/css/images/icons-png/arrow-r-white.png
deleted file mode 100755
index 9a4ff07c..00000000
Binary files a/static/css/images/icons-png/arrow-r-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-u-black.png b/static/css/images/icons-png/arrow-u-black.png
deleted file mode 100755
index de107e15..00000000
Binary files a/static/css/images/icons-png/arrow-u-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-u-l-black.png b/static/css/images/icons-png/arrow-u-l-black.png
deleted file mode 100755
index 707a7c4e..00000000
Binary files a/static/css/images/icons-png/arrow-u-l-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-u-l-white.png b/static/css/images/icons-png/arrow-u-l-white.png
deleted file mode 100755
index 157e10b3..00000000
Binary files a/static/css/images/icons-png/arrow-u-l-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-u-r-black.png b/static/css/images/icons-png/arrow-u-r-black.png
deleted file mode 100755
index f5f4a420..00000000
Binary files a/static/css/images/icons-png/arrow-u-r-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-u-r-white.png b/static/css/images/icons-png/arrow-u-r-white.png
deleted file mode 100755
index 9026da63..00000000
Binary files a/static/css/images/icons-png/arrow-u-r-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/arrow-u-white.png b/static/css/images/icons-png/arrow-u-white.png
deleted file mode 100755
index a55ca59e..00000000
Binary files a/static/css/images/icons-png/arrow-u-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/audio-black.png b/static/css/images/icons-png/audio-black.png
deleted file mode 100755
index 05cc4fd8..00000000
Binary files a/static/css/images/icons-png/audio-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/audio-white.png b/static/css/images/icons-png/audio-white.png
deleted file mode 100755
index 279102b4..00000000
Binary files a/static/css/images/icons-png/audio-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/back-black.png b/static/css/images/icons-png/back-black.png
deleted file mode 100755
index e3ee4ea6..00000000
Binary files a/static/css/images/icons-png/back-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/back-white.png b/static/css/images/icons-png/back-white.png
deleted file mode 100755
index 4c4e76bd..00000000
Binary files a/static/css/images/icons-png/back-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/bars-black.png b/static/css/images/icons-png/bars-black.png
deleted file mode 100755
index 5a261326..00000000
Binary files a/static/css/images/icons-png/bars-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/bars-white.png b/static/css/images/icons-png/bars-white.png
deleted file mode 100755
index 9c8ceeca..00000000
Binary files a/static/css/images/icons-png/bars-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/bullets-black.png b/static/css/images/icons-png/bullets-black.png
deleted file mode 100755
index a1d29253..00000000
Binary files a/static/css/images/icons-png/bullets-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/bullets-white.png b/static/css/images/icons-png/bullets-white.png
deleted file mode 100755
index 754b30d9..00000000
Binary files a/static/css/images/icons-png/bullets-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/calendar-black.png b/static/css/images/icons-png/calendar-black.png
deleted file mode 100755
index 579487a8..00000000
Binary files a/static/css/images/icons-png/calendar-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/calendar-white.png b/static/css/images/icons-png/calendar-white.png
deleted file mode 100755
index b03f2eb3..00000000
Binary files a/static/css/images/icons-png/calendar-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/camera-black.png b/static/css/images/icons-png/camera-black.png
deleted file mode 100755
index d4e69213..00000000
Binary files a/static/css/images/icons-png/camera-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/camera-white.png b/static/css/images/icons-png/camera-white.png
deleted file mode 100755
index 3758bab8..00000000
Binary files a/static/css/images/icons-png/camera-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-d-black.png b/static/css/images/icons-png/carat-d-black.png
deleted file mode 100755
index 86972cca..00000000
Binary files a/static/css/images/icons-png/carat-d-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-d-white.png b/static/css/images/icons-png/carat-d-white.png
deleted file mode 100755
index 12c0e67b..00000000
Binary files a/static/css/images/icons-png/carat-d-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-l-black.png b/static/css/images/icons-png/carat-l-black.png
deleted file mode 100755
index 1a19660b..00000000
Binary files a/static/css/images/icons-png/carat-l-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-l-white.png b/static/css/images/icons-png/carat-l-white.png
deleted file mode 100755
index 7c549270..00000000
Binary files a/static/css/images/icons-png/carat-l-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-r-black.png b/static/css/images/icons-png/carat-r-black.png
deleted file mode 100755
index 1b47d50a..00000000
Binary files a/static/css/images/icons-png/carat-r-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-r-white.png b/static/css/images/icons-png/carat-r-white.png
deleted file mode 100755
index fae9babc..00000000
Binary files a/static/css/images/icons-png/carat-r-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-u-black.png b/static/css/images/icons-png/carat-u-black.png
deleted file mode 100755
index c7b85cf4..00000000
Binary files a/static/css/images/icons-png/carat-u-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/carat-u-white.png b/static/css/images/icons-png/carat-u-white.png
deleted file mode 100755
index 9035505d..00000000
Binary files a/static/css/images/icons-png/carat-u-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/check-black.png b/static/css/images/icons-png/check-black.png
deleted file mode 100755
index 816c8307..00000000
Binary files a/static/css/images/icons-png/check-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/check-white.png b/static/css/images/icons-png/check-white.png
deleted file mode 100755
index 3abbe9ea..00000000
Binary files a/static/css/images/icons-png/check-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/clock-black.png b/static/css/images/icons-png/clock-black.png
deleted file mode 100755
index 411a7388..00000000
Binary files a/static/css/images/icons-png/clock-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/clock-white.png b/static/css/images/icons-png/clock-white.png
deleted file mode 100755
index fe8bdef8..00000000
Binary files a/static/css/images/icons-png/clock-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/cloud-black.png b/static/css/images/icons-png/cloud-black.png
deleted file mode 100755
index 84a07a9f..00000000
Binary files a/static/css/images/icons-png/cloud-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/cloud-white.png b/static/css/images/icons-png/cloud-white.png
deleted file mode 100755
index 47214248..00000000
Binary files a/static/css/images/icons-png/cloud-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/comment-black.png b/static/css/images/icons-png/comment-black.png
deleted file mode 100755
index 430f6d44..00000000
Binary files a/static/css/images/icons-png/comment-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/comment-white.png b/static/css/images/icons-png/comment-white.png
deleted file mode 100755
index f5276994..00000000
Binary files a/static/css/images/icons-png/comment-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/delete-black.png b/static/css/images/icons-png/delete-black.png
deleted file mode 100755
index 71f34925..00000000
Binary files a/static/css/images/icons-png/delete-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/delete-white.png b/static/css/images/icons-png/delete-white.png
deleted file mode 100755
index 42d9164b..00000000
Binary files a/static/css/images/icons-png/delete-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/edit-black.png b/static/css/images/icons-png/edit-black.png
deleted file mode 100755
index fcbb3dae..00000000
Binary files a/static/css/images/icons-png/edit-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/edit-white.png b/static/css/images/icons-png/edit-white.png
deleted file mode 100755
index bbb6a524..00000000
Binary files a/static/css/images/icons-png/edit-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/eye-black.png b/static/css/images/icons-png/eye-black.png
deleted file mode 100755
index 8ffe2cc2..00000000
Binary files a/static/css/images/icons-png/eye-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/eye-white.png b/static/css/images/icons-png/eye-white.png
deleted file mode 100755
index d2a65baf..00000000
Binary files a/static/css/images/icons-png/eye-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/forbidden-black.png b/static/css/images/icons-png/forbidden-black.png
deleted file mode 100755
index 1f7d0d23..00000000
Binary files a/static/css/images/icons-png/forbidden-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/forbidden-white.png b/static/css/images/icons-png/forbidden-white.png
deleted file mode 100755
index f23d7355..00000000
Binary files a/static/css/images/icons-png/forbidden-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/forward-black.png b/static/css/images/icons-png/forward-black.png
deleted file mode 100755
index ace9799f..00000000
Binary files a/static/css/images/icons-png/forward-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/forward-white.png b/static/css/images/icons-png/forward-white.png
deleted file mode 100755
index 567cc45c..00000000
Binary files a/static/css/images/icons-png/forward-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/gear-black.png b/static/css/images/icons-png/gear-black.png
deleted file mode 100755
index 857668d6..00000000
Binary files a/static/css/images/icons-png/gear-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/gear-white.png b/static/css/images/icons-png/gear-white.png
deleted file mode 100755
index 6e7402c9..00000000
Binary files a/static/css/images/icons-png/gear-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/grid-black.png b/static/css/images/icons-png/grid-black.png
deleted file mode 100755
index d8964364..00000000
Binary files a/static/css/images/icons-png/grid-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/grid-white.png b/static/css/images/icons-png/grid-white.png
deleted file mode 100755
index 575b1792..00000000
Binary files a/static/css/images/icons-png/grid-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/heart-black.png b/static/css/images/icons-png/heart-black.png
deleted file mode 100755
index f0bd388b..00000000
Binary files a/static/css/images/icons-png/heart-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/heart-white.png b/static/css/images/icons-png/heart-white.png
deleted file mode 100755
index dfec28e3..00000000
Binary files a/static/css/images/icons-png/heart-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/home-black.png b/static/css/images/icons-png/home-black.png
deleted file mode 100755
index 1c40d03c..00000000
Binary files a/static/css/images/icons-png/home-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/home-white.png b/static/css/images/icons-png/home-white.png
deleted file mode 100755
index bf8d59ec..00000000
Binary files a/static/css/images/icons-png/home-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/info-black.png b/static/css/images/icons-png/info-black.png
deleted file mode 100755
index f0c9027c..00000000
Binary files a/static/css/images/icons-png/info-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/info-white.png b/static/css/images/icons-png/info-white.png
deleted file mode 100755
index 2e5080aa..00000000
Binary files a/static/css/images/icons-png/info-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/location-black.png b/static/css/images/icons-png/location-black.png
deleted file mode 100755
index 13191776..00000000
Binary files a/static/css/images/icons-png/location-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/location-white.png b/static/css/images/icons-png/location-white.png
deleted file mode 100755
index fc3134e1..00000000
Binary files a/static/css/images/icons-png/location-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/lock-black.png b/static/css/images/icons-png/lock-black.png
deleted file mode 100755
index 153d8ba0..00000000
Binary files a/static/css/images/icons-png/lock-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/lock-white.png b/static/css/images/icons-png/lock-white.png
deleted file mode 100755
index fe179bca..00000000
Binary files a/static/css/images/icons-png/lock-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/mail-black.png b/static/css/images/icons-png/mail-black.png
deleted file mode 100755
index dd4bf752..00000000
Binary files a/static/css/images/icons-png/mail-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/mail-white.png b/static/css/images/icons-png/mail-white.png
deleted file mode 100755
index 64395a2c..00000000
Binary files a/static/css/images/icons-png/mail-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/minus-black.png b/static/css/images/icons-png/minus-black.png
deleted file mode 100755
index fd9e5ae8..00000000
Binary files a/static/css/images/icons-png/minus-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/minus-white.png b/static/css/images/icons-png/minus-white.png
deleted file mode 100755
index 3769eec8..00000000
Binary files a/static/css/images/icons-png/minus-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/navigation-black.png b/static/css/images/icons-png/navigation-black.png
deleted file mode 100755
index 05fa9632..00000000
Binary files a/static/css/images/icons-png/navigation-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/navigation-white.png b/static/css/images/icons-png/navigation-white.png
deleted file mode 100755
index b8455321..00000000
Binary files a/static/css/images/icons-png/navigation-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/phone-black.png b/static/css/images/icons-png/phone-black.png
deleted file mode 100755
index cf8e2fcc..00000000
Binary files a/static/css/images/icons-png/phone-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/phone-white.png b/static/css/images/icons-png/phone-white.png
deleted file mode 100755
index 122a4de6..00000000
Binary files a/static/css/images/icons-png/phone-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/plus-black.png b/static/css/images/icons-png/plus-black.png
deleted file mode 100755
index 0d3d3819..00000000
Binary files a/static/css/images/icons-png/plus-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/plus-white.png b/static/css/images/icons-png/plus-white.png
deleted file mode 100755
index a6aa8337..00000000
Binary files a/static/css/images/icons-png/plus-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/power-black.png b/static/css/images/icons-png/power-black.png
deleted file mode 100755
index 27ba8bbc..00000000
Binary files a/static/css/images/icons-png/power-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/power-white.png b/static/css/images/icons-png/power-white.png
deleted file mode 100755
index 0bfba5d1..00000000
Binary files a/static/css/images/icons-png/power-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/recycle-black.png b/static/css/images/icons-png/recycle-black.png
deleted file mode 100755
index 41222c0f..00000000
Binary files a/static/css/images/icons-png/recycle-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/recycle-white.png b/static/css/images/icons-png/recycle-white.png
deleted file mode 100755
index be0e07a0..00000000
Binary files a/static/css/images/icons-png/recycle-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/refresh-black.png b/static/css/images/icons-png/refresh-black.png
deleted file mode 100755
index e89516e1..00000000
Binary files a/static/css/images/icons-png/refresh-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/refresh-white.png b/static/css/images/icons-png/refresh-white.png
deleted file mode 100755
index d4f38f80..00000000
Binary files a/static/css/images/icons-png/refresh-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/search-black.png b/static/css/images/icons-png/search-black.png
deleted file mode 100755
index 3538c6c4..00000000
Binary files a/static/css/images/icons-png/search-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/search-white.png b/static/css/images/icons-png/search-white.png
deleted file mode 100755
index 530c2360..00000000
Binary files a/static/css/images/icons-png/search-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/shop-black.png b/static/css/images/icons-png/shop-black.png
deleted file mode 100755
index 2f37a11d..00000000
Binary files a/static/css/images/icons-png/shop-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/shop-white.png b/static/css/images/icons-png/shop-white.png
deleted file mode 100755
index 2caa811d..00000000
Binary files a/static/css/images/icons-png/shop-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/star-black.png b/static/css/images/icons-png/star-black.png
deleted file mode 100755
index e8b6398d..00000000
Binary files a/static/css/images/icons-png/star-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/star-white.png b/static/css/images/icons-png/star-white.png
deleted file mode 100755
index 3957d4a5..00000000
Binary files a/static/css/images/icons-png/star-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/tag-black.png b/static/css/images/icons-png/tag-black.png
deleted file mode 100755
index 763d1eaa..00000000
Binary files a/static/css/images/icons-png/tag-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/tag-white.png b/static/css/images/icons-png/tag-white.png
deleted file mode 100755
index a097086c..00000000
Binary files a/static/css/images/icons-png/tag-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/user-black.png b/static/css/images/icons-png/user-black.png
deleted file mode 100755
index 9e33cdce..00000000
Binary files a/static/css/images/icons-png/user-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/user-white.png b/static/css/images/icons-png/user-white.png
deleted file mode 100755
index bec1b9fb..00000000
Binary files a/static/css/images/icons-png/user-white.png and /dev/null differ
diff --git a/static/css/images/icons-png/video-black.png b/static/css/images/icons-png/video-black.png
deleted file mode 100755
index 2c873601..00000000
Binary files a/static/css/images/icons-png/video-black.png and /dev/null differ
diff --git a/static/css/images/icons-png/video-white.png b/static/css/images/icons-png/video-white.png
deleted file mode 100755
index 365c2dca..00000000
Binary files a/static/css/images/icons-png/video-white.png and /dev/null differ
diff --git a/static/css/images/icons-svg/action-black.svg b/static/css/images/icons-svg/action-black.svg
deleted file mode 100755
index 20048d83..00000000
--- a/static/css/images/icons-svg/action-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/action-white.svg b/static/css/images/icons-svg/action-white.svg
deleted file mode 100755
index 23da40d6..00000000
--- a/static/css/images/icons-svg/action-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/alert-black.svg b/static/css/images/icons-svg/alert-black.svg
deleted file mode 100755
index d4179feb..00000000
--- a/static/css/images/icons-svg/alert-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/alert-white.svg b/static/css/images/icons-svg/alert-white.svg
deleted file mode 100755
index ff06604b..00000000
--- a/static/css/images/icons-svg/alert-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-d-black.svg b/static/css/images/icons-svg/arrow-d-black.svg
deleted file mode 100755
index 7a8b7de3..00000000
--- a/static/css/images/icons-svg/arrow-d-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-d-l-black.svg b/static/css/images/icons-svg/arrow-d-l-black.svg
deleted file mode 100755
index 8c8d3057..00000000
--- a/static/css/images/icons-svg/arrow-d-l-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-d-l-white.svg b/static/css/images/icons-svg/arrow-d-l-white.svg
deleted file mode 100755
index f7379cd7..00000000
--- a/static/css/images/icons-svg/arrow-d-l-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-d-r-black.svg b/static/css/images/icons-svg/arrow-d-r-black.svg
deleted file mode 100755
index 95861e05..00000000
--- a/static/css/images/icons-svg/arrow-d-r-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-d-r-white.svg b/static/css/images/icons-svg/arrow-d-r-white.svg
deleted file mode 100755
index 7874ca89..00000000
--- a/static/css/images/icons-svg/arrow-d-r-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-d-white.svg b/static/css/images/icons-svg/arrow-d-white.svg
deleted file mode 100755
index f80ad1bc..00000000
--- a/static/css/images/icons-svg/arrow-d-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-l-black.svg b/static/css/images/icons-svg/arrow-l-black.svg
deleted file mode 100755
index 0190649d..00000000
--- a/static/css/images/icons-svg/arrow-l-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-l-white.svg b/static/css/images/icons-svg/arrow-l-white.svg
deleted file mode 100755
index d9de81d3..00000000
--- a/static/css/images/icons-svg/arrow-l-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-r-black.svg b/static/css/images/icons-svg/arrow-r-black.svg
deleted file mode 100755
index 7853c5f3..00000000
--- a/static/css/images/icons-svg/arrow-r-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-r-white.svg b/static/css/images/icons-svg/arrow-r-white.svg
deleted file mode 100755
index 8c28fc7a..00000000
--- a/static/css/images/icons-svg/arrow-r-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-u-black.svg b/static/css/images/icons-svg/arrow-u-black.svg
deleted file mode 100755
index abf9d90d..00000000
--- a/static/css/images/icons-svg/arrow-u-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-u-l-black.svg b/static/css/images/icons-svg/arrow-u-l-black.svg
deleted file mode 100755
index 08b5c6d5..00000000
--- a/static/css/images/icons-svg/arrow-u-l-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-u-l-white.svg b/static/css/images/icons-svg/arrow-u-l-white.svg
deleted file mode 100755
index 234471ea..00000000
--- a/static/css/images/icons-svg/arrow-u-l-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-u-r-black.svg b/static/css/images/icons-svg/arrow-u-r-black.svg
deleted file mode 100755
index db1536d5..00000000
--- a/static/css/images/icons-svg/arrow-u-r-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-u-r-white.svg b/static/css/images/icons-svg/arrow-u-r-white.svg
deleted file mode 100755
index 5a510f2f..00000000
--- a/static/css/images/icons-svg/arrow-u-r-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/arrow-u-white.svg b/static/css/images/icons-svg/arrow-u-white.svg
deleted file mode 100755
index 7e2aeb22..00000000
--- a/static/css/images/icons-svg/arrow-u-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/audio-black.svg b/static/css/images/icons-svg/audio-black.svg
deleted file mode 100755
index f3651d78..00000000
--- a/static/css/images/icons-svg/audio-black.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/audio-white.svg b/static/css/images/icons-svg/audio-white.svg
deleted file mode 100755
index a6896994..00000000
--- a/static/css/images/icons-svg/audio-white.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/back-black.svg b/static/css/images/icons-svg/back-black.svg
deleted file mode 100755
index d6f928a1..00000000
--- a/static/css/images/icons-svg/back-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/back-white.svg b/static/css/images/icons-svg/back-white.svg
deleted file mode 100755
index b34d43b5..00000000
--- a/static/css/images/icons-svg/back-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/bars-black.svg b/static/css/images/icons-svg/bars-black.svg
deleted file mode 100755
index 1aebe360..00000000
--- a/static/css/images/icons-svg/bars-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/bars-white.svg b/static/css/images/icons-svg/bars-white.svg
deleted file mode 100755
index 98cd3200..00000000
--- a/static/css/images/icons-svg/bars-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/bullets-black.svg b/static/css/images/icons-svg/bullets-black.svg
deleted file mode 100755
index 3bf96803..00000000
--- a/static/css/images/icons-svg/bullets-black.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/bullets-white.svg b/static/css/images/icons-svg/bullets-white.svg
deleted file mode 100755
index ecc4f95f..00000000
--- a/static/css/images/icons-svg/bullets-white.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/calendar-black.svg b/static/css/images/icons-svg/calendar-black.svg
deleted file mode 100755
index 5c3aeded..00000000
--- a/static/css/images/icons-svg/calendar-black.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/calendar-white.svg b/static/css/images/icons-svg/calendar-white.svg
deleted file mode 100755
index 177dab9f..00000000
--- a/static/css/images/icons-svg/calendar-white.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/camera-black.svg b/static/css/images/icons-svg/camera-black.svg
deleted file mode 100755
index 865095df..00000000
--- a/static/css/images/icons-svg/camera-black.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/camera-white.svg b/static/css/images/icons-svg/camera-white.svg
deleted file mode 100755
index b84265c6..00000000
--- a/static/css/images/icons-svg/camera-white.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-d-black.svg b/static/css/images/icons-svg/carat-d-black.svg
deleted file mode 100755
index b6445a7c..00000000
--- a/static/css/images/icons-svg/carat-d-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-d-white.svg b/static/css/images/icons-svg/carat-d-white.svg
deleted file mode 100755
index 4d6d185c..00000000
--- a/static/css/images/icons-svg/carat-d-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-l-black.svg b/static/css/images/icons-svg/carat-l-black.svg
deleted file mode 100755
index 2c8b91fc..00000000
--- a/static/css/images/icons-svg/carat-l-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-l-white.svg b/static/css/images/icons-svg/carat-l-white.svg
deleted file mode 100755
index e18f613c..00000000
--- a/static/css/images/icons-svg/carat-l-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-r-black.svg b/static/css/images/icons-svg/carat-r-black.svg
deleted file mode 100755
index 57cf4979..00000000
--- a/static/css/images/icons-svg/carat-r-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-r-white.svg b/static/css/images/icons-svg/carat-r-white.svg
deleted file mode 100755
index b034d95f..00000000
--- a/static/css/images/icons-svg/carat-r-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-u-black.svg b/static/css/images/icons-svg/carat-u-black.svg
deleted file mode 100755
index 533a7397..00000000
--- a/static/css/images/icons-svg/carat-u-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/carat-u-white.svg b/static/css/images/icons-svg/carat-u-white.svg
deleted file mode 100755
index 670e48b8..00000000
--- a/static/css/images/icons-svg/carat-u-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/check-black.svg b/static/css/images/icons-svg/check-black.svg
deleted file mode 100755
index db5b715c..00000000
--- a/static/css/images/icons-svg/check-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/check-white.svg b/static/css/images/icons-svg/check-white.svg
deleted file mode 100755
index b257fd71..00000000
--- a/static/css/images/icons-svg/check-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/clock-black.svg b/static/css/images/icons-svg/clock-black.svg
deleted file mode 100755
index c68abefb..00000000
--- a/static/css/images/icons-svg/clock-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/clock-white.svg b/static/css/images/icons-svg/clock-white.svg
deleted file mode 100755
index 55892385..00000000
--- a/static/css/images/icons-svg/clock-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/cloud-black.svg b/static/css/images/icons-svg/cloud-black.svg
deleted file mode 100755
index 6fa55f43..00000000
--- a/static/css/images/icons-svg/cloud-black.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/cloud-white.svg b/static/css/images/icons-svg/cloud-white.svg
deleted file mode 100755
index 3e0bde31..00000000
--- a/static/css/images/icons-svg/cloud-white.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/comment-black.svg b/static/css/images/icons-svg/comment-black.svg
deleted file mode 100755
index 485fcc86..00000000
--- a/static/css/images/icons-svg/comment-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/comment-white.svg b/static/css/images/icons-svg/comment-white.svg
deleted file mode 100755
index 8d188db6..00000000
--- a/static/css/images/icons-svg/comment-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/delete-black.svg b/static/css/images/icons-svg/delete-black.svg
deleted file mode 100755
index 74d99888..00000000
--- a/static/css/images/icons-svg/delete-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/delete-white.svg b/static/css/images/icons-svg/delete-white.svg
deleted file mode 100755
index a6cc735c..00000000
--- a/static/css/images/icons-svg/delete-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/edit-black.svg b/static/css/images/icons-svg/edit-black.svg
deleted file mode 100755
index d908f9d9..00000000
--- a/static/css/images/icons-svg/edit-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/edit-white.svg b/static/css/images/icons-svg/edit-white.svg
deleted file mode 100755
index a88643df..00000000
--- a/static/css/images/icons-svg/edit-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/eye-black.svg b/static/css/images/icons-svg/eye-black.svg
deleted file mode 100755
index 7f96a8e7..00000000
--- a/static/css/images/icons-svg/eye-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/eye-white.svg b/static/css/images/icons-svg/eye-white.svg
deleted file mode 100755
index 7b0d0e85..00000000
--- a/static/css/images/icons-svg/eye-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/forbidden-black.svg b/static/css/images/icons-svg/forbidden-black.svg
deleted file mode 100755
index fe831bc6..00000000
--- a/static/css/images/icons-svg/forbidden-black.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/forbidden-white.svg b/static/css/images/icons-svg/forbidden-white.svg
deleted file mode 100755
index 710ac395..00000000
--- a/static/css/images/icons-svg/forbidden-white.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/forward-black.svg b/static/css/images/icons-svg/forward-black.svg
deleted file mode 100755
index 35af7b68..00000000
--- a/static/css/images/icons-svg/forward-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/forward-white.svg b/static/css/images/icons-svg/forward-white.svg
deleted file mode 100755
index 5cd2def3..00000000
--- a/static/css/images/icons-svg/forward-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/gear-black.svg b/static/css/images/icons-svg/gear-black.svg
deleted file mode 100755
index 4f397c5f..00000000
--- a/static/css/images/icons-svg/gear-black.svg
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/gear-white.svg b/static/css/images/icons-svg/gear-white.svg
deleted file mode 100755
index 3a5668fc..00000000
--- a/static/css/images/icons-svg/gear-white.svg
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/grid-black.svg b/static/css/images/icons-svg/grid-black.svg
deleted file mode 100755
index e692e1f8..00000000
--- a/static/css/images/icons-svg/grid-black.svg
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/grid-white.svg b/static/css/images/icons-svg/grid-white.svg
deleted file mode 100755
index 5cfaa7c1..00000000
--- a/static/css/images/icons-svg/grid-white.svg
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/heart-black.svg b/static/css/images/icons-svg/heart-black.svg
deleted file mode 100755
index 77373d5f..00000000
--- a/static/css/images/icons-svg/heart-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/heart-white.svg b/static/css/images/icons-svg/heart-white.svg
deleted file mode 100755
index 48fd304a..00000000
--- a/static/css/images/icons-svg/heart-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/home-black.svg b/static/css/images/icons-svg/home-black.svg
deleted file mode 100755
index a4950a37..00000000
--- a/static/css/images/icons-svg/home-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/home-white.svg b/static/css/images/icons-svg/home-white.svg
deleted file mode 100755
index b7c1a611..00000000
--- a/static/css/images/icons-svg/home-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/info-black.svg b/static/css/images/icons-svg/info-black.svg
deleted file mode 100755
index 151cfa2b..00000000
--- a/static/css/images/icons-svg/info-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/info-white.svg b/static/css/images/icons-svg/info-white.svg
deleted file mode 100755
index dd0f885b..00000000
--- a/static/css/images/icons-svg/info-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/location-black.svg b/static/css/images/icons-svg/location-black.svg
deleted file mode 100755
index 16a59b8f..00000000
--- a/static/css/images/icons-svg/location-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/location-white.svg b/static/css/images/icons-svg/location-white.svg
deleted file mode 100755
index ce48397e..00000000
--- a/static/css/images/icons-svg/location-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/lock-black.svg b/static/css/images/icons-svg/lock-black.svg
deleted file mode 100755
index deb3d489..00000000
--- a/static/css/images/icons-svg/lock-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/lock-white.svg b/static/css/images/icons-svg/lock-white.svg
deleted file mode 100755
index 543cfbb9..00000000
--- a/static/css/images/icons-svg/lock-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/mail-black.svg b/static/css/images/icons-svg/mail-black.svg
deleted file mode 100755
index 827e2983..00000000
--- a/static/css/images/icons-svg/mail-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/mail-white.svg b/static/css/images/icons-svg/mail-white.svg
deleted file mode 100755
index 2f0b7176..00000000
--- a/static/css/images/icons-svg/mail-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/minus-black.svg b/static/css/images/icons-svg/minus-black.svg
deleted file mode 100755
index cd8aec9c..00000000
--- a/static/css/images/icons-svg/minus-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/minus-white.svg b/static/css/images/icons-svg/minus-white.svg
deleted file mode 100755
index 1e33c630..00000000
--- a/static/css/images/icons-svg/minus-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/navigation-black.svg b/static/css/images/icons-svg/navigation-black.svg
deleted file mode 100755
index a09c35e9..00000000
--- a/static/css/images/icons-svg/navigation-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/navigation-white.svg b/static/css/images/icons-svg/navigation-white.svg
deleted file mode 100755
index 38e99c30..00000000
--- a/static/css/images/icons-svg/navigation-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/phone-black.svg b/static/css/images/icons-svg/phone-black.svg
deleted file mode 100755
index 4879050f..00000000
--- a/static/css/images/icons-svg/phone-black.svg
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/phone-white.svg b/static/css/images/icons-svg/phone-white.svg
deleted file mode 100755
index d180382a..00000000
--- a/static/css/images/icons-svg/phone-white.svg
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/plus-black.svg b/static/css/images/icons-svg/plus-black.svg
deleted file mode 100755
index 2e268b01..00000000
--- a/static/css/images/icons-svg/plus-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/plus-white.svg b/static/css/images/icons-svg/plus-white.svg
deleted file mode 100755
index 488129f0..00000000
--- a/static/css/images/icons-svg/plus-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/power-black.svg b/static/css/images/icons-svg/power-black.svg
deleted file mode 100755
index c078e270..00000000
--- a/static/css/images/icons-svg/power-black.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/power-white.svg b/static/css/images/icons-svg/power-white.svg
deleted file mode 100755
index aa5a7a17..00000000
--- a/static/css/images/icons-svg/power-white.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/recycle-black.svg b/static/css/images/icons-svg/recycle-black.svg
deleted file mode 100755
index c481e295..00000000
--- a/static/css/images/icons-svg/recycle-black.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/recycle-white.svg b/static/css/images/icons-svg/recycle-white.svg
deleted file mode 100755
index 11b9c128..00000000
--- a/static/css/images/icons-svg/recycle-white.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/refresh-black.svg b/static/css/images/icons-svg/refresh-black.svg
deleted file mode 100755
index 16c978c4..00000000
--- a/static/css/images/icons-svg/refresh-black.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/refresh-white.svg b/static/css/images/icons-svg/refresh-white.svg
deleted file mode 100755
index fa370e69..00000000
--- a/static/css/images/icons-svg/refresh-white.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/search-black.svg b/static/css/images/icons-svg/search-black.svg
deleted file mode 100755
index 2b9e8637..00000000
--- a/static/css/images/icons-svg/search-black.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/search-white.svg b/static/css/images/icons-svg/search-white.svg
deleted file mode 100755
index 01ccc7c1..00000000
--- a/static/css/images/icons-svg/search-white.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/shop-black.svg b/static/css/images/icons-svg/shop-black.svg
deleted file mode 100755
index 9e1bd39b..00000000
--- a/static/css/images/icons-svg/shop-black.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/shop-white.svg b/static/css/images/icons-svg/shop-white.svg
deleted file mode 100755
index b98cb4bd..00000000
--- a/static/css/images/icons-svg/shop-white.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/star-black.svg b/static/css/images/icons-svg/star-black.svg
deleted file mode 100755
index f2c1afe4..00000000
--- a/static/css/images/icons-svg/star-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/star-white.svg b/static/css/images/icons-svg/star-white.svg
deleted file mode 100755
index d15188e3..00000000
--- a/static/css/images/icons-svg/star-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/tag-black.svg b/static/css/images/icons-svg/tag-black.svg
deleted file mode 100755
index bd11ae67..00000000
--- a/static/css/images/icons-svg/tag-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/tag-white.svg b/static/css/images/icons-svg/tag-white.svg
deleted file mode 100755
index 7cd4a50a..00000000
--- a/static/css/images/icons-svg/tag-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/user-black.svg b/static/css/images/icons-svg/user-black.svg
deleted file mode 100755
index 7530c987..00000000
--- a/static/css/images/icons-svg/user-black.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/user-white.svg b/static/css/images/icons-svg/user-white.svg
deleted file mode 100755
index 5528c2e9..00000000
--- a/static/css/images/icons-svg/user-white.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/video-black.svg b/static/css/images/icons-svg/video-black.svg
deleted file mode 100755
index cc501814..00000000
--- a/static/css/images/icons-svg/video-black.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/images/icons-svg/video-white.svg b/static/css/images/icons-svg/video-white.svg
deleted file mode 100755
index ddcdf16d..00000000
--- a/static/css/images/icons-svg/video-white.svg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
diff --git a/static/css/jquery.mobile-1.4.2.min.css b/static/css/jquery.mobile-1.4.2.min.css
deleted file mode 100644
index f17e1267..00000000
--- a/static/css/jquery.mobile-1.4.2.min.css
+++ /dev/null
@@ -1,3 +0,0 @@
-/*! jQuery Mobile 1.4.2 | Git HEAD hash: 9d9a42a <> 2014-02-28T17:32:01Z | (c) 2010, 2014 jQuery Foundation, Inc. | jquery.org/license */
-
-.ui-icon-action:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M9%2C5v3l5-4L9%2C0v3c0%2C0-5%2C0-5%2C7C6%2C5%2C9%2C5%2C9%2C5z%20M11%2C12H2V5h1l2-2H0v11h13V7l-2%2C2V12z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-alert:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M7%2C0L0%2C12h14L7%2C0z%20M7%2C11c-0.553%2C0-1-0.447-1-1s0.447-1%2C1-1c0.553%2C0%2C1%2C0.447%2C1%2C1S7.553%2C11%2C7%2C11z%20M7%2C8%20C6.447%2C8%2C6%2C7.553%2C6%2C7V5c0-0.553%2C0.447-1%2C1-1c0.553%2C0%2C1%2C0.447%2C1%2C1v2C8%2C7.553%2C7.553%2C8%2C7%2C8z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-arrow-d-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%2214%2C3%2011%2C0%203.5%2C7.5%200%2C4%200%2C14%2010%2C14%206.5%2C10.5%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-arrow-d-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%2210.5%2C7.5%203%2C0%200%2C3%207.5%2C10.5%204%2C14%2014%2C14%2014%2C4%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-arrow-d:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%229%2C7%209%2C0%205%2C0%205%2C7%200%2C7%207%2C14%2014%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-arrow-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%227%2C5%207%2C0%200%2C7%207%2C14%207%2C9%2014%2C9%2014%2C5%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-arrow-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%2214%2C7%207%2C0%207%2C5%200%2C5%200%2C9%207%2C9%207%2C14%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-arrow-u-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%2214%2C11%206.5%2C3.5%2010%2C0%200%2C0%200%2C10%203.5%2C6.5%2011%2C14%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-arrow-u-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%2214%2C0%204%2C0%207.5%2C3.5%200%2C11%203%2C14%2010.5%2C6.5%2014%2C10%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-arrow-u:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%227%2C0%200%2C7%205%2C7%205%2C14%209%2C14%209%2C7%2014%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-audio:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214.018px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014.018%2014%22%20style%3D%22enable-background%3Anew%200%200%2014.018%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M1%2C4C0.447%2C4%2C0%2C4.447%2C0%2C5v4c0%2C0.553%2C0.447%2C1%2C1%2C1h1l4%2C4V0L2%2C4H1z%20M10.346%2C7c0-1.699-1.042-3.154-2.546-3.867L6.982%2C4.68%20C7.885%2C5.107%2C8.51%2C5.98%2C8.51%2C7S7.885%2C8.893%2C6.982%2C9.32L7.8%2C10.867C9.304%2C10.154%2C10.346%2C8.699%2C10.346%2C7z%20M9.447%2C0.017L8.618%2C1.586%20C10.723%2C2.584%2C12.182%2C4.621%2C12.182%2C7s-1.459%2C4.416-3.563%2C5.414l0.829%2C1.569c2.707-1.283%2C4.57-3.925%2C4.57-6.983%20S12.154%2C1.3%2C9.447%2C0.017z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-back:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M5%2C3V0L1%2C4l4%2C4V5c0%2C0%2C6%2C0%2C6%2C3s-5%2C4-5%2C4v2c0%2C0%2C7-1%2C7-6C13%2C4%2C8%2C3%2C5%2C3z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-bars:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M1%2C4h12c0.553%2C0%2C1-0.447%2C1-1s-0.447-1-1-1H1C0.447%2C2%2C0%2C2.447%2C0%2C3S0.447%2C4%2C1%2C4z%20M13%2C6H1%20C0.447%2C6%2C0%2C6.447%2C0%2C7c0%2C0.553%2C0.447%2C1%2C1%2C1h12c0.553%2C0%2C1-0.447%2C1-1C14%2C6.447%2C13.553%2C6%2C13%2C6z%20M13%2C10H1c-0.553%2C0-1%2C0.447-1%2C1%20s0.447%2C1%2C1%2C1h12c0.553%2C0%2C1-0.447%2C1-1S13.553%2C10%2C13%2C10z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-bullets:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M5%2C4h8c0.553%2C0%2C1-0.447%2C1-1s-0.447-1-1-1H5C4.447%2C2%2C4%2C2.447%2C4%2C3S4.447%2C4%2C5%2C4z%20M13%2C6H5%20C4.447%2C6%2C4%2C6.447%2C4%2C7c0%2C0.553%2C0.447%2C1%2C1%2C1h8c0.553%2C0%2C1-0.447%2C1-1C14%2C6.447%2C13.553%2C6%2C13%2C6z%20M13%2C10H5c-0.553%2C0-1%2C0.447-1%2C1%20s0.447%2C1%2C1%2C1h8c0.553%2C0%2C1-0.447%2C1-1S13.553%2C10%2C13%2C10z%20M1%2C2C0.447%2C2%2C0%2C2.447%2C0%2C3s0.447%2C1%2C1%2C1s1-0.447%2C1-1S1.553%2C2%2C1%2C2z%20M1%2C6%20C0.447%2C6%2C0%2C6.447%2C0%2C7c0%2C0.553%2C0.447%2C1%2C1%2C1s1-0.447%2C1-1C2%2C6.447%2C1.553%2C6%2C1%2C6z%20M1%2C10c-0.553%2C0-1%2C0.447-1%2C1s0.447%2C1%2C1%2C1s1-0.447%2C1-1%20S1.553%2C10%2C1%2C10z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-calendar:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M0%2C8h2V6H0V8z%20M3%2C8h2V6H3V8z%20M6%2C8h2V6H6V8z%20M9%2C8h2V6H9V8z%20M12%2C8h2V6h-2V8z%20M0%2C11h2V9H0V11z%20M3%2C11h2V9H3V11z%20M6%2C11h2V9H6V11z%20%20M9%2C11h2V9H9V11z%20M12%2C11h2V9h-2V11z%20M0%2C14h2v-2H0V14z%20M3%2C14h2v-2H3V14z%20M6%2C14h2v-2H6V14z%20M9%2C14h2v-2H9V14z%20M12%2C1%20c0-0.553-0.447-1-1-1s-1%2C0.447-1%2C1H4c0-0.553-0.447-1-1-1S2%2C0.447%2C2%2C1H0v4h14V1H12z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-camera:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M12%2C2.5H9.908c-0.206-0.581-0.756-1-1.408-1h-3c-0.652%2C0-1.202%2C0.419-1.408%2C1H2c-1.104%2C0-2%2C0.896-2%2C2%20v6c0%2C1.104%2C0.896%2C2%2C2%2C2h10c1.104%2C0%2C2-0.896%2C2-2v-6C14%2C3.396%2C13.104%2C2.5%2C12%2C2.5z%20M7%2C10.5c-1.657%2C0-3-1.344-3-3c0-1.657%2C1.343-3%2C3-3%20s3%2C1.343%2C3%2C3C10%2C9.156%2C8.657%2C10.5%2C7%2C10.5z%20M7%2C5.5c-1.104%2C0-2%2C0.896-2%2C2c0%2C1.104%2C0.896%2C2%2C2%2C2c1.104%2C0%2C2-0.896%2C2-2%20C9%2C6.396%2C8.104%2C5.5%2C7%2C5.5z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-carat-d:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20style%3D%22fill%3A%23FFFFFF%3B%22%20points%3D%2211.949%2C3.404%207%2C8.354%202.05%2C3.404%20-0.071%2C5.525%207%2C12.596%2014.07%2C5.525%20%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-carat-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20style%3D%22fill%3A%23FFFFFF%3B%22%20points%3D%2210.596%2C11.949%205.646%2C7%2010.596%2C2.05%208.475%2C-0.071%201.404%2C7%208.475%2C14.07%20%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-carat-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20style%3D%22fill%3A%23FFFFFF%3B%22%20points%3D%223.404%2C2.051%208.354%2C7%203.404%2C11.95%205.525%2C14.07%2012.596%2C7%205.525%2C-0.071%20%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-carat-u:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20style%3D%22fill%3A%23FFFFFF%3B%22%20points%3D%222.051%2C10.596%207%2C5.646%2011.95%2C10.596%2014.07%2C8.475%207%2C1.404%20-0.071%2C8.475%20%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-check:after,html .ui-btn.ui-checkbox-on.ui-checkbox-on:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20style%3D%22fill%3A%23FFFFFF%3B%22%20points%3D%2214%2C4%2011%2C1%205.003%2C6.997%203%2C5%200%2C8%204.966%2C13%204.983%2C12.982%205%2C13%20%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-clock:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M7%2C0C3.134%2C0%2C0%2C3.134%2C0%2C7s3.134%2C7%2C7%2C7s7-3.134%2C7-7S10.866%2C0%2C7%2C0z%20M7%2C12c-2.762%2C0-5-2.238-5-5s2.238-5%2C5-5s5%2C2.238%2C5%2C5%20S9.762%2C12%2C7%2C12z%20M9%2C6H8V4c0-0.553-0.447-1-1-1S6%2C3.447%2C6%2C4v3c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1S9.553%2C6%2C9%2C6z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-cloud:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M14%2C9.5c0-0.793-0.465-1.473-1.134-1.795C12.949%2C7.484%2C13%2C7.249%2C13%2C7c0-1.104-0.896-2-2-2%20c-0.158%2C0-0.311%2C0.023-0.457%2C0.058C9.816%2C3.549%2C8.286%2C2.5%2C6.5%2C2.5c-2.33%2C0-4.224%2C1.777-4.454%2C4.046C0.883%2C6.76%2C0%2C7.773%2C0%2C9%20c0%2C1.381%2C1.119%2C2.5%2C2.5%2C2.5h10v-0.07C13.361%2C11.206%2C14%2C10.432%2C14%2C9.5z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-comment:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M12%2C0H2C0.896%2C0%2C0%2C0.896%2C0%2C2v7c0%2C1.104%2C0.896%2C2%2C2%2C2h1v3l3-3h6c1.104%2C0%2C2-0.896%2C2-2V2C14%2C0.896%2C13.104%2C0%2C12%2C0z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-delete:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%2214%2C3%2011%2C0%207%2C4%203%2C0%200%2C3%204%2C7%200%2C11%203%2C14%207%2C10%2011%2C14%2014%2C11%2010%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-edit:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M1%2C10l-1%2C4l4-1l7-7L8%2C3L1%2C10z%20M11%2C0L9%2C2l3%2C3l2-2L11%2C0z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-eye:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M7%2C2C3%2C2%2C0%2C7%2C0%2C7s3%2C5%2C7%2C5s7-5%2C7-5S11%2C2%2C7%2C2z%20M7%2C10c-1.657%2C0-3-1.344-3-3c0-1.657%2C1.343-3%2C3-3%20s3%2C1.343%2C3%2C3C10%2C8.656%2C8.657%2C10%2C7%2C10z%20M7%2C6C6.448%2C6%2C6%2C6.447%2C6%2C7c0%2C0.553%2C0.448%2C1%2C1%2C1s1-0.447%2C1-1C8%2C6.447%2C7.552%2C6%2C7%2C6z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-forbidden:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M12.601%2C11.187C13.476%2C10.018%2C14%2C8.572%2C14%2C7c0-3.866-3.134-7-7-7C5.428%2C0%2C3.982%2C0.524%2C2.813%2C1.399L2.757%2C1.343L2.053%2C2.048%20L2.048%2C2.053L1.343%2C2.758l0.056%2C0.056C0.524%2C3.982%2C0%2C5.428%2C0%2C7c0%2C3.866%2C3.134%2C7%2C7%2C7c1.572%2C0%2C3.018-0.524%2C4.187-1.399l0.056%2C0.057%20l0.705-0.705l0.005-0.005l0.705-0.705L12.601%2C11.187z%20M7%2C2c2.761%2C0%2C5%2C2.238%2C5%2C5c0%2C1.019-0.308%2C1.964-0.832%2C2.754L4.246%2C2.832%20C5.036%2C2.308%2C5.981%2C2%2C7%2C2z%20M7%2C12c-2.761%2C0-5-2.238-5-5c0-1.019%2C0.308-1.964%2C0.832-2.754l6.922%2C6.922C8.964%2C11.692%2C8.019%2C12%2C7%2C12z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-forward:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M13%2C4L9%2C0v3C6%2C3%2C1%2C4%2C1%2C8c0%2C5%2C7%2C6%2C7%2C6v-2c0%2C0-5-1-5-4s6-3%2C6-3v3L13%2C4z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-gear:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M13.621%2C5.904l-1.036-0.259c-0.168-0.042-0.303-0.168-0.355-0.332c-0.092-0.284-0.205-0.559-0.339-0.82%20c-0.079-0.153-0.073-0.337%2C0.017-0.486l0.549-0.915c0.118-0.196%2C0.088-0.448-0.075-0.61l-0.862-0.863%20c-0.162-0.163-0.414-0.193-0.611-0.075l-0.916%2C0.55C9.844%2C2.182%2C9.659%2C2.188%2C9.506%2C2.109C9.244%2C1.975%2C8.97%2C1.861%2C8.686%2C1.77%20c-0.165-0.052-0.29-0.187-0.332-0.354L8.095%2C0.379C8.039%2C0.156%2C7.839%2C0%2C7.609%2C0H6.391c-0.229%2C0-0.43%2C0.156-0.485%2C0.379L5.646%2C1.415%20C5.604%2C1.582%2C5.479%2C1.718%2C5.313%2C1.77c-0.284%2C0.092-0.559%2C0.206-0.82%2C0.34C4.339%2C2.188%2C4.155%2C2.182%2C4.007%2C2.093L3.092%2C1.544%20c-0.196-0.118-0.448-0.087-0.61%2C0.075L1.619%2C2.481C1.457%2C2.644%2C1.426%2C2.896%2C1.544%2C3.093l0.549%2C0.914%20c0.089%2C0.148%2C0.095%2C0.332%2C0.017%2C0.486C1.975%2C4.755%2C1.861%2C5.029%2C1.77%2C5.314c-0.053%2C0.164-0.188%2C0.29-0.354%2C0.332L0.379%2C5.905%20C0.156%2C5.961%2C0%2C6.161%2C0%2C6.391v1.219c0%2C0.229%2C0.156%2C0.43%2C0.379%2C0.485l1.036%2C0.26C1.582%2C8.396%2C1.717%2C8.521%2C1.77%2C8.687%20c0.092%2C0.284%2C0.205%2C0.559%2C0.34%2C0.82C2.188%2C9.66%2C2.182%2C9.844%2C2.093%2C9.993l-0.549%2C0.915c-0.118%2C0.195-0.087%2C0.448%2C0.075%2C0.61%20l0.862%2C0.862c0.162%2C0.163%2C0.414%2C0.193%2C0.61%2C0.075l0.915-0.549c0.148-0.089%2C0.332-0.095%2C0.486-0.017%20c0.262%2C0.135%2C0.536%2C0.248%2C0.82%2C0.34c0.165%2C0.053%2C0.291%2C0.187%2C0.332%2C0.354l0.259%2C1.036C5.96%2C13.844%2C6.16%2C14%2C6.39%2C14h1.22%20c0.229%2C0%2C0.43-0.156%2C0.485-0.379l0.259-1.036c0.042-0.167%2C0.168-0.302%2C0.333-0.354c0.284-0.092%2C0.559-0.205%2C0.82-0.34%20c0.154-0.078%2C0.338-0.072%2C0.486%2C0.017l0.914%2C0.549c0.197%2C0.118%2C0.449%2C0.088%2C0.611-0.074l0.862-0.863%20c0.163-0.162%2C0.193-0.415%2C0.075-0.611l-0.549-0.915c-0.089-0.148-0.096-0.332-0.017-0.485c0.134-0.263%2C0.248-0.536%2C0.339-0.82%20c0.053-0.165%2C0.188-0.291%2C0.355-0.333l1.036-0.259C13.844%2C8.039%2C14%2C7.839%2C14%2C7.609V6.39C14%2C6.16%2C13.844%2C5.96%2C13.621%2C5.904z%20M7%2C10%20c-1.657%2C0-3-1.343-3-3s1.343-3%2C3-3s3%2C1.343%2C3%2C3S8.657%2C10%2C7%2C10z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-grid:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M3%2C0H1C0.447%2C0%2C0%2C0.447%2C0%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V1C4%2C0.447%2C3.553%2C0%2C3%2C0z%20M8%2C0H6%20C5.447%2C0%2C5%2C0.447%2C5%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V1C9%2C0.447%2C8.553%2C0%2C8%2C0z%20M13%2C0h-2c-0.553%2C0-1%2C0.447-1%2C1v2%20c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V1C14%2C0.447%2C13.553%2C0%2C13%2C0z%20M3%2C5H1C0.447%2C5%2C0%2C5.447%2C0%2C6v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2%20c0.553%2C0%2C1-0.447%2C1-1V6C4%2C5.447%2C3.553%2C5%2C3%2C5z%20M8%2C5H6C5.447%2C5%2C5%2C5.447%2C5%2C6v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V6%20C9%2C5.447%2C8.553%2C5%2C8%2C5z%20M13%2C5h-2c-0.553%2C0-1%2C0.447-1%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V6C14%2C5.447%2C13.553%2C5%2C13%2C5z%20M3%2C10%20H1c-0.553%2C0-1%2C0.447-1%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1v-2C4%2C10.447%2C3.553%2C10%2C3%2C10z%20M8%2C10H6c-0.553%2C0-1%2C0.447-1%2C1v2%20c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1v-2C9%2C10.447%2C8.553%2C10%2C8%2C10z%20M13%2C10h-2c-0.553%2C0-1%2C0.447-1%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2%20c0.553%2C0%2C1-0.447%2C1-1v-2C14%2C10.447%2C13.553%2C10%2C13%2C10z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-heart:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M7%2C1.872c-2-3-7-2-7%2C2c0%2C3%2C4%2C7%2C4%2C7s2.417%2C2.479%2C3%2C3c0.583-0.521%2C3-3%2C3-3s4-4%2C4-7%20C14-0.128%2C9-1.128%2C7%2C1.872z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-home:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%227%2C0%200%2C7%202%2C7%202%2C14%205%2C14%205%2C9%209%2C9%209%2C14%2012%2C14%2012%2C7%2014%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-info:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M7%2C0C3.134%2C0%2C0%2C3.134%2C0%2C7s3.134%2C7%2C7%2C7s7-3.134%2C7-7S10.866%2C0%2C7%2C0z%20M7%2C2c0.552%2C0%2C1%2C0.447%2C1%2C1S7.552%2C4%2C7%2C4S6%2C3.553%2C6%2C3%20S6.448%2C2%2C7%2C2z%20M9%2C11H5v-1h1V6H5V5h3v5h1V11z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-location:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M7%2C0C4.791%2C0%2C3%2C1.791%2C3%2C4c0%2C2%2C4%2C10%2C4%2C10s4-8%2C4-10C11%2C1.791%2C9.209%2C0%2C7%2C0z%20M7%2C6C5.896%2C6%2C5%2C5.104%2C5%2C4%20s0.896-2%2C2-2c1.104%2C0%2C2%2C0.896%2C2%2C2S8.104%2C6%2C7%2C6z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-lock:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M12%2C6V5c0-2.762-2.238-5-5-5C4.239%2C0%2C2%2C2.238%2C2%2C5v1H1v8h12V6H12z%20M7.5%2C9.848V12h-1V9.848%20C6.207%2C9.673%2C6%2C9.366%2C6%2C9c0-0.553%2C0.448-1%2C1-1s1%2C0.447%2C1%2C1C8%2C9.366%2C7.793%2C9.673%2C7.5%2C9.848z%20M10%2C6H4V5c0-1.657%2C1.343-3%2C3-3%20s3%2C1.343%2C3%2C3V6z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-mail:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M0%2C3.75V12h14V3.75L7%2C9L0%2C3.75z%20M14%2C2H0l7%2C5L14%2C2z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-minus:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Crect%20y%3D%225%22%20style%3D%22fill%3A%23FFFFFF%3B%22%20width%3D%2214%22%20height%3D%224%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-navigation:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20style%3D%22fill%3A%23FFFFFF%3B%22%20points%3D%2213%2C1%200%2C6%207%2C7%208%2C14%20%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-phone:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%22-0.01%200.008%2014%2014%22%20style%3D%22enable-background%3Anew%20-0.01%200.008%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M6.939%2C9.189C6.165%2C8.557%2C5.271%2C7.705%2C4.497%2C6.744C3.953%2C6.071%2C3.473%2C5.363%2C3.969%2C4.866l-3.482-3.48%20C-0.021%2C2.02-1.146%2C5.04%2C3.675%2C9.984c5.08%2C5.211%2C8.356%2C4.097%2C8.92%2C3.511l-3.396-3.4C8.725%2C10.568%2C8.113%2C10.146%2C6.939%2C9.189z%20%20M13.82%2C11.519v-0.004c0%2C0-2.648-2.646-2.649-2.647c-0.21-0.211-0.546-0.205-0.754%2C0.002L9.455%2C9.831l3.403%2C3.407%20c0%2C0%2C0.962-0.96%2C0.961-0.961l0.002-0.001C14.043%2C12.056%2C14.021%2C11.721%2C13.82%2C11.519z%20M5.192%2C3.644V3.642%20c0.222-0.222%2C0.2-0.557%2C0-0.758V2.881c0%2C0-2.726-2.725-2.727-2.726C2.255-0.055%2C1.92-0.05%2C1.712%2C0.156L0.751%2C1.121l3.479%2C3.482%20C4.231%2C4.604%2C5.192%2C3.645%2C5.192%2C3.644z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-plus:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23FFF%22%20points%3D%2214%2C5%209%2C5%209%2C0%205%2C0%205%2C5%200%2C5%200%2C9%205%2C9%205%2C14%209%2C14%209%2C9%2014%2C9%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-power:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M11.243%2C2.408c-0.392-0.401-1.024-0.401-1.415%2C0c-0.391%2C0.401-0.391%2C1.054%2C0%2C1.455%20C10.584%2C4.642%2C11%2C5.675%2C11%2C6.773s-0.416%2C2.133-1.172%2C2.91c-1.512%2C1.558-4.145%2C1.558-5.656%2C0C3.416%2C8.904%2C3%2C7.872%2C3%2C6.773%20C3%2C5.673%2C3.416%2C4.64%2C4.172%2C3.863c0.39-0.401%2C0.39-1.054%2C0-1.455c-0.391-0.401-1.024-0.401-1.415%2C0C1.624%2C3.574%2C1%2C5.125%2C1%2C6.773%20c0%2C1.647%2C0.624%2C3.199%2C1.757%2C4.365c1.134%2C1.166%2C2.64%2C1.809%2C4.243%2C1.809c1.604%2C0%2C3.109-0.645%2C4.243-1.811%20C12.376%2C9.975%2C13%2C8.423%2C13%2C6.773C13%2C5.125%2C12.376%2C3.574%2C11.243%2C2.408z%20M7%2C8.053c0.553%2C0%2C1-0.445%2C1-1v-6c0-0.553-0.447-1-1-1%20c-0.553%2C0-1%2C0.447-1%2C1v6C6%2C7.604%2C6.447%2C8.053%2C7%2C8.053z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-recycle:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M3%2C7h1L2%2C4L0%2C7h1c0%2C3.313%2C2.687%2C6%2C6%2C6c0.702%2C0%2C1.374-0.127%2C2-0.35v-2.205C8.41%2C10.789%2C7.732%2C11%2C7%2C11%20C4.791%2C11%2C3%2C9.209%2C3%2C7z%20M13%2C7c0-3.313-2.688-6-6-6C6.298%2C1%2C5.626%2C1.127%2C5%2C1.349v2.206C5.59%2C3.211%2C6.268%2C3%2C7%2C3c2.209%2C0%2C4%2C1.791%2C4%2C4%20h-1l2%2C3l2-3H13z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-refresh:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214.001px%22%20height%3D%2214.002px%22%20viewBox%3D%220%200%2014.001%2014.002%22%20style%3D%22enable-background%3Anew%200%200%2014.001%2014.002%3B%22%20%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M14.001%2C6.001v-6l-2.06%2C2.06c-0.423-0.424-0.897-0.809-1.44-1.122C7.153-0.994%2C2.872%2C0.153%2C0.939%2C3.501%20c-1.933%2C3.348-0.786%2C7.629%2C2.562%2C9.562c3.348%2C1.933%2C7.629%2C0.785%2C9.562-2.562l-1.732-1c-1.381%2C2.392-4.438%2C3.211-6.83%2C1.83%20s-3.211-4.438-1.83-6.83s4.438-3.211%2C6.83-1.83c0.389%2C0.225%2C0.718%2C0.506%2C1.02%2C0.81l-2.52%2C2.52H14.001z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-search:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M10.171%2C8.766c0.617-0.888%2C0.979-1.964%2C0.979-3.126c0-3.037-2.463-5.5-5.5-5.5s-5.5%2C2.463-5.5%2C5.5%20s2.463%2C5.5%2C5.5%2C5.5c1.152%2C0%2C2.223-0.355%2C3.104-0.962l3.684%2C3.683l1.414-1.414L10.171%2C8.766z%20M5.649%2C9.14c-1.933%2C0-3.5-1.567-3.5-3.5%20c0-1.933%2C1.567-3.5%2C3.5-3.5c1.933%2C0%2C3.5%2C1.567%2C3.5%2C3.5C9.149%2C7.572%2C7.582%2C9.14%2C5.649%2C9.14z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-shop:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M10%2C4V3c0-1.657-1.343-3-3-3S4%2C1.343%2C4%2C3v1H1v10h12V4H10z%20M4.5%2C6C4.224%2C6%2C4%2C5.776%2C4%2C5.5%20S4.224%2C5%2C4.5%2C5S5%2C5.224%2C5%2C5.5S4.776%2C6%2C4.5%2C6z%20M5%2C3c0-1.104%2C0.896-2%2C2-2c1.104%2C0%2C2%2C0.896%2C2%2C2v1H5V3z%20M9.5%2C6C9.225%2C6%2C9%2C5.776%2C9%2C5.5%20S9.225%2C5%2C9.5%2C5S10%2C5.224%2C10%2C5.5S9.775%2C6%2C9.5%2C6z%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-star:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20style%3D%22fill%3A%23FFFFFF%3B%22%20points%3D%2214%2C5%209%2C5%207%2C0%205%2C5%200%2C5%204%2C8%202.625%2C13%207%2C10%2011.375%2C13%2010%2C8%20%22%2F%3E%3C%2Fsvg%3E")}.ui-icon-tag:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M5%2C0H0v5l9%2C9l5-5L5%2C0z%20M3%2C4C2.447%2C4%2C2%2C3.553%2C2%2C3s0.447-1%2C1-1s1%2C0.447%2C1%2C1S3.553%2C4%2C3%2C4z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-user:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23FFF%22%20d%3D%22M8.851%2C10.101c-0.18-0.399-0.2-0.763-0.153-1.104C9.383%2C8.49%2C9.738%2C7.621%2C9.891%2C6.465C10.493%2C6.355%2C10.5%2C5.967%2C10.5%2C5.5%20c0-0.437-0.008-0.804-0.502-0.94C9.999%2C4.539%2C10%2C4.521%2C10%2C4.5c0-2.103-1-4-2-4C8%2C0.5%2C7.5%2C0%2C6.5%2C0C5%2C0%2C4%2C1.877%2C4%2C4.5%20c0%2C0.021%2C0.001%2C0.039%2C0.002%2C0.06C3.508%2C4.696%2C3.5%2C5.063%2C3.5%2C5.5c0%2C0.467%2C0.007%2C0.855%2C0.609%2C0.965%20C4.262%2C7.621%2C4.617%2C8.49%2C5.303%2C8.997c0.047%2C0.341%2C0.026%2C0.704-0.153%2C1.104C1.503%2C10.503%2C0%2C12%2C0%2C12v2h14v-2%20C14%2C12%2C12.497%2C10.503%2C8.851%2C10.101z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-icon-video:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%20-2%2014%2014%22%20style%3D%22enable-background%3Anew%200%20-2%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20style%3D%22fill%3A%23FFFFFF%3B%22%20d%3D%22M8%2C0H2C0.896%2C0%2C0%2C0.896%2C0%2C2v6c0%2C1.104%2C0.896%2C2%2C2%2C2h6c1.104%2C0%2C2-0.896%2C2-2V5V2C10%2C0.896%2C9.104%2C0%2C8%2C0z%20%20M10%2C5l4%2C4V1L10%2C5z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-action:after,.ui-alt-icon .ui-icon-action:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M9%2C5v3l5-4L9%2C0v3c0%2C0-5%2C0-5%2C7C6%2C5%2C9%2C5%2C9%2C5z%20M11%2C12H2V5h1l2-2H0v11h13V7l-2%2C2V12z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-alert:after,.ui-alt-icon .ui-icon-alert:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M7%2C0L0%2C12h14L7%2C0z%20M7%2C11c-0.553%2C0-1-0.447-1-1s0.447-1%2C1-1c0.553%2C0%2C1%2C0.447%2C1%2C1S7.553%2C11%2C7%2C11z%20M7%2C8C6.447%2C8%2C6%2C7.553%2C6%2C7V5%20c0-0.553%2C0.447-1%2C1-1c0.553%2C0%2C1%2C0.447%2C1%2C1v2C8%2C7.553%2C7.553%2C8%2C7%2C8z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-d:after,.ui-alt-icon .ui-icon-arrow-d:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%229%2C7%209%2C0%205%2C0%205%2C7%200%2C7%207%2C14%2014%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-d-l:after,.ui-alt-icon .ui-icon-arrow-d-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C3%2011%2C0%203.5%2C7.5%200%2C4%200%2C14%2010%2C14%206.5%2C10.5%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-d-r:after,.ui-alt-icon .ui-icon-arrow-d-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2210.5%2C7.5%203%2C0%200%2C3%207.5%2C10.5%204%2C14%2014%2C14%2014%2C4%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-l:after,.ui-alt-icon .ui-icon-arrow-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%227%2C5%207%2C0%200%2C7%207%2C14%207%2C9%2014%2C9%2014%2C5%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-r:after,.ui-alt-icon .ui-icon-arrow-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C7%207%2C0%207%2C5%200%2C5%200%2C9%207%2C9%207%2C14%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-u:after,.ui-alt-icon .ui-icon-arrow-u:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%227%2C0%200%2C7%205%2C7%205%2C14%209%2C14%209%2C7%2014%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-u-l:after,.ui-alt-icon .ui-icon-arrow-u-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C11%206.5%2C3.5%2010%2C0%200%2C0%200%2C10%203.5%2C6.5%2011%2C14%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-arrow-u-r:after,.ui-alt-icon .ui-icon-arrow-u-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C0%204%2C0%207.5%2C3.5%200%2C11%203%2C14%2010.5%2C6.5%2014%2C10%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-audio:after,.ui-alt-icon .ui-icon-audio:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214.018px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014.018%2014%22%20style%3D%22enable-background%3Anew%200%200%2014.018%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M1%2C4C0.447%2C4%2C0%2C4.447%2C0%2C5v4c0%2C0.553%2C0.447%2C1%2C1%2C1h1l4%2C4V0L2%2C4H1z%20M10.346%2C7c0-1.699-1.042-3.154-2.546-3.867L6.982%2C4.68%20C7.885%2C5.107%2C8.51%2C5.98%2C8.51%2C7S7.885%2C8.893%2C6.982%2C9.32L7.8%2C10.867C9.304%2C10.154%2C10.346%2C8.699%2C10.346%2C7z%20M9.447%2C0.017L8.618%2C1.586%20C10.723%2C2.584%2C12.182%2C4.621%2C12.182%2C7s-1.459%2C4.416-3.563%2C5.414l0.829%2C1.569c2.707-1.283%2C4.57-3.925%2C4.57-6.983%20S12.154%2C1.3%2C9.447%2C0.017z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-back:after,.ui-alt-icon .ui-icon-back:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M5%2C3V0L1%2C4l4%2C4V5c0%2C0%2C6%2C0%2C6%2C3s-5%2C4-5%2C4v2c0%2C0%2C7-1%2C7-6C13%2C4%2C8%2C3%2C5%2C3z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-bars:after,.ui-alt-icon .ui-icon-bars:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M1%2C4h12c0.553%2C0%2C1-0.447%2C1-1s-0.447-1-1-1H1C0.447%2C2%2C0%2C2.447%2C0%2C3S0.447%2C4%2C1%2C4z%20M13%2C6H1C0.447%2C6%2C0%2C6.447%2C0%2C7%20c0%2C0.553%2C0.447%2C1%2C1%2C1h12c0.553%2C0%2C1-0.447%2C1-1C14%2C6.447%2C13.553%2C6%2C13%2C6z%20M13%2C10H1c-0.553%2C0-1%2C0.447-1%2C1s0.447%2C1%2C1%2C1h12%20c0.553%2C0%2C1-0.447%2C1-1S13.553%2C10%2C13%2C10z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-bullets:after,.ui-alt-icon .ui-icon-bullets:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M5%2C4h8c0.553%2C0%2C1-0.447%2C1-1s-0.447-1-1-1H5C4.447%2C2%2C4%2C2.447%2C4%2C3S4.447%2C4%2C5%2C4z%20M13%2C6H5C4.447%2C6%2C4%2C6.447%2C4%2C7%20c0%2C0.553%2C0.447%2C1%2C1%2C1h8c0.553%2C0%2C1-0.447%2C1-1C14%2C6.447%2C13.553%2C6%2C13%2C6z%20M13%2C10H5c-0.553%2C0-1%2C0.447-1%2C1s0.447%2C1%2C1%2C1h8%20c0.553%2C0%2C1-0.447%2C1-1S13.553%2C10%2C13%2C10z%20M1%2C2C0.447%2C2%2C0%2C2.447%2C0%2C3s0.447%2C1%2C1%2C1s1-0.447%2C1-1S1.553%2C2%2C1%2C2z%20M1%2C6C0.447%2C6%2C0%2C6.447%2C0%2C7%20c0%2C0.553%2C0.447%2C1%2C1%2C1s1-0.447%2C1-1C2%2C6.447%2C1.553%2C6%2C1%2C6z%20M1%2C10c-0.553%2C0-1%2C0.447-1%2C1s0.447%2C1%2C1%2C1s1-0.447%2C1-1S1.553%2C10%2C1%2C10z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-calendar:after,.ui-alt-icon .ui-icon-calendar:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M0%2C8h2V6H0V8z%20M3%2C8h2V6H3V8z%20M6%2C8h2V6H6V8z%20M9%2C8h2V6H9V8z%20M12%2C8h2V6h-2V8z%20M0%2C11h2V9H0V11z%20M3%2C11h2V9H3V11z%20M6%2C11h2V9H6V11z%20%20M9%2C11h2V9H9V11z%20M12%2C11h2V9h-2V11z%20M0%2C14h2v-2H0V14z%20M3%2C14h2v-2H3V14z%20M6%2C14h2v-2H6V14z%20M9%2C14h2v-2H9V14z%20M12%2C1%20c0-0.553-0.447-1-1-1s-1%2C0.447-1%2C1H4c0-0.553-0.447-1-1-1S2%2C0.447%2C2%2C1H0v4h14V1H12z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-camera:after,.ui-alt-icon .ui-icon-camera:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M12%2C2.5H9.908c-0.206-0.581-0.756-1-1.408-1h-3c-0.652%2C0-1.202%2C0.419-1.408%2C1H2c-1.104%2C0-2%2C0.896-2%2C2v6c0%2C1.104%2C0.896%2C2%2C2%2C2%20h10c1.104%2C0%2C2-0.896%2C2-2v-6C14%2C3.396%2C13.104%2C2.5%2C12%2C2.5z%20M7%2C10.5c-1.657%2C0-3-1.344-3-3c0-1.657%2C1.343-3%2C3-3s3%2C1.343%2C3%2C3%20C10%2C9.156%2C8.657%2C10.5%2C7%2C10.5z%20M7%2C5.5c-1.104%2C0-2%2C0.896-2%2C2c0%2C1.104%2C0.896%2C2%2C2%2C2c1.104%2C0%2C2-0.896%2C2-2C9%2C6.396%2C8.104%2C5.5%2C7%2C5.5z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-carat-d:after,.ui-alt-icon .ui-icon-carat-d:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2211.949%2C3.404%207%2C8.354%202.05%2C3.404%20-0.071%2C5.525%207%2C12.596%2014.07%2C5.525%20%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-carat-l:after,.ui-alt-icon .ui-icon-carat-l:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2210.596%2C11.949%205.646%2C7%2010.596%2C2.05%208.475%2C-0.071%201.404%2C7%208.475%2C14.07%20%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-carat-r:after,.ui-alt-icon .ui-icon-carat-r:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%223.404%2C2.051%208.354%2C7%203.404%2C11.95%205.525%2C14.07%2012.596%2C7%205.525%2C-0.071%20%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-carat-u:after,.ui-alt-icon .ui-icon-carat-u:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%222.051%2C10.596%207%2C5.646%2011.95%2C10.596%2014.07%2C8.475%207%2C1.404%20-0.071%2C8.475%20%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-check:after,.ui-alt-icon .ui-icon-check:after,html .ui-alt-icon.ui-btn.ui-checkbox-on:after,html .ui-alt-icon .ui-btn.ui-checkbox-on:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C4%2011%2C1%205.003%2C6.997%203%2C5%200%2C8%204.966%2C13%204.983%2C12.982%205%2C13%20%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-clock:after,.ui-alt-icon .ui-icon-clock:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M7%2C0C3.134%2C0%2C0%2C3.134%2C0%2C7s3.134%2C7%2C7%2C7s7-3.134%2C7-7S10.866%2C0%2C7%2C0z%20M7%2C12c-2.762%2C0-5-2.238-5-5s2.238-5%2C5-5s5%2C2.238%2C5%2C5%20S9.762%2C12%2C7%2C12z%20M9%2C6H8V4c0-0.553-0.447-1-1-1S6%2C3.447%2C6%2C4v3c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1S9.553%2C6%2C9%2C6z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-cloud:after,.ui-alt-icon .ui-icon-cloud:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M14%2C9.5c0-0.793-0.465-1.473-1.134-1.795C12.949%2C7.484%2C13%2C7.249%2C13%2C7c0-1.104-0.896-2-2-2c-0.158%2C0-0.311%2C0.023-0.457%2C0.058%20C9.816%2C3.549%2C8.286%2C2.5%2C6.5%2C2.5c-2.33%2C0-4.224%2C1.777-4.454%2C4.046C0.883%2C6.76%2C0%2C7.773%2C0%2C9c0%2C1.381%2C1.119%2C2.5%2C2.5%2C2.5h10v-0.07%20C13.361%2C11.206%2C14%2C10.432%2C14%2C9.5z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-comment:after,.ui-alt-icon .ui-icon-comment:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M12%2C0H2C0.896%2C0%2C0%2C0.896%2C0%2C2v7c0%2C1.104%2C0.896%2C2%2C2%2C2h1v3l3-3h6c1.104%2C0%2C2-0.896%2C2-2V2C14%2C0.896%2C13.104%2C0%2C12%2C0z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-delete:after,.ui-alt-icon .ui-icon-delete:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C3%2011%2C0%207%2C4%203%2C0%200%2C3%204%2C7%200%2C11%203%2C14%207%2C10%2011%2C14%2014%2C11%2010%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-edit:after,.ui-alt-icon .ui-icon-edit:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M1%2C10l-1%2C4l4-1l7-7L8%2C3L1%2C10z%20M11%2C0L9%2C2l3%2C3l2-2L11%2C0z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-eye:after,.ui-alt-icon .ui-icon-eye:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M7%2C2C3%2C2%2C0%2C7%2C0%2C7s3%2C5%2C7%2C5s7-5%2C7-5S11%2C2%2C7%2C2z%20M7%2C10c-1.657%2C0-3-1.344-3-3c0-1.657%2C1.343-3%2C3-3s3%2C1.343%2C3%2C3%20C10%2C8.656%2C8.657%2C10%2C7%2C10z%20M7%2C6C6.448%2C6%2C6%2C6.447%2C6%2C7c0%2C0.553%2C0.448%2C1%2C1%2C1s1-0.447%2C1-1C8%2C6.447%2C7.552%2C6%2C7%2C6z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-forbidden:after,.ui-alt-icon .ui-icon-forbidden:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M12.601%2C11.187C13.476%2C10.018%2C14%2C8.572%2C14%2C7c0-3.866-3.134-7-7-7C5.428%2C0%2C3.982%2C0.524%2C2.813%2C1.399L2.757%2C1.343L2.053%2C2.048%20L2.048%2C2.053L1.343%2C2.758l0.056%2C0.056C0.524%2C3.982%2C0%2C5.428%2C0%2C7c0%2C3.866%2C3.134%2C7%2C7%2C7c1.572%2C0%2C3.018-0.524%2C4.187-1.399l0.056%2C0.057%20l0.705-0.705l0.005-0.005l0.705-0.705L12.601%2C11.187z%20M7%2C2c2.761%2C0%2C5%2C2.238%2C5%2C5c0%2C1.019-0.308%2C1.964-0.832%2C2.754L4.246%2C2.832%20C5.036%2C2.308%2C5.981%2C2%2C7%2C2z%20M7%2C12c-2.761%2C0-5-2.238-5-5c0-1.019%2C0.308-1.964%2C0.832-2.754l6.922%2C6.922C8.964%2C11.692%2C8.019%2C12%2C7%2C12z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-forward:after,.ui-alt-icon .ui-icon-forward:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M13%2C4L9%2C0v3C6%2C3%2C1%2C4%2C1%2C8c0%2C5%2C7%2C6%2C7%2C6v-2c0%2C0-5-1-5-4s6-3%2C6-3v3L13%2C4z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-gear:after,.ui-alt-icon .ui-icon-gear:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M13.621%2C5.904l-1.036-0.259c-0.168-0.042-0.303-0.168-0.355-0.332c-0.092-0.284-0.205-0.559-0.339-0.82%20c-0.079-0.153-0.073-0.337%2C0.017-0.486l0.549-0.915c0.118-0.196%2C0.088-0.448-0.075-0.61l-0.862-0.863%20c-0.162-0.163-0.414-0.193-0.611-0.075l-0.916%2C0.55C9.844%2C2.182%2C9.659%2C2.188%2C9.506%2C2.109C9.244%2C1.975%2C8.97%2C1.861%2C8.686%2C1.77%20c-0.165-0.052-0.29-0.187-0.332-0.354L8.095%2C0.379C8.039%2C0.156%2C7.839%2C0%2C7.609%2C0H6.391c-0.229%2C0-0.43%2C0.156-0.485%2C0.379L5.646%2C1.415%20C5.604%2C1.582%2C5.479%2C1.718%2C5.313%2C1.77c-0.284%2C0.092-0.559%2C0.206-0.82%2C0.34C4.339%2C2.188%2C4.155%2C2.182%2C4.007%2C2.093L3.092%2C1.544%20c-0.196-0.118-0.448-0.087-0.61%2C0.075L1.619%2C2.481C1.457%2C2.644%2C1.426%2C2.896%2C1.544%2C3.093l0.549%2C0.914%20c0.089%2C0.148%2C0.095%2C0.332%2C0.017%2C0.486C1.975%2C4.755%2C1.861%2C5.029%2C1.77%2C5.314c-0.053%2C0.164-0.188%2C0.29-0.354%2C0.332L0.379%2C5.905%20C0.156%2C5.961%2C0%2C6.161%2C0%2C6.391v1.219c0%2C0.229%2C0.156%2C0.43%2C0.379%2C0.485l1.036%2C0.26C1.582%2C8.396%2C1.717%2C8.521%2C1.77%2C8.687%20c0.092%2C0.284%2C0.205%2C0.559%2C0.34%2C0.82C2.188%2C9.66%2C2.182%2C9.844%2C2.093%2C9.993l-0.549%2C0.915c-0.118%2C0.195-0.087%2C0.448%2C0.075%2C0.61%20l0.862%2C0.862c0.162%2C0.163%2C0.414%2C0.193%2C0.61%2C0.075l0.915-0.549c0.148-0.089%2C0.332-0.095%2C0.486-0.017%20c0.262%2C0.135%2C0.536%2C0.248%2C0.82%2C0.34c0.165%2C0.053%2C0.291%2C0.187%2C0.332%2C0.354l0.259%2C1.036C5.96%2C13.844%2C6.16%2C14%2C6.39%2C14h1.22%20c0.229%2C0%2C0.43-0.156%2C0.485-0.379l0.259-1.036c0.042-0.167%2C0.168-0.302%2C0.333-0.354c0.284-0.092%2C0.559-0.205%2C0.82-0.34%20c0.154-0.078%2C0.338-0.072%2C0.486%2C0.017l0.914%2C0.549c0.197%2C0.118%2C0.449%2C0.088%2C0.611-0.074l0.862-0.863%20c0.163-0.162%2C0.193-0.415%2C0.075-0.611l-0.549-0.915c-0.089-0.148-0.096-0.332-0.017-0.485c0.134-0.263%2C0.248-0.536%2C0.339-0.82%20c0.053-0.165%2C0.188-0.291%2C0.355-0.333l1.036-0.259C13.844%2C8.039%2C14%2C7.839%2C14%2C7.609V6.39C14%2C6.16%2C13.844%2C5.96%2C13.621%2C5.904z%20M7%2C10%20c-1.657%2C0-3-1.343-3-3s1.343-3%2C3-3s3%2C1.343%2C3%2C3S8.657%2C10%2C7%2C10z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-grid:after,.ui-alt-icon .ui-icon-grid:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M3%2C0H1C0.447%2C0%2C0%2C0.447%2C0%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V1C4%2C0.447%2C3.553%2C0%2C3%2C0z%20M8%2C0H6%20C5.447%2C0%2C5%2C0.447%2C5%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V1C9%2C0.447%2C8.553%2C0%2C8%2C0z%20M13%2C0h-2c-0.553%2C0-1%2C0.447-1%2C1v2%20c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V1C14%2C0.447%2C13.553%2C0%2C13%2C0z%20M3%2C5H1C0.447%2C5%2C0%2C5.447%2C0%2C6v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2%20c0.553%2C0%2C1-0.447%2C1-1V6C4%2C5.447%2C3.553%2C5%2C3%2C5z%20M8%2C5H6C5.447%2C5%2C5%2C5.447%2C5%2C6v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V6%20C9%2C5.447%2C8.553%2C5%2C8%2C5z%20M13%2C5h-2c-0.553%2C0-1%2C0.447-1%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1V6C14%2C5.447%2C13.553%2C5%2C13%2C5z%20M3%2C10%20H1c-0.553%2C0-1%2C0.447-1%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1v-2C4%2C10.447%2C3.553%2C10%2C3%2C10z%20M8%2C10H6c-0.553%2C0-1%2C0.447-1%2C1v2%20c0%2C0.553%2C0.447%2C1%2C1%2C1h2c0.553%2C0%2C1-0.447%2C1-1v-2C9%2C10.447%2C8.553%2C10%2C8%2C10z%20M13%2C10h-2c-0.553%2C0-1%2C0.447-1%2C1v2c0%2C0.553%2C0.447%2C1%2C1%2C1h2%20c0.553%2C0%2C1-0.447%2C1-1v-2C14%2C10.447%2C13.553%2C10%2C13%2C10z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-heart:after,.ui-alt-icon .ui-icon-heart:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M7%2C1.958c-2-3-7-2.128-7%2C1.872c0%2C3%2C4%2C7%2C4%2C7s2.417%2C2.48%2C3%2C3c0.583-0.52%2C3-3%2C3-3s4-4%2C4-7C14-0.169%2C9-1.042%2C7%2C1.958z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-home:after,.ui-alt-icon .ui-icon-home:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%227%2C0%200%2C7%202%2C7%202%2C14%205%2C14%205%2C9%209%2C9%209%2C14%2012%2C14%2012%2C7%2014%2C7%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-info:after,.ui-alt-icon .ui-icon-info:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M7%2C0C3.134%2C0%2C0%2C3.134%2C0%2C7s3.134%2C7%2C7%2C7s7-3.134%2C7-7S10.866%2C0%2C7%2C0z%20M7%2C2c0.552%2C0%2C1%2C0.447%2C1%2C1S7.552%2C4%2C7%2C4S6%2C3.553%2C6%2C3%20S6.448%2C2%2C7%2C2z%20M9%2C11H5v-1h1V6H5V5h3v5h1V11z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-location:after,.ui-alt-icon .ui-icon-location:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M7%2C0C4.791%2C0%2C3%2C1.791%2C3%2C4c0%2C2%2C4%2C10%2C4%2C10s4-8%2C4-10C11%2C1.791%2C9.209%2C0%2C7%2C0z%20M7%2C6C5.896%2C6%2C5%2C5.104%2C5%2C4s0.896-2%2C2-2%20c1.104%2C0%2C2%2C0.896%2C2%2C2S8.104%2C6%2C7%2C6z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-lock:after,.ui-alt-icon .ui-icon-lock:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M12%2C6V5c0-2.762-2.238-5-5-5C4.239%2C0%2C2%2C2.238%2C2%2C5v1H1v8h12V6H12z%20M7.5%2C9.848V12h-1V9.848C6.207%2C9.673%2C6%2C9.366%2C6%2C9%20c0-0.553%2C0.448-1%2C1-1s1%2C0.447%2C1%2C1C8%2C9.366%2C7.793%2C9.673%2C7.5%2C9.848z%20M10%2C6H4V5c0-1.657%2C1.343-3%2C3-3s3%2C1.343%2C3%2C3V6z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-mail:after,.ui-alt-icon .ui-icon-mail:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M0%2C3.75V12h14V3.75L7%2C9L0%2C3.75z%20M14%2C2H0l7%2C5L14%2C2z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-minus:after,.ui-alt-icon .ui-icon-minus:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Crect%20y%3D%225%22%20width%3D%2214%22%20height%3D%224%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-navigation:after,.ui-alt-icon .ui-icon-navigation:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2213%2C1%200%2C6%207%2C7%208%2C14%20%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-phone:after,.ui-alt-icon .ui-icon-phone:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M6.949%2C9.182C6.175%2C8.549%2C5.281%2C7.697%2C4.507%2C6.736C3.963%2C6.063%2C3.483%2C5.355%2C3.979%2C4.858l-3.482-3.48%20c-0.508%2C0.634-1.633%2C3.654%2C3.188%2C8.598c5.08%2C5.211%2C8.356%2C4.097%2C8.92%2C3.511l-3.396-3.399C8.734%2C10.561%2C8.123%2C10.139%2C6.949%2C9.182z%20%20M13.83%2C11.512v-0.004c0%2C0-2.648-2.646-2.649-2.647c-0.21-0.212-0.546-0.205-0.754%2C0.002L9.465%2C9.823l3.402%2C3.407%20c0%2C0%2C0.963-0.961%2C0.961-0.961l0.002-0.002C14.053%2C12.049%2C14.031%2C11.713%2C13.83%2C11.512z%20M5.202%2C3.636V3.634%20c0.222-0.222%2C0.2-0.557%2C0-0.758V2.873c0%2C0-2.726-2.725-2.727-2.726c-0.21-0.21-0.545-0.205-0.753%2C0.001L0.761%2C1.113L4.24%2C4.595%20C4.241%2C4.596%2C5.202%2C3.637%2C5.202%2C3.636z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-plus:after,.ui-alt-icon .ui-icon-plus:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C5%209%2C5%209%2C0%205%2C0%205%2C5%200%2C5%200%2C9%205%2C9%205%2C14%209%2C14%209%2C9%2014%2C9%20%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-power:after,.ui-alt-icon .ui-icon-power:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M11.243%2C2.408c-0.392-0.401-1.024-0.401-1.415%2C0c-0.391%2C0.401-0.391%2C1.054%2C0%2C1.455C10.584%2C4.642%2C11%2C5.675%2C11%2C6.773%20s-0.416%2C2.133-1.172%2C2.91c-1.512%2C1.558-4.145%2C1.558-5.656%2C0C3.416%2C8.904%2C3%2C7.872%2C3%2C6.773C3%2C5.673%2C3.416%2C4.64%2C4.172%2C3.863%20c0.39-0.401%2C0.39-1.054%2C0-1.455c-0.391-0.401-1.024-0.401-1.415%2C0C1.624%2C3.574%2C1%2C5.125%2C1%2C6.773c0%2C1.647%2C0.624%2C3.199%2C1.757%2C4.365%20c1.134%2C1.166%2C2.64%2C1.809%2C4.243%2C1.809c1.604%2C0%2C3.109-0.645%2C4.243-1.811C12.376%2C9.975%2C13%2C8.423%2C13%2C6.773%20C13%2C5.125%2C12.376%2C3.574%2C11.243%2C2.408z%20M7%2C8.053c0.553%2C0%2C1-0.445%2C1-1v-6c0-0.553-0.447-1-1-1c-0.553%2C0-1%2C0.447-1%2C1v6%20C6%2C7.604%2C6.447%2C8.053%2C7%2C8.053z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-recycle:after,.ui-alt-icon .ui-icon-recycle:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M3%2C7h1L2%2C4L0%2C7h1c0%2C3.313%2C2.687%2C6%2C6%2C6c0.702%2C0%2C1.374-0.127%2C2-0.35v-2.205C8.41%2C10.789%2C7.732%2C11%2C7%2C11C4.791%2C11%2C3%2C9.209%2C3%2C7z%20%20M13%2C7c0-3.313-2.688-6-6-6C6.298%2C1%2C5.626%2C1.127%2C5%2C1.349v2.206C5.59%2C3.211%2C6.268%2C3%2C7%2C3c2.209%2C0%2C4%2C1.791%2C4%2C4h-1l2%2C3l2-3H13z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-refresh:after,.ui-alt-icon .ui-icon-refresh:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214.001px%22%20height%3D%2214.002px%22%20viewBox%3D%220%200%2014.001%2014.002%22%20style%3D%22enable-background%3Anew%200%200%2014.001%2014.002%3B%22%20%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M14.001%2C6.001v-6l-2.06%2C2.06c-0.423-0.424-0.897-0.809-1.44-1.122C7.153-0.994%2C2.872%2C0.153%2C0.939%2C3.501%20c-1.933%2C3.348-0.786%2C7.629%2C2.562%2C9.562c3.348%2C1.933%2C7.629%2C0.785%2C9.562-2.562l-1.732-1c-1.381%2C2.392-4.438%2C3.211-6.83%2C1.83%20s-3.211-4.438-1.83-6.83s4.438-3.211%2C6.83-1.83c0.389%2C0.225%2C0.718%2C0.506%2C1.02%2C0.81l-2.52%2C2.52H14.001z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-search:after,.ui-alt-icon .ui-icon-search:after,.ui-input-search:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M10.171%2C8.766c0.617-0.888%2C0.979-1.964%2C0.979-3.126c0-3.037-2.463-5.5-5.5-5.5s-5.5%2C2.463-5.5%2C5.5s2.463%2C5.5%2C5.5%2C5.5%20c1.152%2C0%2C2.223-0.355%2C3.104-0.962l3.684%2C3.683l1.414-1.414L10.171%2C8.766z%20M5.649%2C9.14c-1.933%2C0-3.5-1.567-3.5-3.5%20c0-1.933%2C1.567-3.5%2C3.5-3.5c1.933%2C0%2C3.5%2C1.567%2C3.5%2C3.5C9.149%2C7.572%2C7.582%2C9.14%2C5.649%2C9.14z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-shop:after,.ui-alt-icon .ui-icon-shop:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M10%2C4V3c0-1.657-1.343-3-3-3S4%2C1.343%2C4%2C3v1H1v10h12V4H10z%20M4.5%2C6C4.224%2C6%2C4%2C5.776%2C4%2C5.5S4.224%2C5%2C4.5%2C5S5%2C5.224%2C5%2C5.5%20S4.776%2C6%2C4.5%2C6z%20M5%2C3c0-1.104%2C0.896-2%2C2-2c1.104%2C0%2C2%2C0.896%2C2%2C2v1H5V3z%20M9.5%2C6C9.225%2C6%2C9%2C5.776%2C9%2C5.5S9.225%2C5%2C9.5%2C5S10%2C5.224%2C10%2C5.5%20S9.775%2C6%2C9.5%2C6z%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-star:after,.ui-alt-icon .ui-icon-star:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20points%3D%2214%2C5%209%2C5%207%2C0%205%2C5%200%2C5%204%2C8%202.625%2C13%207%2C10%2011.375%2C13%2010%2C8%20%22%2F%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-tag:after,.ui-alt-icon .ui-icon-tag:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M5%2C0H0v5l9%2C9l5-5L5%2C0z%20M3%2C4C2.447%2C4%2C2%2C3.553%2C2%2C3s0.447-1%2C1-1s1%2C0.447%2C1%2C1S3.553%2C4%2C3%2C4z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-user:after,.ui-alt-icon .ui-icon-user:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2014%2014%22%20style%3D%22enable-background%3Anew%200%200%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M8.851%2C10.101c-0.18-0.399-0.2-0.763-0.153-1.104C9.383%2C8.49%2C9.738%2C7.621%2C9.891%2C6.465C10.493%2C6.355%2C10.5%2C5.967%2C10.5%2C5.5%20c0-0.437-0.008-0.804-0.502-0.94C9.999%2C4.539%2C10%2C4.521%2C10%2C4.5c0-2.103-1-4-2-4C8%2C0.5%2C7.5%2C0%2C6.5%2C0C5%2C0%2C4%2C1.877%2C4%2C4.5%20c0%2C0.021%2C0.001%2C0.039%2C0.002%2C0.06C3.508%2C4.696%2C3.5%2C5.063%2C3.5%2C5.5c0%2C0.467%2C0.007%2C0.855%2C0.609%2C0.965%20C4.262%2C7.621%2C4.617%2C8.49%2C5.303%2C8.997c0.047%2C0.341%2C0.026%2C0.704-0.153%2C1.104C1.503%2C10.503%2C0%2C12%2C0%2C12v2h14v-2%20C14%2C12%2C12.497%2C10.503%2C8.851%2C10.101z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E")}.ui-alt-icon.ui-icon-video:after,.ui-alt-icon .ui-icon-video:after{background-image:url("data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2214px%22%20height%3D%2214px%22%20viewBox%3D%220%20-2%2014%2014%22%20style%3D%22enable-background%3Anew%200%20-2%2014%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M8%2C0H2C0.896%2C0%2C0%2C0.896%2C0%2C2v6c0%2C1.104%2C0.896%2C2%2C2%2C2h6c1.104%2C0%2C2-0.896%2C2-2V5V2C10%2C0.896%2C9.104%2C0%2C8%2C0z%20M10%2C5l4%2C4V1L10%2C5z%22%2F%3E%3C%2Fsvg%3E")}.ui-nosvg .ui-icon-action:after{background-image:url(http://github.com/images/icons-png/action-white.png)}.ui-nosvg .ui-icon-alert:after{background-image:url(http://github.com/images/icons-png/alert-white.png)}.ui-nosvg .ui-icon-arrow-d-l:after{background-image:url(http://github.com/images/icons-png/arrow-d-l-white.png)}.ui-nosvg .ui-icon-arrow-d-r:after{background-image:url(http://github.com/images/icons-png/arrow-d-r-white.png)}.ui-nosvg .ui-icon-arrow-d:after{background-image:url(http://github.com/images/icons-png/arrow-d-white.png)}.ui-nosvg .ui-icon-arrow-l:after{background-image:url(http://github.com/images/icons-png/arrow-l-white.png)}.ui-nosvg .ui-icon-arrow-r:after{background-image:url(http://github.com/images/icons-png/arrow-r-white.png)}.ui-nosvg .ui-icon-arrow-u-l:after{background-image:url(http://github.com/images/icons-png/arrow-u-l-white.png)}.ui-nosvg .ui-icon-arrow-u-r:after{background-image:url(http://github.com/images/icons-png/arrow-u-r-white.png)}.ui-nosvg .ui-icon-arrow-u:after{background-image:url(http://github.com/images/icons-png/arrow-u-white.png)}.ui-nosvg .ui-icon-audio:after{background-image:url(http://github.com/images/icons-png/audio-white.png)}.ui-nosvg .ui-icon-back:after{background-image:url(http://github.com/images/icons-png/back-white.png)}.ui-nosvg .ui-icon-bars:after{background-image:url(http://github.com/images/icons-png/bars-white.png)}.ui-nosvg .ui-icon-bullets:after{background-image:url(http://github.com/images/icons-png/bullets-white.png)}.ui-nosvg .ui-icon-calendar:after{background-image:url(http://github.com/images/icons-png/calendar-white.png)}.ui-nosvg .ui-icon-camera:after{background-image:url(http://github.com/images/icons-png/camera-white.png)}.ui-nosvg .ui-icon-carat-d:after{background-image:url(http://github.com/images/icons-png/carat-d-white.png)}.ui-nosvg .ui-icon-carat-l:after{background-image:url(http://github.com/images/icons-png/carat-l-white.png)}.ui-nosvg .ui-icon-carat-r:after{background-image:url(http://github.com/images/icons-png/carat-r-white.png)}.ui-nosvg .ui-icon-carat-u:after{background-image:url(http://github.com/images/icons-png/carat-u-white.png)}.ui-nosvg .ui-icon-check:after,html.ui-nosvg .ui-btn.ui-checkbox-on:after{background-image:url(http://github.com/images/icons-png/check-white.png)}.ui-nosvg .ui-icon-clock:after{background-image:url(http://github.com/images/icons-png/clock-white.png)}.ui-nosvg .ui-icon-cloud:after{background-image:url(http://github.com/images/icons-png/cloud-white.png)}.ui-nosvg .ui-icon-comment:after{background-image:url(http://github.com/images/icons-png/comment-white.png)}.ui-nosvg .ui-icon-delete:after{background-image:url(http://github.com/images/icons-png/delete-white.png)}.ui-nosvg .ui-icon-edit:after{background-image:url(http://github.com/images/icons-png/edit-white.png)}.ui-nosvg .ui-icon-eye:after{background-image:url(http://github.com/images/icons-png/eye-white.png)}.ui-nosvg .ui-icon-forbidden:after{background-image:url(http://github.com/images/icons-png/forbidden-white.png)}.ui-nosvg .ui-icon-forward:after{background-image:url(http://github.com/images/icons-png/forward-white.png)}.ui-nosvg .ui-icon-gear:after{background-image:url(http://github.com/images/icons-png/gear-white.png)}.ui-nosvg .ui-icon-grid:after{background-image:url(http://github.com/images/icons-png/grid-white.png)}.ui-nosvg .ui-icon-heart:after{background-image:url(http://github.com/images/icons-png/heart-white.png)}.ui-nosvg .ui-icon-home:after{background-image:url(http://github.com/images/icons-png/home-white.png)}.ui-nosvg .ui-icon-info:after{background-image:url(http://github.com/images/icons-png/info-white.png)}.ui-nosvg .ui-icon-location:after{background-image:url(http://github.com/images/icons-png/location-white.png)}.ui-nosvg .ui-icon-lock:after{background-image:url(http://github.com/images/icons-png/lock-white.png)}.ui-nosvg .ui-icon-mail:after{background-image:url(http://github.com/images/icons-png/mail-white.png)}.ui-nosvg .ui-icon-minus:after{background-image:url(http://github.com/images/icons-png/minus-white.png)}.ui-nosvg .ui-icon-navigation:after{background-image:url(http://github.com/images/icons-png/navigation-white.png)}.ui-nosvg .ui-icon-phone:after{background-image:url(http://github.com/images/icons-png/phone-white.png)}.ui-nosvg .ui-icon-plus:after{background-image:url(http://github.com/images/icons-png/plus-white.png)}.ui-nosvg .ui-icon-power:after{background-image:url(http://github.com/images/icons-png/power-white.png)}.ui-nosvg .ui-icon-recycle:after{background-image:url(http://github.com/images/icons-png/recycle-white.png)}.ui-nosvg .ui-icon-refresh:after{background-image:url(http://github.com/images/icons-png/refresh-white.png)}.ui-nosvg .ui-icon-search:after{background-image:url(http://github.com/images/icons-png/search-white.png)}.ui-nosvg .ui-icon-shop:after{background-image:url(http://github.com/images/icons-png/shop-white.png)}.ui-nosvg .ui-icon-star:after{background-image:url(http://github.com/images/icons-png/star-white.png)}.ui-nosvg .ui-icon-tag:after{background-image:url(http://github.com/images/icons-png/tag-white.png)}.ui-nosvg .ui-icon-user:after{background-image:url(http://github.com/images/icons-png/user-white.png)}.ui-nosvg .ui-icon-video:after{background-image:url(http://github.com/images/icons-png/video-white.png)}.ui-nosvg .ui-alt-icon.ui-icon-action:after,.ui-nosvg .ui-alt-icon .ui-icon-action:after{background-image:url(http://github.com/images/icons-png/action-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-alert:after,.ui-nosvg .ui-alt-icon .ui-icon-alert:after{background-image:url(http://github.com/images/icons-png/alert-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-d:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-d:after{background-image:url(http://github.com/images/icons-png/arrow-d-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-d-l:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-d-l:after{background-image:url(http://github.com/images/icons-png/arrow-d-l-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-d-r:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-d-r:after{background-image:url(http://github.com/images/icons-png/arrow-d-r-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-l:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-l:after{background-image:url(http://github.com/images/icons-png/arrow-l-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-r:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-r:after{background-image:url(http://github.com/images/icons-png/arrow-r-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-u:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-u:after{background-image:url(http://github.com/images/icons-png/arrow-u-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-u-l:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-u-l:after{background-image:url(http://github.com/images/icons-png/arrow-u-l-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-arrow-u-r:after,.ui-nosvg .ui-alt-icon .ui-icon-arrow-u-r:after{background-image:url(http://github.com/images/icons-png/arrow-u-r-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-audio:after,.ui-nosvg .ui-alt-icon .ui-icon-audio:after{background-image:url(http://github.com/images/icons-png/audio-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-back:after,.ui-nosvg .ui-alt-icon .ui-icon-back:after{background-image:url(http://github.com/images/icons-png/back-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-bars:after,.ui-nosvg .ui-alt-icon .ui-icon-bars:after{background-image:url(http://github.com/images/icons-png/bars-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-bullets:after,.ui-nosvg .ui-alt-icon .ui-icon-bullets:after{background-image:url(http://github.com/images/icons-png/bullets-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-calendar:after,.ui-nosvg .ui-alt-icon .ui-icon-calendar:after{background-image:url(http://github.com/images/icons-png/calendar-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-camera:after,.ui-nosvg .ui-alt-icon .ui-icon-camera:after{background-image:url(http://github.com/images/icons-png/camera-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-carat-d:after,.ui-nosvg .ui-alt-icon .ui-icon-carat-d:after{background-image:url(http://github.com/images/icons-png/carat-d-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-carat-l:after,.ui-nosvg .ui-alt-icon .ui-icon-carat-l:after{background-image:url(http://github.com/images/icons-png/carat-l-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-carat-r:after,.ui-nosvg .ui-alt-icon .ui-icon-carat-r:after{background-image:url(http://github.com/images/icons-png/carat-r-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-carat-u:after,.ui-nosvg .ui-alt-icon .ui-icon-carat-u:after{background-image:url(http://github.com/images/icons-png/carat-u-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-check:after,.ui-nosvg .ui-alt-icon .ui-icon-check:after,.ui-nosvg .ui-alt-icon.ui-btn.ui-checkbox-on:after,.ui-nosvg .ui-alt-icon .ui-btn.ui-checkbox-on:after{background-image:url(http://github.com/images/icons-png/check-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-clock:after,.ui-nosvg .ui-alt-icon .ui-icon-clock:after{background-image:url(http://github.com/images/icons-png/clock-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-cloud:after,.ui-nosvg .ui-alt-icon .ui-icon-cloud:after{background-image:url(http://github.com/images/icons-png/cloud-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-comment:after,.ui-nosvg .ui-alt-icon .ui-icon-comment:after{background-image:url(http://github.com/images/icons-png/comment-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-delete:after,.ui-nosvg .ui-alt-icon .ui-icon-delete:after{background-image:url(http://github.com/images/icons-png/delete-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-edit:after,.ui-nosvg .ui-alt-icon .ui-icon-edit:after{background-image:url(http://github.com/images/icons-png/edit-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-eye:after,.ui-nosvg .ui-alt-icon .ui-icon-eye:after{background-image:url(http://github.com/images/icons-png/eye-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-forbidden:after,.ui-nosvg .ui-alt-icon .ui-icon-forbidden:after{background-image:url(http://github.com/images/icons-png/forbidden-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-forward:after,.ui-nosvg .ui-alt-icon .ui-icon-forward:after{background-image:url(http://github.com/images/icons-png/forward-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-gear:after,.ui-nosvg .ui-alt-icon .ui-icon-gear:after{background-image:url(http://github.com/images/icons-png/gear-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-grid:after,.ui-nosvg .ui-alt-icon .ui-icon-grid:after{background-image:url(http://github.com/images/icons-png/grid-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-heart:after,.ui-nosvg .ui-alt-icon .ui-icon-heart:after{background-image:url(http://github.com/images/icons-png/heart-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-home:after,.ui-nosvg .ui-alt-icon .ui-icon-home:after{background-image:url(http://github.com/images/icons-png/home-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-info:after,.ui-nosvg .ui-alt-icon .ui-icon-info:after{background-image:url(http://github.com/images/icons-png/info-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-location:after,.ui-nosvg .ui-alt-icon .ui-icon-location:after{background-image:url(http://github.com/images/icons-png/location-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-lock:after,.ui-nosvg .ui-alt-icon .ui-icon-lock:after{background-image:url(http://github.com/images/icons-png/lock-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-mail:after,.ui-nosvg .ui-alt-icon .ui-icon-mail:after{background-image:url(http://github.com/images/icons-png/mail-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-minus:after,.ui-nosvg .ui-alt-icon .ui-icon-minus:after{background-image:url(http://github.com/images/icons-png/minus-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-navigation:after,.ui-nosvg .ui-alt-icon .ui-icon-navigation:after{background-image:url(http://github.com/images/icons-png/navigation-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-phone:after,.ui-nosvg .ui-alt-icon .ui-icon-phone:after{background-image:url(http://github.com/images/icons-png/phone-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-plus:after,.ui-nosvg .ui-alt-icon .ui-icon-plus:after{background-image:url(http://github.com/images/icons-png/plus-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-power:after,.ui-nosvg .ui-alt-icon .ui-icon-power:after{background-image:url(http://github.com/images/icons-png/power-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-recycle:after,.ui-nosvg .ui-alt-icon .ui-icon-recycle:after{background-image:url(http://github.com/images/icons-png/recycle-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-refresh:after,.ui-nosvg .ui-alt-icon .ui-icon-refresh:after{background-image:url(http://github.com/images/icons-png/refresh-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-search:after,.ui-nosvg .ui-alt-icon .ui-icon-search:after,.ui-nosvg .ui-input-search:after{background-image:url(http://github.com/images/icons-png/search-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-shop:after,.ui-nosvg .ui-alt-icon .ui-icon-shop:after{background-image:url(http://github.com/images/icons-png/shop-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-star:after,.ui-nosvg .ui-alt-icon .ui-icon-star:after{background-image:url(http://github.com/images/icons-png/star-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-tag:after,.ui-nosvg .ui-alt-icon .ui-icon-tag:after{background-image:url(http://github.com/images/icons-png/tag-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-user:after,.ui-nosvg .ui-alt-icon .ui-icon-user:after{background-image:url(http://github.com/images/icons-png/user-black.png)}.ui-nosvg .ui-alt-icon.ui-icon-video:after,.ui-nosvg .ui-alt-icon .ui-icon-video:after{background-image:url(http://github.com/images/icons-png/video-black.png)}html{font-size:100%}body,input,select,textarea,button,.ui-btn{font-size:1em;line-height:1.3;font-family:sans-serif}legend,.ui-input-text input,.ui-input-search input{color:inherit;text-shadow:inherit}.ui-mobile label,div.ui-controlgroup-label{font-weight:400;font-size:16px}.ui-field-contain{border-bottom-color:#828282;border-bottom-color:rgba(0,0,0,.15);border-bottom-width:1px;border-bottom-style:solid}.table-stroke thead th,.table-stripe thead th,.table-stripe tbody tr:last-child{border-bottom:1px solid #d6d6d6;border-bottom:1px solid rgba(0,0,0,.1)}.table-stroke tbody th,.table-stroke tbody td{border-bottom:1px solid #e6e6e6;border-bottom:1px solid rgba(0,0,0,.05)}.table-stripe.table-stroke tbody tr:last-child th,.table-stripe.table-stroke tbody tr:last-child td{border-bottom:0}.table-stripe tbody tr:nth-child(odd) td,.table-stripe tbody tr:nth-child(odd) th{background-color:#eee;background-color:rgba(0,0,0,.04)}.ui-btn,label.ui-btn{font-weight:700;border-width:1px;border-style:solid}.ui-btn:link{text-decoration:none!important}.ui-btn-active{cursor:pointer}.ui-corner-all{-webkit-border-radius:.3125em;border-radius:.3125em}.ui-btn-corner-all,.ui-btn.ui-corner-all,.ui-slider-track.ui-corner-all,.ui-flipswitch.ui-corner-all,.ui-li-count{-webkit-border-radius:.3125em;border-radius:.3125em}.ui-btn-icon-notext.ui-btn-corner-all,.ui-btn-icon-notext.ui-corner-all{-webkit-border-radius:1em;border-radius:1em}.ui-btn-corner-all,.ui-corner-all{-webkit-background-clip:padding;background-clip:padding-box}.ui-popup.ui-corner-all>.ui-popup-arrow-guide{left:.6em;right:.6em;top:.6em;bottom:.6em}.ui-shadow{-webkit-box-shadow:0 1px 3px rgba(0,0,0,.15);-moz-box-shadow:0 1px 3px rgba(0,0,0,.15);box-shadow:0 1px 3px rgba(0,0,0,.15)}.ui-shadow-inset{-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.2);-moz-box-shadow:inset 0 1px 3px rgba(0,0,0,.2);box-shadow:inset 0 1px 3px rgba(0,0,0,.2)}.ui-overlay-shadow{-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);-moz-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6)}.ui-btn-icon-left:after,.ui-btn-icon-right:after,.ui-btn-icon-top:after,.ui-btn-icon-bottom:after,.ui-btn-icon-notext:after{background-color:#666;background-color:rgba(0,0,0,.3);background-position:center center;background-repeat:no-repeat;-webkit-border-radius:1em;border-radius:1em}.ui-alt-icon.ui-btn:after,.ui-alt-icon .ui-btn:after,html .ui-alt-icon.ui-checkbox-off:after,html .ui-alt-icon.ui-radio-off:after,html .ui-alt-icon .ui-checkbox-off:after,html .ui-alt-icon .ui-radio-off:after{background-color:#666;background-color:rgba(0,0,0,.15)}.ui-nodisc-icon.ui-btn:after,.ui-nodisc-icon .ui-btn:after{background-color:transparent}.ui-shadow-icon.ui-btn:after,.ui-shadow-icon .ui-btn:after{-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3)}.ui-btn.ui-checkbox-off:after,.ui-btn.ui-checkbox-on:after,.ui-btn.ui-radio-off:after,.ui-btn.ui-radio-on:after{display:block;width:18px;height:18px;margin:-9px 2px 0 2px}.ui-checkbox-off:after,.ui-btn.ui-radio-off:after{filter:Alpha(Opacity=30);opacity:.3}.ui-btn.ui-checkbox-off:after,.ui-btn.ui-checkbox-on:after{-webkit-border-radius:.1875em;border-radius:.1875em}.ui-radio .ui-btn.ui-radio-on:after{background-image:none;background-color:#fff;width:8px;height:8px;border-width:5px;border-style:solid}.ui-alt-icon.ui-btn.ui-radio-on:after,.ui-alt-icon .ui-btn.ui-radio-on:after{background-color:#000}.ui-icon-loading{background:url(http://github.com/images/ajax-loader.gif);background-size:2.875em 2.875em}.ui-bar-a,.ui-page-theme-a .ui-bar-inherit,html .ui-bar-a .ui-bar-inherit,html .ui-body-a .ui-bar-inherit,html body .ui-group-theme-a .ui-bar-inherit{background-color:#e9e9e9;border-color:#ddd;color:#333;text-shadow:0 1px 0 #eee;font-weight:700}.ui-bar-a{border-width:1px;border-style:solid}.ui-overlay-a,.ui-page-theme-a,.ui-page-theme-a .ui-panel-wrapper{background-color:#f9f9f9;border-color:#bbb;color:#333;text-shadow:0 1px 0 #f3f3f3}.ui-body-a,.ui-page-theme-a .ui-body-inherit,html .ui-bar-a .ui-body-inherit,html .ui-body-a .ui-body-inherit,html body .ui-group-theme-a .ui-body-inherit,html .ui-panel-page-container-a{background-color:#fff;border-color:#ddd;color:#333;text-shadow:0 1px 0 #f3f3f3}.ui-body-a{border-width:1px;border-style:solid}.ui-page-theme-a a,html .ui-bar-a a,html .ui-body-a a,html body .ui-group-theme-a a{color:#38c;font-weight:700}.ui-page-theme-a a:visited,html .ui-bar-a a:visited,html .ui-body-a a:visited,html body .ui-group-theme-a a:visited{color:#38c}.ui-page-theme-a a:hover,html .ui-bar-a a:hover,html .ui-body-a a:hover,html body .ui-group-theme-a a:hover{color:#059}.ui-page-theme-a a:active,html .ui-bar-a a:active,html .ui-body-a a:active,html body .ui-group-theme-a a:active{color:#059}.ui-page-theme-a .ui-btn,html .ui-bar-a .ui-btn,html .ui-body-a .ui-btn,html body .ui-group-theme-a .ui-btn,html head+body .ui-btn.ui-btn-a,.ui-page-theme-a .ui-btn:visited,html .ui-bar-a .ui-btn:visited,html .ui-body-a .ui-btn:visited,html body .ui-group-theme-a .ui-btn:visited,html head+body .ui-btn.ui-btn-a:visited{background-color:#f6f6f6;border-color:#ddd;color:#333;text-shadow:0 1px 0 #f3f3f3}.ui-page-theme-a .ui-btn:hover,html .ui-bar-a .ui-btn:hover,html .ui-body-a .ui-btn:hover,html body .ui-group-theme-a .ui-btn:hover,html head+body .ui-btn.ui-btn-a:hover{background-color:#ededed;border-color:#ddd;color:#333;text-shadow:0 1px 0 #f3f3f3}.ui-page-theme-a .ui-btn:active,html .ui-bar-a .ui-btn:active,html .ui-body-a .ui-btn:active,html body .ui-group-theme-a .ui-btn:active,html head+body .ui-btn.ui-btn-a:active{background-color:#e8e8e8;border-color:#ddd;color:#333;text-shadow:0 1px 0 #f3f3f3}.ui-page-theme-a .ui-btn.ui-btn-active,html .ui-bar-a .ui-btn.ui-btn-active,html .ui-body-a .ui-btn.ui-btn-active,html body .ui-group-theme-a .ui-btn.ui-btn-active,html head+body .ui-btn.ui-btn-a.ui-btn-active,.ui-page-theme-a .ui-checkbox-on:after,html .ui-bar-a .ui-checkbox-on:after,html .ui-body-a .ui-checkbox-on:after,html body .ui-group-theme-a .ui-checkbox-on:after,.ui-btn.ui-checkbox-on.ui-btn-a:after,.ui-page-theme-a .ui-flipswitch-active,html .ui-bar-a .ui-flipswitch-active,html .ui-body-a .ui-flipswitch-active,html body .ui-group-theme-a .ui-flipswitch-active,html body .ui-flipswitch.ui-bar-a.ui-flipswitch-active,.ui-page-theme-a .ui-slider-track .ui-btn-active,html .ui-bar-a .ui-slider-track .ui-btn-active,html .ui-body-a .ui-slider-track .ui-btn-active,html body .ui-group-theme-a .ui-slider-track .ui-btn-active,html body div.ui-slider-track.ui-body-a .ui-btn-active{background-color:#38c;border-color:#38c;color:#fff;text-shadow:0 1px 0 #059}.ui-page-theme-a .ui-radio-on:after,html .ui-bar-a .ui-radio-on:after,html .ui-body-a .ui-radio-on:after,html body .ui-group-theme-a .ui-radio-on:after,.ui-btn.ui-radio-on.ui-btn-a:after{border-color:#38c}.ui-page-theme-a .ui-btn:focus,html .ui-bar-a .ui-btn:focus,html .ui-body-a .ui-btn:focus,html body .ui-group-theme-a .ui-btn:focus,html head+body .ui-btn.ui-btn-a:focus,.ui-page-theme-a .ui-focus,html .ui-bar-a .ui-focus,html .ui-body-a .ui-focus,html body .ui-group-theme-a .ui-focus,html head+body .ui-btn-a.ui-focus,html head+body .ui-body-a.ui-focus{-webkit-box-shadow:0 0 12px #38c;-moz-box-shadow:0 0 12px #38c;box-shadow:0 0 12px #38c}.ui-bar-b,.ui-page-theme-b .ui-bar-inherit,html .ui-bar-b .ui-bar-inherit,html .ui-body-b .ui-bar-inherit,html body .ui-group-theme-b .ui-bar-inherit{background-color:#1d1d1d;border-color:#1b1b1b;color:#fff;text-shadow:0 1px 0 #111;font-weight:700}.ui-bar-b{border-width:1px;border-style:solid}.ui-overlay-b,.ui-page-theme-b,.ui-page-theme-b .ui-panel-wrapper{background-color:#252525;border-color:#454545;color:#fff;text-shadow:0 1px 0 #111}.ui-body-b,.ui-page-theme-b .ui-body-inherit,html .ui-bar-b .ui-body-inherit,html .ui-body-b .ui-body-inherit,html body .ui-group-theme-b .ui-body-inherit,html .ui-panel-page-container-b{background-color:#2a2a2a;border-color:#1d1d1d;color:#fff;text-shadow:0 1px 0 #111}.ui-body-b{border-width:1px;border-style:solid}.ui-page-theme-b a,html .ui-bar-b a,html .ui-body-b a,html body .ui-group-theme-b a{color:#2ad;font-weight:700}.ui-page-theme-b a:visited,html .ui-bar-b a:visited,html .ui-body-b a:visited,html body .ui-group-theme-b a:visited{color:#2ad}.ui-page-theme-b a:hover,html .ui-bar-b a:hover,html .ui-body-b a:hover,html body .ui-group-theme-b a:hover{color:#08b}.ui-page-theme-b a:active,html .ui-bar-b a:active,html .ui-body-b a:active,html body .ui-group-theme-b a:active{color:#08b}.ui-page-theme-b .ui-btn,html .ui-bar-b .ui-btn,html .ui-body-b .ui-btn,html body .ui-group-theme-b .ui-btn,html head+body .ui-btn.ui-btn-b,.ui-page-theme-b .ui-btn:visited,html .ui-bar-b .ui-btn:visited,html .ui-body-b .ui-btn:visited,html body .ui-group-theme-b .ui-btn:visited,html head+body .ui-btn.ui-btn-b:visited{background-color:#333;border-color:#1f1f1f;color:#fff;text-shadow:0 1px 0 #111}.ui-page-theme-b .ui-btn:hover,html .ui-bar-b .ui-btn:hover,html .ui-body-b .ui-btn:hover,html body .ui-group-theme-b .ui-btn:hover,html head+body .ui-btn.ui-btn-b:hover{background-color:#373737;border-color:#1f1f1f;color:#fff;text-shadow:0 1px 0 #111}.ui-page-theme-b .ui-btn:active,html .ui-bar-b .ui-btn:active,html .ui-body-b .ui-btn:active,html body .ui-group-theme-b .ui-btn:active,html head+body .ui-btn.ui-btn-b:active{background-color:#404040;border-color:#1f1f1f;color:#fff;text-shadow:0 1px 0 #111}.ui-page-theme-b .ui-btn.ui-btn-active,html .ui-bar-b .ui-btn.ui-btn-active,html .ui-body-b .ui-btn.ui-btn-active,html body .ui-group-theme-b .ui-btn.ui-btn-active,html head+body .ui-btn.ui-btn-b.ui-btn-active,.ui-page-theme-b .ui-checkbox-on:after,html .ui-bar-b .ui-checkbox-on:after,html .ui-body-b .ui-checkbox-on:after,html body .ui-group-theme-b .ui-checkbox-on:after,.ui-btn.ui-checkbox-on.ui-btn-b:after,.ui-page-theme-b .ui-flipswitch-active,html .ui-bar-b .ui-flipswitch-active,html .ui-body-b .ui-flipswitch-active,html body .ui-group-theme-b .ui-flipswitch-active,html body .ui-flipswitch.ui-bar-b.ui-flipswitch-active,.ui-page-theme-b .ui-slider-track .ui-btn-active,html .ui-bar-b .ui-slider-track .ui-btn-active,html .ui-body-b .ui-slider-track .ui-btn-active,html body .ui-group-theme-b .ui-slider-track .ui-btn-active,html body div.ui-slider-track.ui-body-b .ui-btn-active{background-color:#2ad;border-color:#2ad;color:#fff;text-shadow:0 1px 0 #08b}.ui-page-theme-b .ui-radio-on:after,html .ui-bar-b .ui-radio-on:after,html .ui-body-b .ui-radio-on:after,html body .ui-group-theme-b .ui-radio-on:after,.ui-btn.ui-radio-on.ui-btn-b:after{border-color:#2ad}.ui-page-theme-b .ui-btn:focus,html .ui-bar-b .ui-btn:focus,html .ui-body-b .ui-btn:focus,html body .ui-group-theme-b .ui-btn:focus,html head+body .ui-btn.ui-btn-b:focus,.ui-page-theme-b .ui-focus,html .ui-bar-b .ui-focus,html .ui-body-b .ui-focus,html body .ui-group-theme-b .ui-focus,html head+body .ui-btn-b.ui-focus,html head+body .ui-body-b.ui-focus{-webkit-box-shadow:0 0 12px #2ad;-moz-box-shadow:0 0 12px #2ad;box-shadow:0 0 12px #2ad}.ui-disabled,.ui-state-disabled,button[disabled],.ui-select .ui-btn.ui-state-disabled{filter:Alpha(Opacity=30);opacity:.3;cursor:default!important;pointer-events:none}.ui-btn:focus,.ui-btn.ui-focus{outline:0}.ui-noboxshadow .ui-shadow,.ui-noboxshadow .ui-shadow-inset,.ui-noboxshadow .ui-overlay-shadow,.ui-noboxshadow .ui-shadow-icon.ui-btn:after,.ui-noboxshadow .ui-shadow-icon .ui-btn:after,.ui-noboxshadow .ui-focus,.ui-noboxshadow .ui-btn:focus,.ui-noboxshadow input:focus,.ui-noboxshadow .ui-panel{-webkit-box-shadow:none!important;-moz-box-shadow:none!important;box-shadow:none!important}.ui-noboxshadow .ui-btn:focus,.ui-noboxshadow .ui-focus{outline-width:1px;outline-style:auto}.ui-mobile,.ui-mobile body{height:99.9%}.ui-mobile fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border-width:0}.ui-mobile fieldset{min-width:0}@-moz-document url-prefix(){.ui-mobile fieldset{display:table-column;vertical-align:middle}}.ui-mobile-viewport{margin:0;overflow-x:visible;-webkit-text-size-adjust:100%;-ms-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}body.ui-mobile-viewport,div.ui-mobile-viewport{overflow-x:hidden}.ui-mobile [data-role=page],.ui-mobile [data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-page{outline:0}.ui-mobile .ui-page-active{display:block;overflow:visible;overflow-x:hidden}@media screen and (orientation:portrait){.ui-mobile .ui-page{min-height:420px}}@media screen and (orientation:landscape){.ui-mobile .ui-page{min-height:300px}}.ui-mobile-rendering>*{visibility:hidden}.ui-nojs{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-loading .ui-loader{display:block}.ui-loader{display:none;z-index:9999999;position:fixed;top:50%;left:50%;border:0}.ui-loader-default{background:0;filter:Alpha(Opacity=18);opacity:.18;width:2.875em;height:2.875em;margin-left:-1.4375em;margin-top:-1.4375em}.ui-loader-verbose{width:12.5em;filter:Alpha(Opacity=88);opacity:.88;box-shadow:0 1px 1px -1px #fff;height:auto;margin-left:-6.875em;margin-top:-2.6875em;padding:.625em}.ui-loader-default h1{font-size:0;width:0;height:0;overflow:hidden}.ui-loader-verbose h1{font-size:1em;margin:0;text-align:center}.ui-loader .ui-icon-loading{background-color:#000;display:block;margin:0;width:2.75em;height:2.75em;padding:.0625em;-webkit-border-radius:2.25em;border-radius:2.25em}.ui-loader-verbose .ui-icon-loading{margin:0 auto .625em;filter:Alpha(Opacity=75);opacity:.75}.ui-loader-textonly{padding:.9375em;margin-left:-7.1875em}.ui-loader-textonly .ui-icon-loading{display:none}.ui-loader-fakefix{position:absolute}.ui-bar,.ui-body{position:relative;padding:.4em 1em;overflow:hidden;display:block;clear:both}.ui-bar h1,.ui-bar h2,.ui-bar h3,.ui-bar h4,.ui-bar h5,.ui-bar h6{margin:0;padding:0;font-size:1em;display:inline-block}.ui-header,.ui-footer{border-width:1px 0;border-style:solid;position:relative}.ui-header:empty,.ui-footer:empty{min-height:2.6875em}.ui-header .ui-title,.ui-footer .ui-title{font-size:1em;min-height:1.1em;text-align:center;display:block;margin:0 30%;padding:.7em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;outline:0!important}.ui-footer .ui-title{margin:0 1em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:1em}.ui-corner-all>.ui-header:first-child,.ui-corner-all>.ui-content:first-child,.ui-corner-all>.ui-footer:first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-corner-all>.ui-header:last-child,.ui-corner-all>.ui-content:last-child,.ui-corner-all>.ui-footer:last-child{-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-btn{font-size:16px;margin:.5em 0;padding:.7em 1em;display:block;position:relative;text-align:center;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ui-btn-icon-notext{padding:0;width:1.75em;height:1.75em;text-indent:-9999px;white-space:nowrap!important}.ui-mini{font-size:12.5px}.ui-mini .ui-btn{font-size:inherit}.ui-header .ui-btn,.ui-footer .ui-btn{font-size:12.5px;display:inline-block;vertical-align:middle}.ui-header .ui-btn-left,.ui-header .ui-btn-right{font-size:12.5px}.ui-mini.ui-btn-icon-notext,.ui-mini .ui-btn-icon-notext,.ui-header .ui-btn-icon-notext,.ui-footer .ui-btn-icon-notext{font-size:16px;padding:0}.ui-btn-inline{display:inline-block;vertical-align:middle;margin-right:.625em}.ui-btn-icon-left{padding-left:2.5em}.ui-btn-icon-right{padding-right:2.5em}.ui-btn-icon-top{padding-top:2.5em}.ui-btn-icon-bottom{padding-bottom:2.5em}.ui-header .ui-btn-icon-top,.ui-footer .ui-btn-icon-top,.ui-header .ui-btn-icon-bottom,.ui-footer .ui-btn-icon-bottom{padding-left:.3125em;padding-right:.3125em}.ui-btn-icon-left:after,.ui-btn-icon-right:after,.ui-btn-icon-top:after,.ui-btn-icon-bottom:after,.ui-btn-icon-notext:after{content:"";position:absolute;display:block;width:22px;height:22px}.ui-btn-icon-notext:after,.ui-btn-icon-left:after,.ui-btn-icon-right:after{top:50%;margin-top:-11px}.ui-btn-icon-left:after{left:.5625em}.ui-btn-icon-right:after{right:.5625em}.ui-mini.ui-btn-icon-left:after,.ui-mini .ui-btn-icon-left:after,.ui-header .ui-btn-icon-left:after,.ui-footer .ui-btn-icon-left:after{left:.37em}.ui-mini.ui-btn-icon-right:after,.ui-mini .ui-btn-icon-right:after,.ui-header .ui-btn-icon-right:after,.ui-footer .ui-btn-icon-right:after{right:.37em}.ui-btn-icon-notext:after,.ui-btn-icon-top:after,.ui-btn-icon-bottom:after{left:50%;margin-left:-11px}.ui-btn-icon-top:after{top:.5625em}.ui-btn-icon-bottom:after{top:auto;bottom:.5625em}.ui-header .ui-btn-left,.ui-header .ui-btn-right,.ui-btn-left>[class*=ui-],.ui-btn-right>[class*=ui-]{margin:0}.ui-btn-left,.ui-btn-right{position:absolute;top:.24em}.ui-btn-left{left:.4em}.ui-btn-right{right:.4em}.ui-btn-icon-notext.ui-btn-left{top:.3125em;left:.3125em}.ui-btn-icon-notext.ui-btn-right{top:.3125em;right:.3125em}button.ui-btn,.ui-controlgroup-controls button.ui-btn-icon-notext{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;width:100%}button.ui-btn-inline{width:auto}button.ui-btn::-moz-focus-inner{border:0}button.ui-btn-icon-notext,.ui-controlgroup-horizontal .ui-controlgroup-controls button.ui-btn{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;width:1.75em}.ui-mobile label,.ui-controlgroup-label{display:block;margin:0 0 .4em}.ui-hide-label>label,.ui-hide-label .ui-controlgroup-label,.ui-hide-label .ui-rangeslider label,.ui-hidden-accessible{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-screen-hidden{display:none!important}.ui-mobile-viewport-transitioning,.ui-mobile-viewport-transitioning .ui-page{width:100%;height:100%;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ui-page-pre-in{opacity:0}.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms;animation-timing-function:ease-out;animation-duration:350ms}.out{-webkit-animation-timing-function:ease-in;-webkit-animation-duration:225ms;-moz-animation-timing-function:ease-in;-moz-animation-duration:225ms;animation-timing-function:ease-in;animation-duration:225ms}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-moz-keyframes fadein{from{opacity:0}to{opacity:1}}@keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeout{from{opacity:1}to{opacity:0}}@-moz-keyframes fadeout{from{opacity:1}to{opacity:0}}@keyframes fadeout{from{opacity:1}to{opacity:0}}.fade.out{opacity:0;-webkit-animation-duration:125ms;-webkit-animation-name:fadeout;-moz-animation-duration:125ms;-moz-animation-name:fadeout;animation-duration:125ms;animation-name:fadeout}.fade.in{opacity:1;-webkit-animation-duration:225ms;-webkit-animation-name:fadein;-moz-animation-duration:225ms;-moz-animation-name:fadein;animation-duration:225ms;animation-name:fadein}.pop{-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%;transform-origin:50% 50%}.pop.in{-webkit-transform:scale(1);-webkit-animation-name:popin;-webkit-animation-duration:350ms;-moz-transform:scale(1);-moz-animation-name:popin;-moz-animation-duration:350ms;transform:scale(1);animation-name:popin;animation-duration:350ms;opacity:1}.pop.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms;opacity:0}.pop.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein;animation-name:fadein}.pop.out.reverse{-webkit-transform:scale(.8);-webkit-animation-name:popout;-moz-transform:scale(.8);-moz-animation-name:popout;transform:scale(.8);animation-name:popout}@-webkit-keyframes popin{from{-webkit-transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-moz-keyframes popin{from{-moz-transform:scale(.8);opacity:0}to{-moz-transform:scale(1);opacity:1}}@keyframes popin{from{transform:scale(.8);opacity:0}to{transform:scale(1);opacity:1}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.8);opacity:0}}@-moz-keyframes popout{from{-moz-transform:scale(1);opacity:1}to{-moz-transform:scale(.8);opacity:0}}@keyframes popout{from{transform:scale(1);opacity:1}to{transform:scale(.8);opacity:0}}@-webkit-keyframes slideinfromright{from{-webkit-transform:translate3d(100%,0,0)}to{-webkit-transform:translate3d(0,0,0)}}@-moz-keyframes slideinfromright{from{-moz-transform:translateX(100%)}to{-moz-transform:translateX(0)}}@keyframes slideinfromright{from{transform:translateX(100%)}to{transform:translateX(0)}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translate3d(-100%,0,0)}to{-webkit-transform:translate3d(0,0,0)}}@-moz-keyframes slideinfromleft{from{-moz-transform:translateX(-100%)}to{-moz-transform:translateX(0)}}@keyframes slideinfromleft{from{transform:translateX(-100%)}to{transform:translateX(0)}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(-100%,0,0)}}@-moz-keyframes slideouttoleft{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(-100%)}}@keyframes slideouttoleft{from{transform:translateX(0)}to{transform:translateX(-100%)}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(100%,0,0)}}@-moz-keyframes slideouttoright{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(100%)}}@keyframes slideouttoright{from{transform:translateX(0)}to{transform:translateX(100%)}}.slide.out,.slide.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms;animation-timing-function:ease-out;animation-duration:350ms}.slide.out{-webkit-transform:translate3d(-100%,0,0);-webkit-animation-name:slideouttoleft;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;transform:translateX(-100%);animation-name:slideouttoleft}.slide.in{-webkit-transform:translate3d(0,0,0);-webkit-animation-name:slideinfromright;-moz-transform:translateX(0);-moz-animation-name:slideinfromright;transform:translateX(0);animation-name:slideinfromright}.slide.out.reverse{-webkit-transform:translate3d(100%,0,0);-webkit-animation-name:slideouttoright;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;transform:translateX(100%);animation-name:slideouttoright}.slide.in.reverse{-webkit-transform:translate3d(0,0,0);-webkit-animation-name:slideinfromleft;-moz-transform:translateX(0);-moz-animation-name:slideinfromleft;transform:translateX(0);animation-name:slideinfromleft}.slidefade.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-webkit-animation-duration:225ms;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;-moz-animation-duration:225ms;transform:translateX(-100%);animation-name:slideouttoleft;animation-duration:225ms}.slidefade.in{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-webkit-animation-duration:200ms;-moz-transform:translateX(0);-moz-animation-name:fadein;-moz-animation-duration:200ms;transform:translateX(0);animation-name:fadein;animation-duration:200ms}.slidefade.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-webkit-animation-duration:200ms;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;-moz-animation-duration:200ms;transform:translateX(100%);animation-name:slideouttoright;animation-duration:200ms}.slidefade.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-webkit-animation-duration:200ms;-moz-transform:translateX(0);-moz-animation-name:fadein;-moz-animation-duration:200ms;transform:translateX(0);animation-name:fadein;animation-duration:200ms}.slidedown.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms}.slidedown.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfromtop;-webkit-animation-duration:250ms;-moz-transform:translateY(0);-moz-animation-name:slideinfromtop;-moz-animation-duration:250ms;transform:translateY(0);animation-name:slideinfromtop;animation-duration:250ms}.slidedown.in.reverse{-webkit-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-name:fadein;-moz-animation-duration:150ms;animation-name:fadein;animation-duration:150ms}.slidedown.out.reverse{-webkit-transform:translateY(-100%);-webkit-animation-name:slideouttotop;-webkit-animation-duration:200ms;-moz-transform:translateY(-100%);-moz-animation-name:slideouttotop;-moz-animation-duration:200ms;transform:translateY(-100%);animation-name:slideouttotop;animation-duration:200ms}@-webkit-keyframes slideinfromtop{from{-webkit-transform:translateY(-100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfromtop{from{-moz-transform:translateY(-100%)}to{-moz-transform:translateY(0)}}@keyframes slideinfromtop{from{transform:translateY(-100%)}to{transform:translateY(0)}}@-webkit-keyframes slideouttotop{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(-100%)}}@-moz-keyframes slideouttotop{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(-100%)}}@keyframes slideouttotop{from{transform:translateY(0)}to{transform:translateY(-100%)}}.slideup.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms}.slideup.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfrombottom;-webkit-animation-duration:250ms;-moz-transform:translateY(0);-moz-animation-name:slideinfrombottom;-moz-animation-duration:250ms;transform:translateY(0);animation-name:slideinfrombottom;animation-duration:250ms}.slideup.in.reverse{-webkit-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-name:fadein;-moz-animation-duration:150ms;animation-name:fadein;animation-duration:150ms}.slideup.out.reverse{-webkit-transform:translateY(100%);-webkit-animation-name:slideouttobottom;-webkit-animation-duration:200ms;-moz-transform:translateY(100%);-moz-animation-name:slideouttobottom;-moz-animation-duration:200ms;transform:translateY(100%);animation-name:slideouttobottom;animation-duration:200ms}@-webkit-keyframes slideinfrombottom{from{-webkit-transform:translateY(100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfrombottom{from{-moz-transform:translateY(100%)}to{-moz-transform:translateY(0)}}@keyframes slideinfrombottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@-webkit-keyframes slideouttobottom{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(100%)}}@-moz-keyframes slideouttobottom{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(100%)}}@keyframes slideouttobottom{from{transform:translateY(0)}to{transform:translateY(100%)}}.viewport-flip{-webkit-perspective:1000;-moz-perspective:1000;perspective:1000;position:absolute}.flip{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-moz-backface-visibility:hidden;-moz-transform:translateX(0);backface-visibility:hidden;transform:translateX(0)}.flip.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:175ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:175ms;transform:rotateY(-90deg) scale(.9);animation-name:flipouttoleft;animation-duration:175ms}.flip.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:225ms;-moz-animation-name:flipintoright;-moz-animation-duration:225ms;animation-name:flipintoright;animation-duration:225ms}.flip.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright;transform:rotateY(90deg) scale(.9);animation-name:flipouttoright}.flip.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft;animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@keyframes flipouttoleft{from{transform:rotateY(0)}to{transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@keyframes flipouttoright{from{transform:rotateY(0)}to{transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoleft{from{transform:rotateY(-90deg) scale(.9)}to{transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoright{from{transform:rotateY(90deg) scale(.9)}to{transform:rotateY(0)}}.viewport-turn{-webkit-perspective:200px;-moz-perspective:200px;-ms-perspective:200px;perspective:200px;position:absolute}.turn{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-webkit-transform-origin:0;-moz-backface-visibility:hidden;-moz-transform:translateX(0);-moz-transform-origin:0;backface-visibility:hidden;transform:translateX(0);transform-origin:0}.turn.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:125ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:125ms;transform:rotateY(-90deg) scale(.9);animation-name:flipouttoleft;animation-duration:125ms}.turn.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:250ms;-moz-animation-name:flipintoright;-moz-animation-duration:250ms;animation-name:flipintoright;animation-duration:250ms}.turn.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright;transform:rotateY(90deg) scale(.9);animation-name:flipouttoright}.turn.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft;animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@keyframes flipouttoleft{from{transform:rotateY(0)}to{transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@keyframes flipouttoright{from{transform:rotateY(0)}to{transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoleft{from{transform:rotateY(-90deg) scale(.9)}to{transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoright{from{transform:rotateY(90deg) scale(.9)}to{transform:rotateY(0)}}.flow{-webkit-transform-origin:50% 30%;-webkit-box-shadow:0 0 20px rgba(0,0,0,.4);-moz-transform-origin:50% 30%;-moz-box-shadow:0 0 20px rgba(0,0,0,.4);transform-origin:50% 30%;box-shadow:0 0 20px rgba(0,0,0,.4)}.ui-dialog.flow{-webkit-transform-origin:none;-webkit-box-shadow:none;-moz-transform-origin:none;-moz-box-shadow:none;transform-origin:none;box-shadow:none}.flow.out{-webkit-transform:translateX(-100%) scale(.7);-webkit-animation-name:flowouttoleft;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(-100%) scale(.7);-moz-animation-name:flowouttoleft;-moz-animation-timing-function:ease;-moz-animation-duration:350ms;transform:translateX(-100%) scale(.7);animation-name:flowouttoleft;animation-timing-function:ease;animation-duration:350ms}.flow.in{-webkit-transform:translateX(0) scale(1);-webkit-animation-name:flowinfromright;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(0) scale(1);-moz-animation-name:flowinfromright;-moz-animation-timing-function:ease;-moz-animation-duration:350ms;transform:translateX(0) scale(1);animation-name:flowinfromright;animation-timing-function:ease;animation-duration:350ms}.flow.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:flowouttoright;-moz-transform:translateX(100%);-moz-animation-name:flowouttoright;transform:translateX(100%);animation-name:flowouttoright}.flow.in.reverse{-webkit-animation-name:flowinfromleft;-moz-animation-name:flowinfromleft;animation-name:flowinfromleft}@-webkit-keyframes flowouttoleft{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(-100%) scale(.7)}}@-moz-keyframes flowouttoleft{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(-100%) scale(.7)}}@keyframes flowouttoleft{0%{transform:translateX(0) scale(1)}60%,70%{transform:translateX(0) scale(.7)}100%{transform:translateX(-100%) scale(.7)}}@-webkit-keyframes flowouttoright{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(100%) scale(.7)}}@-moz-keyframes flowouttoright{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(100%) scale(.7)}}@keyframes flowouttoright{0%{transform:translateX(0) scale(1)}60%,70%{transform:translateX(0) scale(.7)}100%{transform:translateX(100%) scale(.7)}}@-webkit-keyframes flowinfromleft{0%{-webkit-transform:translateX(-100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromleft{0%{-moz-transform:translateX(-100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@keyframes flowinfromleft{0%{transform:translateX(-100%) scale(.7)}30%,40%{transform:translateX(0) scale(.7)}100%{transform:translateX(0) scale(1)}}@-webkit-keyframes flowinfromright{0%{-webkit-transform:translateX(100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromright{0%{-moz-transform:translateX(100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@keyframes flowinfromright{0%{transform:translateX(100%) scale(.7)}30%,40%{transform:translateX(0) scale(.7)}100%{transform:translateX(0) scale(1)}}.ui-field-contain,.ui-mobile fieldset.ui-field-contain{display:block;position:relative;overflow:visible;clear:both;padding:.8em 0}.ui-field-contain>label~[class*=ui-],.ui-field-contain .ui-controlgroup-controls{margin:0}.ui-field-contain:last-child{border-bottom-width:0}@media (min-width:28em){.ui-field-contain,.ui-mobile fieldset.ui-field-contain{padding:0;margin:1em 0;border-bottom-width:0}.ui-field-contain:before,.ui-field-contain:after{content:"";display:table}.ui-field-contain:after{clear:both}.ui-field-contain>label,.ui-field-contain .ui-controlgroup-label,.ui-field-contain>.ui-rangeslider>label{float:left;width:20%;margin:.5em 2% 0 0}.ui-popup .ui-field-contain>label,.ui-popup .ui-field-contain .ui-controlgroup-label,.ui-popup .ui-field-contain>.ui-rangeslider>label{float:none;width:auto;margin:0 0 .4em}.ui-field-contain>label~[class*=ui-],.ui-field-contain .ui-controlgroup-controls{float:left;width:78%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-hide-label>label~[class*=ui-],.ui-hide-label .ui-controlgroup-controls,.ui-popup .ui-field-contain>label~[class*=ui-],.ui-popup .ui-field-contain .ui-controlgroup-controls{float:none;width:100%}.ui-field-contain>label~.ui-btn-inline{width:auto;margin-right:.625em}}.ui-grid-a,.ui-grid-b,.ui-grid-c,.ui-grid-d,.ui-grid-solo{overflow:hidden}.ui-block-a,.ui-block-b,.ui-block-c,.ui-block-d,.ui-block-e{margin:0;padding:0;border:0;float:left;min-height:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ui-block-a{clear:left}ul.ui-grid-a,ul.ui-grid-b,ul.ui-grid-c,ul.ui-grid-d,ul.ui-grid-solo,li.ui-block-a,li.ui-block-b,li.ui-block-c,li.ui-block-d,li.ui-block-e{margin-left:0;margin-right:0;padding:0;list-style:none}[class*=ui-block-]>button.ui-btn{margin-right:0;margin-left:0}[class*=ui-block-]>.ui-btn,[class*=ui-block-]>.ui-select,[class*=ui-block-]>.ui-checkbox,[class*=ui-block-]>.ui-radio,[class*=ui-block-]>button.ui-btn-inline,[class*=ui-block-]>button.ui-btn-icon-notext{margin-right:.3125em;margin-left:.3125em}.ui-grid-a>.ui-block-a,.ui-grid-a>.ui-block-b{width:50%}.ui-grid-b>.ui-block-a,.ui-grid-b>.ui-block-b,.ui-grid-b>.ui-block-c{width:33.333%}.ui-grid-c>.ui-block-a,.ui-grid-c>.ui-block-b,.ui-grid-c>.ui-block-c,.ui-grid-c>.ui-block-d{width:25%}.ui-grid-d>.ui-block-a,.ui-grid-d>.ui-block-b,.ui-grid-d>.ui-block-c,.ui-grid-d>.ui-block-d,.ui-grid-d>.ui-block-e{width:20%}.ui-grid-solo>.ui-block-a{width:100%;float:none}@media (max-width:35em){.ui-responsive>.ui-block-a,.ui-responsive>.ui-block-b,.ui-responsive>.ui-block-c,.ui-responsive>.ui-block-d,.ui-responsive>.ui-block-e{width:100%;float:none}}.ui-header-fixed,.ui-footer-fixed{left:0;right:0;width:100%;position:fixed;z-index:1000}.ui-header-fixed{top:-1px;padding-top:1px}.ui-header-fixed.ui-fixed-hidden{top:0;padding-top:0}.ui-header-fixed .ui-btn-left,.ui-header-fixed .ui-btn-right{margin-top:1px}.ui-header-fixed.ui-fixed-hidden .ui-btn-left,.ui-header-fixed.ui-fixed-hidden .ui-btn-right{margin-top:0}.ui-footer-fixed{bottom:-1px;padding-bottom:1px}.ui-footer-fixed.ui-fixed-hidden{bottom:0;padding-bottom:0}.ui-header-fullscreen,.ui-footer-fullscreen{filter:Alpha(Opacity=90);opacity:.9}.ui-page-header-fixed{padding-top:2.8125em}.ui-page-footer-fixed{padding-bottom:2.8125em}.ui-page-header-fullscreen>.ui-content,.ui-page-footer-fullscreen>.ui-content{padding:0}.ui-fixed-hidden{position:absolute}.ui-footer-fixed.ui-fixed-hidden{display:none}.ui-page .ui-footer-fixed.ui-fixed-hidden{display:block}.ui-page-header-fullscreen .ui-fixed-hidden,.ui-page-footer-fullscreen .ui-fixed-hidden{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-header-fixed .ui-btn,.ui-footer-fixed .ui-btn{z-index:10}.ui-android-2x-fixed .ui-li-has-thumb{-webkit-transform:translate3d(0,0,0)}.ui-navbar{max-width:100%}.ui-navbar ul:before,.ui-navbar ul:after{content:"";display:table}.ui-navbar ul:after{clear:both}.ui-navbar ul{list-style:none;margin:0;padding:0;position:relative;display:block;border:0;max-width:100%;overflow:visible}.ui-navbar li .ui-btn{font-size:12.5px;display:block;margin:0;border-right-width:0}.ui-navbar .ui-btn:focus{z-index:1}.ui-navbar li:last-child .ui-btn{margin-right:-4px}.ui-navbar li:last-child .ui-btn:after{margin-right:4px}.ui-content .ui-navbar li:last-child .ui-btn,.ui-content .ui-navbar .ui-grid-duo .ui-block-b .ui-btn{border-right-width:1px;margin-right:0}.ui-content .ui-navbar li:last-child .ui-btn:after,.ui-content .ui-navbar .ui-grid-duo .ui-block-b .ui-btn:after{margin-right:0}.ui-navbar .ui-grid-duo .ui-block-a:last-child .ui-btn{border-right-width:1px;margin-right:-1px}.ui-navbar .ui-grid-duo .ui-block-a:last-child .ui-btn:after{margin-right:1px}.ui-navbar .ui-grid-duo .ui-btn{border-top-width:0}.ui-navbar .ui-grid-duo .ui-block-a:first-child .ui-btn,.ui-navbar .ui-grid-duo .ui-block-a:first-child+.ui-block-b .ui-btn{border-top-width:1px}.ui-header .ui-navbar .ui-btn,.ui-footer .ui-navbar .ui-btn{border-top-width:0;border-bottom-width:0}.ui-header .ui-navbar .ui-grid-duo .ui-block-a:first-child .ui-btn,.ui-footer .ui-navbar .ui-grid-duo .ui-block-a:first-child .ui-btn,.ui-header .ui-navbar .ui-grid-duo .ui-block-a:first-child+.ui-block-b .ui-btn,.ui-footer .ui-navbar .ui-grid-duo .ui-block-a:first-child+.ui-block-b .ui-btn{border-top-width:0}.ui-header .ui-title~.ui-navbar .ui-btn,.ui-footer .ui-title~.ui-navbar .ui-btn,.ui-header .ui-navbar .ui-grid-duo .ui-btn,.ui-footer .ui-navbar .ui-grid-duo .ui-btn,.ui-header .ui-title~.ui-navbar .ui-grid-duo .ui-block-a:first-child .ui-btn,.ui-footer .ui-title~.ui-navbar .ui-grid-duo .ui-block-a:first-child .ui-btn,.ui-header .ui-title~.ui-navbar .ui-grid-duo .ui-block-a:first-child+.ui-block-b .ui-btn,.ui-footer .ui-title~.ui-navbar .ui-grid-duo .ui-block-a:first-child+.ui-block-b .ui-btn{border-top-width:1px}.ui-input-btn input{position:absolute;top:0;left:0;width:100%;height:100%;padding:0;border:0;outline:0;-webkit-border-radius:inherit;border-radius:inherit;-webkit-appearance:none;-moz-appearance:none;cursor:pointer;background:#fff;background:rgba(255,255,255,0);filter:Alpha(Opacity=0);opacity:.1;font-size:1px;text-indent:-9999px;z-index:2}.ui-input-btn.ui-state-disabled input{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-collapsible{margin:0 -1em}.ui-collapsible-inset,.ui-collapsible-set{margin:.5em 0}.ui-collapsible-heading{display:block;margin:0;padding:0;position:relative}.ui-collapsible-heading .ui-btn{text-align:left;margin:0;border-left-width:0;border-right-width:0}.ui-collapsible-heading .ui-btn-icon-top,.ui-collapsible-heading .ui-btn-icon-bottom{text-align:center}.ui-collapsible-inset .ui-collapsible-heading .ui-btn{border-right-width:1px;border-left-width:1px}.ui-collapsible-collapsed+.ui-collapsible:not(.ui-collapsible-inset)>.ui-collapsible-heading .ui-btn{border-top-width:0}.ui-collapsible-set .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn{border-top-width:1px}.ui-collapsible-heading-status{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-collapsible-content{display:block;margin:0;padding:.5em 1em}.ui-collapsible-themed-content .ui-collapsible-content{border-left-width:0;border-right-width:0;border-top-width:0;border-bottom-width:1px;border-style:solid}.ui-collapsible-inset.ui-collapsible-themed-content .ui-collapsible-content{border-left-width:1px;border-right-width:1px}.ui-collapsible-inset .ui-collapsible-content{margin:0}.ui-collapsible-content-collapsed{display:none}.ui-collapsible-set>.ui-collapsible.ui-corner-all{-webkit-border-radius:0;border-radius:0}.ui-collapsible-heading,.ui-collapsible-heading>.ui-btn{-webkit-border-radius:inherit;border-radius:inherit}.ui-collapsible-set .ui-collapsible.ui-first-child{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-collapsible-content,.ui-collapsible-set .ui-collapsible.ui-last-child{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-collapsible-themed-content:not(.ui-collapsible-collapsed)>.ui-collapsible-heading{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0}.ui-collapsible-set .ui-collapsible{margin:-1px -1em 0}.ui-collapsible-set .ui-collapsible-inset{margin:-1px 0 0}.ui-collapsible-set .ui-collapsible.ui-first-child{margin-top:0}.ui-controlgroup,fieldset.ui-controlgroup{padding:0;margin:.5em 0}.ui-field-contain .ui-controlgroup,.ui-field-contain fieldset.ui-controlgroup{margin:0}.ui-mini .ui-controlgroup-label{font-size:16px}.ui-controlgroup.ui-mini .ui-btn-icon-notext,.ui-controlgroup .ui-mini.ui-btn-icon-notext{font-size:inherit}.ui-controlgroup-controls .ui-btn,.ui-controlgroup-controls .ui-checkbox,.ui-controlgroup-controls .ui-radio,.ui-controlgroup-controls .ui-select{margin:0}.ui-controlgroup-controls .ui-btn:focus,.ui-controlgroup-controls .ui-btn.ui-focus{z-index:1}.ui-controlgroup-controls li{list-style:none}.ui-controlgroup-horizontal .ui-controlgroup-controls{display:inline-block;vertical-align:middle}.ui-controlgroup-horizontal .ui-controlgroup-controls:before,.ui-controlgroup-horizontal .ui-controlgroup-controls:after{content:"";display:table}.ui-controlgroup-horizontal .ui-controlgroup-controls:after{clear:both}.ui-controlgroup-horizontal .ui-controlgroup-controls>.ui-btn,.ui-controlgroup-horizontal .ui-controlgroup-controls li>.ui-btn,.ui-controlgroup-horizontal .ui-controlgroup-controls .ui-checkbox,.ui-controlgroup-horizontal .ui-controlgroup-controls .ui-radio,.ui-controlgroup-horizontal .ui-controlgroup-controls .ui-select{float:left;clear:none}.ui-controlgroup-horizontal .ui-controlgroup-controls button.ui-btn,.ui-controlgroup-controls .ui-btn-icon-notext{width:auto}.ui-controlgroup-horizontal .ui-controlgroup-controls .ui-btn-icon-notext,.ui-controlgroup-horizontal .ui-controlgroup-controls button.ui-btn-icon-notext{width:1.5em}.ui-controlgroup-controls .ui-btn-icon-notext{height:auto;padding:.7em 1em}.ui-controlgroup-vertical .ui-controlgroup-controls .ui-btn{border-bottom-width:0}.ui-controlgroup-vertical .ui-controlgroup-controls .ui-btn.ui-last-child{border-bottom-width:1px}.ui-controlgroup-horizontal .ui-controlgroup-controls .ui-btn{border-right-width:0}.ui-controlgroup-horizontal .ui-controlgroup-controls .ui-btn.ui-last-child{border-right-width:1px}.ui-controlgroup-controls .ui-btn-corner-all,.ui-controlgroup-controls .ui-btn.ui-corner-all{-webkit-border-radius:0;border-radius:0}.ui-controlgroup-controls,.ui-controlgroup-controls .ui-radio,.ui-controlgroup-controls .ui-checkbox,.ui-controlgroup-controls .ui-select,.ui-controlgroup-controls li{-webkit-border-radius:inherit;border-radius:inherit}.ui-controlgroup-vertical .ui-btn.ui-first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-controlgroup-vertical .ui-btn.ui-last-child{-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-controlgroup-horizontal .ui-btn.ui-first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-controlgroup-horizontal .ui-btn.ui-last-child{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-controlgroup-controls a.ui-shadow:not(:focus),.ui-controlgroup-controls button.ui-shadow:not(:focus),.ui-controlgroup-controls div.ui-shadow:not(.ui-focus){-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}.ui-controlgroup-label legend{max-width:100%}.ui-controlgroup-controls>label{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-dialog{background:none!important}.ui-dialog-contain{width:92.5%;max-width:500px;margin:10% auto 1em;padding:0;position:relative;top:-1em}.ui-dialog-contain>.ui-header,.ui-dialog-contain>.ui-content,.ui-dialog-contain>.ui-footer{display:block;position:relative;width:auto;margin:0}.ui-dialog-contain>.ui-header{overflow:hidden;z-index:10;padding:0;border-top-width:0}.ui-dialog-contain>.ui-footer{z-index:10;padding:0 1em;border-bottom-width:0}.ui-popup-open .ui-header-fixed,.ui-popup-open .ui-footer-fixed{position:absolute!important}.ui-popup-screen{background-image:url("data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");top:0;left:0;right:0;bottom:1px;position:absolute;filter:Alpha(Opacity=0);opacity:0;z-index:1099}.ui-popup-screen.in{opacity:.5;filter:Alpha(Opacity=50)}.ui-popup-screen.out{opacity:0;filter:Alpha(Opacity=0)}.ui-popup-container{z-index:1100;display:inline-block;position:absolute;padding:0;outline:0}.ui-popup{position:relative}.ui-popup.ui-body-inherit{border-width:1px;border-style:solid}.ui-popup-hidden{left:0;top:0;position:absolute!important;visibility:hidden}.ui-popup-truncate{height:1px;width:1px;margin:-1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-popup.ui-content,.ui-popup .ui-content{overflow:visible}.ui-popup>.ui-header{border-top-width:0}.ui-popup>.ui-footer{border-bottom-width:0}.ui-popup>p,.ui-popup>h1,.ui-popup>h2,.ui-popup>h3,.ui-popup>h4,.ui-popup>h5,.ui-popup>h6{margin:.5em .4375em}.ui-popup>span{display:block;margin:.5em .4375em}.ui-popup-container .ui-content>p,.ui-popup-container .ui-content>h1,.ui-popup-container .ui-content>h2,.ui-popup-container .ui-content>h3,.ui-popup-container .ui-content>h4,.ui-popup-container .ui-content>h5,.ui-popup-container .ui-content>h6{margin:.5em 0}.ui-popup-container .ui-content>span{margin:0}.ui-popup-container .ui-content>p:first-child,.ui-popup-container .ui-content>h1:first-child,.ui-popup-container .ui-content>h2:first-child,.ui-popup-container .ui-content>h3:first-child,.ui-popup-container .ui-content>h4:first-child,.ui-popup-container .ui-content>h5:first-child,.ui-popup-container .ui-content>h6:first-child{margin-top:0}.ui-popup-container .ui-content>p:last-child,.ui-popup-container .ui-content>h1:last-child,.ui-popup-container .ui-content>h2:last-child,.ui-popup-container .ui-content>h3:last-child,.ui-popup-container .ui-content>h4:last-child,.ui-popup-container .ui-content>h5:last-child,.ui-popup-container .ui-content>h6:last-child{margin-bottom:0}.ui-popup>img{max-width:100%;max-height:100%;vertical-align:middle}.ui-popup:not(.ui-content)>img:only-child,.ui-popup:not(.ui-content)>.ui-btn-left:first-child+img:last-child,.ui-popup:not(.ui-content)>.ui-btn-right:first-child+img:last-child{-webkit-border-radius:inherit;border-radius:inherit}.ui-popup iframe{vertical-align:middle}.ui-popup>.ui-btn-left,.ui-popup>.ui-btn-right{position:absolute;top:-11px;margin:0;z-index:1101}.ui-popup>.ui-btn-left{left:-11px}.ui-popup>.ui-btn-right{right:-11px}.ui-popup-arrow-container{width:20px;height:20px}.ui-popup-arrow-container.ui-popup-arrow-l{left:-10px;clip:rect(-1000px,10px,2000px,-1000px)}.ui-popup-arrow-container.ui-popup-arrow-t{top:-10px;clip:rect(-1000px,2000px,10px,-1000px)}.ui-popup-arrow-container.ui-popup-arrow-r{right:-10px;clip:rect(-1000px,2000px,2000px,10px)}.ui-popup-arrow-container.ui-popup-arrow-b{bottom:-10px;clip:rect(10px,2000px,1000px,-1000px)}.ui-popup-arrow-container .ui-popup-arrow{width:28.284271247px;height:28.284271247px;border-width:1px;border-style:solid}.ui-popup-arrow-container.ui-popup-arrow-t .ui-popup-arrow{left:-4.142135623px;top:5.857864376px}.ui-popup-arrow-container.ui-popup-arrow-b .ui-popup-arrow{left:-4.142135623px;top:-14.142135623px}.ui-popup-arrow-container.ui-popup-arrow-l .ui-popup-arrow{left:5.857864376px;top:-4.142135623px}.ui-popup-arrow-container.ui-popup-arrow-r .ui-popup-arrow{left:-14.142135623px;top:-4.142135623px}.ui-popup-arrow-container.ui-popup-arrow-t.ie .ui-popup-arrow{margin-left:-5.857864376269049px;margin-top:-7.0710678118654755px}.ui-popup-arrow-container.ui-popup-arrow-b.ie .ui-popup-arrow{margin-left:-5.857864376269049px;margin-top:-4.142135623730951px}.ui-popup-arrow-container.ui-popup-arrow-l.ie .ui-popup-arrow{margin-left:-7.0710678118654755px;margin-top:-5.857864376269049px}.ui-popup-arrow-container.ui-popup-arrow-r.ie .ui-popup-arrow{margin-left:-4.142135623730951px;margin-top:-5.857864376269049px}.ui-popup>.ui-popup-arrow-guide{position:absolute;left:0;right:0;top:0;bottom:0;visibility:hidden}.ui-popup-arrow-container{position:absolute}.ui-popup-arrow{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);position:absolute;overflow:hidden;box-sizing:border-box}.ui-popup-arrow-container.ie .ui-popup-arrow{-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(M11=0.7071067811865474, M12=-0.7071067811865477, M21=0.7071067811865477, M22=0.7071067811865474, SizingMethod='auto expand')";filter:progid:DXImageTransform.Microsoft.Matrix(M11=.7071067811865474, M12=-.7071067811865477, M21=.7071067811865477, M22=.7071067811865474, SizingMethod='auto expand')}.ui-checkbox,.ui-radio{margin:.5em 0;position:relative}.ui-checkbox .ui-btn,.ui-radio .ui-btn{margin:0;text-align:left;white-space:normal;z-index:2}.ui-controlgroup .ui-checkbox .ui-btn.ui-focus,.ui-controlgroup .ui-radio .ui-btn.ui-focus{z-index:3}.ui-checkbox .ui-btn-icon-top,.ui-radio .ui-btn-icon-top,.ui-checkbox .ui-btn-icon-bottom,.ui-radio .ui-btn-icon-bottom{text-align:center}.ui-controlgroup-horizontal .ui-checkbox .ui-btn:after,.ui-controlgroup-horizontal .ui-radio .ui-btn:after{content:none;display:none}.ui-checkbox input,.ui-radio input{position:absolute;left:.466em;top:50%;width:22px;height:22px;margin:-11px 0 0 0;outline:0!important;z-index:1}.ui-controlgroup-horizontal .ui-checkbox input,.ui-controlgroup-horizontal .ui-radio input{left:50%;margin-left:-9px}.ui-checkbox input:disabled,.ui-radio input:disabled{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-select{margin-top:.5em;margin-bottom:.5em;position:relative}.ui-select>select{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-select .ui-btn{margin:0;opacity:1}.ui-select .ui-btn select{position:absolute;top:0;left:0;width:100%;min-height:1.5em;min-height:100%;height:3em;max-height:100%;outline:0;-webkit-border-radius:inherit;border-radius:inherit;-webkit-appearance:none;-moz-appearance:none;cursor:pointer;filter:Alpha(Opacity=0);opacity:0;z-index:2}@-moz-document url-prefix(){.ui-select .ui-btn select{opacity:.0001}}.ui-select .ui-state-disabled select{display:none}.ui-select span.ui-state-disabled{filter:Alpha(Opacity=100);opacity:1}.ui-select .ui-btn.ui-select-nativeonly{border-radius:0;border:0}.ui-select .ui-btn.ui-select-nativeonly select{opacity:1;text-indent:0;display:block}.ui-select .ui-li-has-count.ui-btn{padding-right:2.8125em}.ui-select .ui-li-has-count.ui-btn-icon-right{padding-right:4.6875em}.ui-select .ui-btn-icon-right .ui-li-count{right:3.2em}.ui-select .ui-btn>span:not(.ui-li-count){display:block;text-overflow:ellipsis;overflow:hidden!important;white-space:nowrap}.ui-selectmenu.ui-popup{min-width:11em}.ui-selectmenu .ui-dialog-contain{overflow:hidden}.ui-selectmenu .ui-header{margin:0;padding:0;border-width:0}.ui-selectmenu.ui-dialog .ui-header{z-index:1;position:relative}.ui-selectmenu.ui-popup .ui-header{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0}.ui-selectmenu.ui-popup .ui-header h1:after{content:'.';visibility:hidden}.ui-selectmenu .ui-header .ui-title{margin:0 2.875em}.ui-selectmenu.ui-dialog .ui-content{overflow:visible;z-index:1}.ui-selectmenu .ui-selectmenu-list{margin:0;-webkit-border-radius:inherit;border-radius:inherit}.ui-header:not(.ui-screen-hidden)+.ui-selectmenu-list{-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-top-left-radius:0;border-top-left-radius:0}.ui-header.ui-screen-hidden+.ui-selectmenu-list li.ui-first-child .ui-btn{border-top-width:0}.ui-selectmenu .ui-selectmenu-list li.ui-last-child .ui-btn{border-bottom-width:0}.ui-selectmenu .ui-btn.ui-li-divider{cursor:default}.ui-selectmenu .ui-selectmenu-placeholder{display:none}.ui-listview,.ui-listview>li{margin:0;padding:0;list-style:none}.ui-content .ui-listview,.ui-panel-inner>.ui-listview{margin:-1em}.ui-content .ui-listview-inset,.ui-panel-inner>.ui-listview-inset{margin:1em 0}.ui-collapsible-content>.ui-listview{margin:-.5em -1em}.ui-collapsible-content>.ui-listview-inset{margin:.5em 0}.ui-listview>li{display:block;position:relative;overflow:visible}.ui-listview>.ui-li-static,.ui-listview>.ui-li-divider,.ui-listview>li>a.ui-btn{margin:0;display:block;position:relative;text-align:left;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-listview>li>.ui-btn:focus{z-index:1}.ui-listview>.ui-li-static,.ui-listview>.ui-li-divider,.ui-listview>li>a.ui-btn{border-width:1px 0 0;border-style:solid}.ui-listview-inset>.ui-li-static,.ui-listview-inset>.ui-li-divider,.ui-listview-inset>li>a.ui-btn{border-right-width:1px;border-left-width:1px}.ui-listview>.ui-li-static.ui-last-child,.ui-listview>.ui-li-divider.ui-last-child,.ui-listview>li.ui-last-child>a.ui-btn{border-bottom-width:1px}.ui-collapsible-content>.ui-listview:not(.ui-listview-inset)>li.ui-first-child,.ui-collapsible-content>.ui-listview:not(.ui-listview-inset)>li.ui-first-child>a.ui-btn{border-top-width:0}.ui-collapsible-themed-content .ui-listview:not(.ui-listview-inset)>li.ui-last-child,.ui-collapsible-themed-content .ui-listview:not(.ui-listview-inset)>li.ui-last-child>a.ui-btn{border-bottom-width:0}.ui-listview>li.ui-first-child,.ui-listview>li.ui-first-child>a.ui-btn{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-listview>li.ui-last-child,.ui-listview>li.ui-last-child>a.ui-btn{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-listview>li.ui-li-has-alt>a.ui-btn{-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0}.ui-listview>li.ui-first-child>a.ui-btn+a.ui-btn{-webkit-border-top-left-radius:0;border-top-left-radius:0;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-listview>li.ui-last-child>a.ui-btn+a.ui-btn{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-listview>li.ui-first-child img:first-child:not(.ui-li-icon){-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-listview>li.ui-last-child img:first-child:not(.ui-li-icon){-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-collapsible-content>.ui-listview:not(.ui-listview-inset){-webkit-border-radius:inherit;border-radius:inherit}.ui-listview>.ui-li-static{padding:.7em 1em}.ui-listview>.ui-li-divider{padding:.5em 1.143em;font-size:14px;font-weight:700;cursor:default;outline:0}.ui-listview>.ui-li-has-count>.ui-btn,.ui-listview>.ui-li-static.ui-li-has-count,.ui-listview>.ui-li-divider.ui-li-has-count{padding-right:2.8125em}.ui-listview>.ui-li-has-count>.ui-btn-icon-right{padding-right:4.6875em}.ui-listview>.ui-li-has-thumb>.ui-btn,.ui-listview>.ui-li-static.ui-li-has-thumb{min-height:3.625em;padding-left:6.25em}.ui-listview>.ui-li-has-icon>.ui-btn,.ui-listview>.ui-li-static.ui-li-has-icon{min-height:1.25em;padding-left:2.5em}.ui-li-count{position:absolute;font-size:12.5px;font-weight:700;text-align:center;border-width:1px;border-style:solid;padding:0 .48em;line-height:1.6em;min-height:1.6em;min-width:.64em;right:.8em;top:50%;margin-top:-.88em}.ui-listview .ui-btn-icon-right .ui-li-count{right:3.2em}.ui-listview .ui-li-has-thumb>img:first-child,.ui-listview .ui-li-has-thumb>.ui-btn>img:first-child,.ui-listview .ui-li-has-thumb .ui-li-thumb{position:absolute;left:0;top:0;max-height:5em;max-width:5em}.ui-listview>.ui-li-has-icon>img:first-child,.ui-listview>.ui-li-has-icon>.ui-btn>img:first-child{position:absolute;left:.625em;top:.9em;max-height:1em;max-width:1em}.ui-listview>li h1,.ui-listview>li h2,.ui-listview>li h3,.ui-listview>li h4,.ui-listview>li h5,.ui-listview>li h6{font-size:1em;font-weight:700;display:block;margin:.45em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-listview>li p{font-size:.75em;font-weight:400;display:block;margin:.6em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-listview .ui-li-aside{position:absolute;top:1em;right:3.333em;margin:0;text-align:right}.ui-listview>li.ui-li-has-alt>.ui-btn{margin-right:2.5em;border-right-width:0}.ui-listview>li.ui-li-has-alt>.ui-btn+.ui-btn{position:absolute;width:2.5em;height:100%;min-height:auto;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border-left-width:1px;top:0;right:0;margin:0;padding:0;z-index:2}.ui-listview-inset>li.ui-li-has-alt>.ui-btn+.ui-btn{border-right-width:1px}.ui-listview>li.ui-li-has-alt>.ui-btn+.ui-btn:focus{z-index:3}ol.ui-listview,ol.ui-listview>.ui-li-divider{counter-reset:listnumbering}ol.ui-listview>li>.ui-btn,ol.ui-listview>li.ui-li-static{vertical-align:middle}ol.ui-listview>li>.ui-btn:first-child:before,ol.ui-listview>li.ui-li-static:before,ol.ui-listview>li.ui-field-contain>label:before,ol.ui-listview>li.ui-field-contain>.ui-controlgroup-label:before{display:inline-block;font-size:.9em;font-weight:400;padding-right:.3em;min-width:1.4em;line-height:1.5;vertical-align:middle;counter-increment:listnumbering;content:counter(listnumbering) "."}ol.ui-listview>li.ui-field-contain:before{content:none;display:none}ol.ui-listview>li h1:first-child,ol.ui-listview>li h2:first-child,ol.ui-listview>li h3:first-child,ol.ui-listview>li h4:first-child,ol.ui-listview>li h5:first-child,ol.ui-listview>li h6:first-child,ol.ui-listview>li p:first-child,ol.ui-listview>li img:first-child+*{display:inline-block;vertical-align:middle}ol.ui-listview>li h1:first-child~*,ol.ui-listview>li h2:first-child~*,ol.ui-listview>li h3:first-child~*,ol.ui-listview>li h4:first-child~*,ol.ui-listview>li h5:first-child~*,ol.ui-listview>li h6:first-child~*,ol.ui-listview>li p:first-child~*,ol.ui-listview>li img:first-child+*~*{margin-top:0;text-indent:2.04em}html .ui-filterable+.ui-listview,html .ui-filterable.ui-listview{margin-top:.5em}.ui-collapsible-content>form.ui-filterable{margin-top:-.5em}.ui-collapsible-content>.ui-input-search.ui-filterable{margin-top:0}.ui-collapsible-content>.ui-filterable+.ui-listview:not(.ui-listview-inset)>li.ui-first-child,.ui-collapsible-content>.ui-filterable+.ui-listview:not(.ui-listview-inset)>li.ui-first-child>a.ui-btn,.ui-collapsible-content>.ui-filterable.ui-listview:not(.ui-listview-inset)>li.ui-first-child,.ui-collapsible-content>.ui-filterable.ui-listview:not(.ui-listview-inset)>li.ui-first-child>a.ui-btn{border-top-width:1px}div.ui-slider{height:30px;margin:.5em 0;padding:0;-ms-touch-action:pan-y pinch-zoom double-tap-zoom}div.ui-slider:before,div.ui-slider:after{content:"";display:table}div.ui-slider:after{clear:both}input.ui-slider-input{display:block;float:left;font-size:14px;font-weight:700;margin:0;padding:4px;width:40px;height:20px;line-height:20px;border-width:1px;border-style:solid;outline:0;text-align:center;vertical-align:text-bottom;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;box-sizing:content-box}.ui-slider-input::-webkit-outer-spin-button,.ui-slider-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ui-slider-track{position:relative;overflow:visible;border-width:1px;border-style:solid;height:15px;margin:0 15px 0 68px;top:6px}.ui-slider-track.ui-mini{height:12px;top:8px}.ui-slider-track .ui-slider-bg{height:100%}.ui-slider-track .ui-btn.ui-slider-handle{position:absolute;z-index:1;top:50%;width:28px;height:28px;margin:-15px 0 0 -15px;outline:0;padding:0}.ui-slider-track.ui-mini .ui-slider-handle{height:14px;width:14px;margin:-8px 0 0 -8px}select.ui-slider-switch{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}div.ui-slider-switch{display:inline-block;height:32px;width:5.8em;top:0}div.ui-slider-switch:before,div.ui-slider-switch:after{display:none;clear:none}div.ui-slider-switch.ui-mini{height:29px;top:0}.ui-slider-inneroffset{margin:0 16px;position:relative;z-index:1}.ui-slider-switch.ui-mini .ui-slider-inneroffset{margin:0 15px 0 14px}.ui-slider-switch .ui-btn.ui-slider-handle{margin:1px 0 0 -15px}.ui-slider-switch.ui-mini .ui-slider-handle{width:25px;height:25px;margin:1px 0 0 -13px;padding:0}.ui-slider-handle-snapping{-webkit-transition:left 70ms linear;-moz-transition:left 70ms linear;transition:left 70ms linear}.ui-slider-switch .ui-slider-label{position:absolute;text-align:center;width:100%;overflow:hidden;font-size:16px;top:0;line-height:2;min-height:100%;white-space:nowrap;cursor:pointer}.ui-slider-switch.ui-mini .ui-slider-label{font-size:14px}.ui-slider-switch .ui-slider-label-a{z-index:1;left:0;text-indent:-1.5em}.ui-slider-switch .ui-slider-label-b{z-index:0;right:0;text-indent:1.5em}.ui-slider-track .ui-slider-bg,.ui-slider-switch .ui-slider-label,.ui-slider-switch .ui-slider-inneroffset,.ui-slider-handle{-webkit-border-radius:inherit;border-radius:inherit}.ui-field-contain div.ui-slider-switch{margin:0}.ui-field-contain div.ui-slider-switch,.ui-field-contain.ui-hide-label div.ui-slider-switch,html .ui-popup .ui-field-contain div.ui-slider-switch{display:inline-block;width:5.8em}.ui-slider-popup{width:64px;height:64px;font-size:36px;padding-top:14px;opacity:.8}.ui-slider-popup{position:absolute!important;text-align:center;z-index:100}.ui-slider-track .ui-btn.ui-slider-handle{font-size:.9em;line-height:30px}.ui-rangeslider{margin:.5em 0}.ui-rangeslider:before,.ui-rangeslider:after{content:"";display:table}.ui-rangeslider:after{clear:both}.ui-rangeslider .ui-slider-input.ui-rangeslider-last{float:right}.ui-rangeslider .ui-rangeslider-sliders{position:relative;overflow:visible;height:30px;margin:0 68px}.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track{position:absolute;top:6px;right:0;left:0;margin:0}.ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track{top:8px}.ui-rangeslider .ui-slider-track:first-child .ui-slider-bg{display:none}.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child{background-color:transparent;background:0;border-width:0;height:0}html >body .ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child{height:15px;border-width:1px}html >body .ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track:first-child{height:12px}div.ui-rangeslider label{position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.ui-field-contain .ui-rangeslider input.ui-slider-input,.ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input,.ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,.ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders{margin-top:0;margin-bottom:0}.ui-input-text,.ui-input-search{margin:.5em 0;border-width:1px;border-style:solid}.ui-input-text input,.ui-input-search input,textarea.ui-input-text{padding:.4em;line-height:1.4em;display:block;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;outline:0}.ui-input-text input,.ui-input-search input{margin:0;min-height:2.2em;text-align:left;border:0;background:transparent none;-webkit-appearance:none;-webkit-border-radius:inherit;border-radius:inherit}textarea.ui-input-text{overflow:auto;resize:vertical}.ui-mini .ui-input-text input,.ui-mini .ui-input-search input,.ui-input-text.ui-mini input,.ui-input-search.ui-mini input,.ui-mini textarea.ui-input-text,textarea.ui-mini{font-size:14px}.ui-mini textarea.ui-input-text,textarea.ui-mini{margin:.446em 0}.ui-input-has-clear,.ui-input-search{position:relative}.ui-input-has-clear{padding-right:2.375em}.ui-mini.ui-input-has-clear{padding-right:2.923em}.ui-input-has-clear input{padding-right:0;-webkit-border-top-right-radius:0;border-top-right-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0}.ui-input-search input{padding-left:1.75em}.ui-input-search:after{position:absolute;left:.3125em;top:50%;margin-top:-7px;content:"";background-position:center center;background-repeat:no-repeat;width:14px;height:14px;filter:Alpha(Opacity=50);opacity:.5}.ui-input-search.ui-input-has-clear .ui-btn.ui-input-clear,.ui-input-text.ui-input-has-clear .ui-btn.ui-input-clear{position:absolute;right:0;top:50%;margin:-14px .3125em 0;border:0;background-color:transparent}.ui-input-search .ui-input-clear-hidden,.ui-input-text .ui-input-clear-hidden{display:none}.ui-input-text input::-moz-placeholder,.ui-input-search input::-moz-placeholder,textarea.ui-input-text::-moz-placeholder{color:#aaa}.ui-input-text input:-ms-input-placeholder,.ui-input-search input:-ms-input-placeholder,textarea.ui-input-text:-ms-input-placeholder{color:#aaa}.ui-input-text input[type=number]::-webkit-outer-spin-button{margin:0}.ui-input-text input::-ms-clear,.ui-input-search input::-ms-clear{display:none}.ui-input-text input:focus,.ui-input-search input:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}textarea.ui-input-text.ui-textinput-autogrow{overflow:hidden}.ui-textinput-autogrow-resize{-webkit-transition:height .25s;-o-transition:height .25s;-moz-transition:height .25s;transition:height .25s}.ui-flipswitch{display:inline-block;vertical-align:middle;width:5.875em;height:1.875em;border-width:1px;border-style:solid;margin:.5em 0;overflow:hidden;-webkit-transition-property:padding,width,background-color,color,border-color;-moz-transition-property:padding,width,background-color,color,border-color;-o-transition-property:padding,width,background-color,color,border-color;transition-property:padding,width,background-color,color,border-color;-webkit-transition-duration:100ms;-moz-transition-duration:100ms;-o-transition-duration:100ms;transition-duration:100ms;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer}.ui-flipswitch.ui-flipswitch-active{padding-left:4em;width:1.875em}.ui-flipswitch-input{position:absolute;height:1px;width:1px;margin:-1px;overflow:hidden;clip:rect(1px,1px,1px,1px);border:0;outline:0;filter:Alpha(Opacity=0);opacity:0}.ui-flipswitch .ui-btn.ui-flipswitch-on,.ui-flipswitch .ui-flipswitch-off{float:left;height:1.75em;margin:.0625em;line-height:1.65em}.ui-flipswitch .ui-btn.ui-flipswitch-on{width:1.75em;padding:0;text-indent:-2.6em;text-align:left;border-width:1px;border-style:solid;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;border-radius:inherit;overflow:visible;color:inherit;text-shadow:inherit}.ui-flipswitch .ui-flipswitch-off{padding:1px;text-indent:1em}html .ui-field-contain>label+.ui-flipswitch,html .ui-popup .ui-field-contain>label+.ui-flipswitch{display:inline-block;width:5.875em;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;box-sizing:content-box}.ui-field-contain .ui-flipswitch.ui-flipswitch-active,.ui-popup .ui-field-contain .ui-flipswitch.ui-flipswitch-active{width:1.875em}.ui-table{border:0;border-collapse:collapse;padding:0;width:100%}.ui-table th,.ui-table td{line-height:1.5em;text-align:left;padding:.4em .5em;vertical-align:top}.ui-table th .ui-btn,.ui-table td .ui-btn{line-height:normal}.ui-table th{font-weight:700}.ui-table caption{text-align:left;margin-bottom:1.4em;opacity:.5}.ui-table-columntoggle-btn{float:right;margin-bottom:.8em}.ui-table-columntoggle-popup fieldset{margin:0}.ui-table-columntoggle{clear:both}@media only all{th.ui-table-priority-6,td.ui-table-priority-6,th.ui-table-priority-5,td.ui-table-priority-5,th.ui-table-priority-4,td.ui-table-priority-4,th.ui-table-priority-3,td.ui-table-priority-3,th.ui-table-priority-2,td.ui-table-priority-2,th.ui-table-priority-1,td.ui-table-priority-1{display:none}}@media screen and (min-width:20em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-1,.ui-table-columntoggle.ui-responsive td.ui-table-priority-1{display:table-cell}}@media screen and (min-width:30em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-2,.ui-table-columntoggle.ui-responsive td.ui-table-priority-2{display:table-cell}}@media screen and (min-width:40em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-3,.ui-table-columntoggle.ui-responsive td.ui-table-priority-3{display:table-cell}}@media screen and (min-width:50em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-4,.ui-table-columntoggle.ui-responsive td.ui-table-priority-4{display:table-cell}}@media screen and (min-width:60em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-5,.ui-table-columntoggle.ui-responsive td.ui-table-priority-5{display:table-cell}}@media screen and (min-width:70em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-6,.ui-table-columntoggle.ui-responsive td.ui-table-priority-6{display:table-cell}}.ui-table-columntoggle th.ui-table-cell-hidden,.ui-table-columntoggle td.ui-table-cell-hidden,.ui-table-columntoggle.ui-responsive th.ui-table-cell-hidden,.ui-table-columntoggle.ui-responsive td.ui-table-cell-hidden{display:none}.ui-table-columntoggle th.ui-table-cell-visible,.ui-table-columntoggle td.ui-table-cell-visible,.ui-table-columntoggle.ui-responsive th.ui-table-cell-visible,.ui-table-columntoggle.ui-responsive td.ui-table-cell-visible{display:table-cell}.ui-table-reflow td .ui-table-cell-label,.ui-table-reflow th .ui-table-cell-label{display:none}@media only all{.ui-table-reflow thead td,.ui-table-reflow thead th{display:none}.ui-table-reflow td,.ui-table-reflow th{text-align:left;display:block}.ui-table-reflow tbody th{margin-top:3em}.ui-table-reflow td .ui-table-cell-label,.ui-table-reflow th .ui-table-cell-label{padding:.4em;min-width:30%;display:inline-block;margin:-.4em 1em -.4em -.4em}.ui-table-reflow th .ui-table-cell-label-top,.ui-table-reflow td .ui-table-cell-label-top{display:block;padding:.4em 0;margin:.4em 0;text-transform:uppercase;font-size:.9em;font-weight:400}}@media (min-width:35em){.ui-table-reflow.ui-responsive{display:table-row-group}.ui-table-reflow.ui-responsive td,.ui-table-reflow.ui-responsive th,.ui-table-reflow.ui-responsive tbody th,.ui-table-reflow.ui-responsive tbody td,.ui-table-reflow.ui-responsive thead td,.ui-table-reflow.ui-responsive thead th{display:table-cell;margin:0}.ui-table-reflow.ui-responsive td .ui-table-cell-label,.ui-table-reflow.ui-responsive th .ui-table-cell-label{display:none}}@media (max-width:35em){.ui-table-reflow.ui-responsive td,.ui-table-reflow.ui-responsive th{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;clear:left}}.ui-panel{width:17em;min-height:100%;max-height:none;border-width:0;position:absolute;top:0;display:block}.ui-panel-closed{width:0;max-height:100%;overflow:hidden;visibility:hidden}.ui-panel-fixed{position:fixed;bottom:-1px;padding-bottom:1px}.ui-panel-display-reveal{z-index:1}.ui-panel-display-push{z-index:999}.ui-panel-display-overlay{z-index:1001}.ui-panel-inner{padding:1em}.ui-panel-page-container{overflow-x:visible}.ui-panel-page-container-themed .ui-page-active{background:0}.ui-panel-wrapper{position:relative;min-height:inherit;border:0;overflow-x:hidden;z-index:999}.ui-panel-fixed-toolbar{overflow-x:hidden}.ui-panel-dismiss{position:absolute;top:0;left:0;right:0;height:100%;z-index:1002;display:none}.ui-panel-dismiss-open{display:block}.ui-panel-animate{-webkit-transition:-webkit-transform 300ms ease;-webkit-transition-duration:300ms;-moz-transition:-moz-transform 300ms ease;transition:transform 300ms ease}@media screen and (max-device-width:768px){.ui-page-header-fixed .ui-panel-animate.ui-panel-wrapper,.ui-page-footer-fixed .ui-panel-animate.ui-panel-wrapper,.ui-panel-animate.ui-panel-fixed-toolbar{-ms-transition:none}.ui-panel-animate.ui-panel-fixed-toolbar{-ms-transition:-ms-transform 1ms;-ms-transform:rotate(0deg)}}.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal){-webkit-backface-visibility:hidden;-webkit-transform:translate3d(0,0,0)}.ui-panel-position-left{left:-17em}.ui-panel-animate.ui-panel-position-left.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-left.ui-panel-display-push{left:0;-webkit-transform:translate3d(-17em,0,0);-moz-transform:translate3d(-17em,0,0);transform:translate3d(-17em,0,0)}.ui-panel-position-left.ui-panel-display-reveal,.ui-panel-open.ui-panel-position-left{left:0}.ui-panel-animate.ui-panel-open.ui-panel-position-left.ui-panel-display-overlay,.ui-panel-animate.ui-panel-open.ui-panel-position-left.ui-panel-display-push{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-moz-transform:none}.ui-panel-position-right{right:-17em}.ui-panel-animate.ui-panel-position-right.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-right.ui-panel-display-push{right:0;-webkit-transform:translate3d(17em,0,0);-moz-transform:translate3d(17em,0,0);transform:translate3d(17em,0,0)}.ui-panel-position-right.ui-panel-display-reveal,.ui-panel-position-right.ui-panel-open{right:0}.ui-panel-animate.ui-panel-open.ui-panel-position-right.ui-panel-display-overlay,.ui-panel-animate.ui-panel-open.ui-panel-position-right.ui-panel-display-push{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-moz-transform:none}.ui-panel-page-content-position-left{left:17em;right:-17em}.ui-panel-animate.ui-panel-page-content-position-left{left:0;right:0;-webkit-transform:translate3d(17em,0,0);-moz-transform:translate3d(17em,0,0);transform:translate3d(17em,0,0)}.ui-panel-page-content-position-right{left:-17em;right:17em}.ui-panel-animate.ui-panel-page-content-position-right{left:0;right:0;-webkit-transform:translate3d(-17em,0,0);-moz-transform:translate3d(-17em,0,0);transform:translate3d(-17em,0,0)}.ui-panel-dismiss-open.ui-panel-dismiss-position-left{left:17em}.ui-panel-dismiss-open.ui-panel-dismiss-position-right{right:17em}.ui-panel-display-reveal{-webkit-box-shadow:inset -5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:inset -5px 0 5px rgba(0,0,0,.15);box-shadow:inset -5px 0 5px rgba(0,0,0,.15)}.ui-panel-position-right.ui-panel-display-reveal{-webkit-box-shadow:inset 5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:inset 5px 0 5px rgba(0,0,0,.15);box-shadow:inset 5px 0 5px rgba(0,0,0,.15)}.ui-panel-display-overlay{-webkit-box-shadow:5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:5px 0 5px rgba(0,0,0,.15);box-shadow:5px 0 5px rgba(0,0,0,.15)}.ui-panel-position-right.ui-panel-display-overlay{-webkit-box-shadow:-5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:-5px 0 5px rgba(0,0,0,.15);box-shadow:-5px 0 5px rgba(0,0,0,.15)}.ui-panel-open.ui-panel-position-left.ui-panel-display-push{border-right-width:1px;margin-right:-1px}.ui-panel-page-content-position-left.ui-panel-page-content-display-push{margin-left:1px;width:auto}.ui-panel-open.ui-panel-position-right.ui-panel-display-push{border-left-width:1px;margin-left:-1px}.ui-panel-page-content-position-right.ui-panel-page-content-display-push{margin-right:1px;width:auto}@media (min-width:55em){.ui-responsive-panel .ui-panel-page-content-open.ui-panel-page-content-position-left{margin-right:17em}.ui-responsive-panel .ui-panel-page-content-open.ui-panel-page-content-position-right{margin-left:17em}.ui-responsive-panel .ui-panel-page-content-open{width:auto}.ui-responsive-panel .ui-panel-dismiss-display-push,.ui-responsive-panel.ui-page-active~.ui-panel-dismiss-display-push{display:none}}.ui-tabs{position:relative;padding:.2em}
\ No newline at end of file
diff --git a/static/fonts/.DS_Store b/static/fonts/.DS_Store
deleted file mode 100644
index 5008ddfc..00000000
Binary files a/static/fonts/.DS_Store and /dev/null differ
diff --git a/static/fonts/glyphicons-halflings-regular.eot b/static/fonts/glyphicons-halflings-regular.eot
deleted file mode 100755
index 423bd5d3..00000000
Binary files a/static/fonts/glyphicons-halflings-regular.eot and /dev/null differ
diff --git a/static/fonts/glyphicons-halflings-regular.svg b/static/fonts/glyphicons-halflings-regular.svg
deleted file mode 100755
index 44694887..00000000
--- a/static/fonts/glyphicons-halflings-regular.svg
+++ /dev/null
@@ -1,229 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/static/fonts/glyphicons-halflings-regular.ttf b/static/fonts/glyphicons-halflings-regular.ttf
deleted file mode 100755
index a498ef4e..00000000
Binary files a/static/fonts/glyphicons-halflings-regular.ttf and /dev/null differ
diff --git a/static/fonts/glyphicons-halflings-regular.woff b/static/fonts/glyphicons-halflings-regular.woff
deleted file mode 100755
index d83c539b..00000000
Binary files a/static/fonts/glyphicons-halflings-regular.woff and /dev/null differ
diff --git a/static/js/.DS_Store b/static/js/.DS_Store
deleted file mode 100644
index 5008ddfc..00000000
Binary files a/static/js/.DS_Store and /dev/null differ
diff --git a/static/js/blockly/blockly_compressed.js b/static/js/blockly/blockly_compressed.js
deleted file mode 100644
index dd228a4d..00000000
--- a/static/js/blockly/blockly_compressed.js
+++ /dev/null
@@ -1,1166 +0,0 @@
-// Do not edit this file; automatically generated by build.py.
-"use strict";
-
-var COMPILED=!0,goog=goog||{};goog.global=this;goog.exportPath_=function(a,b,c){a=a.split(".");c=c||goog.global;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)a.length||void 0===b?c=c[d]?c[d]:c[d]={}:c[d]=b};goog.define=function(a,b){var c=b;COMPILED||goog.global.CLOSURE_DEFINES&&Object.prototype.hasOwnProperty.call(goog.global.CLOSURE_DEFINES,a)&&(c=goog.global.CLOSURE_DEFINES[a]);goog.exportPath_(a,c)};goog.DEBUG=!0;goog.LOCALE="en";goog.TRUSTED_SITE=!0;
-goog.provide=function(a){if(!COMPILED){if(goog.isProvided_(a))throw Error('Namespace "'+a+'" already declared.');delete goog.implicitNamespaces_[a];for(var b=a;(b=b.substring(0,b.lastIndexOf(".")))&&!goog.getObjectByName(b);)goog.implicitNamespaces_[b]=!0}goog.exportPath_(a)};goog.setTestOnly=function(a){if(COMPILED&&!goog.DEBUG)throw a=a||"",Error("Importing test-only code into non-debug environment"+a?": "+a:".");};
-COMPILED||(goog.isProvided_=function(a){return!goog.implicitNamespaces_[a]&&!!goog.getObjectByName(a)},goog.implicitNamespaces_={});goog.getObjectByName=function(a,b){for(var c=a.split("."),d=b||goog.global,e;e=c.shift();)if(goog.isDefAndNotNull(d[e]))d=d[e];else return null;return d};goog.globalize=function(a,b){var c=b||goog.global,d;for(d in a)c[d]=a[d]};
-goog.addDependency=function(a,b,c){if(goog.DEPENDENCIES_ENABLED){var d;a=a.replace(/\\/g,"/");for(var e=goog.dependencies_,f=0;d=b[f];f++)e.nameToPath[d]=a,a in e.pathToNames||(e.pathToNames[a]={}),e.pathToNames[a][d]=!0;for(d=0;b=c[d];d++)a in e.requires||(e.requires[a]={}),e.requires[a][b]=!0}};goog.ENABLE_DEBUG_LOADER=!0;
-goog.require=function(a){if(!COMPILED&&!goog.isProvided_(a)){if(goog.ENABLE_DEBUG_LOADER){var b=goog.getPathFromDeps_(a);if(b){goog.included_[b]=!0;goog.writeScripts_();return}}a="goog.require could not find: "+a;goog.global.console&&goog.global.console.error(a);throw Error(a);}};goog.basePath="";goog.nullFunction=function(){};goog.identityFunction=function(a,b){return a};goog.abstractMethod=function(){throw Error("unimplemented abstract method");};
-goog.addSingletonGetter=function(a){a.getInstance=function(){if(a.instance_)return a.instance_;goog.DEBUG&&(goog.instantiatedSingletons_[goog.instantiatedSingletons_.length]=a);return a.instance_=new a}};goog.instantiatedSingletons_=[];goog.DEPENDENCIES_ENABLED=!COMPILED&&goog.ENABLE_DEBUG_LOADER;
-goog.DEPENDENCIES_ENABLED&&(goog.included_={},goog.dependencies_={pathToNames:{},nameToPath:{},requires:{},visited:{},written:{}},goog.inHtmlDocument_=function(){var a=goog.global.document;return"undefined"!=typeof a&&"write"in a},goog.findBasePath_=function(){if(goog.global.CLOSURE_BASE_PATH)goog.basePath=goog.global.CLOSURE_BASE_PATH;else if(goog.inHtmlDocument_())for(var a=goog.global.document.getElementsByTagName("script"),b=a.length-1;0<=b;--b){var c=a[b].src,d=c.lastIndexOf("?"),d=-1==d?c.length:
-d;if("base.js"==c.substr(d-7,7)){goog.basePath=c.substr(0,d-7);break}}},goog.importScript_=function(a){var b=goog.global.CLOSURE_IMPORT_SCRIPT||goog.writeScriptTag_;!goog.dependencies_.written[a]&&b(a)&&(goog.dependencies_.written[a]=!0)},goog.writeScriptTag_=function(a){if(goog.inHtmlDocument_()){var b=goog.global.document;if("complete"==b.readyState){if(/\bdeps.js$/.test(a))return!1;throw Error('Cannot write "'+a+'" after document load');}b.write('
-
-
-
-
-