1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-03 16:41:50 +00:00

Compare commits

..

14 Commits

Author SHA1 Message Date
Otto Winter
1ad65516cf Bump version to v1.9.0b6 2018-11-13 19:06:32 +01:00
Otto Winter
d4c7e6c634 Merge branch 'dev' into rc 2018-11-13 19:06:26 +01:00
Otto Winter
06eeed9ee9 Bump version to v1.9.0b5 2018-11-12 23:43:03 +01:00
Otto Winter
5655b5fe10 Merge branch 'dev' into rc 2018-11-12 23:43:00 +01:00
Otto Winter
0dec7cfbf8 Lint 2018-11-10 15:39:25 +01:00
Otto Winter
30e7797577 Bump version to v1.9.0b4 2018-11-10 15:31:20 +01:00
Otto Winter
0e5cabadc1 Merge branch 'dev' into rc 2018-11-10 15:31:16 +01:00
Otto Winter
aa5f887ff3 Fix Gitlab CI 2018-11-04 00:10:44 +01:00
Otto Winter
28561ea6a4 Merge branch 'dev' into rc 2018-11-03 17:52:22 +01:00
Otto Winter
6b8125f5f2 Bump version to v1.9.0b3 2018-11-03 17:47:12 +01:00
Otto Winter
ab43390983 Merge branch 'dev' into rc 2018-11-03 17:47:06 +01:00
Otto Winter
4dce7fa103 Bump version to 1.9.0b2 2018-10-31 16:35:45 +01:00
Otto Winter
467ef9902f Merge branch 'dev' into rc 2018-10-31 16:34:36 +01:00
Otto Winter
74fefea5bb Fix gitlab 2018-10-20 19:14:27 +02:00
289 changed files with 6496 additions and 16142 deletions

