diff --git a/.gitignore b/.gitignore
index 6ca9361b11..6002612c13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,19 @@ __pycache__/
# C extensions
*.so
+# Hide sublime text stuff
+*.sublime-project
+*.sublime-workspace
+
+# Hide some OS X stuff
+.DS_Store
+.AppleDouble
+.LSOverride
+Icon
+
+# Thumbnails
+._*
+
# Distribution / packaging
.Python
build/
diff --git a/.travis.yml b/.travis.yml
index b5642478f5..fd2e759fc7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,6 +51,6 @@ matrix:
- clang-format-7 -version
- clang-apply-replacements-7 -version
script:
- - script/clang-tidy.py --all-headers -j 2 --fix
- - script/clang-format.py -i -j 2
+ - script/clang-tidy --all-headers -j 2 --fix
+ - script/clang-format -i -j 2
- script/ci-suggest-changes
diff --git a/docker/rootfs/etc/nginx/servers/direct-ssl.disabled b/docker/rootfs/etc/nginx/servers/direct-ssl.disabled
index bec9c88051..10c753471a 100644
--- a/docker/rootfs/etc/nginx/servers/direct-ssl.disabled
+++ b/docker/rootfs/etc/nginx/servers/direct-ssl.disabled
@@ -2,12 +2,12 @@ server {
listen %%port%% default_server ssl http2;
include /etc/nginx/includes/server_params.conf;
- include /etc/nginx/includes/proxy_params.conf;
- include /etc/nginx/includes/ssl_params.conf;
- # Clear Hass.io Ingress header
- proxy_set_header X-Hassio-Ingress "";
+ include /etc/nginx/includes/proxy_params.conf;
+ include /etc/nginx/includes/ssl_params.conf;
+ # Clear Hass.io Ingress header
+ proxy_set_header X-Hassio-Ingress "";
- # Redirect http requests to https on the same port.
+ # 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;
diff --git a/docker/rootfs/etc/nginx/servers/ingress.conf b/docker/rootfs/etc/nginx/servers/ingress.conf
index 6699ded0cb..3a800d97e7 100644
--- a/docker/rootfs/etc/nginx/servers/ingress.conf
+++ b/docker/rootfs/etc/nginx/servers/ingress.conf
@@ -7,10 +7,10 @@ server {
proxy_set_header X-Hassio-Ingress "YES";
location / {
- # Only allow from Hass.io supervisor
+ # Only allow from Hass.io supervisor
allow 172.30.32.2;
deny all;
proxy_pass http://esphome;
}
-}
\ No newline at end of file
+}
diff --git a/esphome/__main__.py b/esphome/__main__.py
index 4b01b5425f..199b68a6f1 100644
--- a/esphome/__main__.py
+++ b/esphome/__main__.py
@@ -1,16 +1,18 @@
from __future__ import print_function
import argparse
+import functools
import logging
import os
import sys
from datetime import datetime
from esphome import const, writer, yaml_util
+import esphome.codegen as cg
from esphome.config import iter_components, read_config, strip_default_ids
from esphome.const import CONF_BAUD_RATE, CONF_BROKER, CONF_LOGGER, CONF_OTA, \
CONF_PASSWORD, CONF_PORT
-from esphome.core import CORE, EsphomeError
+from esphome.core import CORE, EsphomeError, coroutine, coroutine_with_priority
from esphome.helpers import color, indent
from esphome.py_compat import IS_PY2, safe_input
from esphome.util import run_external_command, run_external_process, safe_print
@@ -117,12 +119,27 @@ def run_miniterm(config, port):
config, line, backtrace_state=backtrace_state)
+def wrap_to_code(name, comp):
+ coro = coroutine(comp.to_code)
+
+ @functools.wraps(comp.to_code)
+ @coroutine_with_priority(coro.priority)
+ def wrapped(conf):
+ cg.add(cg.LineComment(u"{}:".format(name)))
+ if comp.config_schema is not None:
+ cg.add(cg.LineComment(indent(yaml_util.dump(conf).decode('utf-8'))))
+ yield coro(conf)
+
+ return wrapped
+
+
def write_cpp(config):
_LOGGER.info("Generating C++ source...")
- for _, component, conf in iter_components(CORE.config):
+ for name, component, conf in iter_components(CORE.config):
if component.to_code is not None:
- CORE.add_job(component.to_code, conf)
+ coro = wrap_to_code(name, component)
+ CORE.add_job(coro, conf)
CORE.flush_tasks()
@@ -245,7 +262,7 @@ def command_vscode(args):
from esphome import vscode
CORE.config_path = args.configuration
- vscode.read_config()
+ vscode.read_config(args)
def command_compile(args, config):
@@ -423,7 +440,8 @@ def parse_args(argv):
dashboard.add_argument("--socket",
help="Make the dashboard serve under a unix socket", type=str)
- subparsers.add_parser('vscode', help=argparse.SUPPRESS)
+ vscode = subparsers.add_parser('vscode', help=argparse.SUPPRESS)
+ vscode.add_argument('--ace', action='store_true')
return parser.parse_args(argv[1:])
diff --git a/esphome/automation.py b/esphome/automation.py
index d6d568f7ef..07c3b0177f 100644
--- a/esphome/automation.py
+++ b/esphome/automation.py
@@ -128,7 +128,7 @@ def or_condition_to_code(config, condition_id, template_arg, args):
yield cg.new_Pvariable(condition_id, template_arg, conditions)
-@register_condition('not', NotCondition, validate_condition)
+@register_condition('not', NotCondition, validate_potentially_and_condition)
def not_condition_to_code(config, condition_id, template_arg, args):
condition = yield build_condition(config, template_arg, args)
yield cg.new_Pvariable(condition_id, template_arg, condition)
diff --git a/esphome/codegen.py b/esphome/codegen.py
index 30f9ce6d2f..46d652a3cd 100644
--- a/esphome/codegen.py
+++ b/esphome/codegen.py
@@ -10,16 +10,16 @@
# pylint: disable=unused-import
from esphome.cpp_generator import ( # noqa
Expression, RawExpression, RawStatement, TemplateArguments,
- StructInitializer, ArrayInitializer, safe_exp, Statement,
+ StructInitializer, ArrayInitializer, safe_exp, Statement, LineComment,
progmem_array, statement, variable, Pvariable, new_Pvariable,
add, add_global, add_library, add_build_flag, add_define,
get_variable, get_variable_with_full_id, process_lambda, is_template, templatable, MockObj,
MockObjClass)
from esphome.cpp_helpers import ( # noqa
gpio_pin_expression, register_component, build_registry_entry,
- build_registry_list, extract_registry_entry_config)
+ build_registry_list, extract_registry_entry_config, register_parented)
from esphome.cpp_types import ( # noqa
- global_ns, void, nullptr, float_, bool_, std_ns, std_string,
+ global_ns, void, nullptr, float_, double, bool_, std_ns, std_string,
std_vector, uint8, uint16, uint32, int32, const_char_ptr, NAN,
esphome_ns, App, Nameable, Component, ComponentPtr,
PollingComponent, Application, optional, arduino_json_ns, JsonObject,
diff --git a/esphome/components/adc/adc_sensor.cpp b/esphome/components/adc/adc_sensor.cpp
index aef952f27b..d0cea53d49 100644
--- a/esphome/components/adc/adc_sensor.cpp
+++ b/esphome/components/adc/adc_sensor.cpp
@@ -1,6 +1,10 @@
#include "esphome/components/adc/adc_sensor.h"
#include "esphome/core/log.h"
+#ifdef USE_ADC_SENSOR_VCC
+ADC_MODE(ADC_VCC)
+#endif
+
namespace esphome {
namespace adc {
diff --git a/esphome/components/adc/adc_sensor.h b/esphome/components/adc/adc_sensor.h
index 7d26a67ae4..3a08ff6be4 100644
--- a/esphome/components/adc/adc_sensor.h
+++ b/esphome/components/adc/adc_sensor.h
@@ -2,16 +2,13 @@
#include "esphome/core/component.h"
#include "esphome/core/esphal.h"
+#include "esphome/core/defines.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/voltage_sampler/voltage_sampler.h"
namespace esphome {
namespace adc {
-#ifdef USE_ADC_SENSOR_VCC
-ADC_MODE(ADC_VCC)
-#endif
-
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
public:
#ifdef ARDUINO_ARCH_ESP32
diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py
index b778257d66..5c15c68db7 100644
--- a/esphome/components/api/__init__.py
+++ b/esphome/components/api/__init__.py
@@ -87,7 +87,7 @@ HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema({
cv.string: cv.string,
}),
cv.Optional(CONF_VARIABLES): cv.Schema({
- cv.string: cv.lambda_,
+ cv.string: cv.returning_lambda,
}),
})
diff --git a/esphome/components/bang_bang/climate.py b/esphome/components/bang_bang/climate.py
index 7837749ba7..88828ef44f 100644
--- a/esphome/components/bang_bang/climate.py
+++ b/esphome/components/bang_bang/climate.py
@@ -7,7 +7,7 @@ from esphome.const import CONF_AWAY_CONFIG, CONF_COOL_ACTION, \
CONF_ID, CONF_IDLE_ACTION, CONF_SENSOR
bang_bang_ns = cg.esphome_ns.namespace('bang_bang')
-BangBangClimate = bang_bang_ns.class_('BangBangClimate', climate.ClimateDevice)
+BangBangClimate = bang_bang_ns.class_('BangBangClimate', climate.Climate)
BangBangClimateTargetTempConfig = bang_bang_ns.struct('BangBangClimateTargetTempConfig')
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py
index 336870392d..70a6ce0c58 100644
--- a/esphome/components/binary_sensor/__init__.py
+++ b/esphome/components/binary_sensor/__init__.py
@@ -70,7 +70,7 @@ def delayed_off_filter_to_code(config, filter_id):
yield var
-@FILTER_REGISTRY.register('lambda', LambdaFilter, cv.lambda_)
+@FILTER_REGISTRY.register('lambda', LambdaFilter, cv.returning_lambda)
def lambda_filter_to_code(config, filter_id):
lambda_ = yield cg.process_lambda(config, [(bool, 'x')], return_type=cg.optional.template(bool))
yield cg.new_Pvariable(filter_id, lambda_)
diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp
index 439847f72a..39b88f867c 100644
--- a/esphome/components/binary_sensor/filter.cpp
+++ b/esphome/components/binary_sensor/filter.cpp
@@ -5,7 +5,7 @@ namespace esphome {
namespace binary_sensor {
-static const char *TAG = "something.Filter";
+static const char *TAG = "sensor.filter";
void Filter::output(bool value, bool is_initial) {
if (!this->dedup_.next(value))
diff --git a/esphome/components/ble_presence/ble_presence_device.cpp b/esphome/components/ble_presence/ble_presence_device.cpp
index 5a69d48a86..ad6b5ece88 100644
--- a/esphome/components/ble_presence/ble_presence_device.cpp
+++ b/esphome/components/ble_presence/ble_presence_device.cpp
@@ -6,7 +6,7 @@
namespace esphome {
namespace ble_presence {
-static const char *TAG = "something.something";
+static const char *TAG = "ble_presence";
void BLEPresenceDevice::dump_config() { LOG_BINARY_SENSOR("", "BLE Presence", this); }
diff --git a/esphome/components/bme680/bme680.cpp b/esphome/components/bme680/bme680.cpp
index 5c48753ad8..77f381664b 100644
--- a/esphome/components/bme680/bme680.cpp
+++ b/esphome/components/bme680/bme680.cpp
@@ -232,7 +232,7 @@ float BME680Component::get_setup_priority() const { return setup_priority::DATA;
void BME680Component::update() {
uint8_t meas_control = 0; // No need to fetch, we're setting all fields
meas_control |= (this->temperature_oversampling_ & 0b111) << 5;
- meas_control |= (this->pressure_oversampling_ & 0b111) << 5;
+ meas_control |= (this->pressure_oversampling_ & 0b111) << 2;
meas_control |= 0b01; // forced mode
if (!this->write_byte(BME680_REGISTER_CONTROL_MEAS, meas_control)) {
this->status_set_warning();
diff --git a/esphome/components/ccs811/__init__.py b/esphome/components/ccs811/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/esphome/components/ccs811/ccs811.cpp b/esphome/components/ccs811/ccs811.cpp
new file mode 100644
index 0000000000..538d7fe1f5
--- /dev/null
+++ b/esphome/components/ccs811/ccs811.cpp
@@ -0,0 +1,147 @@
+#include "ccs811.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace ccs811 {
+
+static const char *TAG = "ccs811";
+
+// based on
+// - https://cdn.sparkfun.com/datasheets/BreakoutBoards/CCS811_Programming_Guide.pdf
+
+#define CHECK_TRUE(f, error_code) \
+ if (!(f)) { \
+ this->mark_failed(); \
+ this->error_code_ = (error_code); \
+ return; \
+ }
+
+#define CHECKED_IO(f) CHECK_TRUE(f, COMMUNICAITON_FAILED)
+
+void CCS811Component::setup() {
+ // page 9 programming guide - hwid is always 0x81
+ uint8_t hw_id;
+ CHECKED_IO(this->read_byte(0x20, &hw_id))
+ CHECK_TRUE(hw_id == 0x81, INVALID_ID)
+
+ // software reset, page 3 - allowed to fail
+ this->write_bytes(0xFF, {0x11, 0xE5, 0x72, 0x8A});
+ delay(5);
+
+ // page 10, APP_START
+ CHECK_TRUE(!this->status_has_error_(), SENSOR_REPORTED_ERROR)
+ CHECK_TRUE(this->status_app_is_valid_(), APP_INVALID)
+ CHECK_TRUE(this->write_bytes(0xF4, {}), APP_START_FAILED)
+ // App setup, wait for it to load
+ delay(1);
+
+ // set MEAS_MODE (page 5)
+ uint8_t meas_mode = 0;
+ uint32_t interval = this->get_update_interval();
+ if (interval <= 1000)
+ meas_mode = 1 << 4;
+ else if (interval <= 10000)
+ meas_mode = 2 << 4;
+ else
+ meas_mode = 3 << 4;
+
+ CHECKED_IO(this->write_byte(0x01, meas_mode))
+
+ if (this->baseline_.has_value()) {
+ // baseline available, write to sensor
+ this->write_bytes(0x11, decode_uint16(*this->baseline_));
+ }
+}
+void CCS811Component::update() {
+ if (!this->status_has_data_())
+ this->status_set_warning();
+
+ // page 12 - alg result data
+ auto alg_data = this->read_bytes<4>(0x02);
+ if (!alg_data.has_value()) {
+ ESP_LOGW(TAG, "Reading CCS811 data failed!");
+ this->status_set_warning();
+ return;
+ }
+ auto res = *alg_data;
+ uint16_t co2 = encode_uint16(res[0], res[1]);
+ uint16_t tvoc = encode_uint16(res[2], res[3]);
+
+ // also print baseline
+ auto baseline_data = this->read_bytes<2>(0x11);
+ uint16_t baseline = 0;
+ if (baseline_data.has_value()) {
+ baseline = encode_uint16((*baseline_data)[0], (*baseline_data)[1]);
+ }
+
+ ESP_LOGD(TAG, "Got co2=%u ppm, tvoc=%u ppb, baseline=0x%04X", co2, tvoc, baseline);
+
+ if (this->co2_ != nullptr)
+ this->co2_->publish_state(co2);
+ if (this->tvoc_ != nullptr)
+ this->tvoc_->publish_state(tvoc);
+
+ this->status_clear_warning();
+
+ this->send_env_data_();
+}
+void CCS811Component::send_env_data_() {
+ if (this->humidity_ == nullptr && this->temperature_ == nullptr)
+ return;
+
+ float humidity = NAN;
+ if (this->humidity_ != nullptr)
+ humidity = this->humidity_->state;
+ if (isnan(humidity) || humidity < 0 || humidity > 100)
+ humidity = 50;
+ float temperature = NAN;
+ if (this->temperature_ != nullptr)
+ temperature = this->temperature_->state;
+ if (isnan(temperature) || temperature < -25 || temperature > 50)
+ temperature = 25;
+ // temperature has a 25° offset to allow negative temperatures
+ temperature += 25;
+
+ // only 0.5 fractions are supported (application note)
+ auto hum_value = static_cast(roundf(humidity * 2));
+ auto temp_value = static_cast(roundf(temperature * 2));
+ this->write_bytes(0x05, {hum_value, 0x00, temp_value, 0x00});
+}
+void CCS811Component::dump_config() {
+ ESP_LOGCONFIG(TAG, "CCS811");
+ LOG_I2C_DEVICE(this)
+ LOG_UPDATE_INTERVAL(this)
+ LOG_SENSOR(" ", "CO2 Sensor", this->co2_)
+ LOG_SENSOR(" ", "TVOC Sensor", this->tvoc_)
+ if (this->baseline_) {
+ ESP_LOGCONFIG(TAG, " Baseline: %04X", *this->baseline_);
+ } else {
+ ESP_LOGCONFIG(TAG, " Baseline: NOT SET");
+ }
+ if (this->is_failed()) {
+ switch (this->error_code_) {
+ case COMMUNICAITON_FAILED:
+ ESP_LOGW(TAG, "Communication failed! Is the sensor connected?");
+ break;
+ case INVALID_ID:
+ ESP_LOGW(TAG, "Sensor reported an invalid ID. Is this a CCS811?");
+ break;
+ case SENSOR_REPORTED_ERROR:
+ ESP_LOGW(TAG, "Sensor reported internal error");
+ break;
+ case APP_INVALID:
+ ESP_LOGW(TAG, "Sensor reported invalid APP installed.");
+ break;
+ case APP_START_FAILED:
+ ESP_LOGW(TAG, "Sensor reported APP start failed.");
+ break;
+ case UNKNOWN:
+ default:
+ ESP_LOGW(TAG, "Unknown setup error!");
+ break;
+ }
+ }
+}
+
+} // namespace ccs811
+} // namespace esphome
diff --git a/esphome/components/ccs811/ccs811.h b/esphome/components/ccs811/ccs811.h
new file mode 100644
index 0000000000..cea919c9a5
--- /dev/null
+++ b/esphome/components/ccs811/ccs811.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/core/preferences.h"
+#include "esphome/components/sensor/sensor.h"
+#include "esphome/components/i2c/i2c.h"
+
+namespace esphome {
+namespace ccs811 {
+
+class CCS811Component : public PollingComponent, public i2c::I2CDevice {
+ public:
+ void set_co2(sensor::Sensor *co2) { co2_ = co2; }
+ void set_tvoc(sensor::Sensor *tvoc) { tvoc_ = tvoc; }
+ void set_baseline(uint16_t baseline) { baseline_ = baseline; }
+ void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
+ void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
+
+ /// Setup the sensor and test for a connection.
+ void setup() override;
+ /// Schedule temperature+pressure readings.
+ void update() override;
+
+ void dump_config() override;
+
+ float get_setup_priority() const override { return setup_priority::DATA; }
+
+ protected:
+ optional read_status_() { return this->read_byte(0x00); }
+ bool status_has_error_() { return this->read_status_().value_or(1) & 1; }
+ bool status_app_is_valid_() { return this->read_status_().value_or(0) & (1 << 4); }
+ bool status_has_data_() { return this->read_status_().value_or(0) & (1 << 3); }
+ void send_env_data_();
+
+ enum ErrorCode {
+ UNKNOWN,
+ COMMUNICAITON_FAILED,
+ INVALID_ID,
+ SENSOR_REPORTED_ERROR,
+ APP_INVALID,
+ APP_START_FAILED,
+ } error_code_{UNKNOWN};
+
+ sensor::Sensor *co2_{nullptr};
+ sensor::Sensor *tvoc_{nullptr};
+ optional baseline_{};
+ /// Input sensor for humidity reading.
+ sensor::Sensor *humidity_{nullptr};
+ /// Input sensor for temperature reading.
+ sensor::Sensor *temperature_{nullptr};
+};
+
+} // namespace ccs811
+} // namespace esphome
diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py
new file mode 100644
index 0000000000..a8020c77f7
--- /dev/null
+++ b/esphome/components/ccs811/sensor.py
@@ -0,0 +1,46 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import i2c, sensor
+from esphome.const import CONF_ID, ICON_RADIATOR, UNIT_PARTS_PER_MILLION, \
+ UNIT_PARTS_PER_BILLION, CONF_TEMPERATURE, CONF_HUMIDITY, ICON_PERIODIC_TABLE_CO2
+
+DEPENDENCIES = ['i2c']
+
+ccs811_ns = cg.esphome_ns.namespace('ccs811')
+CCS811Component = ccs811_ns.class_('CCS811Component', cg.PollingComponent, i2c.I2CDevice)
+
+CONF_ECO2 = 'eco2'
+CONF_TVOC = 'tvoc'
+CONF_BASELINE = 'baseline'
+
+CONFIG_SCHEMA = cv.Schema({
+ cv.GenerateID(): cv.declare_id(CCS811Component),
+ cv.Required(CONF_ECO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, ICON_PERIODIC_TABLE_CO2,
+ 0),
+ cv.Required(CONF_TVOC): sensor.sensor_schema(UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0),
+
+ cv.Optional(CONF_BASELINE): cv.hex_uint16_t,
+ cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor),
+ cv.Optional(CONF_HUMIDITY): cv.use_id(sensor.Sensor),
+}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x5A))
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield i2c.register_i2c_device(var, config)
+
+ sens = yield sensor.new_sensor(config[CONF_ECO2])
+ cg.add(var.set_co2(sens))
+ sens = yield sensor.new_sensor(config[CONF_TVOC])
+ cg.add(var.set_tvoc(sens))
+
+ if CONF_BASELINE in config:
+ cg.add(var.set_baseline(config[CONF_BASELINE]))
+
+ if CONF_TEMPERATURE in config:
+ sens = yield cg.get_variable(config[CONF_TEMPERATURE])
+ cg.add(var.set_temperature(sens))
+ if CONF_HUMIDITY in config:
+ sens = yield cg.get_variable(config[CONF_HUMIDITY])
+ cg.add(var.set_humidity(sens))
diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py
index ba0b37ed8c..8c9db58694 100644
--- a/esphome/components/climate/__init__.py
+++ b/esphome/components/climate/__init__.py
@@ -12,7 +12,7 @@ IS_PLATFORM_COMPONENT = True
climate_ns = cg.esphome_ns.namespace('climate')
-ClimateDevice = climate_ns.class_('Climate', cg.Nameable)
+Climate = climate_ns.class_('Climate', cg.Nameable)
ClimateCall = climate_ns.class_('ClimateCall')
ClimateTraits = climate_ns.class_('ClimateTraits')
@@ -30,7 +30,7 @@ validate_climate_mode = cv.enum(CLIMATE_MODES, upper=True)
ControlAction = climate_ns.class_('ControlAction', automation.Action)
CLIMATE_SCHEMA = cv.MQTT_COMMAND_COMPONENT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_id(ClimateDevice),
+ cv.GenerateID(): cv.declare_id(Climate),
cv.OnlyWith(CONF_MQTT_ID, 'mqtt'): cv.declare_id(mqtt.MQTTClimateComponent),
cv.Optional(CONF_VISUAL, default={}): cv.Schema({
cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
@@ -68,7 +68,7 @@ def register_climate(var, config):
CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema({
- cv.Required(CONF_ID): cv.use_id(ClimateDevice),
+ cv.Required(CONF_ID): cv.use_id(Climate),
cv.Optional(CONF_MODE): cv.templatable(validate_climate_mode),
cv.Optional(CONF_TARGET_TEMPERATURE): cv.templatable(cv.temperature),
cv.Optional(CONF_TARGET_TEMPERATURE_LOW): cv.templatable(cv.temperature),
diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp
index 5e04182a78..2b40f932f9 100644
--- a/esphome/components/climate/climate.cpp
+++ b/esphome/components/climate/climate.cpp
@@ -207,11 +207,6 @@ ClimateTraits Climate::get_traits() {
return traits;
}
-#ifdef USE_MQTT_CLIMATE
-MQTTClimateComponent *Climate::get_mqtt() const { return this->mqtt_; }
-void Climate::set_mqtt(MQTTClimateComponent *mqtt) { this->mqtt_ = mqtt; }
-#endif
-
void Climate::set_visual_min_temperature_override(float visual_min_temperature_override) {
this->visual_min_temperature_override_ = visual_min_temperature_override;
}
diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h
index 102d700d58..c58eed1a7c 100644
--- a/esphome/components/climate/climate.h
+++ b/esphome/components/climate/climate.h
@@ -169,11 +169,6 @@ class Climate : public Nameable {
*/
ClimateTraits get_traits();
-#ifdef USE_MQTT_COVER
- MQTTClimateComponent *get_mqtt() const;
- void set_mqtt(MQTTClimateComponent *mqtt);
-#endif
-
void set_visual_min_temperature_override(float visual_min_temperature_override);
void set_visual_max_temperature_override(float visual_max_temperature_override);
void set_visual_temperature_step_override(float visual_temperature_step_override);
diff --git a/esphome/components/climate/climate_mode.cpp b/esphome/components/climate/climate_mode.cpp
index 07b97f4f33..32d42b706f 100644
--- a/esphome/components/climate/climate_mode.cpp
+++ b/esphome/components/climate/climate_mode.cpp
@@ -6,13 +6,13 @@ namespace climate {
const char *climate_mode_to_string(ClimateMode mode) {
switch (mode) {
case CLIMATE_MODE_OFF:
- return "OFF";
+ return "off";
case CLIMATE_MODE_AUTO:
- return "AUTO";
+ return "auto";
case CLIMATE_MODE_COOL:
- return "COOL";
+ return "cool";
case CLIMATE_MODE_HEAT:
- return "HEAT";
+ return "heat";
default:
return "UNKNOWN";
}
diff --git a/esphome/components/custom/binary_sensor/__init__.py b/esphome/components/custom/binary_sensor/__init__.py
index b08988cc5a..83b4a3dad8 100644
--- a/esphome/components/custom/binary_sensor/__init__.py
+++ b/esphome/components/custom/binary_sensor/__init__.py
@@ -8,7 +8,7 @@ CustomBinarySensorConstructor = custom_ns.class_('CustomBinarySensorConstructor'
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CustomBinarySensorConstructor),
- cv.Required(CONF_LAMBDA): cv.lambda_,
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_BINARY_SENSORS): cv.ensure_list(binary_sensor.BINARY_SENSOR_SCHEMA),
})
diff --git a/esphome/components/custom/climate/__init__.py b/esphome/components/custom/climate/__init__.py
new file mode 100644
index 0000000000..ed19452dee
--- /dev/null
+++ b/esphome/components/custom/climate/__init__.py
@@ -0,0 +1,26 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import climate
+from esphome.const import CONF_ID, CONF_LAMBDA
+from .. import custom_ns
+
+CustomClimateConstructor = custom_ns.class_('CustomClimateConstructor')
+CONF_CLIMATES = 'climates'
+
+CONFIG_SCHEMA = cv.Schema({
+ cv.GenerateID(): cv.declare_id(CustomClimateConstructor),
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
+ cv.Required(CONF_CLIMATES): cv.ensure_list(climate.CLIMATE_SCHEMA),
+})
+
+
+def to_code(config):
+ template_ = yield cg.process_lambda(
+ config[CONF_LAMBDA], [],
+ return_type=cg.std_vector.template(climate.Climate.operator('ptr')))
+
+ rhs = CustomClimateConstructor(template_)
+ custom = cg.variable(config[CONF_ID], rhs)
+ for i, conf in enumerate(config[CONF_CLIMATES]):
+ rhs = custom.Pget_climate(i)
+ yield climate.register_climate(rhs, conf)
diff --git a/esphome/components/custom/climate/custom_climate.h b/esphome/components/custom/climate/custom_climate.h
new file mode 100644
index 0000000000..250d83f69f
--- /dev/null
+++ b/esphome/components/custom/climate/custom_climate.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/components/climate/climate.h"
+
+namespace esphome {
+namespace custom {
+
+class CustomClimateConstructor {
+ public:
+ CustomClimateConstructor(const std::function()> &init) { this->climates_ = init(); }
+
+ climate::Climate *get_climate(int i) { return this->climates_[i]; }
+
+ protected:
+ std::vector climates_;
+};
+
+} // namespace custom
+} // namespace esphome
diff --git a/esphome/components/custom/cover/__init__.py b/esphome/components/custom/cover/__init__.py
new file mode 100644
index 0000000000..3ab3ec1d04
--- /dev/null
+++ b/esphome/components/custom/cover/__init__.py
@@ -0,0 +1,26 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import cover
+from esphome.const import CONF_ID, CONF_LAMBDA
+from .. import custom_ns
+
+CustomCoverConstructor = custom_ns.class_('CustomCoverConstructor')
+CONF_COVERS = 'covers'
+
+CONFIG_SCHEMA = cv.Schema({
+ cv.GenerateID(): cv.declare_id(CustomCoverConstructor),
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
+ cv.Required(CONF_COVERS): cv.ensure_list(cover.COVER_SCHEMA),
+})
+
+
+def to_code(config):
+ template_ = yield cg.process_lambda(
+ config[CONF_LAMBDA], [],
+ return_type=cg.std_vector.template(cover.Cover.operator('ptr')))
+
+ rhs = CustomCoverConstructor(template_)
+ custom = cg.variable(config[CONF_ID], rhs)
+ for i, conf in enumerate(config[CONF_COVERS]):
+ rhs = custom.Pget_cover(i)
+ yield cover.register_cover(rhs, conf)
diff --git a/esphome/components/custom/cover/custom_cover.h b/esphome/components/custom/cover/custom_cover.h
new file mode 100644
index 0000000000..71f271bc86
--- /dev/null
+++ b/esphome/components/custom/cover/custom_cover.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "esphome/components/cover/cover.h"
+
+namespace esphome {
+namespace custom {
+
+class CustomCoverConstructor {
+ public:
+ CustomCoverConstructor(const std::function()> &init) { this->covers_ = init(); }
+
+ cover::Cover *get_cover(int i) { return this->covers_[i]; }
+
+ protected:
+ std::vector covers_;
+};
+
+} // namespace custom
+} // namespace esphome
diff --git a/esphome/components/custom/light/__init__.py b/esphome/components/custom/light/__init__.py
new file mode 100644
index 0000000000..24b284941e
--- /dev/null
+++ b/esphome/components/custom/light/__init__.py
@@ -0,0 +1,26 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import light
+from esphome.const import CONF_ID, CONF_LAMBDA
+from .. import custom_ns
+
+CustomLightOutputConstructor = custom_ns.class_('CustomLightOutputConstructor')
+CONF_LIGHTS = 'lights'
+
+CONFIG_SCHEMA = cv.Schema({
+ cv.GenerateID(): cv.declare_id(CustomLightOutputConstructor),
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
+ cv.Required(CONF_LIGHTS): cv.ensure_list(light.RGB_LIGHT_SCHEMA),
+})
+
+
+def to_code(config):
+ template_ = yield cg.process_lambda(
+ config[CONF_LAMBDA], [],
+ return_type=cg.std_vector.template(light.LightOutput.operator('ptr')))
+
+ rhs = CustomLightOutputConstructor(template_)
+ custom = cg.variable(config[CONF_ID], rhs)
+ for i, conf in enumerate(config[CONF_LIGHTS]):
+ rhs = custom.Pget_light(i)
+ yield light.register_light(rhs, conf)
diff --git a/esphome/components/custom/light/custom_light_output.h b/esphome/components/custom/light/custom_light_output.h
new file mode 100644
index 0000000000..744e99b889
--- /dev/null
+++ b/esphome/components/custom/light/custom_light_output.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/components/light/light_output.h"
+
+namespace esphome {
+namespace custom {
+
+class CustomLightOutputConstructor {
+ public:
+ CustomLightOutputConstructor(const std::function()> &init) {
+ this->outputs_ = init();
+ }
+
+ light::LightOutput *get_light(int i) { return this->outputs_[i]; }
+
+ protected:
+ std::vector outputs_;
+};
+
+} // namespace custom
+} // namespace esphome
diff --git a/esphome/components/custom/output/__init__.py b/esphome/components/custom/output/__init__.py
index cc4391d4ae..6042863872 100644
--- a/esphome/components/custom/output/__init__.py
+++ b/esphome/components/custom/output/__init__.py
@@ -7,42 +7,27 @@ from .. import custom_ns
CustomBinaryOutputConstructor = custom_ns.class_('CustomBinaryOutputConstructor')
CustomFloatOutputConstructor = custom_ns.class_('CustomFloatOutputConstructor')
-BINARY_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_id(CustomBinaryOutputConstructor),
- cv.Required(CONF_LAMBDA): cv.lambda_,
- cv.Required(CONF_TYPE): 'binary',
- cv.Required(CONF_OUTPUTS):
- cv.ensure_list(output.BINARY_OUTPUT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_id(output.BinaryOutput),
- })),
-})
+CONF_BINARY = 'binary'
+CONF_FLOAT = 'float'
-FLOAT_SCHEMA = cv.Schema({
- cv.GenerateID(): cv.declare_id(CustomFloatOutputConstructor),
- cv.Required(CONF_LAMBDA): cv.lambda_,
- cv.Required(CONF_TYPE): 'float',
- cv.Required(CONF_OUTPUTS):
- cv.ensure_list(output.FLOAT_OUTPUT_SCHEMA.extend({
- cv.GenerateID(): cv.declare_id(output.FloatOutput),
- })),
-})
-
-
-def validate_custom_output(value):
- if not isinstance(value, dict):
- raise cv.Invalid("Value must be dict")
- if CONF_TYPE not in value:
- raise cv.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 cv.Invalid("type must either be binary or float, not {}!".format(type))
-
-
-CONFIG_SCHEMA = validate_custom_output
+CONFIG_SCHEMA = cv.typed_schema({
+ CONF_BINARY: cv.Schema({
+ cv.GenerateID(): cv.declare_id(CustomBinaryOutputConstructor),
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
+ cv.Required(CONF_OUTPUTS):
+ cv.ensure_list(output.BINARY_OUTPUT_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(output.BinaryOutput),
+ })),
+ }),
+ CONF_FLOAT: cv.Schema({
+ cv.GenerateID(): cv.declare_id(CustomFloatOutputConstructor),
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
+ cv.Required(CONF_OUTPUTS):
+ cv.ensure_list(output.FLOAT_OUTPUT_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(output.FloatOutput),
+ })),
+ })
+}, lower=True)
def to_code(config):
diff --git a/esphome/components/custom/sensor/__init__.py b/esphome/components/custom/sensor/__init__.py
index 622d347d8a..e6da4a733c 100644
--- a/esphome/components/custom/sensor/__init__.py
+++ b/esphome/components/custom/sensor/__init__.py
@@ -8,7 +8,7 @@ CustomSensorConstructor = custom_ns.class_('CustomSensorConstructor')
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CustomSensorConstructor),
- cv.Required(CONF_LAMBDA): cv.lambda_,
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_SENSORS): cv.ensure_list(sensor.SENSOR_SCHEMA),
})
diff --git a/esphome/components/custom/switch/__init__.py b/esphome/components/custom/switch/__init__.py
index dc5cb325bd..fd619e6769 100644
--- a/esphome/components/custom/switch/__init__.py
+++ b/esphome/components/custom/switch/__init__.py
@@ -8,7 +8,7 @@ CustomSwitchConstructor = custom_ns.class_('CustomSwitchConstructor')
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CustomSwitchConstructor),
- cv.Required(CONF_LAMBDA): cv.lambda_,
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_SWITCHES):
cv.ensure_list(switch.SWITCH_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(switch.Switch),
diff --git a/esphome/components/custom/text_sensor/__init__.py b/esphome/components/custom/text_sensor/__init__.py
index 38675da142..58db2a3f9e 100644
--- a/esphome/components/custom/text_sensor/__init__.py
+++ b/esphome/components/custom/text_sensor/__init__.py
@@ -8,7 +8,7 @@ CustomTextSensorConstructor = custom_ns.class_('CustomTextSensorConstructor')
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CustomTextSensorConstructor),
- cv.Required(CONF_LAMBDA): cv.lambda_,
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Required(CONF_TEXT_SENSORS):
cv.ensure_list(text_sensor.TEXT_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(text_sensor.TextSensor),
diff --git a/esphome/components/custom_component/__init__.py b/esphome/components/custom_component/__init__.py
index 0dcbb163c8..198aa6a9ec 100644
--- a/esphome/components/custom_component/__init__.py
+++ b/esphome/components/custom_component/__init__.py
@@ -8,7 +8,7 @@ CustomComponentConstructor = custom_component_ns.class_('CustomComponentConstruc
MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(CustomComponentConstructor),
- cv.Required(CONF_LAMBDA): cv.lambda_,
+ cv.Required(CONF_LAMBDA): cv.returning_lambda,
cv.Optional(CONF_COMPONENTS): cv.ensure_list(cv.Schema({
cv.GenerateID(): cv.declare_id(cg.Component)
}).extend(cv.COMPONENT_SCHEMA)),
diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py
index 2236f919f2..df9d561995 100644
--- a/esphome/components/dallas/sensor.py
+++ b/esphome/components/dallas/sensor.py
@@ -13,7 +13,7 @@ CONFIG_SCHEMA = cv.All(sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1).e
cv.Optional(CONF_ADDRESS): cv.hex_int,
cv.Optional(CONF_INDEX): cv.positive_int,
- cv.Optional(CONF_RESOLUTION, default=12): cv.All(cv.int_, cv.Range(min=9, max=12)),
+ cv.Optional(CONF_RESOLUTION, default=12): cv.int_range(min=9, max=12),
}), cv.has_exactly_one_key(CONF_ADDRESS, CONF_INDEX))
diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py
index 4e7901571f..c69e0a5710 100644
--- a/esphome/components/esp32_camera/__init__.py
+++ b/esphome/components/esp32_camera/__init__.py
@@ -55,7 +55,7 @@ CONF_BRIGHTNESS = 'brightness'
CONF_SATURATION = 'saturation'
CONF_TEST_PATTERN = 'test_pattern'
-camera_range_param = cv.All(cv.int_, cv.Range(min=-2, max=2))
+camera_range_param = cv.int_range(min=-2, max=2)
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(ESP32Camera),
@@ -81,7 +81,7 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_IDLE_FRAMERATE, default='0.1 fps'): cv.All(cv.framerate,
cv.Range(min=0, max=1)),
cv.Optional(CONF_RESOLUTION, default='640X480'): cv.enum(FRAME_SIZES, upper=True),
- cv.Optional(CONF_JPEG_QUALITY, default=10): cv.All(cv.int_, cv.Range(min=10, max=63)),
+ cv.Optional(CONF_JPEG_QUALITY, default=10): cv.int_range(min=10, max=63),
cv.Optional(CONF_CONTRAST, default=0): camera_range_param,
cv.Optional(CONF_BRIGHTNESS, default=0): camera_range_param,
cv.Optional(CONF_SATURATION, default=0): camera_range_param,
diff --git a/esphome/components/esp8266_pwm/esp8266_pwm.cpp b/esphome/components/esp8266_pwm/esp8266_pwm.cpp
index 363f4d24bc..96290871e0 100644
--- a/esphome/components/esp8266_pwm/esp8266_pwm.cpp
+++ b/esphome/components/esp8266_pwm/esp8266_pwm.cpp
@@ -11,7 +11,7 @@
namespace esphome {
namespace esp8266_pwm {
-static const char *TAG = "something.something";
+static const char *TAG = "esp8266_pwm";
void ESP8266PWM::setup() {
ESP_LOGCONFIG(TAG, "Setting up ESP8266 PWM Output...");
diff --git a/esphome/components/fastled_base/__init__.py b/esphome/components/fastled_base/__init__.py
index 5ad7280ee8..aad30198af 100644
--- a/esphome/components/fastled_base/__init__.py
+++ b/esphome/components/fastled_base/__init__.py
@@ -1,8 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.components import light, power_supply
-from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS, CONF_RGB_ORDER, CONF_MAX_REFRESH_RATE, \
- CONF_POWER_SUPPLY
+from esphome.components import light
+from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS, CONF_RGB_ORDER, CONF_MAX_REFRESH_RATE
from esphome.core import coroutine
fastled_base_ns = cg.esphome_ns.namespace('fastled_base')
@@ -24,8 +23,6 @@ BASE_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend({
cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
cv.Optional(CONF_RGB_ORDER): cv.one_of(*RGB_ORDERS, upper=True),
cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
-
- cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply),
}).extend(cv.COMPONENT_SCHEMA)
@@ -37,10 +34,6 @@ def new_fastled_light(config):
if CONF_MAX_REFRESH_RATE in config:
cg.add(var.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
- if CONF_POWER_SUPPLY in config:
- var_ = yield cg.get_variable(config[CONF_POWER_SUPPLY])
- cg.add(var.set_power_supply(var_))
-
yield light.register_light(var, config)
cg.add_library('FastLED', '3.2.0')
yield var
diff --git a/esphome/components/fastled_base/fastled_light.cpp b/esphome/components/fastled_base/fastled_light.cpp
index d5cc85d266..8420748dd5 100644
--- a/esphome/components/fastled_base/fastled_light.cpp
+++ b/esphome/components/fastled_base/fastled_light.cpp
@@ -33,27 +33,6 @@ void FastLEDLightOutput::loop() {
this->mark_shown_();
ESP_LOGVV(TAG, "Writing RGB values to bus...");
-
-#ifdef USE_POWER_SUPPLY
- if (this->power_supply_ != nullptr) {
- bool is_on = false;
- for (int i = 0; i < this->num_leds_; i++) {
- if (bool(this->leds_[i])) {
- is_on = true;
- break;
- }
- }
-
- if (is_on && !this->has_requested_high_power_) {
- this->power_supply_->request_high_power();
- this->has_requested_high_power_ = true;
- }
- if (!is_on && this->has_requested_high_power_) {
- this->power_supply_->unrequest_high_power();
- this->has_requested_high_power_ = false;
- }
- }
-#endif
this->controller_->showLeds();
}
diff --git a/esphome/components/fastled_base/fastled_light.h b/esphome/components/fastled_base/fastled_light.h
index 55a48fcb3e..f9ae2f58d5 100644
--- a/esphome/components/fastled_base/fastled_light.h
+++ b/esphome/components/fastled_base/fastled_light.h
@@ -4,10 +4,6 @@
#include "esphome/core/helpers.h"
#include "esphome/components/light/addressable_light.h"
-#ifdef USE_POWER_SUPPLY
-#include "esphome/components/power_supply/power_supply.h"
-#endif
-
#define FASTLED_ESP8266_RAW_PIN_ORDER
#define FASTLED_ESP32_RAW_PIN_ORDER
#define FASTLED_RMT_BUILTIN_DRIVER true
@@ -30,10 +26,6 @@ class FastLEDLightOutput : public Component, public light::AddressableLight {
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
-#ifdef USE_POWER_SUPPLY
- void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_supply_ = power_supply; }
-#endif
-
/// Add some LEDS, can only be called once.
CLEDController &add_leds(CLEDController *controller, int num_leds) {
this->controller_ = controller;
@@ -242,10 +234,6 @@ class FastLEDLightOutput : public Component, public light::AddressableLight {
int num_leds_{0};
uint32_t last_refresh_{0};
optional max_refresh_rate_{};
-#ifdef USE_POWER_SUPPLY
- power_supply::PowerSupply *power_supply_{nullptr};
- bool has_requested_high_power_{false};
-#endif
};
} // namespace fastled_base
diff --git a/esphome/components/font/__init__.py b/esphome/components/font/__init__.py
index 774b49dbc1..e77bd5da8e 100644
--- a/esphome/components/font/__init__.py
+++ b/esphome/components/font/__init__.py
@@ -70,7 +70,7 @@ FONT_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(Font),
cv.Required(CONF_FILE): validate_truetype_file,
cv.Optional(CONF_GLYPHS, default=DEFAULT_GLYPHS): validate_glyphs,
- cv.Optional(CONF_SIZE, default=20): cv.All(cv.int_, cv.Range(min=1)),
+ cv.Optional(CONF_SIZE, default=20): cv.int_range(min=1),
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
})
diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py
new file mode 100644
index 0000000000..3ecbc89f73
--- /dev/null
+++ b/esphome/components/gps/__init__.py
@@ -0,0 +1,23 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import uart
+from esphome.const import CONF_ID
+
+DEPENDENCIES = ['uart']
+
+gps_ns = cg.esphome_ns.namespace('gps')
+GPS = gps_ns.class_('GPS', cg.Component, uart.UARTDevice)
+GPSListener = gps_ns.class_('GPSListener')
+
+CONF_GPS_ID = 'gps_id'
+MULTI_CONF = True
+CONFIG_SCHEMA = cv.Schema({
+ cv.GenerateID(): cv.declare_id(GPS),
+}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA)
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield uart.register_uart_device(var, config)
+ cg.add_library('TinyGPSPlus', '1.0.2')
diff --git a/esphome/components/gps/gps.cpp b/esphome/components/gps/gps.cpp
new file mode 100644
index 0000000000..0391a9a955
--- /dev/null
+++ b/esphome/components/gps/gps.cpp
@@ -0,0 +1,12 @@
+#include "gps.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace gps {
+
+static const char *TAG = "gps";
+
+TinyGPSPlus &GPSListener::get_tiny_gps() { return this->parent_->get_tiny_gps(); }
+
+} // namespace gps
+} // namespace esphome
diff --git a/esphome/components/gps/gps.h b/esphome/components/gps/gps.h
new file mode 100644
index 0000000000..7d845d1bed
--- /dev/null
+++ b/esphome/components/gps/gps.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/components/uart/uart.h"
+#include
+
+namespace esphome {
+namespace gps {
+
+class GPS;
+
+class GPSListener {
+ public:
+ virtual void on_update(TinyGPSPlus &tiny_gps) = 0;
+ TinyGPSPlus &get_tiny_gps();
+
+ protected:
+ friend GPS;
+
+ GPS *parent_;
+};
+
+class GPS : public Component, public uart::UARTDevice {
+ public:
+ void register_listener(GPSListener *listener) {
+ listener->parent_ = this;
+ this->listeners_.push_back(listener);
+ }
+ float get_setup_priority() const override { return setup_priority::HARDWARE; }
+ void loop() override {
+ while (this->available() && !this->has_time_) {
+ if (this->tiny_gps_.encode(this->read())) {
+ for (auto *listener : this->listeners_)
+ listener->on_update(this->tiny_gps_);
+ }
+ }
+ }
+ TinyGPSPlus &get_tiny_gps() { return this->tiny_gps_; }
+
+ protected:
+ bool has_time_{false};
+ TinyGPSPlus tiny_gps_;
+ std::vector listeners_{};
+};
+
+} // namespace gps
+} // namespace esphome
diff --git a/esphome/components/gps/time/__init__.py b/esphome/components/gps/time/__init__.py
new file mode 100644
index 0000000000..bf746d19b2
--- /dev/null
+++ b/esphome/components/gps/time/__init__.py
@@ -0,0 +1,23 @@
+from esphome.components import time as time_
+import esphome.config_validation as cv
+import esphome.codegen as cg
+from esphome.const import CONF_ID
+from .. import gps_ns, GPSListener, CONF_GPS_ID, GPS
+
+DEPENDENCIES = ['gps']
+
+GPSTime = gps_ns.class_('GPSTime', time_.RealTimeClock, GPSListener)
+
+CONFIG_SCHEMA = time_.TIME_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(GPSTime),
+ cv.GenerateID(CONF_GPS_ID): cv.use_id(GPS),
+}).extend(cv.COMPONENT_SCHEMA)
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield time_.register_time(var, config)
+ yield cg.register_component(var, config)
+
+ paren = yield cg.get_variable(config[CONF_GPS_ID])
+ cg.add(paren.register_listener(var))
diff --git a/esphome/components/gps/time/gps_time.cpp b/esphome/components/gps/time/gps_time.cpp
new file mode 100644
index 0000000000..c6aa8adc67
--- /dev/null
+++ b/esphome/components/gps/time/gps_time.cpp
@@ -0,0 +1,10 @@
+#include "gps_time.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace gps {
+
+static const char *TAG = "gps.time";
+
+} // namespace gps
+} // namespace esphome
diff --git a/esphome/components/gps/time/gps_time.h b/esphome/components/gps/time/gps_time.h
new file mode 100644
index 0000000000..b09aee364f
--- /dev/null
+++ b/esphome/components/gps/time/gps_time.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/components/time/real_time_clock.h"
+#include "esphome/components/gps/gps.h"
+
+namespace esphome {
+namespace gps {
+
+class GPSTime : public time::RealTimeClock, public GPSListener {
+ public:
+ void on_update(TinyGPSPlus &tiny_gps) override {
+ if (!this->has_time_)
+ this->from_tiny_gps_(tiny_gps);
+ }
+ void setup() override {
+ this->set_interval(5 * 60 * 1000, [this]() { this->from_tiny_gps_(this->get_tiny_gps()); });
+ }
+
+ protected:
+ void from_tiny_gps_(TinyGPSPlus &tiny_gps) {
+ if (!tiny_gps.time.isValid() || !tiny_gps.date.isValid())
+ return;
+ time::ESPTime val{};
+ val.year = tiny_gps.date.year();
+ val.month = tiny_gps.date.month();
+ val.day_of_month = tiny_gps.date.day();
+ val.hour = tiny_gps.time.hour();
+ val.minute = tiny_gps.time.minute();
+ val.second = tiny_gps.time.second();
+ val.recalc_timestamp_utc(false);
+ this->synchronize_epoch_(val.timestamp);
+ this->has_time_ = true;
+ }
+ bool has_time_{false};
+};
+
+} // namespace gps
+} // namespace esphome
diff --git a/esphome/components/hlw8012/hlw8012.cpp b/esphome/components/hlw8012/hlw8012.cpp
index c5138b7562..2b3b4ec2d9 100644
--- a/esphome/components/hlw8012/hlw8012.cpp
+++ b/esphome/components/hlw8012/hlw8012.cpp
@@ -13,8 +13,8 @@ void HLW8012Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up HLW8012...");
this->sel_pin_->setup();
this->sel_pin_->digital_write(this->current_mode_);
- this->cf_store_.setup(this->cf_pin_);
- this->cf1_store_.setup(this->cf1_pin_);
+ this->cf_store_.pulse_counter_setup(this->cf_pin_);
+ this->cf1_store_.pulse_counter_setup(this->cf1_pin_);
}
void HLW8012Component::dump_config() {
ESP_LOGCONFIG(TAG, "HLW8012:");
@@ -32,18 +32,18 @@ void HLW8012Component::dump_config() {
float HLW8012Component::get_setup_priority() const { return setup_priority::DATA; }
void HLW8012Component::update() {
// HLW8012 has 50% duty cycle
- const uint32_t last_rise_cf = this->cf_store_.get_last_rise();
- const uint32_t last_rise_cf1 = this->cf1_store_.get_last_rise();
- const uint32_t now = micros();
- float full_cycle_cf = this->cf_store_.get_pulse_width_s() * 2;
- float full_cycle_cf1 = this->cf1_store_.get_pulse_width_s() * 2;
- float cf_hz = 0.0f, cf1_hz = 0.0f;
- auto update_interval_micros = static_cast(this->update_interval_ * 1e3f);
-
- if (full_cycle_cf != 0.0f && now - last_rise_cf < update_interval_micros * 3)
- cf_hz = 1.0f / full_cycle_cf;
- if (full_cycle_cf1 != 0.0f && now - last_rise_cf1 < update_interval_micros * 3)
- cf1_hz = 1.0f / full_cycle_cf1;
+ pulse_counter::pulse_counter_t raw_cf = this->cf_store_.read_raw_value();
+ pulse_counter::pulse_counter_t raw_cf1 = this->cf1_store_.read_raw_value();
+ float cf_hz = raw_cf / (this->get_update_interval() / 1000.0f);
+ if (raw_cf <= 1) {
+ // don't count single pulse as power
+ cf_hz = 0.0f;
+ }
+ float cf1_hz = raw_cf1 / (this->get_update_interval() / 1000.0f);
+ if (raw_cf1 <= 1) {
+ // don't count single pulse as anything
+ cf1_hz = 0.0f;
+ }
if (this->nth_value_++ < 2) {
return;
diff --git a/esphome/components/hlw8012/hlw8012.h b/esphome/components/hlw8012/hlw8012.h
index 3eb1ea97c9..b9321b51c6 100644
--- a/esphome/components/hlw8012/hlw8012.h
+++ b/esphome/components/hlw8012/hlw8012.h
@@ -3,7 +3,7 @@
#include "esphome/core/component.h"
#include "esphome/core/esphal.h"
#include "esphome/components/sensor/sensor.h"
-#include "esphome/components/pulse_width/pulse_width.h"
+#include "esphome/components/pulse_counter/pulse_counter_sensor.h"
namespace esphome {
namespace hlw8012 {
@@ -34,9 +34,9 @@ class HLW8012Component : public PollingComponent {
float voltage_divider_{2351};
GPIOPin *sel_pin_;
GPIOPin *cf_pin_;
- pulse_width::PulseWidthSensorStore cf_store_;
+ pulse_counter::PulseCounterStorage cf_store_;
GPIOPin *cf1_pin_;
- pulse_width::PulseWidthSensorStore cf1_store_;
+ pulse_counter::PulseCounterStorage cf1_store_;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
diff --git a/esphome/components/hlw8012/sensor.py b/esphome/components/hlw8012/sensor.py
index 3dd1f0ae33..697c34f9d2 100644
--- a/esphome/components/hlw8012/sensor.py
+++ b/esphome/components/hlw8012/sensor.py
@@ -6,7 +6,7 @@ from esphome.const import CONF_CHANGE_MODE_EVERY, CONF_CURRENT, \
CONF_CURRENT_RESISTOR, CONF_ID, CONF_POWER, CONF_SEL_PIN, CONF_VOLTAGE, CONF_VOLTAGE_DIVIDER, \
ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
-AUTO_LOAD = ['pulse_width']
+AUTO_LOAD = ['pulse_counter']
hlw8012_ns = cg.esphome_ns.namespace('hlw8012')
HLW8012Component = hlw8012_ns.class_('HLW8012Component', cg.PollingComponent)
diff --git a/esphome/components/i2c/i2c.h b/esphome/components/i2c/i2c.h
index 0184c8020a..e41bd6c5e8 100644
--- a/esphome/components/i2c/i2c.h
+++ b/esphome/components/i2c/i2c.h
@@ -163,6 +163,14 @@ class I2CDevice {
*/
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0); // NOLINT
+ template optional> read_bytes(uint8_t a_register) { // NOLINT
+ std::array res;
+ if (!this->read_bytes(a_register, res.data(), N)) {
+ return {};
+ }
+ return res;
+ }
+
/** Read len amount of 16-bit words (MSB first) from a register into data.
*
* @param a_register The register number to write to the bus before reading.
@@ -176,6 +184,13 @@ class I2CDevice {
/// Read a single byte from a register into the data variable. Return true if successful.
bool read_byte(uint8_t a_register, uint8_t *data, uint32_t conversion = 0); // NOLINT
+ optional read_byte(uint8_t a_register) { // NOLINT
+ uint8_t data;
+ if (!this->read_byte(a_register, &data))
+ return {};
+ return data;
+ }
+
/// Read a single 16-bit words (MSB first) from a register into the data variable. Return true if successful.
bool read_byte_16(uint8_t a_register, uint16_t *data, uint32_t conversion = 0); // NOLINT
@@ -188,6 +203,20 @@ class I2CDevice {
*/
bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len); // NOLINT
+ /** Write a vector of data to a register.
+ *
+ * @param a_register The register to write to.
+ * @param data The data to write.
+ * @return If the operation was successful.
+ */
+ bool write_bytes(uint8_t a_register, const std::vector &data) { // NOLINT
+ return this->write_bytes(a_register, data.data(), data.size());
+ }
+
+ template bool write_bytes(uint8_t a_register, const std::array &data) { // NOLINT
+ return this->write_bytes(a_register, data.data(), data.size());
+ }
+
/** Write len amount of 16-bit words (MSB first) to the specified register.
*
* @param a_register The register to write the values to.
diff --git a/esphome/components/integration/sensor.py b/esphome/components/integration/sensor.py
index 13c69f81f2..9e4dc0847f 100644
--- a/esphome/components/integration/sensor.py
+++ b/esphome/components/integration/sensor.py
@@ -33,7 +33,7 @@ CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend({
cv.Required(CONF_TIME_UNIT): cv.enum(INTEGRATION_TIMES, lower=True),
cv.Optional(CONF_INTEGRATION_METHOD, default='trapezoid'):
cv.enum(INTEGRATION_METHODS, lower=True),
- cv.Optional(CONF_RESTORE, default=True): cv.boolean,
+ cv.Optional(CONF_RESTORE, default=False): cv.boolean,
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/ledc/output.py b/esphome/components/ledc/output.py
index 63b32eedf0..e5cb073ca9 100644
--- a/esphome/components/ledc/output.py
+++ b/esphome/components/ledc/output.py
@@ -1,20 +1,54 @@
+import math
from esphome import pins
from esphome.components import output
import esphome.config_validation as cv
import esphome.codegen as cg
-from esphome.const import APB_CLOCK_FREQ, CONF_BIT_DEPTH, CONF_CHANNEL, CONF_FREQUENCY, \
+from esphome.const import CONF_BIT_DEPTH, CONF_CHANNEL, CONF_FREQUENCY, \
CONF_ID, CONF_PIN, ESP_PLATFORM_ESP32
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
+def calc_max_frequency(bit_depth):
+ return 80e6 / (2**bit_depth)
+
+
+def calc_min_frequency(bit_depth):
+ # LEDC_DIV_NUM_HSTIMER is 15-bit unsigned integer
+ # lower 8 bits represent fractional part
+ max_div_num = ((1 << 16) - 1) / 256.0
+ return 80e6 / (max_div_num * (2**bit_depth))
+
+
def validate_frequency_bit_depth(obj):
frequency = obj[CONF_FREQUENCY]
+ if CONF_BIT_DEPTH not in obj:
+ obj = obj.copy()
+ for bit_depth in range(15, 0, -1):
+ if calc_min_frequency(bit_depth) <= frequency <= calc_max_frequency(bit_depth):
+ obj[CONF_BIT_DEPTH] = bit_depth
+ break
+ else:
+ min_freq = min(calc_min_frequency(x) for x in range(1, 16))
+ max_freq = max(calc_max_frequency(x) for x in range(1, 16))
+ if frequency < min_freq:
+ raise cv.Invalid("This frequency setting is not possible, please choose a higher "
+ "frequency (at least {}Hz)".format(int(min_freq)))
+ if frequency > max_freq:
+ raise cv.Invalid("This frequency setting is not possible, please choose a lower "
+ "frequency (at most {}Hz)".format(int(max_freq)))
+ raise cv.Invalid("Invalid frequency!")
+
bit_depth = obj[CONF_BIT_DEPTH]
- max_freq = APB_CLOCK_FREQ / (2**bit_depth)
+ min_freq = calc_min_frequency(bit_depth)
+ max_freq = calc_max_frequency(bit_depth)
if frequency > max_freq:
- raise cv.Invalid('Maximum frequency for bit depth {} is {}Hz'.format(bit_depth, max_freq))
+ raise cv.Invalid('Maximum frequency for bit depth {} is {}Hz. Please decrease the '
+ 'bit_depth.'.format(bit_depth, int(math.floor(max_freq))))
+ if frequency < calc_min_frequency(bit_depth):
+ raise cv.Invalid('Minimum frequency for bit depth {} is {}Hz. Please increase the '
+ 'bit_depth.'.format(bit_depth, int(math.ceil(min_freq))))
return obj
@@ -25,8 +59,8 @@ CONFIG_SCHEMA = cv.All(output.FLOAT_OUTPUT_SCHEMA.extend({
cv.Required(CONF_ID): cv.declare_id(LEDCOutput),
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema,
cv.Optional(CONF_FREQUENCY, default='1kHz'): cv.frequency,
- cv.Optional(CONF_BIT_DEPTH, default=12): cv.All(cv.int_, cv.Range(min=1, max=15)),
- cv.Optional(CONF_CHANNEL): cv.All(cv.int_, cv.Range(min=0, max=15))
+ cv.Optional(CONF_BIT_DEPTH): cv.int_range(min=1, max=15),
+ cv.Optional(CONF_CHANNEL): cv.int_range(min=0, max=15),
}).extend(cv.COMPONENT_SCHEMA), validate_frequency_bit_depth)
diff --git a/esphome/components/light/__init__.py b/esphome/components/light/__init__.py
index 858475f8cf..e0ea8f246d 100644
--- a/esphome/components/light/__init__.py
+++ b/esphome/components/light/__init__.py
@@ -1,9 +1,9 @@
import esphome.codegen as cg
import esphome.config_validation as cv
-from esphome.components import mqtt
+from esphome.components import mqtt, power_supply
from esphome.const import CONF_COLOR_CORRECT, \
CONF_DEFAULT_TRANSITION_LENGTH, CONF_EFFECTS, CONF_GAMMA_CORRECT, CONF_ID, \
- CONF_INTERNAL, CONF_NAME, CONF_MQTT_ID
+ CONF_INTERNAL, CONF_NAME, CONF_MQTT_ID, CONF_POWER_SUPPLY
from esphome.core import coroutine, coroutine_with_priority
from .automation import light_control_to_code # noqa
from .effects import validate_effects, BINARY_EFFECTS, \
@@ -35,6 +35,7 @@ ADDRESSABLE_LIGHT_SCHEMA = RGB_LIGHT_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(AddressableLightState),
cv.Optional(CONF_EFFECTS): validate_effects(ADDRESSABLE_EFFECTS),
cv.Optional(CONF_COLOR_CORRECT): cv.All([cv.percentage], cv.Length(min=3, max=4)),
+ cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply),
})
@@ -52,6 +53,10 @@ def setup_light_core_(light_var, output_var, config):
if CONF_COLOR_CORRECT in config:
cg.add(output_var.set_correction(*config[CONF_COLOR_CORRECT]))
+ if CONF_POWER_SUPPLY in config:
+ var_ = yield cg.get_variable(config[CONF_POWER_SUPPLY])
+ cg.add(output_var.set_power_supply(var_))
+
if CONF_MQTT_ID in config:
mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], light_var)
yield mqtt.register_mqtt_component(mqtt_, config)
diff --git a/esphome/components/light/addressable_light.h b/esphome/components/light/addressable_light.h
index 993b430d3c..b4249097db 100644
--- a/esphome/components/light/addressable_light.h
+++ b/esphome/components/light/addressable_light.h
@@ -1,9 +1,14 @@
#pragma once
#include "esphome/core/component.h"
+#include "esphome/core/defines.h"
#include "light_output.h"
#include "light_state.h"
+#ifdef USE_POWER_SUPPLY
+#include "esphome/components/power_supply/power_supply.h"
+#endif
+
namespace esphome {
namespace light {
@@ -30,6 +35,7 @@ struct ESPColor {
};
};
uint8_t raw[4];
+ uint32_t raw_32;
};
inline ESPColor() ALWAYS_INLINE : r(0), g(0), b(0), w(0) {} // NOLINT
inline ESPColor(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) ALWAYS_INLINE : r(red),
@@ -47,7 +53,7 @@ struct ESPColor {
this->b = rhs.b;
this->w = rhs.w;
}
- inline bool is_on() ALWAYS_INLINE { return this->r != 0 || this->g != 0 || this->b != 0 || this->w != 0; }
+ inline bool is_on() ALWAYS_INLINE { return this->raw_32 != 0; }
inline ESPColor &operator=(const ESPColor &rhs) ALWAYS_INLINE {
this->r = rhs.r;
this->g = rhs.g;
@@ -527,14 +533,32 @@ class AddressableLight : public LightOutput {
void setup_state(LightState *state) override { this->correction_.calculate_gamma_table(state->get_gamma_correct()); }
void schedule_show() { this->next_show_ = true; }
+#ifdef USE_POWER_SUPPLY
+ void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); }
+#endif
+
protected:
bool should_show_() const { return this->effect_active_ || this->next_show_; }
- void mark_shown_() { this->next_show_ = false; }
+ void mark_shown_() {
+ this->next_show_ = false;
+#ifdef USE_POWER_SUPPLY
+ for (auto c : *this) {
+ if (c.get().is_on()) {
+ this->power_.request();
+ return;
+ }
+ }
+ this->power_.unrequest();
+#endif
+ }
virtual ESPColorView get_view_internal(int32_t index) const = 0;
bool effect_active_{false};
bool next_show_{true};
ESPColorCorrection correction_{};
+#ifdef USE_POWER_SUPPLY
+ power_supply::PowerSupplyRequester power_;
+#endif
};
} // namespace light
diff --git a/esphome/components/logger/__init__.py b/esphome/components/logger/__init__.py
index 27141f93c2..94b33ae18e 100644
--- a/esphome/components/logger/__init__.py
+++ b/esphome/components/logger/__init__.py
@@ -112,7 +112,7 @@ def to_code(config):
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)]
- cg.add_build_flag("-DDEBUG_ESP_PORT{}".format(debug_serial_port))
+ cg.add_build_flag("-DDEBUG_ESP_PORT={}".format(debug_serial_port))
cg.add_build_flag("-DLWIP_DEBUG")
DEBUG_COMPONENTS = {
'HTTP_CLIENT',
diff --git a/esphome/components/max7219/display.py b/esphome/components/max7219/display.py
index b40fbafddb..c96454ce8c 100644
--- a/esphome/components/max7219/display.py
+++ b/esphome/components/max7219/display.py
@@ -12,8 +12,8 @@ MAX7219ComponentRef = MAX7219Component.operator('ref')
CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(MAX7219Component),
- cv.Optional(CONF_NUM_CHIPS, default=1): cv.All(cv.uint8_t, cv.Range(min=1)),
- cv.Optional(CONF_INTENSITY, default=15): cv.All(cv.uint8_t, cv.Range(min=0, max=15)),
+ cv.Optional(CONF_NUM_CHIPS, default=1): cv.int_range(min=1, max=255),
+ cv.Optional(CONF_INTENSITY, default=15): cv.int_range(min=0, max=15),
}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA)
diff --git a/esphome/components/mpu6050/mpu6050.cpp b/esphome/components/mpu6050/mpu6050.cpp
index deba316a7f..06f8951bf5 100644
--- a/esphome/components/mpu6050/mpu6050.cpp
+++ b/esphome/components/mpu6050/mpu6050.cpp
@@ -110,7 +110,7 @@ void MPU6050Component::update() {
float accel_y = data[1] * MPU6050_RANGE_PER_DIGIT_2G * GRAVITY_EARTH;
float accel_z = data[2] * MPU6050_RANGE_PER_DIGIT_2G * GRAVITY_EARTH;
- float temperature = raw_data[3] / 340.0f + 36.53f;
+ float temperature = data[3] / 340.0f + 36.53f;
float gyro_x = data[4] * MPU6050_SCALE_DPS_PER_DIGIT_2000;
float gyro_y = data[5] * MPU6050_SCALE_DPS_PER_DIGIT_2000;
diff --git a/esphome/components/mqtt/mqtt_climate.cpp b/esphome/components/mqtt/mqtt_climate.cpp
index c46d979ea2..590a6db7b4 100644
--- a/esphome/components/mqtt/mqtt_climate.cpp
+++ b/esphome/components/mqtt/mqtt_climate.cpp
@@ -24,12 +24,12 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC
JsonArray &modes = root.createNestedArray("modes");
// sort array for nice UI in HA
if (traits.supports_mode(CLIMATE_MODE_AUTO))
- modes.add("auto");
- modes.add("off");
+ modes.add(climate_mode_to_string(CLIMATE_MODE_AUTO));
+ modes.add(climate_mode_to_string(CLIMATE_MODE_OFF));
if (traits.supports_mode(CLIMATE_MODE_COOL))
- modes.add("cool");
+ modes.add(climate_mode_to_string(CLIMATE_MODE_COOL));
if (traits.supports_mode(CLIMATE_MODE_HEAT))
- modes.add("heat");
+ modes.add(climate_mode_to_string(CLIMATE_MODE_HEAT));
if (traits.get_supports_two_point_target_temperature()) {
// temperature_low_command_topic
@@ -60,6 +60,8 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC
// away_mode_state_topic
root["away_mode_state_topic"] = this->get_away_state_topic();
}
+ config.state_topic = false;
+ config.command_topic = false;
}
void MQTTClimateComponent::setup() {
auto traits = this->device_->get_traits();
@@ -144,7 +146,7 @@ bool MQTTClimateComponent::publish_state_() {
if (!this->publish(this->get_mode_state_topic(), mode_s))
success = false;
int8_t accuracy = traits.get_temperature_accuracy_decimals();
- if (traits.get_supports_current_temperature()) {
+ if (traits.get_supports_current_temperature() && !isnan(this->device_->current_temperature)) {
std::string payload = value_accuracy_to_string(this->device_->current_temperature, accuracy);
if (!this->publish(this->get_current_temperature_state_topic(), payload))
success = false;
diff --git a/esphome/components/my9231/__init__.py b/esphome/components/my9231/__init__.py
index 82dfe3e083..7ca0a30cab 100644
--- a/esphome/components/my9231/__init__.py
+++ b/esphome/components/my9231/__init__.py
@@ -13,8 +13,8 @@ CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(MY9231OutputComponent),
cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema,
cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema,
- cv.Optional(CONF_NUM_CHANNELS, default=6): cv.All(cv.int_, cv.Range(min=3, max=1020)),
- cv.Optional(CONF_NUM_CHIPS, default=2): cv.All(cv.int_, cv.Range(min=1, max=255)),
+ cv.Optional(CONF_NUM_CHANNELS, default=6): cv.int_range(min=3, max=1020),
+ cv.Optional(CONF_NUM_CHIPS, default=2): cv.int_range(min=1, max=255),
cv.Optional(CONF_BIT_DEPTH, default=16): cv.one_of(8, 12, 14, 16, int=True),
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/my9231/my9231.h b/esphome/components/my9231/my9231.h
index d7c479c06b..ee15f9743c 100644
--- a/esphome/components/my9231/my9231.h
+++ b/esphome/components/my9231/my9231.h
@@ -1,6 +1,7 @@
#pragma once
#include "esphome/core/component.h"
+#include "esphome/core/esphal.h"
#include "esphome/components/output/float_output.h"
namespace esphome {
diff --git a/esphome/components/my9231/output.py b/esphome/components/my9231/output.py
index 62460faec4..9acc8bdcd6 100644
--- a/esphome/components/my9231/output.py
+++ b/esphome/components/my9231/output.py
@@ -13,7 +13,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend({
cv.GenerateID(CONF_MY9231_ID): cv.use_id(MY9231OutputComponent),
cv.Required(CONF_ID): cv.declare_id(Channel),
- cv.Required(CONF_CHANNEL): cv.All(cv.int_, cv.Range(min=0, max=65535)),
+ cv.Required(CONF_CHANNEL): cv.uint16_t,
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py
index 060aeb0648..f07bdc80d7 100644
--- a/esphome/components/neopixelbus/light.py
+++ b/esphome/components/neopixelbus/light.py
@@ -1,9 +1,9 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
-from esphome.components import light, power_supply
+from esphome.components import light
from esphome.const import CONF_CLOCK_PIN, CONF_DATA_PIN, CONF_METHOD, CONF_NUM_LEDS, CONF_PIN, \
- CONF_POWER_SUPPLY, CONF_TYPE, CONF_VARIANT, CONF_OUTPUT_ID
+ CONF_TYPE, CONF_VARIANT, CONF_OUTPUT_ID
from esphome.core import CORE
neopixelbus_ns = cg.esphome_ns.namespace('neopixelbus')
@@ -138,8 +138,6 @@ CONFIG_SCHEMA = cv.All(light.ADDRESSABLE_LIGHT_SCHEMA.extend({
cv.Optional(CONF_DATA_PIN): pins.output_pin,
cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
-
- cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply),
}).extend(cv.COMPONENT_SCHEMA), validate, validate_method_pin)
@@ -162,8 +160,4 @@ def to_code(config):
cg.add(var.set_pixel_order(getattr(ESPNeoPixelOrder, config[CONF_TYPE])))
- if CONF_POWER_SUPPLY in config:
- var_ = yield cg.get_variable(config[CONF_POWER_SUPPLY])
- cg.add(var.set_power_supply(var_))
-
cg.add_library('NeoPixelBus', '2.4.1')
diff --git a/esphome/components/neopixelbus/neopixelbus_light.h b/esphome/components/neopixelbus/neopixelbus_light.h
index 68d99fb374..25e10d9bbd 100644
--- a/esphome/components/neopixelbus/neopixelbus_light.h
+++ b/esphome/components/neopixelbus/neopixelbus_light.h
@@ -9,10 +9,6 @@
#error The NeoPixelBus library requires at least arduino_core_version 2.4.x
#endif
-#ifdef USE_POWER_SUPPLY
-#include "esphome/components/power_supply/power_supply.h"
-#endif
-
#include "NeoPixelBus.h"
namespace esphome {
@@ -54,10 +50,6 @@ enum class ESPNeoPixelOrder {
template
class NeoPixelBusLightOutputBase : public Component, public light::AddressableLight {
public:
-#ifdef USE_POWER_SUPPLY
- void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_supply_ = power_supply; }
-#endif
-
NeoPixelBus *get_controller() const { return this->controller_; }
void clear_effect_data() override {
@@ -95,27 +87,6 @@ class NeoPixelBusLightOutputBase : public Component, public light::AddressableLi
this->mark_shown_();
this->controller_->Dirty();
-#ifdef USE_POWER_SUPPLY
- if (this->power_supply_ != nullptr) {
- bool is_light_on = false;
- for (int i = 0; i < this->size(); i++) {
- if ((*this)[i].get().is_on()) {
- is_light_on = true;
- break;
- }
- }
-
- if (is_light_on && !this->has_requested_high_power_) {
- this->power_supply_->request_high_power();
- this->has_requested_high_power_ = true;
- }
- if (!is_light_on && this->has_requested_high_power_) {
- this->power_supply_->unrequest_high_power();
- this->has_requested_high_power_ = false;
- }
- }
-#endif
-
this->controller_->Show();
}
@@ -135,10 +106,6 @@ class NeoPixelBusLightOutputBase : public Component, public light::AddressableLi
NeoPixelBus *controller_{nullptr};
uint8_t *effect_data_{nullptr};
uint8_t rgb_offsets_[4]{0, 1, 2, 3};
-#ifdef USE_POWER_SUPPLY
- power_supply::PowerSupply *power_supply_{nullptr};
- bool has_requested_high_power_{false};
-#endif
};
template
diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp
index b69393c998..ee2d67c85e 100644
--- a/esphome/components/ota/ota_component.cpp
+++ b/esphome/components/ota/ota_component.cpp
@@ -4,7 +4,6 @@
#include "esphome/core/helpers.h"
#include "esphome/core/application.h"
#include "esphome/core/util.h"
-//#include "esphome/components/status_led.h"
#include
#include
diff --git a/esphome/components/output/binary_output.h b/esphome/components/output/binary_output.h
index 96f6b3fb48..2697b23616 100644
--- a/esphome/components/output/binary_output.h
+++ b/esphome/components/output/binary_output.h
@@ -27,16 +27,13 @@ class BinaryOutput {
*
* @param power_supply The PowerSupplyComponent, set this to nullptr to disable the power supply.
*/
- void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_supply_ = power_supply; }
+ void set_power_supply(power_supply::PowerSupply *power_supply) { this->power_.set_parent(power_supply); }
#endif
/// Enable this binary output.
virtual void turn_on() {
#ifdef USE_POWER_SUPPLY
- if (this->power_supply_ != nullptr && !this->has_requested_high_power_) {
- this->power_supply_->request_high_power();
- this->has_requested_high_power_ = true;
- }
+ this->power_.request();
#endif
this->write_state(!this->inverted_);
}
@@ -44,10 +41,7 @@ class BinaryOutput {
/// Disable this binary output.
virtual void turn_off() {
#ifdef USE_POWER_SUPPLY
- if (this->power_supply_ != nullptr && this->has_requested_high_power_) {
- this->power_supply_->unrequest_high_power();
- this->has_requested_high_power_ = false;
- }
+ this->power_.unrequest();
#endif
this->write_state(this->inverted_);
}
@@ -62,8 +56,7 @@ class BinaryOutput {
bool inverted_{false};
#ifdef USE_POWER_SUPPLY
- power_supply::PowerSupply *power_supply_{nullptr};
- bool has_requested_high_power_{false};
+ power_supply::PowerSupplyRequester power_{};
#endif
};
diff --git a/esphome/components/output/float_output.cpp b/esphome/components/output/float_output.cpp
index 30984aecc8..0d536d0946 100644
--- a/esphome/components/output/float_output.cpp
+++ b/esphome/components/output/float_output.cpp
@@ -24,15 +24,9 @@ void FloatOutput::set_level(float state) {
#ifdef USE_POWER_SUPPLY
if (state > 0.0f) { // ON
- if (this->power_supply_ != nullptr && !this->has_requested_high_power_) {
- this->power_supply_->request_high_power();
- this->has_requested_high_power_ = true;
- }
+ this->power_.request();
} else { // OFF
- if (this->power_supply_ != nullptr && this->has_requested_high_power_) {
- this->power_supply_->unrequest_high_power();
- this->has_requested_high_power_ = false;
- }
+ this->power_.unrequest();
}
#endif
diff --git a/esphome/components/pca9685/output.py b/esphome/components/pca9685/output.py
index 0c6855c1d4..b5f4805611 100644
--- a/esphome/components/pca9685/output.py
+++ b/esphome/components/pca9685/output.py
@@ -13,7 +13,7 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend({
cv.Required(CONF_ID): cv.declare_id(PCA9685Channel),
cv.GenerateID(CONF_PCA9685_ID): cv.use_id(PCA9685Output),
- cv.Required(CONF_CHANNEL): cv.All(cv.Coerce(int), cv.Range(min=0, max=15)),
+ cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=15),
})
diff --git a/esphome/components/pmsx003/pmsx003.cpp b/esphome/components/pmsx003/pmsx003.cpp
index bbf76ce697..548099a495 100644
--- a/esphome/components/pmsx003/pmsx003.cpp
+++ b/esphome/components/pmsx003/pmsx003.cpp
@@ -132,14 +132,20 @@ void PMSX003Component::parse_data_() {
break;
}
case PMSX003_TYPE_5003ST: {
+ uint16_t pm_1_0_concentration = this->get_16_bit_uint_(10);
uint16_t pm_2_5_concentration = this->get_16_bit_uint_(12);
+ uint16_t pm_10_0_concentration = this->get_16_bit_uint_(14);
uint16_t formaldehyde = this->get_16_bit_uint_(28);
float temperature = this->get_16_bit_uint_(30) / 10.0f;
float humidity = this->get_16_bit_uint_(32) / 10.0f;
ESP_LOGD(TAG, "Got PM2.5 Concentration: %u µg/m^3, Temperature: %.1f°C, Humidity: %.1f%% Formaldehyde: %u µg/m^3",
pm_2_5_concentration, temperature, humidity, formaldehyde);
+ if (this->pm_1_0_sensor_ != nullptr)
+ this->pm_1_0_sensor_->publish_state(pm_1_0_concentration);
if (this->pm_2_5_sensor_ != nullptr)
this->pm_2_5_sensor_->publish_state(pm_2_5_concentration);
+ if (this->pm_10_0_sensor_ != nullptr)
+ this->pm_10_0_sensor_->publish_state(pm_10_0_concentration);
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(temperature);
if (this->humidity_sensor_ != nullptr)
diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py
index a949fbb1ca..fa9a92d430 100644
--- a/esphome/components/pmsx003/sensor.py
+++ b/esphome/components/pmsx003/sensor.py
@@ -24,9 +24,9 @@ PMSX003_TYPES = {
}
SENSORS_TO_TYPE = {
- CONF_PM_1_0: [CONF_PMSX003],
+ CONF_PM_1_0: [CONF_PMSX003, CONF_PMS5003ST],
CONF_PM_2_5: [CONF_PMSX003, CONF_PMS5003T, CONF_PMS5003ST],
- CONF_PM_10_0: [CONF_PMSX003],
+ CONF_PM_10_0: [CONF_PMSX003, CONF_PMS5003ST],
CONF_TEMPERATURE: [CONF_PMS5003T, CONF_PMS5003ST],
CONF_HUMIDITY: [CONF_PMS5003T, CONF_PMS5003ST],
CONF_FORMALDEHYDE: [CONF_PMS5003ST],
diff --git a/esphome/components/power_supply/power_supply.cpp b/esphome/components/power_supply/power_supply.cpp
index 5ce2e38eed..1f8471ac9f 100644
--- a/esphome/components/power_supply/power_supply.cpp
+++ b/esphome/components/power_supply/power_supply.cpp
@@ -42,7 +42,7 @@ void PowerSupply::request_high_power() {
void PowerSupply::unrequest_high_power() {
this->active_requests_--;
if (this->active_requests_ < 0) {
- // if asserts are disabled we're just going to use 0 as our now counter.
+ // we're just going to use 0 as our now counter.
this->active_requests_ = 0;
}
diff --git a/esphome/components/power_supply/power_supply.h b/esphome/components/power_supply/power_supply.h
index b49da3b32a..12d2a9984f 100644
--- a/esphome/components/power_supply/power_supply.h
+++ b/esphome/components/power_supply/power_supply.h
@@ -39,5 +39,26 @@ class PowerSupply : public Component {
int16_t active_requests_{0}; // use signed integer to make catching negative requests easier.
};
+class PowerSupplyRequester {
+ public:
+ void set_parent(PowerSupply *parent) { parent_ = parent; }
+ void request() {
+ if (!this->requested_ && this->parent_ != nullptr) {
+ this->parent_->request_high_power();
+ this->requested_ = true;
+ }
+ }
+ void unrequest() {
+ if (this->requested_ && this->parent_ != nullptr) {
+ this->parent_->unrequest_high_power();
+ this->requested_ = false;
+ }
+ }
+
+ protected:
+ PowerSupply *parent_{nullptr};
+ bool requested_{false};
+};
+
} // namespace power_supply
} // namespace esphome
diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.cpp b/esphome/components/pulse_counter/pulse_counter_sensor.cpp
index 9947cebac8..6503711e35 100644
--- a/esphome/components/pulse_counter/pulse_counter_sensor.cpp
+++ b/esphome/components/pulse_counter/pulse_counter_sensor.cpp
@@ -28,7 +28,9 @@ void ICACHE_RAM_ATTR PulseCounterStorage::gpio_intr(PulseCounterStorage *arg) {
break;
}
}
-bool PulseCounterStorage::pulse_counter_setup() {
+bool PulseCounterStorage::pulse_counter_setup(GPIOPin *pin) {
+ this->pin = pin;
+ this->pin->setup();
this->isr_pin = this->pin->to_isr();
this->pin->attach_interrupt(PulseCounterStorage::gpio_intr, this, CHANGE);
return true;
@@ -42,7 +44,9 @@ pulse_counter_t PulseCounterStorage::read_raw_value() {
#endif
#ifdef ARDUINO_ARCH_ESP32
-bool PulseCounterStorage::pulse_counter_setup() {
+bool PulseCounterStorage::pulse_counter_setup(GPIOPin *pin) {
+ this->pin = pin;
+ this->pin->setup();
this->pcnt_unit = next_pcnt_unit;
next_pcnt_unit = pcnt_unit_t(int(next_pcnt_unit) + 1); // NOLINT
@@ -133,9 +137,7 @@ pulse_counter_t PulseCounterStorage::read_raw_value() {
void PulseCounterSensor::setup() {
ESP_LOGCONFIG(TAG, "Setting up pulse counter '%s'...", this->name_.c_str());
- this->pin_->setup();
- this->storage_.pin = this->pin_;
- if (!this->storage_.pulse_counter_setup()) {
+ if (!this->storage_.pulse_counter_setup(this->pin_)) {
this->mark_failed();
return;
}
diff --git a/esphome/components/pulse_counter/pulse_counter_sensor.h b/esphome/components/pulse_counter/pulse_counter_sensor.h
index cf73156147..483036ac34 100644
--- a/esphome/components/pulse_counter/pulse_counter_sensor.h
+++ b/esphome/components/pulse_counter/pulse_counter_sensor.h
@@ -25,7 +25,7 @@ using pulse_counter_t = int32_t;
#endif
struct PulseCounterStorage {
- bool pulse_counter_setup();
+ bool pulse_counter_setup(GPIOPin *pin);
pulse_counter_t read_raw_value();
static void gpio_intr(PulseCounterStorage *arg);
@@ -42,9 +42,9 @@ struct PulseCounterStorage {
#ifdef ARDUINO_ARCH_ESP8266
ISRInternalGPIOPin *isr_pin;
#endif
- PulseCounterCountMode rising_edge_mode{};
- PulseCounterCountMode falling_edge_mode{};
- uint32_t filter_us{};
+ PulseCounterCountMode rising_edge_mode{PULSE_COUNTER_INCREMENT};
+ PulseCounterCountMode falling_edge_mode{PULSE_COUNTER_DISABLE};
+ uint32_t filter_us{0};
pulse_counter_t last_value{0};
};
diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py
index cfe3ae4c59..8b6f5b1623 100644
--- a/esphome/components/remote_base/__init__.py
+++ b/esphome/components/remote_base/__init__.py
@@ -5,7 +5,7 @@ from esphome.components import binary_sensor
from esphome.const import CONF_DATA, CONF_ID, CONF_TRIGGER_ID, CONF_NBITS, CONF_ADDRESS, \
CONF_COMMAND, CONF_CODE, CONF_PULSE_LENGTH, CONF_SYNC, CONF_ZERO, CONF_ONE, CONF_INVERTED, \
CONF_PROTOCOL, CONF_GROUP, CONF_DEVICE, CONF_STATE, CONF_CHANNEL, CONF_FAMILY, CONF_REPEAT, \
- CONF_WAIT_TIME, CONF_TIMES, CONF_TYPE_ID
+ CONF_WAIT_TIME, CONF_TIMES, CONF_TYPE_ID, CONF_CARRIER_FREQUENCY
from esphome.core import coroutine
from esphome.py_compat import string_types, text_type
from esphome.util import Registry, SimpleRegistry
@@ -359,7 +359,9 @@ def raw_dumper(var, config):
pass
-@register_action('raw', RawAction, RAW_SCHEMA)
+@register_action('raw', RawAction, RAW_SCHEMA.extend({
+ cv.Optional(CONF_CARRIER_FREQUENCY, default='0Hz'): cv.All(cv.frequency, cv.int_),
+}))
def raw_action(var, config, args):
code_ = config[CONF_CODE]
if cg.is_template(code_):
@@ -369,6 +371,8 @@ def raw_action(var, config, args):
code_ = config[CONF_CODE]
arr = cg.progmem_array(config[CONF_CODE_STORAGE_ID], code_)
cg.add(var.set_code_static(arr, len(code_)))
+ templ = yield cg.templatable(config[CONF_CARRIER_FREQUENCY], args, cg.uint32)
+ cg.add(var.set_carrier_frequency(templ))
# RC5
@@ -410,7 +414,7 @@ def rc5_action(var, config, args):
RC_SWITCH_TIMING_SCHEMA = cv.All([cv.uint8_t], cv.Length(min=2, max=2))
RC_SWITCH_PROTOCOL_SCHEMA = cv.Any(
- cv.All(cv.Coerce(int), cv.Range(min=1, max=7)),
+ cv.int_range(min=1, max=7),
cv.Schema({
cv.Required(CONF_PULSE_LENGTH): cv.uint32_t,
cv.Optional(CONF_SYNC, default=[1, 31]): RC_SWITCH_TIMING_SCHEMA,
@@ -457,25 +461,32 @@ RC_SWITCH_TYPE_A_SCHEMA = cv.Schema({
cv.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
})
RC_SWITCH_TYPE_B_SCHEMA = cv.Schema({
- cv.Required(CONF_ADDRESS): cv.All(cv.uint8_t, cv.Range(min=1, max=4)),
- cv.Required(CONF_CHANNEL): cv.All(cv.uint8_t, cv.Range(min=1, max=4)),
+ cv.Required(CONF_ADDRESS): cv.int_range(min=1, max=4),
+ cv.Required(CONF_CHANNEL): cv.int_range(min=1, max=4),
cv.Required(CONF_STATE): cv.boolean,
cv.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
})
RC_SWITCH_TYPE_C_SCHEMA = cv.Schema({
cv.Required(CONF_FAMILY): cv.one_of('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', lower=True),
- cv.Required(CONF_GROUP): cv.All(cv.uint8_t, cv.Range(min=1, max=4)),
- cv.Required(CONF_DEVICE): cv.All(cv.uint8_t, cv.Range(min=1, max=4)),
+ cv.Required(CONF_GROUP): cv.int_range(min=1, max=4),
+ cv.Required(CONF_DEVICE): cv.int_range(min=1, max=4),
cv.Required(CONF_STATE): cv.boolean,
cv.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
})
RC_SWITCH_TYPE_D_SCHEMA = cv.Schema({
cv.Required(CONF_GROUP): cv.one_of('a', 'b', 'c', 'd', lower=True),
- cv.Required(CONF_DEVICE): cv.All(cv.uint8_t, cv.Range(min=1, max=3)),
+ cv.Required(CONF_DEVICE): cv.int_range(min=1, max=3),
cv.Required(CONF_STATE): cv.boolean,
cv.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA,
})
+RC_SWITCH_TRANSMITTER = cv.Schema({
+ cv.Optional(CONF_REPEAT, default={CONF_TIMES: 5}): cv.Schema({
+ cv.Required(CONF_TIMES): cv.templatable(cv.positive_int),
+ cv.Optional(CONF_WAIT_TIME, default='10ms'):
+ cv.templatable(cv.positive_time_period_milliseconds),
+ }),
+})
rc_switch_protocols = ns.rc_switch_protocols
RCSwitchBase = ns.class_('RCSwitchBase')
@@ -494,7 +505,8 @@ def rc_switch_raw_binary_sensor(var, config):
cg.add(var.set_code(config[CONF_CODE]))
-@register_action('rc_switch_raw', RCSwitchRawAction, RC_SWITCH_RAW_SCHEMA)
+@register_action('rc_switch_raw', RCSwitchRawAction,
+ RC_SWITCH_RAW_SCHEMA.extend(RC_SWITCH_TRANSMITTER))
def rc_switch_raw_action(var, config, args):
proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase,
to_exp=build_rc_switch_protocol)
@@ -508,7 +520,8 @@ def rc_switch_type_a_binary_sensor(var, config):
cg.add(var.set_type_a(config[CONF_GROUP], config[CONF_DEVICE], config[CONF_STATE]))
-@register_action('rc_switch_type_a', RCSwitchTypeAAction, RC_SWITCH_TYPE_A_SCHEMA)
+@register_action('rc_switch_type_a', RCSwitchTypeAAction,
+ RC_SWITCH_TYPE_A_SCHEMA.extend(RC_SWITCH_TRANSMITTER))
def rc_switch_type_a_action(var, config, args):
proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase,
to_exp=build_rc_switch_protocol)
@@ -524,7 +537,8 @@ def rc_switch_type_b_binary_sensor(var, config):
cg.add(var.set_type_b(config[CONF_ADDRESS], config[CONF_CHANNEL], config[CONF_STATE]))
-@register_action('rc_switch_type_b', RCSwitchTypeBAction, RC_SWITCH_TYPE_B_SCHEMA)
+@register_action('rc_switch_type_b', RCSwitchTypeBAction,
+ RC_SWITCH_TYPE_B_SCHEMA.extend(RC_SWITCH_TRANSMITTER))
def rc_switch_type_b_action(var, config, args):
proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase,
to_exp=build_rc_switch_protocol)
@@ -541,7 +555,8 @@ def rc_switch_type_c_binary_sensor(var, config):
config[CONF_STATE]))
-@register_action('rc_switch_type_c', RCSwitchTypeCAction, RC_SWITCH_TYPE_C_SCHEMA)
+@register_action('rc_switch_type_c', RCSwitchTypeCAction,
+ RC_SWITCH_TYPE_C_SCHEMA.extend(RC_SWITCH_TRANSMITTER))
def rc_switch_type_c_action(var, config, args):
proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase,
to_exp=build_rc_switch_protocol)
@@ -552,13 +567,15 @@ def rc_switch_type_c_action(var, config, args):
cg.add(var.set_state((yield cg.templatable(config[CONF_STATE], args, bool))))
-@register_binary_sensor('rc_switch_type_d', RCSwitchRawReceiver, RC_SWITCH_TYPE_D_SCHEMA)
+@register_binary_sensor('rc_switch_type_d', RCSwitchRawReceiver,
+ RC_SWITCH_TYPE_D_SCHEMA.extend(RC_SWITCH_TRANSMITTER))
def rc_switch_type_d_binary_sensor(var, config):
cg.add(var.set_protocol(build_rc_switch_protocol(config[CONF_PROTOCOL])))
cg.add(var.set_type_d(config[CONF_GROUP], config[CONF_DEVICE], config[CONF_STATE]))
-@register_action('rc_switch_type_d', RCSwitchTypeDAction, RC_SWITCH_TYPE_D_SCHEMA)
+@register_action('rc_switch_type_d', RCSwitchTypeDAction,
+ RC_SWITCH_TYPE_D_SCHEMA.extend(RC_SWITCH_TRANSMITTER))
def rc_switch_type_d_action(var, config, args):
proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase,
to_exp=build_rc_switch_protocol)
diff --git a/esphome/components/remote_base/raw_protocol.cpp b/esphome/components/remote_base/raw_protocol.cpp
index 4cbd37d476..62d578caf9 100644
--- a/esphome/components/remote_base/raw_protocol.cpp
+++ b/esphome/components/remote_base/raw_protocol.cpp
@@ -6,7 +6,7 @@ namespace remote_base {
static const char *TAG = "remote.raw";
-void RawDumper::dump(RemoteReceiveData src) {
+bool RawDumper::dump(RemoteReceiveData src) {
char buffer[256];
uint32_t buffer_offset = 0;
buffer_offset += sprintf(buffer, "Received Raw: ");
@@ -16,7 +16,7 @@ void RawDumper::dump(RemoteReceiveData src) {
const uint32_t remaining_length = sizeof(buffer) - buffer_offset;
int written;
- if (i + 1 < src.size()) {
+ if (i + 1 < src.size() - 1) {
written = snprintf(buffer + buffer_offset, remaining_length, "%d, ", value);
} else {
written = snprintf(buffer + buffer_offset, remaining_length, "%d", value);
@@ -40,6 +40,7 @@ void RawDumper::dump(RemoteReceiveData src) {
if (buffer_offset != 0) {
ESP_LOGD(TAG, "%s", buffer);
}
+ return true;
}
} // namespace remote_base
diff --git a/esphome/components/remote_base/raw_protocol.h b/esphome/components/remote_base/raw_protocol.h
index a55bb1fb83..1d9f1c5acc 100644
--- a/esphome/components/remote_base/raw_protocol.h
+++ b/esphome/components/remote_base/raw_protocol.h
@@ -44,9 +44,9 @@ template class RawAction : public RemoteTransmitterActionBasecode_static_ = code;
this->code_static_len_ = len;
}
+ TEMPLATABLE_VALUE(uint32_t, carrier_frequency);
void encode(RemoteTransmitData *dst, Ts... x) override {
- // dst->set_data(data);
if (this->code_static_ != nullptr) {
for (size_t i = 0; i < this->code_static_len_; i++) {
auto val = this->code_static_[i];
@@ -58,6 +58,7 @@ template class RawAction : public RemoteTransmitterActionBaseset_data(this->code_func_(x...));
}
+ dst->set_carrier_frequency(this->carrier_frequency_.value(x...));
}
protected:
@@ -68,7 +69,8 @@ template class RawAction : public RemoteTransmitterActionBaseset_carrier_frequency(0);
for (int16_t i = len - 1; i >= 0; i--) {
if (code & (1 << i))
this->one(dst);
@@ -224,21 +225,25 @@ bool RCSwitchRawReceiver::matches(RemoteReceiveData src) {
return decoded_nbits == this->nbits_ && decoded_code == this->code_;
}
-void RCSwitchDumper::dump(RemoteReceiveData src) {
+bool RCSwitchDumper::dump(RemoteReceiveData src) {
for (uint8_t i = 1; i <= 7; i++) {
src.reset();
uint32_t out_data;
uint8_t out_nbits;
RCSwitchBase *protocol = &rc_switch_protocols[i];
- if (protocol->decode(src, &out_data, &out_nbits)) {
+ if (protocol->decode(src, &out_data, &out_nbits) && out_nbits >= 3) {
char buffer[32];
for (uint8_t j = 0; j < out_nbits; j++)
buffer[j] = (out_data & (1 << (out_nbits - j - 1))) ? '1' : '0';
buffer[out_nbits] = '\0';
ESP_LOGD(TAG, "Received RCSwitch Raw: protocol=%u data='%s'", i, buffer);
+
+ // only send first decoded protocol
+ return true;
}
}
+ return false;
}
} // namespace remote_base
diff --git a/esphome/components/remote_base/rc_switch_protocol.h b/esphome/components/remote_base/rc_switch_protocol.h
index e690d6f929..728561c140 100644
--- a/esphome/components/remote_base/rc_switch_protocol.h
+++ b/esphome/components/remote_base/rc_switch_protocol.h
@@ -197,7 +197,7 @@ class RCSwitchRawReceiver : public RemoteReceiverBinarySensorBase {
class RCSwitchDumper : public RemoteReceiverDumperBase {
public:
- void dump(RemoteReceiveData src) override;
+ bool dump(RemoteReceiveData src) override;
};
} // namespace remote_base
diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h
index 6ad63879ad..d8eb1be356 100644
--- a/esphome/components/remote_base/remote_base.h
+++ b/esphome/components/remote_base/remote_base.h
@@ -212,14 +212,21 @@ class RemoteReceiverListener {
class RemoteReceiverDumperBase {
public:
- virtual void dump(RemoteReceiveData src) = 0;
+ virtual bool dump(RemoteReceiveData src) = 0;
+ virtual bool is_secondary() { return false; }
};
class RemoteReceiverBase : public RemoteComponentBase {
public:
RemoteReceiverBase(GPIOPin *pin) : RemoteComponentBase(pin) {}
void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
- void register_dumper(RemoteReceiverDumperBase *dumper) { this->dumpers_.push_back(dumper); }
+ void register_dumper(RemoteReceiverDumperBase *dumper) {
+ if (dumper->is_secondary()) {
+ this->secondary_dumpers_.push_back(dumper);
+ } else {
+ this->dumpers_.push_back(dumper);
+ }
+ }
void set_tolerance(uint8_t tolerance) { tolerance_ = tolerance; }
protected:
@@ -233,9 +240,17 @@ class RemoteReceiverBase : public RemoteComponentBase {
return success;
}
void call_dumpers_() {
+ bool success = false;
for (auto *dumper : this->dumpers_) {
auto data = RemoteReceiveData(&this->temp_, this->tolerance_);
- dumper->dump(data);
+ if (dumper->dump(data))
+ success = true;
+ }
+ if (!success) {
+ for (auto *dumper : this->secondary_dumpers_) {
+ auto data = RemoteReceiveData(&this->temp_, this->tolerance_);
+ dumper->dump(data);
+ }
}
}
void call_listeners_dumpers_() {
@@ -247,6 +262,7 @@ class RemoteReceiverBase : public RemoteComponentBase {
std::vector listeners_;
std::vector dumpers_;
+ std::vector secondary_dumpers_;
std::vector temp_;
uint8_t tolerance_{25};
};
@@ -323,12 +339,13 @@ template class RemoteTransmitterActionBase : public Action class RemoteReceiverDumper : public RemoteReceiverDumperBase {
public:
- void dump(RemoteReceiveData src) override {
+ bool dump(RemoteReceiveData src) override {
auto proto = T();
auto decoded = proto.decode(src);
if (!decoded.has_value())
- return;
+ return false;
proto.dump(*decoded);
+ return true;
}
};
diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp
index 1c48e4cc7b..3d2e6e4b9a 100644
--- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp
+++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp
@@ -53,6 +53,10 @@ void RemoteReceiverComponent::setup() {
void RemoteReceiverComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Remote Receiver:");
LOG_PIN(" Pin: ", this->pin_);
+ if (this->pin_->digital_read()) {
+ ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to "
+ "invert the signal using 'inverted: True' in the pin schema!");
+ }
ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_);
ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_);
ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_);
diff --git a/esphome/components/sds011/sensor.py b/esphome/components/sds011/sensor.py
index 5b34b2dbbd..0f750810a6 100644
--- a/esphome/components/sds011/sensor.py
+++ b/esphome/components/sds011/sensor.py
@@ -33,7 +33,7 @@ CONFIG_SCHEMA = cv.All(cv.Schema({
sensor.sensor_schema(UNIT_MICROGRAMS_PER_CUBIC_METER, ICON_CHEMICAL_WEAPON, 1),
cv.Optional(CONF_RX_ONLY, default=False): cv.boolean,
- cv.Optional(CONF_UPDATE_INTERVAL, default='0min'): cv.positive_time_period_minutes,
+ cv.Optional(CONF_UPDATE_INTERVAL): cv.positive_time_period_minutes,
}).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA), validate_sds011_rx_mode)
@@ -42,7 +42,8 @@ def to_code(config):
yield cg.register_component(var, config)
yield uart.register_uart_device(var, config)
- cg.add(var.set_update_interval_min(config[CONF_UPDATE_INTERVAL]))
+ if CONF_UPDATE_INTERVAL in config:
+ cg.add(var.set_update_interval_min(config[CONF_UPDATE_INTERVAL]))
cg.add(var.set_rx_mode_only(config[CONF_RX_ONLY]))
if CONF_PM_2_5 in config:
diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py
index 0fe0fc6bca..43f0cefd56 100644
--- a/esphome/components/sensor/__init__.py
+++ b/esphome/components/sensor/__init__.py
@@ -148,7 +148,7 @@ def exponential_moving_average_filter_to_code(config, filter_id):
yield cg.new_Pvariable(filter_id, config[CONF_ALPHA], config[CONF_SEND_EVERY])
-@FILTER_REGISTRY.register('lambda', LambdaFilter, cv.lambda_)
+@FILTER_REGISTRY.register('lambda', LambdaFilter, cv.returning_lambda)
def lambda_filter_to_code(config, filter_id):
lambda_ = yield cg.process_lambda(config, [(float, 'x')],
return_type=cg.optional.template(float))
diff --git a/esphome/components/sensor/sensor.cpp b/esphome/components/sensor/sensor.cpp
index 0f54f80c6d..ca6f4c23bb 100644
--- a/esphome/components/sensor/sensor.cpp
+++ b/esphome/components/sensor/sensor.cpp
@@ -88,10 +88,8 @@ std::string Sensor::unique_id() { return ""; }
void Sensor::internal_send_state_to_frontend(float state) {
this->has_state_ = true;
this->state = state;
- if (this->filter_list_ != nullptr) {
- ESP_LOGD(TAG, "'%s': Sending state %.5f %s with %d decimals of accuracy", this->get_name().c_str(), state,
- this->get_unit_of_measurement().c_str(), this->get_accuracy_decimals());
- }
+ ESP_LOGD(TAG, "'%s': Sending state %.5f %s with %d decimals of accuracy", this->get_name().c_str(), state,
+ this->get_unit_of_measurement().c_str(), this->get_accuracy_decimals());
this->callback_.call(state);
}
bool Sensor::has_state() const { return this->has_state_; }
diff --git a/esphome/components/sun/__init__.py b/esphome/components/sun/__init__.py
new file mode 100644
index 0000000000..625e64dcc2
--- /dev/null
+++ b/esphome/components/sun/__init__.py
@@ -0,0 +1,103 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.components import time
+from esphome.const import CONF_TIME_ID, CONF_ID, CONF_TRIGGER_ID
+
+sun_ns = cg.esphome_ns.namespace('sun')
+
+Sun = sun_ns.class_('Sun')
+SunTrigger = sun_ns.class_('SunTrigger', cg.PollingComponent, automation.Trigger.template())
+SunCondition = sun_ns.class_('SunCondition', automation.Condition)
+
+CONF_SUN_ID = 'sun_id'
+CONF_LATITUDE = 'latitude'
+CONF_LONGITUDE = 'longitude'
+CONF_ELEVATION = 'elevation'
+CONF_ON_SUNRISE = 'on_sunrise'
+CONF_ON_SUNSET = 'on_sunset'
+
+ELEVATION_MAP = {
+ 'sunrise': 0.0,
+ 'sunset': 0.0,
+ 'civil': -6.0,
+ 'nautical': -12.0,
+ 'astronomical': -18.0,
+}
+
+
+def elevation(value):
+ if isinstance(value, str):
+ try:
+ value = ELEVATION_MAP[cv.one_of(*ELEVATION_MAP, lower=True, space='_')]
+ except cv.Invalid:
+ pass
+ value = cv.angle(value)
+ return cv.float_range(min=-180, max=180)(value)
+
+
+CONFIG_SCHEMA = cv.Schema({
+ cv.GenerateID(): cv.declare_id(Sun),
+ cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
+ cv.Required(CONF_LATITUDE): cv.float_range(min=-90, max=90),
+ cv.Required(CONF_LONGITUDE): cv.float_range(min=-180, max=180),
+
+ cv.Optional(CONF_ON_SUNRISE): automation.validate_automation({
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SunTrigger),
+ cv.Optional(CONF_ELEVATION, default=0.0): elevation,
+ }),
+ cv.Optional(CONF_ON_SUNSET): automation.validate_automation({
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(SunTrigger),
+ cv.Optional(CONF_ELEVATION, default=0.0): elevation,
+ }),
+})
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ time_ = yield cg.get_variable(config[CONF_TIME_ID])
+ cg.add(var.set_time(time_))
+ cg.add(var.set_latitude(config[CONF_LATITUDE]))
+ cg.add(var.set_longitude(config[CONF_LONGITUDE]))
+
+ for conf in config.get(CONF_ON_SUNRISE, []):
+ trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID])
+ yield cg.register_component(trigger, conf)
+ yield cg.register_parented(trigger, var)
+ cg.add(trigger.set_sunrise(True))
+ cg.add(trigger.set_elevation(conf[CONF_ELEVATION]))
+ yield automation.build_automation(trigger, [], conf)
+
+ for conf in config.get(CONF_ON_SUNSET, []):
+ trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID])
+ yield cg.register_component(trigger, conf)
+ yield cg.register_parented(trigger, var)
+ cg.add(trigger.set_sunrise(False))
+ cg.add(trigger.set_elevation(conf[CONF_ELEVATION]))
+ yield automation.build_automation(trigger, [], conf)
+
+
+@automation.register_condition('sun.is_above_horizon', SunCondition, cv.Schema({
+ cv.GenerateID(): cv.use_id(Sun),
+ cv.Optional(CONF_ELEVATION, default=0): cv.templatable(elevation),
+}))
+def sun_above_horizon_to_code(config, condition_id, template_arg, args):
+ var = cg.new_Pvariable(condition_id, template_arg)
+ yield cg.register_parented(var, config[CONF_ID])
+ templ = yield cg.templatable(config[CONF_ELEVATION], args, cg.double)
+ cg.add(var.set_elevation(templ))
+ cg.add(var.set_above(True))
+ yield var
+
+
+@automation.register_condition('sun.is_below_horizon', SunCondition, cv.Schema({
+ cv.GenerateID(): cv.use_id(Sun),
+ cv.Optional(CONF_ELEVATION, default=0): cv.templatable(elevation),
+}))
+def sun_below_horizon_to_code(config, condition_id, template_arg, args):
+ var = cg.new_Pvariable(condition_id, template_arg)
+ yield cg.register_parented(var, config[CONF_ID])
+ templ = yield cg.templatable(config[CONF_ELEVATION], args, cg.double)
+ cg.add(var.set_elevation(templ))
+ cg.add(var.set_above(False))
+ yield var
diff --git a/esphome/components/sun/sensor/__init__.py b/esphome/components/sun/sensor/__init__.py
new file mode 100644
index 0000000000..5ca315888d
--- /dev/null
+++ b/esphome/components/sun/sensor/__init__.py
@@ -0,0 +1,30 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import sensor
+from esphome.const import UNIT_DEGREES, ICON_WEATHER_SUNSET, CONF_ID, CONF_TYPE
+from .. import sun_ns, CONF_SUN_ID, Sun
+
+DEPENDENCIES = ['sun']
+
+SunSensor = sun_ns.class_('SunSensor', sensor.Sensor, cg.PollingComponent)
+SensorType = sun_ns.enum('SensorType')
+TYPES = {
+ 'elevation': SensorType.SUN_SENSOR_ELEVATION,
+ 'azimuth': SensorType.SUN_SENSOR_AZIMUTH,
+}
+
+CONFIG_SCHEMA = sensor.sensor_schema(UNIT_DEGREES, ICON_WEATHER_SUNSET, 1).extend({
+ cv.GenerateID(): cv.declare_id(SunSensor),
+ cv.GenerateID(CONF_SUN_ID): cv.use_id(Sun),
+ cv.Required(CONF_TYPE): cv.enum(TYPES, lower=True),
+}).extend(cv.polling_component_schema('60s'))
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield sensor.register_sensor(var, config)
+
+ cg.add(var.set_type(config[CONF_TYPE]))
+ paren = yield cg.get_variable(config[CONF_SUN_ID])
+ cg.add(var.set_parent(paren))
diff --git a/esphome/components/sun/sensor/sun_sensor.cpp b/esphome/components/sun/sensor/sun_sensor.cpp
new file mode 100644
index 0000000000..63b7715287
--- /dev/null
+++ b/esphome/components/sun/sensor/sun_sensor.cpp
@@ -0,0 +1,12 @@
+#include "sun_sensor.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace sun {
+
+static const char *TAG = "sun.sensor";
+
+void SunSensor::dump_config() { LOG_SENSOR("", "Sun Sensor", this); }
+
+} // namespace sun
+} // namespace esphome
diff --git a/esphome/components/sun/sensor/sun_sensor.h b/esphome/components/sun/sensor/sun_sensor.h
new file mode 100644
index 0000000000..2bd33375ef
--- /dev/null
+++ b/esphome/components/sun/sensor/sun_sensor.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/components/sun/sun.h"
+#include "esphome/components/sensor/sensor.h"
+
+namespace esphome {
+namespace sun {
+
+enum SensorType {
+ SUN_SENSOR_ELEVATION,
+ SUN_SENSOR_AZIMUTH,
+};
+
+class SunSensor : public sensor::Sensor, public PollingComponent {
+ public:
+ void set_parent(Sun *parent) { parent_ = parent; }
+ void set_type(SensorType type) { type_ = type; }
+ void dump_config() override;
+ void update() override {
+ double val;
+ switch (this->type_) {
+ case SUN_SENSOR_ELEVATION:
+ val = this->parent_->elevation();
+ break;
+ case SUN_SENSOR_AZIMUTH:
+ val = this->parent_->azimuth();
+ break;
+ default:
+ return;
+ }
+ this->publish_state(val);
+ }
+
+ protected:
+ sun::Sun *parent_;
+ SensorType type_;
+};
+
+} // namespace sun
+} // namespace esphome
diff --git a/esphome/components/sun/sun.cpp b/esphome/components/sun/sun.cpp
new file mode 100644
index 0000000000..e0da63bb4b
--- /dev/null
+++ b/esphome/components/sun/sun.cpp
@@ -0,0 +1,168 @@
+#include "sun.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace sun {
+
+static const char *TAG = "sun";
+
+#undef PI
+
+/* Usually, ESPHome uses single-precision floating point values
+ * because those tend to be accurate enough and are more efficient.
+ *
+ * However, some of the data in this class has to be quite accurate, so double is
+ * used everywhere.
+ */
+static const double PI = 3.141592653589793;
+static const double TAU = 6.283185307179586;
+static const double TO_RADIANS = PI / 180.0;
+static const double TO_DEGREES = 180.0 / PI;
+static const double EARTH_TILT = 23.44 * TO_RADIANS;
+
+optional Sun::sunrise(double elevation) {
+ auto time = this->time_->now();
+ if (!time.is_valid())
+ return {};
+ double sun_time = this->sun_time_for_elevation_(time.day_of_year, elevation, true);
+ if (isnan(sun_time))
+ return {};
+ uint32_t epoch = this->calc_epoch_(time, sun_time);
+ return time::ESPTime::from_epoch_local(epoch);
+}
+optional Sun::sunset(double elevation) {
+ auto time = this->time_->now();
+ if (!time.is_valid())
+ return {};
+ double sun_time = this->sun_time_for_elevation_(time.day_of_year, elevation, false);
+ if (isnan(sun_time))
+ return {};
+ uint32_t epoch = this->calc_epoch_(time, sun_time);
+ return time::ESPTime::from_epoch_local(epoch);
+}
+double Sun::elevation() {
+ auto time = this->current_sun_time_();
+ if (isnan(time))
+ return NAN;
+ return this->elevation_(time);
+}
+double Sun::azimuth() {
+ auto time = this->current_sun_time_();
+ if (isnan(time))
+ return NAN;
+ return this->azimuth_(time);
+}
+double Sun::sun_declination_(double sun_time) {
+ double n = sun_time - 1.0;
+ // maximum declination
+ const double tot = -sin(EARTH_TILT);
+
+ // eccentricity of the earth's orbit (ellipse)
+ double eccentricity = 0.0167;
+
+ // days since perihelion (January 3rd)
+ double days_since_perihelion = n - 2;
+ // days since december solstice (december 22)
+ double days_since_december_solstice = n + 10;
+ const double c = TAU / 365.24;
+ double v = cos(c * days_since_december_solstice + 2 * eccentricity * sin(c * days_since_perihelion));
+ // Make sure value is in range (double error may lead to results slightly larger than 1)
+ double x = clamp(tot * v, 0, 1);
+ return asin(x);
+}
+double Sun::elevation_ratio_(double sun_time) {
+ double decl = this->sun_declination_(sun_time);
+ double hangle = this->hour_angle_(sun_time);
+ double a = sin(this->latitude_rad_()) * sin(decl);
+ double b = cos(this->latitude_rad_()) * cos(decl) * cos(hangle);
+ double val = clamp(a + b, -1.0, 1.0);
+ return val;
+}
+double Sun::latitude_rad_() { return this->latitude_ * TO_RADIANS; }
+double Sun::hour_angle_(double sun_time) {
+ double time_of_day = fmod(sun_time, 1.0) * 24.0;
+ return -PI * (time_of_day - 12) / 12;
+}
+double Sun::elevation_(double sun_time) { return this->elevation_rad_(sun_time) * TO_DEGREES; }
+double Sun::elevation_rad_(double sun_time) { return asin(this->elevation_ratio_(sun_time)); }
+double Sun::zenith_rad_(double sun_time) { return acos(this->elevation_ratio_(sun_time)); }
+double Sun::azimuth_rad_(double sun_time) {
+ double hangle = -this->hour_angle_(sun_time);
+ double decl = this->sun_declination_(sun_time);
+ double zen = this->zenith_rad_(sun_time);
+ double nom = cos(zen) * sin(this->latitude_rad_()) - sin(decl);
+ double denom = sin(zen) * cos(this->latitude_rad_());
+ double v = clamp(nom / denom, -1.0, 1.0);
+ double az = PI - acos(v);
+ if (hangle > 0)
+ az = -az;
+ if (az < 0)
+ az += TAU;
+ return az;
+}
+double Sun::azimuth_(double sun_time) { return this->azimuth_rad_(sun_time) * TO_DEGREES; }
+double Sun::calc_sun_time_(const time::ESPTime &time) {
+ // Time as seen at 0° longitude
+ if (!time.is_valid())
+ return NAN;
+
+ double base = (time.day_of_year + time.hour / 24.0 + time.minute / 24.0 / 60.0 + time.second / 24.0 / 60.0 / 60.0);
+ // Add longitude correction
+ double add = this->longitude_ / 360.0;
+ return base + add;
+}
+uint32_t Sun::calc_epoch_(time::ESPTime base, double sun_time) {
+ sun_time -= this->longitude_ / 360.0;
+ base.day_of_year = uint32_t(floor(sun_time));
+
+ sun_time = (sun_time - base.day_of_year) * 24.0;
+ base.hour = uint32_t(floor(sun_time));
+
+ sun_time = (sun_time - base.hour) * 60.0;
+ base.minute = uint32_t(floor(sun_time));
+
+ sun_time = (sun_time - base.minute) * 60.0;
+ base.second = uint32_t(floor(sun_time));
+
+ base.recalc_timestamp_utc(true);
+ return base.timestamp;
+}
+double Sun::sun_time_for_elevation_(int32_t day_of_year, double elevation, bool rising) {
+ // Use binary search, newton's method would be better but binary search already
+ // converges quite well (19 cycles) and much simpler. Function is guaranteed to be
+ // monotonous.
+ double lo, hi;
+ if (rising) {
+ lo = day_of_year + 0.0;
+ hi = day_of_year + 0.5;
+ } else {
+ lo = day_of_year + 1.0;
+ hi = day_of_year + 0.5;
+ }
+
+ double min_elevation = this->elevation_(lo);
+ double max_elevation = this->elevation_(hi);
+ if (elevation < min_elevation || elevation > max_elevation)
+ return NAN;
+
+ // Accuracy: 0.1s
+ const double accuracy = 1.0 / (24.0 * 60.0 * 60.0 * 10.0);
+
+ while (fabs(hi - lo) > accuracy) {
+ double mid = (lo + hi) / 2.0;
+ double value = this->elevation_(mid) - elevation;
+ if (value < 0) {
+ lo = mid;
+ } else if (value > 0) {
+ hi = mid;
+ } else {
+ lo = hi = mid;
+ break;
+ }
+ }
+
+ return (lo + hi) / 2.0;
+}
+
+} // namespace sun
+} // namespace esphome
diff --git a/esphome/components/sun/sun.h b/esphome/components/sun/sun.h
new file mode 100644
index 0000000000..2592c75c62
--- /dev/null
+++ b/esphome/components/sun/sun.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/core/helpers.h"
+#include "esphome/core/automation.h"
+#include "esphome/components/time/real_time_clock.h"
+
+namespace esphome {
+namespace sun {
+
+class Sun {
+ public:
+ void set_time(time::RealTimeClock *time) { time_ = time; }
+ time::RealTimeClock *get_time() const { return time_; }
+ void set_latitude(double latitude) { latitude_ = latitude; }
+ void set_longitude(double longitude) { longitude_ = longitude; }
+
+ optional sunrise(double elevation = 0.0);
+ optional sunset(double elevation = 0.0);
+
+ double elevation();
+ double azimuth();
+
+ protected:
+ double current_sun_time_() { return this->calc_sun_time_(this->time_->utcnow()); }
+
+ /** Calculate the declination of the sun in rad.
+ *
+ * See https://en.wikipedia.org/wiki/Position_of_the_Sun#Declination_of_the_Sun_as_seen_from_Earth
+ *
+ * Accuracy: ±0.2°
+ *
+ * @param sun_time The day of the year, 1 means January 1st. See calc_sun_time_.
+ * @return Sun declination in degrees
+ */
+ double sun_declination_(double sun_time);
+
+ double elevation_ratio_(double sun_time);
+
+ /** Calculate the hour angle based on the sun time of day in hours.
+ *
+ * Positive in morning, 0 at noon, negative in afternoon.
+ *
+ * @param sun_time Sun time, see calc_sun_time_.
+ * @return Hour angle in rad.
+ */
+ double hour_angle_(double sun_time);
+
+ double elevation_(double sun_time);
+
+ double elevation_rad_(double sun_time);
+
+ double zenith_rad_(double sun_time);
+
+ double azimuth_rad_(double sun_time);
+
+ double azimuth_(double sun_time);
+
+ /** Return the sun time given by the time_ object.
+ *
+ * Sun time is defined as doubleing point day of year.
+ * Integer part encodes the day of the year (1=January 1st)
+ * Decimal part encodes time of day (1/24 = 1 hour)
+ */
+ double calc_sun_time_(const time::ESPTime &time);
+
+ uint32_t calc_epoch_(time::ESPTime base, double sun_time);
+
+ /** Calculate the sun time of day
+ *
+ * @param day_of_year
+ * @param elevation
+ * @param rising
+ * @return
+ */
+ double sun_time_for_elevation_(int32_t day_of_year, double elevation, bool rising);
+
+ double latitude_rad_();
+
+ time::RealTimeClock *time_;
+ /// Latitude in degrees, range: -90 to 90.
+ double latitude_;
+ /// Longitude in degrees, range: -180 to 180.
+ double longitude_;
+};
+
+class SunTrigger : public Trigger<>, public PollingComponent, public Parented {
+ public:
+ SunTrigger() : PollingComponent(1000) {}
+
+ void set_sunrise(bool sunrise) { sunrise_ = sunrise; }
+ void set_elevation(double elevation) { elevation_ = elevation; }
+
+ void update() override {
+ double current = this->parent_->elevation();
+ if (isnan(current))
+ return;
+
+ bool crossed;
+ if (this->sunrise_) {
+ crossed = this->last_elevation_ <= this->elevation_ && this->elevation_ < current;
+ } else {
+ crossed = this->last_elevation_ >= this->elevation_ && this->elevation_ > current;
+ }
+
+ if (crossed) {
+ this->trigger();
+ }
+ this->last_elevation_ = current;
+ }
+
+ protected:
+ bool sunrise_;
+ double last_elevation_;
+ double elevation_;
+};
+
+template class SunCondition : public Condition, public Parented {
+ public:
+ TEMPLATABLE_VALUE(double, elevation);
+ void set_above(bool above) { above_ = above; }
+
+ bool check(Ts... x) override {
+ double elevation = this->elevation_.value(x...);
+ double current = this->parent_->elevation();
+ if (this->above_)
+ return current > elevation;
+ else
+ return current < elevation;
+ }
+
+ protected:
+ bool above_;
+};
+
+} // namespace sun
+} // namespace esphome
diff --git a/esphome/components/sun/text_sensor/__init__.py b/esphome/components/sun/text_sensor/__init__.py
new file mode 100644
index 0000000000..9a82a3d75f
--- /dev/null
+++ b/esphome/components/sun/text_sensor/__init__.py
@@ -0,0 +1,45 @@
+from esphome.components import text_sensor
+import esphome.config_validation as cv
+import esphome.codegen as cg
+from esphome.const import CONF_ICON, ICON_WEATHER_SUNSET_DOWN, ICON_WEATHER_SUNSET_UP, CONF_TYPE, \
+ CONF_ID, CONF_FORMAT
+from .. import sun_ns, CONF_SUN_ID, Sun, CONF_ELEVATION, elevation
+
+DEPENDENCIES = ['sun']
+
+SunTextSensor = sun_ns.class_('SunTextSensor', text_sensor.TextSensor, cg.PollingComponent)
+SUN_TYPES = {
+ 'sunset': False,
+ 'sunrise': True,
+}
+
+
+def validate_optional_icon(config):
+ if CONF_ICON not in config:
+ config = config.copy()
+ config[CONF_ICON] = {
+ 'sunset': ICON_WEATHER_SUNSET_DOWN,
+ 'sunrise': ICON_WEATHER_SUNSET_UP,
+ }[config[CONF_TYPE]]
+ return config
+
+
+CONFIG_SCHEMA = cv.All(text_sensor.TEXT_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(SunTextSensor),
+ cv.GenerateID(CONF_SUN_ID): cv.use_id(Sun),
+ cv.Required(CONF_TYPE): cv.one_of(*SUN_TYPES, lower=True),
+ cv.Optional(CONF_ELEVATION, default=0): elevation,
+ cv.Optional(CONF_FORMAT, default='%X'): cv.string_strict,
+}).extend(cv.polling_component_schema('60s')), validate_optional_icon)
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+ yield text_sensor.register_text_sensor(var, config)
+
+ paren = yield cg.get_variable(config[CONF_SUN_ID])
+ cg.add(var.set_parent(paren))
+ cg.add(var.set_sunrise(SUN_TYPES[config[CONF_TYPE]]))
+ cg.add(var.set_elevation(config[CONF_ELEVATION]))
+ cg.add(var.set_format(config[CONF_FORMAT]))
diff --git a/esphome/components/sun/text_sensor/sun_text_sensor.cpp b/esphome/components/sun/text_sensor/sun_text_sensor.cpp
new file mode 100644
index 0000000000..ee949584cc
--- /dev/null
+++ b/esphome/components/sun/text_sensor/sun_text_sensor.cpp
@@ -0,0 +1,12 @@
+#include "sun_text_sensor.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace sun {
+
+static const char *TAG = "sun.text_sensor";
+
+void SunTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Sun Text Sensor", this); }
+
+} // namespace sun
+} // namespace esphome
diff --git a/esphome/components/sun/text_sensor/sun_text_sensor.h b/esphome/components/sun/text_sensor/sun_text_sensor.h
new file mode 100644
index 0000000000..e4f5beca9c
--- /dev/null
+++ b/esphome/components/sun/text_sensor/sun_text_sensor.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/components/sun/sun.h"
+#include "esphome/components/text_sensor/text_sensor.h"
+
+namespace esphome {
+namespace sun {
+
+class SunTextSensor : public text_sensor::TextSensor, public PollingComponent {
+ public:
+ void set_parent(Sun *parent) { parent_ = parent; }
+ void set_elevation(double elevation) { elevation_ = elevation; }
+ void set_sunrise(bool sunrise) { sunrise_ = sunrise; }
+ void set_format(const std::string &format) { format_ = format; }
+
+ void update() override {
+ optional res;
+ if (this->sunrise_)
+ res = this->parent_->sunrise(this->elevation_);
+ else
+ res = this->parent_->sunset(this->elevation_);
+ if (!res) {
+ this->publish_state("");
+ return;
+ }
+
+ this->publish_state(res->strftime(this->format_));
+ }
+
+ void dump_config() override;
+
+ protected:
+ std::string format_{};
+ Sun *parent_;
+ double elevation_;
+ bool sunrise_;
+};
+
+} // namespace sun
+} // namespace esphome
diff --git a/esphome/components/template/binary_sensor/__init__.py b/esphome/components/template/binary_sensor/__init__.py
index 9c1fb549e6..14f9f23ec2 100644
--- a/esphome/components/template/binary_sensor/__init__.py
+++ b/esphome/components/template/binary_sensor/__init__.py
@@ -10,7 +10,7 @@ TemplateBinarySensor = template_ns.class_('TemplateBinarySensor', binary_sensor.
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(TemplateBinarySensor),
- cv.Optional(CONF_LAMBDA): cv.lambda_,
+ cv.Optional(CONF_LAMBDA): cv.returning_lambda,
}).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/template/cover/__init__.py b/esphome/components/template/cover/__init__.py
index 0eccb9fc73..33b3b62870 100644
--- a/esphome/components/template/cover/__init__.py
+++ b/esphome/components/template/cover/__init__.py
@@ -18,7 +18,7 @@ RESTORE_MODES = {
CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(TemplateCover),
- cv.Optional(CONF_LAMBDA): cv.lambda_,
+ cv.Optional(CONF_LAMBDA): cv.returning_lambda,
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
cv.Optional(CONF_ASSUMED_STATE, default=False): cv.boolean,
cv.Optional(CONF_OPEN_ACTION): automation.validate_automation(single=True),
diff --git a/esphome/components/template/output/__init__.py b/esphome/components/template/output/__init__.py
new file mode 100644
index 0000000000..5cc9e089bd
--- /dev/null
+++ b/esphome/components/template/output/__init__.py
@@ -0,0 +1,35 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import automation
+from esphome.components import output
+from esphome.const import CONF_ID, CONF_TYPE
+from .. import template_ns
+
+TemplateBinaryOutput = template_ns.class_('TemplateBinaryOutput', output.BinaryOutput)
+TemplateFloatOutput = template_ns.class_('TemplateFloatOutput', output.FloatOutput)
+
+CONF_BINARY = 'binary'
+CONF_FLOAT = 'float'
+CONF_WRITE_ACTION = 'write_action'
+
+CONFIG_SCHEMA = cv.typed_schema({
+ CONF_BINARY: output.BINARY_OUTPUT_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TemplateBinaryOutput),
+ cv.Required(CONF_WRITE_ACTION): automation.validate_automation(single=True),
+ }),
+ CONF_FLOAT: output.FLOAT_OUTPUT_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TemplateFloatOutput),
+ cv.Required(CONF_WRITE_ACTION): automation.validate_automation(single=True),
+ }),
+}, lower=True)
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ if config[CONF_TYPE] == CONF_BINARY:
+ yield automation.build_automation(var.get_trigger(), [(bool, 'state')],
+ config[CONF_WRITE_ACTION])
+ else:
+ yield automation.build_automation(var.get_trigger(), [(float, 'state')],
+ config[CONF_WRITE_ACTION])
+ yield output.register_output(var, config)
diff --git a/esphome/components/template/output/template_output.h b/esphome/components/template/output/template_output.h
new file mode 100644
index 0000000000..90de801a5c
--- /dev/null
+++ b/esphome/components/template/output/template_output.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "esphome/core/automation.h"
+#include "esphome/components/output/binary_output.h"
+#include "esphome/components/output/float_output.h"
+
+namespace esphome {
+namespace template_ {
+
+class TemplateBinaryOutput : public output::BinaryOutput {
+ public:
+ Trigger *get_trigger() const { return trigger_; }
+
+ protected:
+ void write_state(bool state) override { this->trigger_->trigger(state); }
+
+ Trigger *trigger_ = new Trigger();
+};
+
+class TemplateFloatOutput : public output::FloatOutput {
+ public:
+ Trigger *get_trigger() const { return trigger_; }
+
+ protected:
+ void write_state(float state) override { this->trigger_->trigger(state); }
+
+ Trigger *trigger_ = new Trigger();
+};
+
+} // namespace template_
+} // namespace esphome
diff --git a/esphome/components/template/sensor/__init__.py b/esphome/components/template/sensor/__init__.py
index 788520877a..3fc71cf9de 100644
--- a/esphome/components/template/sensor/__init__.py
+++ b/esphome/components/template/sensor/__init__.py
@@ -9,7 +9,7 @@ TemplateSensor = template_ns.class_('TemplateSensor', sensor.Sensor, cg.PollingC
CONFIG_SCHEMA = sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1).extend({
cv.GenerateID(): cv.declare_id(TemplateSensor),
- cv.Optional(CONF_LAMBDA): cv.lambda_,
+ cv.Optional(CONF_LAMBDA): cv.returning_lambda,
}).extend(cv.polling_component_schema('60s'))
diff --git a/esphome/components/template/switch/__init__.py b/esphome/components/template/switch/__init__.py
index ac27770d47..783f5a1922 100644
--- a/esphome/components/template/switch/__init__.py
+++ b/esphome/components/template/switch/__init__.py
@@ -10,7 +10,7 @@ TemplateSwitch = template_ns.class_('TemplateSwitch', switch.Switch, cg.Componen
CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(TemplateSwitch),
- cv.Optional(CONF_LAMBDA): cv.lambda_,
+ cv.Optional(CONF_LAMBDA): cv.returning_lambda,
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
cv.Optional(CONF_ASSUMED_STATE, default=False): cv.boolean,
cv.Optional(CONF_TURN_OFF_ACTION): automation.validate_automation(single=True),
diff --git a/esphome/components/template/text_sensor/__init__.py b/esphome/components/template/text_sensor/__init__.py
index 23b71a3974..dae99dc9bc 100644
--- a/esphome/components/template/text_sensor/__init__.py
+++ b/esphome/components/template/text_sensor/__init__.py
@@ -11,7 +11,7 @@ TemplateTextSensor = template_ns.class_('TemplateTextSensor', text_sensor.TextSe
CONFIG_SCHEMA = text_sensor.TEXT_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(TemplateTextSensor),
- cv.Optional(CONF_LAMBDA): cv.lambda_,
+ cv.Optional(CONF_LAMBDA): cv.returning_lambda,
}).extend(cv.polling_component_schema('60s'))
diff --git a/esphome/components/time/automation.cpp b/esphome/components/time/automation.cpp
index 67b86e67ea..1232e6f834 100644
--- a/esphome/components/time/automation.cpp
+++ b/esphome/components/time/automation.cpp
@@ -4,7 +4,7 @@
namespace esphome {
namespace time {
-static const char *TAG = "something.something";
+static const char *TAG = "automation";
void CronTrigger::add_second(uint8_t second) { this->seconds_[second] = true; }
void CronTrigger::add_minute(uint8_t minute) { this->minutes_[minute] = true; }
@@ -38,11 +38,11 @@ void CronTrigger::loop() {
}
this->last_check_ = time;
- if (!time.in_range()) {
+ if (!time.fields_in_range()) {
ESP_LOGW(TAG, "Time is out of range!");
ESP_LOGD(TAG, "Second=%02u Minute=%02u Hour=%02u DayOfWeek=%u DayOfMonth=%u DayOfYear=%u Month=%u time=%ld",
time.second, time.minute, time.hour, time.day_of_week, time.day_of_month, time.day_of_year, time.month,
- time.time);
+ time.timestamp);
}
if (this->matches(time))
diff --git a/esphome/components/time/real_time_clock.cpp b/esphome/components/time/real_time_clock.cpp
index f20a9fcaa2..81524826be 100644
--- a/esphome/components/time/real_time_clock.cpp
+++ b/esphome/components/time/real_time_clock.cpp
@@ -35,27 +35,30 @@ size_t ESPTime::strftime(char *buffer, size_t buffer_len, const char *format) {
return ::strftime(buffer, buffer_len, format, &c_tm);
}
ESPTime ESPTime::from_c_tm(struct tm *c_tm, time_t c_time) {
- return ESPTime{.second = uint8_t(c_tm->tm_sec),
- .minute = uint8_t(c_tm->tm_min),
- .hour = uint8_t(c_tm->tm_hour),
- .day_of_week = uint8_t(c_tm->tm_wday + 1),
- .day_of_month = uint8_t(c_tm->tm_mday),
- .day_of_year = uint16_t(c_tm->tm_yday + 1),
- .month = uint8_t(c_tm->tm_mon + 1),
- .year = uint16_t(c_tm->tm_year + 1900),
- .is_dst = bool(c_tm->tm_isdst),
- .time = c_time};
+ ESPTime res{};
+ res.second = uint8_t(c_tm->tm_sec);
+ res.minute = uint8_t(c_tm->tm_min);
+ res.hour = uint8_t(c_tm->tm_hour);
+ res.day_of_week = uint8_t(c_tm->tm_wday + 1);
+ res.day_of_month = uint8_t(c_tm->tm_mday);
+ res.day_of_year = uint16_t(c_tm->tm_yday + 1);
+ res.month = uint8_t(c_tm->tm_mon + 1);
+ res.year = uint16_t(c_tm->tm_year + 1900);
+ res.is_dst = bool(c_tm->tm_isdst);
+ res.timestamp = c_time;
+ return res;
}
struct tm ESPTime::to_c_tm() {
- struct tm c_tm = tm{.tm_sec = this->second,
- .tm_min = this->minute,
- .tm_hour = this->hour,
- .tm_mday = this->day_of_month,
- .tm_mon = this->month - 1,
- .tm_year = this->year - 1900,
- .tm_wday = this->day_of_week - 1,
- .tm_yday = this->day_of_year - 1,
- .tm_isdst = this->is_dst};
+ struct tm c_tm {};
+ c_tm.tm_sec = this->second;
+ c_tm.tm_min = this->minute;
+ c_tm.tm_hour = this->hour;
+ c_tm.tm_mday = this->day_of_month;
+ c_tm.tm_mon = this->month - 1;
+ c_tm.tm_year = this->year - 1900;
+ c_tm.tm_wday = this->day_of_week - 1;
+ c_tm.tm_yday = this->day_of_year - 1;
+ c_tm.tm_isdst = this->is_dst;
return c_tm;
}
std::string ESPTime::strftime(const std::string &format) {
@@ -70,7 +73,6 @@ std::string ESPTime::strftime(const std::string &format) {
timestr.resize(len);
return timestr;
}
-bool ESPTime::is_valid() const { return this->year >= 2018; }
template bool increment_time_value(T ¤t, uint16_t begin, uint16_t end) {
current++;
@@ -81,8 +83,18 @@ template bool increment_time_value(T ¤t, uint16_t begin, uint1
return false;
}
+static bool is_leap_year(uint32_t year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); }
+
+static bool days_in_month(uint8_t month, uint16_t year) {
+ static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ uint8_t days_in_month = DAYS_IN_MONTH[month];
+ if (month == 2 && is_leap_year(year))
+ days_in_month = 29;
+ return days_in_month;
+}
+
void ESPTime::increment_second() {
- this->time++;
+ this->timestamp++;
if (!increment_time_value(this->second, 0, 60))
return;
@@ -97,12 +109,7 @@ void ESPTime::increment_second() {
// hour roll-over, increment day
increment_time_value(this->day_of_week, 1, 8);
- static const uint8_t DAYS_IN_MONTH[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- uint8_t days_in_month = DAYS_IN_MONTH[this->month];
- if (this->month == 2 && this->year % 4 == 0)
- days_in_month = 29;
-
- if (increment_time_value(this->day_of_month, 1, days_in_month + 1)) {
+ if (increment_time_value(this->day_of_month, 1, days_in_month(this->month, this->year) + 1)) {
// day of month roll-over, increment month
increment_time_value(this->month, 1, 13);
}
@@ -113,16 +120,39 @@ void ESPTime::increment_second() {
this->year++;
}
}
-bool ESPTime::operator<(ESPTime other) { return this->time < other.time; }
-bool ESPTime::operator<=(ESPTime other) { return this->time <= other.time; }
-bool ESPTime::operator==(ESPTime other) { return this->time == other.time; }
-bool ESPTime::operator>=(ESPTime other) { return this->time >= other.time; }
-bool ESPTime::operator>(ESPTime other) { return this->time > other.time; }
-bool ESPTime::in_range() const {
- return this->second < 61 && this->minute < 60 && this->hour < 24 && this->day_of_week > 0 && this->day_of_week < 8 &&
- this->day_of_month > 0 && this->day_of_month < 32 && this->day_of_year > 0 && this->day_of_year < 367 &&
- this->month > 0 && this->month < 13;
+void ESPTime::recalc_timestamp_utc(bool use_day_of_year) {
+ time_t res = 0;
+
+ if (!this->fields_in_range()) {
+ this->timestamp = -1;
+ return;
+ }
+
+ for (uint16_t i = 1970; i < this->year; i++)
+ res += is_leap_year(i) ? 366 : 365;
+
+ if (use_day_of_year) {
+ res += this->day_of_year - 1;
+ } else {
+ for (uint8_t i = 1; i < this->month; ++i)
+ res += days_in_month(i, this->year);
+
+ res += this->day_of_month - 1;
+ }
+
+ res *= 24;
+ res += this->hour;
+ res *= 60;
+ res += this->minute;
+ res *= 60;
+ res += this->second;
+ this->timestamp = res;
}
+bool ESPTime::operator<(ESPTime other) { return this->timestamp < other.timestamp; }
+bool ESPTime::operator<=(ESPTime other) { return this->timestamp <= other.timestamp; }
+bool ESPTime::operator==(ESPTime other) { return this->timestamp == other.timestamp; }
+bool ESPTime::operator>=(ESPTime other) { return this->timestamp >= other.timestamp; }
+bool ESPTime::operator>(ESPTime other) { return this->timestamp > other.timestamp; }
} // namespace time
} // namespace esphome
diff --git a/esphome/components/time/real_time_clock.h b/esphome/components/time/real_time_clock.h
index b87636d20e..9f40fdc5b5 100644
--- a/esphome/components/time/real_time_clock.h
+++ b/esphome/components/time/real_time_clock.h
@@ -1,6 +1,7 @@
#pragma once
#include "esphome/core/component.h"
+#include "esphome/core/helpers.h"
#include
#include
#include
@@ -30,8 +31,11 @@ struct ESPTime {
uint16_t year;
/// daylight savings time flag
bool is_dst;
- /// unix epoch time (seconds since UTC Midnight January 1, 1970)
- time_t time;
+ union {
+ ESPDEPRECATED(".time is deprecated, use .timestamp instead") time_t time;
+ /// unix epoch time (seconds since UTC Midnight January 1, 1970)
+ time_t timestamp;
+ };
/** Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument.
* Up to buffer_len bytes are written.
@@ -48,13 +52,20 @@ struct ESPTime {
*/
std::string strftime(const std::string &format);
- bool is_valid() const;
+ /// Check if this ESPTime is valid (all fields in range and year is greater than 2018)
+ bool is_valid() const { return this->year >= 2019 && this->fields_in_range(); }
- bool in_range() const;
+ /// Check if all time fields of this ESPTime are in range.
+ bool fields_in_range() const {
+ return this->second < 61 && this->minute < 60 && this->hour < 24 && this->day_of_week > 0 &&
+ this->day_of_week < 8 && this->day_of_month > 0 && this->day_of_month < 32 && this->day_of_year > 0 &&
+ this->day_of_year < 367 && this->month > 0 && this->month < 13;
+ }
+ /// Convert a C tm struct instance with a C unix epoch timestamp to an ESPTime instance.
static ESPTime from_c_tm(struct tm *c_tm, time_t c_time);
- /** Convert an epoch timestamp to an ESPTime instance of local time.
+ /** Convert an UTC epoch timestamp to a local time ESPTime instance.
*
* @param epoch Seconds since 1st January 1970. In UTC.
* @return The generated ESPTime
@@ -63,7 +74,7 @@ struct ESPTime {
struct tm *c_tm = ::localtime(&epoch);
return ESPTime::from_c_tm(c_tm, epoch);
}
- /** Convert an epoch timestamp to an ESPTime instance of UTC time.
+ /** Convert an UTC epoch timestamp to a UTC time ESPTime instance.
*
* @param epoch Seconds since 1st January 1970. In UTC.
* @return The generated ESPTime
@@ -73,8 +84,13 @@ struct ESPTime {
return ESPTime::from_c_tm(c_tm, epoch);
}
+ /// Recalculate the timestamp field from the other fields of this ESPTime instance (must be UTC).
+ void recalc_timestamp_utc(bool use_day_of_year = true);
+
+ /// Convert this ESPTime instance back to a tm struct.
struct tm to_c_tm();
+ /// Increment this clock instance by one second.
void increment_second();
bool operator<(ESPTime other);
bool operator<=(ESPTime other);
@@ -100,10 +116,10 @@ class RealTimeClock : public Component {
std::string get_timezone() { return this->timezone_; }
/// Get the time in the currently defined timezone.
- ESPTime now() { return ESPTime::from_epoch_utc(this->timestamp_now()); }
+ ESPTime now() { return ESPTime::from_epoch_local(this->timestamp_now()); }
/// Get the time without any time zone or DST corrections.
- ESPTime utcnow() { return ESPTime::from_epoch_local(this->timestamp_now()); }
+ ESPTime utcnow() { return ESPTime::from_epoch_utc(this->timestamp_now()); }
/// Get the current time as the UTC epoch since January 1st 1970.
time_t timestamp_now() { return ::time(nullptr); }
diff --git a/esphome/components/ttp229_bsf/__init__.py b/esphome/components/ttp229_bsf/__init__.py
new file mode 100644
index 0000000000..5ec182d46b
--- /dev/null
+++ b/esphome/components/ttp229_bsf/__init__.py
@@ -0,0 +1,29 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome import pins
+from esphome.const import CONF_ID, CONF_SDO_PIN, CONF_SCL_PIN
+
+DEPENDENCIES = ['i2c']
+AUTO_LOAD = ['binary_sensor']
+
+CONF_TTP229_ID = 'ttp229_id'
+ttp229_bsf_ns = cg.esphome_ns.namespace('ttp229_bsf')
+
+TTP229BSFComponent = ttp229_bsf_ns.class_('TTP229BSFComponent', cg.Component)
+
+MULTI_CONF = True
+CONFIG_SCHEMA = cv.Schema({
+ cv.GenerateID(): cv.declare_id(TTP229BSFComponent),
+ cv.Required(CONF_SDO_PIN): pins.gpio_input_pullup_pin_schema,
+ cv.Required(CONF_SCL_PIN): pins.gpio_output_pin_schema,
+}).extend(cv.COMPONENT_SCHEMA)
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield cg.register_component(var, config)
+
+ sdo = yield cg.gpio_pin_expression(config[CONF_SDO_PIN])
+ cg.add(var.set_sdo_pin(sdo))
+ scl = yield cg.gpio_pin_expression(config[CONF_SCL_PIN])
+ cg.add(var.set_scl_pin(scl))
diff --git a/esphome/components/ttp229_bsf/binary_sensor.py b/esphome/components/ttp229_bsf/binary_sensor.py
new file mode 100644
index 0000000000..7a1ab3dc9f
--- /dev/null
+++ b/esphome/components/ttp229_bsf/binary_sensor.py
@@ -0,0 +1,23 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import binary_sensor
+from esphome.const import CONF_CHANNEL, CONF_ID
+from . import ttp229_bsf_ns, TTP229BSFComponent, CONF_TTP229_ID
+
+DEPENDENCIES = ['ttp229_bsf']
+TTP229BSFChannel = ttp229_bsf_ns.class_('TTP229BSFChannel', binary_sensor.BinarySensor)
+
+CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
+ cv.GenerateID(): cv.declare_id(TTP229BSFChannel),
+ cv.GenerateID(CONF_TTP229_ID): cv.use_id(TTP229BSFComponent),
+ cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=15),
+})
+
+
+def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ yield binary_sensor.register_binary_sensor(var, config)
+
+ cg.add(var.set_channel(config[CONF_CHANNEL]))
+ hub = yield cg.get_variable(config[CONF_TTP229_ID])
+ cg.add(hub.register_channel(var))
diff --git a/esphome/components/ttp229_bsf/ttp229_bsf.cpp b/esphome/components/ttp229_bsf/ttp229_bsf.cpp
new file mode 100644
index 0000000000..9b5c3c67de
--- /dev/null
+++ b/esphome/components/ttp229_bsf/ttp229_bsf.cpp
@@ -0,0 +1,23 @@
+#include "ttp229_bsf.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace ttp229_bsf {
+
+static const char *TAG = "ttp229_bsf";
+
+void TTP229BSFComponent::setup() {
+ ESP_LOGCONFIG(TAG, "Setting up ttp229_bsf... ");
+ this->sdo_pin_->setup();
+ this->scl_pin_->setup();
+ this->scl_pin_->digital_write(true);
+ delay(2);
+}
+void TTP229BSFComponent::dump_config() {
+ ESP_LOGCONFIG(TAG, "ttp229:");
+ LOG_PIN(" SCL pin: ", this->scl_pin_);
+ LOG_PIN(" SDO pin: ", this->sdo_pin_);
+}
+
+} // namespace ttp229_bsf
+} // namespace esphome
diff --git a/esphome/components/ttp229_bsf/ttp229_bsf.h b/esphome/components/ttp229_bsf/ttp229_bsf.h
new file mode 100644
index 0000000000..94dd014d8e
--- /dev/null
+++ b/esphome/components/ttp229_bsf/ttp229_bsf.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#include "esphome/core/component.h"
+#include "esphome/components/binary_sensor/binary_sensor.h"
+
+namespace esphome {
+namespace ttp229_bsf {
+
+class TTP229BSFChannel : public binary_sensor::BinarySensor {
+ public:
+ void set_channel(uint8_t channel) { channel_ = channel; }
+ void process(uint16_t data) { this->publish_state(data & (1 << this->channel_)); }
+
+ protected:
+ uint8_t channel_;
+};
+
+class TTP229BSFComponent : public Component {
+ public:
+ void set_sdo_pin(GPIOPin *sdo_pin) { sdo_pin_ = sdo_pin; }
+ void set_scl_pin(GPIOPin *scl_pin) { scl_pin_ = scl_pin; }
+ void register_channel(TTP229BSFChannel *channel) { this->channels_.push_back(channel); }
+ void setup() override;
+ void dump_config() override;
+ float get_setup_priority() const override { return setup_priority::DATA; }
+ void loop() override {
+ // check datavalid if sdo is high
+ if (!this->sdo_pin_->digital_read()) {
+ return;
+ }
+ uint16_t touched = 0;
+ for (uint8_t i = 0; i < 16; i++) {
+ this->scl_pin_->digital_write(false);
+ delayMicroseconds(2); // 500KHz
+ bool bitval = !this->sdo_pin_->digital_read();
+ this->scl_pin_->digital_write(true);
+ delayMicroseconds(2); // 500KHz
+
+ touched |= uint16_t(bitval) << i;
+ }
+ for (auto *channel : this->channels_) {
+ channel->process(touched);
+ }
+ }
+
+ protected:
+ GPIOPin *sdo_pin_;
+ GPIOPin *scl_pin_;
+ std::vector channels_{};
+};
+
+} // namespace ttp229_bsf
+} // namespace esphome
diff --git a/esphome/components/ttp229_lsf/__init__.py b/esphome/components/ttp229_lsf/__init__.py
index 8b26102c65..6faca970f0 100644
--- a/esphome/components/ttp229_lsf/__init__.py
+++ b/esphome/components/ttp229_lsf/__init__.py
@@ -11,6 +11,7 @@ ttp229_lsf_ns = cg.esphome_ns.namespace('ttp229_lsf')
TTP229LSFComponent = ttp229_lsf_ns.class_('TTP229LSFComponent', cg.Component, i2c.I2CDevice)
+MULTI_CONF = True
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(TTP229LSFComponent),
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x57))
diff --git a/esphome/components/ttp229_lsf/binary_sensor.py b/esphome/components/ttp229_lsf/binary_sensor.py
index da2f8d2717..870bf16287 100644
--- a/esphome/components/ttp229_lsf/binary_sensor.py
+++ b/esphome/components/ttp229_lsf/binary_sensor.py
@@ -10,7 +10,7 @@ TTP229Channel = ttp229_lsf_ns.class_('TTP229Channel', binary_sensor.BinarySensor
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(TTP229Channel),
cv.GenerateID(CONF_TTP229_ID): cv.use_id(TTP229LSFComponent),
- cv.Required(CONF_CHANNEL): cv.All(cv.int_, cv.Range(min=0, max=15))
+ cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=15),
})
diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py
index ef959b69ef..06a0ed94df 100644
--- a/esphome/components/uart/__init__.py
+++ b/esphome/components/uart/__init__.py
@@ -19,7 +19,7 @@ def validate_rx_pin(value):
CONFIG_SCHEMA = cv.All(cv.Schema({
cv.GenerateID(): cv.declare_id(UARTComponent),
- cv.Required(CONF_BAUD_RATE): cv.All(cv.int_, cv.Range(min=1, max=115200)),
+ cv.Required(CONF_BAUD_RATE): cv.int_range(min=1, max=115200),
cv.Optional(CONF_TX_PIN): pins.output_pin,
cv.Optional(CONF_RX_PIN): validate_rx_pin,
}).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN))
diff --git a/esphome/config.py b/esphome/config.py
index 901a78ea9a..ad86811f19 100644
--- a/esphome/config.py
+++ b/esphome/config.py
@@ -7,6 +7,7 @@ import re
import os.path
# pylint: disable=unused-import, wrong-import-order
+import sys
from contextlib import contextmanager
import voluptuous as vol
@@ -17,7 +18,7 @@ from esphome.components.substitutions import CONF_SUBSTITUTIONS
from esphome.const import CONF_ESPHOME, CONF_PLATFORM, ESP_PLATFORMS
from esphome.core import CORE, EsphomeError # noqa
from esphome.helpers import color, indent
-from esphome.py_compat import text_type
+from esphome.py_compat import text_type, IS_PY2
from esphome.util import safe_print, OrderedDict
from typing import List, Optional, Tuple, Union # noqa
@@ -69,10 +70,6 @@ class ComponentManifest(object):
def auto_load(self):
return getattr(self.module, 'AUTO_LOAD', [])
- @property
- def to_code_priority(self):
- return getattr(self.module, 'TO_CODE_PRIORITY', [])
-
def _get_flags_set(self, name, config):
if not hasattr(self.module, name):
return set()
@@ -110,24 +107,59 @@ class ComponentManifest(object):
CORE_COMPONENTS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), 'components'))
+_UNDEF = object()
+CUSTOM_COMPONENTS_PATH = _UNDEF
+
+
+def _mount_config_dir():
+ global CUSTOM_COMPONENTS_PATH
+ if CUSTOM_COMPONENTS_PATH is not _UNDEF:
+ return
+ custom_path = os.path.abspath(os.path.join(CORE.config_dir, 'custom_components'))
+ if not os.path.isdir(custom_path):
+ CUSTOM_COMPONENTS_PATH = None
+ return
+ init_path = os.path.join(custom_path, '__init__.py')
+ if IS_PY2 and not os.path.isfile(init_path):
+ _LOGGER.warning("Found 'custom_components' folder, but file __init__.py was not found. "
+ "ESPHome will automatically create it now....")
+ with open(init_path, 'w') as f:
+ f.write('\n')
+ if CORE.config_dir not in sys.path:
+ sys.path.insert(0, CORE.config_dir)
+ CUSTOM_COMPONENTS_PATH = custom_path
def _lookup_module(domain, is_platform):
if domain in _COMPONENT_CACHE:
return _COMPONENT_CACHE[domain]
- path = 'esphome.components.{}'.format(domain)
+ _mount_config_dir()
+ # First look for custom_components
try:
- module = importlib.import_module(path)
- except ImportError:
- import traceback
- _LOGGER.error("Unable to import component %s:", domain)
- traceback.print_exc()
+ module = importlib.import_module('custom_components.{}'.format(domain))
+ except ImportError as e:
+ # ImportError when no such module
+ if 'No module named' not in str(e):
+ _LOGGER.warning("Unable to import custom component %s:", domain, exc_info=True)
+ except Exception: # pylint: disable=broad-except
+ # Other error means component has an issue
+ _LOGGER.error("Unable to load custom component %s:", domain, exc_info=True)
+ return None
+ else:
+ # Found in custom components
+ manif = ComponentManifest(module, CUSTOM_COMPONENTS_PATH, is_platform=is_platform)
+ _COMPONENT_CACHE[domain] = manif
+ return manif
+
+ try:
+ module = importlib.import_module('esphome.components.{}'.format(domain))
+ except ImportError as e:
+ if 'No module named' not in str(e):
+ _LOGGER.error("Unable to import component %s:", domain, exc_info=True)
return None
except Exception: # pylint: disable=broad-except
- import traceback
- _LOGGER.error("Unable to load component %s:", domain)
- traceback.print_exc()
+ _LOGGER.error("Unable to load component %s:", domain, exc_info=True)
return None
else:
manif = ComponentManifest(module, CORE_COMPONENTS_PATH, is_platform=is_platform)
@@ -233,15 +265,19 @@ class Config(OrderedDict):
return err
return None
- def get_deepest_value_for_path(self, path):
- # type: (ConfigPath) -> ConfigType
+ def get_deepest_document_range_for_path(self, path):
+ # type: (ConfigPath) -> Optional[ESPHomeDataBase]
data = self
+ doc_range = None
for item_index in path:
try:
data = data[item_index]
except (KeyError, IndexError, TypeError):
- return data
- return data
+ return doc_range
+ if isinstance(data, ESPHomeDataBase) and data.esp_range is not None:
+ doc_range = data.esp_range
+
+ return doc_range
def get_nested_item(self, path):
# type: (ConfigPath) -> ConfigType
diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py
index c235371db1..ddad36f8a8 100644
--- a/esphome/config_helpers.py
+++ b/esphome/config_helpers.py
@@ -2,6 +2,7 @@ from __future__ import print_function
import codecs
import json
+import os
from esphome.core import CORE, EsphomeError
from esphome.py_compat import safe_input
@@ -9,7 +10,8 @@ from esphome.py_compat import safe_input
def read_config_file(path):
# type: (basestring) -> unicode
- if CORE.vscode:
+ if CORE.vscode and (not CORE.ace or
+ os.path.abspath(path) == os.path.abspath(CORE.config_path)):
print(json.dumps({
'type': 'read_file',
'path': path,
diff --git a/esphome/config_validation.py b/esphome/config_validation.py
index 56fb260679..ad0d90fcd3 100644
--- a/esphome/config_validation.py
+++ b/esphome/config_validation.py
@@ -8,6 +8,7 @@ import re
from contextlib import contextmanager
import uuid as uuid_
from datetime import datetime
+from string import ascii_letters, digits
import voluptuous as vol
@@ -15,7 +16,7 @@ from esphome import core
from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
CONF_INTERNAL, CONF_NAME, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, \
CONF_RETAIN, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, CONF_TOPIC, \
- CONF_HOUR, CONF_MINUTE, CONF_SECOND, CONF_VALUE, CONF_UPDATE_INTERVAL, CONF_TYPE_ID
+ CONF_HOUR, CONF_MINUTE, CONF_SECOND, CONF_VALUE, CONF_UPDATE_INTERVAL, CONF_TYPE_ID, CONF_TYPE
from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes
from esphome.helpers import list_starts_with
@@ -226,6 +227,11 @@ def int_(value):
check_not_templatable(value)
if isinstance(value, integer_types):
return value
+ if isinstance(value, float):
+ if int(value) == value:
+ return int(value)
+ raise Invalid("This option only accepts integers with no fractional part. Please remove "
+ "the fractional part from {}".format(value))
value = string_strict(value).lower()
base = 10
if value.startswith('0x'):
@@ -279,8 +285,9 @@ def validate_id_name(value):
raise Invalid("First character in ID cannot be a digit.")
if '-' in value:
raise Invalid("Dashes are not supported in IDs, please use underscores instead.")
+ valid_chars = ascii_letters + digits + '_'
for char in value:
- if char != '_' and not char.isalnum():
+ if char not in valid_chars:
raise Invalid(u"IDs must only consist of upper/lowercase characters, the underscore"
u"character and numbers. The character '{}' cannot be used"
u"".format(char))
@@ -333,7 +340,7 @@ def templatable(other_validators):
def validator(value):
if isinstance(value, Lambda):
- return lambda_(value)
+ return returning_lambda(value)
if isinstance(other_validators, dict):
return schema(value)
return schema(value)
@@ -570,10 +577,15 @@ METRIC_SUFFIXES = {
}
-def float_with_unit(quantity, regex_suffix):
+def float_with_unit(quantity, regex_suffix, optional_unit=False):
pattern = re.compile(r"^([-+]?[0-9]*\.?[0-9]*)\s*(\w*?)" + regex_suffix + r"$", re.UNICODE)
def validator(value):
+ if optional_unit:
+ try:
+ return float_(value)
+ except Invalid:
+ pass
match = pattern.match(string(value))
if match is None:
@@ -595,6 +607,7 @@ current = float_with_unit("current", u"(a|A|amp|Amp|amps|Amps|ampere|Ampere)?")
voltage = float_with_unit("voltage", u"(v|V|volt|Volts)?")
distance = float_with_unit("distance", u"(m)")
framerate = float_with_unit("framerate", u"(FPS|fps|Fps|FpS|Hz)")
+angle = float_with_unit("angle", u"(°|deg)", optional_unit=True)
_temperature_c = float_with_unit("temperature", u"(°C|° C|°|C)?")
_temperature_k = float_with_unit("temperature", u"(° K|° K|K)?")
_temperature_f = float_with_unit("temperature", u"(°F|° F|F)?")
@@ -605,7 +618,7 @@ if IS_PY2:
path = u' @ data[%s]' % u']['.join(map(repr, self.path)) \
if self.path else ''
# pylint: disable=no-member
- output = Exception.__unicode__(self)
+ output = self.message
if self.error_type:
output += u' for ' + self.error_type
return output + path
@@ -974,6 +987,20 @@ def lambda_(value):
return value
+def returning_lambda(value):
+ """Coerce this configuration option to a lambda.
+
+ Additionally, make sure the lambda returns something.
+ """
+ value = lambda_(value)
+ if u'return' not in value.value:
+ raise Invalid("Lambda doesn't contain a 'return' statement, but the lambda "
+ "is expected to return a value. \n"
+ "Please make sure the lambda contains at least one "
+ "return statement.")
+ return value
+
+
def dimensions(value):
if isinstance(value, list):
if len(value) != 2:
@@ -1051,6 +1078,24 @@ def extract_keys(schema):
return keys
+def typed_schema(schemas, **kwargs):
+ """Create a schema that has a key to distinguish between schemas"""
+ key = kwargs.pop('key', CONF_TYPE)
+ key_validator = one_of(*schemas, **kwargs)
+
+ def validator(value):
+ if not isinstance(value, dict):
+ raise Invalid("Value must be dict")
+ if CONF_TYPE not in value:
+ raise Invalid("type not specified!")
+ value = value.copy()
+ key_v = key_validator(value.pop(key))
+ value = schemas[key_v](value)
+ value[key] = key_v
+
+ return validator
+
+
class GenerateID(Optional):
"""Mark this key as being an auto-generated ID key."""
def __init__(self, key=CONF_ID):
diff --git a/esphome/const.py b/esphome/const.py
index fa9bae4304..d58ed406c7 100644
--- a/esphome/const.py
+++ b/esphome/const.py
@@ -11,8 +11,6 @@ ESP_PLATFORM_ESP32 = 'ESP32'
ESP_PLATFORM_ESP8266 = 'ESP8266'
ESP_PLATFORMS = [ESP_PLATFORM_ESP32, ESP_PLATFORM_ESP8266]
-APB_CLOCK_FREQ = 80000000
-
ALLOWED_NAME_CHARS = u'abcdefghijklmnopqrstuvwxyz0123456789_'
ARDUINO_VERSION_ESP32_DEV = 'https://github.com/platformio/platform-espressif32.git#feature/stage'
ARDUINO_VERSION_ESP32_1_0_0 = 'espressif32@1.5.0'
@@ -20,6 +18,7 @@ ARDUINO_VERSION_ESP32_1_0_1 = 'espressif32@1.6.0'
ARDUINO_VERSION_ESP8266_DEV = 'https://github.com/platformio/platform-espressif8266.git#feature' \
'/stage'
ARDUINO_VERSION_ESP8266_2_5_0 = 'espressif8266@2.0.0'
+ARDUINO_VERSION_ESP8266_2_5_1 = 'espressif8266@2.1.0'
ARDUINO_VERSION_ESP8266_2_3_0 = 'espressif8266@1.5.0'
SOURCE_FILE_EXTENSIONS = {'.cpp', '.hpp', '.h', '.c', '.tcc', '.ino'}
HEADER_FILE_EXTENSIONS = {'.h', '.hpp', '.tcc'}
@@ -349,7 +348,9 @@ CONF_SAMSUNG = 'samsung'
CONF_SCAN = 'scan'
CONF_SCAN_INTERVAL = 'scan_interval'
CONF_SCL = 'scl'
+CONF_SCL_PIN = 'scl_pin'
CONF_SDA = 'sda'
+CONF_SDO_PIN = 'sdo_pin'
CONF_SECOND = 'second'
CONF_SECONDS = 'seconds'
CONF_SEGMENTS = 'segments'
@@ -465,11 +466,15 @@ ICON_PERCENT = 'mdi:percent'
ICON_PERIODIC_TABLE_CO2 = 'mdi:periodic-table-co2'
ICON_POWER = 'mdi:power'
ICON_PULSE = 'mdi:pulse'
+ICON_RADIATOR = 'mdi:radiator'
ICON_RESTART = 'mdi:restart'
ICON_ROTATE_RIGHT = 'mdi:rotate-right'
ICON_SCALE = 'mdi:scale'
ICON_SCREEN_ROTATION = 'mdi:screen-rotation'
ICON_SIGNAL = 'mdi:signal'
+ICON_WEATHER_SUNSET = 'mdi:weather-sunset'
+ICON_WEATHER_SUNSET_DOWN = 'mdi:weather-sunset-down'
+ICON_WEATHER_SUNSET_UP = 'mdi:weather-sunset-up'
ICON_THERMOMETER = 'mdi:thermometer'
ICON_TIMER = 'mdi:timer'
ICON_WATER_PERCENT = 'mdi:water-percent'
@@ -491,6 +496,7 @@ UNIT_MICROSIEMENS_PER_CENTIMETER = u'µS/cm'
UNIT_MICROTESLA = u'µT'
UNIT_OHM = u'Ω'
UNIT_PARTS_PER_MILLION = 'ppm'
+UNIT_PARTS_PER_BILLION = 'ppb'
UNIT_PERCENT = '%'
UNIT_PULSES_PER_MINUTE = 'pulses/min'
UNIT_SECOND = 's'
diff --git a/esphome/core.py b/esphome/core.py
index 464782368e..f2bc4fdf2d 100644
--- a/esphome/core.py
+++ b/esphome/core.py
@@ -467,6 +467,7 @@ class EsphomeCore(object):
self.dashboard = False
# True if command is run from vscode api
self.vscode = False
+ self.ace = False
# The name of the node
self.name = None # type: str
# The relative path to the configuration YAML
diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp
index 99d5f7fe29..98eca4ce87 100644
--- a/esphome/core/application.cpp
+++ b/esphome/core/application.cpp
@@ -60,7 +60,7 @@ void Application::setup() {
this->dump_config();
}
void Application::dump_config() {
- ESP_LOGI(TAG, "esphome-core version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
+ ESP_LOGI(TAG, "esphome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
for (auto component : this->components_) {
component->dump_config();
diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp
index c42585cab1..769a7825da 100644
--- a/esphome/core/helpers.cpp
+++ b/esphome/core/helpers.cpp
@@ -294,8 +294,6 @@ void HighFrequencyLoopRequester::stop() {
bool HighFrequencyLoopRequester::is_high_frequency() { return high_freq_num_requests > 0; }
float clamp(float val, float min, float max) {
- if (min > max)
- std::swap(min, max);
if (val < min)
return min;
if (val > max)
@@ -309,4 +307,11 @@ bool str_endswith(const std::string &full, const std::string &ending) {
return full.rfind(ending) == (full.size() - ending.size());
}
+uint16_t encode_uint16(uint8_t msb, uint8_t lsb) { return (uint16_t(msb) << 8) | uint16_t(lsb); }
+std::array decode_uint16(uint16_t value) {
+ uint8_t msb = (value >> 8) & 0xFF;
+ uint8_t lsb = (value >> 0) & 0xFF;
+ return {msb, lsb};
+}
+
} // namespace esphome
diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h
index cc046a6962..d21cb85b7d 100644
--- a/esphome/core/helpers.h
+++ b/esphome/core/helpers.h
@@ -127,6 +127,11 @@ uint8_t reverse_bits_8(uint8_t x);
uint16_t reverse_bits_16(uint16_t x);
uint32_t reverse_bits_32(uint32_t x);
+/// Encode a 16-bit unsigned integer given a most and least-significant byte.
+uint16_t encode_uint16(uint8_t msb, uint8_t lsb);
+/// Decode a 16-bit unsigned integer into an array of two values: most significant byte, least significant byte.
+std::array decode_uint16(uint16_t value);
+
/** Cross-platform method to disable interrupts.
*
* Useful when you need to do some timing-dependent communication.
@@ -254,6 +259,18 @@ template class Deduplicator {
T last_value_{};
};
+template class Parented {
+ public:
+ Parented() {}
+ Parented(T *parent) : parent_(parent) {}
+
+ T *get_parent() const { return parent_; }
+ void set_parent(T *parent) { parent_ = parent; }
+
+ protected:
+ T *parent_{nullptr};
+};
+
uint32_t fnv1_hash(const std::string &str);
} // namespace esphome
diff --git a/esphome/core_config.py b/esphome/core_config.py
index 8d2f83c4f1..5230f723af 100644
--- a/esphome/core_config.py
+++ b/esphome/core_config.py
@@ -11,7 +11,7 @@ from esphome.const import ARDUINO_VERSION_ESP32_DEV, ARDUINO_VERSION_ESP8266_DEV
CONF_NAME, CONF_ON_BOOT, CONF_ON_LOOP, CONF_ON_SHUTDOWN, CONF_PLATFORM, \
CONF_PLATFORMIO_OPTIONS, CONF_PRIORITY, CONF_TRIGGER_ID, \
CONF_ESP8266_RESTORE_FROM_FLASH, __version__, ARDUINO_VERSION_ESP8266_2_3_0, \
- ARDUINO_VERSION_ESP8266_2_5_0
+ ARDUINO_VERSION_ESP8266_2_5_0, ARDUINO_VERSION_ESP8266_2_5_1
from esphome.core import CORE, coroutine_with_priority
from esphome.pins import ESP8266_FLASH_SIZES, ESP8266_LD_SCRIPTS
@@ -42,6 +42,7 @@ def validate_board(value):
validate_platform = cv.one_of('ESP32', 'ESP8266', upper=True)
PLATFORMIO_ESP8266_LUT = {
+ '2.5.1': 'espressif8266@2.1.0',
'2.5.0': 'espressif8266@2.0.1',
'2.4.2': 'espressif8266@1.8.0',
'2.4.1': 'espressif8266@1.7.3',
@@ -89,8 +90,7 @@ def default_build_path():
CONFIG_SCHEMA = cv.Schema({
cv.Required(CONF_NAME): cv.valid_name,
- cv.Required(CONF_PLATFORM): cv.one_of('ESP8266', 'ESP32', 'ESPRESSIF32',
- upper=True),
+ cv.Required(CONF_PLATFORM): cv.one_of('ESP8266', 'ESP32', upper=True),
cv.Required(CONF_BOARD): validate_board,
cv.Optional(CONF_ARDUINO_VERSION, default='recommended'): validate_arduino_version,
cv.Optional(CONF_BUILD_PATH, default=default_build_path): cv.string,
@@ -114,6 +114,10 @@ CONFIG_SCHEMA = cv.Schema({
}),
cv.Optional(CONF_INCLUDES, default=[]): cv.ensure_list(cv.file_),
cv.Optional(CONF_LIBRARIES, default=[]): cv.ensure_list(cv.string_strict),
+
+ cv.Optional('esphome_core_version'): cv.invalid("The esphome_core_version option has been "
+ "removed in 1.13 - the esphome core source "
+ "files are now bundled with ESPHome.")
})
PRELOAD_CONFIG_SCHEMA = cv.Schema({
@@ -186,15 +190,14 @@ def to_code(config):
if CORE.arduino_version in ('espressif8266@1.8.0', 'espressif8266@1.7.3',
'espressif8266@1.6.0'):
ld_script = ld_scripts[0]
- elif CORE.arduino_version in (ARDUINO_VERSION_ESP8266_DEV, ARDUINO_VERSION_ESP8266_2_5_0):
+ elif CORE.arduino_version in (ARDUINO_VERSION_ESP8266_DEV, ARDUINO_VERSION_ESP8266_2_5_0,
+ ARDUINO_VERSION_ESP8266_2_5_1):
ld_script = ld_scripts[1]
if ld_script is not None:
cg.add_build_flag('-Wl,-T{}'.format(ld_script))
- if CORE.is_esp8266 and CORE.arduino_version in (ARDUINO_VERSION_ESP8266_DEV,
- ARDUINO_VERSION_ESP8266_2_5_0):
- cg.add_build_flag('-fno-exceptions')
+ cg.add_build_flag('-fno-exceptions')
# Libraries
if CORE.is_esp32:
diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py
index 651d748934..c1e4a87179 100644
--- a/esphome/cpp_generator.py
+++ b/esphome/cpp_generator.py
@@ -328,6 +328,17 @@ class ExpressionStatement(Statement):
return u"{};".format(self.expression)
+class LineComment(Statement):
+ def __init__(self, value): # type: (unicode) -> None
+ super(LineComment, self).__init__()
+ self._value = value
+
+ def __str__(self):
+ parts = self._value.split(u'\n')
+ parts = [u'// {}'.format(x) for x in parts]
+ return u'\n'.join(parts)
+
+
class ProgmemAssignmentExpression(AssignmentExpression):
def __init__(self, type, name, rhs, obj):
super(ProgmemAssignmentExpression, self).__init__(
@@ -424,10 +435,14 @@ def new_Pvariable(id, # type: ID
return Pvariable(id, rhs)
-def add(expression, # type: Union[SafeExpType, Statement]
+def add(expression, # type: Union[Expression, Statement]
):
# type: (...) -> None
- """Add an expression to the codegen setup() storage."""
+ """Add an expression to the codegen section.
+
+ After this is called, the given given expression will
+ show up in the setup() function after this has been called.
+ """
CORE.add(expression)
diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py
index ec0c8f88f2..8e310ac44b 100644
--- a/esphome/cpp_helpers.py
+++ b/esphome/cpp_helpers.py
@@ -1,7 +1,7 @@
from esphome.const import CONF_INVERTED, CONF_MODE, CONF_NUMBER, CONF_SETUP_PRIORITY, \
CONF_UPDATE_INTERVAL, CONF_TYPE_ID
-from esphome.core import coroutine
-from esphome.cpp_generator import RawExpression, add
+from esphome.core import coroutine, ID
+from esphome.cpp_generator import RawExpression, add, get_variable
from esphome.cpp_types import App, GPIOPin
@@ -42,6 +42,15 @@ def register_component(var, config):
yield var
+@coroutine
+def register_parented(var, value):
+ if isinstance(value, ID):
+ paren = yield get_variable(value)
+ else:
+ paren = value
+ add(var.set_parent(paren))
+
+
def extract_registry_entry_config(registry, full_config):
# type: (Registry, ConfigType) -> RegistryEntry
key, config = next((k, v) for k, v in full_config.items() if k in registry)
diff --git a/esphome/cpp_types.py b/esphome/cpp_types.py
index a59137834e..d3e5b2d561 100644
--- a/esphome/cpp_types.py
+++ b/esphome/cpp_types.py
@@ -4,6 +4,7 @@ global_ns = MockObj('', '')
void = global_ns.namespace('void')
nullptr = global_ns.namespace('nullptr')
float_ = global_ns.namespace('float')
+double = global_ns.namespace('double')
bool_ = global_ns.namespace('bool')
std_ns = global_ns.namespace('std')
std_string = std_ns.class_('string')
diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py
index 66ec1e1e54..0d6a26c6ee 100644
--- a/esphome/dashboard/dashboard.py
+++ b/esphome/dashboard/dashboard.py
@@ -256,12 +256,12 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler):
self.write_message({'event': 'exit', 'code': returncode})
def on_close(self):
- # Shutdown proc on WS close
- self._is_closed = True
# Check if proc exists (if 'start' has been run)
if self.is_process_active:
_LOGGER.debug("Terminating process")
self._proc.proc.terminate()
+ # Shutdown proc on WS close
+ self._is_closed = True
def build_command(self, json_message):
raise NotImplementedError
@@ -310,6 +310,11 @@ class EsphomeVscodeHandler(EsphomeCommandWebSocket):
return ["esphome", "--dashboard", "-q", 'dummy', "vscode"]
+class EsphomeAceEditorHandler(EsphomeCommandWebSocket):
+ def build_command(self, json_message):
+ return ["esphome", "--dashboard", "-q", settings.config_dir, "vscode", "--ace"]
+
+
class SerialPortRequestHandler(BaseHandler):
@authenticated
def get(self):
@@ -678,6 +683,7 @@ def make_app(debug=False):
(rel + "clean-mqtt", EsphomeCleanMqttHandler),
(rel + "clean", EsphomeCleanHandler),
(rel + "vscode", EsphomeVscodeHandler),
+ (rel + "ace", EsphomeAceEditorHandler),
(rel + "edit", EditRequestHandler),
(rel + "download.bin", DownloadBinaryRequestHandler),
(rel + "serial-ports", SerialPortRequestHandler),
diff --git a/esphome/dashboard/static/ace.js b/esphome/dashboard/static/ace.js
index 58119de349..f5fca22af2 100644
--- a/esphome/dashboard/static/ace.js
+++ b/esphome/dashboard/static/ace.js
@@ -14,4 +14,3 @@
}
});
})();
-
\ No newline at end of file
diff --git a/esphome/dashboard/static/esphome.js b/esphome/dashboard/static/esphome.js
index 5ec29ba0dd..568537a3c9 100644
--- a/esphome/dashboard/static/esphome.js
+++ b/esphome/dashboard/static/esphome.js
@@ -550,10 +550,75 @@ const editModalElem = document.getElementById("modal-editor");
const editorElem = editModalElem.querySelector("#editor");
const editor = ace.edit(editorElem);
let activeEditorConfig = null;
+let aceWs = null;
+let aceValidationScheduled = false;
+let aceValidationRunning = false;
+const startAceWebsocket = () => {
+ aceWs = new WebSocket(`${wsUrl}ace`);
+ aceWs.addEventListener('message', (event) => {
+ const raw = JSON.parse(event.data);
+ if (raw.event === "line") {
+ const msg = JSON.parse(raw.data);
+ if (msg.type === "result") {
+ console.log(msg);
+ const arr = [];
+
+ for (const v of msg.validation_errors) {
+ let o = {
+ text: v.message,
+ type: 'error',
+ row: 0,
+ column: 0
+ };
+ if (v.range != null) {
+ o.row = v.range.start_line;
+ o.column = v.range.start_col;
+ }
+ arr.push(o);
+ }
+ for (const v of msg.yaml_errors) {
+ arr.push({
+ text: v.message,
+ type: 'error',
+ row: 0,
+ column: 0
+ });
+ }
+
+ editor.session.setAnnotations(arr);
+
+ aceValidationRunning = false;
+ } else if (msg.type === "read_file") {
+ sendAceStdin({
+ type: 'file_response',
+ content: editor.getValue()
+ });
+ }
+ }
+ });
+ aceWs.addEventListener('open', () => {
+ const msg = JSON.stringify({type: 'spawn'});
+ aceWs.send(msg);
+ });
+ aceWs.addEventListener('close', () => {
+ aceWs = null;
+ setTimeout(startAceWebsocket, 5000)
+ });
+};
+const sendAceStdin = (data) => {
+ let send = JSON.stringify({
+ type: 'stdin',
+ data: JSON.stringify(data)+'\n',
+ });
+ aceWs.send(send);
+};
+startAceWebsocket();
+
editor.setTheme("ace/theme/dreamweaver");
editor.session.setMode("ace/mode/yaml");
editor.session.setOption('useSoftTabs', true);
editor.session.setOption('tabSize', 2);
+editor.session.setOption('useWorker', false);
const saveButton = editModalElem.querySelector(".save-button");
const saveValidateButton = editModalElem.querySelector(".save-validate-button");
@@ -569,6 +634,19 @@ const saveEditor = () => {
});
};
+const debounce = (func, wait) => {
+ let timeout;
+ return function() {
+ let context = this, args = arguments;
+ let later = function() {
+ timeout = null;
+ func.apply(context, args);
+ };
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ };
+};
+
editor.commands.addCommand({
name: 'saveCommand',
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
@@ -576,6 +654,24 @@ editor.commands.addCommand({
readOnly: false
});
+editor.session.on('change', debounce(() => {
+ aceValidationScheduled = true;
+}, 250));
+
+setInterval(() => {
+ if (!aceValidationScheduled || aceValidationRunning)
+ return;
+ if (aceWs == null)
+ return;
+
+ sendAceStdin({
+ type: 'validate',
+ file: activeEditorConfig
+ });
+ aceValidationRunning = true;
+ aceValidationScheduled = false;
+}, 100);
+
saveButton.addEventListener('click', saveEditor);
saveValidateButton.addEventListener('click', saveEditor);
@@ -612,3 +708,11 @@ const startWizard = () => {
};
setupWizardStart.addEventListener('click', startWizard);
+
+jQuery.validator.addMethod("nospaces", (value, element) => {
+ return value.indexOf(' ') < 0;
+}, "Name must not contain spaces.");
+
+jQuery.validator.addMethod("lowercase", (value, element) => {
+ return value === value.toLowerCase();
+}, "Name must be lowercase.");
diff --git a/esphome/dashboard/static/ext-searchbox.js b/esphome/dashboard/static/ext-searchbox.js
index 13241257d3..c6379623a7 100644
--- a/esphome/dashboard/static/ext-searchbox.js
+++ b/esphome/dashboard/static/ext-searchbox.js
@@ -5,4 +5,3 @@ ace.define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/
}
});
})();
-
\ No newline at end of file
diff --git a/esphome/dashboard/static/jquery.validate.min.js b/esphome/dashboard/static/jquery.validate.min.js
index 32ba047d75..36d155fe1a 100644
--- a/esphome/dashboard/static/jquery.validate.min.js
+++ b/esphome/dashboard/static/jquery.validate.min.js
@@ -1,4 +1,4 @@
/*! jQuery Validation Plugin - v1.15.0 - 2/24/2016
* http://jqueryvalidation.org/
* Copyright (c) 2016 Jörn Zaefferer; Licensed MIT */
-!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.on("click.validate",":submit",function(b){c.settings.submitHandler&&(c.submitButton=b.target),a(this).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(this).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.on("submit.validate",function(b){function d(){var d,e;return c.settings.submitHandler?(c.submitButton&&(d=a(" ").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),e=c.settings.submitHandler.call(c,c.currentForm,b),c.submitButton&&d.remove(),void 0!==e?e:!1):!0}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is("form")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,b||(d=d.concat(c.errorList))}),c.errorList=d),b},rules:function(b,c){if(this.length){var d,e,f,g,h,i,j=this[0];if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(b,c){i[c]=f[c],delete f[c],"required"===c&&a(j).removeAttr("aria-required")}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g),a(j).attr("aria-required","true")),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}}),a.extend(a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){var c=a(b).val();return null!==c&&!!a.trim(""+c)},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:void 0===c?b:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",pendingClass:"pending",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&""===this.elementValue(b)||-1!==a.inArray(c.keyCode,d)||(b.name in this.submitted||b.name in this.invalid)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date ( ISO ).",number:"Please enter a valid number.",digits:"Please enter only digits.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}."),step:a.validator.format("Please enter a multiple of {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c=a.data(this.form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!a(this).is(e.ignore)&&e[d].call(c,this,b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).on("focusin.validate focusout.validate keyup.validate",":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], [type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox'], [contenteditable]",b).on("click.validate","select, option, [type='radio'], [type='checkbox']",b),this.settings.invalidHandler&&a(this.currentForm).on("invalid-form.validate",this.settings.invalidHandler),a(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required","true")},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c,d,e=this.clean(b),f=this.validationTargetFor(e),g=this,h=!0;return void 0===f?delete this.invalid[e.name]:(this.prepareElement(f),this.currentElements=a(f),d=this.groups[f.name],d&&a.each(this.groups,function(a,b){b===d&&a!==f.name&&(e=g.validationTargetFor(g.clean(g.findByName(a))),e&&e.name in g.invalid&&(g.currentElements.push(e),h=h&&g.check(e)))}),c=this.check(f)!==!1,h=h&&c,c?this.invalid[f.name]=!1:this.invalid[f.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),a(b).attr("aria-invalid",!c)),h},showErrors:function(b){if(b){var c=this;a.extend(this.errorMap,b),this.errorList=a.map(this.errorMap,function(a,b){return{message:a,element:c.findByName(b)[0]}}),this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.invalid={},this.submitted={},this.prepareForm(),this.hideErrors();var b=this.elements().removeData("previousValue").removeAttr("aria-invalid");this.resetElements(b)},resetElements:function(a){var b;if(this.settings.unhighlight)for(b=0;a[b];b++)this.settings.unhighlight.call(this,a[b],this.settings.errorClass,""),this.findByName(a[b].name).removeClass(this.settings.validClass);else a.removeClass(this.settings.errorClass).removeClass(this.settings.validClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)a[b]&&c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea, [contenteditable]").not(":submit, :reset, :image, :disabled").not(this.settings.ignore).filter(function(){var d=this.name||a(this).attr("name");return!d&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.hasAttribute("contenteditable")&&(this.form=a(this).closest("form")[0]),d in c||!b.objectLength(a(this).rules())?!1:(c[d]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},resetInternals:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([])},reset:function(){this.resetInternals(),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d,e=a(b),f=b.type;return"radio"===f||"checkbox"===f?this.findByName(b.name).filter(":checked").val():"number"===f&&"undefined"!=typeof b.validity?b.validity.badInput?"NaN":e.val():(c=b.hasAttribute("contenteditable")?e.text():e.val(),"file"===f?"C:\\fakepath\\"===c.substr(0,12)?c.substr(12):(d=c.lastIndexOf("/"),d>=0?c.substr(d+1):(d=c.lastIndexOf("\\"),d>=0?c.substr(d+1):c)):"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f=a(b).rules(),g=a.map(f,function(a,b){return b}).length,h=!1,i=this.elementValue(b);if("function"==typeof f.normalizer){if(i=f.normalizer.call(b,i),"string"!=typeof i)throw new TypeError("The normalizer should return a string value.");delete f.normalizer}for(d in f){e={method:d,parameters:f[d]};try{if(c=a.validator.methods[d].call(this,i,b,e.parameters),"dependency-mismatch"===c&&1===g){h=!0;continue}if(h=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(j){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",j),j instanceof TypeError&&(j.message+=". Exception occurred when checking element "+b.id+", check the '"+e.method+"' method."),j}}if(!h)return this.objectLength(f)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+b.name+""),e=/\$?\{(\d+)\}/g;return"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),d},formatAndAdd:function(a,b){var c=this.defaultMessage(a,b);this.errorList.push({message:c,element:a,method:b.method}),this.errorMap[a.name]=c,this.submitted[a.name]=c},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g,h=this.errorsFor(b),i=this.idOrName(b),j=a(b).attr("aria-describedby");h.length?(h.removeClass(this.settings.validClass).addClass(this.settings.errorClass),h.html(c)):(h=a("<"+this.settings.errorElement+">").attr("id",i+"-error").addClass(this.settings.errorClass).html(c||""),d=h,this.settings.wrapper&&(d=h.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement(d,a(b)):d.insertAfter(b),h.is("label")?h.attr("for",i):0===h.parents("label[for='"+this.escapeCssMeta(i)+"']").length&&(f=h.attr("id"),j?j.match(new RegExp("\\b"+this.escapeCssMeta(f)+"\\b"))||(j+=" "+f):j=f,a(b).attr("aria-describedby",j),e=this.groups[b.name],e&&(g=this,a.each(g.groups,function(b,c){c===e&&a("[name='"+g.escapeCssMeta(b)+"']",g.currentForm).attr("aria-describedby",h.attr("id"))})))),!c&&this.settings.success&&(h.text(""),"string"==typeof this.settings.success?h.addClass(this.settings.success):this.settings.success(h,b)),this.toShow=this.toShow.add(h)},errorsFor:function(b){var c=this.escapeCssMeta(this.idOrName(b)),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+this.escapeCssMeta(d).replace(/\s+/g,", #")),this.errors().filter(e)},escapeCssMeta:function(a){return a.replace(/([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g,"\\$1")},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+this.escapeCssMeta(b)+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):!0},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(b){this.pending[b.name]||(this.pendingRequest++,a(b).addClass(this.settings.pendingClass),this.pending[b.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],a(b).removeClass(this.settings.pendingClass),c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b,c){return a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,{method:c})})},destroy:function(){this.resetForm(),a(this.currentForm).off(".validate").removeData("validator").find(".validate-equalTo-blur").off(".validate-equalTo").removeClass("validate-equalTo-blur")}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},normalizeAttributeRule:function(a,b,c,d){/min|max|step/.test(c)&&(null===b||/number|range|text/.test(b))&&(d=Number(d),isNaN(d)&&(d=void 0)),d||0===d?a[c]=d:b===c&&"range"!==b&&(a[c]=!0)},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),this.normalizeAttributeRule(e,g,c,d);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),this.normalizeAttributeRule(e,g,c,d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0!==e.param?e.param:!0:(a.data(c.form,"validator").resetElements(a(c)),delete b[d])}}),a.each(b,function(d,e){b[d]=a.isFunction(e)&&"normalizer"!==d?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:b.length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||d>=e},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||c>=a},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},step:function(b,c,d){var e=a(c).attr("type"),f="Step attribute on input type "+e+" is not supported.",g=["text","number","range"],h=new RegExp("\\b"+e+"\\b"),i=e&&!h.test(g.join());if(i)throw new Error(f);return this.optional(c)||b%d===0},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.not(".validate-equalTo-blur").length&&e.addClass("validate-equalTo-blur").on("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d,e){if(this.optional(c))return"dependency-mismatch";e="string"==typeof e&&e||"remote";var f,g,h,i=this.previousValue(c,e);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),i.originalMessage=i.originalMessage||this.settings.messages[c.name][e],this.settings.messages[c.name][e]=i.message,d="string"==typeof d&&{url:d}||d,h=a.param(a.extend({data:b},d.data)),i.old===h?i.valid:(i.old=h,f=this,this.startRequest(c),g={},g[c.name]=b,a.ajax(a.extend(!0,{mode:"abort",port:"validate"+c.name,dataType:"json",data:g,context:f.currentForm,success:function(a){var d,g,h,j=a===!0||"true"===a;f.settings.messages[c.name][e]=i.originalMessage,j?(h=f.formSubmitted,f.resetInternals(),f.toHide=f.errorsFor(c),f.formSubmitted=h,f.successList.push(c),f.invalid[c.name]=!1,f.showErrors()):(d={},g=a||f.defaultMessage(c,{method:e,parameters:b}),d[c.name]=i.message=g,f.invalid[c.name]=!0,f.showErrors(d)),i.valid=j,f.stopRequest(c,j)}},d)),"pending")}}});var b,c={};a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)})});
\ No newline at end of file
+!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.on("click.validate",":submit",function(b){c.settings.submitHandler&&(c.submitButton=b.target),a(this).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(this).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.on("submit.validate",function(b){function d(){var d,e;return c.settings.submitHandler?(c.submitButton&&(d=a(" ").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),e=c.settings.submitHandler.call(c,c.currentForm,b),c.submitButton&&d.remove(),void 0!==e?e:!1):!0}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is("form")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,b||(d=d.concat(c.errorList))}),c.errorList=d),b},rules:function(b,c){if(this.length){var d,e,f,g,h,i,j=this[0];if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(b,c){i[c]=f[c],delete f[c],"required"===c&&a(j).removeAttr("aria-required")}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g),a(j).attr("aria-required","true")),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}}),a.extend(a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){var c=a(b).val();return null!==c&&!!a.trim(""+c)},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:void 0===c?b:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",pendingClass:"pending",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&""===this.elementValue(b)||-1!==a.inArray(c.keyCode,d)||(b.name in this.submitted||b.name in this.invalid)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date ( ISO ).",number:"Please enter a valid number.",digits:"Please enter only digits.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}."),step:a.validator.format("Please enter a multiple of {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c=a.data(this.form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!a(this).is(e.ignore)&&e[d].call(c,this,b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).on("focusin.validate focusout.validate keyup.validate",":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], [type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox'], [contenteditable]",b).on("click.validate","select, option, [type='radio'], [type='checkbox']",b),this.settings.invalidHandler&&a(this.currentForm).on("invalid-form.validate",this.settings.invalidHandler),a(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required","true")},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c,d,e=this.clean(b),f=this.validationTargetFor(e),g=this,h=!0;return void 0===f?delete this.invalid[e.name]:(this.prepareElement(f),this.currentElements=a(f),d=this.groups[f.name],d&&a.each(this.groups,function(a,b){b===d&&a!==f.name&&(e=g.validationTargetFor(g.clean(g.findByName(a))),e&&e.name in g.invalid&&(g.currentElements.push(e),h=h&&g.check(e)))}),c=this.check(f)!==!1,h=h&&c,c?this.invalid[f.name]=!1:this.invalid[f.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),a(b).attr("aria-invalid",!c)),h},showErrors:function(b){if(b){var c=this;a.extend(this.errorMap,b),this.errorList=a.map(this.errorMap,function(a,b){return{message:a,element:c.findByName(b)[0]}}),this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.invalid={},this.submitted={},this.prepareForm(),this.hideErrors();var b=this.elements().removeData("previousValue").removeAttr("aria-invalid");this.resetElements(b)},resetElements:function(a){var b;if(this.settings.unhighlight)for(b=0;a[b];b++)this.settings.unhighlight.call(this,a[b],this.settings.errorClass,""),this.findByName(a[b].name).removeClass(this.settings.validClass);else a.removeClass(this.settings.errorClass).removeClass(this.settings.validClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)a[b]&&c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea, [contenteditable]").not(":submit, :reset, :image, :disabled").not(this.settings.ignore).filter(function(){var d=this.name||a(this).attr("name");return!d&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.hasAttribute("contenteditable")&&(this.form=a(this).closest("form")[0]),d in c||!b.objectLength(a(this).rules())?!1:(c[d]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},resetInternals:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([])},reset:function(){this.resetInternals(),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d,e=a(b),f=b.type;return"radio"===f||"checkbox"===f?this.findByName(b.name).filter(":checked").val():"number"===f&&"undefined"!=typeof b.validity?b.validity.badInput?"NaN":e.val():(c=b.hasAttribute("contenteditable")?e.text():e.val(),"file"===f?"C:\\fakepath\\"===c.substr(0,12)?c.substr(12):(d=c.lastIndexOf("/"),d>=0?c.substr(d+1):(d=c.lastIndexOf("\\"),d>=0?c.substr(d+1):c)):"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f=a(b).rules(),g=a.map(f,function(a,b){return b}).length,h=!1,i=this.elementValue(b);if("function"==typeof f.normalizer){if(i=f.normalizer.call(b,i),"string"!=typeof i)throw new TypeError("The normalizer should return a string value.");delete f.normalizer}for(d in f){e={method:d,parameters:f[d]};try{if(c=a.validator.methods[d].call(this,i,b,e.parameters),"dependency-mismatch"===c&&1===g){h=!0;continue}if(h=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(j){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",j),j instanceof TypeError&&(j.message+=". Exception occurred when checking element "+b.id+", check the '"+e.method+"' method."),j}}if(!h)return this.objectLength(f)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+b.name+""),e=/\$?\{(\d+)\}/g;return"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),d},formatAndAdd:function(a,b){var c=this.defaultMessage(a,b);this.errorList.push({message:c,element:a,method:b.method}),this.errorMap[a.name]=c,this.submitted[a.name]=c},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g,h=this.errorsFor(b),i=this.idOrName(b),j=a(b).attr("aria-describedby");h.length?(h.removeClass(this.settings.validClass).addClass(this.settings.errorClass),h.html(c)):(h=a("<"+this.settings.errorElement+">").attr("id",i+"-error").addClass(this.settings.errorClass).html(c||""),d=h,this.settings.wrapper&&(d=h.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement(d,a(b)):d.insertAfter(b),h.is("label")?h.attr("for",i):0===h.parents("label[for='"+this.escapeCssMeta(i)+"']").length&&(f=h.attr("id"),j?j.match(new RegExp("\\b"+this.escapeCssMeta(f)+"\\b"))||(j+=" "+f):j=f,a(b).attr("aria-describedby",j),e=this.groups[b.name],e&&(g=this,a.each(g.groups,function(b,c){c===e&&a("[name='"+g.escapeCssMeta(b)+"']",g.currentForm).attr("aria-describedby",h.attr("id"))})))),!c&&this.settings.success&&(h.text(""),"string"==typeof this.settings.success?h.addClass(this.settings.success):this.settings.success(h,b)),this.toShow=this.toShow.add(h)},errorsFor:function(b){var c=this.escapeCssMeta(this.idOrName(b)),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+this.escapeCssMeta(d).replace(/\s+/g,", #")),this.errors().filter(e)},escapeCssMeta:function(a){return a.replace(/([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g,"\\$1")},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+this.escapeCssMeta(b)+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):!0},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(b){this.pending[b.name]||(this.pendingRequest++,a(b).addClass(this.settings.pendingClass),this.pending[b.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],a(b).removeClass(this.settings.pendingClass),c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b,c){return a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,{method:c})})},destroy:function(){this.resetForm(),a(this.currentForm).off(".validate").removeData("validator").find(".validate-equalTo-blur").off(".validate-equalTo").removeClass("validate-equalTo-blur")}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},normalizeAttributeRule:function(a,b,c,d){/min|max|step/.test(c)&&(null===b||/number|range|text/.test(b))&&(d=Number(d),isNaN(d)&&(d=void 0)),d||0===d?a[c]=d:b===c&&"range"!==b&&(a[c]=!0)},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),this.normalizeAttributeRule(e,g,c,d);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),this.normalizeAttributeRule(e,g,c,d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0!==e.param?e.param:!0:(a.data(c.form,"validator").resetElements(a(c)),delete b[d])}}),a.each(b,function(d,e){b[d]=a.isFunction(e)&&"normalizer"!==d?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:b.length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||d>=e},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||c>=a},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},step:function(b,c,d){var e=a(c).attr("type"),f="Step attribute on input type "+e+" is not supported.",g=["text","number","range"],h=new RegExp("\\b"+e+"\\b"),i=e&&!h.test(g.join());if(i)throw new Error(f);return this.optional(c)||b%d===0},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.not(".validate-equalTo-blur").length&&e.addClass("validate-equalTo-blur").on("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d,e){if(this.optional(c))return"dependency-mismatch";e="string"==typeof e&&e||"remote";var f,g,h,i=this.previousValue(c,e);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),i.originalMessage=i.originalMessage||this.settings.messages[c.name][e],this.settings.messages[c.name][e]=i.message,d="string"==typeof d&&{url:d}||d,h=a.param(a.extend({data:b},d.data)),i.old===h?i.valid:(i.old=h,f=this,this.startRequest(c),g={},g[c.name]=b,a.ajax(a.extend(!0,{mode:"abort",port:"validate"+c.name,dataType:"json",data:g,context:f.currentForm,success:function(a){var d,g,h,j=a===!0||"true"===a;f.settings.messages[c.name][e]=i.originalMessage,j?(h=f.formSubmitted,f.resetInternals(),f.toHide=f.errorsFor(c),f.formSubmitted=h,f.successList.push(c),f.invalid[c.name]=!1,f.showErrors()):(d={},g=a||f.defaultMessage(c,{method:e,parameters:b}),d[c.name]=i.message=g,f.invalid[c.name]=!0,f.showErrors(d)),i.valid=j,f.stopRequest(c,j)}},d)),"pending")}}});var b,c={};a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)})});
diff --git a/esphome/dashboard/static/materialize-stepper.min.css b/esphome/dashboard/static/materialize-stepper.min.css
old mode 100755
new mode 100644
diff --git a/esphome/dashboard/static/materialize-stepper.min.js b/esphome/dashboard/static/materialize-stepper.min.js
old mode 100755
new mode 100644
diff --git a/esphome/dashboard/static/materialize.min.js b/esphome/dashboard/static/materialize.min.js
index 7d80c9375b..db081d2233 100644
--- a/esphome/dashboard/static/materialize.min.js
+++ b/esphome/dashboard/static/materialize.min.js
@@ -3,4 +3,4 @@
* Copyright 2014-2017 Materialize
* MIT License (https://raw.githubusercontent.com/Dogfalo/materialize/master/LICENSE)
*/
-var _get=function t(e,i,n){null===e&&(e=Function.prototype);var s=Object.getOwnPropertyDescriptor(e,i);if(void 0===s){var o=Object.getPrototypeOf(e);return null===o?void 0:t(o,i,n)}if("value"in s)return s.value;var a=s.get;return void 0!==a?a.call(n):void 0},_createClass=function(){function n(t,e){for(var i=0;i/,p=/^\w+$/;function v(t,e){e=e||o;var i=u.test(t)?e.getElementsByClassName(t.slice(1)):p.test(t)?e.getElementsByTagName(t):e.querySelectorAll(t);return i}function f(t){if(!i){var e=(i=o.implementation.createHTMLDocument(null)).createElement("base");e.href=o.location.href,i.head.appendChild(e)}return i.body.innerHTML=t,i.body.childNodes}function m(t){"loading"!==o.readyState?t():o.addEventListener("DOMContentLoaded",t)}function g(t,e){if(!t)return this;if(t.cash&&t!==a)return t;var i,n=t,s=0;if(d(t))n=l.test(t)?o.getElementById(t.slice(1)):c.test(t)?f(t):v(t,e);else if(h(t))return m(t),this;if(!n)return this;if(n.nodeType||n===a)this[0]=n,this.length=1;else for(i=this.length=n.length;ss.right-i||l+e.width>window.innerWidth-i)&&(n.right=!0),(ho-i||h+e.height>window.innerHeight-i)&&(n.bottom=!0),n},M.checkPossibleAlignments=function(t,e,i,n){var s={top:!0,right:!0,bottom:!0,left:!0,spaceOnTop:null,spaceOnRight:null,spaceOnBottom:null,spaceOnLeft:null},o="visible"===getComputedStyle(e).overflow,a=e.getBoundingClientRect(),r=Math.min(a.height,window.innerHeight),l=Math.min(a.width,window.innerWidth),h=t.getBoundingClientRect(),d=e.scrollLeft,u=e.scrollTop,c=i.left-d,p=i.top-u,v=i.top+h.height-u;return s.spaceOnRight=o?window.innerWidth-(h.left+i.width):l-(c+i.width),s.spaceOnRight<0&&(s.left=!1),s.spaceOnLeft=o?h.right-i.width:c-i.width+h.width,s.spaceOnLeft<0&&(s.right=!1),s.spaceOnBottom=o?window.innerHeight-(h.top+i.height+n):r-(p+i.height+n),s.spaceOnBottom<0&&(s.top=!1),s.spaceOnTop=o?h.bottom-(i.height+n):v-(i.height-n),s.spaceOnTop<0&&(s.bottom=!1),s},M.getOverflowParent=function(t){return null==t?null:t===document.body||"visible"!==getComputedStyle(t).overflow?t:M.getOverflowParent(t.parentElement)},M.getIdFromTrigger=function(t){var e=t.getAttribute("data-target");return e||(e=(e=t.getAttribute("href"))?e.slice(1):""),e},M.getDocumentScrollTop=function(){return window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0},M.getDocumentScrollLeft=function(){return window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0};var getTime=Date.now||function(){return(new Date).getTime()};M.throttle=function(i,n,s){var o=void 0,a=void 0,r=void 0,l=null,h=0;s||(s={});var d=function(){h=!1===s.leading?0:getTime(),l=null,r=i.apply(o,a),o=a=null};return function(){var t=getTime();h||!1!==s.leading||(h=t);var e=n-(t-h);return o=this,a=arguments,e<=0?(clearTimeout(l),l=null,h=t,r=i.apply(o,a),o=a=null):l||!1===s.trailing||(l=setTimeout(d,e)),r}};var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(t,e,i){if(i.get||i.set)throw new TypeError("ES3 does not support getters and setters.");t!=Array.prototype&&t!=Object.prototype&&(t[e]=i.value)},$jscomp.getGlobal=function(t){return"undefined"!=typeof window&&window===t?t:"undefined"!=typeof global&&null!=global?global:t},$jscomp.global=$jscomp.getGlobal(this),$jscomp.SYMBOL_PREFIX="jscomp_symbol_",$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){},$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)},$jscomp.symbolCounter_=0,$jscomp.Symbol=function(t){return $jscomp.SYMBOL_PREFIX+(t||"")+$jscomp.symbolCounter_++},$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var t=$jscomp.global.Symbol.iterator;t||(t=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator")),"function"!=typeof Array.prototype[t]&&$jscomp.defineProperty(Array.prototype,t,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}}),$jscomp.initSymbolIterator=function(){}},$jscomp.arrayIterator=function(t){var e=0;return $jscomp.iteratorPrototype(function(){return e=k.currentTime)for(var h=0;ht&&(s.duration=e.duration),s.children.push(e)}),s.seek(0),s.reset(),s.autoplay&&s.restart(),s},s},O.random=function(t,e){return Math.floor(Math.random()*(e-t+1))+t},O}(),function(r,l){"use strict";var e={accordion:!0,onOpenStart:void 0,onOpenEnd:void 0,onCloseStart:void 0,onCloseEnd:void 0,inDuration:300,outDuration:300},t=function(t){function s(t,e){_classCallCheck(this,s);var i=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,t,e));(i.el.M_Collapsible=i).options=r.extend({},s.defaults,e),i.$headers=i.$el.children("li").children(".collapsible-header"),i.$headers.attr("tabindex",0),i._setupEventHandlers();var n=i.$el.children("li.active").children(".collapsible-body");return i.options.accordion?n.first().css("display","block"):n.css("display","block"),i}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Collapsible=void 0}},{key:"_setupEventHandlers",value:function(){var e=this;this._handleCollapsibleClickBound=this._handleCollapsibleClick.bind(this),this._handleCollapsibleKeydownBound=this._handleCollapsibleKeydown.bind(this),this.el.addEventListener("click",this._handleCollapsibleClickBound),this.$headers.each(function(t){t.addEventListener("keydown",e._handleCollapsibleKeydownBound)})}},{key:"_removeEventHandlers",value:function(){var e=this;this.el.removeEventListener("click",this._handleCollapsibleClickBound),this.$headers.each(function(t){t.removeEventListener("keydown",e._handleCollapsibleKeydownBound)})}},{key:"_handleCollapsibleClick",value:function(t){var e=r(t.target).closest(".collapsible-header");if(t.target&&e.length){var i=e.closest(".collapsible");if(i[0]===this.el){var n=e.closest("li"),s=i.children("li"),o=n[0].classList.contains("active"),a=s.index(n);o?this.close(a):this.open(a)}}}},{key:"_handleCollapsibleKeydown",value:function(t){13===t.keyCode&&this._handleCollapsibleClickBound(t)}},{key:"_animateIn",value:function(t){var e=this,i=this.$el.children("li").eq(t);if(i.length){var n=i.children(".collapsible-body");l.remove(n[0]),n.css({display:"block",overflow:"hidden",height:0,paddingTop:"",paddingBottom:""});var s=n.css("padding-top"),o=n.css("padding-bottom"),a=n[0].scrollHeight;n.css({paddingTop:0,paddingBottom:0}),l({targets:n[0],height:a,paddingTop:s,paddingBottom:o,duration:this.options.inDuration,easing:"easeInOutCubic",complete:function(t){n.css({overflow:"",paddingTop:"",paddingBottom:"",height:""}),"function"==typeof e.options.onOpenEnd&&e.options.onOpenEnd.call(e,i[0])}})}}},{key:"_animateOut",value:function(t){var e=this,i=this.$el.children("li").eq(t);if(i.length){var n=i.children(".collapsible-body");l.remove(n[0]),n.css("overflow","hidden"),l({targets:n[0],height:0,paddingTop:0,paddingBottom:0,duration:this.options.outDuration,easing:"easeInOutCubic",complete:function(){n.css({height:"",overflow:"",padding:"",display:""}),"function"==typeof e.options.onCloseEnd&&e.options.onCloseEnd.call(e,i[0])}})}}},{key:"open",value:function(t){var i=this,e=this.$el.children("li").eq(t);if(e.length&&!e[0].classList.contains("active")){if("function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,e[0]),this.options.accordion){var n=this.$el.children("li");this.$el.children("li.active").each(function(t){var e=n.index(r(t));i.close(e)})}e[0].classList.add("active"),this._animateIn(t)}}},{key:"close",value:function(t){var e=this.$el.children("li").eq(t);e.length&&e[0].classList.contains("active")&&("function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,e[0]),e[0].classList.remove("active"),this._animateOut(t))}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Collapsible}},{key:"defaults",get:function(){return e}}]),s}();M.Collapsible=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"collapsible","M_Collapsible")}(cash,M.anime),function(h,i){"use strict";var e={alignment:"left",autoFocus:!0,constrainWidth:!0,container:null,coverTrigger:!0,closeOnClick:!0,hover:!1,inDuration:150,outDuration:250,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,onItemClick:null},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return i.el.M_Dropdown=i,n._dropdowns.push(i),i.id=M.getIdFromTrigger(t),i.dropdownEl=document.getElementById(i.id),i.$dropdownEl=h(i.dropdownEl),i.options=h.extend({},n.defaults,e),i.isOpen=!1,i.isScrollable=!1,i.isTouchMoving=!1,i.focusedIndex=-1,i.filterQuery=[],i.options.container?h(i.options.container).append(i.dropdownEl):i.$el.after(i.dropdownEl),i._makeDropdownFocusable(),i._resetFilterQueryBound=i._resetFilterQuery.bind(i),i._handleDocumentClickBound=i._handleDocumentClick.bind(i),i._handleDocumentTouchmoveBound=i._handleDocumentTouchmove.bind(i),i._handleDropdownClickBound=i._handleDropdownClick.bind(i),i._handleDropdownKeydownBound=i._handleDropdownKeydown.bind(i),i._handleTriggerKeydownBound=i._handleTriggerKeydown.bind(i),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._resetDropdownStyles(),this._removeEventHandlers(),n._dropdowns.splice(n._dropdowns.indexOf(this),1),this.el.M_Dropdown=void 0}},{key:"_setupEventHandlers",value:function(){this.el.addEventListener("keydown",this._handleTriggerKeydownBound),this.dropdownEl.addEventListener("click",this._handleDropdownClickBound),this.options.hover?(this._handleMouseEnterBound=this._handleMouseEnter.bind(this),this.el.addEventListener("mouseenter",this._handleMouseEnterBound),this._handleMouseLeaveBound=this._handleMouseLeave.bind(this),this.el.addEventListener("mouseleave",this._handleMouseLeaveBound),this.dropdownEl.addEventListener("mouseleave",this._handleMouseLeaveBound)):(this._handleClickBound=this._handleClick.bind(this),this.el.addEventListener("click",this._handleClickBound))}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("keydown",this._handleTriggerKeydownBound),this.dropdownEl.removeEventListener("click",this._handleDropdownClickBound),this.options.hover?(this.el.removeEventListener("mouseenter",this._handleMouseEnterBound),this.el.removeEventListener("mouseleave",this._handleMouseLeaveBound),this.dropdownEl.removeEventListener("mouseleave",this._handleMouseLeaveBound)):this.el.removeEventListener("click",this._handleClickBound)}},{key:"_setupTemporaryEventHandlers",value:function(){document.body.addEventListener("click",this._handleDocumentClickBound,!0),document.body.addEventListener("touchend",this._handleDocumentClickBound),document.body.addEventListener("touchmove",this._handleDocumentTouchmoveBound),this.dropdownEl.addEventListener("keydown",this._handleDropdownKeydownBound)}},{key:"_removeTemporaryEventHandlers",value:function(){document.body.removeEventListener("click",this._handleDocumentClickBound,!0),document.body.removeEventListener("touchend",this._handleDocumentClickBound),document.body.removeEventListener("touchmove",this._handleDocumentTouchmoveBound),this.dropdownEl.removeEventListener("keydown",this._handleDropdownKeydownBound)}},{key:"_handleClick",value:function(t){t.preventDefault(),this.open()}},{key:"_handleMouseEnter",value:function(){this.open()}},{key:"_handleMouseLeave",value:function(t){var e=t.toElement||t.relatedTarget,i=!!h(e).closest(".dropdown-content").length,n=!1,s=h(e).closest(".dropdown-trigger");s.length&&s[0].M_Dropdown&&s[0].M_Dropdown.isOpen&&(n=!0),n||i||this.close()}},{key:"_handleDocumentClick",value:function(t){var e=this,i=h(t.target);this.options.closeOnClick&&i.closest(".dropdown-content").length&&!this.isTouchMoving?setTimeout(function(){e.close()},0):!i.closest(".dropdown-trigger").length&&i.closest(".dropdown-content").length||setTimeout(function(){e.close()},0),this.isTouchMoving=!1}},{key:"_handleTriggerKeydown",value:function(t){t.which!==M.keys.ARROW_DOWN&&t.which!==M.keys.ENTER||this.isOpen||(t.preventDefault(),this.open())}},{key:"_handleDocumentTouchmove",value:function(t){h(t.target).closest(".dropdown-content").length&&(this.isTouchMoving=!0)}},{key:"_handleDropdownClick",value:function(t){if("function"==typeof this.options.onItemClick){var e=h(t.target).closest("li")[0];this.options.onItemClick.call(this,e)}}},{key:"_handleDropdownKeydown",value:function(t){if(t.which===M.keys.TAB)t.preventDefault(),this.close();else if(t.which!==M.keys.ARROW_DOWN&&t.which!==M.keys.ARROW_UP||!this.isOpen)if(t.which===M.keys.ENTER&&this.isOpen){var e=this.dropdownEl.children[this.focusedIndex],i=h(e).find("a, button").first();i.length?i[0].click():e&&e.click()}else t.which===M.keys.ESC&&this.isOpen&&(t.preventDefault(),this.close());else{t.preventDefault();var n=t.which===M.keys.ARROW_DOWN?1:-1,s=this.focusedIndex,o=!1;do{if(s+=n,this.dropdownEl.children[s]&&-1!==this.dropdownEl.children[s].tabIndex){o=!0;break}}while(sl.spaceOnBottom?(h="bottom",i+=l.spaceOnTop,o-=l.spaceOnTop):i+=l.spaceOnBottom)),!l[d]){var u="left"===d?"right":"left";l[u]?d=u:l.spaceOnLeft>l.spaceOnRight?(d="right",n+=l.spaceOnLeft,s-=l.spaceOnLeft):(d="left",n+=l.spaceOnRight)}return"bottom"===h&&(o=o-e.height+(this.options.coverTrigger?t.height:0)),"right"===d&&(s=s-e.width+t.width),{x:s,y:o,verticalAlignment:h,horizontalAlignment:d,height:i,width:n}}},{key:"_animateIn",value:function(){var e=this;i.remove(this.dropdownEl),i({targets:this.dropdownEl,opacity:{value:[0,1],easing:"easeOutQuad"},scaleX:[.3,1],scaleY:[.3,1],duration:this.options.inDuration,easing:"easeOutQuint",complete:function(t){e.options.autoFocus&&e.dropdownEl.focus(),"function"==typeof e.options.onOpenEnd&&e.options.onOpenEnd.call(e,e.el)}})}},{key:"_animateOut",value:function(){var e=this;i.remove(this.dropdownEl),i({targets:this.dropdownEl,opacity:{value:0,easing:"easeOutQuint"},scaleX:.3,scaleY:.3,duration:this.options.outDuration,easing:"easeOutQuint",complete:function(t){e._resetDropdownStyles(),"function"==typeof e.options.onCloseEnd&&e.options.onCloseEnd.call(e,e.el)}})}},{key:"_placeDropdown",value:function(){var t=this.options.constrainWidth?this.el.getBoundingClientRect().width:this.dropdownEl.getBoundingClientRect().width;this.dropdownEl.style.width=t+"px";var e=this._getDropdownPosition();this.dropdownEl.style.left=e.x+"px",this.dropdownEl.style.top=e.y+"px",this.dropdownEl.style.height=e.height+"px",this.dropdownEl.style.width=e.width+"px",this.dropdownEl.style.transformOrigin=("left"===e.horizontalAlignment?"0":"100%")+" "+("top"===e.verticalAlignment?"0":"100%")}},{key:"open",value:function(){this.isOpen||(this.isOpen=!0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el),this._resetDropdownStyles(),this.dropdownEl.style.display="block",this._placeDropdown(),this._animateIn(),this._setupTemporaryEventHandlers())}},{key:"close",value:function(){this.isOpen&&(this.isOpen=!1,this.focusedIndex=-1,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),this._animateOut(),this._removeTemporaryEventHandlers(),this.options.autoFocus&&this.el.focus())}},{key:"recalculateDimensions",value:function(){this.isOpen&&(this.$dropdownEl.css({width:"",height:"",left:"",top:"","transform-origin":""}),this._placeDropdown())}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Dropdown}},{key:"defaults",get:function(){return e}}]),n}();t._dropdowns=[],M.Dropdown=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"dropdown","M_Dropdown")}(cash,M.anime),function(s,i){"use strict";var e={opacity:.5,inDuration:250,outDuration:250,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,preventScrolling:!0,dismissible:!0,startingTop:"4%",endingTop:"10%"},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Modal=i).options=s.extend({},n.defaults,e),i.isOpen=!1,i.id=i.$el.attr("id"),i._openingTrigger=void 0,i.$overlay=s('
'),i.el.tabIndex=0,i._nthModalOpened=0,n._count++,i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){n._count--,this._removeEventHandlers(),this.el.removeAttribute("style"),this.$overlay.remove(),this.el.M_Modal=void 0}},{key:"_setupEventHandlers",value:function(){this._handleOverlayClickBound=this._handleOverlayClick.bind(this),this._handleModalCloseClickBound=this._handleModalCloseClick.bind(this),1===n._count&&document.body.addEventListener("click",this._handleTriggerClick),this.$overlay[0].addEventListener("click",this._handleOverlayClickBound),this.el.addEventListener("click",this._handleModalCloseClickBound)}},{key:"_removeEventHandlers",value:function(){0===n._count&&document.body.removeEventListener("click",this._handleTriggerClick),this.$overlay[0].removeEventListener("click",this._handleOverlayClickBound),this.el.removeEventListener("click",this._handleModalCloseClickBound)}},{key:"_handleTriggerClick",value:function(t){var e=s(t.target).closest(".modal-trigger");if(e.length){var i=M.getIdFromTrigger(e[0]),n=document.getElementById(i).M_Modal;n&&n.open(e),t.preventDefault()}}},{key:"_handleOverlayClick",value:function(){this.options.dismissible&&this.close()}},{key:"_handleModalCloseClick",value:function(t){s(t.target).closest(".modal-close").length&&this.close()}},{key:"_handleKeydown",value:function(t){27===t.keyCode&&this.options.dismissible&&this.close()}},{key:"_handleFocus",value:function(t){this.el.contains(t.target)||this._nthModalOpened!==n._modalsOpen||this.el.focus()}},{key:"_animateIn",value:function(){var t=this;s.extend(this.el.style,{display:"block",opacity:0}),s.extend(this.$overlay[0].style,{display:"block",opacity:0}),i({targets:this.$overlay[0],opacity:this.options.opacity,duration:this.options.inDuration,easing:"easeOutQuad"});var e={targets:this.el,duration:this.options.inDuration,easing:"easeOutCubic",complete:function(){"function"==typeof t.options.onOpenEnd&&t.options.onOpenEnd.call(t,t.el,t._openingTrigger)}};this.el.classList.contains("bottom-sheet")?s.extend(e,{bottom:0,opacity:1}):s.extend(e,{top:[this.options.startingTop,this.options.endingTop],opacity:1,scaleX:[.8,1],scaleY:[.8,1]}),i(e)}},{key:"_animateOut",value:function(){var t=this;i({targets:this.$overlay[0],opacity:0,duration:this.options.outDuration,easing:"easeOutQuart"});var e={targets:this.el,duration:this.options.outDuration,easing:"easeOutCubic",complete:function(){t.el.style.display="none",t.$overlay.remove(),"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t,t.el)}};this.el.classList.contains("bottom-sheet")?s.extend(e,{bottom:"-100%",opacity:0}):s.extend(e,{top:[this.options.endingTop,this.options.startingTop],opacity:0,scaleX:.8,scaleY:.8}),i(e)}},{key:"open",value:function(t){if(!this.isOpen)return this.isOpen=!0,n._modalsOpen++,this._nthModalOpened=n._modalsOpen,this.$overlay[0].style.zIndex=1e3+2*n._modalsOpen,this.el.style.zIndex=1e3+2*n._modalsOpen+1,this._openingTrigger=t?t[0]:void 0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el,this._openingTrigger),this.options.preventScrolling&&(document.body.style.overflow="hidden"),this.el.classList.add("open"),this.el.insertAdjacentElement("afterend",this.$overlay[0]),this.options.dismissible&&(this._handleKeydownBound=this._handleKeydown.bind(this),this._handleFocusBound=this._handleFocus.bind(this),document.addEventListener("keydown",this._handleKeydownBound),document.addEventListener("focus",this._handleFocusBound,!0)),i.remove(this.el),i.remove(this.$overlay[0]),this._animateIn(),this.el.focus(),this}},{key:"close",value:function(){if(this.isOpen)return this.isOpen=!1,n._modalsOpen--,this._nthModalOpened=0,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),this.el.classList.remove("open"),0===n._modalsOpen&&(document.body.style.overflow=""),this.options.dismissible&&(document.removeEventListener("keydown",this._handleKeydownBound),document.removeEventListener("focus",this._handleFocusBound,!0)),i.remove(this.el),i.remove(this.$overlay[0]),this._animateOut(),this}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Modal}},{key:"defaults",get:function(){return e}}]),n}();t._modalsOpen=0,t._count=0,M.Modal=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"modal","M_Modal")}(cash,M.anime),function(o,a){"use strict";var e={inDuration:275,outDuration:200,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Materialbox=i).options=o.extend({},n.defaults,e),i.overlayActive=!1,i.doneAnimating=!0,i.placeholder=o("
").addClass("material-placeholder"),i.originalWidth=0,i.originalHeight=0,i.originInlineStyles=i.$el.attr("style"),i.caption=i.el.getAttribute("data-caption")||"",i.$el.before(i.placeholder),i.placeholder.append(i.$el),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Materialbox=void 0,o(this.placeholder).after(this.el).remove(),this.$el.removeAttr("style")}},{key:"_setupEventHandlers",value:function(){this._handleMaterialboxClickBound=this._handleMaterialboxClick.bind(this),this.el.addEventListener("click",this._handleMaterialboxClickBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleMaterialboxClickBound)}},{key:"_handleMaterialboxClick",value:function(t){!1===this.doneAnimating||this.overlayActive&&this.doneAnimating?this.close():this.open()}},{key:"_handleWindowScroll",value:function(){this.overlayActive&&this.close()}},{key:"_handleWindowResize",value:function(){this.overlayActive&&this.close()}},{key:"_handleWindowEscape",value:function(t){27===t.keyCode&&this.doneAnimating&&this.overlayActive&&this.close()}},{key:"_makeAncestorsOverflowVisible",value:function(){this.ancestorsChanged=o();for(var t=this.placeholder[0].parentNode;null!==t&&!o(t).is(document);){var e=o(t);"visible"!==e.css("overflow")&&(e.css("overflow","visible"),void 0===this.ancestorsChanged?this.ancestorsChanged=e:this.ancestorsChanged=this.ancestorsChanged.add(e)),t=t.parentNode}}},{key:"_animateImageIn",value:function(){var t=this,e={targets:this.el,height:[this.originalHeight,this.newHeight],width:[this.originalWidth,this.newWidth],left:M.getDocumentScrollLeft()+this.windowWidth/2-this.placeholder.offset().left-this.newWidth/2,top:M.getDocumentScrollTop()+this.windowHeight/2-this.placeholder.offset().top-this.newHeight/2,duration:this.options.inDuration,easing:"easeOutQuad",complete:function(){t.doneAnimating=!0,"function"==typeof t.options.onOpenEnd&&t.options.onOpenEnd.call(t,t.el)}};this.maxWidth=this.$el.css("max-width"),this.maxHeight=this.$el.css("max-height"),"none"!==this.maxWidth&&(e.maxWidth=this.newWidth),"none"!==this.maxHeight&&(e.maxHeight=this.newHeight),a(e)}},{key:"_animateImageOut",value:function(){var t=this,e={targets:this.el,width:this.originalWidth,height:this.originalHeight,left:0,top:0,duration:this.options.outDuration,easing:"easeOutQuad",complete:function(){t.placeholder.css({height:"",width:"",position:"",top:"",left:""}),t.attrWidth&&t.$el.attr("width",t.attrWidth),t.attrHeight&&t.$el.attr("height",t.attrHeight),t.$el.removeAttr("style"),t.originInlineStyles&&t.$el.attr("style",t.originInlineStyles),t.$el.removeClass("active"),t.doneAnimating=!0,t.ancestorsChanged.length&&t.ancestorsChanged.css("overflow",""),"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t,t.el)}};a(e)}},{key:"_updateVars",value:function(){this.windowWidth=window.innerWidth,this.windowHeight=window.innerHeight,this.caption=this.el.getAttribute("data-caption")||""}},{key:"open",value:function(){var t=this;this._updateVars(),this.originalWidth=this.el.getBoundingClientRect().width,this.originalHeight=this.el.getBoundingClientRect().height,this.doneAnimating=!1,this.$el.addClass("active"),this.overlayActive=!0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el),this.placeholder.css({width:this.placeholder[0].getBoundingClientRect().width+"px",height:this.placeholder[0].getBoundingClientRect().height+"px",position:"relative",top:0,left:0}),this._makeAncestorsOverflowVisible(),this.$el.css({position:"absolute","z-index":1e3,"will-change":"left, top, width, height"}),this.attrWidth=this.$el.attr("width"),this.attrHeight=this.$el.attr("height"),this.attrWidth&&(this.$el.css("width",this.attrWidth+"px"),this.$el.removeAttr("width")),this.attrHeight&&(this.$el.css("width",this.attrHeight+"px"),this.$el.removeAttr("height")),this.$overlay=o('
').css({opacity:0}).one("click",function(){t.doneAnimating&&t.close()}),this.$el.before(this.$overlay);var e=this.$overlay[0].getBoundingClientRect();this.$overlay.css({width:this.windowWidth+"px",height:this.windowHeight+"px",left:-1*e.left+"px",top:-1*e.top+"px"}),a.remove(this.el),a.remove(this.$overlay[0]),a({targets:this.$overlay[0],opacity:1,duration:this.options.inDuration,easing:"easeOutQuad"}),""!==this.caption&&(this.$photocaption&&a.remove(this.$photoCaption[0]),this.$photoCaption=o('
'),this.$photoCaption.text(this.caption),o("body").append(this.$photoCaption),this.$photoCaption.css({display:"inline"}),a({targets:this.$photoCaption[0],opacity:1,duration:this.options.inDuration,easing:"easeOutQuad"}));var i=0,n=this.originalWidth/this.windowWidth,s=this.originalHeight/this.windowHeight;this.newWidth=0,this.newHeight=0,si.options.responsiveThreshold,i.$img=i.$el.find("img").first(),i.$img.each(function(){this.complete&&s(this).trigger("load")}),i._updateParallax(),i._setupEventHandlers(),i._setupStyles(),n._parallaxes.push(i),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){n._parallaxes.splice(n._parallaxes.indexOf(this),1),this.$img[0].style.transform="",this._removeEventHandlers(),this.$el[0].M_Parallax=void 0}},{key:"_setupEventHandlers",value:function(){this._handleImageLoadBound=this._handleImageLoad.bind(this),this.$img[0].addEventListener("load",this._handleImageLoadBound),0===n._parallaxes.length&&(n._handleScrollThrottled=M.throttle(n._handleScroll,5),window.addEventListener("scroll",n._handleScrollThrottled),n._handleWindowResizeThrottled=M.throttle(n._handleWindowResize,5),window.addEventListener("resize",n._handleWindowResizeThrottled))}},{key:"_removeEventHandlers",value:function(){this.$img[0].removeEventListener("load",this._handleImageLoadBound),0===n._parallaxes.length&&(window.removeEventListener("scroll",n._handleScrollThrottled),window.removeEventListener("resize",n._handleWindowResizeThrottled))}},{key:"_setupStyles",value:function(){this.$img[0].style.opacity=1}},{key:"_handleImageLoad",value:function(){this._updateParallax()}},{key:"_updateParallax",value:function(){var t=0e.options.responsiveThreshold}}},{key:"defaults",get:function(){return e}}]),n}();t._parallaxes=[],M.Parallax=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"parallax","M_Parallax")}(cash),function(a,s){"use strict";var e={duration:300,onShow:null,swipeable:!1,responsiveThreshold:1/0},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Tabs=i).options=a.extend({},n.defaults,e),i.$tabLinks=i.$el.children("li.tab").children("a"),i.index=0,i._setupActiveTabLink(),i.options.swipeable?i._setupSwipeableTabs():i._setupNormalTabs(),i._setTabsAndTabWidth(),i._createIndicator(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this._indicator.parentNode.removeChild(this._indicator),this.options.swipeable?this._teardownSwipeableTabs():this._teardownNormalTabs(),this.$el[0].M_Tabs=void 0}},{key:"_setupEventHandlers",value:function(){this._handleWindowResizeBound=this._handleWindowResize.bind(this),window.addEventListener("resize",this._handleWindowResizeBound),this._handleTabClickBound=this._handleTabClick.bind(this),this.el.addEventListener("click",this._handleTabClickBound)}},{key:"_removeEventHandlers",value:function(){window.removeEventListener("resize",this._handleWindowResizeBound),this.el.removeEventListener("click",this._handleTabClickBound)}},{key:"_handleWindowResize",value:function(){this._setTabsAndTabWidth(),0!==this.tabWidth&&0!==this.tabsWidth&&(this._indicator.style.left=this._calcLeftPos(this.$activeTabLink)+"px",this._indicator.style.right=this._calcRightPos(this.$activeTabLink)+"px")}},{key:"_handleTabClick",value:function(t){var e=this,i=a(t.target).closest("li.tab"),n=a(t.target).closest("a");if(n.length&&n.parent().hasClass("tab"))if(i.hasClass("disabled"))t.preventDefault();else if(!n.attr("target")){this.$activeTabLink.removeClass("active");var s=this.$content;this.$activeTabLink=n,this.$content=a(M.escapeHash(n[0].hash)),this.$tabLinks=this.$el.children("li.tab").children("a"),this.$activeTabLink.addClass("active");var o=this.index;this.index=Math.max(this.$tabLinks.index(n),0),this.options.swipeable?this._tabsCarousel&&this._tabsCarousel.set(this.index,function(){"function"==typeof e.options.onShow&&e.options.onShow.call(e,e.$content[0])}):this.$content.length&&(this.$content[0].style.display="block",this.$content.addClass("active"),"function"==typeof this.options.onShow&&this.options.onShow.call(this,this.$content[0]),s.length&&!s.is(this.$content)&&(s[0].style.display="none",s.removeClass("active"))),this._setTabsAndTabWidth(),this._animateIndicator(o),t.preventDefault()}}},{key:"_createIndicator",value:function(){var t=this,e=document.createElement("li");e.classList.add("indicator"),this.el.appendChild(e),this._indicator=e,setTimeout(function(){t._indicator.style.left=t._calcLeftPos(t.$activeTabLink)+"px",t._indicator.style.right=t._calcRightPos(t.$activeTabLink)+"px"},0)}},{key:"_setupActiveTabLink",value:function(){this.$activeTabLink=a(this.$tabLinks.filter('[href="'+location.hash+'"]')),0===this.$activeTabLink.length&&(this.$activeTabLink=this.$el.children("li.tab").children("a.active").first()),0===this.$activeTabLink.length&&(this.$activeTabLink=this.$el.children("li.tab").children("a").first()),this.$tabLinks.removeClass("active"),this.$activeTabLink[0].classList.add("active"),this.index=Math.max(this.$tabLinks.index(this.$activeTabLink),0),this.$activeTabLink.length&&(this.$content=a(M.escapeHash(this.$activeTabLink[0].hash)),this.$content.addClass("active"))}},{key:"_setupSwipeableTabs",value:function(){var i=this;window.innerWidth>this.options.responsiveThreshold&&(this.options.swipeable=!1);var n=a();this.$tabLinks.each(function(t){var e=a(M.escapeHash(t.hash));e.addClass("carousel-item"),n=n.add(e)});var t=a('
');n.first().before(t),t.append(n),n[0].style.display="";var e=this.$activeTabLink.closest(".tab").index();this._tabsCarousel=M.Carousel.init(t[0],{fullWidth:!0,noWrap:!0,onCycleTo:function(t){var e=i.index;i.index=a(t).index(),i.$activeTabLink.removeClass("active"),i.$activeTabLink=i.$tabLinks.eq(i.index),i.$activeTabLink.addClass("active"),i._animateIndicator(e),"function"==typeof i.options.onShow&&i.options.onShow.call(i,i.$content[0])}}),this._tabsCarousel.set(e)}},{key:"_teardownSwipeableTabs",value:function(){var t=this._tabsCarousel.$el;this._tabsCarousel.destroy(),t.after(t.children()),t.remove()}},{key:"_setupNormalTabs",value:function(){this.$tabLinks.not(this.$activeTabLink).each(function(t){if(t.hash){var e=a(M.escapeHash(t.hash));e.length&&(e[0].style.display="none")}})}},{key:"_teardownNormalTabs",value:function(){this.$tabLinks.each(function(t){if(t.hash){var e=a(M.escapeHash(t.hash));e.length&&(e[0].style.display="")}})}},{key:"_setTabsAndTabWidth",value:function(){this.tabsWidth=this.$el.width(),this.tabWidth=Math.max(this.tabsWidth,this.el.scrollWidth)/this.$tabLinks.length}},{key:"_calcRightPos",value:function(t){return Math.ceil(this.tabsWidth-t.position().left-t[0].getBoundingClientRect().width)}},{key:"_calcLeftPos",value:function(t){return Math.floor(t.position().left)}},{key:"updateTabIndicator",value:function(){this._setTabsAndTabWidth(),this._animateIndicator(this.index)}},{key:"_animateIndicator",value:function(t){var e=0,i=0;0<=this.index-t?e=90:i=90;var n={targets:this._indicator,left:{value:this._calcLeftPos(this.$activeTabLink),delay:e},right:{value:this._calcRightPos(this.$activeTabLink),delay:i},duration:this.options.duration,easing:"easeOutQuad"};s.remove(this._indicator),s(n)}},{key:"select",value:function(t){var e=this.$tabLinks.filter('[href="#'+t+'"]');e.length&&e.trigger("click")}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Tabs}},{key:"defaults",get:function(){return e}}]),n}();M.Tabs=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"tabs","M_Tabs")}(cash,M.anime),function(d,e){"use strict";var i={exitDelay:200,enterDelay:0,html:null,margin:5,inDuration:250,outDuration:200,position:"bottom",transitionMovement:10},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Tooltip=i).options=d.extend({},n.defaults,e),i.isOpen=!1,i.isHovered=!1,i.isFocused=!1,i._appendTooltipEl(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){d(this.tooltipEl).remove(),this._removeEventHandlers(),this.el.M_Tooltip=void 0}},{key:"_appendTooltipEl",value:function(){var t=document.createElement("div");t.classList.add("material-tooltip"),this.tooltipEl=t;var e=document.createElement("div");e.classList.add("tooltip-content"),e.innerHTML=this.options.html,t.appendChild(e),document.body.appendChild(t)}},{key:"_updateTooltipContent",value:function(){this.tooltipEl.querySelector(".tooltip-content").innerHTML=this.options.html}},{key:"_setupEventHandlers",value:function(){this._handleMouseEnterBound=this._handleMouseEnter.bind(this),this._handleMouseLeaveBound=this._handleMouseLeave.bind(this),this._handleFocusBound=this._handleFocus.bind(this),this._handleBlurBound=this._handleBlur.bind(this),this.el.addEventListener("mouseenter",this._handleMouseEnterBound),this.el.addEventListener("mouseleave",this._handleMouseLeaveBound),this.el.addEventListener("focus",this._handleFocusBound,!0),this.el.addEventListener("blur",this._handleBlurBound,!0)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("mouseenter",this._handleMouseEnterBound),this.el.removeEventListener("mouseleave",this._handleMouseLeaveBound),this.el.removeEventListener("focus",this._handleFocusBound,!0),this.el.removeEventListener("blur",this._handleBlurBound,!0)}},{key:"open",value:function(t){this.isOpen||(t=void 0===t||void 0,this.isOpen=!0,this.options=d.extend({},this.options,this._getAttributeOptions()),this._updateTooltipContent(),this._setEnterDelayTimeout(t))}},{key:"close",value:function(){this.isOpen&&(this.isHovered=!1,this.isFocused=!1,this.isOpen=!1,this._setExitDelayTimeout())}},{key:"_setExitDelayTimeout",value:function(){var t=this;clearTimeout(this._exitDelayTimeout),this._exitDelayTimeout=setTimeout(function(){t.isHovered||t.isFocused||t._animateOut()},this.options.exitDelay)}},{key:"_setEnterDelayTimeout",value:function(t){var e=this;clearTimeout(this._enterDelayTimeout),this._enterDelayTimeout=setTimeout(function(){(e.isHovered||e.isFocused||t)&&e._animateIn()},this.options.enterDelay)}},{key:"_positionTooltip",value:function(){var t,e=this.el,i=this.tooltipEl,n=e.offsetHeight,s=e.offsetWidth,o=i.offsetHeight,a=i.offsetWidth,r=this.options.margin,l=void 0,h=void 0;this.xMovement=0,this.yMovement=0,l=e.getBoundingClientRect().top+M.getDocumentScrollTop(),h=e.getBoundingClientRect().left+M.getDocumentScrollLeft(),"top"===this.options.position?(l+=-o-r,h+=s/2-a/2,this.yMovement=-this.options.transitionMovement):"right"===this.options.position?(l+=n/2-o/2,h+=s+r,this.xMovement=this.options.transitionMovement):"left"===this.options.position?(l+=n/2-o/2,h+=-a-r,this.xMovement=-this.options.transitionMovement):(l+=n+r,h+=s/2-a/2,this.yMovement=this.options.transitionMovement),t=this._repositionWithinScreen(h,l,a,o),d(i).css({top:t.y+"px",left:t.x+"px"})}},{key:"_repositionWithinScreen",value:function(t,e,i,n){var s=M.getDocumentScrollLeft(),o=M.getDocumentScrollTop(),a=t-s,r=e-o,l={left:a,top:r,width:i,height:n},h=this.options.margin+this.options.transitionMovement,d=M.checkWithinContainer(document.body,l,h);return d.left?a=h:d.right&&(a-=a+i-window.innerWidth),d.top?r=h:d.bottom&&(r-=r+n-window.innerHeight),{x:a+s,y:r+o}}},{key:"_animateIn",value:function(){this._positionTooltip(),this.tooltipEl.style.visibility="visible",e.remove(this.tooltipEl),e({targets:this.tooltipEl,opacity:1,translateX:this.xMovement,translateY:this.yMovement,duration:this.options.inDuration,easing:"easeOutCubic"})}},{key:"_animateOut",value:function(){e.remove(this.tooltipEl),e({targets:this.tooltipEl,opacity:0,translateX:0,translateY:0,duration:this.options.outDuration,easing:"easeOutCubic"})}},{key:"_handleMouseEnter",value:function(){this.isHovered=!0,this.isFocused=!1,this.open(!1)}},{key:"_handleMouseLeave",value:function(){this.isHovered=!1,this.isFocused=!1,this.close()}},{key:"_handleFocus",value:function(){M.tabPressed&&(this.isFocused=!0,this.open(!1))}},{key:"_handleBlur",value:function(){this.isFocused=!1,this.close()}},{key:"_getAttributeOptions",value:function(){var t={},e=this.el.getAttribute("data-tooltip"),i=this.el.getAttribute("data-position");return e&&(t.html=e),i&&(t.position=i),t}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Tooltip}},{key:"defaults",get:function(){return i}}]),n}();M.Tooltip=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"tooltip","M_Tooltip")}(cash,M.anime),function(i){"use strict";var t=t||{},e=document.querySelectorAll.bind(document);function m(t){var e="";for(var i in t)t.hasOwnProperty(i)&&(e+=i+":"+t[i]+";");return e}var g={duration:750,show:function(t,e){if(2===t.button)return!1;var i=e||this,n=document.createElement("div");n.className="waves-ripple",i.appendChild(n);var s,o,a,r,l,h,d,u=(h={top:0,left:0},d=(s=i)&&s.ownerDocument,o=d.documentElement,void 0!==s.getBoundingClientRect&&(h=s.getBoundingClientRect()),a=null!==(l=r=d)&&l===l.window?r:9===r.nodeType&&r.defaultView,{top:h.top+a.pageYOffset-o.clientTop,left:h.left+a.pageXOffset-o.clientLeft}),c=t.pageY-u.top,p=t.pageX-u.left,v="scale("+i.clientWidth/100*10+")";"touches"in t&&(c=t.touches[0].pageY-u.top,p=t.touches[0].pageX-u.left),n.setAttribute("data-hold",Date.now()),n.setAttribute("data-scale",v),n.setAttribute("data-x",p),n.setAttribute("data-y",c);var f={top:c+"px",left:p+"px"};n.className=n.className+" waves-notransition",n.setAttribute("style",m(f)),n.className=n.className.replace("waves-notransition",""),f["-webkit-transform"]=v,f["-moz-transform"]=v,f["-ms-transform"]=v,f["-o-transform"]=v,f.transform=v,f.opacity="1",f["-webkit-transition-duration"]=g.duration+"ms",f["-moz-transition-duration"]=g.duration+"ms",f["-o-transition-duration"]=g.duration+"ms",f["transition-duration"]=g.duration+"ms",f["-webkit-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f["-moz-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f["-o-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f["transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",n.setAttribute("style",m(f))},hide:function(t){l.touchup(t);var e=this,i=(e.clientWidth,null),n=e.getElementsByClassName("waves-ripple");if(!(0i||1"+o+""+a+" "+r+""),i.length&&e.prepend(i)}},{key:"_resetCurrentElement",value:function(){this.activeIndex=-1,this.$active.removeClass("active")}},{key:"_resetAutocomplete",value:function(){h(this.container).empty(),this._resetCurrentElement(),this.oldVal=null,this.isOpen=!1,this._mousedown=!1}},{key:"selectOption",value:function(t){var e=t.text().trim();this.el.value=e,this.$el.trigger("change"),this._resetAutocomplete(),this.close(),"function"==typeof this.options.onAutocomplete&&this.options.onAutocomplete.call(this,e)}},{key:"_renderDropdown",value:function(t,i){var n=this;this._resetAutocomplete();var e=[];for(var s in t)if(t.hasOwnProperty(s)&&-1!==s.toLowerCase().indexOf(i)){if(this.count>=this.options.limit)break;var o={data:t[s],key:s};e.push(o),this.count++}if(this.options.sortFunction){e.sort(function(t,e){return n.options.sortFunction(t.key.toLowerCase(),e.key.toLowerCase(),i.toLowerCase())})}for(var a=0;a");r.data?l.append(''+r.key+" "):l.append(""+r.key+" "),h(this.container).append(l),this._highlight(i,l)}}},{key:"open",value:function(){var t=this.el.value.toLowerCase();this._resetAutocomplete(),t.length>=this.options.minLength&&(this.isOpen=!0,this._renderDropdown(this.options.data,t)),this.dropdown.isOpen?this.dropdown.recalculateDimensions():this.dropdown.open()}},{key:"close",value:function(){this.dropdown.close()}},{key:"updateData",value:function(t){var e=this.el.value.toLowerCase();this.options.data=t,this.isOpen&&this._renderDropdown(t,e)}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Autocomplete}},{key:"defaults",get:function(){return e}}]),s}();t._keydown=!1,M.Autocomplete=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"autocomplete","M_Autocomplete")}(cash),function(d){M.updateTextFields=function(){d("input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], input[type=date], input[type=time], textarea").each(function(t,e){var i=d(this);0'),d("body").append(e));var i=t.css("font-family"),n=t.css("font-size"),s=t.css("line-height"),o=t.css("padding-top"),a=t.css("padding-right"),r=t.css("padding-bottom"),l=t.css("padding-left");n&&e.css("font-size",n),i&&e.css("font-family",i),s&&e.css("line-height",s),o&&e.css("padding-top",o),a&&e.css("padding-right",a),r&&e.css("padding-bottom",r),l&&e.css("padding-left",l),t.data("original-height")||t.data("original-height",t.height()),"off"===t.attr("wrap")&&e.css("overflow-wrap","normal").css("white-space","pre"),e.text(t[0].value+"\n");var h=e.html().replace(/\n/g," ");e.html(h),0'),this.$slides.each(function(t,e){var i=s(' ');n.$indicators.append(i[0])}),this.$el.append(this.$indicators[0]),this.$indicators=this.$indicators.children("li.indicator-item"))}},{key:"_removeIndicators",value:function(){this.$el.find("ul.indicators").remove()}},{key:"set",value:function(t){var e=this;if(t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.activeIndex!=t){this.$active=this.$slides.eq(this.activeIndex);var i=this.$active.find(".caption");this.$active.removeClass("active"),o({targets:this.$active[0],opacity:0,duration:this.options.duration,easing:"easeOutQuad",complete:function(){e.$slides.not(".active").each(function(t){o({targets:t,opacity:0,translateX:0,translateY:0,duration:0,easing:"easeOutQuad"})})}}),this._animateCaptionIn(i[0],this.options.duration),this.options.indicators&&(this.$indicators.eq(this.activeIndex).removeClass("active"),this.$indicators.eq(t).addClass("active")),o({targets:this.$slides.eq(t)[0],opacity:1,duration:this.options.duration,easing:"easeOutQuad"}),o({targets:this.$slides.eq(t).find(".caption")[0],opacity:1,translateX:0,translateY:0,duration:this.options.duration,delay:this.options.duration,easing:"easeOutQuad"}),this.$slides.eq(t).addClass("active"),this.activeIndex=t,this.start()}}},{key:"pause",value:function(){clearInterval(this.interval)}},{key:"start",value:function(){clearInterval(this.interval),this.interval=setInterval(this._handleIntervalBound,this.options.duration+this.options.interval)}},{key:"next",value:function(){var t=this.activeIndex+1;t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.set(t)}},{key:"prev",value:function(){var t=this.activeIndex-1;t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.set(t)}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Slider}},{key:"defaults",get:function(){return e}}]),n}();M.Slider=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"slider","M_Slider")}(cash,M.anime),function(n,s){n(document).on("click",".card",function(t){if(n(this).children(".card-reveal").length){var i=n(t.target).closest(".card");void 0===i.data("initialOverflow")&&i.data("initialOverflow",void 0===i.css("overflow")?"":i.css("overflow"));var e=n(this).find(".card-reveal");n(t.target).is(n(".card-reveal .card-title"))||n(t.target).is(n(".card-reveal .card-title i"))?s({targets:e[0],translateY:0,duration:225,easing:"easeInOutQuad",complete:function(t){var e=t.animatables[0].target;n(e).css({display:"none"}),i.css("overflow",i.data("initialOverflow"))}}):(n(t.target).is(n(".card .activator"))||n(t.target).is(n(".card .activator i")))&&(i.css("overflow","hidden"),e.css({display:"block"}),s({targets:e[0],translateY:"-100%",duration:300,easing:"easeInOutQuad"}))}})}(cash,M.anime),function(h){"use strict";var e={data:[],placeholder:"",secondaryPlaceholder:"",autocompleteOptions:{},limit:1/0,onChipAdd:null,onChipSelect:null,onChipDelete:null},t=function(t){function l(t,e){_classCallCheck(this,l);var i=_possibleConstructorReturn(this,(l.__proto__||Object.getPrototypeOf(l)).call(this,l,t,e));return(i.el.M_Chips=i).options=h.extend({},l.defaults,e),i.$el.addClass("chips input-field"),i.chipsData=[],i.$chips=h(),i._setupInput(),i.hasAutocomplete=0"),this.$el.append(this.$input)),this.$input.addClass("input")}},{key:"_setupLabel",value:function(){this.$label=this.$el.find("label"),this.$label.length&&this.$label.setAttribute("for",this.$input.attr("id"))}},{key:"_setPlaceholder",value:function(){void 0!==this.chipsData&&!this.chipsData.length&&this.options.placeholder?h(this.$input).prop("placeholder",this.options.placeholder):(void 0===this.chipsData||this.chipsData.length)&&this.options.secondaryPlaceholder&&h(this.$input).prop("placeholder",this.options.secondaryPlaceholder)}},{key:"_isValid",value:function(t){if(t.hasOwnProperty("tag")&&""!==t.tag){for(var e=!1,i=0;i=this.options.limit)){var e=this._renderChip(t);this.$chips.add(e),this.chipsData.push(t),h(this.$input).before(e),this._setPlaceholder(),"function"==typeof this.options.onChipAdd&&this.options.onChipAdd.call(this,this.$el,e)}}},{key:"deleteChip",value:function(t){var e=this.$chips.eq(t);this.$chips.eq(t).remove(),this.$chips=this.$chips.filter(function(t){return 0<=h(t).index()}),this.chipsData.splice(t,1),this._setPlaceholder(),"function"==typeof this.options.onChipDelete&&this.options.onChipDelete.call(this,this.$el,e[0])}},{key:"selectChip",value:function(t){var e=this.$chips.eq(t);(this._selectedChip=e)[0].focus(),"function"==typeof this.options.onChipSelect&&this.options.onChipSelect.call(this,this.$el,e[0])}}],[{key:"init",value:function(t,e){return _get(l.__proto__||Object.getPrototypeOf(l),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Chips}},{key:"_handleChipsKeydown",value:function(t){l._keydown=!0;var e=h(t.target).closest(".chips"),i=t.target&&e.length;if(!h(t.target).is("input, textarea")&&i){var n=e[0].M_Chips;if(8===t.keyCode||46===t.keyCode){t.preventDefault();var s=n.chipsData.length;if(n._selectedChip){var o=n._selectedChip.index();n.deleteChip(o),n._selectedChip=null,s=Math.max(o-1,0)}n.chipsData.length&&n.selectChip(s)}else if(37===t.keyCode){if(n._selectedChip){var a=n._selectedChip.index()-1;if(a<0)return;n.selectChip(a)}}else if(39===t.keyCode&&n._selectedChip){var r=n._selectedChip.index()+1;r>=n.chipsData.length?n.$input[0].focus():n.selectChip(r)}}}},{key:"_handleChipsKeyup",value:function(t){l._keydown=!1}},{key:"_handleChipsBlur",value:function(t){l._keydown||(h(t.target).closest(".chips")[0].M_Chips._selectedChip=null)}},{key:"defaults",get:function(){return e}}]),l}();t._keydown=!1,M.Chips=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"chips","M_Chips"),h(document).ready(function(){h(document.body).on("click",".chip .close",function(){var t=h(this).closest(".chips");t.length&&t[0].M_Chips||h(this).closest(".chip").remove()})})}(cash),function(s){"use strict";var e={top:0,bottom:1/0,offset:0,onPositionChange:null},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Pushpin=i).options=s.extend({},n.defaults,e),i.originalOffset=i.el.offsetTop,n._pushpins.push(i),i._setupEventHandlers(),i._updatePosition(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this.el.style.top=null,this._removePinClasses(),this._removeEventHandlers();var t=n._pushpins.indexOf(this);n._pushpins.splice(t,1)}},{key:"_setupEventHandlers",value:function(){document.addEventListener("scroll",n._updateElements)}},{key:"_removeEventHandlers",value:function(){document.removeEventListener("scroll",n._updateElements)}},{key:"_updatePosition",value:function(){var t=M.getDocumentScrollTop()+this.options.offset;this.options.top<=t&&this.options.bottom>=t&&!this.el.classList.contains("pinned")&&(this._removePinClasses(),this.el.style.top=this.options.offset+"px",this.el.classList.add("pinned"),"function"==typeof this.options.onPositionChange&&this.options.onPositionChange.call(this,"pinned")),tthis.options.bottom&&!this.el.classList.contains("pin-bottom")&&(this._removePinClasses(),this.el.classList.add("pin-bottom"),this.el.style.top=this.options.bottom-this.originalOffset+"px","function"==typeof this.options.onPositionChange&&this.options.onPositionChange.call(this,"pin-bottom"))}},{key:"_removePinClasses",value:function(){this.el.classList.remove("pin-top"),this.el.classList.remove("pinned"),this.el.classList.remove("pin-bottom")}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Pushpin}},{key:"_updateElements",value:function(){for(var t in n._pushpins){n._pushpins[t]._updatePosition()}}},{key:"defaults",get:function(){return e}}]),n}();t._pushpins=[],M.Pushpin=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"pushpin","M_Pushpin")}(cash),function(r,s){"use strict";var e={direction:"top",hoverEnabled:!0,toolbarEnabled:!1};r.fn.reverse=[].reverse;var t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_FloatingActionButton=i).options=r.extend({},n.defaults,e),i.isOpen=!1,i.$anchor=i.$el.children("a").first(),i.$menu=i.$el.children("ul").first(),i.$floatingBtns=i.$el.find("ul .btn-floating"),i.$floatingBtnsReverse=i.$el.find("ul .btn-floating").reverse(),i.offsetY=0,i.offsetX=0,i.$el.addClass("direction-"+i.options.direction),"top"===i.options.direction?i.offsetY=40:"right"===i.options.direction?i.offsetX=-40:"bottom"===i.options.direction?i.offsetY=-40:i.offsetX=40,i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_FloatingActionButton=void 0}},{key:"_setupEventHandlers",value:function(){this._handleFABClickBound=this._handleFABClick.bind(this),this._handleOpenBound=this.open.bind(this),this._handleCloseBound=this.close.bind(this),this.options.hoverEnabled&&!this.options.toolbarEnabled?(this.el.addEventListener("mouseenter",this._handleOpenBound),this.el.addEventListener("mouseleave",this._handleCloseBound)):this.el.addEventListener("click",this._handleFABClickBound)}},{key:"_removeEventHandlers",value:function(){this.options.hoverEnabled&&!this.options.toolbarEnabled?(this.el.removeEventListener("mouseenter",this._handleOpenBound),this.el.removeEventListener("mouseleave",this._handleCloseBound)):this.el.removeEventListener("click",this._handleFABClickBound)}},{key:"_handleFABClick",value:function(){this.isOpen?this.close():this.open()}},{key:"_handleDocumentClick",value:function(t){r(t.target).closest(this.$menu).length||this.close()}},{key:"open",value:function(){this.isOpen||(this.options.toolbarEnabled?this._animateInToolbar():this._animateInFAB(),this.isOpen=!0)}},{key:"close",value:function(){this.isOpen&&(this.options.toolbarEnabled?(window.removeEventListener("scroll",this._handleCloseBound,!0),document.body.removeEventListener("click",this._handleDocumentClickBound,!0),this._animateOutToolbar()):this._animateOutFAB(),this.isOpen=!1)}},{key:"_animateInFAB",value:function(){var e=this;this.$el.addClass("active");var i=0;this.$floatingBtnsReverse.each(function(t){s({targets:t,opacity:1,scale:[.4,1],translateY:[e.offsetY,0],translateX:[e.offsetX,0],duration:275,delay:i,easing:"easeInOutQuad"}),i+=40})}},{key:"_animateOutFAB",value:function(){var e=this;this.$floatingBtnsReverse.each(function(t){s.remove(t),s({targets:t,opacity:0,scale:.4,translateY:e.offsetY,translateX:e.offsetX,duration:175,easing:"easeOutQuad",complete:function(){e.$el.removeClass("active")}})})}},{key:"_animateInToolbar",value:function(){var t,e=this,i=window.innerWidth,n=window.innerHeight,s=this.el.getBoundingClientRect(),o=r('
'),a=this.$anchor.css("background-color");this.$anchor.append(o),this.offsetX=s.left-i/2+s.width/2,this.offsetY=n-s.bottom,t=i/o[0].clientWidth,this.btnBottom=s.bottom,this.btnLeft=s.left,this.btnWidth=s.width,this.$el.addClass("active"),this.$el.css({"text-align":"center",width:"100%",bottom:0,left:0,transform:"translateX("+this.offsetX+"px)",transition:"none"}),this.$anchor.css({transform:"translateY("+-this.offsetY+"px)",transition:"none"}),o.css({"background-color":a}),setTimeout(function(){e.$el.css({transform:"",transition:"transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s"}),e.$anchor.css({overflow:"visible",transform:"",transition:"transform .2s"}),setTimeout(function(){e.$el.css({overflow:"hidden","background-color":a}),o.css({transform:"scale("+t+")",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"}),e.$menu.children("li").children("a").css({opacity:1}),e._handleDocumentClickBound=e._handleDocumentClick.bind(e),window.addEventListener("scroll",e._handleCloseBound,!0),document.body.addEventListener("click",e._handleDocumentClickBound,!0)},100)},0)}},{key:"_animateOutToolbar",value:function(){var t=this,e=window.innerWidth,i=window.innerHeight,n=this.$el.find(".fab-backdrop"),s=this.$anchor.css("background-color");this.offsetX=this.btnLeft-e/2+this.btnWidth/2,this.offsetY=i-this.btnBottom,this.$el.removeClass("active"),this.$el.css({"background-color":"transparent",transition:"none"}),this.$anchor.css({transition:"none"}),n.css({transform:"scale(0)","background-color":s}),this.$menu.children("li").children("a").css({opacity:""}),setTimeout(function(){n.remove(),t.$el.css({"text-align":"",width:"",bottom:"",left:"",overflow:"","background-color":"",transform:"translate3d("+-t.offsetX+"px,0,0)"}),t.$anchor.css({overflow:"",transform:"translate3d(0,"+t.offsetY+"px,0)"}),setTimeout(function(){t.$el.css({transform:"translate3d(0,0,0)",transition:"transform .2s"}),t.$anchor.css({transform:"translate3d(0,0,0)",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"})},20)},200)}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_FloatingActionButton}},{key:"defaults",get:function(){return e}}]),n}();M.FloatingActionButton=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"floatingActionButton","M_FloatingActionButton")}(cash,M.anime),function(g){"use strict";var e={autoClose:!1,format:"mmm dd, yyyy",parse:null,defaultDate:null,setDefaultDate:!1,disableWeekends:!1,disableDayFn:null,firstDay:0,minDate:null,maxDate:null,yearRange:10,minYear:0,maxYear:9999,minMonth:void 0,maxMonth:void 0,startRange:null,endRange:null,isRTL:!1,showMonthAfterYear:!1,showDaysInNextAndPreviousMonths:!1,container:null,showClearBtn:!1,i18n:{cancel:"Cancel",clear:"Clear",done:"Ok",previousMonth:"‹",nextMonth:"›",months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdays:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],weekdaysAbbrev:["S","M","T","W","T","F","S"]},events:[],onSelect:null,onOpen:null,onClose:null,onDraw:null},t=function(t){function B(t,e){_classCallCheck(this,B);var i=_possibleConstructorReturn(this,(B.__proto__||Object.getPrototypeOf(B)).call(this,B,t,e));(i.el.M_Datepicker=i).options=g.extend({},B.defaults,e),e&&e.hasOwnProperty("i18n")&&"object"==typeof e.i18n&&(i.options.i18n=g.extend({},B.defaults.i18n,e.i18n)),i.options.minDate&&i.options.minDate.setHours(0,0,0,0),i.options.maxDate&&i.options.maxDate.setHours(0,0,0,0),i.id=M.guid(),i._setupVariables(),i._insertHTMLIntoDOM(),i._setupModal(),i._setupEventHandlers(),i.options.defaultDate||(i.options.defaultDate=new Date(Date.parse(i.el.value)));var n=i.options.defaultDate;return B._isDate(n)?i.options.setDefaultDate?(i.setDate(n,!0),i.setInputValue()):i.gotoDate(n):i.gotoDate(new Date),i.isOpen=!1,i}return _inherits(B,Component),_createClass(B,[{key:"destroy",value:function(){this._removeEventHandlers(),this.modal.destroy(),g(this.modalEl).remove(),this.destroySelects(),this.el.M_Datepicker=void 0}},{key:"destroySelects",value:function(){var t=this.calendarEl.querySelector(".orig-select-year");t&&M.FormSelect.getInstance(t).destroy();var e=this.calendarEl.querySelector(".orig-select-month");e&&M.FormSelect.getInstance(e).destroy()}},{key:"_insertHTMLIntoDOM",value:function(){this.options.showClearBtn&&(g(this.clearBtn).css({visibility:""}),this.clearBtn.innerHTML=this.options.i18n.clear),this.doneBtn.innerHTML=this.options.i18n.done,this.cancelBtn.innerHTML=this.options.i18n.cancel,this.options.container?this.$modalEl.appendTo(this.options.container):this.$modalEl.insertBefore(this.el)}},{key:"_setupModal",value:function(){var t=this;this.modalEl.id="modal-"+this.id,this.modal=M.Modal.init(this.modalEl,{onCloseEnd:function(){t.isOpen=!1}})}},{key:"toString",value:function(t){var e=this;return t=t||this.options.format,B._isDate(this.date)?t.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g).map(function(t){return e.formats[t]?e.formats[t]():t}).join(""):""}},{key:"setDate",value:function(t,e){if(!t)return this.date=null,this._renderDateDisplay(),this.draw();if("string"==typeof t&&(t=new Date(Date.parse(t))),B._isDate(t)){var i=this.options.minDate,n=this.options.maxDate;B._isDate(i)&&tn.maxDate||n.disableWeekends&&B._isWeekend(y)||n.disableDayFn&&n.disableDayFn(y),isEmpty:C,isStartRange:x,isEndRange:L,isInRange:T,showDaysInNextAndPreviousMonths:n.showDaysInNextAndPreviousMonths};l.push(this.renderDay($)),7==++_&&(r.push(this.renderRow(l,n.isRTL,m)),_=0,m=!(l=[]))}return this.renderTable(n,r,i)}},{key:"renderDay",value:function(t){var e=[],i="false";if(t.isEmpty){if(!t.showDaysInNextAndPreviousMonths)return' ';e.push("is-outside-current-month"),e.push("is-selection-disabled")}return t.isDisabled&&e.push("is-disabled"),t.isToday&&e.push("is-today"),t.isSelected&&(e.push("is-selected"),i="true"),t.hasEvent&&e.push("has-event"),t.isInRange&&e.push("is-inrange"),t.isStartRange&&e.push("is-startrange"),t.isEndRange&&e.push("is-endrange"),''+t.day+" "}},{key:"renderRow",value:function(t,e,i){return''+(e?t.reverse():t).join("")+" "}},{key:"renderTable",value:function(t,e,i){return''+this.renderHead(t)+this.renderBody(e)+"
"}},{key:"renderHead",value:function(t){var e=void 0,i=[];for(e=0;e<7;e++)i.push(''+this.renderDayName(t,e,!0)+" ");return""+(t.isRTL?i.reverse():i).join("")+" "}},{key:"renderBody",value:function(t){return""+t.join("")+" "}},{key:"renderTitle",value:function(t,e,i,n,s,o){var a,r,l=void 0,h=void 0,d=void 0,u=this.options,c=i===u.minYear,p=i===u.maxYear,v='',f=!0,m=!0;for(d=[],l=0;l<12;l++)d.push('
u.maxMonth?'disabled="disabled"':"")+">"+u.i18n.months[l]+" ");for(a='
'+d.join("")+" ",g.isArray(u.yearRange)?(l=u.yearRange[0],h=u.yearRange[1]+1):(l=i-u.yearRange,h=1+i+u.yearRange),d=[];l
=u.minYear&&d.push('"+l+" ");r=''+d.join("")+" ";v+=' ',v+='',u.showMonthAfterYear?v+=r+a:v+=a+r,v+="
",c&&(0===n||u.minMonth>=n)&&(f=!1),p&&(11===n||u.maxMonth<=n)&&(m=!1);return(v+=' ')+" "}},{key:"draw",value:function(t){if(this.isOpen||t){var e,i=this.options,n=i.minYear,s=i.maxYear,o=i.minMonth,a=i.maxMonth,r="";this._y<=n&&(this._y=n,!isNaN(o)&&this._m=s&&(this._y=s,!isNaN(a)&&this._m>a&&(this._m=a)),e="datepicker-title-"+Math.random().toString(36).replace(/[^a-z]+/g,"").substr(0,2);for(var l=0;l<1;l++)this._renderDateDisplay(),r+=this.renderTitle(this,l,this.calendars[l].year,this.calendars[l].month,this.calendars[0].year,e)+this.render(this.calendars[l].year,this.calendars[l].month,e);this.destroySelects(),this.calendarEl.innerHTML=r;var h=this.calendarEl.querySelector(".orig-select-year"),d=this.calendarEl.querySelector(".orig-select-month");M.FormSelect.init(h,{classes:"select-year",dropdownOptions:{container:document.body,constrainWidth:!1}}),M.FormSelect.init(d,{classes:"select-month",dropdownOptions:{container:document.body,constrainWidth:!1}}),h.addEventListener("change",this._handleYearChange.bind(this)),d.addEventListener("change",this._handleMonthChange.bind(this)),"function"==typeof this.options.onDraw&&this.options.onDraw(this)}}},{key:"_setupEventHandlers",value:function(){this._handleInputKeydownBound=this._handleInputKeydown.bind(this),this._handleInputClickBound=this._handleInputClick.bind(this),this._handleInputChangeBound=this._handleInputChange.bind(this),this._handleCalendarClickBound=this._handleCalendarClick.bind(this),this._finishSelectionBound=this._finishSelection.bind(this),this._handleMonthChange=this._handleMonthChange.bind(this),this._closeBound=this.close.bind(this),this.el.addEventListener("click",this._handleInputClickBound),this.el.addEventListener("keydown",this._handleInputKeydownBound),this.el.addEventListener("change",this._handleInputChangeBound),this.calendarEl.addEventListener("click",this._handleCalendarClickBound),this.doneBtn.addEventListener("click",this._finishSelectionBound),this.cancelBtn.addEventListener("click",this._closeBound),this.options.showClearBtn&&(this._handleClearClickBound=this._handleClearClick.bind(this),this.clearBtn.addEventListener("click",this._handleClearClickBound))}},{key:"_setupVariables",value:function(){var e=this;this.$modalEl=g(B._template),this.modalEl=this.$modalEl[0],this.calendarEl=this.modalEl.querySelector(".datepicker-calendar"),this.yearTextEl=this.modalEl.querySelector(".year-text"),this.dateTextEl=this.modalEl.querySelector(".date-text"),this.options.showClearBtn&&(this.clearBtn=this.modalEl.querySelector(".datepicker-clear")),this.doneBtn=this.modalEl.querySelector(".datepicker-done"),this.cancelBtn=this.modalEl.querySelector(".datepicker-cancel"),this.formats={d:function(){return e.date.getDate()},dd:function(){var t=e.date.getDate();return(t<10?"0":"")+t},ddd:function(){return e.options.i18n.weekdaysShort[e.date.getDay()]},dddd:function(){return e.options.i18n.weekdays[e.date.getDay()]},m:function(){return e.date.getMonth()+1},mm:function(){var t=e.date.getMonth()+1;return(t<10?"0":"")+t},mmm:function(){return e.options.i18n.monthsShort[e.date.getMonth()]},mmmm:function(){return e.options.i18n.months[e.date.getMonth()]},yy:function(){return(""+e.date.getFullYear()).slice(2)},yyyy:function(){return e.date.getFullYear()}}}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleInputClickBound),this.el.removeEventListener("keydown",this._handleInputKeydownBound),this.el.removeEventListener("change",this._handleInputChangeBound),this.calendarEl.removeEventListener("click",this._handleCalendarClickBound)}},{key:"_handleInputClick",value:function(){this.open()}},{key:"_handleInputKeydown",value:function(t){t.which===M.keys.ENTER&&(t.preventDefault(),this.open())}},{key:"_handleCalendarClick",value:function(t){if(this.isOpen){var e=g(t.target);e.hasClass("is-disabled")||(!e.hasClass("datepicker-day-button")||e.hasClass("is-empty")||e.parent().hasClass("is-disabled")?e.closest(".month-prev").length?this.prevMonth():e.closest(".month-next").length&&this.nextMonth():(this.setDate(new Date(t.target.getAttribute("data-year"),t.target.getAttribute("data-month"),t.target.getAttribute("data-day"))),this.options.autoClose&&this._finishSelection()))}}},{key:"_handleClearClick",value:function(){this.date=null,this.setInputValue(),this.close()}},{key:"_handleMonthChange",value:function(t){this.gotoMonth(t.target.value)}},{key:"_handleYearChange",value:function(t){this.gotoYear(t.target.value)}},{key:"gotoMonth",value:function(t){isNaN(t)||(this.calendars[0].month=parseInt(t,10),this.adjustCalendars())}},{key:"gotoYear",value:function(t){isNaN(t)||(this.calendars[0].year=parseInt(t,10),this.adjustCalendars())}},{key:"_handleInputChange",value:function(t){var e=void 0;t.firedBy!==this&&(e=this.options.parse?this.options.parse(this.el.value,this.options.format):new Date(Date.parse(this.el.value)),B._isDate(e)&&this.setDate(e))}},{key:"renderDayName",value:function(t,e,i){for(e+=t.firstDay;7<=e;)e-=7;return i?t.i18n.weekdaysAbbrev[e]:t.i18n.weekdays[e]}},{key:"_finishSelection",value:function(){this.setInputValue(),this.close()}},{key:"open",value:function(){if(!this.isOpen)return this.isOpen=!0,"function"==typeof this.options.onOpen&&this.options.onOpen.call(this),this.draw(),this.modal.open(),this}},{key:"close",value:function(){if(this.isOpen)return this.isOpen=!1,"function"==typeof this.options.onClose&&this.options.onClose.call(this),this.modal.close(),this}}],[{key:"init",value:function(t,e){return _get(B.__proto__||Object.getPrototypeOf(B),"init",this).call(this,this,t,e)}},{key:"_isDate",value:function(t){return/Date/.test(Object.prototype.toString.call(t))&&!isNaN(t.getTime())}},{key:"_isWeekend",value:function(t){var e=t.getDay();return 0===e||6===e}},{key:"_setToStartOfDay",value:function(t){B._isDate(t)&&t.setHours(0,0,0,0)}},{key:"_getDaysInMonth",value:function(t,e){return[31,B._isLeapYear(t)?29:28,31,30,31,30,31,31,30,31,30,31][e]}},{key:"_isLeapYear",value:function(t){return t%4==0&&t%100!=0||t%400==0}},{key:"_compareDates",value:function(t,e){return t.getTime()===e.getTime()}},{key:"_setToStartOfDay",value:function(t){B._isDate(t)&&t.setHours(0,0,0,0)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Datepicker}},{key:"defaults",get:function(){return e}}]),B}();t._template=['"].join(""),M.Datepicker=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"datepicker","M_Datepicker")}(cash),function(h){"use strict";var e={dialRadius:135,outerRadius:105,innerRadius:70,tickRadius:20,duration:350,container:null,defaultTime:"now",fromNow:0,showClearBtn:!1,i18n:{cancel:"Cancel",clear:"Clear",done:"Ok"},autoClose:!1,twelveHour:!0,vibrate:!0,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,onSelect:null},t=function(t){function f(t,e){_classCallCheck(this,f);var i=_possibleConstructorReturn(this,(f.__proto__||Object.getPrototypeOf(f)).call(this,f,t,e));return(i.el.M_Timepicker=i).options=h.extend({},f.defaults,e),i.id=M.guid(),i._insertHTMLIntoDOM(),i._setupModal(),i._setupVariables(),i._setupEventHandlers(),i._clockSetup(),i._pickerSetup(),i}return _inherits(f,Component),_createClass(f,[{key:"destroy",value:function(){this._removeEventHandlers(),this.modal.destroy(),h(this.modalEl).remove(),this.el.M_Timepicker=void 0}},{key:"_setupEventHandlers",value:function(){this._handleInputKeydownBound=this._handleInputKeydown.bind(this),this._handleInputClickBound=this._handleInputClick.bind(this),this._handleClockClickStartBound=this._handleClockClickStart.bind(this),this._handleDocumentClickMoveBound=this._handleDocumentClickMove.bind(this),this._handleDocumentClickEndBound=this._handleDocumentClickEnd.bind(this),this.el.addEventListener("click",this._handleInputClickBound),this.el.addEventListener("keydown",this._handleInputKeydownBound),this.plate.addEventListener("mousedown",this._handleClockClickStartBound),this.plate.addEventListener("touchstart",this._handleClockClickStartBound),h(this.spanHours).on("click",this.showView.bind(this,"hours")),h(this.spanMinutes).on("click",this.showView.bind(this,"minutes"))}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleInputClickBound),this.el.removeEventListener("keydown",this._handleInputKeydownBound)}},{key:"_handleInputClick",value:function(){this.open()}},{key:"_handleInputKeydown",value:function(t){t.which===M.keys.ENTER&&(t.preventDefault(),this.open())}},{key:"_handleClockClickStart",value:function(t){t.preventDefault();var e=this.plate.getBoundingClientRect(),i=e.left,n=e.top;this.x0=i+this.options.dialRadius,this.y0=n+this.options.dialRadius,this.moved=!1;var s=f._Pos(t);this.dx=s.x-this.x0,this.dy=s.y-this.y0,this.setHand(this.dx,this.dy,!1),document.addEventListener("mousemove",this._handleDocumentClickMoveBound),document.addEventListener("touchmove",this._handleDocumentClickMoveBound),document.addEventListener("mouseup",this._handleDocumentClickEndBound),document.addEventListener("touchend",this._handleDocumentClickEndBound)}},{key:"_handleDocumentClickMove",value:function(t){t.preventDefault();var e=f._Pos(t),i=e.x-this.x0,n=e.y-this.y0;this.moved=!0,this.setHand(i,n,!1,!0)}},{key:"_handleDocumentClickEnd",value:function(t){var e=this;t.preventDefault(),document.removeEventListener("mouseup",this._handleDocumentClickEndBound),document.removeEventListener("touchend",this._handleDocumentClickEndBound);var i=f._Pos(t),n=i.x-this.x0,s=i.y-this.y0;this.moved&&n===this.dx&&s===this.dy&&this.setHand(n,s),"hours"===this.currentView?this.showView("minutes",this.options.duration/2):this.options.autoClose&&(h(this.minutesView).addClass("timepicker-dial-out"),setTimeout(function(){e.done()},this.options.duration/2)),"function"==typeof this.options.onSelect&&this.options.onSelect.call(this,this.hours,this.minutes),document.removeEventListener("mousemove",this._handleDocumentClickMoveBound),document.removeEventListener("touchmove",this._handleDocumentClickMoveBound)}},{key:"_insertHTMLIntoDOM",value:function(){this.$modalEl=h(f._template),this.modalEl=this.$modalEl[0],this.modalEl.id="modal-"+this.id;var t=document.querySelector(this.options.container);this.options.container&&t?this.$modalEl.appendTo(t):this.$modalEl.insertBefore(this.el)}},{key:"_setupModal",value:function(){var t=this;this.modal=M.Modal.init(this.modalEl,{onOpenStart:this.options.onOpenStart,onOpenEnd:this.options.onOpenEnd,onCloseStart:this.options.onCloseStart,onCloseEnd:function(){"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t),t.isOpen=!1}})}},{key:"_setupVariables",value:function(){this.currentView="hours",this.vibrate=navigator.vibrate?"vibrate":navigator.webkitVibrate?"webkitVibrate":null,this._canvas=this.modalEl.querySelector(".timepicker-canvas"),this.plate=this.modalEl.querySelector(".timepicker-plate"),this.hoursView=this.modalEl.querySelector(".timepicker-hours"),this.minutesView=this.modalEl.querySelector(".timepicker-minutes"),this.spanHours=this.modalEl.querySelector(".timepicker-span-hours"),this.spanMinutes=this.modalEl.querySelector(".timepicker-span-minutes"),this.spanAmPm=this.modalEl.querySelector(".timepicker-span-am-pm"),this.footer=this.modalEl.querySelector(".timepicker-footer"),this.amOrPm="PM"}},{key:"_pickerSetup",value:function(){var t=h(''+this.options.i18n.clear+" ").appendTo(this.footer).on("click",this.clear.bind(this));this.options.showClearBtn&&t.css({visibility:""});var e=h('
');h(''+this.options.i18n.cancel+" ").appendTo(e).on("click",this.close.bind(this)),h(''+this.options.i18n.done+" ").appendTo(e).on("click",this.done.bind(this)),e.appendTo(this.footer)}},{key:"_clockSetup",value:function(){this.options.twelveHour&&(this.$amBtn=h('AM
'),this.$pmBtn=h('PM
'),this.$amBtn.on("click",this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm),this.$pmBtn.on("click",this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm)),this._buildHoursView(),this._buildMinutesView(),this._buildSVGClock()}},{key:"_buildSVGClock",value:function(){var t=this.options.dialRadius,e=this.options.tickRadius,i=2*t,n=f._createSVGEl("svg");n.setAttribute("class","timepicker-svg"),n.setAttribute("width",i),n.setAttribute("height",i);var s=f._createSVGEl("g");s.setAttribute("transform","translate("+t+","+t+")");var o=f._createSVGEl("circle");o.setAttribute("class","timepicker-canvas-bearing"),o.setAttribute("cx",0),o.setAttribute("cy",0),o.setAttribute("r",4);var a=f._createSVGEl("line");a.setAttribute("x1",0),a.setAttribute("y1",0);var r=f._createSVGEl("circle");r.setAttribute("class","timepicker-canvas-bg"),r.setAttribute("r",e),s.appendChild(a),s.appendChild(r),s.appendChild(o),n.appendChild(s),this._canvas.appendChild(n),this.hand=a,this.bg=r,this.bearing=o,this.g=s}},{key:"_buildHoursView",value:function(){var t=h('
');if(this.options.twelveHour)for(var e=1;e<13;e+=1){var i=t.clone(),n=e/6*Math.PI,s=this.options.outerRadius;i.css({left:this.options.dialRadius+Math.sin(n)*s-this.options.tickRadius+"px",top:this.options.dialRadius-Math.cos(n)*s-this.options.tickRadius+"px"}),i.html(0===e?"00":e),this.hoursView.appendChild(i[0])}else for(var o=0;o<24;o+=1){var a=t.clone(),r=o/6*Math.PI,l=0'),e=0;e<60;e+=5){var i=t.clone(),n=e/30*Math.PI;i.css({left:this.options.dialRadius+Math.sin(n)*this.options.outerRadius-this.options.tickRadius+"px",top:this.options.dialRadius-Math.cos(n)*this.options.outerRadius-this.options.tickRadius+"px"}),i.html(f._addLeadingZero(e)),this.minutesView.appendChild(i[0])}}},{key:"_handleAmPmClick",value:function(t){var e=h(t.target);this.amOrPm=e.hasClass("am-btn")?"AM":"PM",this._updateAmPmView()}},{key:"_updateAmPmView",value:function(){this.options.twelveHour&&(this.$amBtn.toggleClass("text-primary","AM"===this.amOrPm),this.$pmBtn.toggleClass("text-primary","PM"===this.amOrPm))}},{key:"_updateTimeFromInput",value:function(){var t=((this.el.value||this.options.defaultTime||"")+"").split(":");if(this.options.twelveHour&&void 0!==t[1]&&(0','",""].join(""),M.Timepicker=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"timepicker","M_Timepicker")}(cash),function(s){"use strict";var e={},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_CharacterCounter=i).options=s.extend({},n.defaults,e),i.isInvalid=!1,i.isValidLength=!1,i._setupCounter(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.CharacterCounter=void 0,this._removeCounter()}},{key:"_setupEventHandlers",value:function(){this._handleUpdateCounterBound=this.updateCounter.bind(this),this.el.addEventListener("focus",this._handleUpdateCounterBound,!0),this.el.addEventListener("input",this._handleUpdateCounterBound,!0)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("focus",this._handleUpdateCounterBound,!0),this.el.removeEventListener("input",this._handleUpdateCounterBound,!0)}},{key:"_setupCounter",value:function(){this.counterEl=document.createElement("span"),s(this.counterEl).addClass("character-counter").css({float:"right","font-size":"12px",height:1}),this.$el.parent().append(this.counterEl)}},{key:"_removeCounter",value:function(){s(this.counterEl).remove()}},{key:"updateCounter",value:function(){var t=+this.$el.attr("data-length"),e=this.el.value.length;this.isValidLength=e<=t;var i=e;t&&(i+="/"+t,this._validateInput()),s(this.counterEl).html(i)}},{key:"_validateInput",value:function(){this.isValidLength&&this.isInvalid?(this.isInvalid=!1,this.$el.removeClass("invalid")):this.isValidLength||this.isInvalid||(this.isInvalid=!0,this.$el.removeClass("valid"),this.$el.addClass("invalid"))}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_CharacterCounter}},{key:"defaults",get:function(){return e}}]),n}();M.CharacterCounter=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"characterCounter","M_CharacterCounter")}(cash),function(b){"use strict";var e={duration:200,dist:-100,shift:0,padding:0,numVisible:5,fullWidth:!1,indicators:!1,noWrap:!1,onCycleTo:null},t=function(t){function i(t,e){_classCallCheck(this,i);var n=_possibleConstructorReturn(this,(i.__proto__||Object.getPrototypeOf(i)).call(this,i,t,e));return(n.el.M_Carousel=n).options=b.extend({},i.defaults,e),n.hasMultipleSlides=1'),n.$el.find(".carousel-item").each(function(t,e){if(n.images.push(t),n.showIndicators){var i=b(' ');0===e&&i[0].classList.add("active"),n.$indicators.append(i)}}),n.showIndicators&&n.$el.append(n.$indicators),n.count=n.images.length,n.options.numVisible=Math.min(n.count,n.options.numVisible),n.xform="transform",["webkit","Moz","O","ms"].every(function(t){var e=t+"Transform";return void 0===document.body.style[e]||(n.xform=e,!1)}),n._setupEventHandlers(),n._scroll(n.offset),n}return _inherits(i,Component),_createClass(i,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Carousel=void 0}},{key:"_setupEventHandlers",value:function(){var i=this;this._handleCarouselTapBound=this._handleCarouselTap.bind(this),this._handleCarouselDragBound=this._handleCarouselDrag.bind(this),this._handleCarouselReleaseBound=this._handleCarouselRelease.bind(this),this._handleCarouselClickBound=this._handleCarouselClick.bind(this),void 0!==window.ontouchstart&&(this.el.addEventListener("touchstart",this._handleCarouselTapBound),this.el.addEventListener("touchmove",this._handleCarouselDragBound),this.el.addEventListener("touchend",this._handleCarouselReleaseBound)),this.el.addEventListener("mousedown",this._handleCarouselTapBound),this.el.addEventListener("mousemove",this._handleCarouselDragBound),this.el.addEventListener("mouseup",this._handleCarouselReleaseBound),this.el.addEventListener("mouseleave",this._handleCarouselReleaseBound),this.el.addEventListener("click",this._handleCarouselClickBound),this.showIndicators&&this.$indicators&&(this._handleIndicatorClickBound=this._handleIndicatorClick.bind(this),this.$indicators.find(".indicator-item").each(function(t,e){t.addEventListener("click",i._handleIndicatorClickBound)}));var t=M.throttle(this._handleResize,200);this._handleThrottledResizeBound=t.bind(this),window.addEventListener("resize",this._handleThrottledResizeBound)}},{key:"_removeEventHandlers",value:function(){var i=this;void 0!==window.ontouchstart&&(this.el.removeEventListener("touchstart",this._handleCarouselTapBound),this.el.removeEventListener("touchmove",this._handleCarouselDragBound),this.el.removeEventListener("touchend",this._handleCarouselReleaseBound)),this.el.removeEventListener("mousedown",this._handleCarouselTapBound),this.el.removeEventListener("mousemove",this._handleCarouselDragBound),this.el.removeEventListener("mouseup",this._handleCarouselReleaseBound),this.el.removeEventListener("mouseleave",this._handleCarouselReleaseBound),this.el.removeEventListener("click",this._handleCarouselClickBound),this.showIndicators&&this.$indicators&&this.$indicators.find(".indicator-item").each(function(t,e){t.removeEventListener("click",i._handleIndicatorClickBound)}),window.removeEventListener("resize",this._handleThrottledResizeBound)}},{key:"_handleCarouselTap",value:function(t){"mousedown"===t.type&&b(t.target).is("img")&&t.preventDefault(),this.pressed=!0,this.dragged=!1,this.verticalDragged=!1,this.reference=this._xpos(t),this.referenceY=this._ypos(t),this.velocity=this.amplitude=0,this.frame=this.offset,this.timestamp=Date.now(),clearInterval(this.ticker),this.ticker=setInterval(this._trackBound,100)}},{key:"_handleCarouselDrag",value:function(t){var e=void 0,i=void 0,n=void 0;if(this.pressed)if(e=this._xpos(t),i=this._ypos(t),n=this.reference-e,Math.abs(this.referenceY-i)<30&&!this.verticalDragged)(2=this.dim*(this.count-1)?this.target=this.dim*(this.count-1):this.target<0&&(this.target=0)),this.amplitude=this.target-this.offset,this.timestamp=Date.now(),requestAnimationFrame(this._autoScrollBound),this.dragged&&(t.preventDefault(),t.stopPropagation()),!1}},{key:"_handleCarouselClick",value:function(t){if(this.dragged)return t.preventDefault(),t.stopPropagation(),!1;if(!this.options.fullWidth){var e=b(t.target).closest(".carousel-item").index();0!==this._wrap(this.center)-e&&(t.preventDefault(),t.stopPropagation()),this._cycleTo(e)}}},{key:"_handleIndicatorClick",value:function(t){t.stopPropagation();var e=b(t.target).closest(".indicator-item");e.length&&this._cycleTo(e.index())}},{key:"_handleResize",value:function(t){this.options.fullWidth?(this.itemWidth=this.$el.find(".carousel-item").first().innerWidth(),this.imageHeight=this.$el.find(".carousel-item.active").height(),this.dim=2*this.itemWidth+this.options.padding,this.offset=2*this.center*this.itemWidth,this.target=this.offset,this._setCarouselHeight(!0)):this._scroll()}},{key:"_setCarouselHeight",value:function(t){var i=this,e=this.$el.find(".carousel-item.active").length?this.$el.find(".carousel-item.active").first():this.$el.find(".carousel-item").first(),n=e.find("img").first();if(n.length)if(n[0].complete){var s=n.height();if(0=this.count?t%this.count:t<0?this._wrap(this.count+t%this.count):t}},{key:"_track",value:function(){var t,e,i,n;e=(t=Date.now())-this.timestamp,this.timestamp=t,i=this.offset-this.frame,this.frame=this.offset,n=1e3*i/(1+e),this.velocity=.8*n+.2*this.velocity}},{key:"_autoScroll",value:function(){var t=void 0,e=void 0;this.amplitude&&(t=Date.now()-this.timestamp,2<(e=this.amplitude*Math.exp(-t/this.options.duration))||e<-2?(this._scroll(this.target-e),requestAnimationFrame(this._autoScrollBound)):this._scroll(this.target))}},{key:"_scroll",value:function(t){var e=this;this.$el.hasClass("scrolling")||this.el.classList.add("scrolling"),null!=this.scrollingTimeout&&window.clearTimeout(this.scrollingTimeout),this.scrollingTimeout=window.setTimeout(function(){e.$el.removeClass("scrolling")},this.options.duration);var i,n,s,o,a=void 0,r=void 0,l=void 0,h=void 0,d=void 0,u=void 0,c=this.center,p=1/this.options.numVisible;if(this.offset="number"==typeof t?t:this.offset,this.center=Math.floor((this.offset+this.dim/2)/this.dim),o=-(s=(n=this.offset-this.center*this.dim)<0?1:-1)*n*2/this.dim,i=this.count>>1,this.options.fullWidth?(l="translateX(0)",u=1):(l="translateX("+(this.el.clientWidth-this.itemWidth)/2+"px) ",l+="translateY("+(this.el.clientHeight-this.itemHeight)/2+"px)",u=1-p*o),this.showIndicators){var v=this.center%this.count,f=this.$indicators.find(".indicator-item.active");f.index()!==v&&(f.removeClass("active"),this.$indicators.find(".indicator-item").eq(v)[0].classList.add("active"))}if(!this.noWrap||0<=this.center&&this.center=this.count||e<0){if(this.noWrap)return;e=this._wrap(e)}this._cycleTo(e)}},{key:"prev",value:function(t){(void 0===t||isNaN(t))&&(t=1);var e=this.center-t;if(e>=this.count||e<0){if(this.noWrap)return;e=this._wrap(e)}this._cycleTo(e)}},{key:"set",value:function(t,e){if((void 0===t||isNaN(t))&&(t=0),t>this.count||t<0){if(this.noWrap)return;t=this._wrap(t)}this._cycleTo(t,e)}}],[{key:"init",value:function(t,e){return _get(i.__proto__||Object.getPrototypeOf(i),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Carousel}},{key:"defaults",get:function(){return e}}]),i}();M.Carousel=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"carousel","M_Carousel")}(cash),function(S){"use strict";var e={onOpen:void 0,onClose:void 0},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_TapTarget=i).options=S.extend({},n.defaults,e),i.isOpen=!1,i.$origin=S("#"+i.$el.attr("data-target")),i._setup(),i._calculatePositioning(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.TapTarget=void 0}},{key:"_setupEventHandlers",value:function(){this._handleDocumentClickBound=this._handleDocumentClick.bind(this),this._handleTargetClickBound=this._handleTargetClick.bind(this),this._handleOriginClickBound=this._handleOriginClick.bind(this),this.el.addEventListener("click",this._handleTargetClickBound),this.originEl.addEventListener("click",this._handleOriginClickBound);var t=M.throttle(this._handleResize,200);this._handleThrottledResizeBound=t.bind(this),window.addEventListener("resize",this._handleThrottledResizeBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleTargetClickBound),this.originEl.removeEventListener("click",this._handleOriginClickBound),window.removeEventListener("resize",this._handleThrottledResizeBound)}},{key:"_handleTargetClick",value:function(t){this.open()}},{key:"_handleOriginClick",value:function(t){this.close()}},{key:"_handleResize",value:function(t){this._calculatePositioning()}},{key:"_handleDocumentClick",value:function(t){S(t.target).closest(".tap-target-wrapper").length||(this.close(),t.preventDefault(),t.stopPropagation())}},{key:"_setup",value:function(){this.wrapper=this.$el.parent()[0],this.waveEl=S(this.wrapper).find(".tap-target-wave")[0],this.originEl=S(this.wrapper).find(".tap-target-origin")[0],this.contentEl=this.$el.find(".tap-target-content")[0],S(this.wrapper).hasClass(".tap-target-wrapper")||(this.wrapper=document.createElement("div"),this.wrapper.classList.add("tap-target-wrapper"),this.$el.before(S(this.wrapper)),this.wrapper.append(this.el)),this.contentEl||(this.contentEl=document.createElement("div"),this.contentEl.classList.add("tap-target-content"),this.$el.append(this.contentEl)),this.waveEl||(this.waveEl=document.createElement("div"),this.waveEl.classList.add("tap-target-wave"),this.originEl||(this.originEl=this.$origin.clone(!0,!0),this.originEl.addClass("tap-target-origin"),this.originEl.removeAttr("id"),this.originEl.removeAttr("style"),this.originEl=this.originEl[0],this.waveEl.append(this.originEl)),this.wrapper.append(this.waveEl))}},{key:"_calculatePositioning",value:function(){var t="fixed"===this.$origin.css("position");if(!t)for(var e=this.$origin.parents(),i=0;i'+t.getAttribute("label")+" ")[0]),i.each(function(t){var e=n._appendOptionWithIcon(n.$el,t,"optgroup-option");n._addOptionToValueDict(t,e)})}}),this.$el.after(this.dropdownOptions),this.input=document.createElement("input"),d(this.input).addClass("select-dropdown dropdown-trigger"),this.input.setAttribute("type","text"),this.input.setAttribute("readonly","true"),this.input.setAttribute("data-target",this.dropdownOptions.id),this.el.disabled&&d(this.input).prop("disabled","true"),this.$el.before(this.input),this._setValueToInput();var t=d(' ');if(this.$el.before(t[0]),!this.el.disabled){var e=d.extend({},this.options.dropdownOptions);e.onOpenEnd=function(t){var e=d(n.dropdownOptions).find(".selected").first();if(e.length&&(M.keyDown=!0,n.dropdown.focusedIndex=e.index(),n.dropdown._focusFocusedItem(),M.keyDown=!1,n.dropdown.isScrollable)){var i=e[0].getBoundingClientRect().top-n.dropdownOptions.getBoundingClientRect().top;i-=n.dropdownOptions.clientHeight/2,n.dropdownOptions.scrollTop=i}},this.isMultiple&&(e.closeOnClick=!1),this.dropdown=M.Dropdown.init(this.input,e)}this._setSelectedStates()}},{key:"_addOptionToValueDict",value:function(t,e){var i=Object.keys(this._valueDict).length,n=this.dropdownOptions.id+i,s={};e.id=n,s.el=t,s.optionEl=e,this._valueDict[n]=s}},{key:"_removeDropdown",value:function(){d(this.wrapper).find(".caret").remove(),d(this.input).remove(),d(this.dropdownOptions).remove(),d(this.wrapper).before(this.$el),d(this.wrapper).remove()}},{key:"_appendOptionWithIcon",value:function(t,e,i){var n=e.disabled?"disabled ":"",s="optgroup-option"===i?"optgroup-option ":"",o=this.isMultiple?''+e.innerHTML+" ":e.innerHTML,a=d(" "),r=d(" ");r.html(o),a.addClass(n+" "+s),a.append(r);var l=e.getAttribute("data-icon");if(l){var h=d(' ');a.prepend(h)}return d(this.dropdownOptions).append(a[0]),a[0]}},{key:"_toggleEntryFromArray",value:function(t){var e=!this._keysSelected.hasOwnProperty(t),i=d(this._valueDict[t].optionEl);return e?this._keysSelected[t]=!0:delete this._keysSelected[t],i.toggleClass("selected",e),i.find('input[type="checkbox"]').prop("checked",e),i.prop("selected",e),e}},{key:"_setValueToInput",value:function(){var i=[];if(this.$el.find("option").each(function(t){if(d(t).prop("selected")){var e=d(t).text();i.push(e)}}),!i.length){var t=this.$el.find("option:disabled").eq(0);t.length&&""===t[0].value&&i.push(t.text())}this.input.value=i.join(", ")}},{key:"_setSelectedStates",value:function(){for(var t in this._keysSelected={},this._valueDict){var e=this._valueDict[t],i=d(e.el).prop("selected");d(e.optionEl).find('input[type="checkbox"]').prop("checked",i),i?(this._activateOption(d(this.dropdownOptions),d(e.optionEl)),this._keysSelected[t]=!0):d(e.optionEl).removeClass("selected")}}},{key:"_activateOption",value:function(t,e){e&&(this.isMultiple||t.find("li.selected").removeClass("selected"),d(e).addClass("selected"))}},{key:"getSelectedValues",value:function(){var t=[];for(var e in this._keysSelected)t.push(this._valueDict[e].el.value);return t}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_FormSelect}},{key:"defaults",get:function(){return e}}]),n}();M.FormSelect=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"formSelect","M_FormSelect")}(cash),function(s,e){"use strict";var i={},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Range=i).options=s.extend({},n.defaults,e),i._mousedown=!1,i._setupThumb(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this._removeThumb(),this.el.M_Range=void 0}},{key:"_setupEventHandlers",value:function(){this._handleRangeChangeBound=this._handleRangeChange.bind(this),this._handleRangeMousedownTouchstartBound=this._handleRangeMousedownTouchstart.bind(this),this._handleRangeInputMousemoveTouchmoveBound=this._handleRangeInputMousemoveTouchmove.bind(this),this._handleRangeMouseupTouchendBound=this._handleRangeMouseupTouchend.bind(this),this._handleRangeBlurMouseoutTouchleaveBound=this._handleRangeBlurMouseoutTouchleave.bind(this),this.el.addEventListener("change",this._handleRangeChangeBound),this.el.addEventListener("mousedown",this._handleRangeMousedownTouchstartBound),this.el.addEventListener("touchstart",this._handleRangeMousedownTouchstartBound),this.el.addEventListener("input",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("mousemove",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("touchmove",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("mouseup",this._handleRangeMouseupTouchendBound),this.el.addEventListener("touchend",this._handleRangeMouseupTouchendBound),this.el.addEventListener("blur",this._handleRangeBlurMouseoutTouchleaveBound),this.el.addEventListener("mouseout",this._handleRangeBlurMouseoutTouchleaveBound),this.el.addEventListener("touchleave",this._handleRangeBlurMouseoutTouchleaveBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("change",this._handleRangeChangeBound),this.el.removeEventListener("mousedown",this._handleRangeMousedownTouchstartBound),this.el.removeEventListener("touchstart",this._handleRangeMousedownTouchstartBound),this.el.removeEventListener("input",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("mousemove",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("touchmove",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("mouseup",this._handleRangeMouseupTouchendBound),this.el.removeEventListener("touchend",this._handleRangeMouseupTouchendBound),this.el.removeEventListener("blur",this._handleRangeBlurMouseoutTouchleaveBound),this.el.removeEventListener("mouseout",this._handleRangeBlurMouseoutTouchleaveBound),this.el.removeEventListener("touchleave",this._handleRangeBlurMouseoutTouchleaveBound)}},{key:"_handleRangeChange",value:function(){s(this.value).html(this.$el.val()),s(this.thumb).hasClass("active")||this._showRangeBubble();var t=this._calcRangeOffset();s(this.thumb).addClass("active").css("left",t+"px")}},{key:"_handleRangeMousedownTouchstart",value:function(t){if(s(this.value).html(this.$el.val()),this._mousedown=!0,this.$el.addClass("active"),s(this.thumb).hasClass("active")||this._showRangeBubble(),"input"!==t.type){var e=this._calcRangeOffset();s(this.thumb).addClass("active").css("left",e+"px")}}},{key:"_handleRangeInputMousemoveTouchmove",value:function(){if(this._mousedown){s(this.thumb).hasClass("active")||this._showRangeBubble();var t=this._calcRangeOffset();s(this.thumb).addClass("active").css("left",t+"px"),s(this.value).html(this.$el.val())}}},{key:"_handleRangeMouseupTouchend",value:function(){this._mousedown=!1,this.$el.removeClass("active")}},{key:"_handleRangeBlurMouseoutTouchleave",value:function(){if(!this._mousedown){var t=7+parseInt(this.$el.css("padding-left"))+"px";s(this.thumb).hasClass("active")&&(e.remove(this.thumb),e({targets:this.thumb,height:0,width:0,top:10,easing:"easeOutQuad",marginLeft:t,duration:100})),s(this.thumb).removeClass("active")}}},{key:"_setupThumb",value:function(){this.thumb=document.createElement("span"),this.value=document.createElement("span"),s(this.thumb).addClass("thumb"),s(this.value).addClass("value"),s(this.thumb).append(this.value),this.$el.after(this.thumb)}},{key:"_removeThumb",value:function(){s(this.thumb).remove()}},{key:"_showRangeBubble",value:function(){var t=-7+parseInt(s(this.thumb).parent().css("padding-left"))+"px";e.remove(this.thumb),e({targets:this.thumb,height:30,width:30,top:-30,marginLeft:t,duration:300,easing:"easeOutQuint"})}},{key:"_calcRangeOffset",value:function(){var t=this.$el.width()-15,e=parseFloat(this.$el.attr("max"))||100,i=parseFloat(this.$el.attr("min"))||0;return(parseFloat(this.$el.val())-i)/(e-i)*t}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Range}},{key:"defaults",get:function(){return i}}]),n}();M.Range=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"range","M_Range"),t.init(s("input[type=range]"))}(cash,M.anime);
\ No newline at end of file
+var _get=function t(e,i,n){null===e&&(e=Function.prototype);var s=Object.getOwnPropertyDescriptor(e,i);if(void 0===s){var o=Object.getPrototypeOf(e);return null===o?void 0:t(o,i,n)}if("value"in s)return s.value;var a=s.get;return void 0!==a?a.call(n):void 0},_createClass=function(){function n(t,e){for(var i=0;i/,p=/^\w+$/;function v(t,e){e=e||o;var i=u.test(t)?e.getElementsByClassName(t.slice(1)):p.test(t)?e.getElementsByTagName(t):e.querySelectorAll(t);return i}function f(t){if(!i){var e=(i=o.implementation.createHTMLDocument(null)).createElement("base");e.href=o.location.href,i.head.appendChild(e)}return i.body.innerHTML=t,i.body.childNodes}function m(t){"loading"!==o.readyState?t():o.addEventListener("DOMContentLoaded",t)}function g(t,e){if(!t)return this;if(t.cash&&t!==a)return t;var i,n=t,s=0;if(d(t))n=l.test(t)?o.getElementById(t.slice(1)):c.test(t)?f(t):v(t,e);else if(h(t))return m(t),this;if(!n)return this;if(n.nodeType||n===a)this[0]=n,this.length=1;else for(i=this.length=n.length;ss.right-i||l+e.width>window.innerWidth-i)&&(n.right=!0),(ho-i||h+e.height>window.innerHeight-i)&&(n.bottom=!0),n},M.checkPossibleAlignments=function(t,e,i,n){var s={top:!0,right:!0,bottom:!0,left:!0,spaceOnTop:null,spaceOnRight:null,spaceOnBottom:null,spaceOnLeft:null},o="visible"===getComputedStyle(e).overflow,a=e.getBoundingClientRect(),r=Math.min(a.height,window.innerHeight),l=Math.min(a.width,window.innerWidth),h=t.getBoundingClientRect(),d=e.scrollLeft,u=e.scrollTop,c=i.left-d,p=i.top-u,v=i.top+h.height-u;return s.spaceOnRight=o?window.innerWidth-(h.left+i.width):l-(c+i.width),s.spaceOnRight<0&&(s.left=!1),s.spaceOnLeft=o?h.right-i.width:c-i.width+h.width,s.spaceOnLeft<0&&(s.right=!1),s.spaceOnBottom=o?window.innerHeight-(h.top+i.height+n):r-(p+i.height+n),s.spaceOnBottom<0&&(s.top=!1),s.spaceOnTop=o?h.bottom-(i.height+n):v-(i.height-n),s.spaceOnTop<0&&(s.bottom=!1),s},M.getOverflowParent=function(t){return null==t?null:t===document.body||"visible"!==getComputedStyle(t).overflow?t:M.getOverflowParent(t.parentElement)},M.getIdFromTrigger=function(t){var e=t.getAttribute("data-target");return e||(e=(e=t.getAttribute("href"))?e.slice(1):""),e},M.getDocumentScrollTop=function(){return window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0},M.getDocumentScrollLeft=function(){return window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0};var getTime=Date.now||function(){return(new Date).getTime()};M.throttle=function(i,n,s){var o=void 0,a=void 0,r=void 0,l=null,h=0;s||(s={});var d=function(){h=!1===s.leading?0:getTime(),l=null,r=i.apply(o,a),o=a=null};return function(){var t=getTime();h||!1!==s.leading||(h=t);var e=n-(t-h);return o=this,a=arguments,e<=0?(clearTimeout(l),l=null,h=t,r=i.apply(o,a),o=a=null):l||!1===s.trailing||(l=setTimeout(d,e)),r}};var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(t,e,i){if(i.get||i.set)throw new TypeError("ES3 does not support getters and setters.");t!=Array.prototype&&t!=Object.prototype&&(t[e]=i.value)},$jscomp.getGlobal=function(t){return"undefined"!=typeof window&&window===t?t:"undefined"!=typeof global&&null!=global?global:t},$jscomp.global=$jscomp.getGlobal(this),$jscomp.SYMBOL_PREFIX="jscomp_symbol_",$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){},$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)},$jscomp.symbolCounter_=0,$jscomp.Symbol=function(t){return $jscomp.SYMBOL_PREFIX+(t||"")+$jscomp.symbolCounter_++},$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var t=$jscomp.global.Symbol.iterator;t||(t=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator")),"function"!=typeof Array.prototype[t]&&$jscomp.defineProperty(Array.prototype,t,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}}),$jscomp.initSymbolIterator=function(){}},$jscomp.arrayIterator=function(t){var e=0;return $jscomp.iteratorPrototype(function(){return e=k.currentTime)for(var h=0;ht&&(s.duration=e.duration),s.children.push(e)}),s.seek(0),s.reset(),s.autoplay&&s.restart(),s},s},O.random=function(t,e){return Math.floor(Math.random()*(e-t+1))+t},O}(),function(r,l){"use strict";var e={accordion:!0,onOpenStart:void 0,onOpenEnd:void 0,onCloseStart:void 0,onCloseEnd:void 0,inDuration:300,outDuration:300},t=function(t){function s(t,e){_classCallCheck(this,s);var i=_possibleConstructorReturn(this,(s.__proto__||Object.getPrototypeOf(s)).call(this,s,t,e));(i.el.M_Collapsible=i).options=r.extend({},s.defaults,e),i.$headers=i.$el.children("li").children(".collapsible-header"),i.$headers.attr("tabindex",0),i._setupEventHandlers();var n=i.$el.children("li.active").children(".collapsible-body");return i.options.accordion?n.first().css("display","block"):n.css("display","block"),i}return _inherits(s,Component),_createClass(s,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Collapsible=void 0}},{key:"_setupEventHandlers",value:function(){var e=this;this._handleCollapsibleClickBound=this._handleCollapsibleClick.bind(this),this._handleCollapsibleKeydownBound=this._handleCollapsibleKeydown.bind(this),this.el.addEventListener("click",this._handleCollapsibleClickBound),this.$headers.each(function(t){t.addEventListener("keydown",e._handleCollapsibleKeydownBound)})}},{key:"_removeEventHandlers",value:function(){var e=this;this.el.removeEventListener("click",this._handleCollapsibleClickBound),this.$headers.each(function(t){t.removeEventListener("keydown",e._handleCollapsibleKeydownBound)})}},{key:"_handleCollapsibleClick",value:function(t){var e=r(t.target).closest(".collapsible-header");if(t.target&&e.length){var i=e.closest(".collapsible");if(i[0]===this.el){var n=e.closest("li"),s=i.children("li"),o=n[0].classList.contains("active"),a=s.index(n);o?this.close(a):this.open(a)}}}},{key:"_handleCollapsibleKeydown",value:function(t){13===t.keyCode&&this._handleCollapsibleClickBound(t)}},{key:"_animateIn",value:function(t){var e=this,i=this.$el.children("li").eq(t);if(i.length){var n=i.children(".collapsible-body");l.remove(n[0]),n.css({display:"block",overflow:"hidden",height:0,paddingTop:"",paddingBottom:""});var s=n.css("padding-top"),o=n.css("padding-bottom"),a=n[0].scrollHeight;n.css({paddingTop:0,paddingBottom:0}),l({targets:n[0],height:a,paddingTop:s,paddingBottom:o,duration:this.options.inDuration,easing:"easeInOutCubic",complete:function(t){n.css({overflow:"",paddingTop:"",paddingBottom:"",height:""}),"function"==typeof e.options.onOpenEnd&&e.options.onOpenEnd.call(e,i[0])}})}}},{key:"_animateOut",value:function(t){var e=this,i=this.$el.children("li").eq(t);if(i.length){var n=i.children(".collapsible-body");l.remove(n[0]),n.css("overflow","hidden"),l({targets:n[0],height:0,paddingTop:0,paddingBottom:0,duration:this.options.outDuration,easing:"easeInOutCubic",complete:function(){n.css({height:"",overflow:"",padding:"",display:""}),"function"==typeof e.options.onCloseEnd&&e.options.onCloseEnd.call(e,i[0])}})}}},{key:"open",value:function(t){var i=this,e=this.$el.children("li").eq(t);if(e.length&&!e[0].classList.contains("active")){if("function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,e[0]),this.options.accordion){var n=this.$el.children("li");this.$el.children("li.active").each(function(t){var e=n.index(r(t));i.close(e)})}e[0].classList.add("active"),this._animateIn(t)}}},{key:"close",value:function(t){var e=this.$el.children("li").eq(t);e.length&&e[0].classList.contains("active")&&("function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,e[0]),e[0].classList.remove("active"),this._animateOut(t))}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Collapsible}},{key:"defaults",get:function(){return e}}]),s}();M.Collapsible=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"collapsible","M_Collapsible")}(cash,M.anime),function(h,i){"use strict";var e={alignment:"left",autoFocus:!0,constrainWidth:!0,container:null,coverTrigger:!0,closeOnClick:!0,hover:!1,inDuration:150,outDuration:250,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,onItemClick:null},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return i.el.M_Dropdown=i,n._dropdowns.push(i),i.id=M.getIdFromTrigger(t),i.dropdownEl=document.getElementById(i.id),i.$dropdownEl=h(i.dropdownEl),i.options=h.extend({},n.defaults,e),i.isOpen=!1,i.isScrollable=!1,i.isTouchMoving=!1,i.focusedIndex=-1,i.filterQuery=[],i.options.container?h(i.options.container).append(i.dropdownEl):i.$el.after(i.dropdownEl),i._makeDropdownFocusable(),i._resetFilterQueryBound=i._resetFilterQuery.bind(i),i._handleDocumentClickBound=i._handleDocumentClick.bind(i),i._handleDocumentTouchmoveBound=i._handleDocumentTouchmove.bind(i),i._handleDropdownClickBound=i._handleDropdownClick.bind(i),i._handleDropdownKeydownBound=i._handleDropdownKeydown.bind(i),i._handleTriggerKeydownBound=i._handleTriggerKeydown.bind(i),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._resetDropdownStyles(),this._removeEventHandlers(),n._dropdowns.splice(n._dropdowns.indexOf(this),1),this.el.M_Dropdown=void 0}},{key:"_setupEventHandlers",value:function(){this.el.addEventListener("keydown",this._handleTriggerKeydownBound),this.dropdownEl.addEventListener("click",this._handleDropdownClickBound),this.options.hover?(this._handleMouseEnterBound=this._handleMouseEnter.bind(this),this.el.addEventListener("mouseenter",this._handleMouseEnterBound),this._handleMouseLeaveBound=this._handleMouseLeave.bind(this),this.el.addEventListener("mouseleave",this._handleMouseLeaveBound),this.dropdownEl.addEventListener("mouseleave",this._handleMouseLeaveBound)):(this._handleClickBound=this._handleClick.bind(this),this.el.addEventListener("click",this._handleClickBound))}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("keydown",this._handleTriggerKeydownBound),this.dropdownEl.removeEventListener("click",this._handleDropdownClickBound),this.options.hover?(this.el.removeEventListener("mouseenter",this._handleMouseEnterBound),this.el.removeEventListener("mouseleave",this._handleMouseLeaveBound),this.dropdownEl.removeEventListener("mouseleave",this._handleMouseLeaveBound)):this.el.removeEventListener("click",this._handleClickBound)}},{key:"_setupTemporaryEventHandlers",value:function(){document.body.addEventListener("click",this._handleDocumentClickBound,!0),document.body.addEventListener("touchend",this._handleDocumentClickBound),document.body.addEventListener("touchmove",this._handleDocumentTouchmoveBound),this.dropdownEl.addEventListener("keydown",this._handleDropdownKeydownBound)}},{key:"_removeTemporaryEventHandlers",value:function(){document.body.removeEventListener("click",this._handleDocumentClickBound,!0),document.body.removeEventListener("touchend",this._handleDocumentClickBound),document.body.removeEventListener("touchmove",this._handleDocumentTouchmoveBound),this.dropdownEl.removeEventListener("keydown",this._handleDropdownKeydownBound)}},{key:"_handleClick",value:function(t){t.preventDefault(),this.open()}},{key:"_handleMouseEnter",value:function(){this.open()}},{key:"_handleMouseLeave",value:function(t){var e=t.toElement||t.relatedTarget,i=!!h(e).closest(".dropdown-content").length,n=!1,s=h(e).closest(".dropdown-trigger");s.length&&s[0].M_Dropdown&&s[0].M_Dropdown.isOpen&&(n=!0),n||i||this.close()}},{key:"_handleDocumentClick",value:function(t){var e=this,i=h(t.target);this.options.closeOnClick&&i.closest(".dropdown-content").length&&!this.isTouchMoving?setTimeout(function(){e.close()},0):!i.closest(".dropdown-trigger").length&&i.closest(".dropdown-content").length||setTimeout(function(){e.close()},0),this.isTouchMoving=!1}},{key:"_handleTriggerKeydown",value:function(t){t.which!==M.keys.ARROW_DOWN&&t.which!==M.keys.ENTER||this.isOpen||(t.preventDefault(),this.open())}},{key:"_handleDocumentTouchmove",value:function(t){h(t.target).closest(".dropdown-content").length&&(this.isTouchMoving=!0)}},{key:"_handleDropdownClick",value:function(t){if("function"==typeof this.options.onItemClick){var e=h(t.target).closest("li")[0];this.options.onItemClick.call(this,e)}}},{key:"_handleDropdownKeydown",value:function(t){if(t.which===M.keys.TAB)t.preventDefault(),this.close();else if(t.which!==M.keys.ARROW_DOWN&&t.which!==M.keys.ARROW_UP||!this.isOpen)if(t.which===M.keys.ENTER&&this.isOpen){var e=this.dropdownEl.children[this.focusedIndex],i=h(e).find("a, button").first();i.length?i[0].click():e&&e.click()}else t.which===M.keys.ESC&&this.isOpen&&(t.preventDefault(),this.close());else{t.preventDefault();var n=t.which===M.keys.ARROW_DOWN?1:-1,s=this.focusedIndex,o=!1;do{if(s+=n,this.dropdownEl.children[s]&&-1!==this.dropdownEl.children[s].tabIndex){o=!0;break}}while(sl.spaceOnBottom?(h="bottom",i+=l.spaceOnTop,o-=l.spaceOnTop):i+=l.spaceOnBottom)),!l[d]){var u="left"===d?"right":"left";l[u]?d=u:l.spaceOnLeft>l.spaceOnRight?(d="right",n+=l.spaceOnLeft,s-=l.spaceOnLeft):(d="left",n+=l.spaceOnRight)}return"bottom"===h&&(o=o-e.height+(this.options.coverTrigger?t.height:0)),"right"===d&&(s=s-e.width+t.width),{x:s,y:o,verticalAlignment:h,horizontalAlignment:d,height:i,width:n}}},{key:"_animateIn",value:function(){var e=this;i.remove(this.dropdownEl),i({targets:this.dropdownEl,opacity:{value:[0,1],easing:"easeOutQuad"},scaleX:[.3,1],scaleY:[.3,1],duration:this.options.inDuration,easing:"easeOutQuint",complete:function(t){e.options.autoFocus&&e.dropdownEl.focus(),"function"==typeof e.options.onOpenEnd&&e.options.onOpenEnd.call(e,e.el)}})}},{key:"_animateOut",value:function(){var e=this;i.remove(this.dropdownEl),i({targets:this.dropdownEl,opacity:{value:0,easing:"easeOutQuint"},scaleX:.3,scaleY:.3,duration:this.options.outDuration,easing:"easeOutQuint",complete:function(t){e._resetDropdownStyles(),"function"==typeof e.options.onCloseEnd&&e.options.onCloseEnd.call(e,e.el)}})}},{key:"_placeDropdown",value:function(){var t=this.options.constrainWidth?this.el.getBoundingClientRect().width:this.dropdownEl.getBoundingClientRect().width;this.dropdownEl.style.width=t+"px";var e=this._getDropdownPosition();this.dropdownEl.style.left=e.x+"px",this.dropdownEl.style.top=e.y+"px",this.dropdownEl.style.height=e.height+"px",this.dropdownEl.style.width=e.width+"px",this.dropdownEl.style.transformOrigin=("left"===e.horizontalAlignment?"0":"100%")+" "+("top"===e.verticalAlignment?"0":"100%")}},{key:"open",value:function(){this.isOpen||(this.isOpen=!0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el),this._resetDropdownStyles(),this.dropdownEl.style.display="block",this._placeDropdown(),this._animateIn(),this._setupTemporaryEventHandlers())}},{key:"close",value:function(){this.isOpen&&(this.isOpen=!1,this.focusedIndex=-1,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),this._animateOut(),this._removeTemporaryEventHandlers(),this.options.autoFocus&&this.el.focus())}},{key:"recalculateDimensions",value:function(){this.isOpen&&(this.$dropdownEl.css({width:"",height:"",left:"",top:"","transform-origin":""}),this._placeDropdown())}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Dropdown}},{key:"defaults",get:function(){return e}}]),n}();t._dropdowns=[],M.Dropdown=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"dropdown","M_Dropdown")}(cash,M.anime),function(s,i){"use strict";var e={opacity:.5,inDuration:250,outDuration:250,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,preventScrolling:!0,dismissible:!0,startingTop:"4%",endingTop:"10%"},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Modal=i).options=s.extend({},n.defaults,e),i.isOpen=!1,i.id=i.$el.attr("id"),i._openingTrigger=void 0,i.$overlay=s('
'),i.el.tabIndex=0,i._nthModalOpened=0,n._count++,i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){n._count--,this._removeEventHandlers(),this.el.removeAttribute("style"),this.$overlay.remove(),this.el.M_Modal=void 0}},{key:"_setupEventHandlers",value:function(){this._handleOverlayClickBound=this._handleOverlayClick.bind(this),this._handleModalCloseClickBound=this._handleModalCloseClick.bind(this),1===n._count&&document.body.addEventListener("click",this._handleTriggerClick),this.$overlay[0].addEventListener("click",this._handleOverlayClickBound),this.el.addEventListener("click",this._handleModalCloseClickBound)}},{key:"_removeEventHandlers",value:function(){0===n._count&&document.body.removeEventListener("click",this._handleTriggerClick),this.$overlay[0].removeEventListener("click",this._handleOverlayClickBound),this.el.removeEventListener("click",this._handleModalCloseClickBound)}},{key:"_handleTriggerClick",value:function(t){var e=s(t.target).closest(".modal-trigger");if(e.length){var i=M.getIdFromTrigger(e[0]),n=document.getElementById(i).M_Modal;n&&n.open(e),t.preventDefault()}}},{key:"_handleOverlayClick",value:function(){this.options.dismissible&&this.close()}},{key:"_handleModalCloseClick",value:function(t){s(t.target).closest(".modal-close").length&&this.close()}},{key:"_handleKeydown",value:function(t){27===t.keyCode&&this.options.dismissible&&this.close()}},{key:"_handleFocus",value:function(t){this.el.contains(t.target)||this._nthModalOpened!==n._modalsOpen||this.el.focus()}},{key:"_animateIn",value:function(){var t=this;s.extend(this.el.style,{display:"block",opacity:0}),s.extend(this.$overlay[0].style,{display:"block",opacity:0}),i({targets:this.$overlay[0],opacity:this.options.opacity,duration:this.options.inDuration,easing:"easeOutQuad"});var e={targets:this.el,duration:this.options.inDuration,easing:"easeOutCubic",complete:function(){"function"==typeof t.options.onOpenEnd&&t.options.onOpenEnd.call(t,t.el,t._openingTrigger)}};this.el.classList.contains("bottom-sheet")?s.extend(e,{bottom:0,opacity:1}):s.extend(e,{top:[this.options.startingTop,this.options.endingTop],opacity:1,scaleX:[.8,1],scaleY:[.8,1]}),i(e)}},{key:"_animateOut",value:function(){var t=this;i({targets:this.$overlay[0],opacity:0,duration:this.options.outDuration,easing:"easeOutQuart"});var e={targets:this.el,duration:this.options.outDuration,easing:"easeOutCubic",complete:function(){t.el.style.display="none",t.$overlay.remove(),"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t,t.el)}};this.el.classList.contains("bottom-sheet")?s.extend(e,{bottom:"-100%",opacity:0}):s.extend(e,{top:[this.options.endingTop,this.options.startingTop],opacity:0,scaleX:.8,scaleY:.8}),i(e)}},{key:"open",value:function(t){if(!this.isOpen)return this.isOpen=!0,n._modalsOpen++,this._nthModalOpened=n._modalsOpen,this.$overlay[0].style.zIndex=1e3+2*n._modalsOpen,this.el.style.zIndex=1e3+2*n._modalsOpen+1,this._openingTrigger=t?t[0]:void 0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el,this._openingTrigger),this.options.preventScrolling&&(document.body.style.overflow="hidden"),this.el.classList.add("open"),this.el.insertAdjacentElement("afterend",this.$overlay[0]),this.options.dismissible&&(this._handleKeydownBound=this._handleKeydown.bind(this),this._handleFocusBound=this._handleFocus.bind(this),document.addEventListener("keydown",this._handleKeydownBound),document.addEventListener("focus",this._handleFocusBound,!0)),i.remove(this.el),i.remove(this.$overlay[0]),this._animateIn(),this.el.focus(),this}},{key:"close",value:function(){if(this.isOpen)return this.isOpen=!1,n._modalsOpen--,this._nthModalOpened=0,"function"==typeof this.options.onCloseStart&&this.options.onCloseStart.call(this,this.el),this.el.classList.remove("open"),0===n._modalsOpen&&(document.body.style.overflow=""),this.options.dismissible&&(document.removeEventListener("keydown",this._handleKeydownBound),document.removeEventListener("focus",this._handleFocusBound,!0)),i.remove(this.el),i.remove(this.$overlay[0]),this._animateOut(),this}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Modal}},{key:"defaults",get:function(){return e}}]),n}();t._modalsOpen=0,t._count=0,M.Modal=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"modal","M_Modal")}(cash,M.anime),function(o,a){"use strict";var e={inDuration:275,outDuration:200,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Materialbox=i).options=o.extend({},n.defaults,e),i.overlayActive=!1,i.doneAnimating=!0,i.placeholder=o("
").addClass("material-placeholder"),i.originalWidth=0,i.originalHeight=0,i.originInlineStyles=i.$el.attr("style"),i.caption=i.el.getAttribute("data-caption")||"",i.$el.before(i.placeholder),i.placeholder.append(i.$el),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Materialbox=void 0,o(this.placeholder).after(this.el).remove(),this.$el.removeAttr("style")}},{key:"_setupEventHandlers",value:function(){this._handleMaterialboxClickBound=this._handleMaterialboxClick.bind(this),this.el.addEventListener("click",this._handleMaterialboxClickBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleMaterialboxClickBound)}},{key:"_handleMaterialboxClick",value:function(t){!1===this.doneAnimating||this.overlayActive&&this.doneAnimating?this.close():this.open()}},{key:"_handleWindowScroll",value:function(){this.overlayActive&&this.close()}},{key:"_handleWindowResize",value:function(){this.overlayActive&&this.close()}},{key:"_handleWindowEscape",value:function(t){27===t.keyCode&&this.doneAnimating&&this.overlayActive&&this.close()}},{key:"_makeAncestorsOverflowVisible",value:function(){this.ancestorsChanged=o();for(var t=this.placeholder[0].parentNode;null!==t&&!o(t).is(document);){var e=o(t);"visible"!==e.css("overflow")&&(e.css("overflow","visible"),void 0===this.ancestorsChanged?this.ancestorsChanged=e:this.ancestorsChanged=this.ancestorsChanged.add(e)),t=t.parentNode}}},{key:"_animateImageIn",value:function(){var t=this,e={targets:this.el,height:[this.originalHeight,this.newHeight],width:[this.originalWidth,this.newWidth],left:M.getDocumentScrollLeft()+this.windowWidth/2-this.placeholder.offset().left-this.newWidth/2,top:M.getDocumentScrollTop()+this.windowHeight/2-this.placeholder.offset().top-this.newHeight/2,duration:this.options.inDuration,easing:"easeOutQuad",complete:function(){t.doneAnimating=!0,"function"==typeof t.options.onOpenEnd&&t.options.onOpenEnd.call(t,t.el)}};this.maxWidth=this.$el.css("max-width"),this.maxHeight=this.$el.css("max-height"),"none"!==this.maxWidth&&(e.maxWidth=this.newWidth),"none"!==this.maxHeight&&(e.maxHeight=this.newHeight),a(e)}},{key:"_animateImageOut",value:function(){var t=this,e={targets:this.el,width:this.originalWidth,height:this.originalHeight,left:0,top:0,duration:this.options.outDuration,easing:"easeOutQuad",complete:function(){t.placeholder.css({height:"",width:"",position:"",top:"",left:""}),t.attrWidth&&t.$el.attr("width",t.attrWidth),t.attrHeight&&t.$el.attr("height",t.attrHeight),t.$el.removeAttr("style"),t.originInlineStyles&&t.$el.attr("style",t.originInlineStyles),t.$el.removeClass("active"),t.doneAnimating=!0,t.ancestorsChanged.length&&t.ancestorsChanged.css("overflow",""),"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t,t.el)}};a(e)}},{key:"_updateVars",value:function(){this.windowWidth=window.innerWidth,this.windowHeight=window.innerHeight,this.caption=this.el.getAttribute("data-caption")||""}},{key:"open",value:function(){var t=this;this._updateVars(),this.originalWidth=this.el.getBoundingClientRect().width,this.originalHeight=this.el.getBoundingClientRect().height,this.doneAnimating=!1,this.$el.addClass("active"),this.overlayActive=!0,"function"==typeof this.options.onOpenStart&&this.options.onOpenStart.call(this,this.el),this.placeholder.css({width:this.placeholder[0].getBoundingClientRect().width+"px",height:this.placeholder[0].getBoundingClientRect().height+"px",position:"relative",top:0,left:0}),this._makeAncestorsOverflowVisible(),this.$el.css({position:"absolute","z-index":1e3,"will-change":"left, top, width, height"}),this.attrWidth=this.$el.attr("width"),this.attrHeight=this.$el.attr("height"),this.attrWidth&&(this.$el.css("width",this.attrWidth+"px"),this.$el.removeAttr("width")),this.attrHeight&&(this.$el.css("width",this.attrHeight+"px"),this.$el.removeAttr("height")),this.$overlay=o('
').css({opacity:0}).one("click",function(){t.doneAnimating&&t.close()}),this.$el.before(this.$overlay);var e=this.$overlay[0].getBoundingClientRect();this.$overlay.css({width:this.windowWidth+"px",height:this.windowHeight+"px",left:-1*e.left+"px",top:-1*e.top+"px"}),a.remove(this.el),a.remove(this.$overlay[0]),a({targets:this.$overlay[0],opacity:1,duration:this.options.inDuration,easing:"easeOutQuad"}),""!==this.caption&&(this.$photocaption&&a.remove(this.$photoCaption[0]),this.$photoCaption=o('
'),this.$photoCaption.text(this.caption),o("body").append(this.$photoCaption),this.$photoCaption.css({display:"inline"}),a({targets:this.$photoCaption[0],opacity:1,duration:this.options.inDuration,easing:"easeOutQuad"}));var i=0,n=this.originalWidth/this.windowWidth,s=this.originalHeight/this.windowHeight;this.newWidth=0,this.newHeight=0,si.options.responsiveThreshold,i.$img=i.$el.find("img").first(),i.$img.each(function(){this.complete&&s(this).trigger("load")}),i._updateParallax(),i._setupEventHandlers(),i._setupStyles(),n._parallaxes.push(i),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){n._parallaxes.splice(n._parallaxes.indexOf(this),1),this.$img[0].style.transform="",this._removeEventHandlers(),this.$el[0].M_Parallax=void 0}},{key:"_setupEventHandlers",value:function(){this._handleImageLoadBound=this._handleImageLoad.bind(this),this.$img[0].addEventListener("load",this._handleImageLoadBound),0===n._parallaxes.length&&(n._handleScrollThrottled=M.throttle(n._handleScroll,5),window.addEventListener("scroll",n._handleScrollThrottled),n._handleWindowResizeThrottled=M.throttle(n._handleWindowResize,5),window.addEventListener("resize",n._handleWindowResizeThrottled))}},{key:"_removeEventHandlers",value:function(){this.$img[0].removeEventListener("load",this._handleImageLoadBound),0===n._parallaxes.length&&(window.removeEventListener("scroll",n._handleScrollThrottled),window.removeEventListener("resize",n._handleWindowResizeThrottled))}},{key:"_setupStyles",value:function(){this.$img[0].style.opacity=1}},{key:"_handleImageLoad",value:function(){this._updateParallax()}},{key:"_updateParallax",value:function(){var t=0e.options.responsiveThreshold}}},{key:"defaults",get:function(){return e}}]),n}();t._parallaxes=[],M.Parallax=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"parallax","M_Parallax")}(cash),function(a,s){"use strict";var e={duration:300,onShow:null,swipeable:!1,responsiveThreshold:1/0},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Tabs=i).options=a.extend({},n.defaults,e),i.$tabLinks=i.$el.children("li.tab").children("a"),i.index=0,i._setupActiveTabLink(),i.options.swipeable?i._setupSwipeableTabs():i._setupNormalTabs(),i._setTabsAndTabWidth(),i._createIndicator(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this._indicator.parentNode.removeChild(this._indicator),this.options.swipeable?this._teardownSwipeableTabs():this._teardownNormalTabs(),this.$el[0].M_Tabs=void 0}},{key:"_setupEventHandlers",value:function(){this._handleWindowResizeBound=this._handleWindowResize.bind(this),window.addEventListener("resize",this._handleWindowResizeBound),this._handleTabClickBound=this._handleTabClick.bind(this),this.el.addEventListener("click",this._handleTabClickBound)}},{key:"_removeEventHandlers",value:function(){window.removeEventListener("resize",this._handleWindowResizeBound),this.el.removeEventListener("click",this._handleTabClickBound)}},{key:"_handleWindowResize",value:function(){this._setTabsAndTabWidth(),0!==this.tabWidth&&0!==this.tabsWidth&&(this._indicator.style.left=this._calcLeftPos(this.$activeTabLink)+"px",this._indicator.style.right=this._calcRightPos(this.$activeTabLink)+"px")}},{key:"_handleTabClick",value:function(t){var e=this,i=a(t.target).closest("li.tab"),n=a(t.target).closest("a");if(n.length&&n.parent().hasClass("tab"))if(i.hasClass("disabled"))t.preventDefault();else if(!n.attr("target")){this.$activeTabLink.removeClass("active");var s=this.$content;this.$activeTabLink=n,this.$content=a(M.escapeHash(n[0].hash)),this.$tabLinks=this.$el.children("li.tab").children("a"),this.$activeTabLink.addClass("active");var o=this.index;this.index=Math.max(this.$tabLinks.index(n),0),this.options.swipeable?this._tabsCarousel&&this._tabsCarousel.set(this.index,function(){"function"==typeof e.options.onShow&&e.options.onShow.call(e,e.$content[0])}):this.$content.length&&(this.$content[0].style.display="block",this.$content.addClass("active"),"function"==typeof this.options.onShow&&this.options.onShow.call(this,this.$content[0]),s.length&&!s.is(this.$content)&&(s[0].style.display="none",s.removeClass("active"))),this._setTabsAndTabWidth(),this._animateIndicator(o),t.preventDefault()}}},{key:"_createIndicator",value:function(){var t=this,e=document.createElement("li");e.classList.add("indicator"),this.el.appendChild(e),this._indicator=e,setTimeout(function(){t._indicator.style.left=t._calcLeftPos(t.$activeTabLink)+"px",t._indicator.style.right=t._calcRightPos(t.$activeTabLink)+"px"},0)}},{key:"_setupActiveTabLink",value:function(){this.$activeTabLink=a(this.$tabLinks.filter('[href="'+location.hash+'"]')),0===this.$activeTabLink.length&&(this.$activeTabLink=this.$el.children("li.tab").children("a.active").first()),0===this.$activeTabLink.length&&(this.$activeTabLink=this.$el.children("li.tab").children("a").first()),this.$tabLinks.removeClass("active"),this.$activeTabLink[0].classList.add("active"),this.index=Math.max(this.$tabLinks.index(this.$activeTabLink),0),this.$activeTabLink.length&&(this.$content=a(M.escapeHash(this.$activeTabLink[0].hash)),this.$content.addClass("active"))}},{key:"_setupSwipeableTabs",value:function(){var i=this;window.innerWidth>this.options.responsiveThreshold&&(this.options.swipeable=!1);var n=a();this.$tabLinks.each(function(t){var e=a(M.escapeHash(t.hash));e.addClass("carousel-item"),n=n.add(e)});var t=a('
');n.first().before(t),t.append(n),n[0].style.display="";var e=this.$activeTabLink.closest(".tab").index();this._tabsCarousel=M.Carousel.init(t[0],{fullWidth:!0,noWrap:!0,onCycleTo:function(t){var e=i.index;i.index=a(t).index(),i.$activeTabLink.removeClass("active"),i.$activeTabLink=i.$tabLinks.eq(i.index),i.$activeTabLink.addClass("active"),i._animateIndicator(e),"function"==typeof i.options.onShow&&i.options.onShow.call(i,i.$content[0])}}),this._tabsCarousel.set(e)}},{key:"_teardownSwipeableTabs",value:function(){var t=this._tabsCarousel.$el;this._tabsCarousel.destroy(),t.after(t.children()),t.remove()}},{key:"_setupNormalTabs",value:function(){this.$tabLinks.not(this.$activeTabLink).each(function(t){if(t.hash){var e=a(M.escapeHash(t.hash));e.length&&(e[0].style.display="none")}})}},{key:"_teardownNormalTabs",value:function(){this.$tabLinks.each(function(t){if(t.hash){var e=a(M.escapeHash(t.hash));e.length&&(e[0].style.display="")}})}},{key:"_setTabsAndTabWidth",value:function(){this.tabsWidth=this.$el.width(),this.tabWidth=Math.max(this.tabsWidth,this.el.scrollWidth)/this.$tabLinks.length}},{key:"_calcRightPos",value:function(t){return Math.ceil(this.tabsWidth-t.position().left-t[0].getBoundingClientRect().width)}},{key:"_calcLeftPos",value:function(t){return Math.floor(t.position().left)}},{key:"updateTabIndicator",value:function(){this._setTabsAndTabWidth(),this._animateIndicator(this.index)}},{key:"_animateIndicator",value:function(t){var e=0,i=0;0<=this.index-t?e=90:i=90;var n={targets:this._indicator,left:{value:this._calcLeftPos(this.$activeTabLink),delay:e},right:{value:this._calcRightPos(this.$activeTabLink),delay:i},duration:this.options.duration,easing:"easeOutQuad"};s.remove(this._indicator),s(n)}},{key:"select",value:function(t){var e=this.$tabLinks.filter('[href="#'+t+'"]');e.length&&e.trigger("click")}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Tabs}},{key:"defaults",get:function(){return e}}]),n}();M.Tabs=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"tabs","M_Tabs")}(cash,M.anime),function(d,e){"use strict";var i={exitDelay:200,enterDelay:0,html:null,margin:5,inDuration:250,outDuration:200,position:"bottom",transitionMovement:10},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Tooltip=i).options=d.extend({},n.defaults,e),i.isOpen=!1,i.isHovered=!1,i.isFocused=!1,i._appendTooltipEl(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){d(this.tooltipEl).remove(),this._removeEventHandlers(),this.el.M_Tooltip=void 0}},{key:"_appendTooltipEl",value:function(){var t=document.createElement("div");t.classList.add("material-tooltip"),this.tooltipEl=t;var e=document.createElement("div");e.classList.add("tooltip-content"),e.innerHTML=this.options.html,t.appendChild(e),document.body.appendChild(t)}},{key:"_updateTooltipContent",value:function(){this.tooltipEl.querySelector(".tooltip-content").innerHTML=this.options.html}},{key:"_setupEventHandlers",value:function(){this._handleMouseEnterBound=this._handleMouseEnter.bind(this),this._handleMouseLeaveBound=this._handleMouseLeave.bind(this),this._handleFocusBound=this._handleFocus.bind(this),this._handleBlurBound=this._handleBlur.bind(this),this.el.addEventListener("mouseenter",this._handleMouseEnterBound),this.el.addEventListener("mouseleave",this._handleMouseLeaveBound),this.el.addEventListener("focus",this._handleFocusBound,!0),this.el.addEventListener("blur",this._handleBlurBound,!0)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("mouseenter",this._handleMouseEnterBound),this.el.removeEventListener("mouseleave",this._handleMouseLeaveBound),this.el.removeEventListener("focus",this._handleFocusBound,!0),this.el.removeEventListener("blur",this._handleBlurBound,!0)}},{key:"open",value:function(t){this.isOpen||(t=void 0===t||void 0,this.isOpen=!0,this.options=d.extend({},this.options,this._getAttributeOptions()),this._updateTooltipContent(),this._setEnterDelayTimeout(t))}},{key:"close",value:function(){this.isOpen&&(this.isHovered=!1,this.isFocused=!1,this.isOpen=!1,this._setExitDelayTimeout())}},{key:"_setExitDelayTimeout",value:function(){var t=this;clearTimeout(this._exitDelayTimeout),this._exitDelayTimeout=setTimeout(function(){t.isHovered||t.isFocused||t._animateOut()},this.options.exitDelay)}},{key:"_setEnterDelayTimeout",value:function(t){var e=this;clearTimeout(this._enterDelayTimeout),this._enterDelayTimeout=setTimeout(function(){(e.isHovered||e.isFocused||t)&&e._animateIn()},this.options.enterDelay)}},{key:"_positionTooltip",value:function(){var t,e=this.el,i=this.tooltipEl,n=e.offsetHeight,s=e.offsetWidth,o=i.offsetHeight,a=i.offsetWidth,r=this.options.margin,l=void 0,h=void 0;this.xMovement=0,this.yMovement=0,l=e.getBoundingClientRect().top+M.getDocumentScrollTop(),h=e.getBoundingClientRect().left+M.getDocumentScrollLeft(),"top"===this.options.position?(l+=-o-r,h+=s/2-a/2,this.yMovement=-this.options.transitionMovement):"right"===this.options.position?(l+=n/2-o/2,h+=s+r,this.xMovement=this.options.transitionMovement):"left"===this.options.position?(l+=n/2-o/2,h+=-a-r,this.xMovement=-this.options.transitionMovement):(l+=n+r,h+=s/2-a/2,this.yMovement=this.options.transitionMovement),t=this._repositionWithinScreen(h,l,a,o),d(i).css({top:t.y+"px",left:t.x+"px"})}},{key:"_repositionWithinScreen",value:function(t,e,i,n){var s=M.getDocumentScrollLeft(),o=M.getDocumentScrollTop(),a=t-s,r=e-o,l={left:a,top:r,width:i,height:n},h=this.options.margin+this.options.transitionMovement,d=M.checkWithinContainer(document.body,l,h);return d.left?a=h:d.right&&(a-=a+i-window.innerWidth),d.top?r=h:d.bottom&&(r-=r+n-window.innerHeight),{x:a+s,y:r+o}}},{key:"_animateIn",value:function(){this._positionTooltip(),this.tooltipEl.style.visibility="visible",e.remove(this.tooltipEl),e({targets:this.tooltipEl,opacity:1,translateX:this.xMovement,translateY:this.yMovement,duration:this.options.inDuration,easing:"easeOutCubic"})}},{key:"_animateOut",value:function(){e.remove(this.tooltipEl),e({targets:this.tooltipEl,opacity:0,translateX:0,translateY:0,duration:this.options.outDuration,easing:"easeOutCubic"})}},{key:"_handleMouseEnter",value:function(){this.isHovered=!0,this.isFocused=!1,this.open(!1)}},{key:"_handleMouseLeave",value:function(){this.isHovered=!1,this.isFocused=!1,this.close()}},{key:"_handleFocus",value:function(){M.tabPressed&&(this.isFocused=!0,this.open(!1))}},{key:"_handleBlur",value:function(){this.isFocused=!1,this.close()}},{key:"_getAttributeOptions",value:function(){var t={},e=this.el.getAttribute("data-tooltip"),i=this.el.getAttribute("data-position");return e&&(t.html=e),i&&(t.position=i),t}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Tooltip}},{key:"defaults",get:function(){return i}}]),n}();M.Tooltip=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"tooltip","M_Tooltip")}(cash,M.anime),function(i){"use strict";var t=t||{},e=document.querySelectorAll.bind(document);function m(t){var e="";for(var i in t)t.hasOwnProperty(i)&&(e+=i+":"+t[i]+";");return e}var g={duration:750,show:function(t,e){if(2===t.button)return!1;var i=e||this,n=document.createElement("div");n.className="waves-ripple",i.appendChild(n);var s,o,a,r,l,h,d,u=(h={top:0,left:0},d=(s=i)&&s.ownerDocument,o=d.documentElement,void 0!==s.getBoundingClientRect&&(h=s.getBoundingClientRect()),a=null!==(l=r=d)&&l===l.window?r:9===r.nodeType&&r.defaultView,{top:h.top+a.pageYOffset-o.clientTop,left:h.left+a.pageXOffset-o.clientLeft}),c=t.pageY-u.top,p=t.pageX-u.left,v="scale("+i.clientWidth/100*10+")";"touches"in t&&(c=t.touches[0].pageY-u.top,p=t.touches[0].pageX-u.left),n.setAttribute("data-hold",Date.now()),n.setAttribute("data-scale",v),n.setAttribute("data-x",p),n.setAttribute("data-y",c);var f={top:c+"px",left:p+"px"};n.className=n.className+" waves-notransition",n.setAttribute("style",m(f)),n.className=n.className.replace("waves-notransition",""),f["-webkit-transform"]=v,f["-moz-transform"]=v,f["-ms-transform"]=v,f["-o-transform"]=v,f.transform=v,f.opacity="1",f["-webkit-transition-duration"]=g.duration+"ms",f["-moz-transition-duration"]=g.duration+"ms",f["-o-transition-duration"]=g.duration+"ms",f["transition-duration"]=g.duration+"ms",f["-webkit-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f["-moz-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f["-o-transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",f["transition-timing-function"]="cubic-bezier(0.250, 0.460, 0.450, 0.940)",n.setAttribute("style",m(f))},hide:function(t){l.touchup(t);var e=this,i=(e.clientWidth,null),n=e.getElementsByClassName("waves-ripple");if(!(0i||1"+o+""+a+" "+r+""),i.length&&e.prepend(i)}},{key:"_resetCurrentElement",value:function(){this.activeIndex=-1,this.$active.removeClass("active")}},{key:"_resetAutocomplete",value:function(){h(this.container).empty(),this._resetCurrentElement(),this.oldVal=null,this.isOpen=!1,this._mousedown=!1}},{key:"selectOption",value:function(t){var e=t.text().trim();this.el.value=e,this.$el.trigger("change"),this._resetAutocomplete(),this.close(),"function"==typeof this.options.onAutocomplete&&this.options.onAutocomplete.call(this,e)}},{key:"_renderDropdown",value:function(t,i){var n=this;this._resetAutocomplete();var e=[];for(var s in t)if(t.hasOwnProperty(s)&&-1!==s.toLowerCase().indexOf(i)){if(this.count>=this.options.limit)break;var o={data:t[s],key:s};e.push(o),this.count++}if(this.options.sortFunction){e.sort(function(t,e){return n.options.sortFunction(t.key.toLowerCase(),e.key.toLowerCase(),i.toLowerCase())})}for(var a=0;a");r.data?l.append(''+r.key+" "):l.append(""+r.key+" "),h(this.container).append(l),this._highlight(i,l)}}},{key:"open",value:function(){var t=this.el.value.toLowerCase();this._resetAutocomplete(),t.length>=this.options.minLength&&(this.isOpen=!0,this._renderDropdown(this.options.data,t)),this.dropdown.isOpen?this.dropdown.recalculateDimensions():this.dropdown.open()}},{key:"close",value:function(){this.dropdown.close()}},{key:"updateData",value:function(t){var e=this.el.value.toLowerCase();this.options.data=t,this.isOpen&&this._renderDropdown(t,e)}}],[{key:"init",value:function(t,e){return _get(s.__proto__||Object.getPrototypeOf(s),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Autocomplete}},{key:"defaults",get:function(){return e}}]),s}();t._keydown=!1,M.Autocomplete=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"autocomplete","M_Autocomplete")}(cash),function(d){M.updateTextFields=function(){d("input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], input[type=date], input[type=time], textarea").each(function(t,e){var i=d(this);0'),d("body").append(e));var i=t.css("font-family"),n=t.css("font-size"),s=t.css("line-height"),o=t.css("padding-top"),a=t.css("padding-right"),r=t.css("padding-bottom"),l=t.css("padding-left");n&&e.css("font-size",n),i&&e.css("font-family",i),s&&e.css("line-height",s),o&&e.css("padding-top",o),a&&e.css("padding-right",a),r&&e.css("padding-bottom",r),l&&e.css("padding-left",l),t.data("original-height")||t.data("original-height",t.height()),"off"===t.attr("wrap")&&e.css("overflow-wrap","normal").css("white-space","pre"),e.text(t[0].value+"\n");var h=e.html().replace(/\n/g," ");e.html(h),0'),this.$slides.each(function(t,e){var i=s(' ');n.$indicators.append(i[0])}),this.$el.append(this.$indicators[0]),this.$indicators=this.$indicators.children("li.indicator-item"))}},{key:"_removeIndicators",value:function(){this.$el.find("ul.indicators").remove()}},{key:"set",value:function(t){var e=this;if(t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.activeIndex!=t){this.$active=this.$slides.eq(this.activeIndex);var i=this.$active.find(".caption");this.$active.removeClass("active"),o({targets:this.$active[0],opacity:0,duration:this.options.duration,easing:"easeOutQuad",complete:function(){e.$slides.not(".active").each(function(t){o({targets:t,opacity:0,translateX:0,translateY:0,duration:0,easing:"easeOutQuad"})})}}),this._animateCaptionIn(i[0],this.options.duration),this.options.indicators&&(this.$indicators.eq(this.activeIndex).removeClass("active"),this.$indicators.eq(t).addClass("active")),o({targets:this.$slides.eq(t)[0],opacity:1,duration:this.options.duration,easing:"easeOutQuad"}),o({targets:this.$slides.eq(t).find(".caption")[0],opacity:1,translateX:0,translateY:0,duration:this.options.duration,delay:this.options.duration,easing:"easeOutQuad"}),this.$slides.eq(t).addClass("active"),this.activeIndex=t,this.start()}}},{key:"pause",value:function(){clearInterval(this.interval)}},{key:"start",value:function(){clearInterval(this.interval),this.interval=setInterval(this._handleIntervalBound,this.options.duration+this.options.interval)}},{key:"next",value:function(){var t=this.activeIndex+1;t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.set(t)}},{key:"prev",value:function(){var t=this.activeIndex-1;t>=this.$slides.length?t=0:t<0&&(t=this.$slides.length-1),this.set(t)}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Slider}},{key:"defaults",get:function(){return e}}]),n}();M.Slider=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"slider","M_Slider")}(cash,M.anime),function(n,s){n(document).on("click",".card",function(t){if(n(this).children(".card-reveal").length){var i=n(t.target).closest(".card");void 0===i.data("initialOverflow")&&i.data("initialOverflow",void 0===i.css("overflow")?"":i.css("overflow"));var e=n(this).find(".card-reveal");n(t.target).is(n(".card-reveal .card-title"))||n(t.target).is(n(".card-reveal .card-title i"))?s({targets:e[0],translateY:0,duration:225,easing:"easeInOutQuad",complete:function(t){var e=t.animatables[0].target;n(e).css({display:"none"}),i.css("overflow",i.data("initialOverflow"))}}):(n(t.target).is(n(".card .activator"))||n(t.target).is(n(".card .activator i")))&&(i.css("overflow","hidden"),e.css({display:"block"}),s({targets:e[0],translateY:"-100%",duration:300,easing:"easeInOutQuad"}))}})}(cash,M.anime),function(h){"use strict";var e={data:[],placeholder:"",secondaryPlaceholder:"",autocompleteOptions:{},limit:1/0,onChipAdd:null,onChipSelect:null,onChipDelete:null},t=function(t){function l(t,e){_classCallCheck(this,l);var i=_possibleConstructorReturn(this,(l.__proto__||Object.getPrototypeOf(l)).call(this,l,t,e));return(i.el.M_Chips=i).options=h.extend({},l.defaults,e),i.$el.addClass("chips input-field"),i.chipsData=[],i.$chips=h(),i._setupInput(),i.hasAutocomplete=0"),this.$el.append(this.$input)),this.$input.addClass("input")}},{key:"_setupLabel",value:function(){this.$label=this.$el.find("label"),this.$label.length&&this.$label.setAttribute("for",this.$input.attr("id"))}},{key:"_setPlaceholder",value:function(){void 0!==this.chipsData&&!this.chipsData.length&&this.options.placeholder?h(this.$input).prop("placeholder",this.options.placeholder):(void 0===this.chipsData||this.chipsData.length)&&this.options.secondaryPlaceholder&&h(this.$input).prop("placeholder",this.options.secondaryPlaceholder)}},{key:"_isValid",value:function(t){if(t.hasOwnProperty("tag")&&""!==t.tag){for(var e=!1,i=0;i=this.options.limit)){var e=this._renderChip(t);this.$chips.add(e),this.chipsData.push(t),h(this.$input).before(e),this._setPlaceholder(),"function"==typeof this.options.onChipAdd&&this.options.onChipAdd.call(this,this.$el,e)}}},{key:"deleteChip",value:function(t){var e=this.$chips.eq(t);this.$chips.eq(t).remove(),this.$chips=this.$chips.filter(function(t){return 0<=h(t).index()}),this.chipsData.splice(t,1),this._setPlaceholder(),"function"==typeof this.options.onChipDelete&&this.options.onChipDelete.call(this,this.$el,e[0])}},{key:"selectChip",value:function(t){var e=this.$chips.eq(t);(this._selectedChip=e)[0].focus(),"function"==typeof this.options.onChipSelect&&this.options.onChipSelect.call(this,this.$el,e[0])}}],[{key:"init",value:function(t,e){return _get(l.__proto__||Object.getPrototypeOf(l),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Chips}},{key:"_handleChipsKeydown",value:function(t){l._keydown=!0;var e=h(t.target).closest(".chips"),i=t.target&&e.length;if(!h(t.target).is("input, textarea")&&i){var n=e[0].M_Chips;if(8===t.keyCode||46===t.keyCode){t.preventDefault();var s=n.chipsData.length;if(n._selectedChip){var o=n._selectedChip.index();n.deleteChip(o),n._selectedChip=null,s=Math.max(o-1,0)}n.chipsData.length&&n.selectChip(s)}else if(37===t.keyCode){if(n._selectedChip){var a=n._selectedChip.index()-1;if(a<0)return;n.selectChip(a)}}else if(39===t.keyCode&&n._selectedChip){var r=n._selectedChip.index()+1;r>=n.chipsData.length?n.$input[0].focus():n.selectChip(r)}}}},{key:"_handleChipsKeyup",value:function(t){l._keydown=!1}},{key:"_handleChipsBlur",value:function(t){l._keydown||(h(t.target).closest(".chips")[0].M_Chips._selectedChip=null)}},{key:"defaults",get:function(){return e}}]),l}();t._keydown=!1,M.Chips=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"chips","M_Chips"),h(document).ready(function(){h(document.body).on("click",".chip .close",function(){var t=h(this).closest(".chips");t.length&&t[0].M_Chips||h(this).closest(".chip").remove()})})}(cash),function(s){"use strict";var e={top:0,bottom:1/0,offset:0,onPositionChange:null},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Pushpin=i).options=s.extend({},n.defaults,e),i.originalOffset=i.el.offsetTop,n._pushpins.push(i),i._setupEventHandlers(),i._updatePosition(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this.el.style.top=null,this._removePinClasses(),this._removeEventHandlers();var t=n._pushpins.indexOf(this);n._pushpins.splice(t,1)}},{key:"_setupEventHandlers",value:function(){document.addEventListener("scroll",n._updateElements)}},{key:"_removeEventHandlers",value:function(){document.removeEventListener("scroll",n._updateElements)}},{key:"_updatePosition",value:function(){var t=M.getDocumentScrollTop()+this.options.offset;this.options.top<=t&&this.options.bottom>=t&&!this.el.classList.contains("pinned")&&(this._removePinClasses(),this.el.style.top=this.options.offset+"px",this.el.classList.add("pinned"),"function"==typeof this.options.onPositionChange&&this.options.onPositionChange.call(this,"pinned")),tthis.options.bottom&&!this.el.classList.contains("pin-bottom")&&(this._removePinClasses(),this.el.classList.add("pin-bottom"),this.el.style.top=this.options.bottom-this.originalOffset+"px","function"==typeof this.options.onPositionChange&&this.options.onPositionChange.call(this,"pin-bottom"))}},{key:"_removePinClasses",value:function(){this.el.classList.remove("pin-top"),this.el.classList.remove("pinned"),this.el.classList.remove("pin-bottom")}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Pushpin}},{key:"_updateElements",value:function(){for(var t in n._pushpins){n._pushpins[t]._updatePosition()}}},{key:"defaults",get:function(){return e}}]),n}();t._pushpins=[],M.Pushpin=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"pushpin","M_Pushpin")}(cash),function(r,s){"use strict";var e={direction:"top",hoverEnabled:!0,toolbarEnabled:!1};r.fn.reverse=[].reverse;var t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_FloatingActionButton=i).options=r.extend({},n.defaults,e),i.isOpen=!1,i.$anchor=i.$el.children("a").first(),i.$menu=i.$el.children("ul").first(),i.$floatingBtns=i.$el.find("ul .btn-floating"),i.$floatingBtnsReverse=i.$el.find("ul .btn-floating").reverse(),i.offsetY=0,i.offsetX=0,i.$el.addClass("direction-"+i.options.direction),"top"===i.options.direction?i.offsetY=40:"right"===i.options.direction?i.offsetX=-40:"bottom"===i.options.direction?i.offsetY=-40:i.offsetX=40,i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_FloatingActionButton=void 0}},{key:"_setupEventHandlers",value:function(){this._handleFABClickBound=this._handleFABClick.bind(this),this._handleOpenBound=this.open.bind(this),this._handleCloseBound=this.close.bind(this),this.options.hoverEnabled&&!this.options.toolbarEnabled?(this.el.addEventListener("mouseenter",this._handleOpenBound),this.el.addEventListener("mouseleave",this._handleCloseBound)):this.el.addEventListener("click",this._handleFABClickBound)}},{key:"_removeEventHandlers",value:function(){this.options.hoverEnabled&&!this.options.toolbarEnabled?(this.el.removeEventListener("mouseenter",this._handleOpenBound),this.el.removeEventListener("mouseleave",this._handleCloseBound)):this.el.removeEventListener("click",this._handleFABClickBound)}},{key:"_handleFABClick",value:function(){this.isOpen?this.close():this.open()}},{key:"_handleDocumentClick",value:function(t){r(t.target).closest(this.$menu).length||this.close()}},{key:"open",value:function(){this.isOpen||(this.options.toolbarEnabled?this._animateInToolbar():this._animateInFAB(),this.isOpen=!0)}},{key:"close",value:function(){this.isOpen&&(this.options.toolbarEnabled?(window.removeEventListener("scroll",this._handleCloseBound,!0),document.body.removeEventListener("click",this._handleDocumentClickBound,!0),this._animateOutToolbar()):this._animateOutFAB(),this.isOpen=!1)}},{key:"_animateInFAB",value:function(){var e=this;this.$el.addClass("active");var i=0;this.$floatingBtnsReverse.each(function(t){s({targets:t,opacity:1,scale:[.4,1],translateY:[e.offsetY,0],translateX:[e.offsetX,0],duration:275,delay:i,easing:"easeInOutQuad"}),i+=40})}},{key:"_animateOutFAB",value:function(){var e=this;this.$floatingBtnsReverse.each(function(t){s.remove(t),s({targets:t,opacity:0,scale:.4,translateY:e.offsetY,translateX:e.offsetX,duration:175,easing:"easeOutQuad",complete:function(){e.$el.removeClass("active")}})})}},{key:"_animateInToolbar",value:function(){var t,e=this,i=window.innerWidth,n=window.innerHeight,s=this.el.getBoundingClientRect(),o=r('
'),a=this.$anchor.css("background-color");this.$anchor.append(o),this.offsetX=s.left-i/2+s.width/2,this.offsetY=n-s.bottom,t=i/o[0].clientWidth,this.btnBottom=s.bottom,this.btnLeft=s.left,this.btnWidth=s.width,this.$el.addClass("active"),this.$el.css({"text-align":"center",width:"100%",bottom:0,left:0,transform:"translateX("+this.offsetX+"px)",transition:"none"}),this.$anchor.css({transform:"translateY("+-this.offsetY+"px)",transition:"none"}),o.css({"background-color":a}),setTimeout(function(){e.$el.css({transform:"",transition:"transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s"}),e.$anchor.css({overflow:"visible",transform:"",transition:"transform .2s"}),setTimeout(function(){e.$el.css({overflow:"hidden","background-color":a}),o.css({transform:"scale("+t+")",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"}),e.$menu.children("li").children("a").css({opacity:1}),e._handleDocumentClickBound=e._handleDocumentClick.bind(e),window.addEventListener("scroll",e._handleCloseBound,!0),document.body.addEventListener("click",e._handleDocumentClickBound,!0)},100)},0)}},{key:"_animateOutToolbar",value:function(){var t=this,e=window.innerWidth,i=window.innerHeight,n=this.$el.find(".fab-backdrop"),s=this.$anchor.css("background-color");this.offsetX=this.btnLeft-e/2+this.btnWidth/2,this.offsetY=i-this.btnBottom,this.$el.removeClass("active"),this.$el.css({"background-color":"transparent",transition:"none"}),this.$anchor.css({transition:"none"}),n.css({transform:"scale(0)","background-color":s}),this.$menu.children("li").children("a").css({opacity:""}),setTimeout(function(){n.remove(),t.$el.css({"text-align":"",width:"",bottom:"",left:"",overflow:"","background-color":"",transform:"translate3d("+-t.offsetX+"px,0,0)"}),t.$anchor.css({overflow:"",transform:"translate3d(0,"+t.offsetY+"px,0)"}),setTimeout(function(){t.$el.css({transform:"translate3d(0,0,0)",transition:"transform .2s"}),t.$anchor.css({transform:"translate3d(0,0,0)",transition:"transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)"})},20)},200)}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_FloatingActionButton}},{key:"defaults",get:function(){return e}}]),n}();M.FloatingActionButton=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"floatingActionButton","M_FloatingActionButton")}(cash,M.anime),function(g){"use strict";var e={autoClose:!1,format:"mmm dd, yyyy",parse:null,defaultDate:null,setDefaultDate:!1,disableWeekends:!1,disableDayFn:null,firstDay:0,minDate:null,maxDate:null,yearRange:10,minYear:0,maxYear:9999,minMonth:void 0,maxMonth:void 0,startRange:null,endRange:null,isRTL:!1,showMonthAfterYear:!1,showDaysInNextAndPreviousMonths:!1,container:null,showClearBtn:!1,i18n:{cancel:"Cancel",clear:"Clear",done:"Ok",previousMonth:"‹",nextMonth:"›",months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdays:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],weekdaysAbbrev:["S","M","T","W","T","F","S"]},events:[],onSelect:null,onOpen:null,onClose:null,onDraw:null},t=function(t){function B(t,e){_classCallCheck(this,B);var i=_possibleConstructorReturn(this,(B.__proto__||Object.getPrototypeOf(B)).call(this,B,t,e));(i.el.M_Datepicker=i).options=g.extend({},B.defaults,e),e&&e.hasOwnProperty("i18n")&&"object"==typeof e.i18n&&(i.options.i18n=g.extend({},B.defaults.i18n,e.i18n)),i.options.minDate&&i.options.minDate.setHours(0,0,0,0),i.options.maxDate&&i.options.maxDate.setHours(0,0,0,0),i.id=M.guid(),i._setupVariables(),i._insertHTMLIntoDOM(),i._setupModal(),i._setupEventHandlers(),i.options.defaultDate||(i.options.defaultDate=new Date(Date.parse(i.el.value)));var n=i.options.defaultDate;return B._isDate(n)?i.options.setDefaultDate?(i.setDate(n,!0),i.setInputValue()):i.gotoDate(n):i.gotoDate(new Date),i.isOpen=!1,i}return _inherits(B,Component),_createClass(B,[{key:"destroy",value:function(){this._removeEventHandlers(),this.modal.destroy(),g(this.modalEl).remove(),this.destroySelects(),this.el.M_Datepicker=void 0}},{key:"destroySelects",value:function(){var t=this.calendarEl.querySelector(".orig-select-year");t&&M.FormSelect.getInstance(t).destroy();var e=this.calendarEl.querySelector(".orig-select-month");e&&M.FormSelect.getInstance(e).destroy()}},{key:"_insertHTMLIntoDOM",value:function(){this.options.showClearBtn&&(g(this.clearBtn).css({visibility:""}),this.clearBtn.innerHTML=this.options.i18n.clear),this.doneBtn.innerHTML=this.options.i18n.done,this.cancelBtn.innerHTML=this.options.i18n.cancel,this.options.container?this.$modalEl.appendTo(this.options.container):this.$modalEl.insertBefore(this.el)}},{key:"_setupModal",value:function(){var t=this;this.modalEl.id="modal-"+this.id,this.modal=M.Modal.init(this.modalEl,{onCloseEnd:function(){t.isOpen=!1}})}},{key:"toString",value:function(t){var e=this;return t=t||this.options.format,B._isDate(this.date)?t.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g).map(function(t){return e.formats[t]?e.formats[t]():t}).join(""):""}},{key:"setDate",value:function(t,e){if(!t)return this.date=null,this._renderDateDisplay(),this.draw();if("string"==typeof t&&(t=new Date(Date.parse(t))),B._isDate(t)){var i=this.options.minDate,n=this.options.maxDate;B._isDate(i)&&tn.maxDate||n.disableWeekends&&B._isWeekend(y)||n.disableDayFn&&n.disableDayFn(y),isEmpty:C,isStartRange:x,isEndRange:L,isInRange:T,showDaysInNextAndPreviousMonths:n.showDaysInNextAndPreviousMonths};l.push(this.renderDay($)),7==++_&&(r.push(this.renderRow(l,n.isRTL,m)),_=0,m=!(l=[]))}return this.renderTable(n,r,i)}},{key:"renderDay",value:function(t){var e=[],i="false";if(t.isEmpty){if(!t.showDaysInNextAndPreviousMonths)return' ';e.push("is-outside-current-month"),e.push("is-selection-disabled")}return t.isDisabled&&e.push("is-disabled"),t.isToday&&e.push("is-today"),t.isSelected&&(e.push("is-selected"),i="true"),t.hasEvent&&e.push("has-event"),t.isInRange&&e.push("is-inrange"),t.isStartRange&&e.push("is-startrange"),t.isEndRange&&e.push("is-endrange"),''+t.day+" "}},{key:"renderRow",value:function(t,e,i){return''+(e?t.reverse():t).join("")+" "}},{key:"renderTable",value:function(t,e,i){return''+this.renderHead(t)+this.renderBody(e)+"
"}},{key:"renderHead",value:function(t){var e=void 0,i=[];for(e=0;e<7;e++)i.push(''+this.renderDayName(t,e,!0)+" ");return""+(t.isRTL?i.reverse():i).join("")+" "}},{key:"renderBody",value:function(t){return""+t.join("")+" "}},{key:"renderTitle",value:function(t,e,i,n,s,o){var a,r,l=void 0,h=void 0,d=void 0,u=this.options,c=i===u.minYear,p=i===u.maxYear,v='',f=!0,m=!0;for(d=[],l=0;l<12;l++)d.push('
u.maxMonth?'disabled="disabled"':"")+">"+u.i18n.months[l]+" ");for(a='
'+d.join("")+" ",g.isArray(u.yearRange)?(l=u.yearRange[0],h=u.yearRange[1]+1):(l=i-u.yearRange,h=1+i+u.yearRange),d=[];l
=u.minYear&&d.push('"+l+" ");r=''+d.join("")+" ";v+=' ',v+='',u.showMonthAfterYear?v+=r+a:v+=a+r,v+="
",c&&(0===n||u.minMonth>=n)&&(f=!1),p&&(11===n||u.maxMonth<=n)&&(m=!1);return(v+=' ')+" "}},{key:"draw",value:function(t){if(this.isOpen||t){var e,i=this.options,n=i.minYear,s=i.maxYear,o=i.minMonth,a=i.maxMonth,r="";this._y<=n&&(this._y=n,!isNaN(o)&&this._m=s&&(this._y=s,!isNaN(a)&&this._m>a&&(this._m=a)),e="datepicker-title-"+Math.random().toString(36).replace(/[^a-z]+/g,"").substr(0,2);for(var l=0;l<1;l++)this._renderDateDisplay(),r+=this.renderTitle(this,l,this.calendars[l].year,this.calendars[l].month,this.calendars[0].year,e)+this.render(this.calendars[l].year,this.calendars[l].month,e);this.destroySelects(),this.calendarEl.innerHTML=r;var h=this.calendarEl.querySelector(".orig-select-year"),d=this.calendarEl.querySelector(".orig-select-month");M.FormSelect.init(h,{classes:"select-year",dropdownOptions:{container:document.body,constrainWidth:!1}}),M.FormSelect.init(d,{classes:"select-month",dropdownOptions:{container:document.body,constrainWidth:!1}}),h.addEventListener("change",this._handleYearChange.bind(this)),d.addEventListener("change",this._handleMonthChange.bind(this)),"function"==typeof this.options.onDraw&&this.options.onDraw(this)}}},{key:"_setupEventHandlers",value:function(){this._handleInputKeydownBound=this._handleInputKeydown.bind(this),this._handleInputClickBound=this._handleInputClick.bind(this),this._handleInputChangeBound=this._handleInputChange.bind(this),this._handleCalendarClickBound=this._handleCalendarClick.bind(this),this._finishSelectionBound=this._finishSelection.bind(this),this._handleMonthChange=this._handleMonthChange.bind(this),this._closeBound=this.close.bind(this),this.el.addEventListener("click",this._handleInputClickBound),this.el.addEventListener("keydown",this._handleInputKeydownBound),this.el.addEventListener("change",this._handleInputChangeBound),this.calendarEl.addEventListener("click",this._handleCalendarClickBound),this.doneBtn.addEventListener("click",this._finishSelectionBound),this.cancelBtn.addEventListener("click",this._closeBound),this.options.showClearBtn&&(this._handleClearClickBound=this._handleClearClick.bind(this),this.clearBtn.addEventListener("click",this._handleClearClickBound))}},{key:"_setupVariables",value:function(){var e=this;this.$modalEl=g(B._template),this.modalEl=this.$modalEl[0],this.calendarEl=this.modalEl.querySelector(".datepicker-calendar"),this.yearTextEl=this.modalEl.querySelector(".year-text"),this.dateTextEl=this.modalEl.querySelector(".date-text"),this.options.showClearBtn&&(this.clearBtn=this.modalEl.querySelector(".datepicker-clear")),this.doneBtn=this.modalEl.querySelector(".datepicker-done"),this.cancelBtn=this.modalEl.querySelector(".datepicker-cancel"),this.formats={d:function(){return e.date.getDate()},dd:function(){var t=e.date.getDate();return(t<10?"0":"")+t},ddd:function(){return e.options.i18n.weekdaysShort[e.date.getDay()]},dddd:function(){return e.options.i18n.weekdays[e.date.getDay()]},m:function(){return e.date.getMonth()+1},mm:function(){var t=e.date.getMonth()+1;return(t<10?"0":"")+t},mmm:function(){return e.options.i18n.monthsShort[e.date.getMonth()]},mmmm:function(){return e.options.i18n.months[e.date.getMonth()]},yy:function(){return(""+e.date.getFullYear()).slice(2)},yyyy:function(){return e.date.getFullYear()}}}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleInputClickBound),this.el.removeEventListener("keydown",this._handleInputKeydownBound),this.el.removeEventListener("change",this._handleInputChangeBound),this.calendarEl.removeEventListener("click",this._handleCalendarClickBound)}},{key:"_handleInputClick",value:function(){this.open()}},{key:"_handleInputKeydown",value:function(t){t.which===M.keys.ENTER&&(t.preventDefault(),this.open())}},{key:"_handleCalendarClick",value:function(t){if(this.isOpen){var e=g(t.target);e.hasClass("is-disabled")||(!e.hasClass("datepicker-day-button")||e.hasClass("is-empty")||e.parent().hasClass("is-disabled")?e.closest(".month-prev").length?this.prevMonth():e.closest(".month-next").length&&this.nextMonth():(this.setDate(new Date(t.target.getAttribute("data-year"),t.target.getAttribute("data-month"),t.target.getAttribute("data-day"))),this.options.autoClose&&this._finishSelection()))}}},{key:"_handleClearClick",value:function(){this.date=null,this.setInputValue(),this.close()}},{key:"_handleMonthChange",value:function(t){this.gotoMonth(t.target.value)}},{key:"_handleYearChange",value:function(t){this.gotoYear(t.target.value)}},{key:"gotoMonth",value:function(t){isNaN(t)||(this.calendars[0].month=parseInt(t,10),this.adjustCalendars())}},{key:"gotoYear",value:function(t){isNaN(t)||(this.calendars[0].year=parseInt(t,10),this.adjustCalendars())}},{key:"_handleInputChange",value:function(t){var e=void 0;t.firedBy!==this&&(e=this.options.parse?this.options.parse(this.el.value,this.options.format):new Date(Date.parse(this.el.value)),B._isDate(e)&&this.setDate(e))}},{key:"renderDayName",value:function(t,e,i){for(e+=t.firstDay;7<=e;)e-=7;return i?t.i18n.weekdaysAbbrev[e]:t.i18n.weekdays[e]}},{key:"_finishSelection",value:function(){this.setInputValue(),this.close()}},{key:"open",value:function(){if(!this.isOpen)return this.isOpen=!0,"function"==typeof this.options.onOpen&&this.options.onOpen.call(this),this.draw(),this.modal.open(),this}},{key:"close",value:function(){if(this.isOpen)return this.isOpen=!1,"function"==typeof this.options.onClose&&this.options.onClose.call(this),this.modal.close(),this}}],[{key:"init",value:function(t,e){return _get(B.__proto__||Object.getPrototypeOf(B),"init",this).call(this,this,t,e)}},{key:"_isDate",value:function(t){return/Date/.test(Object.prototype.toString.call(t))&&!isNaN(t.getTime())}},{key:"_isWeekend",value:function(t){var e=t.getDay();return 0===e||6===e}},{key:"_setToStartOfDay",value:function(t){B._isDate(t)&&t.setHours(0,0,0,0)}},{key:"_getDaysInMonth",value:function(t,e){return[31,B._isLeapYear(t)?29:28,31,30,31,30,31,31,30,31,30,31][e]}},{key:"_isLeapYear",value:function(t){return t%4==0&&t%100!=0||t%400==0}},{key:"_compareDates",value:function(t,e){return t.getTime()===e.getTime()}},{key:"_setToStartOfDay",value:function(t){B._isDate(t)&&t.setHours(0,0,0,0)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Datepicker}},{key:"defaults",get:function(){return e}}]),B}();t._template=['"].join(""),M.Datepicker=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"datepicker","M_Datepicker")}(cash),function(h){"use strict";var e={dialRadius:135,outerRadius:105,innerRadius:70,tickRadius:20,duration:350,container:null,defaultTime:"now",fromNow:0,showClearBtn:!1,i18n:{cancel:"Cancel",clear:"Clear",done:"Ok"},autoClose:!1,twelveHour:!0,vibrate:!0,onOpenStart:null,onOpenEnd:null,onCloseStart:null,onCloseEnd:null,onSelect:null},t=function(t){function f(t,e){_classCallCheck(this,f);var i=_possibleConstructorReturn(this,(f.__proto__||Object.getPrototypeOf(f)).call(this,f,t,e));return(i.el.M_Timepicker=i).options=h.extend({},f.defaults,e),i.id=M.guid(),i._insertHTMLIntoDOM(),i._setupModal(),i._setupVariables(),i._setupEventHandlers(),i._clockSetup(),i._pickerSetup(),i}return _inherits(f,Component),_createClass(f,[{key:"destroy",value:function(){this._removeEventHandlers(),this.modal.destroy(),h(this.modalEl).remove(),this.el.M_Timepicker=void 0}},{key:"_setupEventHandlers",value:function(){this._handleInputKeydownBound=this._handleInputKeydown.bind(this),this._handleInputClickBound=this._handleInputClick.bind(this),this._handleClockClickStartBound=this._handleClockClickStart.bind(this),this._handleDocumentClickMoveBound=this._handleDocumentClickMove.bind(this),this._handleDocumentClickEndBound=this._handleDocumentClickEnd.bind(this),this.el.addEventListener("click",this._handleInputClickBound),this.el.addEventListener("keydown",this._handleInputKeydownBound),this.plate.addEventListener("mousedown",this._handleClockClickStartBound),this.plate.addEventListener("touchstart",this._handleClockClickStartBound),h(this.spanHours).on("click",this.showView.bind(this,"hours")),h(this.spanMinutes).on("click",this.showView.bind(this,"minutes"))}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleInputClickBound),this.el.removeEventListener("keydown",this._handleInputKeydownBound)}},{key:"_handleInputClick",value:function(){this.open()}},{key:"_handleInputKeydown",value:function(t){t.which===M.keys.ENTER&&(t.preventDefault(),this.open())}},{key:"_handleClockClickStart",value:function(t){t.preventDefault();var e=this.plate.getBoundingClientRect(),i=e.left,n=e.top;this.x0=i+this.options.dialRadius,this.y0=n+this.options.dialRadius,this.moved=!1;var s=f._Pos(t);this.dx=s.x-this.x0,this.dy=s.y-this.y0,this.setHand(this.dx,this.dy,!1),document.addEventListener("mousemove",this._handleDocumentClickMoveBound),document.addEventListener("touchmove",this._handleDocumentClickMoveBound),document.addEventListener("mouseup",this._handleDocumentClickEndBound),document.addEventListener("touchend",this._handleDocumentClickEndBound)}},{key:"_handleDocumentClickMove",value:function(t){t.preventDefault();var e=f._Pos(t),i=e.x-this.x0,n=e.y-this.y0;this.moved=!0,this.setHand(i,n,!1,!0)}},{key:"_handleDocumentClickEnd",value:function(t){var e=this;t.preventDefault(),document.removeEventListener("mouseup",this._handleDocumentClickEndBound),document.removeEventListener("touchend",this._handleDocumentClickEndBound);var i=f._Pos(t),n=i.x-this.x0,s=i.y-this.y0;this.moved&&n===this.dx&&s===this.dy&&this.setHand(n,s),"hours"===this.currentView?this.showView("minutes",this.options.duration/2):this.options.autoClose&&(h(this.minutesView).addClass("timepicker-dial-out"),setTimeout(function(){e.done()},this.options.duration/2)),"function"==typeof this.options.onSelect&&this.options.onSelect.call(this,this.hours,this.minutes),document.removeEventListener("mousemove",this._handleDocumentClickMoveBound),document.removeEventListener("touchmove",this._handleDocumentClickMoveBound)}},{key:"_insertHTMLIntoDOM",value:function(){this.$modalEl=h(f._template),this.modalEl=this.$modalEl[0],this.modalEl.id="modal-"+this.id;var t=document.querySelector(this.options.container);this.options.container&&t?this.$modalEl.appendTo(t):this.$modalEl.insertBefore(this.el)}},{key:"_setupModal",value:function(){var t=this;this.modal=M.Modal.init(this.modalEl,{onOpenStart:this.options.onOpenStart,onOpenEnd:this.options.onOpenEnd,onCloseStart:this.options.onCloseStart,onCloseEnd:function(){"function"==typeof t.options.onCloseEnd&&t.options.onCloseEnd.call(t),t.isOpen=!1}})}},{key:"_setupVariables",value:function(){this.currentView="hours",this.vibrate=navigator.vibrate?"vibrate":navigator.webkitVibrate?"webkitVibrate":null,this._canvas=this.modalEl.querySelector(".timepicker-canvas"),this.plate=this.modalEl.querySelector(".timepicker-plate"),this.hoursView=this.modalEl.querySelector(".timepicker-hours"),this.minutesView=this.modalEl.querySelector(".timepicker-minutes"),this.spanHours=this.modalEl.querySelector(".timepicker-span-hours"),this.spanMinutes=this.modalEl.querySelector(".timepicker-span-minutes"),this.spanAmPm=this.modalEl.querySelector(".timepicker-span-am-pm"),this.footer=this.modalEl.querySelector(".timepicker-footer"),this.amOrPm="PM"}},{key:"_pickerSetup",value:function(){var t=h(''+this.options.i18n.clear+" ").appendTo(this.footer).on("click",this.clear.bind(this));this.options.showClearBtn&&t.css({visibility:""});var e=h('
');h(''+this.options.i18n.cancel+" ").appendTo(e).on("click",this.close.bind(this)),h(''+this.options.i18n.done+" ").appendTo(e).on("click",this.done.bind(this)),e.appendTo(this.footer)}},{key:"_clockSetup",value:function(){this.options.twelveHour&&(this.$amBtn=h('AM
'),this.$pmBtn=h('PM
'),this.$amBtn.on("click",this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm),this.$pmBtn.on("click",this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm)),this._buildHoursView(),this._buildMinutesView(),this._buildSVGClock()}},{key:"_buildSVGClock",value:function(){var t=this.options.dialRadius,e=this.options.tickRadius,i=2*t,n=f._createSVGEl("svg");n.setAttribute("class","timepicker-svg"),n.setAttribute("width",i),n.setAttribute("height",i);var s=f._createSVGEl("g");s.setAttribute("transform","translate("+t+","+t+")");var o=f._createSVGEl("circle");o.setAttribute("class","timepicker-canvas-bearing"),o.setAttribute("cx",0),o.setAttribute("cy",0),o.setAttribute("r",4);var a=f._createSVGEl("line");a.setAttribute("x1",0),a.setAttribute("y1",0);var r=f._createSVGEl("circle");r.setAttribute("class","timepicker-canvas-bg"),r.setAttribute("r",e),s.appendChild(a),s.appendChild(r),s.appendChild(o),n.appendChild(s),this._canvas.appendChild(n),this.hand=a,this.bg=r,this.bearing=o,this.g=s}},{key:"_buildHoursView",value:function(){var t=h('
');if(this.options.twelveHour)for(var e=1;e<13;e+=1){var i=t.clone(),n=e/6*Math.PI,s=this.options.outerRadius;i.css({left:this.options.dialRadius+Math.sin(n)*s-this.options.tickRadius+"px",top:this.options.dialRadius-Math.cos(n)*s-this.options.tickRadius+"px"}),i.html(0===e?"00":e),this.hoursView.appendChild(i[0])}else for(var o=0;o<24;o+=1){var a=t.clone(),r=o/6*Math.PI,l=0'),e=0;e<60;e+=5){var i=t.clone(),n=e/30*Math.PI;i.css({left:this.options.dialRadius+Math.sin(n)*this.options.outerRadius-this.options.tickRadius+"px",top:this.options.dialRadius-Math.cos(n)*this.options.outerRadius-this.options.tickRadius+"px"}),i.html(f._addLeadingZero(e)),this.minutesView.appendChild(i[0])}}},{key:"_handleAmPmClick",value:function(t){var e=h(t.target);this.amOrPm=e.hasClass("am-btn")?"AM":"PM",this._updateAmPmView()}},{key:"_updateAmPmView",value:function(){this.options.twelveHour&&(this.$amBtn.toggleClass("text-primary","AM"===this.amOrPm),this.$pmBtn.toggleClass("text-primary","PM"===this.amOrPm))}},{key:"_updateTimeFromInput",value:function(){var t=((this.el.value||this.options.defaultTime||"")+"").split(":");if(this.options.twelveHour&&void 0!==t[1]&&(0','",""].join(""),M.Timepicker=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"timepicker","M_Timepicker")}(cash),function(s){"use strict";var e={},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_CharacterCounter=i).options=s.extend({},n.defaults,e),i.isInvalid=!1,i.isValidLength=!1,i._setupCounter(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.CharacterCounter=void 0,this._removeCounter()}},{key:"_setupEventHandlers",value:function(){this._handleUpdateCounterBound=this.updateCounter.bind(this),this.el.addEventListener("focus",this._handleUpdateCounterBound,!0),this.el.addEventListener("input",this._handleUpdateCounterBound,!0)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("focus",this._handleUpdateCounterBound,!0),this.el.removeEventListener("input",this._handleUpdateCounterBound,!0)}},{key:"_setupCounter",value:function(){this.counterEl=document.createElement("span"),s(this.counterEl).addClass("character-counter").css({float:"right","font-size":"12px",height:1}),this.$el.parent().append(this.counterEl)}},{key:"_removeCounter",value:function(){s(this.counterEl).remove()}},{key:"updateCounter",value:function(){var t=+this.$el.attr("data-length"),e=this.el.value.length;this.isValidLength=e<=t;var i=e;t&&(i+="/"+t,this._validateInput()),s(this.counterEl).html(i)}},{key:"_validateInput",value:function(){this.isValidLength&&this.isInvalid?(this.isInvalid=!1,this.$el.removeClass("invalid")):this.isValidLength||this.isInvalid||(this.isInvalid=!0,this.$el.removeClass("valid"),this.$el.addClass("invalid"))}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_CharacterCounter}},{key:"defaults",get:function(){return e}}]),n}();M.CharacterCounter=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"characterCounter","M_CharacterCounter")}(cash),function(b){"use strict";var e={duration:200,dist:-100,shift:0,padding:0,numVisible:5,fullWidth:!1,indicators:!1,noWrap:!1,onCycleTo:null},t=function(t){function i(t,e){_classCallCheck(this,i);var n=_possibleConstructorReturn(this,(i.__proto__||Object.getPrototypeOf(i)).call(this,i,t,e));return(n.el.M_Carousel=n).options=b.extend({},i.defaults,e),n.hasMultipleSlides=1'),n.$el.find(".carousel-item").each(function(t,e){if(n.images.push(t),n.showIndicators){var i=b(' ');0===e&&i[0].classList.add("active"),n.$indicators.append(i)}}),n.showIndicators&&n.$el.append(n.$indicators),n.count=n.images.length,n.options.numVisible=Math.min(n.count,n.options.numVisible),n.xform="transform",["webkit","Moz","O","ms"].every(function(t){var e=t+"Transform";return void 0===document.body.style[e]||(n.xform=e,!1)}),n._setupEventHandlers(),n._scroll(n.offset),n}return _inherits(i,Component),_createClass(i,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.M_Carousel=void 0}},{key:"_setupEventHandlers",value:function(){var i=this;this._handleCarouselTapBound=this._handleCarouselTap.bind(this),this._handleCarouselDragBound=this._handleCarouselDrag.bind(this),this._handleCarouselReleaseBound=this._handleCarouselRelease.bind(this),this._handleCarouselClickBound=this._handleCarouselClick.bind(this),void 0!==window.ontouchstart&&(this.el.addEventListener("touchstart",this._handleCarouselTapBound),this.el.addEventListener("touchmove",this._handleCarouselDragBound),this.el.addEventListener("touchend",this._handleCarouselReleaseBound)),this.el.addEventListener("mousedown",this._handleCarouselTapBound),this.el.addEventListener("mousemove",this._handleCarouselDragBound),this.el.addEventListener("mouseup",this._handleCarouselReleaseBound),this.el.addEventListener("mouseleave",this._handleCarouselReleaseBound),this.el.addEventListener("click",this._handleCarouselClickBound),this.showIndicators&&this.$indicators&&(this._handleIndicatorClickBound=this._handleIndicatorClick.bind(this),this.$indicators.find(".indicator-item").each(function(t,e){t.addEventListener("click",i._handleIndicatorClickBound)}));var t=M.throttle(this._handleResize,200);this._handleThrottledResizeBound=t.bind(this),window.addEventListener("resize",this._handleThrottledResizeBound)}},{key:"_removeEventHandlers",value:function(){var i=this;void 0!==window.ontouchstart&&(this.el.removeEventListener("touchstart",this._handleCarouselTapBound),this.el.removeEventListener("touchmove",this._handleCarouselDragBound),this.el.removeEventListener("touchend",this._handleCarouselReleaseBound)),this.el.removeEventListener("mousedown",this._handleCarouselTapBound),this.el.removeEventListener("mousemove",this._handleCarouselDragBound),this.el.removeEventListener("mouseup",this._handleCarouselReleaseBound),this.el.removeEventListener("mouseleave",this._handleCarouselReleaseBound),this.el.removeEventListener("click",this._handleCarouselClickBound),this.showIndicators&&this.$indicators&&this.$indicators.find(".indicator-item").each(function(t,e){t.removeEventListener("click",i._handleIndicatorClickBound)}),window.removeEventListener("resize",this._handleThrottledResizeBound)}},{key:"_handleCarouselTap",value:function(t){"mousedown"===t.type&&b(t.target).is("img")&&t.preventDefault(),this.pressed=!0,this.dragged=!1,this.verticalDragged=!1,this.reference=this._xpos(t),this.referenceY=this._ypos(t),this.velocity=this.amplitude=0,this.frame=this.offset,this.timestamp=Date.now(),clearInterval(this.ticker),this.ticker=setInterval(this._trackBound,100)}},{key:"_handleCarouselDrag",value:function(t){var e=void 0,i=void 0,n=void 0;if(this.pressed)if(e=this._xpos(t),i=this._ypos(t),n=this.reference-e,Math.abs(this.referenceY-i)<30&&!this.verticalDragged)(2=this.dim*(this.count-1)?this.target=this.dim*(this.count-1):this.target<0&&(this.target=0)),this.amplitude=this.target-this.offset,this.timestamp=Date.now(),requestAnimationFrame(this._autoScrollBound),this.dragged&&(t.preventDefault(),t.stopPropagation()),!1}},{key:"_handleCarouselClick",value:function(t){if(this.dragged)return t.preventDefault(),t.stopPropagation(),!1;if(!this.options.fullWidth){var e=b(t.target).closest(".carousel-item").index();0!==this._wrap(this.center)-e&&(t.preventDefault(),t.stopPropagation()),this._cycleTo(e)}}},{key:"_handleIndicatorClick",value:function(t){t.stopPropagation();var e=b(t.target).closest(".indicator-item");e.length&&this._cycleTo(e.index())}},{key:"_handleResize",value:function(t){this.options.fullWidth?(this.itemWidth=this.$el.find(".carousel-item").first().innerWidth(),this.imageHeight=this.$el.find(".carousel-item.active").height(),this.dim=2*this.itemWidth+this.options.padding,this.offset=2*this.center*this.itemWidth,this.target=this.offset,this._setCarouselHeight(!0)):this._scroll()}},{key:"_setCarouselHeight",value:function(t){var i=this,e=this.$el.find(".carousel-item.active").length?this.$el.find(".carousel-item.active").first():this.$el.find(".carousel-item").first(),n=e.find("img").first();if(n.length)if(n[0].complete){var s=n.height();if(0=this.count?t%this.count:t<0?this._wrap(this.count+t%this.count):t}},{key:"_track",value:function(){var t,e,i,n;e=(t=Date.now())-this.timestamp,this.timestamp=t,i=this.offset-this.frame,this.frame=this.offset,n=1e3*i/(1+e),this.velocity=.8*n+.2*this.velocity}},{key:"_autoScroll",value:function(){var t=void 0,e=void 0;this.amplitude&&(t=Date.now()-this.timestamp,2<(e=this.amplitude*Math.exp(-t/this.options.duration))||e<-2?(this._scroll(this.target-e),requestAnimationFrame(this._autoScrollBound)):this._scroll(this.target))}},{key:"_scroll",value:function(t){var e=this;this.$el.hasClass("scrolling")||this.el.classList.add("scrolling"),null!=this.scrollingTimeout&&window.clearTimeout(this.scrollingTimeout),this.scrollingTimeout=window.setTimeout(function(){e.$el.removeClass("scrolling")},this.options.duration);var i,n,s,o,a=void 0,r=void 0,l=void 0,h=void 0,d=void 0,u=void 0,c=this.center,p=1/this.options.numVisible;if(this.offset="number"==typeof t?t:this.offset,this.center=Math.floor((this.offset+this.dim/2)/this.dim),o=-(s=(n=this.offset-this.center*this.dim)<0?1:-1)*n*2/this.dim,i=this.count>>1,this.options.fullWidth?(l="translateX(0)",u=1):(l="translateX("+(this.el.clientWidth-this.itemWidth)/2+"px) ",l+="translateY("+(this.el.clientHeight-this.itemHeight)/2+"px)",u=1-p*o),this.showIndicators){var v=this.center%this.count,f=this.$indicators.find(".indicator-item.active");f.index()!==v&&(f.removeClass("active"),this.$indicators.find(".indicator-item").eq(v)[0].classList.add("active"))}if(!this.noWrap||0<=this.center&&this.center=this.count||e<0){if(this.noWrap)return;e=this._wrap(e)}this._cycleTo(e)}},{key:"prev",value:function(t){(void 0===t||isNaN(t))&&(t=1);var e=this.center-t;if(e>=this.count||e<0){if(this.noWrap)return;e=this._wrap(e)}this._cycleTo(e)}},{key:"set",value:function(t,e){if((void 0===t||isNaN(t))&&(t=0),t>this.count||t<0){if(this.noWrap)return;t=this._wrap(t)}this._cycleTo(t,e)}}],[{key:"init",value:function(t,e){return _get(i.__proto__||Object.getPrototypeOf(i),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Carousel}},{key:"defaults",get:function(){return e}}]),i}();M.Carousel=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"carousel","M_Carousel")}(cash),function(S){"use strict";var e={onOpen:void 0,onClose:void 0},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_TapTarget=i).options=S.extend({},n.defaults,e),i.isOpen=!1,i.$origin=S("#"+i.$el.attr("data-target")),i._setup(),i._calculatePositioning(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this.el.TapTarget=void 0}},{key:"_setupEventHandlers",value:function(){this._handleDocumentClickBound=this._handleDocumentClick.bind(this),this._handleTargetClickBound=this._handleTargetClick.bind(this),this._handleOriginClickBound=this._handleOriginClick.bind(this),this.el.addEventListener("click",this._handleTargetClickBound),this.originEl.addEventListener("click",this._handleOriginClickBound);var t=M.throttle(this._handleResize,200);this._handleThrottledResizeBound=t.bind(this),window.addEventListener("resize",this._handleThrottledResizeBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("click",this._handleTargetClickBound),this.originEl.removeEventListener("click",this._handleOriginClickBound),window.removeEventListener("resize",this._handleThrottledResizeBound)}},{key:"_handleTargetClick",value:function(t){this.open()}},{key:"_handleOriginClick",value:function(t){this.close()}},{key:"_handleResize",value:function(t){this._calculatePositioning()}},{key:"_handleDocumentClick",value:function(t){S(t.target).closest(".tap-target-wrapper").length||(this.close(),t.preventDefault(),t.stopPropagation())}},{key:"_setup",value:function(){this.wrapper=this.$el.parent()[0],this.waveEl=S(this.wrapper).find(".tap-target-wave")[0],this.originEl=S(this.wrapper).find(".tap-target-origin")[0],this.contentEl=this.$el.find(".tap-target-content")[0],S(this.wrapper).hasClass(".tap-target-wrapper")||(this.wrapper=document.createElement("div"),this.wrapper.classList.add("tap-target-wrapper"),this.$el.before(S(this.wrapper)),this.wrapper.append(this.el)),this.contentEl||(this.contentEl=document.createElement("div"),this.contentEl.classList.add("tap-target-content"),this.$el.append(this.contentEl)),this.waveEl||(this.waveEl=document.createElement("div"),this.waveEl.classList.add("tap-target-wave"),this.originEl||(this.originEl=this.$origin.clone(!0,!0),this.originEl.addClass("tap-target-origin"),this.originEl.removeAttr("id"),this.originEl.removeAttr("style"),this.originEl=this.originEl[0],this.waveEl.append(this.originEl)),this.wrapper.append(this.waveEl))}},{key:"_calculatePositioning",value:function(){var t="fixed"===this.$origin.css("position");if(!t)for(var e=this.$origin.parents(),i=0;i'+t.getAttribute("label")+" ")[0]),i.each(function(t){var e=n._appendOptionWithIcon(n.$el,t,"optgroup-option");n._addOptionToValueDict(t,e)})}}),this.$el.after(this.dropdownOptions),this.input=document.createElement("input"),d(this.input).addClass("select-dropdown dropdown-trigger"),this.input.setAttribute("type","text"),this.input.setAttribute("readonly","true"),this.input.setAttribute("data-target",this.dropdownOptions.id),this.el.disabled&&d(this.input).prop("disabled","true"),this.$el.before(this.input),this._setValueToInput();var t=d(' ');if(this.$el.before(t[0]),!this.el.disabled){var e=d.extend({},this.options.dropdownOptions);e.onOpenEnd=function(t){var e=d(n.dropdownOptions).find(".selected").first();if(e.length&&(M.keyDown=!0,n.dropdown.focusedIndex=e.index(),n.dropdown._focusFocusedItem(),M.keyDown=!1,n.dropdown.isScrollable)){var i=e[0].getBoundingClientRect().top-n.dropdownOptions.getBoundingClientRect().top;i-=n.dropdownOptions.clientHeight/2,n.dropdownOptions.scrollTop=i}},this.isMultiple&&(e.closeOnClick=!1),this.dropdown=M.Dropdown.init(this.input,e)}this._setSelectedStates()}},{key:"_addOptionToValueDict",value:function(t,e){var i=Object.keys(this._valueDict).length,n=this.dropdownOptions.id+i,s={};e.id=n,s.el=t,s.optionEl=e,this._valueDict[n]=s}},{key:"_removeDropdown",value:function(){d(this.wrapper).find(".caret").remove(),d(this.input).remove(),d(this.dropdownOptions).remove(),d(this.wrapper).before(this.$el),d(this.wrapper).remove()}},{key:"_appendOptionWithIcon",value:function(t,e,i){var n=e.disabled?"disabled ":"",s="optgroup-option"===i?"optgroup-option ":"",o=this.isMultiple?''+e.innerHTML+" ":e.innerHTML,a=d(" "),r=d(" ");r.html(o),a.addClass(n+" "+s),a.append(r);var l=e.getAttribute("data-icon");if(l){var h=d(' ');a.prepend(h)}return d(this.dropdownOptions).append(a[0]),a[0]}},{key:"_toggleEntryFromArray",value:function(t){var e=!this._keysSelected.hasOwnProperty(t),i=d(this._valueDict[t].optionEl);return e?this._keysSelected[t]=!0:delete this._keysSelected[t],i.toggleClass("selected",e),i.find('input[type="checkbox"]').prop("checked",e),i.prop("selected",e),e}},{key:"_setValueToInput",value:function(){var i=[];if(this.$el.find("option").each(function(t){if(d(t).prop("selected")){var e=d(t).text();i.push(e)}}),!i.length){var t=this.$el.find("option:disabled").eq(0);t.length&&""===t[0].value&&i.push(t.text())}this.input.value=i.join(", ")}},{key:"_setSelectedStates",value:function(){for(var t in this._keysSelected={},this._valueDict){var e=this._valueDict[t],i=d(e.el).prop("selected");d(e.optionEl).find('input[type="checkbox"]').prop("checked",i),i?(this._activateOption(d(this.dropdownOptions),d(e.optionEl)),this._keysSelected[t]=!0):d(e.optionEl).removeClass("selected")}}},{key:"_activateOption",value:function(t,e){e&&(this.isMultiple||t.find("li.selected").removeClass("selected"),d(e).addClass("selected"))}},{key:"getSelectedValues",value:function(){var t=[];for(var e in this._keysSelected)t.push(this._valueDict[e].el.value);return t}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_FormSelect}},{key:"defaults",get:function(){return e}}]),n}();M.FormSelect=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"formSelect","M_FormSelect")}(cash),function(s,e){"use strict";var i={},t=function(t){function n(t,e){_classCallCheck(this,n);var i=_possibleConstructorReturn(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n,t,e));return(i.el.M_Range=i).options=s.extend({},n.defaults,e),i._mousedown=!1,i._setupThumb(),i._setupEventHandlers(),i}return _inherits(n,Component),_createClass(n,[{key:"destroy",value:function(){this._removeEventHandlers(),this._removeThumb(),this.el.M_Range=void 0}},{key:"_setupEventHandlers",value:function(){this._handleRangeChangeBound=this._handleRangeChange.bind(this),this._handleRangeMousedownTouchstartBound=this._handleRangeMousedownTouchstart.bind(this),this._handleRangeInputMousemoveTouchmoveBound=this._handleRangeInputMousemoveTouchmove.bind(this),this._handleRangeMouseupTouchendBound=this._handleRangeMouseupTouchend.bind(this),this._handleRangeBlurMouseoutTouchleaveBound=this._handleRangeBlurMouseoutTouchleave.bind(this),this.el.addEventListener("change",this._handleRangeChangeBound),this.el.addEventListener("mousedown",this._handleRangeMousedownTouchstartBound),this.el.addEventListener("touchstart",this._handleRangeMousedownTouchstartBound),this.el.addEventListener("input",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("mousemove",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("touchmove",this._handleRangeInputMousemoveTouchmoveBound),this.el.addEventListener("mouseup",this._handleRangeMouseupTouchendBound),this.el.addEventListener("touchend",this._handleRangeMouseupTouchendBound),this.el.addEventListener("blur",this._handleRangeBlurMouseoutTouchleaveBound),this.el.addEventListener("mouseout",this._handleRangeBlurMouseoutTouchleaveBound),this.el.addEventListener("touchleave",this._handleRangeBlurMouseoutTouchleaveBound)}},{key:"_removeEventHandlers",value:function(){this.el.removeEventListener("change",this._handleRangeChangeBound),this.el.removeEventListener("mousedown",this._handleRangeMousedownTouchstartBound),this.el.removeEventListener("touchstart",this._handleRangeMousedownTouchstartBound),this.el.removeEventListener("input",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("mousemove",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("touchmove",this._handleRangeInputMousemoveTouchmoveBound),this.el.removeEventListener("mouseup",this._handleRangeMouseupTouchendBound),this.el.removeEventListener("touchend",this._handleRangeMouseupTouchendBound),this.el.removeEventListener("blur",this._handleRangeBlurMouseoutTouchleaveBound),this.el.removeEventListener("mouseout",this._handleRangeBlurMouseoutTouchleaveBound),this.el.removeEventListener("touchleave",this._handleRangeBlurMouseoutTouchleaveBound)}},{key:"_handleRangeChange",value:function(){s(this.value).html(this.$el.val()),s(this.thumb).hasClass("active")||this._showRangeBubble();var t=this._calcRangeOffset();s(this.thumb).addClass("active").css("left",t+"px")}},{key:"_handleRangeMousedownTouchstart",value:function(t){if(s(this.value).html(this.$el.val()),this._mousedown=!0,this.$el.addClass("active"),s(this.thumb).hasClass("active")||this._showRangeBubble(),"input"!==t.type){var e=this._calcRangeOffset();s(this.thumb).addClass("active").css("left",e+"px")}}},{key:"_handleRangeInputMousemoveTouchmove",value:function(){if(this._mousedown){s(this.thumb).hasClass("active")||this._showRangeBubble();var t=this._calcRangeOffset();s(this.thumb).addClass("active").css("left",t+"px"),s(this.value).html(this.$el.val())}}},{key:"_handleRangeMouseupTouchend",value:function(){this._mousedown=!1,this.$el.removeClass("active")}},{key:"_handleRangeBlurMouseoutTouchleave",value:function(){if(!this._mousedown){var t=7+parseInt(this.$el.css("padding-left"))+"px";s(this.thumb).hasClass("active")&&(e.remove(this.thumb),e({targets:this.thumb,height:0,width:0,top:10,easing:"easeOutQuad",marginLeft:t,duration:100})),s(this.thumb).removeClass("active")}}},{key:"_setupThumb",value:function(){this.thumb=document.createElement("span"),this.value=document.createElement("span"),s(this.thumb).addClass("thumb"),s(this.value).addClass("value"),s(this.thumb).append(this.value),this.$el.after(this.thumb)}},{key:"_removeThumb",value:function(){s(this.thumb).remove()}},{key:"_showRangeBubble",value:function(){var t=-7+parseInt(s(this.thumb).parent().css("padding-left"))+"px";e.remove(this.thumb),e({targets:this.thumb,height:30,width:30,top:-30,marginLeft:t,duration:300,easing:"easeOutQuint"})}},{key:"_calcRangeOffset",value:function(){var t=this.$el.width()-15,e=parseFloat(this.$el.attr("max"))||100,i=parseFloat(this.$el.attr("min"))||0;return(parseFloat(this.$el.val())-i)/(e-i)*t}}],[{key:"init",value:function(t,e){return _get(n.__proto__||Object.getPrototypeOf(n),"init",this).call(this,this,t,e)}},{key:"getInstance",value:function(t){return(t.jquery?t[0]:t).M_Range}},{key:"defaults",get:function(){return i}}]),n}();M.Range=t,M.jQueryLoaded&&M.initializeJqueryWrapper(t,"range","M_Range"),t.init(s("input[type=range]"))}(cash,M.anime);
diff --git a/esphome/dashboard/static/mode-yaml.js b/esphome/dashboard/static/mode-yaml.js
index e64c0bbb18..998e39c9a4 100644
--- a/esphome/dashboard/static/mode-yaml.js
+++ b/esphome/dashboard/static/mode-yaml.js
@@ -5,4 +5,3 @@ ace.define("ace/mode/yaml_highlight_rules",["require","exports","module","ace/li
}
});
})();
-
\ No newline at end of file
diff --git a/esphome/dashboard/static/theme-dreamweaver.js b/esphome/dashboard/static/theme-dreamweaver.js
index fe965171cd..a2fc54e022 100644
--- a/esphome/dashboard/static/theme-dreamweaver.js
+++ b/esphome/dashboard/static/theme-dreamweaver.js
@@ -5,4 +5,3 @@ ace.define("ace/theme/dreamweaver",["require","exports","module","ace/lib/dom"],
}
});
})();
-
\ No newline at end of file
diff --git a/esphome/dashboard/templates/index.html b/esphome/dashboard/templates/index.html
index e7259b719d..b7df4509cc 100644
--- a/esphome/dashboard/templates/index.html
+++ b/esphome/dashboard/templates/index.html
@@ -189,7 +189,7 @@
0-9
and _
)
-
+
Name of node
@@ -207,8 +207,7 @@
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.
+ If unsure you can also select a similar board or choose the "Generic" option.
diff --git a/esphome/espota2.py b/esphome/espota2.py
old mode 100755
new mode 100644
index 65684f9bfc..786f49dbdf
--- a/esphome/espota2.py
+++ b/esphome/espota2.py
@@ -130,7 +130,7 @@ def check_error(data, expect):
"choose the correct 'board' option (esp01_1m always works) and try again.")
if dat == RESPONSE_ERROR_ESP8266_NOT_ENOUGH_SPACE:
raise OTAError("Error: ESP does not have enough space to store OTA file. Please try "
- "flashing a minimal firmware (see FAQ)")
+ "flashing a minimal firmware (remove everything except ota)")
if dat == RESPONSE_ERROR_ESP32_NOT_ENOUGH_SPACE:
raise OTAError("Error: The OTA partition on the ESP is too small. ESPHome needs to resize "
"this partition, please flash over USB.")
diff --git a/esphome/vscode.py b/esphome/vscode.py
index ebbacdf6c7..f0fa4ef52a 100644
--- a/esphome/vscode.py
+++ b/esphome/vscode.py
@@ -1,19 +1,16 @@
from __future__ import print_function
import json
+import os
from esphome.config import load_config, _format_vol_invalid
from esphome.core import CORE
from esphome.py_compat import text_type, safe_input
-from esphome.yaml_util import ESPHomeDataBase
def _get_invalid_range(res, invalid):
# type: (Config, vol.Invalid) -> Optional[DocumentRange]
- obj = res.get_deepest_value_for_path(invalid.path)
- if isinstance(obj, ESPHomeDataBase) and obj.esp_range is not None:
- return obj.esp_range
- return None
+ return res.get_deepest_document_range_for_path(invalid.path)
def _dump_range(range):
@@ -53,13 +50,18 @@ class VSCodeResult(object):
})
-def read_config():
+def read_config(args):
while True:
CORE.reset()
data = json.loads(safe_input())
assert data['type'] == 'validate'
CORE.vscode = True
- CORE.config_path = data['file']
+ CORE.ace = args.ace
+ f = data['file']
+ if CORE.ace:
+ CORE.config_path = os.path.join(args.configuration, f)
+ else:
+ CORE.config_path = data['file']
vs = VSCodeResult()
try:
res = load_config()
@@ -67,6 +69,9 @@ def read_config():
vs.add_yaml_error(text_type(err))
else:
for err in res.errors:
- range_ = _get_invalid_range(res, err)
- vs.add_validation_error(range_, _format_vol_invalid(err, res))
+ try:
+ range_ = _get_invalid_range(res, err)
+ vs.add_validation_error(range_, _format_vol_invalid(err, res))
+ except Exception: # pylint: disable=broad-except
+ continue
print(vs.dump())
diff --git a/esphome/writer.py b/esphome/writer.py
index a69f92214c..cfda7bd0b6 100644
--- a/esphome/writer.py
+++ b/esphome/writer.py
@@ -266,7 +266,7 @@ def write_platformio_project():
write_platformio_ini(content)
-DEFINES_H_FORMAT = u"""\
+DEFINES_H_FORMAT = ESPHOME_H_FORMAT = u"""\
#pragma once
{}
"""
@@ -301,7 +301,7 @@ def copy_src_tree():
source_files_l = [it for it in source_files.items()]
source_files_l.sort()
- # Build #include list for main.cpp
+ # Build #include list for esphome.h
include_l = []
for target, path in source_files_l:
if os.path.splitext(path)[1] in HEADER_FILE_EXTENSIONS:
@@ -341,8 +341,8 @@ def copy_src_tree():
CORE.relative_src_path('esphome', 'core', 'defines.h'))
write_file_if_changed(ESPHOME_README_TXT,
CORE.relative_src_path('esphome', 'README.txt'))
-
- return include_s
+ write_file_if_changed(ESPHOME_H_FORMAT.format(include_s),
+ CORE.relative_src_path('esphome.h'))
def generate_defines_h():
@@ -361,8 +361,8 @@ def write_cpp(code_s):
else:
code_format = CPP_BASE_FORMAT
- include_s = copy_src_tree()
- global_s = include_s + u'\n'
+ copy_src_tree()
+ global_s = u'#include "esphome.h"\n'
global_s += CORE.cpp_global_section
full_file = code_format[0] + CPP_INCLUDE_BEGIN + u'\n' + global_s + CPP_INCLUDE_END
diff --git a/platformio.ini b/platformio.ini
index 878176d874..c5a0d9a21b 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -17,6 +17,7 @@ lib_deps =
FastLED@3.2.0
NeoPixelBus@2.4.1
ESPAsyncTCP@1.2.0
+ TinyGPSPlus@1.0.2
build_flags =
-Wno-reorder
-DUSE_WEB_SERVER
diff --git a/script/build_compile_commands.py b/script/build_compile_commands.py
index e6d761771f..31e4c2fa56 100755
--- a/script/build_compile_commands.py
+++ b/script/build_compile_commands.py
@@ -1,93 +1,9 @@
#!/usr/bin/env python
-import codecs
-import json
-import os
-import re
import sys
+import os.path
-root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..')))
-basepath = os.path.join(root_path, 'esphome')
-temp_header_file = os.path.join(root_path, '.temp-clang-tidy.cpp')
-
-
-def walk_files(path):
- for root, _, files in os.walk(path):
- for name in files:
- yield os.path.join(root, name)
-
-
-def shlex_quote(s):
- if not s:
- return u"''"
- if re.search(r'[^\w@%+=:,./-]', s) is None:
- return s
-
- return u"'" + s.replace(u"'", u"'\"'\"'") + u"'"
-
-
-def build_all_include():
- # Build a cpp file that includes all header files in this repo.
- # Otherwise header-only integrations would not be tested by clang-tidy
- headers = []
- for path in walk_files(basepath):
- filetypes = ('.h',)
- ext = os.path.splitext(path)[1]
- if ext in filetypes:
- path = os.path.relpath(path, root_path)
- include_p = path.replace(os.path.sep, '/')
- headers.append('#include "{}"'.format(include_p))
- headers.sort()
- headers.append('')
- content = '\n'.join(headers)
- with codecs.open(temp_header_file, 'w', encoding='utf-8') as f:
- f.write(content)
-
-
-def build_compile_commands():
- gcc_flags_json = os.path.join(root_path, '.gcc-flags.json')
- if not os.path.isfile(gcc_flags_json):
- print("Could not find {} file which is required for clang-tidy.")
- print('Please run "pio init --ide atom" in the root esphome folder to generate that file.')
- sys.exit(1)
- with codecs.open(gcc_flags_json, 'r', encoding='utf-8') as f:
- gcc_flags = json.load(f)
- exec_path = gcc_flags['execPath']
- include_paths = gcc_flags['gccIncludePaths'].split(',')
- includes = ['-I{}'.format(p) for p in include_paths]
- cpp_flags = gcc_flags['gccDefaultCppFlags'].split(' ')
- defines = [flag for flag in cpp_flags if flag.startswith('-D')]
- command = [exec_path]
- command.extend(includes)
- command.extend(defines)
- command.append('-std=gnu++11')
- command.append('-Wall')
- command.append('-Wno-delete-non-virtual-dtor')
- command.append('-Wno-unused-variable')
- command.append('-Wunreachable-code')
-
- source_files = []
- for path in walk_files(basepath):
- filetypes = ('.cpp',)
- ext = os.path.splitext(path)[1]
- if ext in filetypes:
- source_files.append(os.path.abspath(path))
- source_files.append(temp_header_file)
- source_files.sort()
- compile_commands = [{
- 'directory': root_path,
- 'command': ' '.join(shlex_quote(x) for x in (command + ['-o', p + '.o', '-c', p])),
- 'file': p
- } for p in source_files]
- compile_commands_json = os.path.join(root_path, 'compile_commands.json')
- if os.path.isfile(compile_commands_json):
- with codecs.open(compile_commands_json, 'r', encoding='utf-8') as f:
- try:
- if json.load(f) == compile_commands:
- return
- except:
- pass
- with codecs.open(compile_commands_json, 'w', encoding='utf-8') as f:
- json.dump(compile_commands, f, indent=2)
+sys.path.append(os.path.dirname(__file__))
+from helpers import build_all_include, build_compile_commands
def main():
diff --git a/script/ci-custom.py b/script/ci-custom.py
index 7637f9313c..6aff5717cf 100755
--- a/script/ci-custom.py
+++ b/script/ci-custom.py
@@ -3,7 +3,9 @@ from __future__ import print_function
import codecs
import collections
+import fnmatch
import os.path
+import subprocess
import sys
@@ -18,43 +20,191 @@ def find_all(a_str, sub):
column += len(sub)
-files = []
-for root, _, fs in os.walk('esphome'):
- for f in fs:
- _, ext = os.path.splitext(f)
- if ext in ('.h', '.c', '.cpp', '.tcc', '.yaml', '.yml', '.ini', '.txt',
- '.py', '.html', '.js', '.md'):
- files.append(os.path.join(root, f))
-ignore = [
- 'esphome/dashboard/static/materialize.min.js',
- 'esphome/dashboard/static/ace.js',
- 'esphome/dashboard/static/mode-yaml.js',
- 'esphome/dashboard/static/theme-dreamweaver.js',
- 'esphome/dashboard/static/jquery.validate.min.js',
- 'esphome/dashboard/static/ext-searchbox.js',
-]
-files = [f for f in files if f not in ignore]
+command = ['git', 'ls-files', '-s']
+proc = subprocess.Popen(command, stdout=subprocess.PIPE)
+output, err = proc.communicate()
+lines = [x.split() for x in output.decode('utf-8').splitlines()]
+EXECUTABLE_BIT = {
+ s[3].strip(): int(s[0]) for s in lines
+}
+files = [s[3].strip() for s in lines]
files.sort()
+file_types = ('.h', '.c', '.cpp', '.tcc', '.yaml', '.yml', '.ini', '.txt', '.ico',
+ '.py', '.html', '.js', '.md', '.sh', '.css', '.proto', '.conf', '.cfg')
+cpp_include = ('*.h', '*.c', '*.cpp', '*.tcc')
+ignore_types = ('.ico',)
+
+LINT_FILE_CHECKS = []
+LINT_CONTENT_CHECKS = []
+
+
+def run_check(lint_obj, fname, *args):
+ include = lint_obj['include']
+ exclude = lint_obj['exclude']
+ func = lint_obj['func']
+ if include is not None:
+ for incl in include:
+ if fnmatch.fnmatch(fname, incl):
+ break
+ else:
+ return None
+ for excl in exclude:
+ if fnmatch.fnmatch(fname, excl):
+ return None
+ return func(*args)
+
+
+def run_checks(lints, fname, *args):
+ for lint in lints:
+ add_errors(fname, run_check(lint, fname, *args))
+
+
+def _add_check(checks, func, include=None, exclude=None):
+ checks.append({
+ 'include': include,
+ 'exclude': exclude or [],
+ 'func': func,
+ })
+
+
+def lint_file_check(**kwargs):
+ def decorator(func):
+ _add_check(LINT_FILE_CHECKS, func, **kwargs)
+ return func
+ return decorator
+
+
+def lint_content_check(**kwargs):
+ def decorator(func):
+ _add_check(LINT_CONTENT_CHECKS, func, **kwargs)
+ return func
+ return decorator
+
+
+def lint_content_find_check(find, **kwargs):
+ decor = lint_content_check(**kwargs)
+
+ def decorator(func):
+ def new_func(content):
+ for line, col in find_all(content, find):
+ err = func()
+ return "{err} See line {line}:{col}.".format(err=err, line=line+1, col=col+1)
+ return decor(new_func)
+ return decorator
+
+
+@lint_file_check(include=['*.ino'])
+def lint_ino(fname):
+ return "This file extension (.ino) is not allowed. Please use either .cpp or .h"
+
+
+@lint_file_check(exclude=['*{}'.format(f) for f in file_types] + [
+ '.clang-*', '.dockerignore', '.editorconfig', '*.gitignore', 'LICENSE', 'pylintrc',
+ 'MANIFEST.in', 'docker/Dockerfile*', 'docker/rootfs/*', 'script/*'
+])
+def lint_ext_check(fname):
+ return "This file extension is not a registered file type. If this is an error, please " \
+ "update the script/ci-custom.py script."
+
+
+@lint_file_check(exclude=[
+ 'docker/rootfs/*', 'script/*', 'setup.py'
+])
+def lint_executable_bit(fname):
+ ex = EXECUTABLE_BIT[fname]
+ if ex != 100644:
+ return 'File has invalid executable bit {}. If running from a windows machine please ' \
+ 'see disabling executable bit in git.'.format(ex)
+ return None
+
+
+@lint_content_find_check('\t', exclude=[
+ 'esphome/dashboard/static/ace.js', 'esphome/dashboard/static/ext-searchbox.js',
+ 'script/.neopixelbus.patch',
+])
+def lint_tabs():
+ return "File contains tab character. Please convert tabs to spaces."
+
+
+@lint_content_find_check('\r')
+def lint_newline():
+ return "File contains windows newline. Please set your editor to unix newline mode."
+
+
+@lint_content_check()
+def lint_end_newline(content):
+ if content and not content.endswith('\n'):
+ return "File does not end with a newline, please add an empty line at the end of the file."
+ return None
+
+
+@lint_content_find_check('"esphome.h"', include=cpp_include, exclude=['tests/custom.h'])
+def lint_esphome_h():
+ return ("File contains reference to 'esphome.h' - This file is "
+ "auto-generated and should only be used for *custom* "
+ "components. Please replace with references to the direct files.")
+
+
+@lint_content_check(include=['*.h'])
+def lint_pragma_once(content):
+ if '#pragma once' not in content:
+ return ("Header file contains no 'pragma once' header guard. Please add a "
+ "'#pragma once' line at the top of the file.")
+ return None
+
+
+@lint_content_find_check('ESP_LOG', include=['*.h', '*.tcc'], exclude=[
+ 'esphome/components/binary_sensor/binary_sensor.h',
+ 'esphome/components/cover/cover.h',
+ 'esphome/components/display/display_buffer.h',
+ 'esphome/components/i2c/i2c.h',
+ 'esphome/components/mqtt/mqtt_component.h',
+ 'esphome/components/output/binary_output.h',
+ 'esphome/components/output/float_output.h',
+ 'esphome/components/sensor/sensor.h',
+ 'esphome/components/stepper/stepper.h',
+ 'esphome/components/switch/switch.h',
+ 'esphome/components/text_sensor/text_sensor.h',
+ 'esphome/core/component.h',
+ 'esphome/core/esphal.h',
+ 'esphome/core/log.h',
+ 'tests/custom.h',
+])
+def lint_log_in_header():
+ return ('Found reference to ESP_LOG in header file. Using ESP_LOG* in header files '
+ 'is currently not possible - please move the definition to a source file (.cpp)')
+
+
errors = collections.defaultdict(list)
-for f in files:
+
+
+def add_errors(fname, errs):
+ if not isinstance(errs, list):
+ errs = [errs]
+ errs = [x for x in errs if x is not None]
+ for err in errs:
+ if not isinstance(err, str):
+ raise ValueError("Error is not instance of string!")
+ if not errs:
+ return
+ errors[fname].extend(errs)
+
+
+for fname in files:
+ _, ext = os.path.splitext(fname)
+ run_checks(LINT_FILE_CHECKS, fname, fname)
+ if ext in ('.ico',):
+ continue
try:
- with codecs.open(f, 'r', encoding='utf-8') as f_handle:
+ with codecs.open(fname, 'r', encoding='utf-8') as f_handle:
content = f_handle.read()
except UnicodeDecodeError:
- errors[f].append("File is not readable as UTF-8. Please set your editor to UTF-8 mode.")
+ add_errors(fname, "File is not readable as UTF-8. Please set your editor to UTF-8 mode.")
continue
- for line, col in find_all(content, '\t'):
- errors[f].append("File contains tab character on line {}:{}. "
- "Please convert tabs to spaces.".format(line, col))
- for line, col in find_all(content, '\r'):
- errors[f].append("File contains windows newline on line {}:{}. "
- "Please set your editor to unix newline mode.".format(line, col))
- if content and not content.endswith('\n'):
- errors[f].append("File does not end with a newline, please add an empty line at the end of "
- "the file.")
+ run_checks(LINT_CONTENT_CHECKS, fname, content)
-for f, errs in errors.items():
+for f, errs in sorted(errors.items()):
print("\033[0;32m************* File \033[1;32m{}\033[0m".format(f))
for err in errs:
print(err)
diff --git a/script/clang-format.py b/script/clang-format
similarity index 77%
rename from script/clang-format.py
rename to script/clang-format
index f928e76e2a..d5792c783e 100755
--- a/script/clang-format.py
+++ b/script/clang-format
@@ -2,16 +2,19 @@
from __future__ import print_function
+import argparse
import multiprocessing
import os
import re
import subprocess
import sys
-
-import argparse
-import click
import threading
+import click
+
+sys.path.append(os.path.dirname(__file__))
+from helpers import basepath, get_output, walk_files, filter_changed
+
is_py2 = sys.version[0] == '2'
if is_py2:
@@ -50,44 +53,6 @@ def progress_bar_show(value):
return value
-def walk_files(path):
- for root, _, files in os.walk(path):
- for name in files:
- yield os.path.join(root, name)
-
-
-def get_output(*args):
- proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, err = proc.communicate()
- return output.decode('utf-8')
-
-
-def splitlines_no_ends(string):
- return [s.strip() for s in string.splitlines()]
-
-
-def filter_changed(files):
- for remote in ('upstream', 'origin'):
- command = ['git', 'merge-base', '{}/dev'.format(remote), 'HEAD']
- try:
- merge_base = splitlines_no_ends(get_output(*command))[0]
- break
- except:
- pass
- else:
- return files
- command = ['git', 'diff', merge_base, '--name-only']
- changed = splitlines_no_ends(get_output(*command))
- changed = {os.path.relpath(f, os.getcwd()) for f in changed}
- print("Changed Files:")
- files = [p for p in files if p in changed]
- for p in files:
- print(" {}".format(p))
- if not files:
- print(" No changed files")
- return files
-
-
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-j', '--jobs', type=int,
diff --git a/script/clang-tidy.py b/script/clang-tidy
similarity index 54%
rename from script/clang-tidy.py
rename to script/clang-tidy
index 7187c16454..124008a873 100755
--- a/script/clang-tidy.py
+++ b/script/clang-tidy
@@ -2,8 +2,6 @@
from __future__ import print_function
-import codecs
-import json
import multiprocessing
import os
import re
@@ -18,6 +16,10 @@ import argparse
import click
import threading
+sys.path.append(os.path.dirname(__file__))
+from helpers import basepath, shlex_quote, get_output, build_compile_commands, \
+ build_all_include, temp_header_file, walk_files, filter_changed
+
is_py2 = sys.version[0] == '2'
if is_py2:
@@ -25,11 +27,6 @@ if is_py2:
else:
import queue as queue
-root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..')))
-basepath = os.path.join(root_path, 'esphome')
-rel_basepath = os.path.relpath(basepath, os.getcwd())
-temp_header_file = os.path.join(root_path, '.temp-clang-tidy.cpp')
-
def run_tidy(args, tmpdir, queue, lock, failed_files):
while True:
@@ -67,119 +64,6 @@ def run_tidy(args, tmpdir, queue, lock, failed_files):
def progress_bar_show(value):
if value is None:
return ''
- return value
-
-
-def walk_files(path):
- for root, _, files in os.walk(path):
- for name in files:
- yield os.path.join(root, name)
-
-
-def get_output(*args):
- proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- output, err = proc.communicate()
- return output.decode('utf-8')
-
-
-def splitlines_no_ends(string):
- return [s.strip() for s in string.splitlines()]
-
-
-def filter_changed(files):
- for remote in ('upstream', 'origin'):
- command = ['git', 'merge-base', '{}/dev'.format(remote), 'HEAD']
- try:
- merge_base = splitlines_no_ends(get_output(*command))[0]
- break
- except:
- pass
- else:
- return files
- command = ['git', 'diff', merge_base, '--name-only']
- changed = splitlines_no_ends(get_output(*command))
- changed = {os.path.relpath(f, os.getcwd()) for f in changed}
- print("Changed Files:")
- files = [p for p in files if p in changed]
- for p in files:
- print(" {}".format(p))
- if not files:
- print(" No changed files")
- return files
-
-
-def shlex_quote(s):
- if not s:
- return u"''"
- if re.search(r'[^\w@%+=:,./-]', s) is None:
- return s
-
- return u"'" + s.replace(u"'", u"'\"'\"'") + u"'"
-
-
-def build_compile_commands():
- gcc_flags_json = os.path.join(root_path, '.gcc-flags.json')
- if not os.path.isfile(gcc_flags_json):
- print("Could not find {} file which is required for clang-tidy.")
- print('Please run "pio init --ide atom" in the root esphome folder to generate that file.')
- sys.exit(1)
- with codecs.open(gcc_flags_json, 'r', encoding='utf-8') as f:
- gcc_flags = json.load(f)
- exec_path = gcc_flags['execPath']
- include_paths = gcc_flags['gccIncludePaths'].split(',')
- includes = ['-I{}'.format(p) for p in include_paths]
- cpp_flags = gcc_flags['gccDefaultCppFlags'].split(' ')
- defines = [flag for flag in cpp_flags if flag.startswith('-D')]
- command = [exec_path]
- command.extend(includes)
- command.extend(defines)
- command.append('-std=gnu++11')
- command.append('-Wall')
- command.append('-Wno-delete-non-virtual-dtor')
- command.append('-Wno-unused-variable')
- command.append('-Wunreachable-code')
-
- source_files = []
- for path in walk_files(basepath):
- filetypes = ('.cpp',)
- ext = os.path.splitext(path)[1]
- if ext in filetypes:
- source_files.append(os.path.abspath(path))
- source_files.append(temp_header_file)
- source_files.sort()
- compile_commands = [{
- 'directory': root_path,
- 'command': ' '.join(shlex_quote(x) for x in (command + ['-o', p + '.o', '-c', p])),
- 'file': p
- } for p in source_files]
- compile_commands_json = os.path.join(root_path, 'compile_commands.json')
- if os.path.isfile(compile_commands_json):
- with codecs.open(compile_commands_json, 'r', encoding='utf-8') as f:
- try:
- if json.load(f) == compile_commands:
- return
- except:
- pass
- with codecs.open(compile_commands_json, 'w', encoding='utf-8') as f:
- json.dump(compile_commands, f, indent=2)
-
-
-def build_all_include():
- # Build a cpp file that includes all header files in this repo.
- # Otherwise header-only integrations would not be tested by clang-tidy
- headers = []
- for path in walk_files(basepath):
- filetypes = ('.h',)
- ext = os.path.splitext(path)[1]
- if ext in filetypes:
- path = os.path.relpath(path, root_path)
- include_p = path.replace(os.path.sep, '/')
- headers.append('#include "{}"'.format(include_p))
- headers.sort()
- headers.append('')
- content = '\n'.join(headers)
- with codecs.open(temp_header_file, 'w', encoding='utf-8') as f:
- f.write(content)
def main():
@@ -212,6 +96,7 @@ def main():
""")
return 1
+ build_all_include()
build_compile_commands()
files = []
@@ -231,7 +116,6 @@ def main():
files.sort()
if args.all_headers:
- build_all_include()
files.insert(0, temp_header_file)
tmpdir = None
diff --git a/script/fulltest b/script/fulltest
new file mode 100755
index 0000000000..0fa88516c2
--- /dev/null
+++ b/script/fulltest
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+set -e
+
+cd "$(dirname "$0")/.."
+
+set -x
+
+script/ci-custom.py
+script/lint-python
+script/lint-cpp
+script/test
diff --git a/script/helpers.py b/script/helpers.py
new file mode 100644
index 0000000000..8b37dce570
--- /dev/null
+++ b/script/helpers.py
@@ -0,0 +1,128 @@
+import codecs
+import json
+import os.path
+import re
+import subprocess
+import sys
+
+root_path = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..')))
+basepath = os.path.join(root_path, 'esphome')
+temp_header_file = os.path.join(root_path, '.temp-clang-tidy.cpp')
+
+
+def shlex_quote(s):
+ if not s:
+ return u"''"
+ if re.search(r'[^\w@%+=:,./-]', s) is None:
+ return s
+
+ return u"'" + s.replace(u"'", u"'\"'\"'") + u"'"
+
+
+def build_all_include():
+ # Build a cpp file that includes all header files in this repo.
+ # Otherwise header-only integrations would not be tested by clang-tidy
+ headers = []
+ for path in walk_files(basepath):
+ filetypes = ('.h',)
+ ext = os.path.splitext(path)[1]
+ if ext in filetypes:
+ path = os.path.relpath(path, root_path)
+ include_p = path.replace(os.path.sep, '/')
+ headers.append('#include "{}"'.format(include_p))
+ headers.sort()
+ headers.append('')
+ content = '\n'.join(headers)
+ with codecs.open(temp_header_file, 'w', encoding='utf-8') as f:
+ f.write(content)
+
+
+def build_compile_commands():
+ gcc_flags_json = os.path.join(root_path, '.gcc-flags.json')
+ if not os.path.isfile(gcc_flags_json):
+ print("Could not find {} file which is required for clang-tidy.")
+ print('Please run "pio init --ide atom" in the root esphome folder to generate that file.')
+ sys.exit(1)
+ with codecs.open(gcc_flags_json, 'r', encoding='utf-8') as f:
+ gcc_flags = json.load(f)
+ exec_path = gcc_flags['execPath']
+ include_paths = gcc_flags['gccIncludePaths'].split(',')
+ includes = ['-I{}'.format(p) for p in include_paths]
+ cpp_flags = gcc_flags['gccDefaultCppFlags'].split(' ')
+ defines = [flag for flag in cpp_flags if flag.startswith('-D')]
+ command = [exec_path]
+ command.extend(includes)
+ command.extend(defines)
+ command.append('-std=gnu++11')
+ command.append('-Wall')
+ command.append('-Wno-delete-non-virtual-dtor')
+ command.append('-Wno-unused-variable')
+ command.append('-Wunreachable-code')
+
+ source_files = []
+ for path in walk_files(basepath):
+ filetypes = ('.cpp',)
+ ext = os.path.splitext(path)[1]
+ if ext in filetypes:
+ source_files.append(os.path.abspath(path))
+ source_files.append(temp_header_file)
+ source_files.sort()
+ compile_commands = [{
+ 'directory': root_path,
+ 'command': ' '.join(shlex_quote(x) for x in (command + ['-o', p + '.o', '-c', p])),
+ 'file': p
+ } for p in source_files]
+ compile_commands_json = os.path.join(root_path, 'compile_commands.json')
+ if os.path.isfile(compile_commands_json):
+ with codecs.open(compile_commands_json, 'r', encoding='utf-8') as f:
+ try:
+ if json.load(f) == compile_commands:
+ return
+ except:
+ pass
+ with codecs.open(compile_commands_json, 'w', encoding='utf-8') as f:
+ json.dump(compile_commands, f, indent=2)
+
+
+def walk_files(path):
+ for root, _, files in os.walk(path):
+ for name in files:
+ yield os.path.join(root, name)
+
+
+def get_output(*args):
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output, err = proc.communicate()
+ return output.decode('utf-8')
+
+
+def splitlines_no_ends(string):
+ return [s.strip() for s in string.splitlines()]
+
+
+def changed_files():
+ for remote in ('upstream', 'origin'):
+ command = ['git', 'merge-base', '{}/dev'.format(remote), 'HEAD']
+ try:
+ merge_base = splitlines_no_ends(get_output(*command))[0]
+ break
+ except:
+ pass
+ else:
+ raise ValueError("Git not configured")
+ command = ['git', 'diff', merge_base, '--name-only']
+ changed = splitlines_no_ends(get_output(*command))
+ changed = [os.path.relpath(f, os.getcwd()) for f in changed]
+ changed.sort()
+ return changed
+
+
+def filter_changed(files):
+ changed = changed_files()
+ files = [f for f in files if f in changed]
+ print("Changed files:")
+ if not files:
+ print(" No changed files!")
+ for c in files:
+ print(" {}".format(c))
+ return files
diff --git a/script/lint-cpp b/script/lint-cpp
index b1766d8a28..88728c9abd 100755
--- a/script/lint-cpp
+++ b/script/lint-cpp
@@ -12,5 +12,5 @@ fi
set -x
-script/clang-tidy.py -c --fix --all-headers
-script/clang-format.py -c -i
+script/clang-tidy $@ --fix --all-headers
+script/clang-format $@ -i
diff --git a/script/lint-python b/script/lint-python
index 5ce638b854..cb702bf362 100755
--- a/script/lint-python
+++ b/script/lint-python
@@ -1,10 +1,74 @@
-#!/usr/bin/env bash
+#!/usr/bin/env python
-set -e
+from __future__ import print_function
-cd "$(dirname "$0")/.."
-set -x
+import argparse
+import collections
+import os
+import re
+import sys
-script/ci-custom.py
-flake8 esphome
-pylint esphome
+sys.path.append(os.path.dirname(__file__))
+from helpers import basepath, get_output, walk_files, filter_changed
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('files', nargs='*', default=[],
+ help='files to be processed (regex on path)')
+ parser.add_argument('-c', '--changed', action='store_true',
+ help='Only run on changed files')
+ args = parser.parse_args()
+
+ files = []
+ for path in walk_files(basepath):
+ filetypes = ('.py',)
+ ext = os.path.splitext(path)[1]
+ if ext in filetypes:
+ path = os.path.relpath(path, os.getcwd())
+ files.append(path)
+ # Match against re
+ file_name_re = re.compile('|'.join(args.files))
+ files = [p for p in files if file_name_re.search(p)]
+
+ if args.changed:
+ files = filter_changed(files)
+
+ files.sort()
+
+ errors = collections.defaultdict(list)
+ cmd = ['flake8'] + files
+ print("Running flake8...")
+ log = get_output(*cmd)
+ for line in log.splitlines():
+ line = line.split(':')
+ if len(line) < 4:
+ continue
+ file_ = line[0]
+ linno = line[1]
+ msg = (u':'.join(line[3:])).strip()
+ errors[file_].append(u'{}:{} - {}'.format(file_, linno, msg))
+
+ cmd = ['pylint', '-f', 'parseable', '--persistent=n'] + files
+ print("Running pylint...")
+ log = get_output(*cmd)
+ for line in log.splitlines():
+ line = line.split(':')
+ if len(line) < 3:
+ continue
+ file_ = line[0]
+ linno = line[1]
+ msg = (u':'.join(line[3:])).strip()
+ errors[file_].append(u'{}:{} - {}'.format(file_, linno, msg))
+
+ for f, errs in sorted(errors.items()):
+ print("\033[0;32m************* File \033[1;32m{}\033[0m".format(f))
+ for err in errs:
+ print(err)
+ print()
+
+ sys.exit(len(errors))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/script/quicklint b/script/quicklint
new file mode 100755
index 0000000000..06c31d519d
--- /dev/null
+++ b/script/quicklint
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -e
+
+cd "$(dirname "$0")/.."
+
+set -x
+
+script/ci-custom.py
+script/lint-python -c
+script/lint-cpp -c
diff --git a/tests/custom.h b/tests/custom.h
index be1e91fb94..0c30437b8c 100644
--- a/tests/custom.h
+++ b/tests/custom.h
@@ -1,3 +1,5 @@
+#pragma once
+#include "esphome.h"
class CustomSensor : public Component, public Sensor {
public:
diff --git a/tests/test1.yaml b/tests/test1.yaml
index 454bc8c6a8..b9177802fa 100644
--- a/tests/test1.yaml
+++ b/tests/test1.yaml
@@ -15,6 +15,14 @@ esphome:
then:
- lambda: >-
ESP_LOGV("main", "ON LOOP!");
+ - light.addressable_set:
+ id: addr1
+ range_from: 1
+ range_to: 100
+ red: 100%
+ green: !lambda 'return 255;'
+ blue: 0%
+ white: 100%
build_path: build/test1
wifi:
@@ -503,6 +511,13 @@ sensor:
name: "SDS011 PM10.0"
update_interval: 5min
rx_only: false
+ - platform: ccs811
+ eco2:
+ name: CCS811 eCO2
+ tvoc:
+ name: CCS811 TVOC
+ update_interval: 30s
+ baseline: 0x4242
esp32_touch:
@@ -1131,6 +1146,8 @@ pn532:
rdm6300:
+gps:
+
time:
- platform: sntp
id: sntp_time
@@ -1142,6 +1159,7 @@ time:
cron: '/30 0-30,30/5 * ? JAN-DEC MON,SAT-SUN,TUE-FRI'
then:
- lambda: 'ESP_LOGD("main", "time");'
+- platform: gps
cover:
- platform: template
diff --git a/tests/test3.yaml b/tests/test3.yaml
index 2eedb25fc5..7fcc7e1e60 100644
--- a/tests/test3.yaml
+++ b/tests/test3.yaml
@@ -189,6 +189,9 @@ binary_sensor:
- platform: ttp229_lsf
channel: 1
name: TTP229 LSF Test
+ - platform: ttp229_bsf
+ channel: 1
+ name: TTP229 BSF Test
- platform: custom
lambda: |-
auto s = new CustomBinarySensor();
@@ -392,3 +395,7 @@ servo:
output: out
ttp229_lsf:
+
+ttp229_bsf:
+ sdo_pin: D0
+ scl_pin: D1