47
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,47 @@
---
name: Bug report
about: Create a report to help us improve
---
<!-- Thanks for reporting a bug for this project. READ THIS FIRST:
- Please make sure to submit issues in the right GitHub repository, if unsure just post it here:
- esphomeyaml [here] - This is mostly for reporting bugs when compiling and when you get a long stack trace while compiling or if a configuration fails to validate.
- esphomelib [https://github.com/OttoWinter/esphomelib] - Report bugs there if the ESP is crashing or a feature is not working as expected.
- esphomedocs [https://github.com/OttoWinter/esphomedocs] - Report bugs there if the documentation is wrong/outdated.
- Provide as many details as possible. Paste logs, configuration sample and code into the backticks (```). Do not delete any text from this template!
-->
**Operating environment (Hass.io/Docker/pip/etc.):**
<!--
Please provide details about your environment.
-->
**ESP (ESP32/ESP8266/Board/Sonoff):**
<!--
Please provide details about which ESP you're using.
-->
**Affected component:**
<!--
Please add the link to the documentation at https://esphomelib.com/esphomeyaml/index.html of the component in question.
-->
**Description of problem:**
**Problem-relevant YAML-configuration entries:**
```yaml
```
**Traceback (if applicable):**
<!--
Please copy the traceback here if compilation is failing. If possible, also connect to the ESP and copy its logs into the backticks.
-->
```
```
**Additional information:**

View File

@@ -0,0 +1,22 @@
---
name: Feature request
about: Suggest an idea for this project
---
<!-- READ THIS FIRST:
- This is for feature requests only, if you want to have a certain new sensor/module supported, please use the "new integration" template.
- Please be as descriptive as possible, especially use-cases that can otherwise not be solved boost the problem's priority.
-->
**Is your feature request related to a problem? Please describe.**
<!--
A clear and concise description of what the problem is.
-->
Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A description of what you want to happen.
**Additional context**
Add any other context about the feature request here.

View File

@@ -0,0 +1,20 @@
---
name: New integration
about: Suggest a new integration for esphomelib
---
<!-- READ THIS FIRST:
- This is for new integrations (such as new sensors/modules) only, for new features within the environment please use the "feature request" template.
- Do not delete anything from this template and fill out the form as precisely as possible.
-->
**What new integration would you wish to have?**
<!-- A name/description of the new integration/board. -->
**If possible, provide a link to an existing library for the integration:**
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Additional context**

View File

@@ -3,12 +3,18 @@
**Related issue (if applicable):** fixes <link to issue>
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here>
**Pull request in [esphome-core](https://github.com/esphome/esphome-core) with C++ framework changes (if applicable):** esphome/esphome-core#<esphome-core PR number goes here>
**Pull request in [esphomedocs](https://github.com/OttoWinter/esphomedocs) with documentation (if applicable):** OttoWinter/esphomedocs#<esphomedocs PR number goes here>
**Pull request in [esphomelib](https://github.com/OttoWinter/esphomelib) with C++ framework changes (if applicable):** OttoWinter/esphomelib#<esphomelib PR number goes here>
## Example entry for YAML configuration (if applicable):
```yaml
```
## Checklist:
- [ ] The code change is tested and works locally.
- [ ] Tests have been added to verify that the new code works (under `tests/` folder).
- [ ] Check this box if you have read, understand, comply, and agree with the [Code of Conduct](https://github.com/OttoWinter/esphomeyaml/blob/master/CODE_OF_CONDUCT.md).
If user exposed functionality or configuration variables are added/changed:
- [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).

1
.gitignore vendored
View File

@@ -105,4 +105,3 @@ venv.bak/
config/
tests/build/
tests/.esphome/

View File

@@ -2,126 +2,299 @@
# Based on https://gitlab.com/hassio-addons/addon-node-red/blob/master/.gitlab-ci.yml
variables:
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375/
stages:
- lint
- test
- build
- deploy
.lint: &lint
image: esphome/esphome-base-amd64
stage: lint
before_script:
- pip install -e .
- pip install flake8==3.6.0 pylint==1.9.4 pillow
tags:
- docker
- python2.7
- esphomeyaml-lint
.test: &test
image: esphome/esphome-base-amd64
stage: test
before_script:
- pip install -e .
tags:
- docker
- python2.7
- esphomeyaml-test
variables:
TZ: UTC
cache:
paths:
- tests/build
.docker-base: &docker-base
image: esphome/esphome-base-builder
.docker-builder: &docker-builder
before_script:
- docker info
- docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
script:
- docker run --rm --privileged hassioaddons/qemu-user-static:latest
- TAG="${CI_COMMIT_TAG#v}"
- TAG="${TAG:-${CI_COMMIT_SHA:0:7}}"
- echo "Tag ${TAG}"
- |
if [[ "${IS_HASSIO}" == "YES" ]]; then
BUILD_FROM=esphome/esphome-hassio-base-${BUILD_ARCH}:1.2.1
BUILD_TO=esphome/esphome-hassio-${BUILD_ARCH}
DOCKERFILE=docker/Dockerfile.hassio
else
BUILD_FROM=esphome/esphome-base-${BUILD_ARCH}:1.2.1
if [[ "${BUILD_ARCH}" == "amd64" ]]; then
BUILD_TO=esphome/esphome
else
BUILD_TO=esphome/esphome-${BUILD_ARCH}
fi
DOCKERFILE=docker/Dockerfile
fi
- |
docker build \
--build-arg "BUILD_FROM=${BUILD_FROM}" \
--build-arg "BUILD_VERSION=${TAG}" \
--tag "${BUILD_TO}:${TAG}" \
--file "${DOCKERFILE}" \
.
- |
if [[ "${RELEASE}" = "YES" ]]; then
echo "Pushing to ${BUILD_TO}:${TAG}"
docker push "${BUILD_TO}:${TAG}"
fi
- |
if [[ "${LATEST}" = "YES" ]]; then
echo "Pushing to :latest"
docker tag ${BUILD_TO}:${TAG} ${BUILD_TO}:latest
docker push ${BUILD_TO}:latest
fi
- |
if [[ "${BETA}" = "YES" ]]; then
echo "Pushing to :beta"
docker tag \
${BUILD_TO}:${TAG} \
${BUILD_TO}:beta
docker push ${BUILD_TO}:beta
fi
- |
if [[ "${DEV}" = "YES" ]]; then
echo "Pushing to :dev"
docker tag \
${BUILD_TO}:${TAG} \
${BUILD_TO}:dev
docker push ${BUILD_TO}:dev
fi
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
services:
- docker:dind
tags:
- docker
stage: deploy
- hassio-builder
flake8:
<<: *lint
script:
- flake8 esphome
- flake8 esphomeyaml
pylint:
<<: *lint
script:
- pylint esphome
- pylint esphomeyaml
test1:
<<: *test
script:
- esphome tests/test1.yaml compile
- esphomeyaml tests/test1.yaml compile
test2:
<<: *test
script:
- esphome tests/test2.yaml compile
- esphomeyaml tests/test2.yaml compile
test3:
<<: *test
.build-hassio: &build-hassio
<<: *docker-builder
stage: build
script:
- esphome tests/test3.yaml compile
- docker run --rm --privileged hassioaddons/qemu-user-static:latest
- BUILD_FROM=homeassistant/${ADDON_ARCH}-base-ubuntu:latest
- ADDON_VERSION="${CI_COMMIT_TAG#v}"
- ADDON_VERSION="${ADDON_VERSION:-${CI_COMMIT_SHA:0:7}}"
- ESPHOMELIB_VERSION="${ESPHOMELIB_VERSION:-dev}"
- echo "Build from ${BUILD_FROM}"
- echo "Add-on version ${ADDON_VERSION}"
- echo "Esphomelib version ${ESPHOMELIB_VERSION}"
- echo "Tag ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:dev"
- echo "Tag ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}"
- |
docker build \
--build-arg "BUILD_FROM=${BUILD_FROM}" \
--build-arg "ADDON_ARCH=${ADDON_ARCH}" \
--build-arg "ADDON_VERSION=${ADDON_VERSION}" \
--build-arg "ESPHOMELIB_VERSION=${ESPHOMELIB_VERSION}" \
--tag "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:dev" \
--tag "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
--file "docker/Dockerfile.hassio" \
.
- |
if [ "${DO_PUSH:-true}" = true ]; then
echo "Pushing to CI registry"
docker push ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}
docker push ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:dev
fi
# Generic deploy template
.deploy-release: &deploy-release
<<: *docker-builder
stage: deploy
script:
- version="${CI_COMMIT_TAG#v}"
- echo "Publishing release version ${version}"
- docker pull "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}"
- docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
- echo "Tag ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- docker push "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- echo "Tag ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- docker push "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- echo "Tag ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- docker push "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- echo "Tag ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- echo "Tag ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:latest"
- echo "Tag ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:rc"
only:
- /^v\d+\.\d+\.\d+$/
except:
- /^(?!master).+@/
.deploy-beta: &deploy-beta
<<: *docker-builder
stage: deploy
script:
- version="${CI_COMMIT_TAG#v}"
- echo "Publishing beta version ${version}"
- docker pull "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}"
- docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
- echo "Tag ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- docker push "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- echo "Tag ${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- docker push "${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- echo "Tag ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:${version}"
- echo "Tag ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- |
docker tag \
"${CI_REGISTRY}/esphomeyaml-hassio-${ADDON_ARCH}:${CI_COMMIT_SHA}" \
"ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:rc"
- docker push "ottowinter/esphomeyaml-hassio-${ADDON_ARCH}:rc"
only:
- /^v\d+\.\d+\.\d+b\d+$/
except:
- /^(?!rc).+@/
# Build jobs
build:normal:
<<: *docker-builder
stage: build
script:
- docker build -t "${CI_REGISTRY}/esphomeyaml:dev" .
.build-hassio-edge: &build-hassio-edge
<<: *build-hassio
except:
- /^v\d+\.\d+\.\d+$/
- /^v\d+\.\d+\.\d+b\d+$/
.build-hassio-release: &build-hassio-release
<<: *build-hassio
only:
- /^v\d+\.\d+\.\d+$/
- /^v\d+\.\d+\.\d+b\d+$/
build:hassio-armhf-edge:
<<: *build-hassio-edge
variables:
ADDON_ARCH: armhf
DO_PUSH: "false"
build:hassio-armhf:
<<: *build-hassio-release
variables:
ADDON_ARCH: armhf
ESPHOMELIB_VERSION: "${CI_COMMIT_TAG}"
#build:hassio-aarch64-edge:
# <<: *build-hassio-edge
# variables:
# ADDON_ARCH: aarch64
# DO_PUSH: "false"
#build:hassio-aarch64:
# <<: *build-hassio-release
# variables:
# ADDON_ARCH: aarch64
# ESPHOMELIB_VERSION: "${CI_COMMIT_TAG}"
build:hassio-i386-edge:
<<: *build-hassio-edge
variables:
ADDON_ARCH: i386
DO_PUSH: "false"
build:hassio-i386:
<<: *build-hassio-release
variables:
ADDON_ARCH: i386
ESPHOMELIB_VERSION: "${CI_COMMIT_TAG}"
build:hassio-amd64-edge:
<<: *build-hassio-edge
variables:
ADDON_ARCH: amd64
DO_PUSH: "false"
build:hassio-amd64:
<<: *build-hassio-release
variables:
ADDON_ARCH: amd64
ESPHOMELIB_VERSION: "${CI_COMMIT_TAG}"
# Deploy jobs
deploy-release:armhf:
<<: *deploy-release
variables:
ADDON_ARCH: armhf
deploy-beta:armhf:
<<: *deploy-beta
variables:
ADDON_ARCH: armhf
#deploy-release:aarch64:
# <<: *deploy-release
# variables:
# ADDON_ARCH: aarch64
#
#deploy-beta:aarch64:
# <<: *deploy-beta
# variables:
# ADDON_ARCH: aarch64
deploy-release:i386:
<<: *deploy-release
variables:
ADDON_ARCH: i386
deploy-beta:i386:
<<: *deploy-beta
variables:
ADDON_ARCH: i386
deploy-release:amd64:
<<: *deploy-release
variables:
ADDON_ARCH: amd64
deploy-beta:amd64:
<<: *deploy-beta
variables:
ADDON_ARCH: amd64
.deploy-pypi: &deploy-pypi
stage: deploy
image: python:2.7
before_script:
- pip install -e .
- pip install twine
@@ -129,7 +302,8 @@ test3:
- python setup.py sdist
- twine upload dist/*
tags:
- docker
- python2.7
- esphomeyaml-test
deploy-release:pypi:
<<: *deploy-pypi
@@ -144,204 +318,3 @@ deploy-beta:pypi:
- /^v\d+\.\d+\.\d+b\d+$/
except:
- /^(?!rc).+@/
.latest: &latest
<<: *docker-base
only:
- /^v([0-9\.]+)$/
except:
- branches
.latest-vars: &latest-vars
RELEASE: YES
LATEST: YES
# Also push to beta tag
BETA: YES
.beta: &beta
<<: *docker-base
only:
- /^v([0-9\.]+b\d+)$/
except:
- branches
.beta-vars: &beta-vars
RELEASE: YES
BETA: YES
.dev: &dev
<<: *docker-base
only:
- dev
.dev-vars: &dev-vars
DEV: YES
aarch64-beta-docker:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: aarch64
IS_HASSIO: "NO"
RELEASE: "YES"
aarch64-beta-hassio:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: aarch64
IS_HASSIO: "YES"
RELEASE: "YES"
aarch64-dev-docker:
<<: *dev
variables:
BUILD_ARCH: aarch64
DEV: "YES"
IS_HASSIO: "NO"
aarch64-dev-hassio:
<<: *dev
variables:
BUILD_ARCH: aarch64
DEV: "YES"
IS_HASSIO: "YES"
aarch64-latest-docker:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: aarch64
IS_HASSIO: "NO"
LATEST: "YES"
RELEASE: "YES"
aarch64-latest-hassio:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: aarch64
IS_HASSIO: "YES"
LATEST: "YES"
RELEASE: "YES"
amd64-beta-docker:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: amd64
IS_HASSIO: "NO"
RELEASE: "YES"
amd64-beta-hassio:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: amd64
IS_HASSIO: "YES"
RELEASE: "YES"
amd64-dev-docker:
<<: *dev
variables:
BUILD_ARCH: amd64
DEV: "YES"
IS_HASSIO: "NO"
amd64-dev-hassio:
<<: *dev
variables:
BUILD_ARCH: amd64
DEV: "YES"
IS_HASSIO: "YES"
amd64-latest-docker:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: amd64
IS_HASSIO: "NO"
LATEST: "YES"
RELEASE: "YES"
amd64-latest-hassio:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: amd64
IS_HASSIO: "YES"
LATEST: "YES"
RELEASE: "YES"
armhf-beta-docker:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: armhf
IS_HASSIO: "NO"
RELEASE: "YES"
armhf-beta-hassio:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: armhf
IS_HASSIO: "YES"
RELEASE: "YES"
armhf-dev-docker:
<<: *dev
variables:
BUILD_ARCH: armhf
DEV: "YES"
IS_HASSIO: "NO"
armhf-dev-hassio:
<<: *dev
variables:
BUILD_ARCH: armhf
DEV: "YES"
IS_HASSIO: "YES"
armhf-latest-docker:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: armhf
IS_HASSIO: "NO"
LATEST: "YES"
RELEASE: "YES"
armhf-latest-hassio:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: armhf
IS_HASSIO: "YES"
LATEST: "YES"
RELEASE: "YES"
i386-beta-docker:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: i386
IS_HASSIO: "NO"
RELEASE: "YES"
i386-beta-hassio:
<<: *beta
variables:
BETA: "YES"
BUILD_ARCH: i386
IS_HASSIO: "YES"
RELEASE: "YES"
i386-dev-docker:
<<: *dev
variables:
BUILD_ARCH: i386
DEV: "YES"
IS_HASSIO: "NO"
i386-dev-hassio:
<<: *dev
variables:
BUILD_ARCH: i386
DEV: "YES"
IS_HASSIO: "YES"
i386-latest-docker:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: i386
IS_HASSIO: "NO"
LATEST: "YES"
RELEASE: "YES"
i386-latest-hassio:
<<: *latest
variables:
BETA: "YES"
BUILD_ARCH: i386
IS_HASSIO: "YES"
LATEST: "YES"
RELEASE: "YES"

View File

@@ -1,31 +1,20 @@
sudo: false
language: python
matrix:
fast_finish: true
python:
- "2.7"
jobs:
include:
- python: "2.7"
env: TARGET=Lint2.7
install: pip install -e . && pip install flake8==3.6.0 pylint==1.9.4 pillow
- name: "Lint"
install:
- pip install -r requirements.txt
- pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow
script:
- flake8 esphome
- pylint esphome
- python: "3.5.3"
env: TARGET=Lint3.5
install: pip install -U https://github.com/platformio/platformio-core/archive/develop.zip && pip install -e . && pip install flake8==3.6.0 pylint==2.2.2 pillow
- flake8 esphomeyaml
- pylint esphomeyaml
- name: "Test"
install:
- pip install -e .
- pip install tzlocal pillow
script:
- flake8 esphome
- pylint esphome
- python: "2.7"
env: TARGET=Test2.7
install: pip install -e . && pip install flake8==3.6.0 pylint==1.9.4 pillow
script:
- esphome tests/test1.yaml compile
- esphome tests/test2.yaml compile
- esphome tests/test3.yaml compile
#- python: "3.5.3"
# env: TARGET=Test3.5
# install: pip install -U https://github.com/platformio/platformio-core/archive/develop.zip && pip install -e . && pip install flake8==3.6.0 pylint==2.2.2 pillow
# script:
# - esphome tests/test1.yaml compile
# - esphome tests/test2.yaml compile
- esphomeyaml tests/test1.yaml compile
- esphomeyaml tests/test2.yaml compile

View File

@@ -1,16 +1,16 @@
# Contributing to ESPHome
# Contributing to esphomeyaml
This python project is responsible for reading in YAML configuration files,
esphomeyaml is a part of esphomelib and is responsible for reading in YAML configuration files,
converting them to C++ code. This code is then converted to a platformio project and compiled
with [esphome-core](https://github.com/esphome/esphome-core), the C++ framework behind the project.
with [esphomelib](https://github.com/OttoWinter/esphomelib), the C++ framework behind the project.
For a detailed guide, please see https://esphome.io/guides/contributing.html#contributing-to-esphomeyaml
For a detailed guide, please see https://esphomelib.com/esphomeyaml/guides/contributing.html#contributing-to-esphomeyaml
Things to note when contributing:
- Please test your changes :)
- If a new feature is added or an existing user-facing feature is changed, you should also
update the [docs](https://github.com/esphome/esphome-docs). See [contributing to esphome-docs](https://esphome.io/guides/contributing.html#contributing-to-esphomedocs)
update the [docs](https://github.com/OttoWinter/esphomedocs). See [contributing to esphomedocs](https://esphomelib.com/esphomeyaml/guides/contributing.html#contributing-to-esphomedocs)
for more information.
- Please also update the tests in the `tests/` folder. You can do so by just adding a line in one of the YAML files
which checks if your new feature compiles correctly.

29
Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
ARG BUILD_FROM=python:2.7
FROM ${BUILD_FROM}
MAINTAINER Otto Winter <contact@otto-winter.com>
RUN apt-get update && apt-get install -y \
python-pil \
git \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* && \
pip install --no-cache-dir --no-binary :all: platformio && \
platformio settings set enable_telemetry No && \
platformio settings set check_libraries_interval 1000000 && \
platformio settings set check_platformio_interval 1000000 && \
platformio settings set check_platforms_interval 1000000
ENV ESPHOMEYAML_OTA_HOST_PORT=6123
EXPOSE 6123
VOLUME /config
WORKDIR /usr/src/app
COPY docker/platformio.ini /pio/platformio.ini
RUN platformio run -d /pio; rm -rf /pio
COPY . .
RUN pip install --no-cache-dir --no-binary :all: -e . && \
pip install --no-cache-dir --no-binary :all: tzlocal
WORKDIR /config
ENTRYPOINT ["esphomeyaml"]
CMD ["/config", "dashboard"]

View File

@@ -1,17 +1,4 @@
include README.md
include esphome/dashboard/templates/index.html
include esphome/dashboard/templates/login.html
include esphome/dashboard/static/ace.js
include esphome/dashboard/static/esphome.css
include esphome/dashboard/static/esphome.js
include esphome/dashboard/static/favicon.ico
include esphome/dashboard/static/jquery.min.js
include esphome/dashboard/static/jquery.validate.min.js
include esphome/dashboard/static/jquery-ui.min.js
include esphome/dashboard/static/materialize.min.css
include esphome/dashboard/static/materialize.min.js
include esphome/dashboard/static/materialize-stepper.min.css
include esphome/dashboard/static/materialize-stepper.min.js
include esphome/dashboard/static/mode-yaml.js
include esphome/dashboard/static/theme-dreamweaver.js
include esphome/dashboard/static/ext-searchbox.js
include esphomeyaml/dashboard/templates/index.html
include esphomeyaml/dashboard/static/materialize-stepper.min.css
include esphomeyaml/dashboard/static/materialize-stepper.min.js

View File

@@ -1,9 +1,38 @@
# ESPHome [![Build Status](https://travis-ci.org/esphome/esphome.svg?branch=master)](https://travis-ci.org/esphome/esphome) [![Discord Chat](https://img.shields.io/discord/429907082951524364.svg)](https://discord.gg/KhAMKrd) [![GitHub release](https://img.shields.io/github/release/esphome/esphome.svg)](https://GitHub.com/esphome/esphome/releases/)
# esphomeyaml for [esphomelib](https://github.com/OttoWinter/esphomelib)
[![ESPHome Logo](https://esphome.io/_images/logo-text.png)](https://esphome.io/)
### Getting Started Guide: https://esphomelib.com/esphomeyaml/guides/getting_started_command_line.html
**Documentation:** https://esphome.io/
### Available Components: https://esphomelib.com/esphomeyaml/index.html
For issues, please go to [the issue tracker](https://github.com/esphome/issues/issues).
esphomeyaml is the solution for your ESP8266/ESP32 projects with Home Assistant. It allows you to create **custom firmwares** for your microcontrollers with no programming experience required. All you need to know is the YAML configuration format which is also used by [Home Assistant](https://www.home-assistant.io).
For feature requests, please see [feature requests](https://github.com/esphome/feature-requests/issues).
esphomeyaml will:
* Read your configuration file and warn you about potential errors (like using the invalid pins.)
* Create a custom C++ sketch file for you using esphomeyaml's powerful C++ generation engine.
* Compile the sketch file for you using [platformio](http://platformio.org/).
* Upload the binary to your ESP via Over the Air updates.
* Automatically start remote logs via MQTT.
And all of that with a single command 🎉:
```bash
esphomeyaml configuration.yaml run
```
## Features
* **No programming experience required:** just edit YAML configuration
files like you're used to with Home Assistant.
* **Flexible:** Use [esphomelib](https://github.com/OttoWinter/esphomelib)'s powerful core to create custom sensors/outputs.
* **Fast and efficient:** Written in C++ and keeps memory consumption to a minimum.
* **Made for [Home Assistant](https://www.home-assistant.io):** Almost all [Home Assistant](https://www.home-assistant.io) features are supported out of the box. Including RGB lights and many more.
* **Easy reproducible configuration:** No need to go through a long setup process for every single node. Just copy a configuration file and run a single command.
* **Smart Over The Air Updates:** esphomeyaml has OTA updates deeply integrated into the system. It even automatically enters a recovery mode if a boot loop is detected.
* **Powerful logging engine:** View colorful logs and debug issues remotely.
* **Open Source**
* For me: Makes documenting esphomelib's features a lot easier.
## Special Thanks
Special Thanks to the Home Assistant project. Lots of the code base of esphomeyaml is based off of Home Assistant, for example the loading and config validation code.

View File

@@ -1,10 +0,0 @@
ARG BUILD_FROM=esphome/esphome-base-amd64:1.2.1
FROM ${BUILD_FROM}
COPY . .
RUN \
pip2 install --no-cache-dir --no-binary :all: -e .
WORKDIR /config
ENTRYPOINT ["esphome"]
CMD ["/config", "dashboard"]

30
docker/Dockerfile.builder Normal file
View File

@@ -0,0 +1,30 @@
FROM multiarch/ubuntu-core:amd64-xenial
# setup locals
RUN apt-get update && apt-get install -y \
jq \
git \
python3-setuptools \
&& rm -rf /var/lib/apt/lists/* \
ENV LANG C.UTF-8
# Install docker
# https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
RUN apt-get update && apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
software-properties-common \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \
&& add-apt-repository "deb https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
&& apt-get update && apt-get install -y docker-ce \
&& rm -rf /var/lib/apt/lists/*
# setup arm binary support
RUN apt-get update && apt-get install -y \
qemu-user-static \
binfmt-support \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /data

View File

@@ -1,20 +1,42 @@
ARG BUILD_FROM=esphome/esphome-hassio-base-amd64:1.2.1
# Dockerfile for HassIO add-on
ARG BUILD_FROM=homeassistant/amd64-base-ubuntu:latest
FROM ${BUILD_FROM}
# Copy root filesystem
COPY docker/rootfs/ /
COPY setup.py setup.cfg MANIFEST.in /opt/esphome/
COPY esphome /opt/esphome/esphome
RUN apt-get update && apt-get install -y --no-install-recommends \
python \
python-pip \
python-setuptools \
python-pil \
git \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* && \
pip install --no-cache-dir --no-binary :all: platformio && \
platformio settings set enable_telemetry No && \
platformio settings set check_libraries_interval 1000000 && \
platformio settings set check_platformio_interval 1000000 && \
platformio settings set check_platforms_interval 1000000
RUN \
pip2 install --no-cache-dir --no-binary :all: -e /opt/esphome
COPY docker/platformio.ini /pio/platformio.ini
RUN platformio run -d /pio; rm -rf /pio
# Build arguments
ARG BUILD_VERSION=dev
ARG ESPHOMELIB_VERSION="dev"
RUN platformio lib -g install "https://github.com/OttoWinter/esphomelib.git#${ESPHOMELIB_VERSION}"
COPY . .
RUN pip install --no-cache-dir --no-binary :all: -e . && \
pip install --no-cache-dir --no-binary :all: tzlocal
CMD ["esphomeyaml", "/config/esphomeyaml", "dashboard"]
# Build arugments
ARG ADDON_ARCH
ARG ADDON_VERSION
# Labels
LABEL \
io.hass.name="ESPHome" \
io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
io.hass.name="esphomeyaml" \
io.hass.description="esphomeyaml HassIO add-on for intelligently managing all your ESP8266/ESP32 devices." \
io.hass.arch="${ADDON_ARCH}" \
io.hass.type="addon" \
io.hass.version=${BUILD_VERSION}
io.hass.version="${ADDON_VERSION}" \
io.hass.url="https://esphomelib.com/esphomeyaml/index.html" \
maintainer="Otto Winter <contact@otto-winter.com>"

View File

@@ -3,4 +3,4 @@ FROM python:2.7
COPY requirements.txt /requirements.txt
RUN pip install -r /requirements.txt && \
pip install flake8==3.6.0 pylint==1.9.4 pillow
pip install flake8==3.5.0 pylint==1.9.3 tzlocal pillow

View File

@@ -8,14 +8,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
git \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/*rm -rf /var/lib/apt/lists/* /tmp/* && \
pip install --no-cache-dir --no-binary :all: platformio && \
platformio settings set enable_telemetry No && \
platformio settings set check_libraries_interval 1000000 && \
platformio settings set check_platformio_interval 1000000 && \
platformio settings set check_platforms_interval 1000000
platformio settings set enable_telemetry No
COPY docker/platformio.ini /pio/platformio.ini
RUN platformio run -d /pio; rm -rf /pio
COPY requirements.txt /requirements.txt
RUN pip install --no-cache-dir -r /requirements.txt
RUN pip install --no-cache-dir -r /requirements.txt && \
pip install --no-cache-dir tzlocal pillow

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
# the Docker repository tag being built.
declare CACHE_TAG
echo "CACHE_TAG: ${CACHE_TAG}"
# the name and tag of the Docker repository being built. (This variable is a combination of DOCKER_REPO:CACHE_TAG.)
declare IMAGE_NAME
echo "IMAGE_NAME: ${IMAGE_NAME}"
# the architecture to build
declare BUILD_ARCH
echo "BUILD_ARCH: ${BUILD_ARCH}"
# whether this is a hassio build
declare IS_HASSIO
echo "IS_HASSIO: ${IS_HASSIO}"
echo "PWD: $PWD"
if [[ ${IS_HASSIO} = "YES" ]]; then
docker build \
--build-arg "BUILD_FROM=esphome/esphome-hassio-base-${BUILD_ARCH}:1.2.1" \
--build-arg "BUILD_VERSION=${CACHE_TAG}" \
-t "${IMAGE_NAME}" -f ../docker/Dockerfile.hassio ..
else
docker build \
--build-arg "BUILD_FROM=esphome/esphome-base-${BUILD_ARCH}:1.2.1" \
-t "${IMAGE_NAME}" -f ../docker/Dockerfile ..
fi

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
# the architecture to build
declare BUILD_ARCH
echo "BUILD_ARCH: ${BUILD_ARCH}"
if [[ ${BUILD_ARCH} = "amd64" ]]; then
echo "No qemu required..."
exit 0
fi
if [[ ${BUILD_ARCH} = "i386" ]]; then
echo "No qemu required..."
exit 0
fi
echo "Installing qemu..."
docker run --rm --privileged multiarch/qemu-user-static:register --reset

View File

@@ -2,11 +2,11 @@
; platforms
[env:espressif8266]
platform = espressif8266@1.8.0
platform = espressif8266
board = nodemcuv2
framework = arduino
[env:espressif32]
platform = espressif32@1.5.0
platform = espressif32
board = nodemcu-32s
framework = arduino

View File

@@ -1,35 +0,0 @@
#!/usr/bin/with-contenv bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# This files check if all user configuration requirements are met
# ==============================================================================
# shellcheck disable=SC1091
source /usr/lib/hassio-addons/base.sh
# Check SSL requirements, if enabled
if hass.config.true 'ssl'; then
if ! hass.config.has_value 'certfile'; then
hass.die 'SSL is enabled, but no certfile was specified.'
fi
if ! hass.config.has_value 'keyfile'; then
hass.die 'SSL is enabled, but no keyfile was specified'
fi
if ! hass.file_exists "/ssl/$(hass.config.get 'certfile')"; then
if ! hass.file_exists "/ssl/$(hass.config.get 'keyfile')"; then
# Both files are missing, let's print a friendlier error message
text="You enabled encrypted connections using the \"ssl\": true option.
However, the SSL files \"$(hass.config.get 'certfile')\" and \"$(hass.config.get 'keyfile')\"
were not found. If you're using Hass.io on your local network and don't want
to encrypt connections to the ESPHome dashboard, you can manually disable
SSL by setting \"ssl\" to false."
hass.die "${text}"
fi
hass.die 'The configured certfile is not found'
fi
if ! hass.file_exists "/ssl/$(hass.config.get 'keyfile')"; then
hass.die 'The configured keyfile is not found'
fi
fi

View File

@@ -1,28 +0,0 @@
#!/usr/bin/with-contenv bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Configures NGINX for use with ESPHome
# ==============================================================================
# shellcheck disable=SC1091
source /usr/lib/hassio-addons/base.sh
declare certfile
declare keyfile
declare port
mkdir -p /var/log/nginx
# Enable SSL
if hass.config.true 'ssl'; then
rm /etc/nginx/nginx.conf
mv /etc/nginx/nginx-ssl.conf /etc/nginx/nginx.conf
certfile=$(hass.config.get 'certfile')
keyfile=$(hass.config.get 'keyfile')
sed -i "s/%%certfile%%/${certfile}/g" /etc/nginx/nginx.conf
sed -i "s/%%keyfile%%/${keyfile}/g" /etc/nginx/nginx.conf
fi
port=$(hass.config.get 'port')
sed -i "s/%%port%%/${port}/g" /etc/nginx/nginx.conf

View File

@@ -1,14 +0,0 @@
#!/usr/bin/with-contenv bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# This files installs the user ESPHome version if specified
# ==============================================================================
# shellcheck disable=SC1091
source /usr/lib/hassio-addons/base.sh
declare esphome_version
if hass.config.has_value 'esphome_version'; then
esphome_version=$(hass.config.get 'esphome_version')
pip2 install --no-cache-dir --no-binary :all: "https://github.com/esphome/esphome/archive/${esphome_version}.zip"
fi

View File

@@ -1,13 +0,0 @@
#!/usr/bin/with-contenv bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# This files migrates the esphome config directory from the old path
# ==============================================================================
# shellcheck disable=SC1091
source /usr/lib/hassio-addons/base.sh
if [[ ! -d /config/esphome && -d /config/esphomeyaml ]]; then
echo "Moving config directory from /config/esphomeyaml to /config/esphome"
mv /config/esphomeyaml /config/esphome
mv /config/esphome/.esphomeyaml /config/esphome/.esphome
fi

View File

@@ -1,62 +0,0 @@
worker_processes 1;
pid /var/run/nginx.pid;
error_log stderr;
events {
worker_connections 1024;
}
http {
access_log stdout;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream esphome {
ip_hash;
server unix:/var/run/esphome.sock;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name hassio.local;
listen %%port%% default_server ssl;
root /dev/null;
ssl_certificate /ssl/%%certfile%%;
ssl_certificate_key /ssl/%%keyfile%%;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
# Redirect http requests to https on the same port.
# https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
error_page 497 https://$http_host$request_uri;
location / {
proxy_redirect off;
proxy_pass http://esphome;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Authorization "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
}
}
}

View File

@@ -1,46 +0,0 @@
worker_processes 1;
pid /var/run/nginx.pid;
error_log stderr;
events {
worker_connections 1024;
}
http {
access_log stdout;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream esphome {
ip_hash;
server unix:/var/run/esphome.sock;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name hassio.local;
listen %%port%% default_server;
root /dev/null;
location / {
proxy_redirect off;
proxy_pass http://esphome;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Authorization "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
}
}
}

View File

@@ -1,9 +0,0 @@
#!/usr/bin/execlineb -S0
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when ESPHome fails
# ==============================================================================
if -n { s6-test $# -ne 0 }
if -n { s6-test ${1} -eq 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -1,14 +0,0 @@
#!/usr/bin/with-contenv bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Runs the ESPHome dashboard
# ==============================================================================
# shellcheck disable=SC1091
source /usr/lib/hassio-addons/base.sh
if hass.config.true 'leave_front_door_open'; then
export DISABLE_HA_AUTHENTICATION=true
fi
hass.log.info "Starting ESPHome dashboard..."
exec esphome /config/esphome dashboard --socket /var/run/esphome.sock --hassio

View File

@@ -1,9 +0,0 @@
#!/usr/bin/execlineb -S0
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Take down the S6 supervision tree when NGINX fails
# ==============================================================================
if -n { s6-test $# -ne 0 }
if -n { s6-test ${1} -eq 256 }
s6-svscanctl -t /var/run/s6/services

View File

@@ -1,10 +0,0 @@
#!/usr/bin/with-contenv bash
# ==============================================================================
# Community Hass.io Add-ons: ESPHome
# Runs the NGINX proxy
# ==============================================================================
# shellcheck disable=SC1091
source /usr/lib/hassio-addons/base.sh
hass.log.info "Starting NGINX..."
exec nginx -g "daemon off;"

View File

@@ -1,330 +0,0 @@
syntax = "proto3";
// The Home Assistant protocol is structured as a simple
// TCP socket with short binary messages encoded in the protocol buffers format
// First, a message in this protocol has a specific format:
// * VarInt denoting the size of the message object. (type is not part of this)
// * VarInt denoting the type of message.
// * The message object encoded as a ProtoBuf message
// The connection is established in 4 steps:
// * First, the client connects to the server and sends a "Hello Request" identifying itself
// * The server responds with a "Hello Response" and selects the protocol version
// * After receiving this message, the client attempts to authenticate itself using
// the password and a "Connect Request"
// * The server responds with a "Connect Response" and notifies of invalid password.
// If anything in this initial process fails, the connection must immediately closed
// by both sides and _no_ disconnection message is to be sent.
// Message sent at the beginning of each connection
// Can only be sent by the client and only at the beginning of the connection
message HelloRequest {
// Description of client (like User Agent)
// For example "Home Assistant"
// Not strictly necessary to send but nice for debugging
// purposes.
string client_info = 1;
}
// Confirmation of successful connection request.
// Can only be sent by the server and only at the beginning of the connection
message HelloResponse {
// The version of the API to use. The _client_ (for example Home Assistant) needs to check
// for compatibility and if necessary adopt to an older API.
// Major is for breaking changes in the base protocol - a mismatch will lead to immediate disconnect_client_
// Minor is for breaking changes in individual messages - a mismatch will lead to a warning message
uint32 api_version_major = 1;
uint32 api_version_minor = 2;
// A string identifying the server (ESP); like client info this may be empty
// and only exists for debugging/logging purposes.
// For example "ESPHome v1.10.0 on ESP8266"
string server_info = 3;
}
// Message sent at the beginning of each connection to authenticate the client
// Can only be sent by the client and only at the beginning of the connection
message ConnectRequest {
// The password to log in with
string password = 1;
}
// Confirmation of successful connection. After this the connection is available for all traffic.
// Can only be sent by the server and only at the beginning of the connection
message ConnectResponse {
bool invalid_password = 1;
}
// Request to close the connection.
// Can be sent by both the client and server
message DisconnectRequest {
// Do not close the connection before the acknowledgement arrives
}
message DisconnectResponse {
// Empty - Both parties are required to close the connection after this
// message has been received.
}
message PingRequest {
// Empty
}
message PingResponse {
// Empty
}
message DeviceInfoRequest {
// Empty
}
message DeviceInfoResponse {
bool uses_password = 1;
// The name of the node, given by "App.set_name()"
string name = 2;
// The mac address of the device. For example "AC:BC:32:89:0E:A9"
string mac_address = 3;
// A string describing the ESPHome version. For example "1.10.0"
string esphome_core_version = 4;
// A string describing the date of compilation, this is generated by the compiler
// and therefore may not be in the same format all the time.
// If the user isn't using esphome, this will also not be set.
string compilation_time = 5;
// The model of the board. For example NodeMCU
string model = 6;
bool has_deep_sleep = 7;
}
message ListEntitiesRequest {
// Empty
}
message ListEntitiesBinarySensorResponse {
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string device_class = 5;
bool is_status_binary_sensor = 6;
}
message ListEntitiesCoverResponse {
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
bool is_optimistic = 5;
}
message ListEntitiesFanResponse {
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
bool supports_oscillation = 5;
bool supports_speed = 6;
}
message ListEntitiesLightResponse {
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
bool supports_brightness = 5;
bool supports_rgb = 6;
bool supports_white_value = 7;
bool supports_color_temperature = 8;
float min_mireds = 9;
float max_mireds = 10;
repeated string effects = 11;
}
message ListEntitiesSensorResponse {
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
string unit_of_measurement = 6;
int32 accuracy_decimals = 7;
}
message ListEntitiesSwitchResponse {
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
bool optimistic = 6;
}
message ListEntitiesTextSensorResponse {
string object_id = 1;
fixed32 key = 2;
string name = 3;
string unique_id = 4;
string icon = 5;
}
message ListEntitiesDoneResponse {
// Empty
}
message SubscribeStatesRequest {
// Empty
}
message BinarySensorStateResponse {
fixed32 key = 1;
bool state = 2;
}
message CoverStateResponse {
fixed32 key = 1;
enum CoverState {
OPEN = 0;
CLOSED = 1;
}
CoverState state = 2;
}
enum FanSpeed {
LOW = 0;
MEDIUM = 1;
HIGH = 2;
}
message FanStateResponse {
fixed32 key = 1;
bool state = 2;
bool oscillating = 3;
FanSpeed speed = 4;
}
message LightStateResponse {
fixed32 key = 1;
bool state = 2;
float brightness = 3;
float red = 4;
float green = 5;
float blue = 6;
float white = 7;
float color_temperature = 8;
string effect = 9;
}
message SensorStateResponse {
fixed32 key = 1;
float state = 2;
}
message SwitchStateResponse {
fixed32 key = 1;
bool state = 2;
}
message TextSensorStateResponse {
fixed32 key = 1;
string state = 2;
}
message CoverCommandRequest {
fixed32 key = 1;
enum CoverCommand {
OPEN = 0;
CLOSE = 1;
STOP = 2;
}
bool has_state = 2;
CoverCommand command = 3;
}
message FanCommandRequest {
fixed32 key = 1;
bool has_state = 2;
bool state = 3;
bool has_speed = 4;
FanSpeed speed = 5;
bool has_oscillating = 6;
bool oscillating = 7;
}
message LightCommandRequest {
fixed32 key = 1;
bool has_state = 2;
bool state = 3;
bool has_brightness = 4;
float brightness = 5;
bool has_rgb = 6;
float red = 7;
float green = 8;
float blue = 9;
bool has_white = 10;
float white = 11;
bool has_color_temperature = 12;
float color_temperature = 13;
bool has_transition_length = 14;
uint32 transition_length = 15;
bool has_flash_length = 16;
uint32 flash_length = 17;
bool has_effect = 18;
string effect = 19;
}
message SwitchCommandRequest {
fixed32 key = 1;
bool state = 2;
}
enum LogLevel {
NONE = 0;
ERROR = 1;
WARN = 2;
INFO = 3;
DEBUG = 4;
VERBOSE = 5;
VERY_VERBOSE = 6;
}
message SubscribeLogsRequest {
LogLevel level = 1;
bool dump_config = 2;
}
message SubscribeLogsResponse {
LogLevel level = 1;
string tag = 2;
string message = 3;
bool send_failed = 4;
}
message SubscribeServiceCallsRequest {
}
message ServiceCallResponse {
string service = 1;
map<string, string> data = 2;
map<string, string> data_template = 3;
map<string, string> variables = 4;
}
// 1. Client sends SubscribeHomeAssistantStatesRequest
// 2. Server responds with zero or more SubscribeHomeAssistantStateResponse (async)
// 3. Client sends HomeAssistantStateResponse for state changes.
message SubscribeHomeAssistantStatesRequest {
}
message SubscribeHomeAssistantStateResponse {
string entity_id = 1;
}
message HomeAssistantStateResponse {
string entity_id = 1;
string state = 2;
}
message GetTimeRequest {
}
message GetTimeResponse {
fixed32 epoch_seconds = 1;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,495 +0,0 @@
from datetime import datetime
import functools
import logging
import socket
import threading
import time
# pylint: disable=unused-import
from typing import Optional # noqa
from google.protobuf import message # noqa
from esphome import const
import esphome.api.api_pb2 as pb
from esphome.const import CONF_PASSWORD, CONF_PORT
from esphome.core import EsphomeError
from esphome.helpers import resolve_ip_address, indent, color
from esphome.py_compat import text_type, IS_PY2, byte_to_bytes, char_to_byte, format_bytes
from esphome.util import safe_print
_LOGGER = logging.getLogger(__name__)
class APIConnectionError(EsphomeError):
pass
MESSAGE_TYPE_TO_PROTO = {
1: pb.HelloRequest,
2: pb.HelloResponse,
3: pb.ConnectRequest,
4: pb.ConnectResponse,
5: pb.DisconnectRequest,
6: pb.DisconnectResponse,
7: pb.PingRequest,
8: pb.PingResponse,
9: pb.DeviceInfoRequest,
10: pb.DeviceInfoResponse,
11: pb.ListEntitiesRequest,
12: pb.ListEntitiesBinarySensorResponse,
13: pb.ListEntitiesCoverResponse,
14: pb.ListEntitiesFanResponse,
15: pb.ListEntitiesLightResponse,
16: pb.ListEntitiesSensorResponse,
17: pb.ListEntitiesSwitchResponse,
18: pb.ListEntitiesTextSensorResponse,
19: pb.ListEntitiesDoneResponse,
20: pb.SubscribeStatesRequest,
21: pb.BinarySensorStateResponse,
22: pb.CoverStateResponse,
23: pb.FanStateResponse,
24: pb.LightStateResponse,
25: pb.SensorStateResponse,
26: pb.SwitchStateResponse,
27: pb.TextSensorStateResponse,
28: pb.SubscribeLogsRequest,
29: pb.SubscribeLogsResponse,
30: pb.CoverCommandRequest,
31: pb.FanCommandRequest,
32: pb.LightCommandRequest,
33: pb.SwitchCommandRequest,
34: pb.SubscribeServiceCallsRequest,
35: pb.ServiceCallResponse,
36: pb.GetTimeRequest,
37: pb.GetTimeResponse,
}
def _varuint_to_bytes(value):
if value <= 0x7F:
return byte_to_bytes(value)
ret = bytes()
while value:
temp = value & 0x7F
value >>= 7
if value:
ret += byte_to_bytes(temp | 0x80)
else:
ret += byte_to_bytes(temp)
return ret
def _bytes_to_varuint(value):
result = 0
bitpos = 0
for c in value:
val = char_to_byte(c)
result |= (val & 0x7F) << bitpos
bitpos += 7
if (val & 0x80) == 0:
return result
return None
# pylint: disable=too-many-instance-attributes,not-callable
class APIClient(threading.Thread):
def __init__(self, address, port, password):
threading.Thread.__init__(self)
self._address = address # type: str
self._port = port # type: int
self._password = password # type: Optional[str]
self._socket = None # type: Optional[socket.socket]
self._socket_open_event = threading.Event()
self._socket_write_lock = threading.Lock()
self._connected = False
self._authenticated = False
self._message_handlers = []
self._keepalive = 5
self._ping_timer = None
self._refresh_ping()
self.on_disconnect = None
self.on_connect = None
self.on_login = None
self.auto_reconnect = False
self._running_event = threading.Event()
self._stop_event = threading.Event()
@property
def stopped(self):
return self._stop_event.is_set()
def _refresh_ping(self):
if self._ping_timer is not None:
self._ping_timer.cancel()
self._ping_timer = None
def func():
self._ping_timer = None
if self._connected:
try:
self.ping()
except APIConnectionError:
self._fatal_error()
else:
self._refresh_ping()
self._ping_timer = threading.Timer(self._keepalive, func)
self._ping_timer.start()
def _cancel_ping(self):
if self._ping_timer is not None:
self._ping_timer.cancel()
self._ping_timer = None
def _close_socket(self):
self._cancel_ping()
if self._socket is not None:
self._socket.close()
self._socket = None
self._socket_open_event.clear()
self._connected = False
self._authenticated = False
self._message_handlers = []
def stop(self, force=False):
if self.stopped:
raise ValueError
if self._connected and not force:
try:
self.disconnect()
except APIConnectionError:
pass
self._close_socket()
self._stop_event.set()
if not force:
self.join()
def connect(self):
if not self._running_event.wait(0.1):
raise APIConnectionError("You need to call start() first!")
if self._connected:
raise APIConnectionError("Already connected!")
try:
ip = resolve_ip_address(self._address)
except EsphomeError as err:
_LOGGER.warning("Error resolving IP address of %s. Is it connected to WiFi?",
self._address)
_LOGGER.warning("(If this error persists, please set a static IP address: "
"https://esphome.io/components/wifi.html#manual-ips)")
raise APIConnectionError(err)
_LOGGER.info("Connecting to %s:%s (%s)", self._address, self._port, ip)
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.settimeout(10.0)
self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
try:
self._socket.connect((ip, self._port))
except socket.error as err:
self._fatal_error()
raise APIConnectionError("Error connecting to {}: {}".format(ip, err))
self._socket.settimeout(0.1)
self._socket_open_event.set()
hello = pb.HelloRequest()
hello.client_info = 'ESPHome v{}'.format(const.__version__)
try:
resp = self._send_message_await_response(hello, pb.HelloResponse)
except APIConnectionError as err:
self._fatal_error()
raise err
_LOGGER.debug("Successfully connected to %s ('%s' API=%s.%s)", self._address,
resp.server_info, resp.api_version_major, resp.api_version_minor)
self._connected = True
if self.on_connect is not None:
self.on_connect()
def _check_connected(self):
if not self._connected:
self._fatal_error()
raise APIConnectionError("Must be connected!")
def login(self):
self._check_connected()
if self._authenticated:
raise APIConnectionError("Already logged in!")
connect = pb.ConnectRequest()
if self._password is not None:
connect.password = self._password
resp = self._send_message_await_response(connect, pb.ConnectResponse)
if resp.invalid_password:
raise APIConnectionError("Invalid password!")
self._authenticated = True
if self.on_login is not None:
self.on_login()
def _fatal_error(self):
was_connected = self._connected
self._close_socket()
if was_connected and self.on_disconnect is not None:
self.on_disconnect()
def _write(self, data): # type: (bytes) -> None
if self._socket is None:
raise APIConnectionError("Socket closed")
_LOGGER.debug("Write: %s", format_bytes(data))
with self._socket_write_lock:
try:
self._socket.sendall(data)
except socket.error as err:
self._fatal_error()
raise APIConnectionError("Error while writing data: {}".format(err))
def _send_message(self, msg):
# type: (message.Message) -> None
for message_type, klass in MESSAGE_TYPE_TO_PROTO.items():
if isinstance(msg, klass):
break
else:
raise ValueError
encoded = msg.SerializeToString()
_LOGGER.debug("Sending %s:\n%s", type(msg), indent(text_type(msg)))
if IS_PY2:
req = chr(0x00)
else:
req = bytes([0])
req += _varuint_to_bytes(len(encoded))
req += _varuint_to_bytes(message_type)
req += encoded
self._write(req)
self._refresh_ping()
def _send_message_await_response_complex(self, send_msg, do_append, do_stop, timeout=1):
event = threading.Event()
responses = []
def on_message(resp):
if do_append(resp):
responses.append(resp)
if do_stop(resp):
event.set()
self._message_handlers.append(on_message)
self._send_message(send_msg)
ret = event.wait(timeout)
try:
self._message_handlers.remove(on_message)
except ValueError:
pass
if not ret:
raise APIConnectionError("Timeout while waiting for message response!")
return responses
def _send_message_await_response(self, send_msg, response_type, timeout=1):
def is_response(msg):
return isinstance(msg, response_type)
return self._send_message_await_response_complex(send_msg, is_response, is_response,
timeout)[0]
def device_info(self):
self._check_connected()
return self._send_message_await_response(pb.DeviceInfoRequest(), pb.DeviceInfoResponse)
def ping(self):
self._check_connected()
return self._send_message_await_response(pb.PingRequest(), pb.PingResponse)
def disconnect(self):
self._check_connected()
try:
self._send_message_await_response(pb.DisconnectRequest(), pb.DisconnectResponse)
except APIConnectionError:
pass
self._close_socket()
if self.on_disconnect is not None:
self.on_disconnect()
def _check_authenticated(self):
if not self._authenticated:
raise APIConnectionError("Must login first!")
def subscribe_logs(self, on_log, log_level=None, dump_config=False):
self._check_authenticated()
def on_msg(msg):
if isinstance(msg, pb.SubscribeLogsResponse):
on_log(msg)
self._message_handlers.append(on_msg)
req = pb.SubscribeLogsRequest(dump_config=dump_config)
if log_level is not None:
req.level = log_level
self._send_message(req)
def _recv(self, amount):
ret = bytes()
if amount == 0:
return ret
while len(ret) < amount:
if self.stopped:
raise APIConnectionError("Stopped!")
if not self._socket_open_event.is_set():
raise APIConnectionError("No socket!")
try:
val = self._socket.recv(amount - len(ret))
except AttributeError:
raise APIConnectionError("Socket was closed")
except socket.timeout:
continue
except socket.error as err:
raise APIConnectionError("Error while receiving data: {}".format(err))
ret += val
return ret
def _recv_varint(self):
raw = bytes()
while not raw or char_to_byte(raw[-1]) & 0x80:
raw += self._recv(1)
return _bytes_to_varuint(raw)
def _run_once(self):
if not self._socket_open_event.wait(0.1):
return
# Preamble
if char_to_byte(self._recv(1)[0]) != 0x00:
raise APIConnectionError("Invalid preamble")
length = self._recv_varint()
msg_type = self._recv_varint()
raw_msg = self._recv(length)
if msg_type not in MESSAGE_TYPE_TO_PROTO:
_LOGGER.debug("Skipping message type %s", msg_type)
return
msg = MESSAGE_TYPE_TO_PROTO[msg_type]()
msg.ParseFromString(raw_msg)
_LOGGER.debug("Got message: %s:\n%s", type(msg), indent(str(msg)))
for msg_handler in self._message_handlers[:]:
msg_handler(msg)
self._handle_internal_messages(msg)
self._refresh_ping()
def run(self):
self._running_event.set()
while not self.stopped:
try:
self._run_once()
except APIConnectionError as err:
if self.stopped:
break
if self._connected:
_LOGGER.error("Error while reading incoming messages: %s", err)
self._fatal_error()
self._running_event.clear()
def _handle_internal_messages(self, msg):
if isinstance(msg, pb.DisconnectRequest):
self._send_message(pb.DisconnectResponse())
if self._socket is not None:
self._socket.close()
self._socket = None
self._connected = False
if self.on_disconnect is not None:
self.on_disconnect()
elif isinstance(msg, pb.PingRequest):
self._send_message(pb.PingResponse())
elif isinstance(msg, pb.GetTimeRequest):
resp = pb.GetTimeResponse()
resp.epoch_seconds = int(time.time())
self._send_message(resp)
def run_logs(config, address):
conf = config['api']
port = conf[CONF_PORT]
password = conf[CONF_PASSWORD]
_LOGGER.info("Starting log output from %s using esphome API", address)
cli = APIClient(address, port, password)
stopping = False
retry_timer = []
has_connects = []
def try_connect(tries=0, is_disconnect=True):
if stopping:
return
if is_disconnect:
_LOGGER.warning(u"Disconnected from API.")
while retry_timer:
retry_timer.pop(0).cancel()
error = None
try:
cli.connect()
cli.login()
except APIConnectionError as err: # noqa
error = err
if error is None:
_LOGGER.info("Successfully connected to %s", address)
return
wait_time = min(2**tries, 300)
if not has_connects:
_LOGGER.warning(u"Initial connection failed. The ESP might not be connected "
u"to WiFi yet (%s). Re-Trying in %s seconds",
error, wait_time)
else:
_LOGGER.warning(u"Couldn't connect to API (%s). Trying to reconnect in %s seconds",
error, wait_time)
timer = threading.Timer(wait_time, functools.partial(try_connect, tries + 1, is_disconnect))
timer.start()
retry_timer.append(timer)
def on_log(msg):
time_ = datetime.now().time().strftime(u'[%H:%M:%S]')
text = msg.message
if msg.send_failed:
text = color('white', '(Message skipped because it was too big to fit in '
'TCP buffer - This is only cosmetic)')
safe_print(time_ + text)
def on_login():
try:
cli.subscribe_logs(on_log, dump_config=not has_connects)
has_connects.append(True)
except APIConnectionError:
cli.disconnect()
cli.on_disconnect = try_connect
cli.on_login = on_login
cli.start()
try:
try_connect(is_disconnect=False)
while True:
time.sleep(1)
except KeyboardInterrupt:
stopping = True
cli.stop(True)
while retry_timer:
retry_timer.pop(0).cancel()
return 0

View File

@@ -1,391 +0,0 @@
import copy
import voluptuous as vol
import esphome.config_validation as cv
from esphome.const import CONF_ABOVE, CONF_ACTION_ID, CONF_AND, CONF_AUTOMATION_ID, \
CONF_BELOW, CONF_CONDITION, CONF_CONDITION_ID, CONF_DELAY, CONF_ELSE, CONF_ID, CONF_IF, \
CONF_LAMBDA, CONF_OR, CONF_RANGE, CONF_THEN, CONF_TRIGGER_ID, CONF_WHILE, CONF_WAIT_UNTIL
from esphome.core import CORE
from esphome.cpp_generator import Pvariable, TemplateArguments, add, get_variable, \
process_lambda, templatable
from esphome.cpp_types import Action, App, Component, PollingComponent, Trigger, bool_, \
esphome_ns, float_, uint32, void
from esphome.util import ServiceRegistry
def maybe_simple_id(*validators):
validator = vol.All(*validators)
def validate(value):
if isinstance(value, dict):
return validator(value)
return validator({CONF_ID: value})
return validate
def validate_recursive_condition(value):
is_list = isinstance(value, list)
value = cv.ensure_list()(value)[:]
for i, item in enumerate(value):
path = [i] if is_list else []
item = copy.deepcopy(item)
if not isinstance(item, dict):
raise vol.Invalid(u"Condition must consist of key-value mapping! Got {}".format(item),
path)
key = next((x for x in item if x != CONF_CONDITION_ID), None)
if key is None:
raise vol.Invalid(u"Key missing from action! Got {}".format(item), path)
if key not in CONDITION_REGISTRY:
raise vol.Invalid(u"Unable to find condition with the name '{}', is the "
u"component loaded?".format(key), path + [key])
item.setdefault(CONF_CONDITION_ID, None)
key2 = next((x for x in item if x not in (CONF_CONDITION_ID, key)), None)
if key2 is not None:
raise vol.Invalid(u"Cannot have two conditions in one item. Key '{}' overrides '{}'! "
u"Did you forget to indent the block inside the condition?"
u"".format(key, key2), path)
validator = CONDITION_REGISTRY[key][0]
try:
condition = validator(item[key])
except vol.Invalid as err:
err.prepend(path)
raise err
value[i] = {
CONF_CONDITION_ID: cv.declare_variable_id(Condition)(item[CONF_CONDITION_ID]),
key: condition,
}
return value
def validate_recursive_action(value):
is_list = isinstance(value, list)
if not is_list:
value = [value]
for i, item in enumerate(value):
path = [i] if is_list else []
item = copy.deepcopy(item)
if not isinstance(item, dict):
raise vol.Invalid(u"Action must consist of key-value mapping! Got {}".format(item),
path)
key = next((x for x in item if x != CONF_ACTION_ID), None)
if key is None:
raise vol.Invalid(u"Key missing from action! Got {}".format(item), path)
if key not in ACTION_REGISTRY:
raise vol.Invalid(u"Unable to find action with the name '{}', is the component loaded?"
u"".format(key), path + [key])
item.setdefault(CONF_ACTION_ID, None)
key2 = next((x for x in item if x not in (CONF_ACTION_ID, key)), None)
if key2 is not None:
raise vol.Invalid(u"Cannot have two actions in one item. Key '{}' overrides '{}'! "
u"Did you forget to indent the block inside the action?"
u"".format(key, key2), path)
validator = ACTION_REGISTRY[key][0]
try:
action = validator(item[key])
except vol.Invalid as err:
err.prepend(path)
raise err
value[i] = {
CONF_ACTION_ID: cv.declare_variable_id(Action)(item[CONF_ACTION_ID]),
key: action,
}
return value
ACTION_REGISTRY = ServiceRegistry()
CONDITION_REGISTRY = ServiceRegistry()
# pylint: disable=invalid-name
DelayAction = esphome_ns.class_('DelayAction', Action, Component)
LambdaAction = esphome_ns.class_('LambdaAction', Action)
IfAction = esphome_ns.class_('IfAction', Action)
WhileAction = esphome_ns.class_('WhileAction', Action)
WaitUntilAction = esphome_ns.class_('WaitUntilAction', Action, Component)
UpdateComponentAction = esphome_ns.class_('UpdateComponentAction', Action)
Automation = esphome_ns.class_('Automation')
Condition = esphome_ns.class_('Condition')
AndCondition = esphome_ns.class_('AndCondition', Condition)
OrCondition = esphome_ns.class_('OrCondition', Condition)
RangeCondition = esphome_ns.class_('RangeCondition', Condition)
LambdaCondition = esphome_ns.class_('LambdaCondition', Condition)
def validate_automation(extra_schema=None, extra_validators=None, single=False):
if extra_schema is None:
extra_schema = {}
if isinstance(extra_schema, vol.Schema):
extra_schema = extra_schema.schema
schema = AUTOMATION_SCHEMA.extend(extra_schema)
def validator_(value):
if isinstance(value, list):
try:
# First try as a sequence of actions
return [schema({CONF_THEN: value})]
except vol.Invalid as err:
if err.path and err.path[0] == CONF_THEN:
err.path.pop(0)
# Next try as a sequence of automations
try:
return vol.Schema([schema])(value)
except vol.Invalid as err2:
if 'Unable to find action' in str(err):
raise err2
raise vol.MultipleInvalid([err, err2])
elif isinstance(value, dict):
if CONF_THEN in value:
return [schema(value)]
return [schema({CONF_THEN: value})]
# This should only happen with invalid configs, but let's have a nice error message.
return [schema(value)]
def validator(value):
value = validator_(value)
if extra_validators is not None:
value = vol.Schema([extra_validators])(value)
if single:
if len(value) != 1:
raise vol.Invalid("Cannot have more than 1 automation for templates")
return value[0]
return value
return validator
AUTOMATION_SCHEMA = vol.Schema({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(Trigger),
cv.GenerateID(CONF_AUTOMATION_ID): cv.declare_variable_id(Automation),
vol.Optional(CONF_IF): validate_recursive_condition,
vol.Required(CONF_THEN): validate_recursive_action,
})
AND_CONDITION_SCHEMA = validate_recursive_condition
@CONDITION_REGISTRY.register(CONF_AND, AND_CONDITION_SCHEMA)
def and_condition_to_code(config, condition_id, arg_type, template_arg):
for conditions in build_conditions(config, arg_type):
yield
rhs = AndCondition.new(template_arg, conditions)
type = AndCondition.template(template_arg)
yield Pvariable(condition_id, rhs, type=type)
OR_CONDITION_SCHEMA = validate_recursive_condition
@CONDITION_REGISTRY.register(CONF_OR, OR_CONDITION_SCHEMA)
def or_condition_to_code(config, condition_id, arg_type, template_arg):
for conditions in build_conditions(config, arg_type):
yield
rhs = OrCondition.new(template_arg, conditions)
type = OrCondition.template(template_arg)
yield Pvariable(condition_id, rhs, type=type)
RANGE_CONDITION_SCHEMA = vol.All(vol.Schema({
vol.Optional(CONF_ABOVE): cv.templatable(cv.float_),
vol.Optional(CONF_BELOW): cv.templatable(cv.float_),
}), cv.has_at_least_one_key(CONF_ABOVE, CONF_BELOW))
@CONDITION_REGISTRY.register(CONF_RANGE, RANGE_CONDITION_SCHEMA)
def range_condition_to_code(config, condition_id, arg_type, template_arg):
for conditions in build_conditions(config, arg_type):
yield
rhs = RangeCondition.new(template_arg, conditions)
type = RangeCondition.template(template_arg)
condition = Pvariable(condition_id, rhs, type=type)
if CONF_ABOVE in config:
for template_ in templatable(config[CONF_ABOVE], arg_type, float_):
yield
condition.set_min(template_)
if CONF_BELOW in config:
for template_ in templatable(config[CONF_BELOW], arg_type, float_):
yield
condition.set_max(template_)
yield condition
DELAY_ACTION_SCHEMA = cv.templatable(cv.positive_time_period_milliseconds)
@ACTION_REGISTRY.register(CONF_DELAY, DELAY_ACTION_SCHEMA)
def delay_action_to_code(config, action_id, arg_type, template_arg):
rhs = App.register_component(DelayAction.new(template_arg))
type = DelayAction.template(template_arg)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config, arg_type, uint32):
yield
add(action.set_delay(template_))
yield action
IF_ACTION_SCHEMA = vol.All({
vol.Required(CONF_CONDITION): validate_recursive_condition,
vol.Optional(CONF_THEN): validate_recursive_action,
vol.Optional(CONF_ELSE): validate_recursive_action,
}, cv.has_at_least_one_key(CONF_THEN, CONF_ELSE))
@ACTION_REGISTRY.register(CONF_IF, IF_ACTION_SCHEMA)
def if_action_to_code(config, action_id, arg_type, template_arg):
for conditions in build_conditions(config[CONF_CONDITION], arg_type):
yield None
rhs = IfAction.new(template_arg, conditions)
type = IfAction.template(template_arg)
action = Pvariable(action_id, rhs, type=type)
if CONF_THEN in config:
for actions in build_actions(config[CONF_THEN], arg_type):
yield None
add(action.add_then(actions))
if CONF_ELSE in config:
for actions in build_actions(config[CONF_ELSE], arg_type):
yield None
add(action.add_else(actions))
yield action
WHILE_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_CONDITION): validate_recursive_condition,
vol.Required(CONF_THEN): validate_recursive_action,
})
@ACTION_REGISTRY.register(CONF_WHILE, WHILE_ACTION_SCHEMA)
def while_action_to_code(config, action_id, arg_type, template_arg):
for conditions in build_conditions(config[CONF_CONDITION], arg_type):
yield None
rhs = WhileAction.new(template_arg, conditions)
type = WhileAction.template(template_arg)
action = Pvariable(action_id, rhs, type=type)
for actions in build_actions(config[CONF_THEN], arg_type):
yield None
add(action.add_then(actions))
yield action
def validate_wait_until(value):
schema = vol.Schema({
vol.Required(CONF_CONDITION): validate_recursive_condition
})
if isinstance(value, dict) and CONF_CONDITION in value:
return schema(value)
return validate_wait_until({CONF_CONDITION: value})
WAIT_UNTIL_ACTION_SCHEMA = validate_wait_until
@ACTION_REGISTRY.register(CONF_WAIT_UNTIL, WAIT_UNTIL_ACTION_SCHEMA)
def wait_until_action_to_code(config, action_id, arg_type, template_arg):
for conditions in build_conditions(config[CONF_CONDITION], arg_type):
yield None
rhs = WaitUntilAction.new(template_arg, conditions)
type = WaitUntilAction.template(template_arg)
action = Pvariable(action_id, rhs, type=type)
add(App.register_component(action))
yield action
LAMBDA_ACTION_SCHEMA = cv.lambda_
@ACTION_REGISTRY.register(CONF_LAMBDA, LAMBDA_ACTION_SCHEMA)
def lambda_action_to_code(config, action_id, arg_type, template_arg):
for lambda_ in process_lambda(config, [(arg_type, 'x')], return_type=void):
yield None
rhs = LambdaAction.new(template_arg, lambda_)
type = LambdaAction.template(template_arg)
yield Pvariable(action_id, rhs, type=type)
LAMBDA_CONDITION_SCHEMA = cv.lambda_
@CONDITION_REGISTRY.register(CONF_LAMBDA, LAMBDA_CONDITION_SCHEMA)
def lambda_condition_to_code(config, condition_id, arg_type, template_arg):
for lambda_ in process_lambda(config, [(arg_type, 'x')], return_type=bool_):
yield
rhs = LambdaCondition.new(template_arg, lambda_)
type = LambdaCondition.template(template_arg)
yield Pvariable(condition_id, rhs, type=type)
CONF_COMPONENT_UPDATE = 'component.update'
COMPONENT_UPDATE_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(PollingComponent),
})
@ACTION_REGISTRY.register(CONF_COMPONENT_UPDATE, COMPONENT_UPDATE_ACTION_SCHEMA)
def component_update_action_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = UpdateComponentAction.new(template_arg, var)
type = UpdateComponentAction.template(template_arg)
yield Pvariable(action_id, rhs, type=type)
def build_action(full_config, arg_type):
action_id = full_config[CONF_ACTION_ID]
key, config = next((k, v) for k, v in full_config.items() if k in ACTION_REGISTRY)
builder = ACTION_REGISTRY[key][1]
template_arg = TemplateArguments(arg_type)
for result in builder(config, action_id, arg_type, template_arg):
yield None
yield result
def build_actions(config, arg_type):
actions = []
for conf in config:
for action in build_action(conf, arg_type):
yield None
actions.append(action)
yield actions
def build_condition(full_config, arg_type):
action_id = full_config[CONF_CONDITION_ID]
key, config = next((k, v) for k, v in full_config.items() if k in CONDITION_REGISTRY)
builder = CONDITION_REGISTRY[key][1]
template_arg = TemplateArguments(arg_type)
for result in builder(config, action_id, arg_type, template_arg):
yield None
yield result
def build_conditions(config, arg_type):
conditions = []
for conf in config:
for condition in build_condition(conf, arg_type):
yield None
conditions.append(condition)
yield conditions
def build_automation_(trigger, arg_type, config):
rhs = App.make_automation(TemplateArguments(arg_type), trigger)
type = Automation.template(arg_type)
obj = Pvariable(config[CONF_AUTOMATION_ID], rhs, type=type)
if CONF_IF in config:
conditions = None
for conditions in build_conditions(config[CONF_IF], arg_type):
yield None
add(obj.add_conditions(conditions))
actions = None
for actions in build_actions(config[CONF_THEN], arg_type):
yield None
add(obj.add_actions(actions))
yield obj
def build_automation(trigger, arg_type, config):
CORE.add_job(build_automation_, trigger, arg_type, config)

View File

@@ -1,27 +0,0 @@
import voluptuous as vol
from esphome.components import i2c, sensor
import esphome.config_validation as cv
from esphome.const import CONF_ADDRESS, CONF_ID
from esphome.cpp_generator import Pvariable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, Component
DEPENDENCIES = ['i2c']
MULTI_CONF = True
ADS1115Component = sensor.sensor_ns.class_('ADS1115Component', Component, i2c.I2CDevice)
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(ADS1115Component),
vol.Required(CONF_ADDRESS): cv.i2c_address,
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
rhs = App.make_ads1115_component(config[CONF_ADDRESS])
var = Pvariable(config[CONF_ID], rhs)
setup_component(var, config)
BUILD_FLAGS = '-DUSE_ADS1115_SENSOR'

View File

@@ -1,33 +0,0 @@
import voluptuous as vol
from esphome.components import i2c, sensor
import esphome.config_validation as cv
from esphome.const import CONF_ADDRESS, CONF_ID, CONF_UPDATE_INTERVAL
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, PollingComponent
DEPENDENCIES = ['i2c']
MULTI_CONF = True
CONF_APDS9960_ID = 'apds9960_id'
APDS9960 = sensor.sensor_ns.class_('APDS9960', PollingComponent, i2c.I2CDevice)
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(APDS9960),
vol.Optional(CONF_ADDRESS): cv.i2c_address,
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
rhs = App.make_apds9960(config.get(CONF_UPDATE_INTERVAL))
var = Pvariable(config[CONF_ID], rhs)
if CONF_ADDRESS in config:
add(var.set_address(config[CONF_ADDRESS]))
setup_component(var, config)
BUILD_FLAGS = '-DUSE_APDS9960'

View File

@@ -1,88 +0,0 @@
import voluptuous as vol
from esphome.automation import ACTION_REGISTRY
import esphome.config_validation as cv
from esphome.const import CONF_DATA, CONF_DATA_TEMPLATE, CONF_ID, CONF_PASSWORD, CONF_PORT, \
CONF_REBOOT_TIMEOUT, CONF_SERVICE, CONF_VARIABLES
from esphome.core import CORE
from esphome.cpp_generator import Pvariable, add, get_variable, process_lambda
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import Action, App, Component, StoringController, esphome_ns
api_ns = esphome_ns.namespace('api')
APIServer = api_ns.class_('APIServer', Component, StoringController)
HomeAssistantServiceCallAction = api_ns.class_('HomeAssistantServiceCallAction', Action)
KeyValuePair = api_ns.class_('KeyValuePair')
TemplatableKeyValuePair = api_ns.class_('TemplatableKeyValuePair')
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(APIServer),
vol.Optional(CONF_PORT, default=6053): cv.port,
vol.Optional(CONF_PASSWORD, default=''): cv.string_strict,
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
rhs = App.init_api_server()
api = Pvariable(config[CONF_ID], rhs)
if config[CONF_PORT] != 6053:
add(api.set_port(config[CONF_PORT]))
if config.get(CONF_PASSWORD):
add(api.set_password(config[CONF_PASSWORD]))
if CONF_REBOOT_TIMEOUT in config:
add(api.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
setup_component(api, config)
BUILD_FLAGS = '-DUSE_API'
def lib_deps(config):
if CORE.is_esp32:
return 'AsyncTCP@1.0.1'
if CORE.is_esp8266:
return 'ESPAsyncTCP@1.1.3'
raise NotImplementedError
CONF_HOMEASSISTANT_SERVICE = 'homeassistant.service'
HOMEASSISTANT_SERVIC_ACTION_SCHEMA = vol.Schema({
cv.GenerateID(): cv.use_variable_id(APIServer),
vol.Required(CONF_SERVICE): cv.string,
vol.Optional(CONF_DATA): vol.Schema({
cv.string: cv.string,
}),
vol.Optional(CONF_DATA_TEMPLATE): vol.Schema({
cv.string: cv.string,
}),
vol.Optional(CONF_VARIABLES): vol.Schema({
cv.string: cv.lambda_,
}),
})
@ACTION_REGISTRY.register(CONF_HOMEASSISTANT_SERVICE, HOMEASSISTANT_SERVIC_ACTION_SCHEMA)
def homeassistant_service_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_home_assistant_service_call_action(template_arg)
type = HomeAssistantServiceCallAction.template(arg_type)
act = Pvariable(action_id, rhs, type=type)
add(act.set_service(config[CONF_SERVICE]))
if CONF_DATA in config:
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA].items()]
add(act.set_data(datas))
if CONF_DATA_TEMPLATE in config:
datas = [KeyValuePair(k, v) for k, v in config[CONF_DATA_TEMPLATE].items()]
add(act.set_data_template(datas))
if CONF_VARIABLES in config:
datas = []
for key, value in config[CONF_VARIABLES].items():
for value_ in process_lambda(value, []):
yield None
datas.append(TemplatableKeyValuePair(key, value_))
add(act.set_variables(datas))
yield act

View File

@@ -1,36 +0,0 @@
import voluptuous as vol
from esphome.components import binary_sensor, sensor
from esphome.components.apds9960 import APDS9960, CONF_APDS9960_ID
import esphome.config_validation as cv
from esphome.const import CONF_DIRECTION, CONF_NAME
from esphome.cpp_generator import get_variable
DEPENDENCIES = ['apds9960']
APDS9960GestureDirectionBinarySensor = sensor.sensor_ns.class_(
'APDS9960GestureDirectionBinarySensor', binary_sensor.BinarySensor)
DIRECTIONS = {
'UP': 'make_up_direction',
'DOWN': 'make_down_direction',
'LEFT': 'make_left_direction',
'RIGHT': 'make_right_direction',
}
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(APDS9960GestureDirectionBinarySensor),
vol.Required(CONF_DIRECTION): cv.one_of(*DIRECTIONS, upper=True),
cv.GenerateID(CONF_APDS9960_ID): cv.use_variable_id(APDS9960)
}))
def to_code(config):
for hub in get_variable(config[CONF_APDS9960_ID]):
yield
func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]])
rhs = func(config[CONF_NAME])
binary_sensor.register_binary_sensor(rhs, config)
def to_hass_config(data, config):
return binary_sensor.core_to_hass_config(data, config)

View File

@@ -1,39 +0,0 @@
import voluptuous as vol
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.const import CONF_BINARY_SENSORS, CONF_ID, CONF_LAMBDA, CONF_NAME
from esphome.cpp_generator import Pvariable, add, process_lambda, variable
from esphome.cpp_types import std_vector
CustomBinarySensorConstructor = binary_sensor.binary_sensor_ns.class_(
'CustomBinarySensorConstructor')
PLATFORM_SCHEMA = binary_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(CustomBinarySensorConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Required(CONF_BINARY_SENSORS):
cv.ensure_list(binary_sensor.BINARY_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(binary_sensor.BinarySensor),
})),
})
def to_code(config):
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=std_vector.template(binary_sensor.BinarySensorPtr)):
yield
rhs = CustomBinarySensorConstructor(template_)
custom = variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_BINARY_SENSORS]):
var = Pvariable(conf[CONF_ID], custom.get_binary_sensor(i))
add(var.set_name(conf[CONF_NAME]))
binary_sensor.setup_binary_sensor(var, conf)
BUILD_FLAGS = '-DUSE_CUSTOM_BINARY_SENSOR'
def to_hass_config(data, config):
return [binary_sensor.core_to_hass_config(data, sens) for sens in config[CONF_BINARY_SENSORS]]

View File

@@ -1,30 +0,0 @@
import voluptuous as vol
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.const import CONF_ENTITY_ID, CONF_ID, CONF_NAME
from esphome.cpp_generator import Pvariable
from esphome.cpp_types import App
DEPENDENCIES = ['api']
HomeassistantBinarySensor = binary_sensor.binary_sensor_ns.class_('HomeassistantBinarySensor',
binary_sensor.BinarySensor)
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(HomeassistantBinarySensor),
vol.Required(CONF_ENTITY_ID): cv.entity_id,
}))
def to_code(config):
rhs = App.make_homeassistant_binary_sensor(config[CONF_NAME], config[CONF_ENTITY_ID])
subs = Pvariable(config[CONF_ID], rhs)
binary_sensor.setup_binary_sensor(subs, config)
BUILD_FLAGS = '-DUSE_HOMEASSISTANT_BINARY_SENSOR'
def to_hass_config(data, config):
return binary_sensor.core_to_hass_config(data, config)

View File

@@ -1,60 +0,0 @@
import voluptuous as vol
from esphome.automation import ACTION_REGISTRY
from esphome.components import binary_sensor
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE
from esphome.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import Action, App, Component, bool_, optional
TemplateBinarySensor = binary_sensor.binary_sensor_ns.class_('TemplateBinarySensor',
binary_sensor.BinarySensor,
Component)
BinarySensorPublishAction = binary_sensor.binary_sensor_ns.class_('BinarySensorPublishAction',
Action)
PLATFORM_SCHEMA = cv.nameable(binary_sensor.BINARY_SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateBinarySensor),
vol.Optional(CONF_LAMBDA): cv.lambda_,
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
rhs = App.make_template_binary_sensor(config[CONF_NAME])
var = Pvariable(config[CONF_ID], rhs)
binary_sensor.setup_binary_sensor(var, config)
setup_component(var, config)
if CONF_LAMBDA in config:
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(bool_)):
yield
add(var.set_template(template_))
BUILD_FLAGS = '-DUSE_TEMPLATE_BINARY_SENSOR'
CONF_BINARY_SENSOR_TEMPLATE_PUBLISH = 'binary_sensor.template.publish'
BINARY_SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(binary_sensor.BinarySensor),
vol.Required(CONF_STATE): cv.templatable(cv.boolean),
})
@ACTION_REGISTRY.register(CONF_BINARY_SENSOR_TEMPLATE_PUBLISH,
BINARY_SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def binary_sensor_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_binary_sensor_publish_action(template_arg)
type = BinarySensorPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_STATE], arg_type, bool_):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config):
return binary_sensor.core_to_hass_config(data, config)

View File

@@ -1,88 +0,0 @@
import voluptuous as vol
from esphome import automation
from esphome.automation import ACTION_REGISTRY
from esphome.components import cover
import esphome.config_validation as cv
from esphome.const import CONF_ASSUMED_STATE, CONF_CLOSE_ACTION, CONF_ID, CONF_LAMBDA, CONF_NAME, \
CONF_OPEN_ACTION, CONF_OPTIMISTIC, CONF_STATE, CONF_STOP_ACTION
from esphome.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import Action, App, NoArg, optional
from esphome.py_compat import string_types
TemplateCover = cover.cover_ns.class_('TemplateCover', cover.Cover)
CoverPublishAction = cover.cover_ns.class_('CoverPublishAction', Action)
PLATFORM_SCHEMA = cv.nameable(cover.COVER_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateCover),
vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_ASSUMED_STATE): cv.boolean,
vol.Optional(CONF_OPEN_ACTION): automation.validate_automation(single=True),
vol.Optional(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
vol.Optional(CONF_STOP_ACTION): automation.validate_automation(single=True),
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
rhs = App.make_template_cover(config[CONF_NAME])
var = Pvariable(config[CONF_ID], rhs)
cover.setup_cover(var, config)
setup_component(var, config)
if CONF_LAMBDA in config:
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(cover.CoverState)):
yield
add(var.set_state_lambda(template_))
if CONF_OPEN_ACTION in config:
automation.build_automation(var.get_open_trigger(), NoArg,
config[CONF_OPEN_ACTION])
if CONF_CLOSE_ACTION in config:
automation.build_automation(var.get_close_trigger(), NoArg,
config[CONF_CLOSE_ACTION])
if CONF_STOP_ACTION in config:
automation.build_automation(var.get_stop_trigger(), NoArg,
config[CONF_STOP_ACTION])
if CONF_OPTIMISTIC in config:
add(var.set_optimistic(config[CONF_OPTIMISTIC]))
if CONF_ASSUMED_STATE in config:
add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
BUILD_FLAGS = '-DUSE_TEMPLATE_COVER'
CONF_COVER_TEMPLATE_PUBLISH = 'cover.template.publish'
COVER_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(cover.Cover),
vol.Required(CONF_STATE): cv.templatable(cover.validate_cover_state),
})
@ACTION_REGISTRY.register(CONF_COVER_TEMPLATE_PUBLISH,
COVER_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def cover_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_cover_publish_action(template_arg)
type = CoverPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
state = config[CONF_STATE]
if isinstance(state, string_types):
template_ = cover.COVER_STATES[state]
else:
for template_ in templatable(state, arg_type, cover.CoverState):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config):
ret = cover.core_to_hass_config(data, config)
if ret is None:
return None
if CONF_OPTIMISTIC in config:
ret['optimistic'] = config[CONF_OPTIMISTIC]
return ret

View File

@@ -1,33 +0,0 @@
import voluptuous as vol
import esphome.config_validation as cv
from esphome.const import CONF_COMPONENTS, CONF_ID, CONF_LAMBDA
from esphome.cpp_generator import Pvariable, process_lambda, variable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import Component, ComponentPtr, esphome_ns, std_vector
CustomComponentConstructor = esphome_ns.class_('CustomComponentConstructor')
MULTI_CONF = True
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(CustomComponentConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_COMPONENTS): cv.ensure_list(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(Component)
}).extend(cv.COMPONENT_SCHEMA.schema)),
})
def to_code(config):
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=std_vector.template(ComponentPtr)):
yield
rhs = CustomComponentConstructor(template_)
custom = variable(config[CONF_ID], rhs)
for i, comp_config in enumerate(config.get(CONF_COMPONENTS, [])):
comp = Pvariable(comp_config[CONF_ID], custom.get_component(i))
setup_component(comp, comp_config)
BUILD_FLAGS = '-DUSE_CUSTOM_COMPONENT'

View File

@@ -1,27 +0,0 @@
import voluptuous as vol
from esphome import pins
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PIN, CONF_UPDATE_INTERVAL
from esphome.cpp_generator import Pvariable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, PollingComponent
DallasComponent = sensor.sensor_ns.class_('DallasComponent', PollingComponent)
MULTI_CONF = True
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(DallasComponent),
vol.Required(CONF_PIN): pins.input_pullup_pin,
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
rhs = App.make_dallas_component(config[CONF_PIN], config.get(CONF_UPDATE_INTERVAL))
var = Pvariable(config[CONF_ID], rhs)
setup_component(var, config)
BUILD_FLAGS = '-DUSE_DALLAS_SENSOR'

View File

@@ -1,127 +0,0 @@
# coding=utf-8
import voluptuous as vol
from esphome import core
from esphome.automation import ACTION_REGISTRY, maybe_simple_id
import esphome.config_validation as cv
from esphome.const import CONF_LAMBDA, CONF_ROTATION, CONF_UPDATE_INTERVAL, CONF_PAGES, CONF_ID
from esphome.core import CORE
from esphome.cpp_generator import add, process_lambda, Pvariable, templatable, get_variable
from esphome.cpp_types import esphome_ns, void, Action
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
})
display_ns = esphome_ns.namespace('display')
DisplayBuffer = display_ns.class_('DisplayBuffer')
DisplayPage = display_ns.class_('DisplayPage')
DisplayPagePtr = DisplayPage.operator('ptr')
DisplayBufferRef = DisplayBuffer.operator('ref')
DisplayPageShowAction = display_ns.class_('DisplayPageShowAction', Action)
DisplayPageShowNextAction = display_ns.class_('DisplayPageShowNextAction', Action)
DisplayPageShowPrevAction = display_ns.class_('DisplayPageShowPrevAction', Action)
DISPLAY_ROTATIONS = {
0: display_ns.DISPLAY_ROTATION_0_DEGREES,
90: display_ns.DISPLAY_ROTATION_90_DEGREES,
180: display_ns.DISPLAY_ROTATION_180_DEGREES,
270: display_ns.DISPLAY_ROTATION_270_DEGREES,
}
def validate_rotation(value):
value = cv.string(value)
if value.endswith(u"°"):
value = value[:-1]
try:
value = int(value)
except ValueError:
raise vol.Invalid(u"Expected integer for rotation")
return cv.one_of(*DISPLAY_ROTATIONS)(value)
BASIC_DISPLAY_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
vol.Optional(CONF_LAMBDA): cv.lambda_,
})
FULL_DISPLAY_PLATFORM_SCHEMA = BASIC_DISPLAY_PLATFORM_SCHEMA.extend({
vol.Optional(CONF_ROTATION): validate_rotation,
vol.Optional(CONF_PAGES): vol.All(cv.ensure_list({
cv.GenerateID(): cv.declare_variable_id(DisplayPage),
vol.Required(CONF_LAMBDA): cv.lambda_,
}), vol.Length(min=1)),
})
def setup_display_core_(display_var, config):
if CONF_UPDATE_INTERVAL in config:
add(display_var.set_update_interval(config[CONF_UPDATE_INTERVAL]))
if CONF_ROTATION in config:
add(display_var.set_rotation(DISPLAY_ROTATIONS[config[CONF_ROTATION]]))
if CONF_PAGES in config:
pages = []
for conf in config[CONF_PAGES]:
for lambda_ in process_lambda(conf[CONF_LAMBDA], [(DisplayBufferRef, 'it')],
return_type=void):
yield
var = Pvariable(conf[CONF_ID], DisplayPage.new(lambda_))
pages.append(var)
add(display_var.set_pages(pages))
CONF_DISPLAY_PAGE_SHOW = 'display.page.show'
DISPLAY_PAGE_SHOW_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.templatable(cv.use_variable_id(DisplayPage)),
})
@ACTION_REGISTRY.register(CONF_DISPLAY_PAGE_SHOW, DISPLAY_PAGE_SHOW_ACTION_SCHEMA)
def display_page_show_to_code(config, action_id, arg_type, template_arg):
type = DisplayPageShowAction.template(arg_type)
action = Pvariable(action_id, type.new(), type=type)
if isinstance(config[CONF_ID], core.Lambda):
for template_ in templatable(config[CONF_ID], arg_type, DisplayPagePtr):
yield None
add(action.set_page(template_))
else:
for var in get_variable(config[CONF_ID]):
yield None
add(action.set_page(var))
yield action
CONF_DISPLAY_PAGE_SHOW_NEXT = 'display.page.show_next'
DISPLAY_PAGE_SHOW_NEXT_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.templatable(cv.use_variable_id(DisplayBuffer)),
})
@ACTION_REGISTRY.register(CONF_DISPLAY_PAGE_SHOW_NEXT, DISPLAY_PAGE_SHOW_NEXT_ACTION_SCHEMA)
def display_page_show_next_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
type = DisplayPageShowNextAction.template(arg_type)
yield Pvariable(action_id, type.new(var), type=type)
CONF_DISPLAY_PAGE_SHOW_PREVIOUS = 'display.page.show_previous'
DISPLAY_PAGE_SHOW_PREVIOUS_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.templatable(cv.use_variable_id(DisplayBuffer)),
})
@ACTION_REGISTRY.register(CONF_DISPLAY_PAGE_SHOW_PREVIOUS, DISPLAY_PAGE_SHOW_PREVIOUS_ACTION_SCHEMA)
def display_page_show_previous_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
type = DisplayPageShowPrevAction.template(arg_type)
yield Pvariable(action_id, type.new(var), type=type)
def setup_display(display_var, config):
CORE.add_job(setup_display_core_, display_var, config)
BUILD_FLAGS = '-DUSE_DISPLAY'

View File

@@ -1,40 +0,0 @@
import voluptuous as vol
from esphome import config_validation as cv
from esphome.components import sensor
from esphome.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32
from esphome.core import HexInt
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, Component, esphome_ns
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
CONF_ESP32_BLE_ID = 'esp32_ble_id'
ESP32BLETracker = esphome_ns.class_('ESP32BLETracker', Component)
XiaomiSensor = esphome_ns.class_('XiaomiSensor', sensor.Sensor)
XiaomiDevice = esphome_ns.class_('XiaomiDevice')
XIAOMI_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(XiaomiSensor)
})
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(ESP32BLETracker),
vol.Optional(CONF_SCAN_INTERVAL): cv.positive_time_period_seconds,
}).extend(cv.COMPONENT_SCHEMA.schema)
def make_address_array(address):
return [HexInt(i) for i in address.parts]
def to_code(config):
rhs = App.make_esp32_ble_tracker()
ble = Pvariable(config[CONF_ID], rhs)
if CONF_SCAN_INTERVAL in config:
add(ble.set_scan_interval(config[CONF_SCAN_INTERVAL]))
setup_component(ble, config)
BUILD_FLAGS = '-DUSE_ESP32_BLE_TRACKER'

View File

@@ -1,85 +0,0 @@
import voluptuous as vol
from esphome import pins
from esphome.components import wifi
import esphome.config_validation as cv
from esphome.const import CONF_DOMAIN, CONF_ID, CONF_MANUAL_IP, CONF_STATIC_IP, CONF_TYPE, \
CONF_USE_ADDRESS, ESP_PLATFORM_ESP32
from esphome.core import CORE
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import gpio_output_pin_expression
from esphome.cpp_types import App, Component, esphome_ns, global_ns
CONFLICTS_WITH = ['wifi']
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
CONF_PHY_ADDR = 'phy_addr'
CONF_MDC_PIN = 'mdc_pin'
CONF_MDIO_PIN = 'mdio_pin'
CONF_CLK_MODE = 'clk_mode'
CONF_POWER_PIN = 'power_pin'
EthernetType = esphome_ns.enum('EthernetType')
ETHERNET_TYPES = {
'LAN8720': EthernetType.ETHERNET_TYPE_LAN8720,
'TLK110': EthernetType.ETHERNET_TYPE_TLK110,
}
eth_clock_mode_t = global_ns.enum('eth_clock_mode_t')
CLK_MODES = {
'GPIO0_IN': eth_clock_mode_t.ETH_CLOCK_GPIO0_IN,
'GPIO0_OUT': eth_clock_mode_t.ETH_CLOCK_GPIO0_OUT,
'GPIO16_OUT': eth_clock_mode_t.ETH_CLOCK_GPIO16_OUT,
'GPIO17_OUT': eth_clock_mode_t.ETH_CLOCK_GPIO17_OUT,
}
EthernetComponent = esphome_ns.class_('EthernetComponent', Component)
def validate(config):
if CONF_USE_ADDRESS not in config:
if CONF_MANUAL_IP in config:
use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP])
else:
use_address = CORE.name + config[CONF_DOMAIN]
config[CONF_USE_ADDRESS] = use_address
return config
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(EthernetComponent),
vol.Required(CONF_TYPE): cv.one_of(*ETHERNET_TYPES, upper=True),
vol.Required(CONF_MDC_PIN): pins.output_pin,
vol.Required(CONF_MDIO_PIN): pins.input_output_pin,
vol.Optional(CONF_CLK_MODE, default='GPIO0_IN'): cv.one_of(*CLK_MODES, upper=True, space='_'),
vol.Optional(CONF_PHY_ADDR, default=0): vol.All(cv.int_, vol.Range(min=0, max=31)),
vol.Optional(CONF_POWER_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_MANUAL_IP): wifi.STA_MANUAL_IP_SCHEMA,
vol.Optional(CONF_DOMAIN, default='.local'): cv.domain_name,
vol.Optional(CONF_USE_ADDRESS): cv.string_strict,
vol.Optional('hostname'): cv.invalid("The hostname option has been removed in 1.11.0"),
}), validate)
def to_code(config):
rhs = App.init_ethernet()
eth = Pvariable(config[CONF_ID], rhs)
add(eth.set_phy_addr(config[CONF_PHY_ADDR]))
add(eth.set_mdc_pin(config[CONF_MDC_PIN]))
add(eth.set_mdio_pin(config[CONF_MDIO_PIN]))
add(eth.set_type(ETHERNET_TYPES[config[CONF_TYPE]]))
add(eth.set_clk_mode(CLK_MODES[config[CONF_CLK_MODE]]))
add(eth.set_use_address(config[CONF_USE_ADDRESS]))
if CONF_POWER_PIN in config:
for pin in gpio_output_pin_expression(config[CONF_POWER_PIN]):
yield
add(eth.set_power_pin(pin))
if CONF_MANUAL_IP in config:
add(eth.set_manual_ip(wifi.manual_ip(config[CONF_MANUAL_IP])))
REQUIRED_BUILD_FLAGS = '-DUSE_ETHERNET'

View File

@@ -1,119 +0,0 @@
# coding=utf-8
import voluptuous as vol
from esphome import core
from esphome.components import display
import esphome.config_validation as cv
from esphome.const import CONF_FILE, CONF_GLYPHS, CONF_ID, CONF_SIZE
from esphome.core import CORE, HexInt
from esphome.cpp_generator import Pvariable, progmem_array, safe_exp
from esphome.cpp_types import App, uint8
from esphome.py_compat import sort_by_cmp
DEPENDENCIES = ['display']
MULTI_CONF = True
Font = display.display_ns.class_('Font')
Glyph = display.display_ns.class_('Glyph')
def validate_glyphs(value):
if isinstance(value, list):
value = vol.Schema([cv.string])(value)
value = vol.Schema([cv.string])(list(value))
def comparator(x, y):
x_ = x.encode('utf-8')
y_ = y.encode('utf-8')
for c in range(min(len(x_), len(y_))):
if x_[c] < y_[c]:
return -1
if x_[c] > y_[c]:
return 1
if len(x_) < len(y_):
return -1
if len(x_) > len(y_):
return 1
raise vol.Invalid(u"Found duplicate glyph {}".format(x))
sort_by_cmp(value, comparator)
return value
def validate_pillow_installed(value):
try:
import PIL
except ImportError:
raise vol.Invalid("Please install the pillow python package to use this feature. "
"(pip install pillow)")
if PIL.__version__[0] < '4':
raise vol.Invalid("Please update your pillow installation to at least 4.0.x. "
"(pip install -U pillow)")
return value
def validate_truetype_file(value):
if value.endswith('.zip'): # for Google Fonts downloads
raise vol.Invalid(u"Please unzip the font archive '{}' first and then use the .ttf files "
u"inside.".format(value))
if not value.endswith('.ttf'):
raise vol.Invalid(u"Only truetype (.ttf) files are supported. Please make sure you're "
u"using the correct format or rename the extension to .ttf")
return cv.file_(value)
DEFAULT_GLYPHS = u' !"%()+,-.:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°'
CONF_RAW_DATA_ID = 'raw_data_id'
FONT_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.declare_variable_id(Font),
vol.Required(CONF_FILE): validate_truetype_file,
vol.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs,
vol.Optional(CONF_SIZE, default=20): vol.All(cv.int_, vol.Range(min=1)),
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(uint8),
})
CONFIG_SCHEMA = vol.All(validate_pillow_installed, FONT_SCHEMA)
def to_code(config):
from PIL import ImageFont
path = CORE.relative_path(config[CONF_FILE])
try:
font = ImageFont.truetype(path, config[CONF_SIZE])
except Exception as e:
raise core.EsphomeError(u"Could not load truetype file {}: {}".format(path, e))
ascent, descent = font.getmetrics()
glyph_args = {}
data = []
for glyph in config[CONF_GLYPHS]:
mask = font.getmask(glyph, mode='1')
_, (offset_x, offset_y) = font.font.getsize(glyph)
width, height = mask.size
width8 = ((width + 7) // 8) * 8
glyph_data = [0 for _ in range(height * width8 // 8)] # noqa: F812
for y in range(height):
for x in range(width):
if not mask.getpixel((x, y)):
continue
pos = x + y * width8
glyph_data[pos // 8] |= 0x80 >> (pos % 8)
glyph_args[glyph] = (len(data), offset_x, offset_y, width, height)
data += glyph_data
rhs = safe_exp([HexInt(x) for x in data])
prog_arr = progmem_array(config[CONF_RAW_DATA_ID], rhs)
glyphs = []
for glyph in config[CONF_GLYPHS]:
glyphs.append(Glyph(glyph, prog_arr, *glyph_args[glyph]))
rhs = App.make_font(glyphs, ascent, ascent + descent)
Pvariable(config[CONF_ID], rhs)

View File

@@ -1,35 +0,0 @@
import voluptuous as vol
from esphome import config_validation as cv
from esphome.const import CONF_ID, CONF_INITIAL_VALUE, CONF_RESTORE_VALUE, CONF_TYPE
from esphome.cpp_generator import Pvariable, RawExpression, TemplateArguments, add
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, Component, esphome_ns
GlobalVariableComponent = esphome_ns.class_('GlobalVariableComponent', Component)
MULTI_CONF = True
CONFIG_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.declare_variable_id(GlobalVariableComponent),
vol.Required(CONF_TYPE): cv.string_strict,
vol.Optional(CONF_INITIAL_VALUE): cv.string_strict,
vol.Optional(CONF_RESTORE_VALUE): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
type_ = RawExpression(config[CONF_TYPE])
template_args = TemplateArguments(type_)
res_type = GlobalVariableComponent.template(template_args)
initial_value = None
if CONF_INITIAL_VALUE in config:
initial_value = RawExpression(config[CONF_INITIAL_VALUE])
rhs = App.Pmake_global_variable(template_args, initial_value)
glob = Pvariable(config[CONF_ID], rhs, type=res_type)
if config.get(CONF_RESTORE_VALUE, False):
hash_ = hash(config[CONF_ID].id) % 2**32
add(glob.set_restore_value(hash_))
setup_component(glob, config)

View File

@@ -1,63 +0,0 @@
# coding=utf-8
import logging
import voluptuous as vol
from esphome import core
from esphome.components import display, font
import esphome.config_validation as cv
from esphome.const import CONF_FILE, CONF_ID, CONF_RESIZE
from esphome.core import CORE, HexInt
from esphome.cpp_generator import Pvariable, progmem_array, safe_exp
from esphome.cpp_types import App, uint8
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['display']
MULTI_CONF = True
Image_ = display.display_ns.class_('Image')
CONF_RAW_DATA_ID = 'raw_data_id'
IMAGE_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.declare_variable_id(Image_),
vol.Required(CONF_FILE): cv.file_,
vol.Optional(CONF_RESIZE): cv.dimensions,
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_variable_id(uint8),
})
CONFIG_SCHEMA = vol.All(font.validate_pillow_installed, IMAGE_SCHEMA)
def to_code(config):
from PIL import Image
path = CORE.relative_path(config[CONF_FILE])
try:
image = Image.open(path)
except Exception as e:
raise core.EsphomeError(u"Could not load image file {}: {}".format(path, e))
if CONF_RESIZE in config:
image.thumbnail(config[CONF_RESIZE])
image = image.convert('1', dither=Image.NONE)
width, height = image.size
if width > 500 or height > 500:
_LOGGER.warning("The image you requested is very big. Please consider using the resize "
"parameter")
width8 = ((width + 7) // 8) * 8
data = [0 for _ in range(height * width8 // 8)]
for y in range(height):
for x in range(width):
if image.getpixel((x, y)):
continue
pos = x + y * width8
data[pos // 8] |= 0x80 >> (pos % 8)
rhs = safe_exp([HexInt(x) for x in data])
prog_arr = progmem_array(config[CONF_RAW_DATA_ID], rhs)
rhs = App.make_image(prog_arr, width, height)
Pvariable(config[CONF_ID], rhs)

View File

@@ -1,24 +0,0 @@
import voluptuous as vol
from esphome import automation
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_INTERVAL
from esphome.cpp_generator import Pvariable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, NoArg, PollingComponent, Trigger, esphome_ns
IntervalTrigger = esphome_ns.class_('IntervalTrigger', Trigger.template(NoArg), PollingComponent)
CONFIG_SCHEMA = automation.validate_automation(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(IntervalTrigger),
vol.Required(CONF_INTERVAL): cv.positive_time_period_milliseconds,
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
for conf in config:
rhs = App.register_component(IntervalTrigger.new(conf[CONF_INTERVAL]))
trigger = Pvariable(conf[CONF_ID], rhs)
setup_component(trigger, conf)
automation.build_automation(trigger, NoArg, conf)

View File

@@ -1,195 +0,0 @@
import voluptuous as vol
from esphome import pins
from esphome.components import light
from esphome.components.light import AddressableLight
from esphome.components.power_supply import PowerSupplyComponent
import esphome.config_validation as cv
from esphome.const import CONF_CLOCK_PIN, CONF_COLOR_CORRECT, CONF_DATA_PIN, \
CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_MAKE_ID, CONF_METHOD, \
CONF_NAME, CONF_NUM_LEDS, CONF_PIN, CONF_POWER_SUPPLY, CONF_TYPE, CONF_VARIANT
from esphome.core import CORE
from esphome.cpp_generator import TemplateArguments, add, get_variable, variable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, Application, Component, global_ns
NeoPixelBusLightOutputBase = light.light_ns.class_('NeoPixelBusLightOutputBase', Component,
AddressableLight)
ESPNeoPixelOrder = light.light_ns.namespace('ESPNeoPixelOrder')
def validate_type(value):
value = cv.string(value).upper()
if 'R' not in value:
raise vol.Invalid("Must have R in type")
if 'G' not in value:
raise vol.Invalid("Must have G in type")
if 'B' not in value:
raise vol.Invalid("Must have B in type")
rest = set(value) - set('RGBW')
if rest:
raise vol.Invalid("Type has invalid color: {}".format(', '.join(rest)))
if len(set(value)) != len(value):
raise vol.Invalid("Type has duplicate color!")
return value
def validate_variant(value):
value = cv.string(value).upper()
if value == 'WS2813':
value = 'WS2812X'
if value == 'WS2812':
value = '800KBPS'
if value == 'LC8812':
value = 'SK6812'
return cv.one_of(*VARIANTS)(value)
def validate_method(value):
if value is None:
if CORE.is_esp32:
return 'ESP32_I2S_1'
if CORE.is_esp8266:
return 'ESP8266_DMA'
raise NotImplementedError
if CORE.is_esp32:
return cv.one_of(*ESP32_METHODS, upper=True, space='_')(value)
if CORE.is_esp8266:
return cv.one_of(*ESP8266_METHODS, upper=True, space='_')(value)
raise NotImplementedError
def validate_method_pin(value):
method = value[CONF_METHOD]
method_pins = {
'ESP8266_DMA': [3],
'ESP8266_UART0': [1],
'ESP8266_ASYNC_UART0': [1],
'ESP8266_UART1': [2],
'ESP8266_ASYNC_UART1': [2],
'ESP32_I2S_0': list(range(0, 32)),
'ESP32_I2S_1': list(range(0, 32)),
}
if CORE.is_esp8266:
method_pins['BIT_BANG'] = list(range(0, 16))
elif CORE.is_esp32:
method_pins['BIT_BANG'] = list(range(0, 32))
pins_ = method_pins[method]
for opt in (CONF_PIN, CONF_CLOCK_PIN, CONF_DATA_PIN):
if opt in value and value[opt] not in pins_:
raise vol.Invalid("Method {} only supports pin(s) {}".format(
method, ', '.join('GPIO{}'.format(x) for x in pins_)
), path=[CONF_METHOD])
return value
VARIANTS = {
'WS2812X': 'Ws2812x',
'SK6812': 'Sk6812',
'800KBPS': '800Kbps',
'400KBPS': '400Kbps',
}
ESP8266_METHODS = {
'ESP8266_DMA': 'NeoEsp8266Dma{}Method',
'ESP8266_UART0': 'NeoEsp8266Uart0{}Method',
'ESP8266_UART1': 'NeoEsp8266Uart1{}Method',
'ESP8266_ASYNC_UART0': 'NeoEsp8266AsyncUart0{}Method',
'ESP8266_ASYNC_UART1': 'NeoEsp8266AsyncUart1{}Method',
'BIT_BANG': 'NeoEsp8266BitBang{}Method',
}
ESP32_METHODS = {
'ESP32_I2S_0': 'NeoEsp32I2s0{}Method',
'ESP32_I2S_1': 'NeoEsp32I2s1{}Method',
'BIT_BANG': 'NeoEsp32BitBang{}Method',
}
def format_method(config):
variant = VARIANTS[config[CONF_VARIANT]]
method = config[CONF_METHOD]
if CORE.is_esp8266:
return ESP8266_METHODS[method].format(variant)
if CORE.is_esp32:
return ESP32_METHODS[method].format(variant)
raise NotImplementedError
def validate(config):
if CONF_PIN in config:
if CONF_CLOCK_PIN in config or CONF_DATA_PIN in config:
raise vol.Invalid("Cannot specify both 'pin' and 'clock_pin'+'data_pin'")
return config
if CONF_CLOCK_PIN in config:
if CONF_DATA_PIN not in config:
raise vol.Invalid("If you give clock_pin, you must also specify data_pin")
return config
raise vol.Invalid("Must specify at least one of 'pin' or 'clock_pin'+'data_pin'")
MakeNeoPixelBusLight = Application.struct('MakeNeoPixelBusLight')
PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(light.AddressableLightState),
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakeNeoPixelBusLight),
vol.Optional(CONF_TYPE, default='GRB'): validate_type,
vol.Optional(CONF_VARIANT, default='800KBPS'): validate_variant,
vol.Optional(CONF_METHOD, default=None): validate_method,
vol.Optional(CONF_PIN): pins.output_pin,
vol.Optional(CONF_CLOCK_PIN): pins.output_pin,
vol.Optional(CONF_DATA_PIN): pins.output_pin,
vol.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
vol.Optional(CONF_GAMMA_CORRECT): cv.positive_float,
vol.Optional(CONF_COLOR_CORRECT): vol.All([cv.percentage], vol.Length(min=3, max=4)),
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
vol.Optional(CONF_POWER_SUPPLY): cv.use_variable_id(PowerSupplyComponent),
vol.Optional(CONF_EFFECTS): light.validate_effects(light.ADDRESSABLE_EFFECTS),
}).extend(cv.COMPONENT_SCHEMA.schema), validate, validate_method_pin)
def to_code(config):
type_ = config[CONF_TYPE]
has_white = 'W' in type_
if has_white:
func = App.make_neo_pixel_bus_rgbw_light
color_feat = global_ns.NeoRgbwFeature
else:
func = App.make_neo_pixel_bus_rgb_light
color_feat = global_ns.NeoRgbFeature
template = TemplateArguments(getattr(global_ns, format_method(config)), color_feat)
rhs = func(template, config[CONF_NAME])
make = variable(config[CONF_MAKE_ID], rhs, type=MakeNeoPixelBusLight.template(template))
output = make.Poutput
if CONF_PIN in config:
add(output.add_leds(config[CONF_NUM_LEDS], config[CONF_PIN]))
else:
add(output.add_leds(config[CONF_NUM_LEDS], config[CONF_CLOCK_PIN], config[CONF_DATA_PIN]))
add(output.set_pixel_order(getattr(ESPNeoPixelOrder, type_)))
if CONF_POWER_SUPPLY in config:
for power_supply in get_variable(config[CONF_POWER_SUPPLY]):
yield
add(output.set_power_supply(power_supply))
if CONF_COLOR_CORRECT in config:
add(output.set_correction(*config[CONF_COLOR_CORRECT]))
light.setup_light(make.Pstate, config)
setup_component(output, config)
REQUIRED_BUILD_FLAGS = '-DUSE_NEO_PIXEL_BUS_LIGHT'
LIB_DEPS = 'NeoPixelBus@2.4.1'
def to_hass_config(data, config):
return light.core_to_hass_config(data, config, brightness=True, rgb=True, color_temp=False,
white_value='W' in config[CONF_TYPE])

View File

@@ -1,52 +0,0 @@
import voluptuous as vol
from esphome.components import light
from esphome.components.light import AddressableLight
import esphome.config_validation as cv
from esphome.const import CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_FROM, CONF_ID, \
CONF_MAKE_ID, CONF_NAME, CONF_SEGMENTS, CONF_TO
from esphome.cpp_generator import get_variable, variable
from esphome.cpp_types import App, Application
AddressableSegment = light.light_ns.class_('AddressableSegment')
PartitionLightOutput = light.light_ns.class_('PartitionLightOutput', AddressableLight)
MakePartitionLight = Application.struct('MakePartitionLight')
def validate_from_to(value):
if value[CONF_FROM] > value[CONF_TO]:
raise vol.Invalid(u"From ({}) must not be larger than to ({})"
u"".format(value[CONF_FROM], value[CONF_TO]))
return value
PLATFORM_SCHEMA = cv.nameable(light.LIGHT_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(light.AddressableLightState),
cv.GenerateID(CONF_MAKE_ID): cv.declare_variable_id(MakePartitionLight),
vol.Required(CONF_SEGMENTS): vol.All(cv.ensure_list({
vol.Required(CONF_ID): cv.use_variable_id(light.AddressableLightState),
vol.Required(CONF_FROM): cv.positive_int,
vol.Required(CONF_TO): cv.positive_int,
}, validate_from_to), vol.Length(min=1)),
vol.Optional(CONF_DEFAULT_TRANSITION_LENGTH): cv.positive_time_period_milliseconds,
vol.Optional(CONF_EFFECTS): light.validate_effects(light.ADDRESSABLE_EFFECTS),
}))
def to_code(config):
segments = []
for conf in config[CONF_SEGMENTS]:
for var in get_variable(conf[CONF_ID]):
yield
segments.append(AddressableSegment(var, conf[CONF_FROM],
conf[CONF_TO] - conf[CONF_FROM] + 1))
rhs = App.make_partition_light(config[CONF_NAME], segments)
make = variable(config[CONF_MAKE_ID], rhs)
light.setup_light(make.Pstate, config)
def to_hass_config(data, config):
return light.core_to_hass_config(data, config, brightness=True, rgb=True, color_temp=False)

View File

@@ -1,180 +0,0 @@
import re
import voluptuous as vol
from esphome.automation import ACTION_REGISTRY, LambdaAction
import esphome.config_validation as cv
from esphome.const import CONF_ARGS, CONF_BAUD_RATE, CONF_FORMAT, CONF_HARDWARE_UART, CONF_ID, \
CONF_LEVEL, CONF_LOGS, CONF_TAG, CONF_TX_BUFFER_SIZE
from esphome.core import CORE, EsphomeError, Lambda
from esphome.cpp_generator import Pvariable, RawExpression, add, process_lambda, statement
from esphome.cpp_types import App, Component, esphome_ns, global_ns, void
from esphome.py_compat import text_type
LOG_LEVELS = {
'NONE': global_ns.ESPHOME_LOG_LEVEL_NONE,
'ERROR': global_ns.ESPHOME_LOG_LEVEL_ERROR,
'WARN': global_ns.ESPHOME_LOG_LEVEL_WARN,
'INFO': global_ns.ESPHOME_LOG_LEVEL_INFO,
'DEBUG': global_ns.ESPHOME_LOG_LEVEL_DEBUG,
'VERBOSE': global_ns.ESPHOME_LOG_LEVEL_VERBOSE,
'VERY_VERBOSE': global_ns.ESPHOME_LOG_LEVEL_VERY_VERBOSE,
}
LOG_LEVEL_TO_ESP_LOG = {
'ERROR': global_ns.ESP_LOGE,
'WARN': global_ns.ESP_LOGW,
'INFO': global_ns.ESP_LOGI,
'DEBUG': global_ns.ESP_LOGD,
'VERBOSE': global_ns.ESP_LOGV,
'VERY_VERBOSE': global_ns.ESP_LOGVV,
}
LOG_LEVEL_SEVERITY = ['NONE', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'VERBOSE', 'VERY_VERBOSE']
UART_SELECTION_ESP32 = ['UART0', 'UART1', 'UART2']
UART_SELECTION_ESP8266 = ['UART0', 'UART0_SWAP', 'UART1']
HARDWARE_UART_TO_UART_SELECTION = {
'UART0': global_ns.UART_SELECTION_UART0,
'UART0_SWAP': global_ns.UART_SELECTION_UART0_SWAP,
'UART1': global_ns.UART_SELECTION_UART1,
'UART2': global_ns.UART_SELECTION_UART2,
}
HARDWARE_UART_TO_SERIAL = {
'UART0': 'Serial',
'UART0_SWAP': 'Serial',
'UART1': 'Serial1',
'UART2': 'Serial2',
}
# pylint: disable=invalid-name
is_log_level = cv.one_of(*LOG_LEVELS, upper=True)
def uart_selection(value):
if CORE.is_esp32:
return cv.one_of(*UART_SELECTION_ESP32, upper=True)(value)
if CORE.is_esp8266:
return cv.one_of(*UART_SELECTION_ESP8266, upper=True)(value)
raise NotImplementedError
def validate_local_no_higher_than_global(value):
global_level = value.get(CONF_LEVEL, 'DEBUG')
for tag, level in value.get(CONF_LOGS, {}).items():
if LOG_LEVEL_SEVERITY.index(level) > LOG_LEVEL_SEVERITY.index(global_level):
raise EsphomeError(u"The local log level {} for {} must be less severe than the "
u"global log level {}.".format(level, tag, global_level))
return value
LogComponent = esphome_ns.class_('LogComponent', Component)
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(LogComponent),
vol.Optional(CONF_BAUD_RATE, default=115200): cv.positive_int,
vol.Optional(CONF_TX_BUFFER_SIZE, default=512): cv.validate_bytes,
vol.Optional(CONF_HARDWARE_UART, default='UART0'): uart_selection,
vol.Optional(CONF_LEVEL): is_log_level,
vol.Optional(CONF_LOGS): vol.Schema({
cv.string: is_log_level,
})
}), validate_local_no_higher_than_global)
def to_code(config):
rhs = App.init_log(config.get(CONF_BAUD_RATE),
config.get(CONF_TX_BUFFER_SIZE),
HARDWARE_UART_TO_UART_SELECTION[config.get(CONF_HARDWARE_UART)])
log = Pvariable(config[CONF_ID], rhs)
if CONF_LEVEL in config:
add(log.set_global_log_level(LOG_LEVELS[config[CONF_LEVEL]]))
for tag, level in config.get(CONF_LOGS, {}).items():
add(log.set_log_level(tag, LOG_LEVELS[level]))
def required_build_flags(config):
flags = []
if CONF_LEVEL in config:
flags.append(u'-DESPHOME_LOG_LEVEL={}'.format(str(LOG_LEVELS[config[CONF_LEVEL]])))
this_severity = LOG_LEVEL_SEVERITY.index(config[CONF_LEVEL])
verbose_severity = LOG_LEVEL_SEVERITY.index('VERBOSE')
is_at_least_verbose = this_severity >= verbose_severity
has_serial_logging = config.get(CONF_BAUD_RATE) != 0
if CORE.is_esp8266 and has_serial_logging and is_at_least_verbose:
debug_serial_port = HARDWARE_UART_TO_SERIAL[config.get(CONF_HARDWARE_UART)]
flags.append(u"-DDEBUG_ESP_PORT={}".format(debug_serial_port))
flags.append(u"-DLWIP_DEBUG")
DEBUG_COMPONENTS = {
'HTTP_CLIENT',
'HTTP_SERVER',
'HTTP_UPDATE',
'OTA',
'SSL',
'TLS_MEM',
'UPDATER',
'WIFI',
}
for comp in DEBUG_COMPONENTS:
flags.append(u"-DDEBUG_ESP_{}".format(comp))
if CORE.is_esp32 and is_at_least_verbose:
flags.append('-DCORE_DEBUG_LEVEL=5')
return flags
def maybe_simple_message(schema):
def validator(value):
if isinstance(value, dict):
return vol.Schema(schema)(value)
return vol.Schema(schema)({CONF_FORMAT: value})
return validator
def validate_printf(value):
# https://stackoverflow.com/questions/30011379/how-can-i-parse-a-c-format-string-in-python
# pylint: disable=anomalous-backslash-in-string
cfmt = u"""\
( # start of capture group 1
% # literal "%"
(?: # first option
(?:[-+0 #]{0,5}) # optional flags
(?:\d+|\*)? # width
(?:\.(?:\d+|\*))? # precision
(?:h|l|ll|w|I|I32|I64)? # size
[cCdiouxXeEfgGaAnpsSZ] # type
) | # OR
%%) # literal "%%"
""" # noqa
matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.X)
if len(matches) != len(value[CONF_ARGS]):
raise vol.Invalid(u"Found {} printf-patterns ({}), but {} args were given!"
u"".format(len(matches), u', '.join(matches), len(value[CONF_ARGS])))
return value
CONF_LOGGER_LOG = 'logger.log'
LOGGER_LOG_ACTION_SCHEMA = vol.All(maybe_simple_message({
vol.Required(CONF_FORMAT): cv.string,
vol.Optional(CONF_ARGS, default=list): cv.ensure_list(cv.lambda_),
vol.Optional(CONF_LEVEL, default="DEBUG"): cv.one_of(*LOG_LEVEL_TO_ESP_LOG, upper=True),
vol.Optional(CONF_TAG, default="main"): cv.string,
}), validate_printf)
@ACTION_REGISTRY.register(CONF_LOGGER_LOG, LOGGER_LOG_ACTION_SCHEMA)
def logger_log_action_to_code(config, action_id, arg_type, template_arg):
esp_log = LOG_LEVEL_TO_ESP_LOG[config[CONF_LEVEL]]
args = [RawExpression(text_type(x)) for x in config[CONF_ARGS]]
text = text_type(statement(esp_log(config[CONF_TAG], config[CONF_FORMAT], *args)))
for lambda_ in process_lambda(Lambda(text), [(arg_type, 'x')], return_type=void):
yield None
rhs = LambdaAction.new(template_arg, lambda_)
type = LambdaAction.template(template_arg)
yield Pvariable(action_id, rhs, type=type)

View File

@@ -1,46 +0,0 @@
import voluptuous as vol
from esphome import pins
from esphome.components import output
import esphome.config_validation as cv
from esphome.const import (CONF_BIT_DEPTH, CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_ID,
CONF_NUM_CHANNELS, CONF_NUM_CHIPS, CONF_UPDATE_ON_BOOT)
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import gpio_output_pin_expression, setup_component
from esphome.cpp_types import App, Component
MY9231OutputComponent = output.output_ns.class_('MY9231OutputComponent', Component)
MULTI_CONF = True
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(MY9231OutputComponent),
vol.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema,
vol.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_NUM_CHANNELS): vol.All(vol.Coerce(int),
vol.Range(3, 1020)),
vol.Optional(CONF_NUM_CHIPS): vol.All(vol.Coerce(int),
vol.Range(1, 255)),
vol.Optional(CONF_BIT_DEPTH): cv.one_of(8, 12, 14, 16, int=True),
vol.Optional(CONF_UPDATE_ON_BOOT): vol.Coerce(bool),
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
for di in gpio_output_pin_expression(config[CONF_DATA_PIN]):
yield
for dcki in gpio_output_pin_expression(config[CONF_CLOCK_PIN]):
yield
rhs = App.make_my9231_component(di, dcki)
my9231 = Pvariable(config[CONF_ID], rhs)
if CONF_NUM_CHANNELS in config:
add(my9231.set_num_channels(config[CONF_NUM_CHANNELS]))
if CONF_NUM_CHIPS in config:
add(my9231.set_num_chips(config[CONF_NUM_CHIPS]))
if CONF_BIT_DEPTH in config:
add(my9231.set_bit_depth(config[CONF_BIT_DEPTH]))
if CONF_UPDATE_ON_BOOT in config:
add(my9231.set_update(config[CONF_UPDATE_ON_BOOT]))
setup_component(my9231, config)
BUILD_FLAGS = '-DUSE_MY9231_OUTPUT'

View File

@@ -1,68 +0,0 @@
import voluptuous as vol
from esphome.components import output
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_OUTPUTS, CONF_TYPE
from esphome.cpp_generator import process_lambda, variable
from esphome.cpp_types import std_vector
CustomBinaryOutputConstructor = output.output_ns.class_('CustomBinaryOutputConstructor')
CustomFloatOutputConstructor = output.output_ns.class_('CustomFloatOutputConstructor')
BINARY_SCHEMA = output.PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(CustomBinaryOutputConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Required(CONF_TYPE): 'binary',
vol.Required(CONF_OUTPUTS):
cv.ensure_list(output.BINARY_OUTPUT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(output.BinaryOutput),
})),
})
FLOAT_SCHEMA = output.PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(CustomFloatOutputConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Required(CONF_TYPE): 'float',
vol.Required(CONF_OUTPUTS):
cv.ensure_list(output.FLOAT_OUTPUT_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(output.FloatOutput),
})),
})
def validate_custom_output(value):
if not isinstance(value, dict):
raise vol.Invalid("Value must be dict")
if CONF_TYPE not in value:
raise vol.Invalid("type not specified!")
type = cv.string_strict(value[CONF_TYPE]).lower()
value[CONF_TYPE] = type
if type == 'binary':
return BINARY_SCHEMA(value)
if type == 'float':
return FLOAT_SCHEMA(value)
raise vol.Invalid("type must either be binary or float, not {}!".format(type))
PLATFORM_SCHEMA = validate_custom_output
def to_code(config):
type = config[CONF_TYPE]
if type == 'binary':
ret_type = output.BinaryOutputPtr
klass = CustomBinaryOutputConstructor
else:
ret_type = output.FloatOutputPtr
klass = CustomFloatOutputConstructor
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=std_vector.template(ret_type)):
yield
rhs = klass(template_)
custom = variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_OUTPUTS]):
output.register_output(custom.get_output(i), conf)
BUILD_FLAGS = '-DUSE_CUSTOM_OUTPUT'

View File

@@ -1,32 +0,0 @@
import voluptuous as vol
from esphome.components import i2c, output
import esphome.config_validation as cv
from esphome.const import CONF_ADDRESS, CONF_FREQUENCY, CONF_ID
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, Component
DEPENDENCIES = ['i2c']
MULTI_CONF = True
PCA9685OutputComponent = output.output_ns.class_('PCA9685OutputComponent',
Component, i2c.I2CDevice)
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(PCA9685OutputComponent),
vol.Required(CONF_FREQUENCY): vol.All(cv.frequency,
vol.Range(min=23.84, max=1525.88)),
vol.Optional(CONF_ADDRESS): cv.i2c_address,
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
rhs = App.make_pca9685_component(config.get(CONF_FREQUENCY))
pca9685 = Pvariable(config[CONF_ID], rhs)
if CONF_ADDRESS in config:
add(pca9685.set_address(config[CONF_ADDRESS]))
setup_component(pca9685, config)
BUILD_FLAGS = '-DUSE_PCA9685_OUTPUT'

View File

@@ -1,46 +0,0 @@
import voluptuous as vol
from esphome import automation, pins
from esphome.components import binary_sensor, spi
from esphome.components.spi import SPIComponent
import esphome.config_validation as cv
from esphome.const import CONF_CS_PIN, CONF_ID, CONF_ON_TAG, CONF_SPI_ID, CONF_TRIGGER_ID, \
CONF_UPDATE_INTERVAL
from esphome.cpp_generator import Pvariable, get_variable
from esphome.cpp_helpers import gpio_output_pin_expression, setup_component
from esphome.cpp_types import App, PollingComponent, Trigger, std_string
DEPENDENCIES = ['spi']
MULTI_CONF = True
PN532Component = binary_sensor.binary_sensor_ns.class_('PN532Component', PollingComponent,
spi.SPIDevice)
PN532Trigger = binary_sensor.binary_sensor_ns.class_('PN532Trigger', Trigger.template(std_string))
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(PN532Component),
cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
vol.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
vol.Optional(CONF_ON_TAG): automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(PN532Trigger),
}),
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
for spi_ in get_variable(config[CONF_SPI_ID]):
yield
for cs in gpio_output_pin_expression(config[CONF_CS_PIN]):
yield
rhs = App.make_pn532_component(spi_, cs, config.get(CONF_UPDATE_INTERVAL))
pn532 = Pvariable(config[CONF_ID], rhs)
for conf_ in config.get(CONF_ON_TAG, []):
trigger = Pvariable(conf_[CONF_TRIGGER_ID], pn532.make_trigger())
automation.build_automation(trigger, std_string, conf_)
setup_component(pn532, config)
BUILD_FLAGS = '-DUSE_PN532'

View File

@@ -1,36 +0,0 @@
import voluptuous as vol
from esphome import pins
import esphome.config_validation as cv
from esphome.const import CONF_ENABLE_TIME, CONF_ID, CONF_KEEP_ON_TIME, CONF_PIN
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import gpio_output_pin_expression, setup_component
from esphome.cpp_types import App, Component, esphome_ns
PowerSupplyComponent = esphome_ns.class_('PowerSupplyComponent', Component)
MULTI_CONF = True
CONFIG_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.declare_variable_id(PowerSupplyComponent),
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_ENABLE_TIME): cv.positive_time_period_milliseconds,
vol.Optional(CONF_KEEP_ON_TIME): cv.positive_time_period_milliseconds,
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
for pin in gpio_output_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_power_supply(pin)
psu = Pvariable(config[CONF_ID], rhs)
if CONF_ENABLE_TIME in config:
add(psu.set_enable_time(config[CONF_ENABLE_TIME]))
if CONF_KEEP_ON_TIME in config:
add(psu.set_keep_on_time(config[CONF_KEEP_ON_TIME]))
setup_component(psu, config)
BUILD_FLAGS = '-DUSE_OUTPUT'

View File

@@ -1,29 +0,0 @@
import voluptuous as vol
from esphome.components import binary_sensor, uart
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_UART_ID
from esphome.cpp_generator import Pvariable, get_variable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, Component
DEPENDENCIES = ['uart']
RDM6300Component = binary_sensor.binary_sensor_ns.class_('RDM6300Component', Component,
uart.UARTDevice)
CONFIG_SCHEMA = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(RDM6300Component),
cv.GenerateID(CONF_UART_ID): cv.use_variable_id(uart.UARTComponent),
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
for uart_ in get_variable(config[CONF_UART_ID]):
yield
rhs = App.make_rdm6300_component(uart_)
var = Pvariable(config[CONF_ID], rhs)
setup_component(var, config)
BUILD_FLAGS = '-DUSE_RDM6300'

View File

@@ -1,52 +0,0 @@
import voluptuous as vol
from esphome import automation
from esphome.automation import ACTION_REGISTRY, maybe_simple_id
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.cpp_generator import Pvariable, get_variable
from esphome.cpp_types import Action, NoArg, Trigger, esphome_ns
Script = esphome_ns.class_('Script', Trigger.template(NoArg))
ScriptExecuteAction = esphome_ns.class_('ScriptExecuteAction', Action)
ScriptStopAction = esphome_ns.class_('ScriptStopAction', Action)
CONFIG_SCHEMA = automation.validate_automation({
vol.Required(CONF_ID): cv.declare_variable_id(Script),
})
def to_code(config):
for conf in config:
trigger = Pvariable(conf[CONF_ID], Script.new())
automation.build_automation(trigger, NoArg, conf)
CONF_SCRIPT_EXECUTE = 'script.execute'
SCRIPT_EXECUTE_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(Script),
})
@ACTION_REGISTRY.register(CONF_SCRIPT_EXECUTE, SCRIPT_EXECUTE_ACTION_SCHEMA)
def script_execute_action_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_execute_action(template_arg)
type = ScriptExecuteAction.template(arg_type)
yield Pvariable(action_id, rhs, type=type)
CONF_SCRIPT_STOP = 'script.stop'
SCRIPT_STOP_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(Script),
})
@ACTION_REGISTRY.register(CONF_SCRIPT_STOP, SCRIPT_STOP_ACTION_SCHEMA)
def script_stop_action_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_stop_action(template_arg)
type = ScriptStopAction.template(arg_type)
yield Pvariable(action_id, rhs, type=type)

View File

@@ -1,35 +0,0 @@
import voluptuous as vol
from esphome.components import sensor
from esphome.components.apds9960 import APDS9960, CONF_APDS9960_ID
import esphome.config_validation as cv
from esphome.const import CONF_NAME, CONF_TYPE
from esphome.cpp_generator import get_variable
DEPENDENCIES = ['apds9960']
TYPES = {
'CLEAR': 'make_clear_channel',
'RED': 'make_red_channel',
'GREEN': 'make_green_channel',
'BLUE': 'make_blue_channel',
'PROXIMITY': 'make_proximity',
}
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(sensor.Sensor),
vol.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True),
cv.GenerateID(CONF_APDS9960_ID): cv.use_variable_id(APDS9960)
}))
def to_code(config):
for hub in get_variable(config[CONF_APDS9960_ID]):
yield
func = getattr(hub, TYPES[config[CONF_TYPE]])
rhs = func(config[CONF_NAME])
sensor.register_sensor(rhs, config)
def to_hass_config(data, config):
return sensor.core_to_hass_config(data, config)

View File

@@ -1,37 +0,0 @@
import voluptuous as vol
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_SENSORS
from esphome.cpp_generator import Pvariable, add, process_lambda, variable
from esphome.cpp_types import std_vector
CustomSensorConstructor = sensor.sensor_ns.class_('CustomSensorConstructor')
PLATFORM_SCHEMA = sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(CustomSensorConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Required(CONF_SENSORS): cv.ensure_list(sensor.SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(sensor.Sensor),
})),
})
def to_code(config):
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=std_vector.template(sensor.SensorPtr)):
yield
rhs = CustomSensorConstructor(template_)
custom = variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_SENSORS]):
var = Pvariable(conf[CONF_ID], custom.get_sensor(i))
add(var.set_name(conf[CONF_NAME]))
sensor.setup_sensor(var, conf)
BUILD_FLAGS = '-DUSE_CUSTOM_SENSOR'
def to_hass_config(data, config):
return [sensor.core_to_hass_config(data, sens) for sens in config[CONF_SENSORS]]

View File

@@ -1,29 +0,0 @@
import voluptuous as vol
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import CONF_ENTITY_ID, CONF_ID, CONF_NAME
from esphome.cpp_generator import Pvariable
from esphome.cpp_types import App
DEPENDENCIES = ['api']
HomeassistantSensor = sensor.sensor_ns.class_('HomeassistantSensor', sensor.Sensor)
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(HomeassistantSensor),
vol.Required(CONF_ENTITY_ID): cv.entity_id,
}))
def to_code(config):
rhs = App.make_homeassistant_sensor(config[CONF_NAME], config[CONF_ENTITY_ID])
subs = Pvariable(config[CONF_ID], rhs)
sensor.setup_sensor(subs, config)
BUILD_FLAGS = '-DUSE_HOMEASSISTANT_SENSOR'
def to_hass_config(data, config):
return sensor.core_to_hass_config(data, config)

View File

@@ -1,39 +0,0 @@
import voluptuous as vol
from esphome import pins
from esphome.components import sensor, spi
from esphome.components.spi import SPIComponent
import esphome.config_validation as cv
from esphome.const import CONF_CS_PIN, CONF_ID, CONF_NAME, CONF_SPI_ID, CONF_UPDATE_INTERVAL
from esphome.cpp_generator import Pvariable, get_variable
from esphome.cpp_helpers import gpio_output_pin_expression, setup_component
from esphome.cpp_types import App
MAX31855Sensor = sensor.sensor_ns.class_('MAX31855Sensor', sensor.PollingSensorComponent,
spi.SPIDevice)
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(MAX31855Sensor),
cv.GenerateID(CONF_SPI_ID): cv.use_variable_id(SPIComponent),
vol.Required(CONF_CS_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
for spi_ in get_variable(config[CONF_SPI_ID]):
yield
for cs in gpio_output_pin_expression(config[CONF_CS_PIN]):
yield
rhs = App.make_max31855_sensor(config[CONF_NAME], spi_, cs,
config.get(CONF_UPDATE_INTERVAL))
max31855 = Pvariable(config[CONF_ID], rhs)
sensor.setup_sensor(max31855, config)
setup_component(max31855, config)
BUILD_FLAGS = '-DUSE_MAX31855_SENSOR'
def to_hass_config(data, config):
return sensor.core_to_hass_config(data, config)

View File

@@ -1,58 +0,0 @@
import voluptuous as vol
from esphome.automation import ACTION_REGISTRY
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE, CONF_UPDATE_INTERVAL
from esphome.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import Action, App, float_, optional
TemplateSensor = sensor.sensor_ns.class_('TemplateSensor', sensor.PollingSensorComponent)
SensorPublishAction = sensor.sensor_ns.class_('SensorPublishAction', Action)
PLATFORM_SCHEMA = cv.nameable(sensor.SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateSensor),
vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
rhs = App.make_template_sensor(config[CONF_NAME], config.get(CONF_UPDATE_INTERVAL))
template = Pvariable(config[CONF_ID], rhs)
sensor.setup_sensor(template, config)
setup_component(template, config)
if CONF_LAMBDA in config:
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(float_)):
yield
add(template.set_template(template_))
BUILD_FLAGS = '-DUSE_TEMPLATE_SENSOR'
CONF_SENSOR_TEMPLATE_PUBLISH = 'sensor.template.publish'
SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(sensor.Sensor),
vol.Required(CONF_STATE): cv.templatable(cv.float_),
})
@ACTION_REGISTRY.register(CONF_SENSOR_TEMPLATE_PUBLISH, SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def sensor_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_sensor_publish_action(template_arg)
type = SensorPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_STATE], arg_type, float_):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config):
return sensor.core_to_hass_config(data, config)

View File

@@ -1,40 +0,0 @@
import voluptuous as vol
from esphome import pins
import esphome.config_validation as cv
from esphome.const import CONF_CLK_PIN, CONF_ID, CONF_MISO_PIN, CONF_MOSI_PIN
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import gpio_input_pin_expression, gpio_output_pin_expression, \
setup_component
from esphome.cpp_types import App, Component, esphome_ns
SPIComponent = esphome_ns.class_('SPIComponent', Component)
SPIDevice = esphome_ns.class_('SPIDevice')
MULTI_CONF = True
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(SPIComponent),
vol.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema,
vol.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema,
}), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN))
def to_code(config):
for clk in gpio_output_pin_expression(config[CONF_CLK_PIN]):
yield
rhs = App.init_spi(clk)
spi = Pvariable(config[CONF_ID], rhs)
if CONF_MISO_PIN in config:
for miso in gpio_input_pin_expression(config[CONF_MISO_PIN]):
yield
add(spi.set_miso(miso))
if CONF_MOSI_PIN in config:
for mosi in gpio_input_pin_expression(config[CONF_MOSI_PIN]):
yield
add(spi.set_mosi(mosi))
setup_component(spi, config)
BUILD_FLAGS = '-DUSE_SPI'

View File

@@ -1,55 +0,0 @@
import voluptuous as vol
from esphome import pins
from esphome.components import stepper
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PIN_A, CONF_PIN_B, CONF_PIN_C, CONF_PIN_D, \
CONF_SLEEP_WHEN_DONE, CONF_STEP_MODE
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import gpio_output_pin_expression, setup_component
from esphome.cpp_types import App, Component
ULN2003StepMode = stepper.stepper_ns.enum('ULN2003StepMode')
STEP_MODES = {
'FULL_STEP': ULN2003StepMode.ULN2003_STEP_MODE_FULL_STEP,
'HALF_STEP': ULN2003StepMode.ULN2003_STEP_MODE_HALF_STEP,
'WAVE_DRIVE': ULN2003StepMode.ULN2003_STEP_MODE_WAVE_DRIVE,
}
ULN2003 = stepper.stepper_ns.class_('ULN2003', stepper.Stepper, Component)
PLATFORM_SCHEMA = stepper.STEPPER_PLATFORM_SCHEMA.extend({
vol.Required(CONF_ID): cv.declare_variable_id(ULN2003),
vol.Required(CONF_PIN_A): pins.gpio_output_pin_schema,
vol.Required(CONF_PIN_B): pins.gpio_output_pin_schema,
vol.Required(CONF_PIN_C): pins.gpio_output_pin_schema,
vol.Required(CONF_PIN_D): pins.gpio_output_pin_schema,
vol.Optional(CONF_SLEEP_WHEN_DONE): cv.boolean,
vol.Optional(CONF_STEP_MODE): cv.one_of(*STEP_MODES, upper=True, space='_')
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
for pin_a in gpio_output_pin_expression(config[CONF_PIN_A]):
yield
for pin_b in gpio_output_pin_expression(config[CONF_PIN_B]):
yield
for pin_c in gpio_output_pin_expression(config[CONF_PIN_C]):
yield
for pin_d in gpio_output_pin_expression(config[CONF_PIN_D]):
yield
rhs = App.make_uln2003(pin_a, pin_b, pin_c, pin_d)
uln = Pvariable(config[CONF_ID], rhs)
if CONF_SLEEP_WHEN_DONE in config:
add(uln.set_sleep_when_done(config[CONF_SLEEP_WHEN_DONE]))
if CONF_STEP_MODE in config:
add(uln.set_step_mode(STEP_MODES[config[CONF_STEP_MODE]]))
stepper.setup_stepper(uln, config)
setup_component(uln, config)
BUILD_FLAGS = '-DUSE_ULN2003'

View File

@@ -1,135 +0,0 @@
import logging
import re
import voluptuous as vol
from esphome import core
import esphome.config_validation as cv
from esphome.core import EsphomeError
_LOGGER = logging.getLogger(__name__)
CONF_SUBSTITUTIONS = 'substitutions'
VALID_SUBSTITUTIONS_CHARACTERS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' \
'0123456789_'
def validate_substitution_key(value):
value = cv.string(value)
if not value:
raise vol.Invalid("Substitution key must not be empty")
if value[0] == '$':
value = value[1:]
if value[0].isdigit():
raise vol.Invalid("First character in substitutions cannot be a digit.")
for char in value:
if char not in VALID_SUBSTITUTIONS_CHARACTERS:
raise vol.Invalid(
u"Substitution must only consist of upper/lowercase characters, the underscore "
u"and numbers. The character '{}' cannot be used".format(char))
return value
CONFIG_SCHEMA = vol.Schema({
validate_substitution_key: cv.string_strict,
})
def to_code(config):
pass
VARIABLE_PROG = re.compile('\\$([{0}]+|\\{{[{0}]*\\}})'.format(VALID_SUBSTITUTIONS_CHARACTERS))
def _expand_substitutions(substitutions, value, path):
if u'$' not in value:
return value
orig_value = value
i = 0
while True:
m = VARIABLE_PROG.search(value, i)
if not m:
# Nothing more to match. Done
break
i, j = m.span(0)
name = m.group(1)
if name.startswith(u'{') and name.endswith(u'}'):
name = name[1:-1]
if name not in substitutions:
_LOGGER.warning(u"Found '%s' (see %s) which looks like a substitution, but '%s' was "
u"not declared", orig_value, u'->'.join(str(x) for x in path), name)
i = j
continue
sub = substitutions[name]
tail = value[j:]
value = value[:i] + sub
i = len(value)
value += tail
return value
def _substitute_item(substitutions, item, path):
if isinstance(item, list):
for i, it in enumerate(item):
sub = _substitute_item(substitutions, it, path + [i])
if sub is not None:
item[i] = sub
elif isinstance(item, dict):
replace_keys = []
for k, v in item.items():
if path or k != CONF_SUBSTITUTIONS:
sub = _substitute_item(substitutions, k, path + [k])
if sub is not None:
replace_keys.append((k, sub))
sub = _substitute_item(substitutions, v, path + [k])
if sub is not None:
item[k] = sub
for old, new in replace_keys:
item[new] = item[old]
del item[old]
elif isinstance(item, str):
sub = _expand_substitutions(substitutions, item, path)
if sub != item:
return sub
elif isinstance(item, core.Lambda):
sub = _expand_substitutions(substitutions, item.value, path)
if sub != item:
item.value = sub
return None
def do_substitution_pass(config):
if CONF_SUBSTITUTIONS not in config:
return config
substitutions = config[CONF_SUBSTITUTIONS]
if not isinstance(substitutions, dict):
raise EsphomeError(u"Substitutions must be a key to value mapping, got {}"
u"".format(type(substitutions)))
key = ''
try:
replace_keys = []
for key, value in substitutions.items():
sub = validate_substitution_key(key)
if sub != key:
replace_keys.append((key, sub))
substitutions[key] = cv.string_strict(value)
for old, new in replace_keys:
substitutions[new] = substitutions[old]
del substitutions[old]
except vol.Invalid as err:
err.path.append(key)
raise EsphomeError(u"Error while parsing substitutions: {}".format(err))
config[CONF_SUBSTITUTIONS] = substitutions
_substitute_item(substitutions, config, [])
return config

View File

@@ -1,162 +0,0 @@
import voluptuous as vol
from esphome import automation
from esphome.automation import ACTION_REGISTRY, CONDITION_REGISTRY, Condition, maybe_simple_id
from esphome.components import mqtt
from esphome.components.mqtt import setup_mqtt_component
import esphome.config_validation as cv
from esphome.const import CONF_ICON, CONF_ID, CONF_INTERNAL, CONF_INVERTED, CONF_MQTT_ID, \
CONF_ON_TURN_OFF, CONF_ON_TURN_ON, CONF_OPTIMISTIC, CONF_TRIGGER_ID
from esphome.core import CORE
from esphome.cpp_generator import Pvariable, add, get_variable
from esphome.cpp_types import Action, App, Nameable, NoArg, Trigger, esphome_ns
PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend({
})
switch_ns = esphome_ns.namespace('switch_')
Switch = switch_ns.class_('Switch', Nameable)
SwitchPtr = Switch.operator('ptr')
MQTTSwitchComponent = switch_ns.class_('MQTTSwitchComponent', mqtt.MQTTComponent)
ToggleAction = switch_ns.class_('ToggleAction', Action)
TurnOffAction = switch_ns.class_('TurnOffAction', Action)
TurnOnAction = switch_ns.class_('TurnOnAction', Action)
SwitchCondition = switch_ns.class_('SwitchCondition', Condition)
SwitchTurnOnTrigger = switch_ns.class_('SwitchTurnOnTrigger', Trigger.template(NoArg))
SwitchTurnOffTrigger = switch_ns.class_('SwitchTurnOffTrigger', Trigger.template(NoArg))
SWITCH_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
cv.GenerateID(CONF_MQTT_ID): cv.declare_variable_id(MQTTSwitchComponent),
vol.Optional(CONF_ICON): cv.icon,
vol.Optional(CONF_INVERTED): cv.boolean,
vol.Optional(CONF_ON_TURN_ON): automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SwitchTurnOnTrigger),
}),
vol.Optional(CONF_ON_TURN_OFF): automation.validate_automation({
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_variable_id(SwitchTurnOffTrigger),
}),
})
SWITCH_PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(SWITCH_SCHEMA.schema)
def setup_switch_core_(switch_var, config):
if CONF_INTERNAL in config:
add(switch_var.set_internal(config[CONF_INTERNAL]))
if CONF_ICON in config:
add(switch_var.set_icon(config[CONF_ICON]))
if CONF_INVERTED in config:
add(switch_var.set_inverted(config[CONF_INVERTED]))
for conf in config.get(CONF_ON_TURN_ON, []):
rhs = switch_var.make_switch_turn_on_trigger()
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
for conf in config.get(CONF_ON_TURN_OFF, []):
rhs = switch_var.make_switch_turn_off_trigger()
trigger = Pvariable(conf[CONF_TRIGGER_ID], rhs)
automation.build_automation(trigger, NoArg, conf)
setup_mqtt_component(switch_var.Pget_mqtt(), config)
def setup_switch(switch_obj, config):
if not CORE.has_id(config[CONF_ID]):
switch_obj = Pvariable(config[CONF_ID], switch_obj, has_side_effects=True)
CORE.add_job(setup_switch_core_, switch_obj, config)
def register_switch(var, config):
switch_var = Pvariable(config[CONF_ID], var, has_side_effects=True)
add(App.register_switch(switch_var))
CORE.add_job(setup_switch_core_, switch_var, config)
BUILD_FLAGS = '-DUSE_SWITCH'
CONF_SWITCH_TOGGLE = 'switch.toggle'
SWITCH_TOGGLE_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(Switch),
})
@ACTION_REGISTRY.register(CONF_SWITCH_TOGGLE, SWITCH_TOGGLE_ACTION_SCHEMA)
def switch_toggle_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_toggle_action(template_arg)
type = ToggleAction.template(arg_type)
yield Pvariable(action_id, rhs, type=type)
CONF_SWITCH_TURN_OFF = 'switch.turn_off'
SWITCH_TURN_OFF_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(Switch),
})
@ACTION_REGISTRY.register(CONF_SWITCH_TURN_OFF, SWITCH_TURN_OFF_ACTION_SCHEMA)
def switch_turn_off_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_turn_off_action(template_arg)
type = TurnOffAction.template(arg_type)
yield Pvariable(action_id, rhs, type=type)
CONF_SWITCH_TURN_ON = 'switch.turn_on'
SWITCH_TURN_ON_ACTION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(Switch),
})
@ACTION_REGISTRY.register(CONF_SWITCH_TURN_ON, SWITCH_TURN_ON_ACTION_SCHEMA)
def switch_turn_on_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_turn_on_action(template_arg)
type = TurnOnAction.template(arg_type)
yield Pvariable(action_id, rhs, type=type)
CONF_SWITCH_IS_ON = 'switch.is_on'
SWITCH_IS_ON_CONDITION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(Switch),
})
@CONDITION_REGISTRY.register(CONF_SWITCH_IS_ON, SWITCH_IS_ON_CONDITION_SCHEMA)
def switch_is_on_to_code(config, condition_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_switch_is_on_condition(template_arg)
type = SwitchCondition.template(arg_type)
yield Pvariable(condition_id, rhs, type=type)
CONF_SWITCH_IS_OFF = 'switch.is_off'
SWITCH_IS_OFF_CONDITION_SCHEMA = maybe_simple_id({
vol.Required(CONF_ID): cv.use_variable_id(Switch),
})
@CONDITION_REGISTRY.register(CONF_SWITCH_IS_OFF, SWITCH_IS_OFF_CONDITION_SCHEMA)
def switch_is_off_to_code(config, condition_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_switch_is_off_condition(template_arg)
type = SwitchCondition.template(arg_type)
yield Pvariable(condition_id, rhs, type=type)
def core_to_hass_config(data, config):
ret = mqtt.build_hass_config(data, 'switch', config, include_state=True, include_command=True)
if ret is None:
return None
if CONF_ICON in config:
ret['icon'] = config[CONF_ICON]
if CONF_OPTIMISTIC in config:
ret['optimistic'] = config[CONF_OPTIMISTIC]
return ret

View File

@@ -1,38 +0,0 @@
import voluptuous as vol
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_SWITCHES
from esphome.cpp_generator import Pvariable, add, process_lambda, variable
from esphome.cpp_types import std_vector
CustomSwitchConstructor = switch.switch_ns.class_('CustomSwitchConstructor')
PLATFORM_SCHEMA = switch.PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(CustomSwitchConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Required(CONF_SWITCHES):
cv.ensure_list(switch.SWITCH_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(switch.Switch),
})),
})
def to_code(config):
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=std_vector.template(switch.SwitchPtr)):
yield
rhs = CustomSwitchConstructor(template_)
custom = variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_SWITCHES]):
var = Pvariable(conf[CONF_ID], custom.get_switch(i))
add(var.set_name(conf[CONF_NAME]))
switch.setup_switch(var, conf)
BUILD_FLAGS = '-DUSE_CUSTOM_SWITCH'
def to_hass_config(data, config):
return [switch.core_to_hass_config(data, swi) for swi in config[CONF_SWITCHES]]

View File

@@ -1,54 +0,0 @@
import voluptuous as vol
from esphome import pins
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_INTERLOCK, CONF_NAME, CONF_PIN, CONF_RESTORE_MODE
from esphome.cpp_generator import Pvariable, add, get_variable
from esphome.cpp_helpers import gpio_output_pin_expression, setup_component
from esphome.cpp_types import App, Component
GPIOSwitch = switch.switch_ns.class_('GPIOSwitch', switch.Switch, Component)
GPIOSwitchRestoreMode = switch.switch_ns.enum('GPIOSwitchRestoreMode')
RESTORE_MODES = {
'RESTORE_DEFAULT_OFF': GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_DEFAULT_OFF,
'RESTORE_DEFAULT_ON': GPIOSwitchRestoreMode.GPIO_SWITCH_RESTORE_DEFAULT_ON,
'ALWAYS_OFF': GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_OFF,
'ALWAYS_ON': GPIOSwitchRestoreMode.GPIO_SWITCH_ALWAYS_ON,
}
PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(GPIOSwitch),
vol.Required(CONF_PIN): pins.gpio_output_pin_schema,
vol.Optional(CONF_RESTORE_MODE): cv.one_of(*RESTORE_MODES, upper=True, space='_'),
vol.Optional(CONF_INTERLOCK): cv.ensure_list(cv.use_variable_id(switch.Switch)),
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
for pin in gpio_output_pin_expression(config[CONF_PIN]):
yield
rhs = App.make_gpio_switch(config[CONF_NAME], pin)
gpio = Pvariable(config[CONF_ID], rhs)
if CONF_RESTORE_MODE in config:
add(gpio.set_restore_mode(RESTORE_MODES[config[CONF_RESTORE_MODE]]))
if CONF_INTERLOCK in config:
interlock = []
for it in config[CONF_INTERLOCK]:
for lock in get_variable(it):
yield
interlock.append(lock)
add(gpio.set_interlock(interlock))
switch.setup_switch(gpio, config)
setup_component(gpio, config)
BUILD_FLAGS = '-DUSE_GPIO_SWITCH'
def to_hass_config(data, config):
return switch.core_to_hass_config(data, config)

View File

@@ -1,78 +0,0 @@
import voluptuous as vol
from esphome import automation
from esphome.automation import ACTION_REGISTRY
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import CONF_ASSUMED_STATE, CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_OPTIMISTIC, \
CONF_RESTORE_STATE, CONF_STATE, CONF_TURN_OFF_ACTION, CONF_TURN_ON_ACTION
from esphome.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import Action, App, Component, NoArg, bool_, optional
TemplateSwitch = switch.switch_ns.class_('TemplateSwitch', switch.Switch, Component)
SwitchPublishAction = switch.switch_ns.class_('SwitchPublishAction', Action)
PLATFORM_SCHEMA = cv.nameable(switch.SWITCH_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateSwitch),
vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_OPTIMISTIC): cv.boolean,
vol.Optional(CONF_ASSUMED_STATE): cv.boolean,
vol.Optional(CONF_TURN_OFF_ACTION): automation.validate_automation(single=True),
vol.Optional(CONF_TURN_ON_ACTION): automation.validate_automation(single=True),
vol.Optional(CONF_RESTORE_STATE): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
rhs = App.make_template_switch(config[CONF_NAME])
template = Pvariable(config[CONF_ID], rhs)
switch.setup_switch(template, config)
if CONF_LAMBDA in config:
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(bool_)):
yield
add(template.set_state_lambda(template_))
if CONF_TURN_OFF_ACTION in config:
automation.build_automation(template.get_turn_off_trigger(), NoArg,
config[CONF_TURN_OFF_ACTION])
if CONF_TURN_ON_ACTION in config:
automation.build_automation(template.get_turn_on_trigger(), NoArg,
config[CONF_TURN_ON_ACTION])
if CONF_OPTIMISTIC in config:
add(template.set_optimistic(config[CONF_OPTIMISTIC]))
if CONF_ASSUMED_STATE in config:
add(template.set_assumed_state(config[CONF_ASSUMED_STATE]))
if CONF_RESTORE_STATE in config:
add(template.set_restore_state(config[CONF_RESTORE_STATE]))
setup_component(template, config)
BUILD_FLAGS = '-DUSE_TEMPLATE_SWITCH'
CONF_SWITCH_TEMPLATE_PUBLISH = 'switch.template.publish'
SWITCH_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(switch.Switch),
vol.Required(CONF_STATE): cv.templatable(cv.boolean),
})
@ACTION_REGISTRY.register(CONF_SWITCH_TEMPLATE_PUBLISH, SWITCH_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def switch_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_switch_publish_action(template_arg)
type = SwitchPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_STATE], arg_type, bool_):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config):
return switch.core_to_hass_config(data, config)

View File

@@ -1,38 +0,0 @@
import voluptuous as vol
from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_TEXT_SENSORS
from esphome.cpp_generator import Pvariable, add, process_lambda, variable
from esphome.cpp_types import std_vector
CustomTextSensorConstructor = text_sensor.text_sensor_ns.class_('CustomTextSensorConstructor')
PLATFORM_SCHEMA = text_sensor.PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(CustomTextSensorConstructor),
vol.Required(CONF_LAMBDA): cv.lambda_,
vol.Required(CONF_TEXT_SENSORS):
cv.ensure_list(text_sensor.TEXT_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(text_sensor.TextSensor),
})),
})
def to_code(config):
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=std_vector.template(text_sensor.TextSensorPtr)):
yield
rhs = CustomTextSensorConstructor(template_)
custom = variable(config[CONF_ID], rhs)
for i, conf in enumerate(config[CONF_TEXT_SENSORS]):
var = Pvariable(conf[CONF_ID], custom.get_text_sensor(i))
add(var.set_name(conf[CONF_NAME]))
text_sensor.setup_text_sensor(var, conf)
BUILD_FLAGS = '-DUSE_CUSTOM_TEXT_SENSOR'
def to_hass_config(data, config):
return [text_sensor.core_to_hass_config(data, sens) for sens in config[CONF_TEXT_SENSORS]]

View File

@@ -1,30 +0,0 @@
import voluptuous as vol
from esphome.components import text_sensor
import esphome.config_validation as cv
from esphome.const import CONF_ENTITY_ID, CONF_ID, CONF_NAME
from esphome.cpp_generator import Pvariable
from esphome.cpp_types import App, Component
DEPENDENCIES = ['api']
HomeassistantTextSensor = text_sensor.text_sensor_ns.class_('HomeassistantTextSensor',
text_sensor.TextSensor, Component)
PLATFORM_SCHEMA = cv.nameable(text_sensor.TEXT_SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(HomeassistantTextSensor),
vol.Required(CONF_ENTITY_ID): cv.entity_id,
}))
def to_code(config):
rhs = App.make_homeassistant_text_sensor(config[CONF_NAME], config[CONF_ENTITY_ID])
sensor_ = Pvariable(config[CONF_ID], rhs)
text_sensor.setup_text_sensor(sensor_, config)
BUILD_FLAGS = '-DUSE_HOMEASSISTANT_TEXT_SENSOR'
def to_hass_config(data, config):
return text_sensor.core_to_hass_config(data, config)

View File

@@ -1,59 +0,0 @@
import voluptuous as vol
from esphome.automation import ACTION_REGISTRY
from esphome.components import text_sensor
from esphome.components.text_sensor import TextSensorPublishAction
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_NAME, CONF_STATE, CONF_UPDATE_INTERVAL
from esphome.cpp_generator import Pvariable, add, get_variable, process_lambda, templatable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, PollingComponent, optional, std_string
TemplateTextSensor = text_sensor.text_sensor_ns.class_('TemplateTextSensor',
text_sensor.TextSensor, PollingComponent)
PLATFORM_SCHEMA = cv.nameable(text_sensor.TEXT_SENSOR_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(TemplateTextSensor),
vol.Optional(CONF_LAMBDA): cv.lambda_,
vol.Optional(CONF_UPDATE_INTERVAL): cv.update_interval,
}).extend(cv.COMPONENT_SCHEMA.schema))
def to_code(config):
rhs = App.make_template_text_sensor(config[CONF_NAME], config.get(CONF_UPDATE_INTERVAL))
template = Pvariable(config[CONF_ID], rhs)
text_sensor.setup_text_sensor(template, config)
setup_component(template, config)
if CONF_LAMBDA in config:
for template_ in process_lambda(config[CONF_LAMBDA], [],
return_type=optional.template(std_string)):
yield
add(template.set_template(template_))
BUILD_FLAGS = '-DUSE_TEMPLATE_TEXT_SENSOR'
CONF_TEXT_SENSOR_TEMPLATE_PUBLISH = 'text_sensor.template.publish'
TEXT_SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA = vol.Schema({
vol.Required(CONF_ID): cv.use_variable_id(text_sensor.TextSensor),
vol.Required(CONF_STATE): cv.templatable(cv.string_strict),
})
@ACTION_REGISTRY.register(CONF_TEXT_SENSOR_TEMPLATE_PUBLISH,
TEXT_SENSOR_TEMPLATE_PUBLISH_ACTION_SCHEMA)
def text_sensor_template_publish_to_code(config, action_id, arg_type, template_arg):
for var in get_variable(config[CONF_ID]):
yield None
rhs = var.make_text_sensor_publish_action(template_arg)
type = TextSensorPublishAction.template(arg_type)
action = Pvariable(action_id, rhs, type=type)
for template_ in templatable(config[CONF_STATE], arg_type, std_string):
yield None
add(action.set_state(template_))
yield action
def to_hass_config(data, config):
return text_sensor.core_to_hass_config(data, config)

View File

@@ -1,24 +0,0 @@
from esphome.components import time as time_
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.cpp_generator import Pvariable
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App
DEPENDENCIES = ['api']
HomeAssistantTime = time_.time_ns.class_('HomeAssistantTime', time_.RealTimeClockComponent)
PLATFORM_SCHEMA = time_.TIME_PLATFORM_SCHEMA.extend({
cv.GenerateID(): cv.declare_variable_id(HomeAssistantTime),
}).extend(cv.COMPONENT_SCHEMA.schema)
def to_code(config):
rhs = App.make_homeassistant_time_component()
ha_time = Pvariable(config[CONF_ID], rhs)
time_.setup_time(ha_time, config)
setup_component(ha_time, config)
BUILD_FLAGS = '-DUSE_HOMEASSISTANT_TIME'

View File

@@ -1,34 +0,0 @@
import voluptuous as vol
from esphome import pins
import esphome.config_validation as cv
from esphome.const import CONF_BAUD_RATE, CONF_ID, CONF_RX_PIN, CONF_TX_PIN
from esphome.cpp_generator import Pvariable, add
from esphome.cpp_helpers import setup_component
from esphome.cpp_types import App, Component, esphome_ns
UARTComponent = esphome_ns.class_('UARTComponent', Component)
UARTDevice = esphome_ns.class_('UARTDevice')
MULTI_CONF = True
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(UARTComponent),
vol.Optional(CONF_TX_PIN): pins.output_pin,
vol.Optional(CONF_RX_PIN): pins.input_pin,
vol.Required(CONF_BAUD_RATE): cv.positive_int,
}).extend(cv.COMPONENT_SCHEMA.schema), cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN))
def to_code(config):
rhs = App.init_uart(config[CONF_BAUD_RATE])
var = Pvariable(config[CONF_ID], rhs)
if CONF_TX_PIN in config:
add(var.set_tx_pin(config[CONF_TX_PIN]))
if CONF_RX_PIN in config:
add(var.set_rx_pin(config[CONF_RX_PIN]))
setup_component(var, config)
BUILD_FLAGS = '-DUSE_UART'

View File

@@ -1,190 +0,0 @@
import voluptuous as vol
import esphome.config_validation as cv
from esphome.const import CONF_AP, CONF_BSSID, CONF_CHANNEL, CONF_DNS1, CONF_DNS2, \
CONF_DOMAIN, CONF_FAST_CONNECT, CONF_GATEWAY, CONF_ID, CONF_MANUAL_IP, CONF_NETWORKS, \
CONF_PASSWORD, CONF_POWER_SAVE_MODE, CONF_REBOOT_TIMEOUT, CONF_SSID, CONF_STATIC_IP, \
CONF_SUBNET, CONF_USE_ADDRESS, CONF_HIDDEN
from esphome.core import CORE, HexInt
from esphome.cpp_generator import Pvariable, StructInitializer, add, variable
from esphome.cpp_types import App, Component, esphome_ns, global_ns
IPAddress = global_ns.class_('IPAddress')
ManualIP = esphome_ns.struct('ManualIP')
WiFiComponent = esphome_ns.class_('WiFiComponent', Component)
WiFiAP = esphome_ns.struct('WiFiAP')
WiFiPowerSaveMode = esphome_ns.enum('WiFiPowerSaveMode')
WIFI_POWER_SAVE_MODES = {
'NONE': WiFiPowerSaveMode.WIFI_POWER_SAVE_NONE,
'LIGHT': WiFiPowerSaveMode.WIFI_POWER_SAVE_LIGHT,
'HIGH': WiFiPowerSaveMode.WIFI_POWER_SAVE_HIGH,
}
def validate_password(value):
value = cv.string_strict(value)
if not value:
return value
if len(value) < 8:
raise vol.Invalid(u"WPA password must be at least 8 characters long")
if len(value) > 64:
raise vol.Invalid(u"WPA password must be at most 64 characters long")
return value
def validate_channel(value):
value = cv.positive_int(value)
if value < 1:
raise vol.Invalid("Minimum WiFi channel is 1")
if value > 14:
raise vol.Invalid("Maximum WiFi channel is 14")
return value
AP_MANUAL_IP_SCHEMA = vol.Schema({
vol.Required(CONF_STATIC_IP): cv.ipv4,
vol.Required(CONF_GATEWAY): cv.ipv4,
vol.Required(CONF_SUBNET): cv.ipv4,
})
STA_MANUAL_IP_SCHEMA = AP_MANUAL_IP_SCHEMA.extend({
vol.Optional(CONF_DNS1, default="1.1.1.1"): cv.ipv4,
vol.Optional(CONF_DNS2, default="1.0.0.1"): cv.ipv4,
})
WIFI_NETWORK_BASE = vol.Schema({
cv.GenerateID(): cv.declare_variable_id(WiFiAP),
vol.Optional(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_CHANNEL): validate_channel,
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
})
WIFI_NETWORK_AP = WIFI_NETWORK_BASE.extend({
})
WIFI_NETWORK_STA = WIFI_NETWORK_BASE.extend({
vol.Optional(CONF_BSSID): cv.mac_address,
vol.Optional(CONF_HIDDEN): cv.boolean,
})
def validate(config):
if CONF_PASSWORD in config and CONF_SSID not in config:
raise vol.Invalid("Cannot have WiFi password without SSID!")
if CONF_SSID in config:
network = {CONF_SSID: config.pop(CONF_SSID)}
if CONF_PASSWORD in config:
network[CONF_PASSWORD] = config.pop(CONF_PASSWORD)
if CONF_NETWORKS in config:
raise vol.Invalid("You cannot use the 'ssid:' option together with 'networks:'. Please "
"copy your network into the 'networks:' key")
config[CONF_NETWORKS] = cv.ensure_list(WIFI_NETWORK_STA)(network)
if (CONF_NETWORKS not in config) and (CONF_AP not in config):
raise vol.Invalid("Please specify at least an SSID or an Access Point "
"to create.")
if config.get(CONF_FAST_CONNECT, False):
networks = config.get(CONF_NETWORKS, [])
if not networks:
raise vol.Invalid("At least one network required for fast_connect!")
if len(networks) != 1:
raise vol.Invalid("Fast connect can only be used with one network!")
if CONF_USE_ADDRESS not in config:
if CONF_MANUAL_IP in config:
use_address = str(config[CONF_MANUAL_IP][CONF_STATIC_IP])
else:
use_address = CORE.name + config[CONF_DOMAIN]
config[CONF_USE_ADDRESS] = use_address
return config
CONFIG_SCHEMA = vol.All(vol.Schema({
cv.GenerateID(): cv.declare_variable_id(WiFiComponent),
vol.Optional(CONF_NETWORKS): cv.ensure_list(WIFI_NETWORK_STA),
vol.Optional(CONF_SSID): cv.ssid,
vol.Optional(CONF_PASSWORD): validate_password,
vol.Optional(CONF_MANUAL_IP): STA_MANUAL_IP_SCHEMA,
vol.Optional(CONF_AP): WIFI_NETWORK_AP,
vol.Optional(CONF_DOMAIN, default='.local'): cv.domain_name,
vol.Optional(CONF_REBOOT_TIMEOUT): cv.positive_time_period_milliseconds,
vol.Optional(CONF_POWER_SAVE_MODE): cv.one_of(*WIFI_POWER_SAVE_MODES, upper=True),
vol.Optional(CONF_FAST_CONNECT): cv.boolean,
vol.Optional(CONF_USE_ADDRESS): cv.string_strict,
vol.Optional('hostname'): cv.invalid("The hostname option has been removed in 1.11.0"),
}), validate)
def safe_ip(ip):
if ip is None:
return IPAddress(0, 0, 0, 0)
return IPAddress(*ip.args)
def manual_ip(config):
if config is None:
return None
return StructInitializer(
ManualIP,
('static_ip', safe_ip(config[CONF_STATIC_IP])),
('gateway', safe_ip(config[CONF_GATEWAY])),
('subnet', safe_ip(config[CONF_SUBNET])),
('dns1', safe_ip(config.get(CONF_DNS1))),
('dns2', safe_ip(config.get(CONF_DNS2))),
)
def wifi_network(config, static_ip):
ap = variable(config[CONF_ID], WiFiAP())
if CONF_SSID in config:
add(ap.set_ssid(config[CONF_SSID]))
if CONF_PASSWORD in config:
add(ap.set_password(config[CONF_PASSWORD]))
if CONF_BSSID in config:
add(ap.set_bssid([HexInt(i) for i in config[CONF_BSSID].parts]))
if CONF_HIDDEN in config:
add(ap.set_hidden(config[CONF_HIDDEN]))
if CONF_CHANNEL in config:
add(ap.set_channel(config[CONF_CHANNEL]))
if static_ip is not None:
add(ap.set_manual_ip(manual_ip(static_ip)))
return ap
def to_code(config):
rhs = App.init_wifi()
wifi = Pvariable(config[CONF_ID], rhs)
add(wifi.set_use_address(config[CONF_USE_ADDRESS]))
for network in config.get(CONF_NETWORKS, []):
add(wifi.add_sta(wifi_network(network, config.get(CONF_MANUAL_IP))))
if CONF_AP in config:
add(wifi.set_ap(wifi_network(config[CONF_AP], config.get(CONF_MANUAL_IP))))
if CONF_REBOOT_TIMEOUT in config:
add(wifi.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
if CONF_POWER_SAVE_MODE in config:
add(wifi.set_power_save_mode(WIFI_POWER_SAVE_MODES[config[CONF_POWER_SAVE_MODE]]))
if CONF_FAST_CONNECT in config:
add(wifi.set_fast_connect(config[CONF_FAST_CONNECT]))
def lib_deps(config):
if CORE.is_esp8266:
return 'ESP8266WiFi'
if CORE.is_esp32:
return None
raise NotImplementedError

View File

@@ -1,604 +0,0 @@
from __future__ import print_function
from collections import OrderedDict
import importlib
import json
import logging
import re
import voluptuous as vol
from esphome import core, core_config, yaml_util
from esphome.components import substitutions
from esphome.const import CONF_ESPHOME, CONF_PLATFORM, ESP_PLATFORMS
from esphome.core import CORE, EsphomeError
from esphome.helpers import color, indent
from esphome.py_compat import text_type
from esphome.util import safe_print
# pylint: disable=unused-import, wrong-import-order
from typing import List, Optional, Tuple, Union # noqa
from esphome.core import ConfigType # noqa
_LOGGER = logging.getLogger(__name__)
_COMPONENT_CACHE = {}
def get_component(domain):
if domain in _COMPONENT_CACHE:
return _COMPONENT_CACHE[domain]
path = 'esphome.components.{}'.format(domain)
try:
module = importlib.import_module(path)
except (ImportError, ValueError) as err:
_LOGGER.debug(err)
else:
_COMPONENT_CACHE[domain] = module
return module
_LOGGER.error("Unable to find component %s", domain)
return None
def get_platform(domain, platform):
return get_component("{}.{}".format(domain, platform))
def is_platform_component(component):
return hasattr(component, 'PLATFORM_SCHEMA')
def iter_components(config):
for domain, conf in config.items():
if domain == CONF_ESPHOME:
yield CONF_ESPHOME, core_config, conf
continue
component = get_component(domain)
if getattr(component, 'MULTI_CONF', False):
for conf_ in conf:
yield domain, component, conf_
else:
yield domain, component, conf
if is_platform_component(component):
for p_config in conf:
p_name = u"{}.{}".format(domain, p_config[CONF_PLATFORM])
platform = get_component(p_name)
yield p_name, platform, p_config
ConfigPath = List[Union[str, int]]
def _path_begins_with_(path, other): # type: (ConfigPath, ConfigPath) -> bool
if len(path) < len(other):
return False
return path[:len(other)] == other
def _path_begins_with(path, other): # type: (ConfigPath, ConfigPath) -> bool
ret = _path_begins_with_(path, other)
return ret
class Config(OrderedDict):
def __init__(self):
super(Config, self).__init__()
self.errors = [] # type: List[Tuple[basestring, ConfigPath]]
self.domains = [] # type: List[Tuple[ConfigPath, basestring]]
def add_error(self, message, path):
# type: (basestring, ConfigPath) -> None
if not isinstance(message, text_type):
message = text_type(message)
self.errors.append((message, path))
def add_domain(self, path, name):
# type: (ConfigPath, basestring) -> None
self.domains.append((path, name))
def remove_domain(self, path, name):
self.domains.remove((path, name))
def lookup_domain(self, path):
# type: (ConfigPath) -> Optional[basestring]
best_len = 0
best_domain = None
for d_path, domain in self.domains:
if len(d_path) < best_len:
continue
if _path_begins_with(path, d_path):
best_len = len(d_path)
best_domain = domain
return best_domain
def is_in_error_path(self, path):
for _, p in self.errors:
if _path_begins_with(p, path):
return True
return False
def get_error_for_path(self, path):
for msg, p in self.errors:
if self.nested_item_path(p) == path:
return msg
return None
def nested_item(self, path):
data = self
for item_index in path:
try:
data = data[item_index]
except (KeyError, IndexError, TypeError):
return {}
return data
def nested_item_path(self, path):
data = self
part = []
for item_index in path:
try:
data = data[item_index]
except (KeyError, IndexError, TypeError):
return part
part.append(item_index)
return part
def iter_ids(config, path=None):
path = path or []
if isinstance(config, core.ID):
yield config, path
elif isinstance(config, core.Lambda):
for id in config.requires_ids:
yield id, path
elif isinstance(config, list):
for i, item in enumerate(config):
for result in iter_ids(item, path + [i]):
yield result
elif isinstance(config, dict):
for key, value in config.items():
for result in iter_ids(value, path + [key]):
yield result
def do_id_pass(result): # type: (Config) -> None
from esphome.cpp_generator import MockObjClass
declare_ids = [] # type: List[Tuple[core.ID, ConfigPath]]
searching_ids = [] # type: List[Tuple[core.ID, ConfigPath]]
for id, path in iter_ids(result):
if id.is_declaration:
if id.id is not None and any(v[0].id == id.id for v in declare_ids):
result.add_error(u"ID {} redefined!".format(id.id), path)
continue
declare_ids.append((id, path))
else:
searching_ids.append((id, path))
# Resolve default ids after manual IDs
for id, _ in declare_ids:
id.resolve([v[0].id for v in declare_ids])
# Check searched IDs
for id, path in searching_ids:
if id.id is not None:
# manually declared
match = next((v[0] for v in declare_ids if v[0].id == id.id), None)
if match is None:
# No declared ID with this name
result.add_error("Couldn't find ID '{}'".format(id.id), path)
continue
if not isinstance(match.type, MockObjClass) or not isinstance(id.type, MockObjClass):
continue
if not match.type.inherits_from(id.type):
result.add_error("ID '{}' of type {} doesn't inherit from {}. Please double check "
"your ID is pointing to the correct value"
"".format(id.id, match.type, id.type), path)
if id.id is None and id.type is not None:
for v in declare_ids:
if v[0] is None or not isinstance(v[0].type, MockObjClass):
continue
inherits = v[0].type.inherits_from(id.type)
if inherits:
id.id = v[0].id
break
else:
result.add_error("Couldn't resolve ID for type '{}'".format(id.type), path)
def validate_config(config):
result = Config()
def _comp_error(ex, path):
# type: (vol.Invalid, List[basestring]) -> None
if isinstance(ex, vol.MultipleInvalid):
errors = ex.errors
else:
errors = [ex]
for e in errors:
path_ = path + e.path
domain = result.lookup_domain(path_) or ''
result.add_error(_format_vol_invalid(e, config, path, domain), path_)
skip_paths = list() # type: List[ConfigPath]
# Step 1: Load everything
result.add_domain([CONF_ESPHOME], CONF_ESPHOME)
result[CONF_ESPHOME] = config[CONF_ESPHOME]
for domain, conf in config.items():
domain = str(domain)
if domain == CONF_ESPHOME or domain.startswith(u'.'):
skip_paths.append([domain])
continue
result.add_domain([domain], domain)
result[domain] = conf
if conf is None:
result[domain] = conf = {}
component = get_component(domain)
if component is None:
result.add_error(u"Component not found: {}".format(domain), [domain])
skip_paths.append([domain])
continue
if not isinstance(conf, list) and getattr(component, 'MULTI_CONF', False):
result[domain] = conf = [conf]
success = True
dependencies = getattr(component, 'DEPENDENCIES', [])
for dependency in dependencies:
if dependency not in config:
result.add_error(u"Component {} requires component {}".format(domain, dependency),
[domain])
success = False
if not success:
skip_paths.append([domain])
continue
success = True
conflicts_with = getattr(component, 'CONFLICTS_WITH', [])
for conflict in conflicts_with:
if conflict in config:
result.add_error(u"Component {} cannot be used together with component {}"
u"".format(domain, conflict), [domain])
success = False
if not success:
skip_paths.append([domain])
continue
esp_platforms = getattr(component, 'ESP_PLATFORMS', ESP_PLATFORMS)
if CORE.esp_platform not in esp_platforms:
result.add_error(u"Component {} doesn't support {}.".format(domain, CORE.esp_platform),
[domain])
skip_paths.append([domain])
continue
if not hasattr(component, 'PLATFORM_SCHEMA'):
continue
result.remove_domain([domain], domain)
if not isinstance(conf, list) and conf:
result[domain] = conf = [conf]
for i, p_config in enumerate(conf):
if not isinstance(p_config, dict):
result.add_error(u"Platform schemas must have 'platform:' key", [domain, i])
skip_paths.append([domain, i])
continue
p_name = p_config.get('platform')
if p_name is None:
result.add_error(u"No platform specified for {}".format(domain), [domain, i])
skip_paths.append([domain, i])
continue
p_domain = u'{}.{}'.format(domain, p_name)
result.add_domain([domain, i], p_domain)
platform = get_platform(domain, p_name)
if platform is None:
result.add_error(u"Platform not found: '{}'".format(p_domain), [domain, i])
skip_paths.append([domain, i])
continue
success = True
dependencies = getattr(platform, 'DEPENDENCIES', [])
for dependency in dependencies:
if dependency not in config:
result.add_error(u"Platform {} requires component {}"
u"".format(p_domain, dependency), [domain, i])
success = False
if not success:
skip_paths.append([domain, i])
continue
success = True
conflicts_with = getattr(platform, 'CONFLICTS_WITH', [])
for conflict in conflicts_with:
if conflict in config:
result.add_error(u"Platform {} cannot be used together with component {}"
u"".format(p_domain, conflict), [domain, i])
success = False
if not success:
skip_paths.append([domain, i])
continue
esp_platforms = getattr(platform, 'ESP_PLATFORMS', ESP_PLATFORMS)
if CORE.esp_platform not in esp_platforms:
result.add_error(u"Platform {} doesn't support {}."
u"".format(p_domain, CORE.esp_platform), [domain, i])
skip_paths.append([domain, i])
continue
# Step 2: Validate configuration
try:
result[CONF_ESPHOME] = core_config.CONFIG_SCHEMA(result[CONF_ESPHOME])
except vol.Invalid as ex:
_comp_error(ex, [CONF_ESPHOME])
for domain, conf in result.items():
domain = str(domain)
if [domain] in skip_paths:
continue
component = get_component(domain)
if hasattr(component, 'CONFIG_SCHEMA'):
multi_conf = getattr(component, 'MULTI_CONF', False)
if multi_conf:
for i, conf_ in enumerate(conf):
try:
validated = component.CONFIG_SCHEMA(conf_)
result[domain][i] = validated
except vol.Invalid as ex:
_comp_error(ex, [domain, i])
else:
try:
validated = component.CONFIG_SCHEMA(conf)
result[domain] = validated
except vol.Invalid as ex:
_comp_error(ex, [domain])
continue
if not hasattr(component, 'PLATFORM_SCHEMA'):
continue
for i, p_config in enumerate(conf):
if [domain, i] in skip_paths:
continue
p_name = p_config['platform']
platform = get_platform(domain, p_name)
if hasattr(platform, 'PLATFORM_SCHEMA'):
try:
p_validated = platform.PLATFORM_SCHEMA(p_config)
except vol.Invalid as ex:
_comp_error(ex, [domain, i])
continue
result[domain][i] = p_validated
if not result.errors:
# Only parse IDs if no validation error. Otherwise
# user gets confusing messages
do_id_pass(result)
return result
def _nested_getitem(data, path):
for item_index in path:
try:
data = data[item_index]
except (KeyError, IndexError, TypeError):
return None
return data
def humanize_error(config, validation_error):
offending_item_summary = _nested_getitem(config, validation_error.path)
if isinstance(offending_item_summary, dict):
try:
offending_item_summary = json.dumps(offending_item_summary)
except (TypeError, ValueError):
pass
validation_error = text_type(validation_error)
m = re.match(r'^(.*?)\s*(?:for dictionary value )?@ data\[.*$', validation_error)
if m is not None:
validation_error = m.group(1)
validation_error = validation_error.strip()
if not validation_error.endswith(u'.'):
validation_error += u'.'
if offending_item_summary is None:
return validation_error
return u"{} Got '{}'".format(validation_error, offending_item_summary)
def _format_vol_invalid(ex, config, path, domain):
# type: (vol.Invalid, ConfigType, ConfigPath, basestring) -> unicode
message = u''
if u'extra keys not allowed' in ex.error_message:
try:
paren = ex.path[-2]
except IndexError:
paren = domain
message += u'[{}] is an invalid option for [{}].'.format(ex.path[-1], paren)
elif u'required key not provided' in ex.error_message:
try:
paren = ex.path[-2]
except IndexError:
paren = domain
message += u"'{}' is a required option for [{}].".format(ex.path[-1], paren)
else:
message += humanize_error(_nested_getitem(config, path), ex)
return message
def load_config():
try:
config = yaml_util.load_yaml(CORE.config_path)
except OSError:
raise EsphomeError(u"Invalid YAML at {}".format(CORE.config_path))
CORE.raw_config = config
config = substitutions.do_substitution_pass(config)
core_config.preload_core_config(config)
try:
result = validate_config(config)
except EsphomeError:
raise
except Exception:
_LOGGER.error(u"Unexpected exception while reading configuration:")
raise
return result
def line_info(obj, highlight=True):
"""Display line config source."""
if not highlight:
return None
if hasattr(obj, '__config_file__'):
return color('cyan', "[source {}:{}]"
.format(obj.__config_file__, obj.__line__ or '?'))
return None
def _print_on_next_line(obj):
if isinstance(obj, (list, tuple, dict)):
return True
if isinstance(obj, str):
return len(obj) > 80
if isinstance(obj, core.Lambda):
return len(obj.value) > 80
return False
def dump_dict(config, path, at_root=True):
# type: (Config, ConfigPath, bool) -> Tuple[unicode, bool]
conf = config.nested_item(path)
ret = u''
multiline = False
if at_root:
error = config.get_error_for_path(path)
if error is not None:
ret += u'\n' + color('bold_red', error) + u'\n'
if isinstance(conf, (list, tuple)):
multiline = True
if not conf:
ret += u'[]'
multiline = False
for i in range(len(conf)):
path_ = path + [i]
error = config.get_error_for_path(path_)
if error is not None:
ret += u'\n' + color('bold_red', error) + u'\n'
sep = u'- '
if config.is_in_error_path(path_):
sep = color('red', sep)
msg, _ = dump_dict(config, path_, at_root=False)
msg = indent(msg)
inf = line_info(config.nested_item(path_), highlight=config.is_in_error_path(path_))
if inf is not None:
msg = inf + u'\n' + msg
elif msg:
msg = msg[2:]
ret += sep + msg + u'\n'
elif isinstance(conf, dict):
multiline = True
if not conf:
ret += u'{}'
multiline = False
for k in conf.keys():
path_ = path + [k]
error = config.get_error_for_path(path_)
if error is not None:
ret += u'\n' + color('bold_red', error) + u'\n'
st = u'{}: '.format(k)
if config.is_in_error_path(path_):
st = color('red', st)
msg, m = dump_dict(config, path_, at_root=False)
inf = line_info(config.nested_item(path_), highlight=config.is_in_error_path(path_))
if m:
msg = u'\n' + indent(msg)
if inf is not None:
if m:
msg = u' ' + inf + msg
else:
msg = msg + u' ' + inf
ret += st + msg + u'\n'
elif isinstance(conf, str):
if not conf:
conf += u"''"
if len(conf) > 80:
conf = u'|-\n' + indent(conf)
error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white'
ret += color(col, text_type(conf))
elif isinstance(conf, core.Lambda):
conf = u'!lambda |-\n' + indent(text_type(conf.value))
error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white'
ret += color(col, conf)
elif conf is None:
pass
else:
error = config.get_error_for_path(path)
col = 'bold_red' if error else 'white'
ret += color(col, text_type(conf))
multiline = u'\n' in ret
return ret, multiline
def strip_default_ids(config):
if isinstance(config, list):
to_remove = []
for i, x in enumerate(config):
x = config[i] = strip_default_ids(x)
if isinstance(x, core.ID) and not x.is_manual:
to_remove.append(x)
for x in to_remove:
config.remove(x)
elif isinstance(config, dict):
to_remove = []
for k, v in config.items():
v = config[k] = strip_default_ids(v)
if isinstance(v, core.ID) and not v.is_manual:
to_remove.append(k)
for k in to_remove:
config.pop(k)
return config
def read_config(verbose):
_LOGGER.info("Reading configuration...")
try:
res = load_config()
except EsphomeError as err:
_LOGGER.error(u"Error while reading config: %s", err)
return None
if res.errors:
if not verbose:
res = strip_default_ids(res)
safe_print(color('bold_red', u"Failed config"))
safe_print('')
for path, domain in res.domains:
if not res.is_in_error_path(path):
continue
safe_print(color('bold_red', u'{}:'.format(domain)) + u' ' +
(line_info(res.nested_item(path)) or u''))
safe_print(indent(dump_dict(res, path)[0]))
return None
return OrderedDict(res)

View File

@@ -1,49 +0,0 @@
from esphome.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_PCF8574, \
CONF_SETUP_PRIORITY
from esphome.core import CORE, EsphomeError
from esphome.cpp_generator import IntLiteral, RawExpression
from esphome.cpp_types import GPIOInputPin, GPIOOutputPin
def generic_gpio_pin_expression_(conf, mock_obj, default_mode):
if conf is None:
return
number = conf[CONF_NUMBER]
inverted = conf.get(CONF_INVERTED)
if CONF_PCF8574 in conf:
from esphome.components import pcf8574
for hub in CORE.get_variable(conf[CONF_PCF8574]):
yield None
if default_mode == u'INPUT':
mode = pcf8574.PCF8675_GPIO_MODES[conf.get(CONF_MODE, u'INPUT')]
yield hub.make_input_pin(number, mode, inverted)
return
if default_mode == u'OUTPUT':
yield hub.make_output_pin(number, inverted)
return
raise EsphomeError(u"Unknown default mode {}".format(default_mode))
if len(conf) == 1:
yield IntLiteral(number)
return
mode = RawExpression(conf.get(CONF_MODE, default_mode))
yield mock_obj(number, mode, inverted)
def gpio_output_pin_expression(conf):
for exp in generic_gpio_pin_expression_(conf, GPIOOutputPin, 'OUTPUT'):
yield None
yield exp
def gpio_input_pin_expression(conf):
for exp in generic_gpio_pin_expression_(conf, GPIOInputPin, 'INPUT'):
yield None
yield exp
def setup_component(obj, config):
if CONF_SETUP_PRIORITY in config:
CORE.add(obj.set_setup_priority(config[CONF_SETUP_PRIORITY]))

View File

@@ -1,37 +0,0 @@
from esphome.cpp_generator import MockObj
global_ns = MockObj('', '')
void = global_ns.namespace('void')
float_ = global_ns.namespace('float')
bool_ = global_ns.namespace('bool')
std_ns = global_ns.namespace('std')
std_string = std_ns.class_('string')
std_vector = std_ns.class_('vector')
uint8 = global_ns.namespace('uint8_t')
uint16 = global_ns.namespace('uint16_t')
uint32 = global_ns.namespace('uint32_t')
int32 = global_ns.namespace('int32_t')
const_char_ptr = global_ns.namespace('const char *')
NAN = global_ns.namespace('NAN')
esphome_ns = global_ns # using namespace esphome;
NoArg = esphome_ns.class_('NoArg')
App = esphome_ns.App
io_ns = esphome_ns.namespace('io')
Nameable = esphome_ns.class_('Nameable')
Trigger = esphome_ns.class_('Trigger')
Action = esphome_ns.class_('Action')
Component = esphome_ns.class_('Component')
ComponentPtr = Component.operator('ptr')
PollingComponent = esphome_ns.class_('PollingComponent', Component)
Application = esphome_ns.class_('Application')
optional = esphome_ns.class_('optional')
arduino_json_ns = global_ns.namespace('ArduinoJson')
JsonObject = arduino_json_ns.class_('JsonObject')
JsonObjectRef = JsonObject.operator('ref')
JsonObjectConstRef = JsonObjectRef.operator('const')
Controller = esphome_ns.class_('Controller')
StoringController = esphome_ns.class_('StoringController', Controller)
GPIOPin = esphome_ns.class_('GPIOPin')
GPIOOutputPin = esphome_ns.class_('GPIOOutputPin', GPIOPin)
GPIOInputPin = esphome_ns.class_('GPIOInputPin', GPIOPin)

View File

@@ -1,575 +0,0 @@
# pylint: disable=wrong-import-position
from __future__ import print_function
import codecs
import hmac
import json
import logging
import os
import subprocess
import threading
import tornado
import tornado.concurrent
import tornado.gen
import tornado.httpserver
import tornado.ioloop
import tornado.iostream
from tornado.log import access_log
import tornado.netutil
import tornado.process
import tornado.web
import tornado.websocket
from esphome import const
from esphome.__main__ import get_serial_ports
from esphome.helpers import mkdir_p
from esphome.py_compat import IS_PY2
from esphome.storage_json import EsphomeStorageJSON, StorageJSON, \
esphome_storage_path, ext_storage_path
from esphome.util import shlex_quote
# pylint: disable=unused-import, wrong-import-order
from typing import Optional # noqa
from esphome.zeroconf import DashboardStatus, Zeroconf
_LOGGER = logging.getLogger(__name__)
CONFIG_DIR = ''
PASSWORD_DIGEST = ''
COOKIE_SECRET = None
USING_PASSWORD = False
ON_HASSIO = False
USING_HASSIO_AUTH = True
HASSIO_MQTT_CONFIG = None
if IS_PY2:
cookie_authenticated_yes = 'yes'
else:
cookie_authenticated_yes = b'yes'
# pylint: disable=abstract-method
class BaseHandler(tornado.web.RequestHandler):
def is_authenticated(self):
if USING_HASSIO_AUTH or USING_PASSWORD:
return self.get_secure_cookie('authenticated') == cookie_authenticated_yes
return True
# pylint: disable=abstract-method, arguments-differ
class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
def __init__(self, application, request, **kwargs):
super(EsphomeCommandWebSocket, self).__init__(application, request, **kwargs)
self.proc = None
self.closed = False
def on_message(self, message):
if USING_HASSIO_AUTH or USING_PASSWORD:
if self.get_secure_cookie('authenticated') != cookie_authenticated_yes:
return
if self.proc is not None:
return
command = self.build_command(message)
_LOGGER.info(u"Running command '%s'", ' '.join(shlex_quote(x) for x in command))
self.proc = tornado.process.Subprocess(command,
stdout=tornado.process.Subprocess.STREAM,
stderr=subprocess.STDOUT)
self.proc.set_exit_callback(self.proc_on_exit)
tornado.ioloop.IOLoop.current().spawn_callback(self.redirect_stream)
@tornado.gen.coroutine
def redirect_stream(self):
while True:
try:
if IS_PY2:
reg = '[\n\r]'
else:
reg = b'[\n\r]'
data = yield self.proc.stdout.read_until_regex(reg)
if not IS_PY2:
data = data.decode('utf-8', 'backslashreplace')
except tornado.iostream.StreamClosedError:
break
try:
self.write_message({'event': 'line', 'data': data})
except UnicodeDecodeError:
data = codecs.decode(data, 'utf8', 'replace')
self.write_message({'event': 'line', 'data': data})
def proc_on_exit(self, returncode):
if not self.closed:
_LOGGER.debug("Process exited with return code %s", returncode)
self.write_message({'event': 'exit', 'code': returncode})
def on_close(self):
self.closed = True
if self.proc is not None and self.proc.returncode is None:
_LOGGER.debug("Terminating process")
self.proc.proc.terminate()
def build_command(self, message):
raise NotImplementedError
class EsphomeLogsHandler(EsphomeCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = CONFIG_DIR + '/' + js['configuration']
return ["esphome", "--dashboard", config_file, "logs", '--serial-port', js["port"]]
class EsphomeRunHandler(EsphomeCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphome", "--dashboard", config_file, "run", '--upload-port', js["port"]]
class EsphomeCompileHandler(EsphomeCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphome", "--dashboard", config_file, "compile"]
class EsphomeValidateHandler(EsphomeCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphome", "--dashboard", config_file, "config"]
class EsphomeCleanMqttHandler(EsphomeCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphome", "--dashboard", config_file, "clean-mqtt"]
class EsphomeCleanHandler(EsphomeCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphome", "--dashboard", config_file, "clean"]
class EsphomeHassConfigHandler(EsphomeCommandWebSocket):
def build_command(self, message):
js = json.loads(message)
config_file = os.path.join(CONFIG_DIR, js['configuration'])
return ["esphome", "--dashboard", config_file, "hass-config"]
class SerialPortRequestHandler(BaseHandler):
def get(self):
if not self.is_authenticated():
self.redirect('/login')
return
ports = get_serial_ports()
data = []
for port, desc in ports:
if port == '/dev/ttyAMA0':
desc = 'UART pins on GPIO header'
split_desc = desc.split(' - ')
if len(split_desc) == 2 and split_desc[0] == split_desc[1]:
# Some serial ports repeat their values
desc = split_desc[0]
data.append({'port': port, 'desc': desc})
data.append({'port': 'OTA', 'desc': 'Over-The-Air'})
data.sort(key=lambda x: x['port'], reverse=True)
self.write(json.dumps(data))
class WizardRequestHandler(BaseHandler):
def post(self):
from esphome import wizard
if not self.is_authenticated():
self.redirect('/login')
return
kwargs = {k: ''.join(v) for k, v in self.request.arguments.items()}
destination = os.path.join(CONFIG_DIR, kwargs['name'] + '.yaml')
wizard.wizard_write(path=destination, **kwargs)
self.redirect('/?begin=True')
class DownloadBinaryRequestHandler(BaseHandler):
def get(self):
if not self.is_authenticated():
self.redirect('/login')
return
configuration = self.get_argument('configuration')
storage_path = ext_storage_path(CONFIG_DIR, configuration)
storage_json = StorageJSON.load(storage_path)
if storage_json is None:
self.send_error()
return
path = storage_json.firmware_bin_path
self.set_header('Content-Type', 'application/octet-stream')
filename = '{}.bin'.format(storage_json.name)
self.set_header("Content-Disposition", 'attachment; filename="{}"'.format(filename))
with open(path, 'rb') as f:
while 1:
data = f.read(16384) # or some other nice-sized chunk
if not data:
break
self.write(data)
self.finish()
def _list_yaml_files():
files = []
for file in os.listdir(CONFIG_DIR):
if not file.endswith('.yaml'):
continue
if file.startswith('.'):
continue
if file == 'secrets.yaml':
continue
files.append(file)
files.sort()
return files
def _list_dashboard_entries():
files = _list_yaml_files()
return [DashboardEntry(file) for file in files]
class DashboardEntry(object):
def __init__(self, filename):
self.filename = filename
self._storage = None
self._loaded_storage = False
@property
def full_path(self): # type: () -> str
return os.path.join(CONFIG_DIR, self.filename)
@property
def storage(self): # type: () -> Optional[StorageJSON]
if not self._loaded_storage:
self._storage = StorageJSON.load(ext_storage_path(CONFIG_DIR, self.filename))
self._loaded_storage = True
return self._storage
@property
def address(self):
if self.storage is None:
return None
return self.storage.address
@property
def name(self):
if self.storage is None:
return self.filename[:-len('.yaml')]
return self.storage.name
@property
def esp_platform(self):
if self.storage is None:
return None
return self.storage.esp_platform
@property
def board(self):
if self.storage is None:
return None
return self.storage.board
@property
def update_available(self):
if self.storage is None:
return True
return self.update_old != self.update_new
@property
def update_old(self):
if self.storage is None:
return ''
return self.storage.esphome_version or ''
@property
def update_new(self):
return const.__version__
class MainRequestHandler(BaseHandler):
def get(self):
if not self.is_authenticated():
self.redirect('/login')
return
begin = bool(self.get_argument('begin', False))
entries = _list_dashboard_entries()
version = const.__version__
docs_link = 'https://beta.esphome.io/' if 'b' in version else \
'https://esphome.io/'
self.render("templates/index.html", entries=entries,
version=version, begin=begin, docs_link=docs_link,
get_static_file_url=get_static_file_url)
class PingThread(threading.Thread):
def run(self):
zc = Zeroconf()
def on_update(dat):
for key, b in dat.items():
PING_RESULT[key] = b
stat = DashboardStatus(zc, on_update)
stat.start()
while not STOP_EVENT.is_set():
entries = _list_dashboard_entries()
stat.request_query({entry.filename: entry.name + '.local.' for entry in entries})
PING_REQUEST.wait()
PING_REQUEST.clear()
stat.stop()
stat.join()
zc.close()
class PingRequestHandler(BaseHandler):
def get(self):
if not self.is_authenticated():
self.redirect('/login')
return
PING_REQUEST.set()
self.write(json.dumps(PING_RESULT))
def is_allowed(configuration):
return os.path.sep not in configuration
class EditRequestHandler(BaseHandler):
def get(self):
if not self.is_authenticated():
self.redirect('/login')
return
configuration = self.get_argument('configuration')
if not is_allowed(configuration):
self.set_status(401)
return
with open(os.path.join(CONFIG_DIR, configuration), 'r') as f:
content = f.read()
self.write(content)
def post(self):
if not self.is_authenticated():
self.redirect('/login')
return
configuration = self.get_argument('configuration')
if not is_allowed(configuration):
self.set_status(401)
return
with open(os.path.join(CONFIG_DIR, configuration), 'wb') as f:
f.write(self.request.body)
self.set_status(200)
return
PING_RESULT = {} # type: dict
STOP_EVENT = threading.Event()
PING_REQUEST = threading.Event()
class LoginHandler(BaseHandler):
def get(self):
if USING_HASSIO_AUTH:
self.render_hassio_login()
return
self.write('<html><body><form action="/login" method="post">'
'Password: <input type="password" name="password">'
'<input type="submit" value="Sign in">'
'</form></body></html>')
def render_hassio_login(self, error=None):
version = const.__version__
docs_link = 'https://beta.esphome.io/' if 'b' in version else \
'https://esphome.io/'
self.render("templates/login.html", version=version, docs_link=docs_link, error=error,
get_static_file_url=get_static_file_url)
def post_hassio_login(self):
import requests
headers = {
'X-HASSIO-KEY': os.getenv('HASSIO_TOKEN'),
}
data = {
'username': str(self.get_argument('username', '')),
'password': str(self.get_argument('password', ''))
}
try:
req = requests.post('http://hassio/auth', headers=headers, data=data)
if req.status_code == 200:
self.set_secure_cookie("authenticated", cookie_authenticated_yes)
self.redirect('/')
return
except Exception as err: # pylint: disable=broad-except
_LOGGER.warning("Error during Hass.io auth request: %s", err)
self.set_status(500)
self.render_hassio_login(error="Internal server error")
return
self.set_status(401)
self.render_hassio_login(error="Invalid username or password")
def post(self):
if USING_HASSIO_AUTH:
self.post_hassio_login()
return
password = str(self.get_argument("password", ''))
if IS_PY2:
password = hmac.new(password).digest()
else:
password = hmac.new(password.encode()).digest()
if hmac.compare_digest(PASSWORD_DIGEST, password):
self.set_secure_cookie("authenticated", cookie_authenticated_yes)
self.redirect("/")
_STATIC_FILE_HASHES = {}
def get_static_file_url(name):
static_path = os.path.join(os.path.dirname(__file__), 'static')
if name in _STATIC_FILE_HASHES:
hash_ = _STATIC_FILE_HASHES[name]
else:
path = os.path.join(static_path, name)
with open(path, 'rb') as f_handle:
hash_ = hash(f_handle.read())
_STATIC_FILE_HASHES[name] = hash_
return u'/static/{}?hash={}'.format(name, hash_)
def make_app(debug=False):
def log_function(handler):
if handler.get_status() < 400:
log_method = access_log.info
if isinstance(handler, SerialPortRequestHandler) and not debug:
return
if isinstance(handler, PingRequestHandler) and not debug:
return
elif handler.get_status() < 500:
log_method = access_log.warning
else:
log_method = access_log.error
request_time = 1000.0 * handler.request.request_time()
# pylint: disable=protected-access
log_method("%d %s %.2fms", handler.get_status(),
handler._request_summary(), request_time)
class StaticFileHandler(tornado.web.StaticFileHandler):
def set_extra_headers(self, path):
if debug:
self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
static_path = os.path.join(os.path.dirname(__file__), 'static')
settings = {
'debug': debug,
'cookie_secret': COOKIE_SECRET,
'log_function': log_function,
'websocket_ping_interval': 30.0,
}
app = tornado.web.Application([
(r"/", MainRequestHandler),
(r"/login", LoginHandler),
(r"/logs", EsphomeLogsHandler),
(r"/run", EsphomeRunHandler),
(r"/compile", EsphomeCompileHandler),
(r"/validate", EsphomeValidateHandler),
(r"/clean-mqtt", EsphomeCleanMqttHandler),
(r"/clean", EsphomeCleanHandler),
(r"/hass-config", EsphomeHassConfigHandler),
(r"/edit", EditRequestHandler),
(r"/download.bin", DownloadBinaryRequestHandler),
(r"/serial-ports", SerialPortRequestHandler),
(r"/ping", PingRequestHandler),
(r"/wizard.html", WizardRequestHandler),
(r'/static/(.*)', StaticFileHandler, {'path': static_path}),
], **settings)
if debug:
_STATIC_FILE_HASHES.clear()
return app
def start_web_server(args):
global CONFIG_DIR
global PASSWORD_DIGEST
global USING_PASSWORD
global ON_HASSIO
global USING_HASSIO_AUTH
global COOKIE_SECRET
CONFIG_DIR = args.configuration
mkdir_p(CONFIG_DIR)
mkdir_p(os.path.join(CONFIG_DIR, ".esphome"))
ON_HASSIO = args.hassio
if ON_HASSIO:
USING_HASSIO_AUTH = not bool(os.getenv('DISABLE_HA_AUTHENTICATION'))
USING_PASSWORD = False
else:
USING_HASSIO_AUTH = False
USING_PASSWORD = args.password
if USING_PASSWORD:
if IS_PY2:
PASSWORD_DIGEST = hmac.new(args.password).digest()
else:
PASSWORD_DIGEST = hmac.new(args.password.encode()).digest()
if USING_HASSIO_AUTH or USING_PASSWORD:
path = esphome_storage_path(CONFIG_DIR)
storage = EsphomeStorageJSON.load(path)
if storage is None:
storage = EsphomeStorageJSON.get_default()
storage.save(path)
COOKIE_SECRET = storage.cookie_secret
app = make_app(args.verbose)
if args.socket is not None:
_LOGGER.info("Starting dashboard web server on unix socket %s and configuration dir %s...",
args.socket, CONFIG_DIR)
server = tornado.httpserver.HTTPServer(app)
socket = tornado.netutil.bind_unix_socket(args.socket, mode=0o666)
server.add_socket(socket)
else:
_LOGGER.info("Starting dashboard web server on port %s and configuration dir %s...",
args.port, CONFIG_DIR)
app.listen(args.port)
if args.open_ui:
import webbrowser
webbrowser.open('localhost:{}'.format(args.port))
ping_thread = PingThread()
ping_thread.start()
try:
tornado.ioloop.IOLoop.current().start()
except KeyboardInterrupt:
_LOGGER.info("Shutting down...")
STOP_EVENT.set()
PING_REQUEST.set()
ping_thread.join()
if args.socket is not None:
os.remove(args.socket)

File diff suppressed because one or more lines are too long

View File

@@ -1,242 +0,0 @@
nav .brand-logo {
margin-left: 48px;
font-size: 20px;
}
main .container {
margin-top: -12vh;
flex-shrink: 0;
}
.ribbon {
width: 100%;
height: 17vh;
background-color: #3F51B5;
flex-shrink: 0;
}
.ribbon-fab:not(.tap-target-origin) {
position: absolute;
right: 24px;
top: calc(17vh + 34px);
}
i.very-large {
font-size: 8rem;
padding-top: 2px;
color: #424242;
}
.card .card-content {
padding-left: 18px;
padding-bottom: 10px;
}
.card-action a, .card-dropdown-action a {
cursor: pointer;
}
.inlinecode {
box-sizing: border-box;
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27,31,35,0.05);
border-radius: 3px;
font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;
}
.autoscroll {
display: flex;
flex-direction: column-reverse;
flex-basis: auto;
}
.autoscroll div {
flex-basis: 100%;
}
.log {
background-color: #1c1c1c;
margin-top: 0;
margin-bottom: 0;
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
font-size: 12px;
padding: 16px;
overflow: auto;
line-height: 1.45;
border-radius: 3px;
white-space: pre-wrap;
overflow-wrap: break-word;
color: #DDD;
}
.log-bold { font-weight: bold; }
.log-italic { font-style: italic; }
.log-underline { text-decoration: underline; }
.log-strikethrough { text-decoration: line-through; }
.log-underline.log-strikethrough { text-decoration: underline line-through; }
.log-secret {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.log-secret-redacted {
opacity: 0;
width: 1px;
font-size: 1px;
}
.log-fg-black { color: rgb(128,128,128); }
.log-fg-red { color: rgb(255,0,0); }
.log-fg-green { color: rgb(0,255,0); }
.log-fg-yellow { color: rgb(255,255,0); }
.log-fg-blue { color: rgb(0,0,255); }
.log-fg-magenta { color: rgb(255,0,255); }
.log-fg-cyan { color: rgb(0,255,255); }
.log-fg-white { color: rgb(187,187,187); }
.log-bg-black { background-color: rgb(0,0,0); }
.log-bg-red { background-color: rgb(255,0,0); }
.log-bg-green { background-color: rgb(0,255,0); }
.log-bg-yellow { background-color: rgb(255,255,0); }
.log-bg-blue { background-color: rgb(0,0,255); }
.log-bg-magenta { background-color: rgb(255,0,255); }
.log-bg-cyan { background-color: rgb(0,255,255); }
.log-bg-white { background-color: rgb(255,255,255); }
.modal {
width: 95%;
max-height: 90%;
height: 85% !important;
}
.page-footer {
padding-top: 0;
}
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
ul.browser-default {
padding-left: 30px;
margin-top: 10px;
margin-bottom: 15px;
}
ul.browser-default li {
list-style-type: initial;
}
ul.stepper:not(.horizontal) .step.active::before, ul.stepper:not(.horizontal) .step.done::before, ul.stepper.horizontal .step.active .step-title::before, ul.stepper.horizontal .step.done .step-title::before {
background-color: #3f51b5 !important;
}
.select-port-container {
margin-top: 8px;
margin-right: 24px;
width: 350px;
}
.select-port-container .select-dropdown {
color: #fff;
}
.select-port-container .caret {
fill: #fff;
}
.dropdown-trigger {
cursor: pointer;
}
.select-action {
width: auto !important;
height: auto !important;
}
/* https://github.com/tnhu/status-indicator/blob/master/styles.css */
.status-indicator .status-indicator-icon {
display: inline-block;
border-radius: 50%;
width: 10px;
height: 10px;
}
.status-indicator.unknown .status-indicator-icon {
background-color: rgb(216, 226, 233);
}
.status-indicator.unknown .status-indicator-text::after {
content: "Unknown status";
}
.status-indicator.offline .status-indicator-icon {
background-color: rgb(255, 77, 77);
}
.status-indicator.offline .status-indicator-text::after {
content: "Offline";
}
.status-indicator.not-responding .status-indicator-icon {
background-color: rgb(255, 170, 0);
}
.status-indicator.not-responding .status-indicator-text::after {
content: "Not Responding";
}
@keyframes status-indicator-pulse-online {
0% {
box-shadow: 0 0 0 0 rgba(75, 210, 143, .5);
}
25% {
box-shadow: 0 0 0 10px rgba(75, 210, 143, 0);
}
30% {
box-shadow: 0 0 0 0 rgba(75, 210, 143, 0);
}
}
.status-indicator.online .status-indicator-icon {
background-color: rgb(75, 210, 143);
animation-duration: 5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
animation-direction: normal;
animation-delay: 0s;
animation-fill-mode: none;
animation-name: status-indicator-pulse-online;
}
.status-indicator.online .status-indicator-text::after {
content: "Online";
}
#editor {
margin-top: 0;
margin-bottom: 0;
padding: 16px;
border-radius: 3px;
height: 100%
}
.update-available i {
vertical-align: bottom;
font-size: 20px !important;
color: #3F51B5 !important;
margin-right: -4.5px;
margin-left: -5.5px;
}
.flash-using-esphomeflasher {
vertical-align: middle;
color: #666 !important;
}

View File

@@ -1,703 +0,0 @@
document.addEventListener('DOMContentLoaded', () => {
M.AutoInit(document.body);
});
const initializeColorState = () => {
return {
bold: false,
italic: false,
underline: false,
strikethrough: false,
foregroundColor: false,
backgroundColor: false,
carriageReturn: false,
secret: false,
};
};
const colorReplace = (pre, state, text) => {
const re = /(?:\033|\\033)(?:\[(.*?)[@-~]|\].*?(?:\007|\033\\))/g;
let i = 0;
if (state.carriageReturn) {
if (text !== "\n") {
// don't remove if \r\n
pre.removeChild(pre.lastChild);
}
state.carriageReturn = false;
}
if (text.includes("\r")) {
state.carriageReturn = true;
}
const lineSpan = document.createElement("span");
lineSpan.classList.add("line");
pre.appendChild(lineSpan);
const addSpan = (content) => {
if (content === "")
return;
const span = document.createElement("span");
if (state.bold) span.classList.add("log-bold");
if (state.italic) span.classList.add("log-italic");
if (state.underline) span.classList.add("log-underline");
if (state.strikethrough) span.classList.add("log-strikethrough");
if (state.secret) span.classList.add("log-secret");
if (state.foregroundColor !== null) span.classList.add(`log-fg-${state.foregroundColor}`);
if (state.backgroundColor !== null) span.classList.add(`log-bg-${state.backgroundColor}`);
span.appendChild(document.createTextNode(content));
lineSpan.appendChild(span);
if (state.secret) {
const redacted = document.createElement("span");
redacted.classList.add("log-secret-redacted");
redacted.appendChild(document.createTextNode("[redacted]"));
lineSpan.appendChild(redacted);
}
};
while (true) {
const match = re.exec(text);
if (match === null)
break;
const j = match.index;
addSpan(text.substring(i, j));
i = j + match[0].length;
if (match[1] === undefined) continue;
for (const colorCode of match[1].split(";")) {
switch (parseInt(colorCode)) {
case 0:
// reset
state.bold = false;
state.italic = false;
state.underline = false;
state.strikethrough = false;
state.foregroundColor = null;
state.backgroundColor = null;
state.secret = false;
break;
case 1:
state.bold = true;
break;
case 3:
state.italic = true;
break;
case 4:
state.underline = true;
break;
case 5:
state.secret = true;
break;
case 6:
state.secret = false;
break;
case 9:
state.strikethrough = true;
break;
case 22:
state.bold = false;
break;
case 23:
state.italic = false;
break;
case 24:
state.underline = false;
break;
case 29:
state.strikethrough = false;
break;
case 30:
state.foregroundColor = "black";
break;
case 31:
state.foregroundColor = "red";
break;
case 32:
state.foregroundColor = "green";
break;
case 33:
state.foregroundColor = "yellow";
break;
case 34:
state.foregroundColor = "blue";
break;
case 35:
state.foregroundColor = "magenta";
break;
case 36:
state.foregroundColor = "cyan";
break;
case 37:
state.foregroundColor = "white";
break;
case 39:
state.foregroundColor = null;
break;
case 41:
state.backgroundColor = "red";
break;
case 42:
state.backgroundColor = "green";
break;
case 43:
state.backgroundColor = "yellow";
break;
case 44:
state.backgroundColor = "blue";
break;
case 45:
state.backgroundColor = "magenta";
break;
case 46:
state.backgroundColor = "cyan";
break;
case 47:
state.backgroundColor = "white";
break;
case 40:
case 49:
state.backgroundColor = null;
break;
}
}
}
addSpan(text.substring(i));
};
const removeUpdateAvailable = (filename) => {
const p = document.querySelector(`.update-available[data-node="${filename}"]`);
if (p === undefined)
return;
p.remove();
};
let configuration = "";
let wsProtocol = "ws:";
if (window.location.protocol === "https:") {
wsProtocol = 'wss:';
}
const wsUrl = wsProtocol + '//' + window.location.hostname + ':' + window.location.port;
let isFetchingPing = false;
const fetchPing = () => {
if (isFetchingPing)
return;
isFetchingPing = true;
fetch('/ping', {credentials: "same-origin"}).then(res => res.json())
.then(response => {
for (let filename in response) {
let node = document.querySelector(`.status-indicator[data-node="${filename}"]`);
if (node === null)
continue;
let status = response[filename];
let klass;
if (status === null) {
klass = 'unknown';
} else if (status === true) {
klass = 'online';
node.setAttribute('data-last-connected', Date.now().toString());
} else if (node.hasAttribute('data-last-connected')) {
const attr = parseInt(node.getAttribute('data-last-connected'));
if (Date.now() - attr <= 5000) {
klass = 'not-responding';
} else {
klass = 'offline';
}
} else {
klass = 'offline';
}
if (node.classList.contains(klass))
continue;
node.classList.remove('unknown', 'online', 'offline', 'not-responding');
node.classList.add(klass);
}
isFetchingPing = false;
});
};
setInterval(fetchPing, 2000);
fetchPing();
const portSelect = document.querySelector('.nav-wrapper select');
let ports = [];
const fetchSerialPorts = (begin=false) => {
fetch('/serial-ports', {credentials: "same-origin"}).then(res => res.json())
.then(response => {
if (ports.length === response.length) {
let allEqual = true;
for (let i = 0; i < response.length; i++) {
if (ports[i].port !== response[i].port) {
allEqual = false;
break;
}
}
if (allEqual)
return;
}
const hasNewPort = response.length >= ports.length;
ports = response;
const inst = M.FormSelect.getInstance(portSelect);
if (inst !== undefined) {
inst.destroy();
}
portSelect.innerHTML = "";
const prevSelected = getUploadPort();
for (let i = 0; i < response.length; i++) {
const val = response[i];
if (val.port === prevSelected) {
portSelect.innerHTML += `<option value="${val.port}" selected>${val.port} (${val.desc})</option>`;
} else {
portSelect.innerHTML += `<option value="${val.port}">${val.port} (${val.desc})</option>`;
}
}
M.FormSelect.init(portSelect, {});
if (!begin && hasNewPort)
M.toast({html: "Discovered new serial port."});
});
};
const getUploadPort = () => {
const inst = M.FormSelect.getInstance(portSelect);
if (inst === undefined) {
return "OTA";
}
inst._setSelectedStates();
return inst.getSelectedValues()[0];
};
setInterval(fetchSerialPorts, 5000);
fetchSerialPorts(true);
const logsModalElem = document.getElementById("modal-logs");
document.querySelectorAll(".action-show-logs").forEach((showLogs) => {
showLogs.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(logsModalElem);
const log = logsModalElem.querySelector(".log");
log.innerHTML = "";
const colorState = initializeColorState();
const stopLogsButton = logsModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = logsModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/logs");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
colorReplace(log, colorState, data.data);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully."});
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration, port: getUploadPort()});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const uploadModalElem = document.getElementById("modal-upload");
document.querySelectorAll(".action-upload").forEach((upload) => {
upload.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(uploadModalElem);
modalInstance.options['dismissible'] = false;
const log = uploadModalElem.querySelector(".log");
log.innerHTML = "";
const colorState = initializeColorState();
const stopLogsButton = uploadModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = uploadModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/run");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
colorReplace(log, colorState, data.data);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully."});
removeUpdateAvailable(configuration);
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration, port: getUploadPort()});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const validateModalElem = document.getElementById("modal-validate");
document.querySelectorAll(".action-validate").forEach((upload) => {
upload.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(validateModalElem);
const log = validateModalElem.querySelector(".log");
log.innerHTML = "";
const colorState = initializeColorState();
const stopLogsButton = validateModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = validateModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/validate");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
colorReplace(log, colorState, data.data);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({
html: `<code class="inlinecode">${configuration}</code> is valid 👍`,
displayLength: 5000,
});
} else {
M.toast({
html: `<code class="inlinecode">${configuration}</code> is invalid 😕`,
displayLength: 5000,
});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const compileModalElem = document.getElementById("modal-compile");
const downloadButton = compileModalElem.querySelector('.download-binary');
document.querySelectorAll(".action-compile").forEach((upload) => {
upload.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(compileModalElem);
modalInstance.options['dismissible'] = false;
const log = compileModalElem.querySelector(".log");
log.innerHTML = "";
const colorState = initializeColorState();
const stopLogsButton = compileModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
downloadButton.classList.add('disabled');
modalInstance.open();
const filenameField = compileModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/compile");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
colorReplace(log, colorState, data.data);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully."});
downloadButton.classList.remove('disabled');
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
downloadButton.addEventListener('click', () => {
const link = document.createElement("a");
link.download = name;
link.href = '/download.bin?configuration=' + encodeURIComponent(configuration);
document.body.appendChild(link);
link.click();
link.remove();
});
const cleanMqttModalElem = document.getElementById("modal-clean-mqtt");
document.querySelectorAll(".action-clean-mqtt").forEach((btn) => {
btn.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(cleanMqttModalElem);
const log = cleanMqttModalElem.querySelector(".log");
log.innerHTML = "";
const colorState = initializeColorState();
const stopLogsButton = cleanMqttModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = cleanMqttModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/clean-mqtt");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
colorReplace(log, colorState, data.data);
} else if (data.event === "exit") {
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const cleanModalElem = document.getElementById("modal-clean");
document.querySelectorAll(".action-clean").forEach((btn) => {
btn.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(cleanModalElem);
const log = cleanModalElem.querySelector(".log");
log.innerHTML = "";
const colorState = initializeColorState();
const stopLogsButton = cleanModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = cleanModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/clean");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
colorReplace(log, colorState, data.data);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully."});
downloadButton.classList.remove('disabled');
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const hassConfigModalElem = document.getElementById("modal-hass-config");
document.querySelectorAll(".action-hass-config").forEach((btn) => {
btn.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(hassConfigModalElem);
const log = hassConfigModalElem.querySelector(".log");
log.innerHTML = "";
const colorState = initializeColorState();
const stopLogsButton = hassConfigModalElem.querySelector(".stop-logs");
let stopped = false;
stopLogsButton.innerHTML = "Stop";
modalInstance.open();
const filenameField = hassConfigModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
const logSocket = new WebSocket(wsUrl + "/hass-config");
logSocket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.event === "line") {
colorReplace(log, colorState, data.data);
} else if (data.event === "exit") {
if (data.code === 0) {
M.toast({html: "Program exited successfully."});
downloadButton.classList.remove('disabled');
} else {
M.toast({html: `Program failed with code ${data.code}`});
}
stopLogsButton.innerHTML = "Close";
stopped = true;
}
});
logSocket.addEventListener('open', () => {
const msg = JSON.stringify({configuration: configuration});
logSocket.send(msg);
});
logSocket.addEventListener('close', () => {
if (!stopped) {
M.toast({html: 'Terminated process.'});
}
});
modalInstance.options.onCloseStart = () => {
logSocket.close();
};
});
});
const editModalElem = document.getElementById("modal-editor");
const editorElem = editModalElem.querySelector("#editor");
const editor = ace.edit(editorElem);
editor.setTheme("ace/theme/dreamweaver");
editor.session.setMode("ace/mode/yaml");
editor.session.setOption('useSoftTabs', true);
editor.session.setOption('tabSize', 2);
const saveButton = editModalElem.querySelector(".save-button");
const saveEditor = () => {
fetch(`/edit?configuration=${configuration}`, {
credentials: "same-origin",
method: "POST",
body: editor.getValue()
}).then(res => res.text()).then(() => {
M.toast({
html: `Saved <code class="inlinecode">${configuration}</code>`
});
});
};
editor.commands.addCommand({
name: 'saveCommand',
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
exec: saveEditor,
readOnly: false
});
saveButton.addEventListener('click', saveEditor);
document.querySelectorAll(".action-edit").forEach((btn) => {
btn.addEventListener('click', (e) => {
configuration = e.target.getAttribute('data-node');
const modalInstance = M.Modal.getInstance(editModalElem);
const filenameField = editModalElem.querySelector('.filename');
filenameField.innerHTML = configuration;
fetch(`/edit?configuration=${configuration}`, {credentials: "same-origin"})
.then(res => res.text()).then(response => {
editor.setValue(response, -1);
});
modalInstance.open();
});
});
const modalSetupElem = document.getElementById("modal-wizard");
const setupWizardStart = document.getElementById('setup-wizard-start');
const startWizard = () => {
const modalInstance = M.Modal.getInstance(modalSetupElem);
modalInstance.open();
modalInstance.options.onCloseStart = () => {
};
$('.stepper').activateStepper({
linearStepsNavigation: false,
autoFocusInput: true,
autoFormCreation: true,
showFeedbackLoader: true,
parallel: false
});
};
setupWizardStart.addEventListener('click', startWizard);

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,401 +0,0 @@
/*!
* jQuery UI 1.8.5
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI
*/
(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.5",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,
NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,
"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");
if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind("mousedown.ui-disableSelection selectstart.ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,
"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c.style(this,h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c.style(this,
h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});
c(function(){var a=document.createElement("div"),b=document.body;c.extend(a.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.appendChild(a).offsetHeight===100;b.removeChild(a).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,
d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)===
"_")return h;e?this.each(function(){var g=b.data(this,a);if(!g)throw"cannot call methods on "+a+" prior to initialization; attempted to call method '"+d+"'";if(!b.isFunction(g[d]))throw"no such method '"+d+"' for "+a+" widget instance";var i=g[d].apply(g,f);if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",
widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+
"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}b.each(d,function(f,h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",
false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(a._preventClickEvent){a._preventClickEvent=false;b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&
this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();
return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);c.browser.safari||a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&
this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-
this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();
d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||
this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if(!this.element[0]||!this.element[0].parentNode)return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,
b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==
a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||
0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-
(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment==
"parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&
a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),
10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():
f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+
this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+
Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-
this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=
this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.5"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");
if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;
c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=
1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;
this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=
this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","iframeFix",{start:function(){var a=
d(this).data("draggable").options;d(a.iframeFix===true?"iframe":a.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;
if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!=
"HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-
b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-
c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,
width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=c.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&
o<l+e){if(f.snapMode!="inner"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left}var t=
p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&
(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.5"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=
i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
"none";if(c[f].visible){c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight};e=="mousedown"&&c[f]._activate.call(c[f],b)}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=
d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);
(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),
c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,
{version:"1.8.5"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),
selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,
c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",
c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=
this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");
a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&
!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d=
e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.5"})})(jQuery);
(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,
arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+
this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+
b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+
"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp();this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",
null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):
d(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||
"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+
this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?
2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},
_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=
this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=
this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");
if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=
0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=
this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},
update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=
null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));
this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,
null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||
d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a==
"string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition==
"absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition==
"relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},
_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-
this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),
10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?
this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=
this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+
this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?
g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():
e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==
f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",
f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",
g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=
0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});
d.extend(d.ui.sortable,{version:"1.8.5"})})(jQuery);
jQuery.effects||function(f,j){function l(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return m.transparent;return m[f.trim(c).toLowerCase()]}function r(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return l(b)}function n(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function o(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in s||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function t(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:f.fx.speeds[b]||f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=r(b.elem,a);b.end=l(b.end);b.colorInit=
true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var m={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,
183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,
165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},p=["add","remove","toggle"],s={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,d){if(f.isFunction(b)){d=b;b=null}return this.each(function(){var e=f(this),g=e.attr("style")||" ",h=o(n.call(this)),q,u=e.attr("className");f.each(p,function(v,
i){c[i]&&e[i+"Class"](c[i])});q=o(n.call(this));e.attr("className",u);e.animate(t(h,q),a,b,function(){f.each(p,function(v,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)})})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?
f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.5",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==
null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();
var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});
c.css({position:"relative",top:0,left:0})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments);a={options:a[1],duration:a[2],callback:a[3]};var b=f.effects[c];return b&&!f.fx.off?b.call(this,a):this},_show:f.fn.show,show:function(c){if(!c||
typeof c=="number"||f.fx.speeds[c]||!f.effects[c])return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||!f.effects[c])return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||!f.effects[c]||typeof c==
"boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,
a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=
e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+
b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/
2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*
a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;
return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,
a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","left"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,g);b.effects.removeWrapper(a);
c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);
(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","left"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/
3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);
b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);
(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","left","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,c/2)}var h={};h[g.size]=
f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);
(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","left","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e=="show"?1:
0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=
0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+
e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);
(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);
(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","left"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],10)/100*
f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);
(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&
this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,
a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);
(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,
b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=
1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","left","width","height","overflow","opacity"],g=["position","top","left","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=c.effects.setMode(a,
b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};if(m=="box"||m=="both"){if(d.from.y!=
d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);a.css("overflow","hidden").css(a.from);
if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);child.to=c.effects.setTransition(child,
f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,n?e:g);c.effects.removeWrapper(a);b.callback&&
b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","left"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=(h=="pos"?"-=":"+=")+
e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);
(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","left"],e=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(e=="show")a.css(f,b=="pos"?-g:g);var i={};i[f]=(e=="show"?b=="pos"?
"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);
b.dequeue()})})}})(jQuery);
(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var f=d.closest(".ui-accordion-header");a.active=f.length?f:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",function(g){return a._keydown(g)}).next().attr("role",
"tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(g){a._clickHandler.call(a,g,this);g.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);
this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex");
this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,f=this.headers.index(a.target),g=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:g=this.headers[(f+1)%d];break;case b.LEFT:case b.UP:g=this.headers[(f-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
a.preventDefault()}if(g){c(a.target).attr("tabIndex",-1);c(g).attr("tabIndex",0);g.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);
a.next().addClass("ui-accordion-content-active")}h=a.next();f=this.active.next();g={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):h,oldContent:f};d=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(h,f,g,b,d)}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
this.active.next().addClass("ui-accordion-content-active");var f=this.active.next(),g={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:f},h=this.active=c([]);this._toggle(h,f,g)}},_toggle:function(a,b,d,f,g){var h=this,e=h.options;h.toShow=a;h.toHide=b;h.data=d;var j=function(){if(h)return h._completed.apply(h,arguments)};h._trigger("changestart",null,h.data);h.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&f?{toShow:c([]),toHide:b,complete:j,
down:g,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:g,autoHeight:e.autoHeight||e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;f=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!f[k]&&!c.easing[k])k="slide";f[k]||(f[k]=function(l){this.slide(l,{easing:k,duration:i||700})});
f[k](d)}else{if(e.collapsible&&f)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.5",animations:{slide:function(a,
b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),f=0,g={},h={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){h[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);g[i]={value:j[1],
unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(h,{step:function(j,i){if(i.prop=="height")f=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=f*g[i.prop].value+g[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide",
paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
(function(e){e.widget("ui.autocomplete",{options:{appendTo:"body",delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},_create:function(){var a=this,b=this.element[0].ownerDocument;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!a.options.disabled){var d=e.ui.keyCode;switch(c.keyCode){case d.PAGE_UP:a._move("previousPage",
c);break;case d.PAGE_DOWN:a._move("nextPage",c);break;case d.UP:a._move("previous",c);c.preventDefault();break;case d.DOWN:a._move("next",c);c.preventDefault();break;case d.ENTER:case d.NUMPAD_ENTER:a.menu.element.is(":visible")&&c.preventDefault();case d.TAB:if(!a.menu.active)return;a.menu.select(c);break;case d.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);
break}}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=e("<ul></ul>").addClass("ui-autocomplete").appendTo(e(this.options.appendTo||"body",b)[0]).mousedown(function(c){var d=a.menu.element[0];
c.target===d&&setTimeout(function(){e(document).one("mousedown",function(f){f.target!==a.element[0]&&f.target!==d&&!e.ui.contains(d,f.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,d){d=d.item.data("item.autocomplete");false!==a._trigger("focus",null,{item:d})&&/^key/.test(c.originalEvent.type)&&a.element.val(d.value)},selected:function(c,d){d=d.item.data("item.autocomplete");var f=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();
a.previous=f}if(false!==a._trigger("select",c,{item:d})){a.term=d.value;a.element.val(d.value)}a.close(c);a.selectedItem=d},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");e.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");
this.menu.element.remove();e.Widget.prototype.destroy.call(this)},_setOption:function(a,b){e.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(e(b||"body",this.element[0].ownerDocument)[0])},_initSource:function(){var a=this,b,c;if(e.isArray(this.options.source)){b=this.options.source;this.source=function(d,f){f(e.ui.autocomplete.filter(b,d.term))}}else if(typeof this.options.source==="string"){c=this.options.source;this.source=
function(d,f){a.xhr&&a.xhr.abort();a.xhr=e.getJSON(c,d,function(g,i,h){h===a.xhr&&f(g);a.xhr=null})}}else this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search")!==false)return this._search(a)},_search:function(a){this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(a.length){a=
this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this._trigger("close",a);this.menu.element.hide();this.menu.deactivate()}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return e.map(a,function(b){if(typeof b===
"string")return{label:b,value:b};return e.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1),c;this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();this.menu.element.show().position(e.extend({of:this.element},this.options.position));a=b.width("").outerWidth();c=this.element.outerWidth();b.outerWidth(Math.max(a,c))},_renderMenu:function(a,b){var c=this;e.each(b,function(d,f){c._renderItem(a,f)})},
_renderItem:function(a,b){return e("<li></li>").data("item.autocomplete",b).append(e("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});e.extend(e.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},
filter:function(a,b){var c=new RegExp(e.ui.autocomplete.escapeRegex(b),"i");return e.grep(a,function(d){return c.test(d.label||d.value||d)})}})})(jQuery);
(function(e){e.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(b){if(e(b.target).closest(".ui-menu-item a").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
-1).mouseenter(function(b){a.activate(b,e(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.attr("scrollTop"),f=this.element.height();if(c<0)this.element.attr("scrollTop",d+c);else c>=f&&this.element.attr("scrollTop",d+c-f+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:b})},
deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0);
a.length?this.activate(c,a):this.activate(c,this.element.children(b))}else this.activate(c,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||this.last())this.activate(a,this.element.children(":first"));else{var b=this.active.offset().top,c=this.element.height(),d=this.element.children("li").filter(function(){var f=e(this).offset().top-b-c+e(this).height();return f<10&&f>-10});d.length||(d=this.element.children(":last"));this.activate(a,d)}else this.activate(a,this.element.children(!this.active||
this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(":last"));else{var b=this.active.offset().top,c=this.element.height();result=this.element.children("li").filter(function(){var d=e(this).offset().top-b+c-e(this).height();return d<10&&d>-10});result.length||(result=this.element.children(":first"));this.activate(a,result)}else this.activate(a,this.element.children(!this.active||this.first()?":last":":first"))},
hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})})(jQuery);
(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return e};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",
i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",e="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",
function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(e)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");
b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");
g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",
c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("label[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var b=this.element.is(":checked");b&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=
this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||
this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),
c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary");
this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{_create:function(){this.element.addClass("ui-buttonset");this._init()},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(":button, :submit, :reset, :checkbox, :radio, a, :data(button)").filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":visible").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end().end()},
destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);
(function(d,G){function L(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>')}function E(a,b){d.extend(a,
b);for(var c in b)if(b[c]==null||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.5"}});var y=(new Date).getTime();d.extend(L.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=
f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},
_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&
b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==
""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,
c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),
true);this._updateDatepicker(b);this._updateAlternate(b)}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{});b=b&&b.constructor==
Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);
d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},
_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=
d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;
for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&
this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&
!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass,b.dpDiv).add(d("td."+d.datepicker._currentClass,b.dpDiv));c[0]?d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();
return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||
a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,
a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));
var c=String.fromCharCode(a.charCode==G?a.keyCode:a.charCode);return a.ctrlKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||
a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);
d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&
d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=d.datepicker._getBorders(b.dpDiv);b.dpDiv.find("iframe.ui-datepicker-cover").css({left:-i[0],top:-i[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,
h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a)).find("iframe.ui-datepicker-cover").css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){d(this).removeClass("ui-state-hover");
this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).addClass("ui-datepicker-prev-hover");
this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);var e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");
a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus()},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),
k=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>k&&k>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];
a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():
"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&
!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;
b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=
this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=
d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,
"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b==
"object"?b.toString():b+"";if(b=="")return null;for(var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff,f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,k=c=-1,l=-1,u=-1,j=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"?4:p=="o"?
3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,w,H){p=o(p)?H:w;for(w=0;w<p.length;w++)if(b.substr(s,p[w].length).toLowerCase()==p[w].toLowerCase()){s+=p[w].length;return w+1}throw"Unknown name at position "+s;},r=function(){if(b.charAt(s)!=a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(j)if(a.charAt(z)=="'"&&!o("'"))j=false;else r();else switch(a.charAt(z)){case "d":l=m("d");
break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":k=m("m");break;case "M":k=n("M",i,g);break;case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "'":if(o("'"))r();else j=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>
-1){k=1;l=u;do{e=this._getDaysInMonth(c,k-1);if(l<=e)break;k++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,k-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=k||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*
60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=j+1<a.length&&a.charAt(j+1)==o)&&j++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},k=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var j=0;j<a.length;j++)if(u)if(a.charAt(j)==
"'"&&!i("'"))u=false;else l+=a.charAt(j);else switch(a.charAt(j)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=k("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=k("M",b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+=
"'";else u=true;break;default:l+=a.charAt(j)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+="0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==G?a.settings[b]:this._defaults[b]},
_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,
this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,k=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,j=u.exec(h);j;){switch(j[2]||"d"){case "d":case "D":g+=
parseInt(j[1],10);break;case "w":case "W":g+=parseInt(j[1],10)*7;break;case "m":case "M":l+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break;case "y":case "Y":k+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break}j=u.exec(h)}return new Date(k,l,g)};if(b=(b=b==null?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):b)&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},
_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?
"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),k=
this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),j=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=j&&n<j?j:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,
"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-k,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+k+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+
n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+k,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+k+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+
(c?"w":"e")+'">'+r+"</span></a>";k=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;k=!h?k:this.formatDate(k,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+
y+".datepicker._gotoToday('#"+a.id+"');\">"+k+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;k=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),w=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var M=this._getDefaultDate(a),I="",C=0;C<i[0];C++){for(var N=
"",D=0;D<i[1];D++){var J=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&C==0?c?
f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,j,o,C>0||D>0,z,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var A=k?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=(t+h)%7;A+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=A+"</tr></thead><tbody>";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,
A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<A;O++){x+="<tr>";var P=!k?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var F=p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,K=B&&!H||!F[0]||j&&q<j||o&&q>o;P+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(B?" ui-datepicker-other-month":"")+(q.getTime()==J.getTime()&&g==a.selectedMonth&&
a._keyEvent||M.getTime()==q.getTime()&&M.getTime()==J.getTime()?" "+this._dayOverClass:"")+(K?" "+this._unselectableClass+" ui-state-disabled":"")+(B&&!w?"":" "+F[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!B||w)&&F[2]?' title="'+F[2]+'"':"")+(K?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(B&&!w?"&#xa0;":K?'<span class="ui-state-default">'+q.getDate()+
"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==J.getTime()?" ui-state-active":"")+(B?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=P+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&D==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");N+=x}I+=N}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':
"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var k=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),j='<div class="ui-datepicker-title">',o="";if(h||!k)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+
a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(j+=o+(h||!(k&&l)?"&#xa0;":""));if(h||!l)j+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,
i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(j+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)j+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";j+="</select>"}j+=this._get(a,"yearSuffix");if(u)j+=(h||!(k&&l)?"&#xa0;":"")+o;j+="</div>";return j},_adjustInstDate:function(a,b,c){var e=
a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,
"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);
c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,
"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=
function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new L;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.5";window["DP_jQuery_"+y]=d})(jQuery);
(function(c,j){c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",of:window,collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");
if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||"&#160;",f=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog",
"aria-labelledby":f}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var e=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);
return false}).appendTo(e);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",f).html(d).prependTo(e);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;e.find("*").add(e).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&
g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");
b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0])d=Math.max(d,c(this).css("z-index"))});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,f=d.options;if(f.modal&&!a||!f.stack&&!f.modal)return d._trigger("focus",b);if(f.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=
f.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;d.next().length&&d.appendTo("body");a._size();a._position(b.position);d.show(b.show);
a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(f){if(f.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),e=g.filter(":first");g=g.filter(":last");if(f.target===g[0]&&!f.shiftKey){e.focus(1);return false}else if(f.target===e[0]&&f.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,
f=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(f);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(e,h){h=c.isFunction(h)?{click:h,text:e}:h;e=c("<button></button>",h).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&e.button()});f.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(e){return{position:e.position,
offset:e.offset}}var b=this,d=b.options,f=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(e,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",e,a(h))},drag:function(e,h){b._trigger("drag",e,a(h))},stop:function(e,h){d.position=[h.position.left-f.scrollLeft(),h.position.top-f.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);
b._trigger("dragStop",e,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}a=a===j?this.options.resizable:a;var d=this,f=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:d._minHeight(),
handles:a,start:function(e,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",e,b(h))},resize:function(e,h){d._trigger("resize",e,b(h))},stop:function(e,h){c(this).removeClass("ui-dialog-resizing");f.height=c(this).height();f.width=c(this).width();d._trigger("resizeStop",e,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,
a.height)},_position:function(a){var b=[],d=[0,0],f;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,e){if(+b[g]===b[g]){d[g]=b[g];b[g]=e}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(f=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(a);
f||this.uiDialog.hide()},_setOption:function(a,b){var d=this,f=d.uiDialog,g=f.is(":data(resizable)"),e=false;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);e=true;break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":f.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case "draggable":b?
d._makeDraggable():f.draggable("destroy");break;case "height":e=true;break;case "maxHeight":g&&f.resizable("option","maxHeight",b);e=true;break;case "maxWidth":g&&f.resizable("option","maxWidth",b);e=true;break;case "minHeight":g&&f.resizable("option","minHeight",b);e=true;break;case "minWidth":g&&f.resizable("option","minWidth",b);e=true;break;case "position":d._position(b);break;case "resizable":g&&!b&&f.resizable("destroy");g&&typeof b==="string"&&f.resizable("option","handles",b);!g&&b!==false&&
d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||"&#160;"));break;case "width":e=true;break}c.Widget.prototype._setOption.apply(d,arguments);e&&d._size()},_size:function(){var a=this.options,b;this.element.css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();this.element.css(a.height==="auto"?{minHeight:Math.max(a.minHeight-b,0),height:c.support.minHeight?"auto":Math.max(a.minHeight-
b,0)}:{minHeight:0,height:Math.max(a.height-b,0)}).show();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.5",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),
function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=
(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){this.oldInstances.push(this.instances.splice(c.inArray(a,this.instances),1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var b=0;c.each(this.instances,function(){b=Math.max(b,this.css("z-index"))});this.maxZ=b},height:function(){var a,
b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<
b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.scrollTo&&d.document){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j=
{top:b.of.pageY,left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/
2;if(b.at[1]==="bottom")j.top+=k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+parseInt(c.curCSS(this,"marginRight",true))||0,w=m+q+parseInt(c.curCSS(this,"marginBottom",true))||0,i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]===
"center")i.top-=m/2;i.left=parseInt(i.left);i.top=parseInt(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();
b.left=d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];
b.left+=a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=
c(b),g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
(function(b,c){b.widget("ui.progressbar",{options:{value:0},min:0,max:100,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===c)return this._value();this._setOption("value",a);return this},_setOption:function(a,d){if(a==="value"){this.options.value=d;this._refreshValue();this._trigger("change")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.max,Math.max(this.min,a))},_refreshValue:function(){var a=this.value();this.valueDiv.toggleClass("ui-corner-right",
a===this.max).width(a+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.5"})})(jQuery);
(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var a=this,b=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");b.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");
this.range=d([]);if(b.range){if(b.range===true){this.range=d("<div></div>");if(!b.values)b.values=[this._valueMin(),this._valueMin()];if(b.values.length&&b.values.length!==2)b.values=[b.values[0],b.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(b.range==="min"||b.range==="max")this.range.addClass("ui-slider-range-"+b.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");
if(b.values&&b.values.length)for(;d(".ui-slider-handle",this.element).length<b.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();
else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!a.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");h=a._start(c,f);if(h===false)return}break}i=a.options.step;h=a.options.values&&a.options.values.length?(g=a.values(f)):(g=a.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=a._valueMin();break;case d.ui.keyCode.END:g=a._valueMax();break;case d.ui.keyCode.PAGE_UP:g=a._trimAlignValue(h+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=a._trimAlignValue(h-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===
a._valueMax())return;g=a._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===a._valueMin())return;g=a._trimAlignValue(h-i);break}a._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(c,e);a._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
this._mouseDestroy();return this},_mouseCapture:function(a){var b=this.options,c,e,f,h,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(b.range===true&&this.values(1)===b.min){g+=1;f=d(this.handles[g])}if(this._start(a,
g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();b=f.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-f.width()/2,top:a.pageY-b.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b=
this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b=
this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);
c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var e;if(this.options.values&&this.options.values.length){e=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>e||b===1&&c<e))c=e;if(c!==this.values(b)){e=this.values();e[b]=c;a=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e});this.values(b?0:1);a!==false&&this.values(b,c,true)}}else if(c!==this.value()){a=this._trigger("slide",a,{handle:this.handles[b],value:c});
a!==false&&this.value(c)}},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=
this._trimAlignValue(a);this._refreshValue();this._change(null,0)}return this._value()},values:function(a,b){var c,e,f;if(arguments.length>1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(a):this.value();
else return this._values()},_setOption:function(a,b){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(a){case "disabled":if(b){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a)},_values:function(a){var b,c;if(arguments.length){b=this.options.values[a];
return b=this._trimAlignValue(b)}else{b=this.options.values.slice();for(c=0;c<b.length;c+=1)b[c]=this._trimAlignValue(b[c]);return b}},_trimAlignValue:function(a){if(a<this._valueMin())return this._valueMin();if(a>this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=a%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a=
this.options.range,b=this.options,c=this,e=!this._animateOff?b.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},b.animate);if(k===1)c.range[e?"animate":"css"]({width:f-
g+"%"},{queue:false,duration:b.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},b.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:b.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},
b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.5"})})(jQuery);
(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading&#8230;</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(a,e){if(a=="selected")this.options.collapsible&&
e==this.options.selected||this.select(e);else{this.options[a]=e;this._tabify()}},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var a=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[a].concat(d.makeArray(arguments)))},_ui:function(a,e){return{tab:a,panel:e,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var a=
d(this);a.html(a.data("label.tabs")).removeData("label.tabs")})},_tabify:function(a){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var b=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||
(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))b.panels=b.panels.add(b._sanitizeSelector(i));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=b._tabId(f);f.href="#"+i;f=d("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(b.panels[g-1]||b.list);f.data("destroy.tabs",true)}b.panels=b.panels.add(f)}else c.disabled.push(g)});if(a){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(b._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=
this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return b.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
if(c.selected>=0&&this.anchors.length){this.panels.eq(c.selected).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");b.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[c.selected],b.panels[c.selected]))});this.load(c.selected)}d(window).bind("unload",function(){b.lis.add(b.anchors).unbind(".tabs");b.lis=b.anchors=b.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));this.element[c.collapsible?"addClass":
"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);a=0;for(var j;j=this.lis[a];a++)d(j)[d.inArray(a,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+g)};this.lis.bind("mouseover.tabs",
function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",function(){e(f,o);b._trigger("show",
null,b._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");b._trigger("show",null,b._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){b.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);b.element.dequeue("tabs")})}:function(g,f){b.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");b.element.dequeue("tabs")};this.anchors.bind(c.event+".tabs",
function(){var g=this,f=d(g).closest("li"),i=b.panels.filter(":not(.ui-tabs-hide)"),l=d(b._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||b.panels.filter(":animated").length||b._trigger("select",null,b._ui(this,l[0]))===false){this.blur();return false}c.selected=b.anchors.index(this);b.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=-1;c.cookie&&b._cookie(c.selected,c.cookie);b.element.queue("tabs",
function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&b._cookie(c.selected,c.cookie);b.element.queue("tabs",function(){r(g,l)});b.load(b.anchors.index(this));this.blur();return false}c.cookie&&b._cookie(c.selected,c.cookie);if(l.length){i.length&&b.element.queue("tabs",function(){s(g,i)});b.element.queue("tabs",function(){r(g,l)});b.load(b.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",
function(){return false})},_getIndex:function(a){if(typeof a=="string")a=this.anchors.index(this.anchors.filter("[href$="+a+"]"));return a},destroy:function(){var a=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=d.data(this,"href.tabs");if(e)this.href=
e;var b=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){b.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});a.cookie&&this._cookie(null,a.cookie);return this},add:function(a,e,b){if(b===p)b=this.anchors.length;
var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,a).replace(/#\{label\}/g,e));a=!a.indexOf("#")?a.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=d("#"+a);j.length||(j=d(h.panelTemplate).attr("id",a).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(b>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[b]);
j.insertBefore(this.panels[b])}h.disabled=d.map(h.disabled,function(k){return k>=b?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[b],this.panels[b]));return this},remove:function(a){a=this._getIndex(a);var e=this.options,b=this.lis.eq(a).remove(),c=this.panels.eq(a).remove();
if(b.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(a+(a+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=a}),function(h){return h>=a?--h:h});this._tabify();this._trigger("remove",null,this._ui(b.find("a")[0],c[0]));return this},enable:function(a){a=this._getIndex(a);var e=this.options;if(d.inArray(a,e.disabled)!=-1){this.lis.eq(a).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(b){return b!=a});this._trigger("enable",null,
this._ui(this.anchors[a],this.panels[a]));return this}},disable:function(a){a=this._getIndex(a);var e=this.options;if(a!=e.selected){this.lis.eq(a).addClass("ui-state-disabled");e.disabled.push(a);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))}return this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;this.anchors.eq(a).trigger(this.options.event+".tabs");return this},
load:function(a){a=this._getIndex(a);var e=this,b=this.options,c=this.anchors.eq(a)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(a).addClass("ui-state-processing");if(b.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(b.spinner)}this.xhr=d.ajax(d.extend({},b.ajaxOptions,{url:h,success:function(k,n){d(e._sanitizeSelector(c.hash)).html(k);e._cleanup();b.cache&&d.data(c,"cache.tabs",
true);e._trigger("load",null,e._ui(e.anchors[a],e.panels[a]));try{b.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[a],e.panels[a]));try{b.ajaxOptions.error(k,n,a,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},url:function(a,
e){this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.5"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(a,e){var b=this,c=this.options,h=b._rotate||(b._rotate=function(j){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var k=c.selected;b.select(++k<b.anchors.length?k:0)},a);j&&j.stopPropagation()});e=b._unrotate||(b._unrotate=!e?function(j){j.clientX&&b.rotate(null)}:
function(){t=c.selected;h()});if(a){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(b.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +0,0 @@
ace.define("ace/mode/yaml_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment",regex:"#.*$"},{token:"list.markup",regex:/^(?:-{3}|\.{3})\s*(?=#|$)/},{token:"list.markup",regex:/^\s*[\-?](?:$|\s)/},{token:"constant",regex:"!![\\w//]+"},{token:"constant.language",regex:"[&\\*][a-zA-Z0-9-_]+"},{token:["meta.tag","keyword"],regex:/^(\s*\w.*?)(:(?=\s|$))/},{token:["meta.tag","keyword"],regex:/(\w+?)(\s*:(?=\s|$))/},{token:"keyword.operator",regex:"<<\\w*:\\w*"},{token:"keyword.operator",regex:"-\\s*(?=[{])"},{token:"string",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'},{token:"string",regex:/[|>][-+\d\s]*$/,onMatch:function(e,t,n,r){var i=/^\s*/.exec(r)[0];return n.length<1?n.push(this.next):n[0]="mlString",n.length<2?n.push(i.length):n[1]=i.length,this.token},next:"mlString"},{token:"string",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"constant.numeric",regex:/(\b|[+\-\.])[\d_]+(?:(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)(?=[^\d-\w]|$)/},{token:"constant.numeric",regex:/[+\-]?\.inf\b|NaN\b|0x[\dA-Fa-f_]+|0b[10_]+/},{token:"constant.language.boolean",regex:"\\b(?:true|false|TRUE|FALSE|True|False|yes|no)\\b"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:/[^\s,:\[\]\{\}]+/}],mlString:[{token:"indent",regex:/^\s*$/},{token:"indent",regex:/^\s*/,onMatch:function(e,t,n){var r=n[1];return r>=e.length?(this.next="start",n.splice(0)):this.next="mlString",this.token},next:"mlString"},{token:"string",regex:".+"}]},this.normalizeRules()};r.inherits(s,i),t.YamlHighlightRules=s}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++n<f){o=e.getLine(n);var h=o.search(i);if(h==-1)continue;if(o[h]!="#")break;c=n}if(c>l){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<a?"start":"","";if(u==-1){if(i==a&&r[i]=="#"&&s[i]=="#")return e.foldWidgets[n-1]="",e.foldWidgets[n+1]="","start"}else if(u==i&&r[i]=="#"&&o[i]=="#"&&e.getLine(n-2).search(/\S/)==-1)return e.foldWidgets[n-1]="start",e.foldWidgets[n+1]="","";return u!=-1&&u<i?e.foldWidgets[n-1]="start":e.foldWidgets[n-1]="",i<a?"start":""}}.call(o.prototype)}),ace.define("ace/mode/yaml",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/yaml_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/folding/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./yaml_highlight_rules").YamlHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./folding/coffee").FoldMode,a=function(){this.HighlightRules=s,this.$outdent=new o,this.foldingRules=new u,this.$behaviour=this.$defaultBehaviour};r.inherits(a,i),function(){this.lineCommentStart=["#"],this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(e=="start"){var i=t.match(/^.*[\{\(\[]\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.$id="ace/mode/yaml"}.call(a.prototype),t.Mode=a}); (function() {
ace.require(["ace/mode/yaml"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@@ -1,8 +0,0 @@
ace.define("ace/theme/dreamweaver",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-dreamweaver",t.cssText='.ace-dreamweaver .ace_gutter {background: #e8e8e8;color: #333;}.ace-dreamweaver .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-dreamweaver {background-color: #FFFFFF;color: black;}.ace-dreamweaver .ace_fold {background-color: #757AD8;}.ace-dreamweaver .ace_cursor {color: black;}.ace-dreamweaver .ace_invisible {color: rgb(191, 191, 191);}.ace-dreamweaver .ace_storage,.ace-dreamweaver .ace_keyword {color: blue;}.ace-dreamweaver .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-dreamweaver .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-dreamweaver .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-dreamweaver .ace_invalid {background-color: rgb(153, 0, 0);color: white;}.ace-dreamweaver .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-dreamweaver .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-dreamweaver .ace_support.ace_type,.ace-dreamweaver .ace_support.ace_class {color: #009;}.ace-dreamweaver .ace_support.ace_php_tag {color: #f00;}.ace-dreamweaver .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-dreamweaver .ace_string {color: #00F;}.ace-dreamweaver .ace_comment {color: rgb(76, 136, 107);}.ace-dreamweaver .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-dreamweaver .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-dreamweaver .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-dreamweaver .ace_variable {color: #06F}.ace-dreamweaver .ace_xml-pe {color: rgb(104, 104, 91);}.ace-dreamweaver .ace_entity.ace_name.ace_function {color: #00F;}.ace-dreamweaver .ace_heading {color: rgb(12, 7, 255);}.ace-dreamweaver .ace_list {color:rgb(185, 6, 144);}.ace-dreamweaver .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-dreamweaver .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-dreamweaver .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-dreamweaver .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-dreamweaver .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-dreamweaver .ace_gutter-active-line {background-color : #DCDCDC;}.ace-dreamweaver .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-dreamweaver .ace_meta.ace_tag {color:#009;}.ace-dreamweaver .ace_meta.ace_tag.ace_anchor {color:#060;}.ace-dreamweaver .ace_meta.ace_tag.ace_form {color:#F90;}.ace-dreamweaver .ace_meta.ace_tag.ace_image {color:#909;}.ace-dreamweaver .ace_meta.ace_tag.ace_script {color:#900;}.ace-dreamweaver .ace_meta.ace_tag.ace_style {color:#909;}.ace-dreamweaver .ace_meta.ace_tag.ace_table {color:#099;}.ace-dreamweaver .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-dreamweaver .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}); (function() {
ace.require(["ace/theme/dreamweaver"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@@ -1,522 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ESPHome Dashboard</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="{{ get_static_file_url('materialize.min.css') }}">
<link rel="stylesheet" href="{{ get_static_file_url('materialize-stepper.min.css') }}">
<link rel="stylesheet" href="{{ get_static_file_url('esphome.css') }}">
<link rel="shortcut icon" href="{{ get_static_file_url('favicon.ico') }}">
<script src="{{ get_static_file_url('jquery.min.js') }}"></script>
<script src="{{ get_static_file_url('jquery-ui.min.js') }}"></script>
<script src="{{ get_static_file_url('materialize.min.js') }}"></script>
<script src="{{ get_static_file_url('jquery.validate.min.js') }}"></script>
<script src="{{ get_static_file_url('materialize-stepper.min.js') }}"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<header>
<nav>
<div class="nav-wrapper indigo">
<a href="#" class="brand-logo left">ESPHome Dashboard</a>
<div class="select-port-container right" id="select-port-target">
<select></select>
</div>
</div>
</nav>
{% if begin %}
<div class="tap-target pink lighten-1 select-port" data-target="select-port-target">
<div class="tap-target-content">
<h5>Select Upload Port</h5>
<p>
Here you can select where ESPHome will attempt to show logs and upload firmwares to.
By default, this is "OTA", or Over-The-Air. Note that you might have to restart the Hass.io add-on
for new serial ports to be detected.
</p>
</div>
</div>
{% end %}
<div class="ribbon"></div>
</header>
<main>
<div class="container">
{% for i, entry in enumerate(entries) %}
<div class="row">
<div class="col s12 m10 offset-m1 l12">
<div class="card horizontal">
<div class="card-image center-align hide-on-small-only">
<i class="material-icons very-large icon-grey">memory</i>
</div>
<div class="card-stacked">
<div class="card-content">
<span class="card-title">
{{ escape(entry.name) }}
<i class="material-icons right dropdown-trigger" data-target="dropdown-{{ i }}">more_vert</i>
</span>
<p>
<span class="status-indicator unknown" data-node="{{ entry.filename }}">
<span class="status-indicator-icon"></span>
<span class="status-indicator-text"></span></span>.
Full path: <code class="inlinecode">{{ escape(entry.full_path) }}</code>
</p>
{% if entry.update_available %}
<p class="update-available" data-node="{{ entry.filename }}">
<i class="material-icons">system_update</i>
Update Available! {{ entry.update_old }} &#x27A1;&#xFE0F;{{ entry.update_new }}
</p>
{% end %}
</div>
<div class="card-action">
<a class="action-upload" data-node="{{ entry.filename }}">Upload</a>
<a class="action-edit" data-node="{{ entry.filename }}">Edit</a>
<a class="action-show-logs" data-node="{{ entry.filename }}">Show Logs</a>
<a class="action-validate" data-node="{{ entry.filename }}">Validate</a>
</div>
<ul id="dropdown-{{ i }}" class="select-action dropdown-content card-dropdown-action">
<li><a class="action-clean-mqtt" data-node="{{ entry.filename }}">Clean MQTT</a></li>
<li><a class="action-clean" data-node="{{ entry.filename }}">Clean Build</a></li>
<li><a class="action-compile" data-node="{{ entry.filename }}">Compile</a></li>
<li><a class="action-hass-config" data-node="{{ entry.filename }}">HASS MQTT Configuration</a></li>
</ul>
</div>
</div>
</div>
</div>
{% end %}
</div>
<div id="modal-logs" class="modal modal-fixed-footer">
<div class="modal-content autoscroll">
<div>
<h4>Show Logs <code class="inlinecode filename"></code></h4>
<div>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Close</a>
</div>
</div>
<div id="modal-upload" class="modal modal-fixed-footer">
<div class="modal-content autoscroll">
<div>
<h4>Compile And Upload <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
</div>
<div class="modal-footer">
<a href="https://esphome.io/guides/faq.html#i-can-t-get-flashing-over-usb-to-work" target="_blank"
class="tooltipped" data-position="left" data-tooltip="Flash using esphomeflasher" rel="noreferrer">
<i class="material-icons flash-using-esphomeflasher">help_outline</i>
</a>
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
<div id="modal-compile" class="modal modal-fixed-footer">
<div class="modal-content autoscroll">
<div>
<h4>Compile <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
</div>
<div class="modal-footer">
<a href="https://esphome.io/guides/faq.html#i-can-t-get-flashing-over-usb-to-work"
target="_blank"
class="tooltipped" data-position="left" data-tooltip="Flash using esphomeflasher" rel="noreferrer">
<i class="material-icons flash-using-esphomeflasher">help_outline</i>
</a>
<a class="modal-close waves-effect waves-green btn-flat disabled download-binary">Download Binary</a>
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
<div id="modal-validate" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Validate <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
<div id="modal-wizard" class="modal">
<div class="modal-content">
<form action="/wizard.html" method="POST">
<ul class="stepper linear">
<li class="step active">
<div class="step-title waves-effect">Introduction And Name</div>
<div class="step-content">
<div class="row">
<p>
Hi there! I'm the ESPHome setup wizard and will guide you through setting up
your first ESP8266 or ESP32-powered device using ESPHome.
</p>
<a href="https://www.espressif.com/en/products/hardware/esp8266ex/overview" target="_blank">ESP8266s</a> and
their successors (the <a href="https://www.espressif.com/en/products/hardware/esp32/overview" target="_blank">ESP32s</a>)
are great low-cost microcontrollers that can communicate with the outside world using WiFi.
They're found in many devices such as the popular Sonoff/iTead, but also exist as development boards
such as the <a
href="https://esphome.io/devices/nodemcu_esp8266.html"
rel="noreferrer" target="_blank">NodeMCU</a>.
<p>
</p>
<a href="https://esphome.io/index.html" rel="noreferrer"
target="_blank">ESPHome</a>,
the tool you're using here, creates custom firmwares for these devices using YAML configuration
files (similar to the ones you might be used to with Home Assistant).
<p>
</p>
This wizard will create a basic YAML configuration file for your "node" (the microcontroller).
Later, you will be able to customize this file and add some of ESPHome's
many integrations.
<p>
<p>
First, I need to know what this node should be called. Choose this name wisely, it should be unique among
all your ESPs.
Names must be <strong>lowercase</strong> and <strong>must not contain spaces</strong> (allowed characters: <code class="inlinecode">a-z</code>,
<code class="inlinecode">0-9</code> and <code class="inlinecode">_</code>)
</p>
<div class="input-field col s12">
<input id="node_name" class="validate" type="text" name="name" required>
<label for="node_name">Name of node</label>
</div>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step">CONTINUE</button>
</div>
</div>
</li>
<li class="step">
<div class="step-title waves-effect">Device Type</div>
<div class="step-content">
<div class="row">
<p>
Great! Now I need to know what type of microcontroller you're using so that I can compile firmware for them.
Please choose the board you're using below. If you're not sure you can also use similar ones
or even the "Generic" option. In most cases that will work too.
</p>
<div class="input-field col s12">
<select id="board" name="board" required>
<optgroup label="ESP8266">
<option value="esp01_1m">Generic ESP8266 (for example Sonoff)</option>
<option value="nodemcuv2">NodeMCU</option>
<option value="d1_mini">Wemos D1 and Wemos D1 mini</option>
<option value="d1_mini_lite">Wemos D1 mini Lite</option>
<option value="d1_mini_pro">Wemos D1 mini Pro</option>
<option value="huzzah">Adafruit HUZZAH ESP8266</option>
<option value="oak">DigiStump Oak</option>
<option value="thing">Sparkfun ESP8266 Thing</option>
<option value="thingdev">Sparkfun ESP8266 Thing - Dev Board</option>
</optgroup>
<optgroup label="ESP32">
<option value="esp-wrover-kit">Generic ESP32 (WROVER Module)</option>
<option value="nodemcu-32s">NodeMCU-32S</option>
<option value="lolin_d32">Wemos Lolin D32</option>
<option value="lolin_d32_pro">Wemos Lolin D32 Pro</option>
<option value="featheresp32">Adafruit ESP32 Feather</option>
<option value="m5stack-core-esp32">M5Stack Core ESP32</option>
</optgroup>
<optgroup label="Other ESP8266s">
<option value="gen4iod">4D Systems gen4 IoD Range</option>
<option value="wifi_slot">Amperka WiFi Slot</option>
<option value="espduino">Doit ESPDuino</option>
<option value="espectro">DycodeX ESPectro Core</option>
<option value="espino">ESPino</option>
<option value="esp_wroom_02">Espressif ESP-WROOM-02 module</option>
<option value="esp12e">Espressif ESP-12E module</option>
<option value="esp01">Espressif ESP-01 512k module</option>
<option value="esp07">Espressif ESP-07 module</option>
<option value="esp8285">Generic ESP8285 module</option>
<option value="espresso_lite_v1">ESPert ESPresso Lite 1.0</option>
<option value="espresso_lite_v2">ESPert ESPresso Lite 2.0</option>
<option value="phoenix_v1">ESPert Phoenix 1.0</option>
<option value="wifinfo">WiFInfo</option>
<option value="heltec_wifi_kit_8">Heltec WiFi kit 8</option>
<option value="nodemcu">NodeMCU 0.9</option>
<option value="modwifi">Olimex MOD-WIFI</option>
<option value="wio_link">SeedStudio Wio Link</option>
<option value="wio_node">SeedStudio Wio Node</option>
<option value="sparkfunBlynk">Sparkfun Blynk Board</option>
<option value="esp210">SweetPea ESP-210</option>
<option value="espinotee">ThaiEasyElec ESPino</option>
<option value="d1">Wemos D1 Revision 1</option>
<option value="wifiduino">WiFiDuino</option>
<option value="xinabox_cw01">XinaBox CW01</option>
</optgroup>
<optgroup label="Other ESP32s">
<option value="lolin32">Wemos Lolin 32</option>
<option value="esp32dev">Espressif ESP32 Dev Module</option>
<option value="m5stack-fire">M5Stack FIRE</option>
<option value="wemosbat">Wemos WiFi &amp; Bluetooth Battery</option>
<option value="node32s">Aiyarafun Node32s</option>
<option value="espea32">April Brother ESPea32</option>
<option value="firebeetle32">DFRobot FireBeetle-ESP32</option>
<option value="esp32doit-devkit-v1">Doit ESP32 Devkit v1</option>
<option value="pocket_32">Dongsen Tech Pocket 32</option>
<option value="espectro32">DycodeX ESPectro32</option>
<option value="esp32vn-iot-uno">ESP32vn IoT Uno</option>
<option value="esp320">Electronic SweetPeas ESP320</option>
<option value="pico32">Espressif ESP32 Pico Kit</option>
<option value="odroid_esp32">Hardkernel Odroid GO</option>
<option value="heltec_wifi_kit_32">Heltec WIFI Kit 32</option>
<option value="heltec_wifi_lora_32">Heltec WIFI LoRa 32</option>
<option value="hornbill32dev">Hornbill ESP32 Dev</option>
<option value="hornbill32minima">Hornbill ESP32 Minima</option>
<option value="intorobot">IntoRobot Fig</option>
<option value="mhetesp32devkit">MH-ET Live ESP32 Devkit</option>
<option value="mhetesp32minikit">MH-ET Live ESP32 Minikit</option>
<option value="nano32">MakerAsia Nano32</option>
<option value="microduino-core-esp32">Microduino Core ESP32</option>
<option value="quantum">Noduino Quantum</option>
<option value="esp32-evb">Olimex ESP32-EVB</option>
<option value="esp32-gateway">Olimex ESP32-GATEWAY</option>
<option value="esp32-pro">Olimex ESP32-PRO</option>
<option value="onehorse32dev">Onehorse ESP32 Dev Module</option>
<option value="alksesp32">RoboticsBrno ALKS ESP32</option>
<option value="esp32thing">Sparkfun ESP32 Thing</option>
<option value="ttgo-lora32-v1">TTGO LoRa32-OLED v1</option>
<option value="espino32">ThaiEasyElec ESPino32</option>
<option value="widora-air">Widora AIR</option>
<option value="xinabox_cw02">XinaBox CW02</option>
<option value="iotbusio">oddWires IoT-Bus Io</option>
<option value="iotbusproteus">oddWires Proteus IoT-Bus</option>
<option value="nina_w10">u-blox NINA-W10 series</option>
</optgroup>
</select>
</div>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step">CONTINUE</button>
</div>
</div>
</li>
<li class="step">
<div class="step-title waves-effect">WiFi And Over-The-Air Updates</div>
<div class="step-content">
<div class="row">
<p>
Thanks! Now I need to know what WiFi Access Point I should instruct the node to connect to.
Please enter an SSID (name of the WiFi network) and password (leave empty for no password).
</p>
<div class="input-field col s12">
<input id="wifi_ssid" class="validate" type="text" name="ssid" required>
<label for="wifi_ssid">WiFi SSID</label>
</div>
<div class="input-field col s12">
<input id="wifi_password" name="psk" type="password">
<label for="wifi_password">WiFi Password</label>
</div>
<p>
ESPHome automatically sets up an Over-The-Air update server on the node
so that you only need to flash a firmware via USB once. This password
is also used to connect to the ESP from Home Assistant.
Optionally, you can set a password for this upload process here:
</p>
<div class="input-field col s12">
<input id="password" class="validate" name="password" type="password">
<label for="password">Access Password</label>
</div>
</div>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo next-step">CONTINUE</button>
</div>
</div>
</li>
<li class="step">
<div class="step-title waves-effect">Done!</div>
<div class="step-content">
<p>
Hooray! 🎉🎉🎉 You've successfully created your first ESPHome configuration file.
When you click Submit, I will save this configuration file under
<code class="inlinecode">&lt;HASS_CONFIG_FOLDER&gt;/esphome/&lt;NAME_OF_NODE&gt;.yaml</code>
and
you will be able to edit this file with the
<a href="https://www.home-assistant.io/addons/configurator/" target="_blank">HASS Configuratior add-on</a>.
</p>
<h5>Next steps</h5>
<ul class="browser-default">
<li>
Flash the firmware. This can be done using the “UPLOAD” option in the dashboard. See
<a href="https://esphome.io/index.html#devices" rel="noreferrer"
target="_blank">this</a>
for guides on how to flash different types of devices. Note that you need to restart this add-on
for newly plugged in serial devices to be detected.
</li>
<li>
With the current configuration, your node will only connect to WiFi and MQTT. To make it actually <i>do</i>
stuff, follow
<a href="https://esphome.io/guides/getting_started_hassio.html#adding-some-basic-features"
rel="noreferrer">
the rest of the getting started guide
</a>.
</li>
<li>
See the <a href="https://esphome.io/index.html" rel="noreferrer"
target="_blank">ESPHome index</a>
for a list of supported sensors/devices.
</li>
<li>
Join the <a href="https://discord.gg/KhAMKrd" target="_blank">Discord server</a> and say hi! When I
have time, I would be happy to help with issues and discuss new features.
</li>
<li>
Star <a href="https://github.com/esphome/esphome"
target="_blank">ESPHome</a> on GitHub
if you find this software awesome and report issues using the bug trackers there.
</li>
</ul>
<div class="step-actions">
<button class="waves-effect waves-dark btn indigo" type="submit">SUBMIT</button>
</div>
</div>
</li>
</ul>
</form>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat">Abort</a>
</div>
</div>
<div id="modal-clean-mqtt" class="modal modal-fixed-footer">
<div class="modal-content autoscroll">
<div>
<h4>Clean MQTT discovery <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Close</a>
</div>
</div>
<div id="modal-clean" class="modal modal-fixed-footer">
<div class="modal-content autoscroll">
<div>
<h4>Clean Build Files <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
<div id="modal-hass-config" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Generate Home Assistant Configuration <code class="inlinecode filename"></code></h4>
<div class="log-container">
<pre class="log"></pre>
</div>
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat stop-logs">Stop</a>
</div>
</div>
<div id="modal-editor" class="modal modal-fixed-footer">
<div class="modal-content">
<h4>Edit <code class="inlinecode filename"></code></h4>
<div id="editor">
</div>
</div>
<div class="modal-footer">
<a class="waves-effect waves-green btn-flat save-button">Save</a>
<a class="modal-close waves-effect waves-green btn-flat">Close</a>
</div>
</div>
<a class="btn-floating btn-large ribbon-fab waves-effect waves-light pink accent-2" id="setup-wizard-start">
<i class="material-icons">add</i>
</a>
{% if len(entries) == 0 %}
<div class="tap-target pink lighten-1 setup-wizard" data-target="setup-wizard-start">
<div class="tap-target-content">
<h5>Set up your first Node</h5>
<p>
Huh... It seems like you you don't have any ESPHome configuration files yet...
Fortunately, there's a setup wizard that will step you through setting up your first node 🎉
</p>
</div>
</div>
{% end %}
</main>
<footer class="page-footer indigo darken-1">
<div class="container">
</div>
<div class="footer-copyright">
<div class="container">
© 2019 Copyright Otto Winter, Made with <a class="grey-text text-lighten-4" href="https://materializecss.com/" target="_blank">Materialize</a>
<a class="grey-text text-lighten-4 right" href="{{ docs_link }}" target="_blank" rel="noreferrer">ESPHome {{ version }} Documentation</a>
</div>
</div>
</footer>
<script src="{{ get_static_file_url('ace.js') }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ get_static_file_url('esphome.js') }}" type="text/javascript"></script>
{% if len(entries) == 0 %}
<script>
document.addEventListener('DOMContentLoaded', () => {
const tapTargetElem = document.querySelector('.tap-target.setup-wizard');
const tapTargetInstance = M.TapTarget.getInstance(tapTargetElem);
tapTargetInstance.options.onOpen = () => {
$('.tap-target-origin').on('click', () => {
startWizard();
});
};
tapTargetInstance.open();
});
</script>
{% end %}
{% if begin %}
<script>
window.history.replaceState({}, document.title, "/");
document.addEventListener('DOMContentLoaded', () => {
const tapTargetElem = document.querySelector('.tap-target.select-port');
const tapTargetInstance = M.TapTarget.getInstance(tapTargetElem);
tapTargetInstance.open();
tapTargetInstance.contentEl.style["top"] = "300px";
tapTargetInstance.contentEl.style["padding"] = "250px";
tapTargetInstance.waveEl.style["top"] = "250px";
tapTargetInstance.waveEl.style["left"] = "250px";
tapTargetInstance.waveEl.style["width"] = "300px";
tapTargetInstance.waveEl.style["height"] = "300px";
});
</script>
{% end %}
</body>
</html>

View File

@@ -1,75 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ESPHome Dashboard</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="{{ get_static_file_url('materialize.min.css') }}">
<link href="{{ get_static_file_url('esphome.css') }}" rel="stylesheet">
<link rel="shortcut icon" href="{{ get_static_file_url('favicon.ico') }}">
<script src="{{ get_static_file_url('materialize.min.js') }}"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<header>
<nav>
<div class="nav-wrapper indigo">
<a class="brand-logo left" href="#">ESPHome Dashboard</a>
</div>
</nav>
<div class="ribbon"></div>
</header>
<main>
<div class="container">
<div class="row">
<div class="col card s10 offset-s1 m10 offset-m1 l8 offset-l2">
<form action="/login" method="post">
<div class="card-content">
<span class="card-title">Enter credentials</span>
<p>
Please login using your Home Assistant credentials.
</p>
{% if error is not None %}
<p>
{{ escape(error) }}
</p>
{% end %}
<div class="row">
<div class="input-field col s12">
<label for="username">Username</label>
<input type="text" class="validate" name="username" id="username" />
</div>
<div class="input-field col s12">
<label for="password">Password</label>
<input type="password" class="validate" name="password" id="password" />
</div>
</div>
</div>
<div class="card-action right-align">
<button class="btn indigo waves-effect waves-light" type="submit" name="action">Login</button>
</div>
</form>
</div>
</div>
</div>
</main>
<footer class="page-footer indigo darken-1">
<div class="container">
</div>
<div class="footer-copyright">
<div class="container">
© 2019 Copyright Otto Winter, Made with <a class="grey-text text-lighten-4" href="https://materializecss.com/" target="_blank">Materialize</a>
<a class="grey-text text-lighten-4 right" href="{{ docs_link }}"
target="_blank">ESPHome {{ version }} Documentation</a>
</div>
</div>
</footer>
</body>
</html>

View File

@@ -1,134 +0,0 @@
from __future__ import print_function
import errno
import logging
import os
import socket
import subprocess
from esphome.py_compat import char_to_byte, text_type
from esphome.zeroconf import Zeroconf
_LOGGER = logging.getLogger(__name__)
def ensure_unique_string(preferred_string, current_strings):
test_string = preferred_string
current_strings_set = set(current_strings)
tries = 1
while test_string in current_strings_set:
tries += 1
test_string = u"{}_{}".format(preferred_string, tries)
return test_string
def indent_all_but_first_and_last(text, padding=u' '):
lines = text.splitlines(True)
if len(lines) <= 2:
return text
return lines[0] + u''.join(padding + line for line in lines[1:-1]) + lines[-1]
def indent_list(text, padding=u' '):
return [padding + line for line in text.splitlines()]
def indent(text, padding=u' '):
return u'\n'.join(indent_list(text, padding))
# From https://stackoverflow.com/a/14945195/8924614
def cpp_string_escape(string, encoding='utf-8'):
def _should_escape(byte): # type: (int) -> bool
if not 32 <= byte < 127:
return True
if byte in (char_to_byte('\\'), char_to_byte('"')):
return True
return False
if isinstance(string, text_type):
string = string.encode(encoding)
result = ''
for character in string:
character = char_to_byte(character)
if _should_escape(character):
result += '\\%03o' % character
else:
result += chr(character)
return '"' + result + '"'
def color(the_color, message=''):
from colorlog.escape_codes import escape_codes, parse_colors
if not message:
res = parse_colors(the_color)
else:
res = parse_colors(the_color) + message + escape_codes['reset']
return res
def run_system_command(*args):
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
rc = p.returncode
return rc, stdout, stderr
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def is_ip_address(host):
parts = host.split('.')
if len(parts) != 4:
return False
try:
for p in parts:
int(p)
return True
except ValueError:
return False
def _resolve_with_zeroconf(host):
from esphome.core import EsphomeError
try:
zc = Zeroconf()
except Exception:
raise EsphomeError("Cannot start mDNS sockets, is this a docker container without "
"host network mode?")
try:
info = zc.resolve_host(host + '.')
except Exception as err:
raise EsphomeError("Error resolving mDNS hostname: {}".format(err))
finally:
zc.close()
if info is None:
raise EsphomeError("Error resolving address with mDNS: Did not respond. "
"Maybe the device is offline.")
return info
def resolve_ip_address(host):
from esphome.core import EsphomeError
try:
ip = socket.gethostbyname(host)
except socket.error as err:
if host.endswith('.local'):
ip = _resolve_with_zeroconf(host)
else:
raise EsphomeError("Error resolving IP address: {}".format(err))
return ip

View File

@@ -1,13 +0,0 @@
from __future__ import print_function
import sys
def main():
print("The esphomeyaml command has been renamed to esphome.")
print("")
print("$ esphome {}".format(' '.join(sys.argv[1:])))
return 1
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1,71 +0,0 @@
import functools
import sys
PYTHON_MAJOR = sys.version_info[0]
IS_PY2 = PYTHON_MAJOR == 2
IS_PY3 = PYTHON_MAJOR == 3
# pylint: disable=no-else-return
def safe_input(line):
if IS_PY2:
return raw_input(line)
else:
return input(line)
if IS_PY2:
text_type = unicode
string_types = (str, unicode)
integer_types = (int, long)
binary_type = str
else:
text_type = str
string_types = (str,)
integer_types = (int,)
binary_type = bytes
def byte_to_bytes(val): # type: (int) -> bytes
if IS_PY2:
return chr(val)
else:
return bytes([val])
def char_to_byte(val): # type: (str) -> int
if IS_PY2:
if isinstance(val, string_types):
return ord(val)
elif isinstance(val, int):
return val
else:
raise ValueError
else:
if isinstance(val, str):
return ord(val)
elif isinstance(val, int):
return val
else:
raise ValueError
def format_bytes(val):
if IS_PY2:
return ' '.join('{:02X}'.format(ord(x)) for x in val)
else:
return ' '.join('{:02X}'.format(x) for x in val)
def sort_by_cmp(list_, cmp):
if IS_PY2:
list_.sort(cmp=cmp)
else:
list_.sort(key=functools.cmp_to_key(cmp))
def indexbytes(buf, i):
if IS_PY3:
return buf[i]
else:
return ord(buf[i])

Some files were not shown because too many files have changed in this diff Show More