From 8144607b6b7dfe1b738cebb171ebff49b47dc0a9 Mon Sep 17 00:00:00 2001 From: msinn Date: Mon, 13 Apr 2020 22:46:18 +0200 Subject: [PATCH 001/126] Version of develop adjusted to "after release" version 1.7b --- bin/shngversion.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/shngversion.py b/bin/shngversion.py index a50396ebab..660200bcef 100755 --- a/bin/shngversion.py +++ b/bin/shngversion.py @@ -52,12 +52,13 @@ # Update auf 1.6b wg. ÄNnderung bei RelativsPath Auflösung & Doku Änderungen # Update auf 1.7 wg. Release -# Update auf 1.7a wg. Kennzeichnung des Stands als "nach dem v1.6 Release" +# Update auf 1.7a wg. Kennzeichnung des Stands als "nach dem v1.7 Release" # Update auf 1.7.1 wg. Release +# Update auf 1.7a wg. Kennzeichnung des Stands als "nach dem v1.7.1 Release" -shNG_version = '1.7.1' -shNG_branch = 'master' +shNG_version = '1.7b' +shNG_branch = 'develop' # --------------------------------------------------------------------------------- FileBASE = None From 585f347ca2f0d139f225f58e3d643958d08bd848 Mon Sep 17 00:00:00 2001 From: msinn Date: Wed, 15 Apr 2020 08:27:57 +0200 Subject: [PATCH 002/126] lib.shtime: fixed bug in beginning_of_week() that returned the date of the monday of the following week --- lib/shtime.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/shtime.py b/lib/shtime.py index 8590855307..ad6c8ca136 100755 --- a/lib/shtime.py +++ b/lib/shtime.py @@ -505,7 +505,7 @@ def beginning_of_week(self, week=None, year=None): if week is None: logger.error("beginning_of_week: "+self.translate("Week not specified")) return self.today() - + week -= 1 #monday = datetime.datetime.strptime(f'{year}-{week}-1', "%Y-%W-%w") # geht erst ab Python 3.6 monday = datetime.datetime.strptime('{year}-{week}-1'.format(year=year, week=week), "%Y-%W-%w") return monday.date() @@ -1002,7 +1002,7 @@ def _initialize_holidays(self): def is_weekend(self, date=None): """ Returns True, if the date is on a weekend - + Note: Easter sunday is not considered a holiday (since it is a sunday already)! :param date: date for which the weekday should be returned. If not specified, today is used From 6e2b3968b90097ee3c75ade9c92582d509a9ba70 Mon Sep 17 00:00:00 2001 From: msinn Date: Wed, 15 Apr 2020 09:30:47 +0200 Subject: [PATCH 003/126] Documentation: Removed 'new' and 'update' tags of v1.7 from documentation --- doc/user/source/beispiele/beispiele.rst | 6 ++--- doc/user/source/conf.py | 20 ++++++++++++--- doc/user/source/index.rst | 25 +++++++++++-------- .../komplettanleitung/01_debian.rst | 6 ++--- .../komplettanleitung/02_smarthomeng.rst | 6 ++--- .../komplettanleitung/05_knxd.rst | 6 ++--- .../komplettanleitung/07_samba.rst | 6 ++--- .../komplettanleitung/08_shng_daemon.rst | 8 +++--- .../source/installation/update_upgrade.rst | 6 ++--- .../konfiguration/admin_gui/admin_gui.rst | 6 ++--- .../source/konfiguration/items/funktionen.rst | 4 +-- .../konfiguration/items/plugin_attribute.rst | 4 +-- .../source/konfiguration/items/properties.rst | 4 +-- .../standard_attribute/standard_attr.rst | 4 +-- .../items/standard_attribute/struct.rst | 4 +-- .../konfiguration_backup_restore.rst | 6 ++--- .../konfigurationsdateien/holidays.rst | 6 ++--- .../konfigurationsdateien/struct.rst | 4 +-- .../konfiguration/module/module_mqtt.rst | 6 ++--- doc/user/source/logiken/funktions_nutzung.rst | 6 ++--- doc/user/source/logiken/mqtt_nutzung.rst | 6 ++--- .../source/logiken/persistente_variablen.rst | 6 ++--- doc/user/source/release/1_7_1.rst | 2 +- 23 files changed, 88 insertions(+), 69 deletions(-) diff --git a/doc/user/source/beispiele/beispiele.rst b/doc/user/source/beispiele/beispiele.rst index 743d96e6ca..f7f6261c61 100644 --- a/doc/user/source/beispiele/beispiele.rst +++ b/doc/user/source/beispiele/beispiele.rst @@ -2,9 +2,9 @@ .. role:: bluesup .. role:: redsup -======================================= -Beispiele, Tipps & Tricks :redsup:`Neu` -======================================= +========================= +Beispiele, Tipps & Tricks +========================= In diesem Abschnitt sind ausführliche Beispiele sowie Tipps & Tricks für die Konfiguration von SmartHomeNG beschrieben. Diese Beispiele beziehen sich auf den Core von SmartHomeNG. Beispiele zu den Plugins sind gegebenfalls in der diff --git a/doc/user/source/conf.py b/doc/user/source/conf.py index 3634b1709a..d51b01e3ae 100755 --- a/doc/user/source/conf.py +++ b/doc/user/source/conf.py @@ -16,6 +16,7 @@ print(i) import bin.shngversion as shngversion +import plugins as pluginsversion import datetime now = datetime.datetime.now() @@ -68,18 +69,18 @@ # # The short X.Y version. #version = '1.3c' -version = shngversion.get_shng_main_version() +shversion = shngversion.get_shng_main_version() # General information about the project. #project = u'SmartHomeNG' -project = u'Anwenderdokumentation v' + version -#copyright = u'2011-2013, Marcus Popp; since 2016 SmartHomeNG Team' -#copyright = u'2016-2017 SmartHomeNG Team, based on smarthome.py © 2011-2014 Marcus Popp' +project = u'Anwenderdokumentation v' copyright = u'2016-2020 SmartHomeNG Team, SmartHomeNG is based on smarthome.py © Marcus Popp' # The full version, including alpha/beta/rc tags. #release = '1.3a dev (as of 13. October 2017)' 13. October 2017 is replaced by makefile with a date in the form of '2. September 2017' #release = '1.3c dev (as of 13. October 2017)' +# +#plgrelease = '1.3c dev (as of 13. October 2017)' if os.path.isfile(os.getcwd()+'/doc_version.flg'): release = '1.4.x' with open(os.getcwd()+'/doc_version.flg') as f: @@ -97,6 +98,17 @@ release += ')' #release = sphinx_bootstrap_theme.__version__ +plgrelease = pluginsversion.plugin_release() +plgbranch = pluginsversion.plugin_branch() +if plgbranch != 'master': + plgrelease += ' ' + plgbranch +version = plgrelease + +if plgrelease > shversion: + project += plgrelease +else: + project += shversion + # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None diff --git a/doc/user/source/index.rst b/doc/user/source/index.rst index cb78614619..3b33b2cefe 100755 --- a/doc/user/source/index.rst +++ b/doc/user/source/index.rst @@ -1,8 +1,8 @@ :tocdepth: 6 -########### +=========== SmartHomeNG -########### +=========== Anwenderdokumentation ===================== @@ -13,20 +13,25 @@ Gerätes wird durch das Metagateway so um viele zusätzliche Schnittstellen erwe möglich dass die Klingel mit der Musikanlage und TV spricht, und dessen Wiedergabe unterbricht oder bei Abwesenheit eine Nachricht per Email verschickt. -Viele haben in die Konfiguration Ihres Smarthome.py Systems viel Arbeit gesteckt und wollen -das jetzt nicht aufgeben und wieder etwas komplett neues machen. So wurde ein Fork SmartHomeNG -erstellt um die Fortentwicklungen im System wieder zusammenzuführen und eine Basis für -Weiterentwicklungen zu stellen. +Das System kann flexibel durch Plugins erweitert werden, wobei die Plugins in folgende Kategorien klassifiziert sind: -Diese Dokumentation reflektiert das aktuelle Release |release|. +- **Gateway**: Anbindung von Devices eines Bus-Systems wie KNX, HomeMatic, EnOcean, 1-Wire, DMX, Philips Hue, ... +- **Interface**: Anbindung einzelner Devices wie AVM Fritzboxen, Heizungssteuerungen, div. AV Devices, ... +- **Web-/Cloud-Dienst**: Anbindung an diverse Web- bzw. Cloud-Dienste, wie Mail, Prowl, Wetter-Dienste, Alexa, ... +- **Protokoll**: Unterstützung diverser Protokolle wie TCP/IP, MQTT, XMPP +- **System**: Systemnahe Erweiterungen wie Datenbank Anbindung, Visu Anbindung, universelle Zeitschaltuhr, + Stateengine (endlicher Automat), ... +Diese Dokumentation reflektiert das aktuelle Release: + +- Version des Core: |release| +- Version der Plugins: |version| Die Entwickler-Dokumentation (für Entwickler von Plugins und den Core von SmartHomeNG), sowie die READMEs der Plugins sind in Englisch gehalten. -Die hier entstehende Anwenderdokumentation ist auf Deutsch. Später wird sie zweisprachig Deutsch/Englisch -zur Verfügung stehen. Sie wird sich aus Inhalten speisen, die zurzeit im `SmartHomeNG Wiki `_ -zur Verfügung stehen. +Die Anwenderdokumentation steht auf Deutsch zur Verfügung. Die Entwicklerdokumentation hingegen, ist in Englisch +verfasst. Hilfe zu SmartHomeNG gibt es im `Supportforum im KNX-User-Forum `_ oder im `Chat auf gitter.im `_ . diff --git a/doc/user/source/installation/komplettanleitung/01_debian.rst b/doc/user/source/installation/komplettanleitung/01_debian.rst index 59b51833cf..7e142a446b 100644 --- a/doc/user/source/installation/komplettanleitung/01_debian.rst +++ b/doc/user/source/installation/komplettanleitung/01_debian.rst @@ -4,9 +4,9 @@ .. role:: bluesup .. role:: redsup -=========================================== -Debian Linux installieren :bluesup:`update` -=========================================== +========================= +Debian Linux installieren +========================= Die genaue Schritt für Schritt Installation des Betriebsystems wird hier nicht beschrieben, das hier ist der falsche Ort dafür. Jedoch werden als diff --git a/doc/user/source/installation/komplettanleitung/02_smarthomeng.rst b/doc/user/source/installation/komplettanleitung/02_smarthomeng.rst index b8bd15d708..65e50f67de 100644 --- a/doc/user/source/installation/komplettanleitung/02_smarthomeng.rst +++ b/doc/user/source/installation/komplettanleitung/02_smarthomeng.rst @@ -5,9 +5,9 @@ .. role:: bluesup .. role:: redsup -========================================== -SmartHomeNG installieren :bluesup:`update` -========================================== +======================== +SmartHomeNG installieren +======================== SmartHomeNG ist eine in Python erstellte Anwendung. Daher muss bevor SmartHomeNG genutzt werden kann, Python installiert werden. Außerdem muß der git Client installert werden, um SmartHomeNG von Github diff --git a/doc/user/source/installation/komplettanleitung/05_knxd.rst b/doc/user/source/installation/komplettanleitung/05_knxd.rst index 7b24be442c..60ba25b680 100644 --- a/doc/user/source/installation/komplettanleitung/05_knxd.rst +++ b/doc/user/source/installation/komplettanleitung/05_knxd.rst @@ -4,9 +4,9 @@ .. role:: bluesup .. role:: redsup -=================================== -knxd installieren :bluesup:`update` -=================================== +================= +knxd installieren +================= Der knxd implementiert Zugriffe auf verschiedenste Schnittstellen zum KNX Bus (z.B. IP-Router, IP-Schnittstelle, USB-Schnittstelle, etc.) und bietet dafür eine dokumentierte Softwareschnittstelle für Programme an. SmartHomeNG diff --git a/doc/user/source/installation/komplettanleitung/07_samba.rst b/doc/user/source/installation/komplettanleitung/07_samba.rst index 824da533f5..4c030f6da7 100644 --- a/doc/user/source/installation/komplettanleitung/07_samba.rst +++ b/doc/user/source/installation/komplettanleitung/07_samba.rst @@ -4,9 +4,9 @@ .. role:: bluesup .. role:: redsup -==================================== -Samba installieren :bluesup:`update` -==================================== +================== +Samba installieren +================== Wer mit einem Windows-Rechner auf die Dateien von SmartHomeNG und SmartVISU zugreifen möchte, *kann* dazu **Samba** installieren. diff --git a/doc/user/source/installation/komplettanleitung/08_shng_daemon.rst b/doc/user/source/installation/komplettanleitung/08_shng_daemon.rst index 72cbfa1091..f76c352a2c 100644 --- a/doc/user/source/installation/komplettanleitung/08_shng_daemon.rst +++ b/doc/user/source/installation/komplettanleitung/08_shng_daemon.rst @@ -4,9 +4,9 @@ .. role:: bluesup .. role:: redsup -================================= -SmartHomeNG als Dienst einrichten -================================= +=================================================== +SmartHomeNG als Dienst einrichten :bluesup:`update` +=================================================== .. contents:: Schritte der Installation :local: @@ -38,9 +38,11 @@ und folgenden Text hineinkopieren: [Service] Type=forking ExecStart=/usr/bin/python3 /usr/local/smarthome/bin/smarthome.py + WorkingDirectory=/usr/local/smarthome User=smarthome PIDFile=/usr/local/smarthome/var/run/smarthome.pid Restart=on-abort + TimeoutStartSec=900 [Install] WantedBy=default.target diff --git a/doc/user/source/installation/update_upgrade.rst b/doc/user/source/installation/update_upgrade.rst index 5dfbe9f2c6..f94df34464 100644 --- a/doc/user/source/installation/update_upgrade.rst +++ b/doc/user/source/installation/update_upgrade.rst @@ -4,9 +4,9 @@ .. role:: redsup .. role:: bluesup -================================================== -Update von einer älteren Version :bluesup:`update` -================================================== +================================ +Update von einer älteren Version +================================ Es kann verschiedene Szenarien geben von denen aus man ein Update machen möchte. Es gibt unterschiedliche Ansätze wenn es sich um eine Virtuelle Maschine handelt oder wenn ein Raspberry Pi upgedated werden soll. Es gibt hier diff --git a/doc/user/source/konfiguration/admin_gui/admin_gui.rst b/doc/user/source/konfiguration/admin_gui/admin_gui.rst index 29f9c04b7f..0bf0fa8978 100644 --- a/doc/user/source/konfiguration/admin_gui/admin_gui.rst +++ b/doc/user/source/konfiguration/admin_gui/admin_gui.rst @@ -4,9 +4,9 @@ .. role:: bluesup .. role:: redsup -======================================== -Konfiguration über die GUI :redsup:`Neu` -======================================== +========================== +Konfiguration über die GUI +========================== SmartHomeNG kann vollständig über die graphische Oberfläche konfiguriert werden. Für einen Teil der Konfiguration stehen Dialoge zur Verfügung, die Erläuterungen zu den einzelnen Einstellungen geben und evtl. vorhandene Standardwerte diff --git a/doc/user/source/konfiguration/items/funktionen.rst b/doc/user/source/konfiguration/items/funktionen.rst index f9bba8dec0..41e895e99b 100644 --- a/doc/user/source/konfiguration/items/funktionen.rst +++ b/doc/user/source/konfiguration/items/funktionen.rst @@ -5,8 +5,8 @@ .. role:: redsup -Funktionen eines Items :bluesup:`update` -======================================== +Funktionen eines Items +====================== Jedes definierte Item bietet die folgenden Methoden an, die unter anderem in **eval** Ausdrücken diff --git a/doc/user/source/konfiguration/items/plugin_attribute.rst b/doc/user/source/konfiguration/items/plugin_attribute.rst index 649f46d3b6..6e609559f7 100644 --- a/doc/user/source/konfiguration/items/plugin_attribute.rst +++ b/doc/user/source/konfiguration/items/plugin_attribute.rst @@ -4,8 +4,8 @@ .. role:: bluesup -Plugin-spezifische Attribute :bluesup:`update` -============================================== +Plugin-spezifische Attribute +============================ In SmartHomeNG werden außer den Standard Attributen weiter Attribute unterstützt, die von Plugins diff --git a/doc/user/source/konfiguration/items/properties.rst b/doc/user/source/konfiguration/items/properties.rst index 8fac72a5bc..f3788b75c6 100644 --- a/doc/user/source/konfiguration/items/properties.rst +++ b/doc/user/source/konfiguration/items/properties.rst @@ -5,8 +5,8 @@ .. role:: redsup -Properties eines Items :bluesup:`update` -======================================== +Properties eines Items +====================== Jedes definierte Item bietet die folgenden Properties an, die unter anderem in **eval** Ausdrücken genutzt werden können. Alle Properties sind zumindest lesend (r/o) zugreifbar. Einige Properties können diff --git a/doc/user/source/konfiguration/items/standard_attribute/standard_attr.rst b/doc/user/source/konfiguration/items/standard_attribute/standard_attr.rst index 020e0484c0..cfdcccd3a7 100644 --- a/doc/user/source/konfiguration/items/standard_attribute/standard_attr.rst +++ b/doc/user/source/konfiguration/items/standard_attribute/standard_attr.rst @@ -20,8 +20,8 @@ .. role:: bluesup -Standard Attribute :bluesup:`update` -==================================== +Standard Attribute +================== In SmartHomeNG werden eine Reihe von Standard Attributen unterstützt. Diese sind in der folgenden diff --git a/doc/user/source/konfiguration/items/standard_attribute/struct.rst b/doc/user/source/konfiguration/items/standard_attribute/struct.rst index 959fbf44ba..4fceb15f85 100644 --- a/doc/user/source/konfiguration/items/standard_attribute/struct.rst +++ b/doc/user/source/konfiguration/items/standard_attribute/struct.rst @@ -10,8 +10,8 @@ .. role:: bluesup .. role:: redesup -`struct` :bluesup:`Update` --------------------------- +struct +------ Eine Reihe von Plugins benötigt eine bestimmte Item Struktur bzw. eine größere Zahl an Items um sinnvoll zu funktionieren. Diese Items müssen dazu innerhalb des Item-Trees als Teilbaum angelegt werden (zum Teil auch mehrfach). diff --git a/doc/user/source/konfiguration/konfiguration_backup_restore.rst b/doc/user/source/konfiguration/konfiguration_backup_restore.rst index 657d4f9572..ec37042930 100644 --- a/doc/user/source/konfiguration/konfiguration_backup_restore.rst +++ b/doc/user/source/konfiguration/konfiguration_backup_restore.rst @@ -4,9 +4,9 @@ .. role:: redsup .. role:: bluesup -======================================================== -Konfiguration Sichern und Wiederherstellen :redsup:`neu` -======================================================== +========================================== +Konfiguration Sichern und Wiederherstellen +========================================== .. index:: Backup; Kommandozeile .. index:: Sichern; Kommandozeile diff --git a/doc/user/source/konfiguration/konfigurationsdateien/holidays.rst b/doc/user/source/konfiguration/konfigurationsdateien/holidays.rst index fbdfacbbb8..b1bec1e26c 100644 --- a/doc/user/source/konfiguration/konfigurationsdateien/holidays.rst +++ b/doc/user/source/konfiguration/konfigurationsdateien/holidays.rst @@ -5,9 +5,9 @@ .. role:: bluesup .. role:: redsup -=========================== -holidays.yaml :redsup:`new` -=========================== +============= +holidays.yaml +============= .. _`holidays.yaml`: diff --git a/doc/user/source/konfiguration/konfigurationsdateien/struct.rst b/doc/user/source/konfiguration/konfigurationsdateien/struct.rst index d9a14330eb..8851ea712a 100644 --- a/doc/user/source/konfiguration/konfigurationsdateien/struct.rst +++ b/doc/user/source/konfiguration/konfigurationsdateien/struct.rst @@ -4,8 +4,8 @@ .. index:: structs; struct.yaml -struct.yaml :bluesup:`update` -============================= +struct.yaml +=========== In dieser Konfigurationsdatei können eigene Item-Strukturen angelegt werden, die über das **struct** Attribut als Template verwendet werden können. diff --git a/doc/user/source/konfiguration/module/module_mqtt.rst b/doc/user/source/konfiguration/module/module_mqtt.rst index 0bd2ea5d8a..350f7f2d79 100644 --- a/doc/user/source/konfiguration/module/module_mqtt.rst +++ b/doc/user/source/konfiguration/module/module_mqtt.rst @@ -6,9 +6,9 @@ .. role:: redsup .. role:: bluesup -========================= -Module mqtt :redsup:`Neu` -========================= +=========== +Module mqtt +=========== Dieses Modul erlaubt es SmartHomeNG über das MQTT Protokoll zu kommunizieren. Es stellt ein einfach zu nutzendes Interface für Logiken und Plugins zur Verfügung. Dabei kann das mqtt Modul von mehreren Logiken und/oder Plugins diff --git a/doc/user/source/logiken/funktions_nutzung.rst b/doc/user/source/logiken/funktions_nutzung.rst index fbf57e09d9..de51361c7d 100644 --- a/doc/user/source/logiken/funktions_nutzung.rst +++ b/doc/user/source/logiken/funktions_nutzung.rst @@ -4,9 +4,9 @@ .. role:: redsup .. role:: bluesup -==================================== -Nutzung von Funktionen :redsup:`Neu` -==================================== +====================== +Nutzung von Funktionen +====================== Bei der Nutzung von Funktionen in Logiken ist eine Besonderheit zu beachten: diff --git a/doc/user/source/logiken/mqtt_nutzung.rst b/doc/user/source/logiken/mqtt_nutzung.rst index fdf3cabd4d..e904779a5f 100644 --- a/doc/user/source/logiken/mqtt_nutzung.rst +++ b/doc/user/source/logiken/mqtt_nutzung.rst @@ -4,9 +4,9 @@ .. role:: redsup .. role:: bluesup -========================================= -Nutzung von MQTT in Logiken :redsup:`Neu` -========================================= +=========================== +Nutzung von MQTT in Logiken +=========================== Die Nutzung des MQTT Protokolls in Logiken wird durch das mqtt Modul von SmartHomeNG möglich, welches ab Version 1.7 zur Verfügung steht. Zur Nutzung muss das mqtt Modul geladen und konfiguiert sein und der konfigurierte MQTT Broker diff --git a/doc/user/source/logiken/persistente_variablen.rst b/doc/user/source/logiken/persistente_variablen.rst index 6a3bbb2d41..d56d44a9e0 100755 --- a/doc/user/source/logiken/persistente_variablen.rst +++ b/doc/user/source/logiken/persistente_variablen.rst @@ -2,9 +2,9 @@ .. role:: bluesup -======================================= -Persistente Variablen :bluesup:`update` -======================================= +===================== +Persistente Variablen +===================== Normale Variablen innerhalb von Logiken sind nur für den jeweiligen Lauf gültig. Es ist jedoch in einigen Fällen notwendig, Werte zwischen verschiedenen Läufen einer Logik zu übergeben. diff --git a/doc/user/source/release/1_7_1.rst b/doc/user/source/release/1_7_1.rst index 3869d9dd7f..efb5914e15 100644 --- a/doc/user/source/release/1_7_1.rst +++ b/doc/user/source/release/1_7_1.rst @@ -2,7 +2,7 @@ Release 1.7.1 - 14. April 2020 ============================== -Dieses ist ein Hotfix Release. Die vollständigen Änderungen der Version v1.7 bitte :doc:`hier ` +Dieses ist ein Hotfix Release. Die vollständigen Änderungen der Version v1.7 bitte :doc:`hier ` nachlesen. From efa430f4db6a5466e087b474a61be04b0d9c0a7b Mon Sep 17 00:00:00 2001 From: msinn Date: Thu, 16 Apr 2020 11:35:52 +0200 Subject: [PATCH 004/126] logo_small as png files added --- media/logo_small_120x120.png | Bin 0 -> 5134 bytes media/logo_small_152x152.png | Bin 0 -> 6289 bytes media/logo_small_32x32.png | Bin 0 -> 1330 bytes media/logo_small_76x76.png | Bin 0 -> 3323 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 media/logo_small_120x120.png create mode 100644 media/logo_small_152x152.png create mode 100644 media/logo_small_32x32.png create mode 100644 media/logo_small_76x76.png diff --git a/media/logo_small_120x120.png b/media/logo_small_120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..e9e28e3d6bf17734acd829af7c5e2e48fbbe7f1b GIT binary patch literal 5134 zcmaJ_bx;)C*Ir<0mJR`FaFH&hV+oNEP+~z`>5$l^q?Se+L;(qr5Me=(kcK6tySu?f zmhO%p@893d_spDo=FXg+xzCxoQF=P+AQC1L0002ec&_^DUVHy1L4#s|SnkFN zpTIJ?7LRn2Q36r{(>c2l{(C*|&?r?j<~RR@Dz^dYpGwQ}NAEhyMriNq;W#4%Fg{jrmZ@gFIo z5M5JUq4_R6`wR|+dmKVb!(?yvqMXeAJH#4)o zUpaZ3p`oZv60ZX+lj#vMWya}=o*pwesH-S+GCWCSJDd!4A?5vl=~n zTnapn_Pi|SYa5AO$97ZtCnNB!ox|s7$ylhJc7}6-?6WphRL>X{7qA~zczs6 z?|H1MEAq;yF}cnmj(@*H?tFe+GHaRRudmXzM2;c)1FqvHLiV9@Uq?;mrWjBJXSIw5Y)>FVk> zt_tswJ72qU%9o*C4er%_HK3#iGh>&x$MUi4-@-gE=}=w_fyG(Pjlt z7mi%I_Z|XH^=EB;LpjGvwt~yQEH|DpfMUVEZqc5_vFQ45UOb?C;ee3{SAl`Wb7$c! z+E;(0W9s1qxVrKS8@$$q!zMxW7L}&>1ofuoIawTwX3oY5Pw#|*;l?kSL${9gySGcP z%1XO*4UW8IwFuHeYU((8LTDvEc)ZG|2ri%?pA74YlLXbdD!UlGadzyH{33s{zg1j-jeYtLNI9OouHka)W=6P z5B})e#aIw4a>Bq|(m2EF++?4Xt;`-cF*X(z-wtnH4lVuE6Hm^h-jDj2+eI&&qTC;q z`4L6$rH`pU1j#3+vD7x zvpH1t`|UoL`yW=Cwyo8*B91%`P`#md#u2^O)k^J?bT|xBqH7pQV^0<*eua|&tJ_1= zCpPQUwpU$)Uvd(_zQ`DSKsT$@rq-#?W;E33pCCW^n|21u)!o}2mdk?ktY}m>uUR-8 z35%<^L|08@HB^KA=M@RxEO#HAQNX90f0ALb;k7G_X$+&@3NF>-v_Gm{Y%Z#yXZUo+$GcT?9dDnfa~I+pJ0sJh(=`ILCtZ#L|D>bouCu|E>vwyjs%vlo@Q==JvAO<^d$ zoFJoK@Boc1=<};*1ES&JxBvL#z_Ki?y80Jg#rZmoQ>o2z>^DwcQR(IO-v*sB_`|*y zH*Np@xbA7Ef<^WIxSApm6J(?e=K7V`rfmgQ5K_z4;b|N}GU*b?3?{L*VD}bF`b}@0 z*)8=WH0sZh@HCVpSf1~J3YVWr{p+pX*}jj(Kl_k3q(Jl8iWGcSaEC5>4JSj|CVY?< zTaop?YTTf%Fa`<@Jato2@J3LI3UT!(iCv1qR5v9cV%}^ay{vBI(CeZfoPj7?rVRvpnn^V|}3EoaCe<6X_c_YN1h zhll4W`(`&hVJMxCq8PsD?6~hRjc33hwYuJw7-FS9IHAscS5_pES@d0C$k6b55?h)) zQNW_E7_^EK_*x*IKbWj6c+f<);Cv#uJEq2F1i!h)s~SrvB;M9#8X7V1G1%pflVoR< z)R9R~)(%h=2~YD&t2cGjn$@~Hf$uPAc|r2vnxNpY^T$I=;0~T4%22L>`*6i4`79IQ zC50O-zwB^4cmo+a9aS-Knd-<&$4QOyc=CPCsbG5S_325WIC7HiY#b4P&qKE}6lCk7 z6<<&XwN8O>o7?pO(Xc6K`{M0iBGLbdNA(qy=b6w{+Gw$JglF?uVx@Hr@M9D9`+4^H zLB;!(-!vNFiw(Pl?RR{07Q$D)FK*zb&0jz4S@C*qx+fkdCz&jcCj2{?X5NHN@YH?D zYN%uk>O!aon1B~4X%*Ke)lWpRXGERD>}IHv&O&7`m6hH?-P^Bw2t6oil%zG#r(cCl zMAg)eC>+w-5!z z5=r?yrjCvon58DOMlL(jhFHxeVHe+e4!EjqxWeeAl_;;rCt<=t@d=(c?v{r4ypF!P z05ZX7^kx7P*ko)TohflQnO#d2ud(twDuwy& zsI8*TeL73*Nt0AM)DQa%yyK@lKWZ@nOAu=o| z-&rPdD8dKxowc1( z@nv)LhQxa+7g2TFf14~PI$QwSzy0I34Zdk_sk~pElEZvF|0ECao}Oh$I)8YMeQe$3dzCkStg^3PI#M(&7ZZwA@ObD+g@v{M0oB z>cI9}A5dlHr@8FR@H-f!mjQ-(AH{M~krtb5x#PPIYd&e3fYLNce%=f@_dx*jg)49J zl@3j{J&IpL{3${*mBel07m}Nn+qRGcLx9{l+pH;!`cIm8+QjB*vL9zl~q z&D`rhd#(P|R$ed*g!QpLh}=r|jWzQZ3GLz&&-F@*MvCG~i>Jr*s|SKm#R2or1bhQF zN=u9IJ8;b^TvTXrGIp`v($Bb>r*}k43rvH4ymf$grf6Kk9 zV69FGU21luA|2Sl|#vWE_ z{Lkn-vv=7pe9#oRjK;)|zn2sNxcq7C=GAJ|`C%<7L7GW}SO`?xYg%OBr9Zd#M2*$A z7-_UC)Nn~fbO>q|jWYP1Uxnn2oq0&sj^@Qb#kJoa)obGqhzlidplMNwc8XeK%!9jM-zn&E#(pgku9o>ca5Wv6g7?m(jt8*wSz~c+bnNyJDo(dET(ZIz zkg`prS}Jlhx8akZ$hd4BjD@HWew)Ov_OsmP)R;E>B;II>t}Y^hq$F3}297%=Kt_TW z*9H*5r1V2l4zN^o!UK21n2>DnK8St3g>@(}*9MbJdE^<4MJx&SZ5K7l1A`tF&9I-e z5(F$1Zt%YTR!5tC;y~z5)uS!Z#kI`knCu*PU#(K_FT=&N#nFAu8pm=1(;PDn6va3h zN}NdUTT3%_h<5r|xtm?b5VGx`Ee})5sB`d9Il`SmV8A;n@-3k4r>$OwYYFf2Pj*;4 zsuI8YUE>ZSd-zAW34qu5+iwl}_K4IEa&)UNmANC$w9U+~tX9SA6l&Z?^&sW|sVZ+@ zjgeKxn3hyR6rMxn44t-LL~Ah5>!odGL!g50%4q-fpFBq0PrNo_=2qdbfm2zFSfTD? zKjEv|oR@~nN3?&hbIa^C*4Z$gSF{Q8F{!_al}fiG`aht@=>MMjf3Z`{gHm+zy_HAf zDX|90S=*6L)>Cn5(3jZlp8#1w?{(gCQ3~SjN0KW>A3IKInTaiuQdh#@_q($XUQ+Lw=O6)O2Q|`+9(#4w5<)pcLqc*x zKk4GX5tI?Me67TsPQmiLZ2kXcAX(Leh|M*6Dtqoesljk zTLN*fWTUf|MTg+x(lTEK;1rxVCRd zCY=$?M67DKDypfzO@sunTh**NV)YT9XJjU6lmYA;AM~T+OlZ#CXir-Wvb#whIA)}z zk0%BRsVB2UclB}~(fL@uM&vv=vxe^TvgF61y;#P5zIjR8$sKjpO` zdGaUH!+P8iaR#mmHx=Xk2B6YRi2Ji*qv$JtT3rv3 zWit@{!TarzQeCr8$fD*ed*h19I0T{51vFEu5H2gFrzbb!>hNxz*fDvB6nAM;{fhok zLqhd_sB(hh`Ez=VipI$Ln$JuPtX$3Yx?!NTbv%=k^nq5pJ`NKmBEF(*dno6ih@g2r zhbP$mjo89-^Sk5-v3$`3ac(@DCsoh;dYvt^zW}JTTeDB~2yO!p+sz_LNUg*@@hC0> z_W)g`bsIFLcA1>}VszKxRG$Fs^z93~`NA#UpcxOt4BJB5=0s3fveh22tfj;;^(nnj z&v{{K+eYbm){EZ3oxY?oAQBImcFynn;!0 zhD;wZYIkWYXK){)LcVD`m(1uI6!*x0k4XUh;e$gjTtWi?$}*5@G2+jF2K#1a(#|DZEyoakui|P-t;? zr^w~~|Nb&_@||QdnKMbwCz+F2Ee%CNJZd}u06?g$B=_N2v;Jo|SkE=En}P9JFg@QX z>*73@ARL>R=QggJlA-7G___ZX+B=S~e$Sm$Uh)tx9alRqUrP^LfUmFb8%G$_)7sL_ z_KmBD{nw+n)X($1RF;#~^~*U#`1|SV!TbLl&mwto7t)5Y7CwWx7znu}K8LBcF~s8k zV}dhi#<{p^E(v94AMM&N()nWaz94o}W*n|(^1|%-IarR#B9R=-4n| z+rW0~XEPrP1w)_g(l@guGpt?1@DH|Q1nNRW6@^*GDIVTM=HS*h%w+hQjsDT?VCNLBip=9|SD0GiUtc_bIFTK#OfSM%vvP1q(=t2S7xLyziW5o=*YT_M<*?@BE3a9BFw04txQICi{NkTvvd7{YP**hx?%-HGx=XL1?gMB6k_04_rdVyF3rzquU>heXEpR# zAv;cN?Y+AcnJxlcOu9|<9M-&Kb$#2ul;YvwUy4Q{fn=9gkqF8O=gOtJ0O`BQyUIVf zJXU*Ch4qt7Jd>CTM4x`0|6>GOl=0rq2CPoswUT}>s4_5i!>k6f@ePv`GG{uyCylxm z&IA&_qUZNIQ-#Oe6drDttU#si-51m!IocyanE88dZd3Ml(pjyP4#;GY8O*$pujRwe zGxGaRXDe?b_Jj7P4@{pV!zc-^fAXu-IGS)^MbWgPcJOXjy9Tqn02hRXX1Yd7(4ZaAZ923YW! z+DkKRRYVbb`uOf*a>UM@0{BUDD2u{pXas z*L+PgrktQ4oOLm8 ziw&2%&W%vr+~Eh}i~))C;Q`}|6x9u&_h_Ym(m(d!SH|8aov&D8Bp*!@6SrPM`xX+& z|Fl0{H?EsgbV))PX7z(mTEv$v=(t=NYz)}}^Ro=v+@HH9IWg9vRtkw!8|yP@d3|(X zbomCjqn0pOgI>mwLx5cG<141+CJrr z%l@qxdA#I(lDBuz#VSP5&>{>pXF3lncnwQz7N`xpf31VBUBS%F`fER32s`?N6#bE4C zLL);SdDiOBKaVMuTahzuD}y~5pctU!!yHkpKtI^&36+N&tBSUP)j?=Rr0U2IK{K1% z4J{x`N?bK%LPFv1qoh4)_PEr@O4c|e^6|rVaoyLw^OZ#mdh@*7%1$>{Q7nLV8b!QL zU%XK%VWQA5=P`d9`D|3JWF}l_zparlD0gRQBuZ!c@2A$}-bq1Kh>c^Zn01v{?y}oX zA^q>%Z*e!Zoy39y-pS_EJ0*yk$$5DBXBY47Id2!z3lYqo3q4;b6X|wEWI@3OCV#~< z@qVKId2H@p@LwL1>WPtuqc(FyxwRl~8NbpTfZZW#VQ=Jd zAtltNy~$a2g%t9PcD3Q&7Wm*tbG%lW_8elx?M;zDmtA)9rKaGQ8^+6s0zQ%yL68iB z|J2>Z=B%ga{J6#g4bXTM6`*)2ud^xrbSHgsBK1uaQ(;vn?`r|Qm{qPgL(sPzz>t&s z{C=EoJ=vzK)6jLh1gk4C$Xh!?Jm@A!fF&fNQo(<=Wmttiy0mN2RBHV!)}8~KC5`Z z{+1z%C`jdkh%l3sG22)i36eK&UZU8r3s2A<7|qGyQXtIcz57I%Ov-3zB*AmZYFw^y zu=4rrJ>qDr+VxeIppdZJ&P|JzQa6um;g`+Jx~91~IQN8W`NQ3%N%Lyt!JBaH-rh~p z`cq~~2Xtl|Fjm%beh3odfc7v~UE&MC5Y0ZC3@vo82MHVPsfg$w`}wm61U~y9 zK;0nFKR~BPlRBjv(p5XG@xPlL`hK^u-1GZuGIB$hT>vX4Tkq&i&-?OH*|O(=cLSr1 z{)W{|Q@GYq1gGhQKFU;}gWUococ>$G@wPb&(sStclARu`djT@|;;WBXhU7K%+Zz8; z$K`PvE~qJ3o&5w)4v*Z-1oo#AF|79HJV(!i0XZHrs6>| zI=0E~tY^Pcy|jNH%l!qD!sj{y(t%2e>-}4*TpNc{-?VMq>-GluR}i%cvMXw1_O$b< zO)0SQl3_5lNhXAl+kuvx)r%#TR5W1DQkVX9zhiSqA)~;KEbVKlVgVq1y75X)lc>nj zK3_1T<)QP7Ozv{otr%=mWx??SoK5gFCAam3Y2V7qyj3;#(uZ5UBYkiqLkl`7lU)@& zUz8x1`!4#a(thqTxf0o6pOH~#NY}6%9Wf&3c zJ0PhOp`eFW4~LfA{*9hHTy=jRP6%vb;BokiD(U++UlyUyH&ON5$avCF4^$SEs#^*qG??LT}5S+OM5} z=~^2{kg*eajXs6azx@eZlqNBYq@8{U}M1IkDYT>%R#5e@?Nv*%w{{4FP zGrc%p-cm4xhS)7eiIm475-U|k^hc`U$i&9K&bz%=AT-sb5K0CgC zqNI)s(NEabx0v0lqrKZ%758>Ka4|5iYnqw$GP{$i*o%9DEQRdasQaGg{Cpp{P;-_k zbSZI}f&qVlSWzlC8WzdeVDMZh10Ax9nER484y4M`IECWi&`4#=7^%8+QK&u|@XgUZ z?!3Jbub}_H+CXt6!MEVmCXe{WtS(cFY}sooKMWoJS!P*iUz8O4`rPk2VOs1VaWM8= zAxaY>IKAZWb|+va-8f5Yoms7CJ{yIJFLLi3xZnhHYow$kW6wKytzDmn~ zSqfvf-~cdV#Ib&hZd8~?`<5x7i&n}I^+DDx=S?Lko`uSJOb5^E?L-8~?ki8;jGp*~ z15YSu4C!<7QGVZx8qrbtM$TXtm0x$?E-XJ1u(Cf1ANp8iH02k*YNlUjTPydD;bG^e zZ0=b$eHbPaiwR*W0|PihJlRrwP-(F+>09-=(A00As1K<5DO&U`G19`uwQGRKaykh> zW|Pvb4dX!F-m2ax=*3@F*7K9*&NcnbodyaOc_b&Hj4-pzEzO55YzuJ#IIOCxI!%AW zS=-l16cPIL{KUH8uT9+J#wgq%2PZl4%wwU<(PFL!>pxmpLG0!X8>yz$%K+yIwzAS) z%zrF~CSVC4QJWJM!1cZk7%}rzpmnPw{O`?)IbLmE`L!9>19nqrB7-CJKY|K8MwjTD01&HhRs0|!E=I)`yDLKPISFmVWE;~j81 zTZ22(-)42bp7jFot=vO$@(P+eNuZ5tfR^TgzMVjsJCnYhr3g@&q?CmFU>&&TWj6*x z0H#Il__Zm$rOG=64P8Thqv{~KWWK`YP8?@=oj`m(Lg}))uY&$xe|B>O$dMdSyRN_K zJPkqRg!#Me)=pr)@&j}Rjt_XWzCQ&4U-g5}L$GQEl#L8?HglRo)NU&r5v+!e)k3k4 zgbZ^ULINUPGq+$-1?_M`(^?lm4iDNZ>%7dW;I(>^^DmXk4-o=3EhOCGAD*}SW-n8v zT3$OGd~q0=laRu2peq=i8gPY%f$$bd#3>l(I#~|>qc>K`l?30DAX7VyKqNDq*%*qJ;Q~11<5zDP8T3!ipA2kjrJ1Jsc%$~UTE)HT z!-7>32HXkd`BM6zbV!W97x`%Db}Tcn1q+iJR{5bIu@%KtM37al+5lBeAR-ZyrVIG5 zGwX54G5MrMBz3dp9ECL?#9@A*Z;8z!#*3=pFGvBvB@F(gX7${SH58(F!pwsd%c|~*8g${Kr2az@9aB(Gywehz2 z+%N-{*Ah>0d0u~v?waorpLA9o=SQ%x(YoPW1sA(cw8N^k%p+LtML3!5izT)#EX2*l z^0srWq1o9af>HsvYL{p@8efuf!aJt{{Q?E<=sMLZ5SNoJOL

H67tAod;64KY0u%2K7bsURat?1 z#=i=|NN#HVOJF4vHSF{x$hmwG%{Z~u8^DPv`lX z4;mD|#_5+-rLq)ZoE%9}$ZA^f0ihl%w2f93I+FEb0XJs0IXqE?RQrzJ83x5q@Do2UF?p2O2p0m+rVYpC9}Prq46n$PML2*0XRQUanP6 zFT5N&1p)&j!!^3z6U|r=a3^p#wR!6_ORvqiqG+@mw}u1(wg3^J0Sxb>y0--L3r9$niZk!blM#FNfCSU@4u$0-;0GHaE~yZ#+8FNwiG9dUgu)#2L-_2^eMTP zi+$Spy97WDv!)HO8FV4%2P^|G?DY8AkON`Vbl{aMRs8_e2-KKurUobJ`HyP^C6CZ|z^Yc$ov z`8%SJ(X)mSYDWGK^5y(tOt@tIF;tzz!!cAiI2arxVg1b>Q=T5<*`6y06Kcb2N+nD(#HGg^%jXi8?qWUo6L&S3<&pyc;|-y-lXQQ> z+2fVi86`og$a4C?|4D0uWGGC;zD+re#jhy3LdI=nX4nrOtyoLWqBm;_N{jw=6}OGR zdUSUL^|uW<7f6fu5Z))G5lu|cPd&wAyLIftR6_GYHFfTFbMQ-fO#L5rKD>YunjOIc z_Kd6!?3_krQlK+l*{m%8ftB1BJ>{^k5T1T#?|=GKk_c=|HNdYeIxUt&dnkt?lv zZORWYf=DWY*Ur(o=nH;%jJHDPHtv`o1va*ksVUhdUiqd66ver3+7Cr+K=3h_3XL&g5NQepjEb5GFmC`C^>)o_9%%b~|5L4jp_@ zZd=al!87j4nx=N*nvwG+&!=hu%?8lCQw2^B3)e^ip0IZgVLiPzY@Qj@%FNJ5PFa<4 z6P29d$YGCO^=HVtuDG81a0Qb$E!m!#t3wHDMBgw*jWzFyTu70GdG|FqlOLNMn!WYd zS@*jV5&=}RNPbDfj}6(b?9nxxr&2BsDZUt6`24mobxM*>Qcw3xfAM;7)Fjy?aG%WT z>ee7&Ef5p;TO^5cUgl3kV^Vd~+vx2iq^+GwU#BSGr@)&hF)A*2U(6BOH-{cltlC#@ zsY-VWD6kKujkI3qW+PCl#=o@`) nnp*$A67Bz=Bzyqv6aI?rxj)_e_uP;d1Pz! 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 FV1ng^e5wEd literal 0 HcmV?d00001 From 97d85b06221a385dc313c82942ccd544ad96403a Mon Sep 17 00:00:00 2001 From: sisamiwe Date: Thu, 16 Apr 2020 14:54:50 +0200 Subject: [PATCH 005/126] Updated user docu for structs; examples for knxd config added Hey, I restructured the user docu of structs to have all information on one place and just link for the different places to that. Furthermore some knxd config examples (from old wiki) have been added. --- doc/user/source/beispiele/beispiele.rst | 3 +- doc/user/source/beispiele/knxd.rst | 66 +++++ .../source/konfiguration/item_structs.rst | 243 +++++++++++++----- .../items/standard_attribute/struct.rst | 16 +- .../konfigurationsdateien/struct.rst | 130 ---------- 5 files changed, 243 insertions(+), 215 deletions(-) create mode 100644 doc/user/source/beispiele/knxd.rst diff --git a/doc/user/source/beispiele/beispiele.rst b/doc/user/source/beispiele/beispiele.rst index 743d96e6ca..9c291e2341 100644 --- a/doc/user/source/beispiele/beispiele.rst +++ b/doc/user/source/beispiele/beispiele.rst @@ -20,5 +20,4 @@ Dokumentation des jeweiligen Plugins im Abschnitt :doc:`Plugins ` items_tipps_und_tricks.rst logiken/logiken.rst structs.rst - - + knxd.rst \ No newline at end of file diff --git a/doc/user/source/beispiele/knxd.rst b/doc/user/source/beispiele/knxd.rst new file mode 100644 index 0000000000..a3336fceba --- /dev/null +++ b/doc/user/source/beispiele/knxd.rst @@ -0,0 +1,66 @@ + +.. index:: eval_trigger; Beispiele +.. index:: eval; Beispiele + +========================================== +knxd: Hinweise und Konfigurationsbeispiele +========================================== + +Hier finden sich einige Hinweise und Konfigurationsbeispiele für die Anwendung von knxd + + +Wichtig +======= + +Diese Liste soll eine Sammlung von Beispielkonfigurationen verschiedenster Schnittstellen liefern. Sie ersetzt nicht die Dokumentation von knxd auf dem Git-Repository. +Sie ist in Lieferanten und anschließend deren Schnittstellen gegliedert. Bei den Beispielen bitte bei "IP-Adresse" die IP der Schnittstelle / des Routers angeben (bspw. 192.168.178.30). + + +Beispielkonfigurationen +======================= + + +busware.de +---------- + +* **TPUART USB Modul** + +* **RTC-Onewire-TPUART Erweiterung für Raspberry Pi (ROT)** + + +MDT +--- + +* **SCN-IP000.01:** + + + +* **SCN-IP100.02:** + *KNXD_OPTS="-u /tmp/eib -i -b ipt:"IP-Adresse"* + +* **SCN-USBR.01:** + *KNXD_OPTS="--eibaddr=1.1.0 --client-addrs=1.1.245:4 --GroupCache --Discovery -Tunnelling --Routing --Server --layer2=usb"* oder kurz: *KNXD_OPTS="-e=1.1.0 -E=1.1.245:4 -c -DTRS -b usb"* wobei --eibaddr=1.1.0... eine freie Busadresse für den knxd ist und --client-addrs=1.1.245:4... den Adressbereich darstellt, den der knx-Server an seine Clients vergibt. Hier von 1.1.245 bis 1.1.249. + + +Weinzierl +--------- + +* **KNX USB Interface 311** +* **KNX USB Interface 312** +* **KNX USB Interface 330** +* **KNX IP Interface 730** + *KNXD_OPTS="-e 0.0.0 -c --no-tunnel-client-queuing -b ipt:IP-Adresse -D -R -T -S"*; Ab KNXD Version 0.14 arbeitet der knxd Prozess mit einer INI Datei. Die Kommandozeilenparameter kann mit einem Tool in das INI Datei Format umwandeln lassen. Beispiel: /usr/lib/knxd_args -e 0.0.1 -E 0.0.2:8 -DTRS --error=3 -t 1023 -i --send-delay=30 ipt:IP-Adresse +* **KNX IP Interface 731** +* **KNX IP Interface 732** +* **KNX IP Interface 740 wireless** +* **KNX IP Router 750** +* **KNX IP Router 751** +* **KNX IP Router 752** +* **KNX IP Linemaster 760** +* **KNX IP Linemaster 762** + + +ABB +--- + +* **ABB IP/R2.1** \ No newline at end of file diff --git a/doc/user/source/konfiguration/item_structs.rst b/doc/user/source/konfiguration/item_structs.rst index 859216ed5d..7572d111a4 100644 --- a/doc/user/source/konfiguration/item_structs.rst +++ b/doc/user/source/konfiguration/item_structs.rst @@ -13,20 +13,26 @@ structs (Item Strukturen) Überblick ========= -Eine Reihe von Plugins benötigt eine bestimmte Item Struktur bzw. eine größere Zahl an Items um sinnvoll zu -funktionieren. Diese Items müssen dazu innerhalb des Item-Trees als Teilbaum angelegt werden (zum Teil auch mehrfach). +Seit SmartHomeNG v1.6 werden Item-Struktur-Templates unterstützt, mit denen sich wiederholende Itemstrukturen einfach realisieren lassen. +Die Anwendung erfolgt mit Hilfe des **struct**-Attributes mit dem jeweiligen Namen des Item-Templates. Dies wird bei dem Item definiert, +unter dem die definierte Struktur (Teil-Item-Baum) eingefügt werden soll. -Seit SmartHomeNG v1.6 werden diese Strukturen/Templates unterstützt, die dann mit Hilfe des **struct**-Attributs in -den Item-Tree eingefügt werden können. Dazu muss bei dem Item an dessen Stelle der Teilbaum eingefügt werden soll, -der Name des Templates (der Item-Struktur) angegeben werden. +Prinzipiell gibt es 2 Anwendungsfälle: + - Der Nutzer kann selbst entsprechende Item-Struktur-Templates anlegen und verwenden + - Eine Reihe von Plugins benötigt eine bestimmte Item Struktur bzw. eine größere Zahl an Items um sinnvoll zu funktionieren. -Die Item Strukturen/Templates können an zwei verschiedenen Stellen definiert werden: +Demzufolge können die Item-Struktur-Templates an zwei verschiedenen Stellen definiert werden: -- der Nutzer kann die Strukturen in der Konfigurationsdatei ../etc/struct.yaml definieren -- Autoren von Plugins können die Strukturen in den Metadaten des Plugins definieren. Beim Start von SmartHomeNG - stehen die dann die Strukturen aller konfigurierten Plugins zur Verfügung. + - der Nutzer kann die Strukturen in der Konfigurationsdatei ../etc/struct.yaml definieren + - Autoren von Plugins können die Strukturen in den Metadaten des Plugins definieren. Beim Start von SmartHomeNG stehen die dann die Strukturen aller konfigurierten Plugins zur Verfügung. -Mit dem **struct**-Attribut kann nicht nur eine Item Struktur in den Item-Tree eingefügt werden, sondern auch mehrere. +Um eine doppelte Namensvergabe zu vermeiden, wird bei der Nutzung den structs, die in Plugins definiert wurden, der +Name des Plugins vorangestellt. Wenn z.B. die struct **weather** genutzt werden soll, die im Plugin **darksky** +definiert wurde, so muss als Referenz **darksky.weather** angegeben werden. + +Eine Übersicht der zur Verfügung stehenden structs kann in der Admin GUI unter **Items/Struktur** Templates eingesehen werden. + +Mit dem **struct**-Attribut kann nicht nur eine, sondern auch mehrere vordefinierte Item-Strukturen in den Item-Tree eingefügt werden. Dazu wird im **struct**-Attribut eine Liste von **struct** Namen angegeben. Wenn eine Liste angegeben wird, werden die Template Strukturen in der Reihenfolge angewendet, in der sie in der Liste angegeben wurden. @@ -38,17 +44,15 @@ die Template Strukturen in der Reihenfolge angewendet, in der sie in der Liste a - mein_wetter2 - .... -Um eine doppelte Namensvergabe zu vermeiden, wird bei der Nutzung den structs, die in Plugins definiert wurden, der -Name des Plugins vorangestellt. Wenn z.B. die struct **weather** genutzt werden soll, die im Plugin **darksky** -definiert wurde, so muss als Referenz **darksky.weather** angegeben werden. - -Eine Übersicht der zur Verfügung stehenden structs kann in der Admin GUI unter **Items/Struktur** Templates eingesehen -werden. +struct bei Plugins +================== +Anwendung +--------- Das folgende Beispiel verdeutlicht das Vorgehen am Wettervorhersage-Plugin **darksky**: -Bisher musste man in den Items einen ganzen Teilbaum eintragen (hier unter **aussen.mein_wetter**): +Bisher musste man in den Items einen ganzen Teilbaum selbst eintragen (hier unter **aussen.mein_wetter**): .. code-block:: yaml @@ -71,11 +75,9 @@ Bisher musste man in den Items einen ganzen Teilbaum eintragen (hier unter **aus ... -Das Plugin **darksky** bringt nun ein Template mit dem Namen **weather** mit, welcher mit **darksky.weather** angesprochen -werden kann. +Das Plugin **darksky** bringt nun ein Template mit dem Namen **weather** mit, welcher mit **darksky.weather** angesprochen werden kann. -Um nun die ganzen Items für die Wettervorhersage anzulegen, muss nur noch für das Item **mein_wetter** das Attribut -**struct** gesetzt werden: +Um nun die ganzen Items für die Wettervorhersage anzulegen, muss nur noch für das Item **mein_wetter** das Attribut **struct** gesetzt werden: .. code-block:: yaml :caption: items/item.yaml @@ -85,19 +87,17 @@ Um nun die ganzen Items für die Wettervorhersage anzulegen, muss nur noch für struct: darksky.weather -Wenn das Plugin darksky konfiguriert ist, kann man in der Administrationsoberfläche die gesamten Items, die zum -Wetterbericht gehören, sehen. +Wenn das Plugin darksky konfiguriert ist, kann man in der Administrationsoberfläche die gesamten Items, die zum Wetterbericht gehören, sehen. Multi-Instance Unterstützung -============================ +---------------------------- Wenn mehrere Instanzen eines Plugins verwendet werden, so muss (wie zu erwarten) bei dem Item welches die **struct** referenziert, das Attribute **instance** angegeben werden. -In der Definition der structs in den Multi-Instance fähigen Plugins wird vom Plugin Autor an Stelle des aktuellen -Instance Namen das Wort **instance** als Platzhalter angegeben (wie im folgenden Beispiel beim Attribut -**ds_matchstring**: +In der Definition der **structs** in den Multi-Instance fähigen Plugins wird vom Plugin Autor an Stelle des aktuellen +Instance Namen das Wort **instance** als Platzhalter angegeben (wie im folgenden Beispiel beim Attribut **ds_matchstring**: .. code-block:: yaml :caption: plugins/darksky/plugin.yaml @@ -115,8 +115,7 @@ Instance Namen das Wort **instance** als Platzhalter angegeben (wie im folgenden ... -In der Definition der Items bestehen zwei Möglichkeiten einer **struct** die **instance** mitzugeben auf die sich -die **struct** beziehen soll. +In der Definition der Items bestehen zwei Möglichkeiten einer **struct** die **instance** mitzugeben auf die sich die **struct** beziehen soll. 1. Die **instance** kann in dem Item in dem die **struct** referenziert wird, als zusätzliches Attribut definiert werden: @@ -142,7 +141,6 @@ Das kann man auch in der Administrationsoberfläche sehen. .. code-block:: yaml :caption: items/item.yaml - ...: weather_home: struct: darksky.weather@home @@ -152,72 +150,179 @@ Das kann man auch in der Administrationsoberfläche sehen. .. note:: - Wenn man eigene Items in den Teilbaum der durch das Template hinzugefügt wurde einfügen will, muss man für diese + Wenn man eigene Items, in den Teilbaum der durch das Template hinzugefügt wurde, einfügen will, muss man für diese selbst hinzugefügten Items natürlich das Attribut **instance** angeben. -Selbst definierte Item-Strukturen -================================= +struct bei selbst definierte Item-Struktur-Templates +==================================================== -Zusätzlich zu den Item-Strukturen, die Plugins als Template mitbringen, können eigene Strukturen angelegt werden. Diese -Strukturen werden in der Konfigurationdatei **../etc/struct.yaml** abgelegt werden. (Siehe -:doc:`Konfigurationsdateien/struct.yaml `) +Anwendung +--------- -Diese Templates werden mit dem Namen der Struktur ohne einen vorrangestellten Plugin-Namen angegeben: +Eigens definierte Item-Struktur-Templates werden in der Konfigurationdatei **../etc/struct.yaml** abgelegt. + +Hierbei gibt die oberste Ebene den Namen der Templates an. Darunter können Item-Strukturen definiert werden, wie man es +auch in der Item Definition in den items.yaml Dateien machen würde. Das folgende Beispiel zeigt die Definition von zwei +Strukturen (**my_struct_01** und **my_struct_02**): .. code-block:: yaml - :caption: items/item.yaml + :caption: etc/struct.yaml + + my_struct_01: + name: Name der erste eigenen Item Struktur + + item_01: + name: Erstes Item + type: num + ... + item_02: + name: Zweites Item + type: bool + ... + subitem: + name: Sub-Item + type: str + ... + + + my_struct_02: + name: Name der zweiten eigenen Item Struktur + type: bool + + item_a: + name: Item A + type: num + ... + item_b: + name: Item B + type: str + ... + +Wenn jetzt in der Item Definition diese Strukturen referenziert werden: + +.. code-block:: yaml + :caption: items/items.yaml + + my_tree: + my_complex_data: + name: Geänderter Name für meine komplexen Daten + struct: my_struct_01 + + individual_item: + name: Individuelles Item + type: str + ... + - komplexes_item: - struct: meine_struktur +entsteht im Item-Tree die selbe Struktur, als wenn man folgendes direkt in die item.yaml eingetragen hätte: + +.. code-block:: yaml + :caption: items/items.yaml + + my_tree: + name: Geänderter Name für meine komplexen Daten + struct: my_struct_01 + + item_01: + name: Erstes Item + type: num + ... + item_02: + name: Zweites Item + type: bool + ... + subitem: + name: Sub-Item + type: str + ... + individual_item: + name: Individuelles Item + type: str + ... -Eigene Items und Attribute innerhalb der Strukturen -=================================================== +Beim Einfügen der Struktur bleibt das Attribut **struct** erhalten, so dass man zur Laufzeit sehen kann, dass die Struktur zumindest in Teilen aus einem Template stammt. Die Definition des Attributes **name** aus dem Template wird durch die Angabe aus der Datei items/item.yaml ersetzt. Das **individual_item** wird an die Struktur des Templates angefügt. +(Siehe :doc:`Konfigurationsdateien/struct.yaml `) + + +Verschachtelte struct Definitionen (nested structs) +--------------------------------------------------- + +Ab SmartHomeNG v1.7 können Strukturdefinitionen verschachtelt werden. Wie Items, die mithilfe des Attributs **struct:** +auf eine Strukturdefinition verweisen, können dies jetzt auch Strukturen selbst tun. + +In Strukturen wird das **struct** Attribut **nur** auf der obersten Ebene als Referenz ausgewertet. + +SmartHomeNG löst alle Unterstrukturreferenzen vor dem Laden des Item Trees auf, um das Laden der Item Definitionen zu beschleunigen. + +.. note:: -Innerhalb der durch die Templates angelegten Strukturen können in der Item Definition eigene Items und Attribute -angegeben werden. Es ist dabei sogar möglich, Attribute die in den Templates gesetzt wurden zu überschreiben. + Wenn Unterstrukturdefinitionen aufgelöst werden, gibt es zwei Unterschiede zu der Art und Weise, + wie Item Definitionen geladen werden. Die Unterschiede treten nur dann zutage, wenn Strukturen / Unterstrukturen + Attribute re-definieren. (Siehe hierzu auch folgende Kaptiel und :doc:`Konfiguration/structs `) -Wenn ein Attribut in einem **struct** Template und in den Item Definitionen definiert wird, "gewinnt" die Angabe -aus der Item Definition. Regel: "Item wins" +Re-Definieren von Attributen (außer list-Atrributen) +---------------------------------------------------- -Besonderheit bei Attributen, die Listen enthalten -------------------------------------------------- +Beim Definieren von Items ist es möglich, dasselbe Attribut für ein Item in mehreren Item YAML-Dateien zu definieren. +Grundsätzlich werden alle Attribute zu einem Item, dass in mehreren Item YAML-Dateien definiert wurde, gemerged, also zusammengeführt. -Wenn ein Attribut eine Liste enthält, kann das Standardverhalten "Angabe im Item gewinnt" abgeändert werden. -In diesem Fall können die Liste die im Item definiert ist und die Liste die im **struct** Template definiert ist, +.. note:: + + Gibt es eine Attributdefinition an mehreren Stellen, gelten folgende Regeln: + - Beim Lesen der Item Definition gewinnt die Attributdefinition, welche zuletzt eingelesen wird. Regel: **"last wins"** + - In Struktur- /Unterstrukturdefinitionen gewinnt die zuerst eingelesene Attributdefinition. Regel: **"first wins"** + - Wenn ein Attribut in einem struct-Template und in den Item Definitionen definiert wird, "gewinnt" die Angabe aus der + Item Definition. Regel: **"Item wins"** + +Beim Auflösen von Unterstrukturen gewinnt die Definition der Struktur der oberen Ebene, wenn das Attribut +in der Struktur der oberen Ebene vor dem **struct**-Attribut definiert ist. Dies ermöglicht ein "Überschreiben" +von Attributwerten, die in einer Unterstruktur definiert wurden. Wenn das Attribut nach dem +**struct**-Attribut definiert ist, gewinnt die Definition in der Unterstruktur. Regel: **"first wins"** + + +Re-Definieren von list-Attributen +---------------------------------- + +Das Verhalten bei Re-Definieren von list-Attributen ist abhängig von der Anwendung. Zu unterscheiden gilt, ob es + - ein struct in einem Item ist, oder + - ein sub-struct in einem struct. + +.. note:: + Gibt es eine Attributdefinition mit Listen an mehreren Stellen, gelten folgende Regeln: + - Bei structs/substructs werden Listen immer gemergt. + - Bei Items/structs nur, wenn dort Am Anfang einer der Spezialeinträge steht. + + +Verhalten bei struct in einem Item +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Wenn ein Attribut eine Liste enthält, kann das Standardverhalten **"first wins"** in **merge** abgeändert werden. +Es können die Liste, die im Item definiert ist, und die Liste, die im **struct** Template definiert ist, miteinander verbunden werden. Dabei wird die Liste aus dem **struct** Template an die Liste im Item Attribut angehängt. Dazu müssen folgende Voraussetzungen erfüllt sein: - -- Das zu mergende Attribut MUSS vor dem **struct** Attribut definiert werden -- Das zu mergende Attribut MUSS im Item als Liste definiert sein -- Das zu mergende Attribut MUSS im Item als ersten Eintrag **merge\*** oder **merge_unique\*** enthalten - (Der Stern/Asterix muss direkt, ohne Leerzeichen, auf **merge** bzw. **merge_unique** folgen) + - Das zu mergende Attribut MUSS vor dem **struct** Attribut definiert werden + - Das zu mergende Attribut MUSS im Item als Liste definiert sein + - Das zu mergende Attribut MUSS im Item als ersten Eintrag **merge\*** oder **merge_unique\*** enthalten + (Der Stern/Asterix muss direkt, ohne Leerzeichen, auf **merge** bzw. **merge_unique** folgen) Falls der erste Listeintrag **merge\*** ist, bleiben doppelte Listeinträge erhalten. -Verwendung des *struct* Attributes in *struct* Definitionen -=========================================================== - -Innerhalb von **struct** Definitionen kann auf der obersten Ebene das Attribut **struct** angeben werden, um weitere -**struct** Templates in die **struct** einzubinden. - -Unterschiede zum **struct** Attribut in Item Definitionen: +Verhalten bei sub-struct in struct +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Ob bei abweichenden Werten in einem Attribut der Wert der übergeordneten **struct** oder der referenzierten - **struct** "gewinnt", hängt von der Reihenfolge der Definition ab. Falls das entsprechende Attribut vor dem - **struct** Attribut definiert wird, bleibt der Wert der übergeordneten **struct** erhalten. Anderenfalls bleibt - der Wert aus der referenzierten **struct** erhalten. Regel: "first wins" -- Innerhalb der **struct** Definitionen braucht das Attribut **merge\*** nicht angegeben zu werden. - Listen von structs und sub-structs werden standardmäßig gemerged. +Bei der Neudefinition von Attributen, bei denen es sich um Listen handelt, erfolgt kein "Überschreiben". Stattdessen +werden die Listen zusammengefügt. Die Reihenfolge der Listeneinträge wird durch die Reihenfolge bestimmt, in der die +Attributdefinitionen eingelesen werden. Beispiele ========= -Ausführliche Beispiele sind im Abschnitt :doc:`Beispiele ` dieser Dokumentation zu finden. +Ausführliche Beispiele sind im Abschnitt :doc:`Beispiele ` dieser Dokumentation zu finden. \ No newline at end of file diff --git a/doc/user/source/konfiguration/items/standard_attribute/struct.rst b/doc/user/source/konfiguration/items/standard_attribute/struct.rst index 959fbf44ba..1a7c0faefa 100644 --- a/doc/user/source/konfiguration/items/standard_attribute/struct.rst +++ b/doc/user/source/konfiguration/items/standard_attribute/struct.rst @@ -13,21 +13,9 @@ `struct` :bluesup:`Update` -------------------------- -Eine Reihe von Plugins benötigt eine bestimmte Item Struktur bzw. eine größere Zahl an Items um sinnvoll zu funktionieren. -Diese Items müssen dazu innerhalb des Item-Trees als Teilbaum angelegt werden (zum Teil auch mehrfach). - -**Seit SmartHomeNG v1.6** können Plugin jetzt diese Strukturen als Templates zur Verfügung stellen, die dann mit Hilfe -des **struct**-Attributs in den Item-Tree eingefügt werden können. Dazu muss bei dem Item an dessen Stelle der Teilbaum +Über das Attribut **struct** werden vordefinierte Item-Stukturen in den Item-Treee eingefügt. Dazu muss bei dem Item an dessen Stelle der Teilbaum eingefügt werden soll, der Name des Templates (der Item-Struktur) angegeben werden. -Weitere Informationen zu **structs** sind auf der Seite :doc:`Konfiguration/structs ` +Weitere Informationen zu **structs** sind auf der Seite :doc:`Konfiguration/structs ` und :doc:`Konfiguration/Konfigurationsdateien/struct.yaml `) zu finden. - -Selbst definierte Item-Strukturen -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Zusätzlich zu den Item-Strukturen, die Plugins als Template mitbringen, können eigene Strukturen angelegt werden. Diese -Strukturen werden in der Konfigurationdatei **../etc/struct.yaml** abgelegt werden. -(Siehe :doc:`Konfiguration/Konfigurationsdateien/struct.yaml `) - diff --git a/doc/user/source/konfiguration/konfigurationsdateien/struct.rst b/doc/user/source/konfiguration/konfigurationsdateien/struct.rst index d9a14330eb..cc7dbb7656 100644 --- a/doc/user/source/konfiguration/konfigurationsdateien/struct.rst +++ b/doc/user/source/konfiguration/konfigurationsdateien/struct.rst @@ -16,133 +16,3 @@ Template verwendet werden können. der Entwicklerdokumentation unter **Development of Plugins** / **Plugin Metadata** zu finden. -Hierbei gibt die oberste Ebene den Namen der Templates an. Darunter können Item Strukturen definiert werden, wie man es -auch in der Item Definition in den items.yaml Dateien machen würde. Das folgende Beispiel zeigt die Definition von zwei -Strukturen (**my_struct_01** und **my_struct_02**): - -.. code-block:: yaml - :caption: etc/struct.yaml - - my_struct_01: - name: Name der Item Struktur - - item_01: - name: Erstes Item - type: num - ... - item_02: - name: Zweites Item - type: bool - ... - subitem: - name: Sub-Item - type: str - ... - - - my_struct_02: - name: Name der zweiten Item Struktur - type: bool - - item_a: - name: Item A - type: num - ... - item_b: - name: Item B - type: str - ... - -Wenn jetzt in der Item Definition diese Strukturen referenziert werden: - -.. code-block:: yaml - :caption: items/items.yaml - - my_tree: - my_complex_data: - name: Geänderter Name für meine komplexen Daten - struct: my_struct_01 - - individual_item: - name: Individuelles Item - type: str - ... - - -entsteht im Item-Tree die selbe Struktur, als wenn man folgendes direkt in die item.yaml eingetragen hätte: - -.. code-block:: yaml - :caption: items/items.yaml - - my_tree: - name: Geänderter Name für meine komplexen Daten - struct: my_struct_01 - - item_01: - name: Erstes Item - type: num - ... - item_02: - name: Zweites Item - type: bool - ... - subitem: - name: Sub-Item - type: str - ... - individual_item: - name: Individuelles Item - type: str - ... - - -Beim Einfügen der Struktur bleibt das Attribut **struct** erhalten, so dass man zur Laufzeit sehen kann, dass die Struktur -zumindest in Teilen aus einem Template stammt. - -Der Name, der im Template bereits angegeben war, wird durch die Angabe au der Datei items/item.yaml ersetzt. - -Das **individual_item** wird in die Struktur des Templates eingefügt. - - -.. index:: structs; Verschachtelte structs - -Verschachtelte struct Definitionen ----------------------------------- - -Ab SmartHomeNG v1.7 können Strukturdefinitionen verschachtelt werden. Wie Items, die mithilfe des Attributs **struct:** -auf eine Strukturdefinition verweisen, können dies jetzt auch Strukturen tun. - -In Strukturen wird das **struct** Attribut **nur** auf der obersten Ebene als Referenz ausgewertet. - -SmartHomeNG löst alle Unterstrukturreferenzen vor dem Laden des Item Trees auf, um das Laden der Item Definitionen -zu beschleunigen. - -.. note:: - - Bitte beachten: Wenn Unterstrukturdefinitionen aufgelöst werden, gibt es zwei Unterschiede zu der Art und Weise, - wie Item Definitionen geladen werden. Die Unterschiede treten nur dann zutage, wenn Strukturen / Unterstrukturen - Attribute re-definieren. (Siehe hierzu auch :doc:`Konfiguration/structs ` - - -Re-Definieren von Attributen -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Beim Definieren von Items ist es möglich, dasselbe Attribut für ein Item in mehreren Item YAML-Dateien zu definieren. -Beim Lesen der Item Definition gewinnt die Attributdefinition, welche zuletzt eingelesen wird. In Struktur- / -Unterstrukturdefinitionen gewinnt die zuerst eingelesene Attributdefinition. - -Beim Auflösen von Unterstrukturen sollte normalerweise die Definition der Struktur der oberen Ebene gewinnen. Dies -ermöglicht ein "Überschreiben" von Attributwerten, die in einer Unterstruktur definiert wurden. Dazu muss das Attribut -in der Struktur der oberen Ebene vor dem **struct**-Attribut definiert werden. Wenn das Attribut nach dem -**struct**-Attribut definiert ist, gewinnt die Definition in der Unterstruktur. Regel: "first wins" - - -Re-Definieren von list-Attributen -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Bei der Neudefinition von Attributen, bei denen es sich um Listen handelt, erfolgt kein "Überschreiben". Stattdessen -werden die Listen zusammengefügt. Die Reihenfolge der Listeneinträge wird durch die Reihenfolge bestimmt, in der die -Attributdefinitionen eingelesen werden. - - - From e2af57be34cdc93fbcf3267ab66ed69785353008 Mon Sep 17 00:00:00 2001 From: Bernd Meiners Date: Fri, 17 Apr 2020 08:18:23 +0200 Subject: [PATCH 006/126] fixes wrong description of knxd router setup in komplettanleitung --- doc/user/source/installation/komplettanleitung/05_knxd.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/user/source/installation/komplettanleitung/05_knxd.rst b/doc/user/source/installation/komplettanleitung/05_knxd.rst index 60ba25b680..c8f0ee3da0 100644 --- a/doc/user/source/installation/komplettanleitung/05_knxd.rst +++ b/doc/user/source/installation/komplettanleitung/05_knxd.rst @@ -129,7 +129,8 @@ Der Parameter **-c** stellt den knxd so ein, das er einen Cache nutzt. Danach fo die Verwendung der Schnittstelle: - IP Schnittstelle: ``KNXD_OPTS="-e 0.0.1 -E 0.0.2:8 -c -b ipt:"`` -- IP Router: ``KNXD_OPTS="-e 0.0.1 -E 0.0.2:8 -c -b ip:"`` +- IP Router: ``KNXD_OPTS="-e 0.0.1 -E 0.0.2:8 -c -b ip:"`` +- IP Router: ``KNXD_OPTS="-e 0.0.1 -E 0.0.2:8 -c -b ip:"`` - USB-Interface: Bitte `Wiki zum knxd `__ konsultieren. Es kann sein, das bei ``KNXD_OPTS`` hinter dem **-c** bei einigen Interfaces noch ein ``--send-delay=30`` eingefügt From e7b1d52938f7746113236138fb9f37e2a22dec7f Mon Sep 17 00:00:00 2001 From: bmxp Date: Sat, 18 Apr 2020 08:26:11 +0200 Subject: [PATCH 007/126] provide knxuf logos --- media/logo_Forum_blue.png | Bin 0 -> 1221 bytes media/logo_Forum_blue.svg | 133 ++++++++++++++++++++++++++++++++++++++ media/logo_Forum_gray.png | Bin 0 -> 1230 bytes media/logo_Forum_gray.svg | 133 ++++++++++++++++++++++++++++++++++++++ media/readme.md | 5 ++ 5 files changed, 271 insertions(+) create mode 100644 media/logo_Forum_blue.png create mode 100644 media/logo_Forum_blue.svg create mode 100644 media/logo_Forum_gray.png create mode 100644 media/logo_Forum_gray.svg create mode 100644 media/readme.md diff --git a/media/logo_Forum_blue.png b/media/logo_Forum_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..3d9be0955cbae47eaa90b57084bca0818e5f97a2 GIT binary patch literal 1221 zcmV;$1UmbPP)$|@2gWvBt=RBWtp6BW$OTR1!}x%8XG4w zZ|-GZQ2W{aNl7kO%TC~FQ96>Es=N69^B1#yAKl{3NeOQuYyi$EG{hsJAMObL*w&WW zNp*IkybPSRDh(H!gWun(8o%4RL@-UjGK6-Ev*SW|&99S!R|LJn{!(fL-UJ2}_QbF7 z9&Mr2t-$|DCE&Ji1U&#u7xdsjksRnb6zZQ4UhYPpvq+Ob8A!7@gS)y9Z}@xi&`d4b zetcRYQM5ymoj@#<1XCm@=JKjM0eExZG)5Tyg3ZRkF{Hg>1bZ27Cbhs0qI!bXMD zj+pxM;mXqzsExjhiVK`m)ot&bft(K0u~|~@rgCRgRL){HS@^H#%Ge{ zbtj6f?OP?VSfE5zucKTsMt><(Inx;l-55P#d2Qh6*N-Iz{LGmdTSsf1tJJK<(*9uetAY6)tLl0*M1zhhkFl+cr zkH;caF9P_|71Vj9nxX@kkz?f?W0{h}ep^bzNooj@82}<&MRk)&rcMDQ3k&BNt4kGK zYt`Dk!>tkj@BsiU-*z`weKE?f7x)o~fXdBP&Kq3d^38V@p7pzJyB$*A`N-OHnIY*E z$4Ze!+mBDn9_~ww-$_To%?ZWs1qy(vf;L)AW5D&U0VhS|%c)cPTYh@`g}xlc%@w`Fza**XseUUxV3#-Z#qU + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/media/logo_Forum_gray.png b/media/logo_Forum_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..4dfe3e002529a5e662860ad6fe331f092193c0e1 GIT binary patch literal 1230 zcmV;<1Tp)GP)!hNf z4%!FNJSY@G+k0=ek`-KEwn<|_912}m3C+1TQqlFLZV%G=G8|-#RuShM!?A~|xQ8}# zG-OuYa=G{Zd}tDHW16;Ws`!QbaDVxp^ZT4%e&?J7*nkp=gg=o;_%||#yqZA>5$o*i zbf>1K=87?9rcfyKx+F=TOOn*z(b2Kk($aD%olf(50i-o}-e%_KJV336VSEK(62KJz z-vJQ8U~onV(Yjs$TFoGYxXH{zb#-;8ZQC9M&;wwWh~83F^$Y+clgSr|XavAx08YuW zJkZnA^UGQQR;_?6%Lj=_wr%?wfG{&3ZfzZs z!wsv=U$p|sWU`~MvWEanxUPFB8jb#1ZA>bay3cW(K>+&!WSIGgrfHuNQN{kK2wA;cp9jstiZz5B6TqLgZ7&1@frW55?9>9pG|i`(`2;iPNCuKSZGG^(oVVZ$)C`ZP_urD!cC zi1rfE9RMW&W|pwjH$^Gs16|iG_iQO_%Uix;B$-UMlqJ6m;0%DUcLR8K1-QFb z34n<9dg3?o`Fv|E7R!6hg;GATDF9f0EGx1sHv`Cc&4vAYc2fYD`3IuXxzz0Q`DTR> z=ZNTQ05fxQbJOv7++M?+?Lvt6ya6I=WUhQumjE)E%-K*VG|kLyg-|1aPG;@|fM76~ z6GBWVigGj(iR7vPJX3f|S}8f;DSJE~cV$_Ag@}>>ZddSb18~5ytc&C0V6MO9U!4Gj(3iRd+EK7pm(;MK#HWxZKt&XYvcUiQ4YlG#@&*wxkb2Y}Os2V-Mn z?UE#YiNAls?WqEAT~*cd-az39uBcK4Ow)YaFpMWFnWE8X8bG%APDB;K??&ET(8A0g z8HO><%o9ZPt!>*2KA&$ZGj{{n?iqKb<^Ud$HUMqR3|W>db#T_Qtdq3@@HXK!BKih^ zTg5*MU|(Nf-$JbbN);$v#jQe!`OTkg3s11X8hx0{Pyhe`07*qoM6N<$f;`$i^Z)<= literal 0 HcmV?d00001 diff --git a/media/logo_Forum_gray.svg b/media/logo_Forum_gray.svg new file mode 100644 index 0000000000..4908413236 --- /dev/null +++ b/media/logo_Forum_gray.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/media/readme.md b/media/readme.md new file mode 100644 index 0000000000..7d4505a442 --- /dev/null +++ b/media/readme.md @@ -0,0 +1,5 @@ +# Notes on Media + +The font used for the logo was Browallia New Bold. + +For the Forum Logo the Blue was set dark and with no transparency at all. From 94830a34e2c9c98b35201dd2b36075dea2801da5 Mon Sep 17 00:00:00 2001 From: bmxp Date: Sat, 18 Apr 2020 08:27:57 +0200 Subject: [PATCH 008/126] display version of SmartHomeNG as well to easy bug tracking --- lib/metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/metadata.py b/lib/metadata.py index 2e8d0d939b..2669642fab 100755 --- a/lib/metadata.py +++ b/lib/metadata.py @@ -376,11 +376,11 @@ def test_shngcompatibility(self): if min_shngversion != '': if min_shngversion > shng_version: - logger.error("{0} '{1}': The version of SmartHomeNG is too old for this {0}. It requires at least version v{2}. The {0} was not loaded.".format(self._addon_type, self._addon_name, min_shngversion)) + logger.error("{0} '{1}': The version {3} of SmartHomeNG is too old for this {0}. It requires at least version v{2}. The {0} was not loaded.".format(self._addon_type, self._addon_name, min_shngversion, shng_version)) return False if max_shngversion != '': if max_shngversion < shng_version: - logger.error("{0} '{1}': The version of SmartHomeNG is too new for this {0}. It requires a version up to v{2}. The {0} was not loaded.".format(self._addon_type, self._addon_name, max_shngversion)) + logger.error("{0} '{1}': The version {3} of SmartHomeNG is too new for this {0}. It requires a version up to v{2}. The {0} was not loaded.".format(self._addon_type, self._addon_name, max_shngversion, shng_version)) return False return True From b45914f7bff962e217780d84d8360f8b3f1a42ac Mon Sep 17 00:00:00 2001 From: bmxp Date: Sat, 18 Apr 2020 08:30:25 +0200 Subject: [PATCH 009/126] add a header to requirements/test.txt --- requirements/test.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/requirements/test.txt b/requirements/test.txt index da541d105c..6694f6d722 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,3 +1,13 @@ +# +--------------------------------------------------+ +# | SmartHomeNG | +# | This file contains all | +# | requirements needed for | +# | automated testing | +# | by travis/tox/pytest | +# | | +# | INSTALL WITH: | +# | pip3 install -r requirements/test.txt --user | +# +--------------------------------------------------+ flake8>=2.5.1 pylint>=1.5.3 From 36bc5c4e8f128185a56ff61dbecea08b2dafd02a Mon Sep 17 00:00:00 2001 From: msinn Date: Sat, 18 Apr 2020 10:02:19 +0200 Subject: [PATCH 010/126] tools: Bugfix in plugin_metadata_checker when checking parameters for mandatory and default parameters --- tools/plugin_metadata_checker.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/plugin_metadata_checker.py b/tools/plugin_metadata_checker.py index fdf4cc1b56..7817efe2c4 100644 --- a/tools/plugin_metadata_checker.py +++ b/tools/plugin_metadata_checker.py @@ -32,7 +32,7 @@ import os import argparse -VERSION = '1.7.1' +VERSION = '1.7.2' print('') print(os.path.basename(__file__) + ' v' + VERSION + ' - Checks the care status of plugin metadata') @@ -591,7 +591,7 @@ def check_metadata(plg, with_description, check_quiet=False, only_inc=False, lis if not is_dict(par_dict): disp_error("Definition of parameter '{}' is not a dict".format(par), '') else: - if par_dict.get('mandatory', None) != None and par_dict.get('mandatory', None) != None: + if par_dict.get('mandatory', None) != None and par_dict.get('default', None) != None: disp_error("parameter '{}': mandatory and default cannot be used together".format(par), "If mandatory and a default value are specified togeather, mandatory has no effect, since a value for the parameter is already specified (the default value).") test_description('parameter', par, par_dict.get('description', None)) @@ -602,7 +602,7 @@ def check_metadata(plg, with_description, check_quiet=False, only_inc=False, lis if not is_dict(par_dict): disp_error("Definition of item_attribute '{}' is not a dict".format(par), '') else: - if par_dict.get('mandatory', None) != None and par_dict.get('mandatory', None) != None: + if par_dict.get('mandatory', None) != None and par_dict.get('default', None) != None: disp_error("item '{}': mandatory and default cannot be used together".format(par), "If mandatory and a default value are specified togeather, mandatory has no effect, since a value for the parameter is already specified (the default value).") test_description('item attribute', par, par_dict.get('description', None)) From f49e8c28718f2a8e03dc42297e893a5dbf37bf5e Mon Sep 17 00:00:00 2001 From: bmxp Date: Sat, 18 Apr 2020 10:23:31 +0200 Subject: [PATCH 011/126] fixes a copy & paste a bug in core mock --- tests/mock/core.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/mock/core.py b/tests/mock/core.py index b684ea2e85..c5677b0e6e 100644 --- a/tests/mock/core.py +++ b/tests/mock/core.py @@ -80,7 +80,7 @@ class MockSmartHome(): def __init__(self): - VERSION = '1.4c.' + VERSION = '1.7a.' VERSION += '0.man' self.version = VERSION self.__logs = {} @@ -176,7 +176,8 @@ def return_items(self): return self.items.return_items() def return_plugins(self): - return self.plugins.get_module(name) + #return self.plugins.get_module(name) ??? + return self.plugins def return_modules(self): return self.modules.return_modules() From 7d46fda71eaa82d85702a53970859c15d34e6f1b Mon Sep 17 00:00:00 2001 From: bmxp Date: Sat, 18 Apr 2020 12:21:34 +0200 Subject: [PATCH 012/126] changes to enable travis/tox test environment to pass checks --- .gitignore | 13 +- .travis.sh | 17 +- .travis.yml | 4 + lib/shpypi.py | 39 +++- tests/howto_test_smarthomeng.rst | 300 +++++++++++++++++++++++++++++++ tests/test_logics.py | 6 + tools/build_requirements.py | 9 + tox.ini | 15 +- 8 files changed, 382 insertions(+), 21 deletions(-) create mode 100644 tests/howto_test_smarthomeng.rst diff --git a/.gitignore b/.gitignore index 22050277e8..bfe2a21db4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ .tox nosetests.xml *.egg-info +test.cache +/.pytest_cache # OSX specific files .DS_Store @@ -30,12 +32,16 @@ Thumbs.db /doc/developer/build /doc/developer/source/plugins_doc -# Don't check in plugins to core reository +# Don't check in plugins to core repository /plugins -# don't check in Requirements for actual configured plugins +# don't check in requirements for actual configured plugins requirements/conf_all.txt +# don't check in requirements that are built each time SHNG starts +requirements/all.txt +requirements/base.txt + # don't check in directories under /var beside listed exeptions /var !/var/backup @@ -45,7 +51,8 @@ requirements/conf_all.txt !/var/rrd !/var/run -# Pycharm settings +# ignore users tools settings /.idea +/.vscode /custom_plugins diff --git a/.travis.sh b/.travis.sh index c17922bd88..b83eb7398f 100755 --- a/.travis.sh +++ b/.travis.sh @@ -31,20 +31,23 @@ LINKS="smarthome/plugins/plugins" # Get the current repository which is processed REPOSITORY="$(basename $TRAVIS_REPO_SLUG)" +REPO_OWNER="$(dirname $TRAVIS_REPO_SLUG)" REPOSITORY_ORIGIN="$REPOSITORY_ORIGIN" # Find out on which branch to work -if [ "$TRAVIS_BRANCH" = "master" ] ; then - REPOSITORY_BRANCH="master" -else - REPOSITORY_BRANCH="develop" -fi +#if [ "$TRAVIS_BRANCH" = "master" ] ; then +# REPOSITORY_BRANCH="master" +#else +# REPOSITORY_BRANCH="develop" +#fi +REPOSITORY_BRANCH=$TRAVIS_BRANCH +echo -e "Current branch for $REPOSITORY is $REPOSITORY_BRANCH" ####################################################################### # 1. Checkout all repositories -echo -e "travis_fold:start:Checkout\nChecking out repositories with $REPOSITORY_BRANCH branch" +echo -e "travis_fold:start:Checkout\nChecking out additional repositories with $REPOSITORY_BRANCH branch" # Change to root directory since script is started in checkout cd $TRAVIS_BUILD_DIR/.. @@ -53,7 +56,7 @@ cd $TRAVIS_BUILD_DIR/.. for REPO in $REPOSITORIES ; do if [ "$REPO" != "$REPOSITORY_ORIGIN" ] ; then echo "Checking out $REPO ..." - git clone https://github.com/smarthomeNG/$REPO.git $REPO + git clone https://github.com/$REPO_OWNER/$REPO.git $REPO cd $REPO git checkout $REPOSITORY_BRANCH cd .. diff --git a/.travis.yml b/.travis.yml index e0638b0553..c0132c95bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,10 @@ jobs: - python: 3.7 dist: xenial +# need to allow ruamel.yaml higher than 0.15.74 to support Python 3.8 +# - python: 3.8 +# dist: xenial + env: - REPOSITORY_ORIGIN=smarthome diff --git a/lib/shpypi.py b/lib/shpypi.py index a6e5e70d80..9de11fbfa5 100644 --- a/lib/shpypi.py +++ b/lib/shpypi.py @@ -69,6 +69,7 @@ def __init__(self, sh=None, base=None): self.sh = sh if sh is None: + self.logger.debug("SmartHomeNG is None") if base: self._sh_dir = base self._error = False @@ -76,6 +77,7 @@ def __init__(self, sh=None, base=None): self._sh_dir = sh.get_basedir() # anders bestimmen für tools/build_requirements.py self._error = False + self.logger.debug("SmartHomeNG is using '{}' as base directory".format(self._sh_dir)) return @@ -900,6 +902,7 @@ def __init__(self): self._conf_plugin_files = [] self.sh_basedir = os.sep.join(os.path.realpath(__file__).split(os.sep)[:-2]) + self.logger.debug("Requirements_files is using '{}' as base directory".format(self.sh_basedir)) return @@ -992,14 +995,27 @@ def _build_packagelist(self, requirements): def _get_filelist(self, selection): - + """ + returns a list of files with all paths for a requirements.txt within a + certain selection subpath. + Currently selection is one of 'modules', 'lib', 'plugins' + When testing with travis the self.sh_basedir will be something like "/home/travis/build//smarthome" + On a native Linux without specialities this is normally "/usr/local/smarthome" + When inspecting the plugins then all requirements.txt for previous plugin versions should be omitted from the list. + The names of previous plugins subdirectories start with "_pv" + """ + self.logger.debug("_get_filelist for '{}'".format(selection)) file_list = [] + basedir_level = self.sh_basedir.count(os.sep) for root, dirnames, filenames in os.walk(self.sh_basedir + os.sep + selection): level = root.count(os.sep) - if level < 6: # don't search for requirements in _pv (previous versions) + #self.logger.debug("level = {}: root = {}".format(level, root)) + if (selection == "plugins" and "_pv" not in root) or (level < basedir_level + 3): for filename in fnmatch.filter(filenames, 'requirements.txt'): # print("level = {}: root = {}".format(level, root)) file_list.append(os.path.join(root, filename)) + self.logger.debug("found '{}'".format(os.path.join(root, filename))) + self.logger.debug("_get_filelist found '{}'".format(file_list)) return file_list @@ -1153,13 +1169,17 @@ def _write_resultfile(self, selection, packagelist_consolidated, requirements): filename = 'requirements' + os.sep + selection + '.txt' complete_filename = self.sh_basedir + os.sep + filename - with open(complete_filename, 'w') as outfile: - self._write_header(outfile, filename) - - for pkg in packagelist_consolidated: - for req in pkg['used_by']: - outfile.write('# {}\n'.format(req)) - outfile.write('{}\n\n'.format(pkg['requests'])) + + if len(packagelist_consolidated) > 0: + with open(complete_filename, 'w') as outfile: + self._write_header(outfile, filename) + + for pkg in packagelist_consolidated: + for req in pkg['used_by']: + outfile.write('# {}\n'.format(req)) + outfile.write('{}\n\n'.format(pkg['requests'])) + else: + self.logger.error("Req_files: _consolidate_requirements: packagelist_consolidated is empty".format()) return complete_filename @@ -1184,6 +1204,7 @@ def create_requirementsfile(self, selection): # build list of all packages selection = selection.lower() + self.logger.debug("create_requirementsfile for '{}'".format(selection)) self._build_filelists(selection) requirements = self.__read_requirementfiles() diff --git a/tests/howto_test_smarthomeng.rst b/tests/howto_test_smarthomeng.rst new file mode 100644 index 0000000000..8c6df7a895 --- /dev/null +++ b/tests/howto_test_smarthomeng.rst @@ -0,0 +1,300 @@ +Testing SmartHomeNG +=================== + +As many Python projects SmartHomeNG also has quite a couple of test to check +parts of the core and some plugins functionality. + +The tests are created as unittest Testcases. The tests for the core can be found in ``tests/`` + +The requirements to run tests are found in ``requirements/test.txt`` and can be installed +using ``pip3 install -r requirements/test.txt --user`` + +To **run a full test** for SmartHomeNG start ``pytest -v`` +in the home directory of SmartHomeNG (normally ``/usr/local/smarthome``) + +With the above statement pytest will search all subdirectories for test cases. + +If **only a test for a specific plugin** should be run, then the command ``pytest -v ../plugin/`` +needs to be called from within the tests directory (normally ``/usr/local/smarthome/tests``) + +Pytest will also use the settings from tox.ini but additionally to the test directories the ``tests`` +directory will be included in the search path. If this would not be the case, then all common definitions +could not be used by the test. + +Create tests for a plugin +========================= + +1. create a subdirectory named ``tests`` within your plugin. +2. Create a test case in a file starting with ``test_`` like ``test_calculations.py``. + Otherwise pytest can not find it. There is a sample included within the ``dev\sample_plugin\tests`` + which can be used for scaffolding. +3. Add tests to your testclass that start with ``test`` as method names +4. Run the tests from + and have them successfullefor your plugin before you push to the develop branch + +Test discovery with pytest +========================== + +pytest implements the following standard test discovery: + +* If no arguments are specified then collection starts from testpaths (if configured) or the current directory. + Alternatively, command line arguments can be used in any combination of directories, file names or node ids. +* Recurse into directories, unless they match norecursedirs. +* In those directories, search for ``test_*.py`` or ``*_test.py`` files, imported by their test package name. +* From those files, collect test items: + * test prefixed test functions or methods outside of class + * test prefixed test functions or methods inside Test prefixed test classes (without an __init__ method) + +Within Python modules, pytest discovers tests using the standard ``unittest.TestCase`` subclassing technique. + +Pytest will look inside ``tox.ini`` to find out the files to use for test cases. + +.. code:: ini + + [tox] + ;envlist = py34, lint + ; tox roughly follows the following phases: + ; 1. configuration: + ; load tox.ini and merge it with options from the command line and the operating system environment variables. + ; 2. packaging (optional): + ; create a source distribution of the current project by invoking ``python setup.py sdist`` + ; Note that for this operation the same Python environment will be used as the one tox is + ; installed into (therefore you need to make sure that it contains your build dependencies). + ; Skip this step for application projects that don’t have a setup.py. + ; 3. environment - for each tox environment (e.g. py27, py36) do: + ; a. environment creation: + ; create a fresh environment, by default virtualenv is used. + ; tox will automatically try to discover a valid Python interpreter version by + ; using the environment name (e.g. py27 means Python 2.7 and the basepython configuration value) + ; and the current operating system PATH value. + ; This is created at first run only to be re-used at subsequent runs. + ; If certain aspects of the project change, a re-creation of the environment is + ; automatically triggered. To force the recreation tox can be invoked with -r/--recreate. + ; b. install (optional): + ; install the environment dependencies specified inside the deps configuration section, + ; and then the earlier packaged source distribution. + ; By default pip is used to install packages, however one can customise this + ; via install_command. Note pip will not update project dependencies + ; (specified either in the install_requires or the extras section of the setup.py) + ; if any version already exists in the virtual environment; therefore we recommend + ; to recreate your environments whenever your project dependencies change. + ; c. commands: + ; run the specified commands in the specified order. Whenever the exit code + ; of any of them is not zero stop, and mark the environment failed. + ; Note, starting a command with a single dash character means ignore exit code. + ; 6. report print out a report of outcomes for each tox environment: + + + ; To run tests on Travis CI add the environments to the .travis.yml too! + envlist = py35, py36, py37 + skip_missing_interpreters = True + + ; do not execute a ``python setup.py sdist`` + skipsdist=True + + [pytest] + testpaths = tests plugins + python_files = test_*.py + python_functions = test_ + python_classes = Test + + [testenv] + ; 3a + setenv = + LANG=de_DE.utf8 + TZ=UTC + PYTHONPATH ={toxinidir}{:}{toxinidir}/tests{:}{toxinidir}/lib{:}{toxinidir}/bin + ; update pip/wheel/setuptools etc. + download=true + ; prevent warnings + whitelist_externals = + head + + ; 3b + deps = + -r{toxinidir}/requirements/test.txt + ; 3c + ; python3 tools/build_requirements.py -debug_tox for debugging build_requirements.py and lib/shpypi.py + commands = + python3 tools/build_requirements.py + head {toxinidir}/requirements/base.txt -n 12 + head {toxinidir}/requirements/all.txt -n 12 + pip install -r {toxinidir}/requirements/base.txt + pip install -r {toxinidir}/requirements/all.txt + py.test -v --ignore=./plugins/database/tests --timeout=30 --cov --cov-report= {posargs} + + #[testenv:py35] + #basepython = python3.5 + + #[testenv:py36] + #basepython = python3.6 + + #[testenv:py37] + #basepython = python3.7 + + #[testenv:py38] + #basepython = python3.8 + # there is no ruamel.yaml version 0.15.74 which is compatible with Python 3.8 as of April 13th, 2020 + + [testenv:lint] + basepython = python3 + ignore_errors = True + commands = + flake8 + pylint bin/smarthome.py + pydocstyle tests + + + +Continuous integration test with Travis CI +========================================== + +At `https://travis-ci.org/github/smarthomeNG/smarthome`_ the last test results can be seen. +The actions that Travis will perform each time a new commit is pushed to the SmartHomeNG repository are +declared in ``.travis.yml`` and ``.travis.sh``. + +.. code:: yaml + + language: python + + jobs: + include: + - python: 3.5 + - python: 3.6 + - python: 3.7 + dist: xenial + + # need to allow ruamel.yaml higher than 0.15.74 to support Python 3.8 + # - python: 3.8 + # dist: xenial + + env: + - REPOSITORY_ORIGIN=smarthome + + before_install: + - sudo apt-get install libudev-dev + - sudo apt-get install librrd-dev libpython3-dev + install: + - pip install tox-travis virtualenv + - pip install sphinx sphinx_rtd_theme recommonmark + + script: + - sh .travis.sh + + +.. code:: bash + + ####################################################################### + # Travis-CI script + # + # This script will checkout all required reqository to run the + # suite. + # + # The following configuration settings are available: + # * Environment settings: + # - REPOSITORY_ORIGIN: defines the current repos origin (e.g. + # "smarthome" or "plugins") + # * Script settings: + # - REPOSITORIES: List of repositories to checkout from smarthomeNG + # organization (e.g. "https://github.com/smarthomeNG/") + # - LINKS: Contains a list of links to create before running the + # suite (e.g. "//") + # * Script variables: + # - REPOSITORY: The name of the current repository + # - REPOSITORY_ORIGIN: The origin repository from environment setting + # - REPOSITORY_BRANCH: The branch to use for checkouts + + echo -e "travis_fold:start:Environment\nEnvironment dump" + set + export + echo "travis_fold:end:Environment" + + ####################################################################### + # Declare some common variables + + REPOSITORIES="smarthome plugins" + LINKS="smarthome/plugins/plugins" + + # Get the current repository which is processed + REPOSITORY="$(basename $TRAVIS_REPO_SLUG)" + REPO_OWNER="$(dirname $TRAVIS_REPO_SLUG)" + REPOSITORY_ORIGIN="$REPOSITORY_ORIGIN" + + # Find out on which branch to work + #if [ "$TRAVIS_BRANCH" = "master" ] ; then + # REPOSITORY_BRANCH="master" + #else + # REPOSITORY_BRANCH="develop" + #fi + + REPOSITORY_BRANCH=$TRAVIS_BRANCH + echo -e "Current branch for $REPOSITORY is $REPOSITORY_BRANCH" + + ####################################################################### + # 1. Checkout all repositories + + echo -e "travis_fold:start:Checkout\nChecking out additional repositories with $REPOSITORY_BRANCH branch" + + # Change to root directory since script is started in checkout + cd $TRAVIS_BUILD_DIR/.. + + # Check out other repositories with develop version + for REPO in $REPOSITORIES ; do + if [ "$REPO" != "$REPOSITORY_ORIGIN" ] ; then + echo "Checking out $REPO ..." + git clone https://github.com/$REPO_OWNER/$REPO.git $REPO + cd $REPO + git checkout $REPOSITORY_BRANCH + cd .. + fi + done + + echo "travis_fold:end:Checkout" + + + ####################################################################### + # 2. Create symlinks in repositories + + echo -e "travis_fold:start:Links\nCreating symlinks" + + # Create symlinks in core repository + for LINK in $LINKS ; do + TARGET=$(dirname "$LINK") + TARGET_REPO=$(dirname "$TARGET") + TARGET_DIR=$(basename "$TARGET") + SOURCE_REPO=$(basename "$LINK") + + echo "Create link from $SOURCE_REPO to $TARGET_REPO/$TARGET_DIR ..." + cd $TARGET_REPO + rm -rf $TARGET_DIR + ln -s ../$SOURCE_REPO $TARGET_DIR + cd .. + done + + echo "travis_fold:end:Links" + + + ####################################################################### + # 3. Run + + echo -e "travis_fold:start:Suite\nRunning suite" + + cd smarthome + #echo "would run tox now" + tox || exit 1 + cd .. + + echo "travis_fold:end:Suite" + + + ####################################################################### + # 4. Docs + + echo -e "travis_fold:start:Docs\nBuilding documentation" + + cd smarthome/doc + #yes | bash build_doc.sh + echo "would build docs here" + cd ../.. + + echo "travis_fold:end:Docs" diff --git a/tests/test_logics.py b/tests/test_logics.py index 33cbffbed3..ac7438f69e 100755 --- a/tests/test_logics.py +++ b/tests/test_logics.py @@ -25,6 +25,7 @@ import unittest import logging import shutil +import os from lib.model.smartplugin import SmartPlugin from lib.logic import Logics @@ -46,6 +47,11 @@ def test_00_begin(self): def test_99_end(self): logger.warning('') + logger.warning('Tidy up') + logger.warning("remove '{}'".format(self.sh._logic_conf_basename+'.yaml')) + os.remove(self.sh._logic_conf_basename+'.yaml') + logger.warning("remove '{}'".format(self.sh._logic_conf_basename+'.yaml.bak')) + os.remove(self.sh._logic_conf_basename+'.yaml.bak') logger.warning('=== End Logic Tests') diff --git a/tools/build_requirements.py b/tools/build_requirements.py index 63893abb7f..7753e27670 100644 --- a/tools/build_requirements.py +++ b/tools/build_requirements.py @@ -39,6 +39,15 @@ sh_basedir = os.sep.join(os.path.realpath(__file__).split(os.sep)[:-2]) sys.path.insert(0, sh_basedir) +program_name = sys.argv[0] +arguments = sys.argv[1:] +if "-debug_tox" in arguments: + import logging + logging.basicConfig(level=logging.DEBUG) + logger = logging.getLogger('build_requirements') + logger.setLevel(logging.DEBUG) + logger.debug("sys.path = {}".format(sys.path)) + import lib.shpypi as shpypi diff --git a/tox.ini b/tox.ini index e431488c63..c5e94bd123 100644 --- a/tox.ini +++ b/tox.ini @@ -53,12 +53,20 @@ setenv = PYTHONPATH ={toxinidir}{:}{toxinidir}/tests{:}{toxinidir}/lib{:}{toxinidir}/bin ; update pip/wheel/setuptools etc. download=true +; prevent warnings +whitelist_externals = + head + ; 3b deps = -r{toxinidir}/requirements/test.txt - -r{toxinidir}/requirements/base.txt ; 3c +; python3 tools/build_requirements.py -debug_tox for debugging build_requirements.py and lib/shpypi.py commands = + python3 tools/build_requirements.py + head {toxinidir}/requirements/base.txt -n 12 + head {toxinidir}/requirements/all.txt -n 12 + pip install -r {toxinidir}/requirements/base.txt pip install -r {toxinidir}/requirements/all.txt #py.test -v --timeout=30 --cov --cov-report= {posargs} py.test -v --ignore=./plugins/database/tests --timeout=30 --cov --cov-report= {posargs} @@ -69,9 +77,12 @@ commands = #[testenv:py36] #basepython = python3.6 -#[testenv:py36] +#[testenv:py37] #basepython = python3.7 +#[testenv:py38] +#basepython = python3.8 +# there is no ruamel.yaml version 0.15.74 which is compatible with Python 3.8 as of April 13th, 2020 [testenv:lint] basepython = python3 From b5a23dfdcc83aaba71d3230b6c2e8e1c14c6f04b Mon Sep 17 00:00:00 2001 From: bmxp Date: Sat, 18 Apr 2020 12:24:23 +0200 Subject: [PATCH 013/126] removed files that are rebuild automatically --- requirements/all.txt | 172 --------------------------------- requirements/base.txt | 45 --------- tests/resources/etc/logic.yaml | 30 ------ 3 files changed, 247 deletions(-) delete mode 100644 requirements/all.txt delete mode 100644 requirements/base.txt delete mode 100755 tests/resources/etc/logic.yaml diff --git a/requirements/all.txt b/requirements/all.txt deleted file mode 100644 index 198b65d612..0000000000 --- a/requirements/all.txt +++ /dev/null @@ -1,172 +0,0 @@ - -# +--------------------------------------------------+ -# | SmartHomeNG | -# | DON'T EDIT THIS FILE | -# | THIS FILE IS GENERATED | -# | BY lib/shpypi.py | -# | ON 04.04.2020 11:06 | -# | | -# | INSTALL WITH: | -# | pip3 install -r requirements/all.txt --user | -# +--------------------------------------------------+ - -# plugin mvg_live -PyMVGLive>=1.1.4 - -# plugin withings_health -arrow>=0.12,<=0.13.1 - -# plugin miflora -bluepy>=1.3.0 - -# SmartHomeNG-module http -cherrypy>=8.1.2 - -# SmartHomeNG-lib -ephem>=3.7 - -# plugin vacations -ferien-api>=0.3.4 - -# SmartHomeNG-lib -holidays>=0.9.11 - -# SmartHomeNG-module http -jinja2>=2.9 - -# plugin bose_soundtouch -libsoundtouch>=0.8.0 - -# plugin miflora -miflora>=0.6 - -# plugin systemair -minimalmodbus>=0.7 - -# plugin withings_health -nokia>=1.0.0,<=1.2.0 - -# plugin uzsu -numpy - -# SmartHomeNG-module mqtt -# plugin mqtt1 -paho-mqtt>=1.2.2 - -# SmartHomeNG-lib -psutil - -# plugin snmp -puresnmp>=1.7.2 - -# plugin appletv -pyatv==0.3.9 - -# plugin stateengine -pydotplus - -# plugin miflora -pygatt>=4.0.5 - -# plugin homematic -pyhomematic>=0.1.28 - -# plugin jsonread -pyjq - -# SmartHomeNG-module admin -pyjwt>=1.6.4 - -# plugin trovis557x -# plugin ksemmodbus -# plugin kostalmodbus -pymodbus>=2.3.0 - -# plugin helios_tcp -pymodbus3>=1.0.0 - -# plugin avdevice -# plugin systemair -# plugin dmx -# plugin dlms -# plugin thz -pyserial>=3.4.0 - -# SmartHomeNG-lib -# plugin backend -# plugin blockly -python-dateutil>=2.5.3 - -# plugin pushbullet -python-magic>=0.4.12 - -# plugin xiaomi_vac -python-miio==0.4.6;python_version<'3.6' - -# plugin xiaomi_vac -python-miio;python_version>='3.6' - -# plugin zwave -python-openzwave>=0.4.0.35 - -# plugin snap7_logo -python-snap7>=0.10 - -# plugin telegram -python-telegram-bot>=9.0.0 - -# plugin iaqstick -pyusb>=1.0.2 - -# plugin withings_health -# SmartHomeNG-lib -# plugin neato -# plugin yamahayxc -requests>=2.20.1 - -# plugin jsonread -requests-file - -# plugin withings_health -requests-oauth>=0.4.1,<0.5 - -# plugin withings_health -requests-oauthlib>=1.0,<1.1 - -# plugin rrd -rrdtool>=0.1.15 - -# SmartHomeNG-lib -ruamel.yaml>=0.13.7,<=0.15.74;python_version<'3.7' - -# SmartHomeNG-lib -ruamel.yaml>0.15.0,<=0.15.74;python_version>='3.7' - -# plugin dashbutton -scapy>=2.4.3 - -# plugin uzsu -scipy>=1.1.0 - -# plugin xiaomi_vac -setuptools - -# plugin xmpp -# plugin harmony -sleekxmpp>=1.3.1 - -# plugin priv_blue -telepot>=8.3 - -# plugin sonos -tinytag>=0.18.0 - -# plugin priv_blue -urllib3>=1.9.1 - -# plugin smarttv -websocket-client>=0.44.0 - -# plugin sonos -xmltodict>=0.11.0 - diff --git a/requirements/base.txt b/requirements/base.txt deleted file mode 100644 index acebfde9f0..0000000000 --- a/requirements/base.txt +++ /dev/null @@ -1,45 +0,0 @@ - -# +--------------------------------------------------+ -# | SmartHomeNG | -# | DON'T EDIT THIS FILE | -# | THIS FILE IS GENERATED | -# | BY lib/shpypi.py | -# | ON 04.04.2020 11:06 | -# | | -# | INSTALL WITH: | -# | pip3 install -r requirements/base.txt --user | -# +--------------------------------------------------+ - -# SmartHomeNG-module http -cherrypy>=8.1.2 - -# SmartHomeNG-lib -ephem>=3.7 - -# SmartHomeNG-lib -holidays>=0.9.11 - -# SmartHomeNG-module http -jinja2>=2.9 - -# SmartHomeNG-module mqtt -paho-mqtt>=1.2.2 - -# SmartHomeNG-lib -psutil - -# SmartHomeNG-module admin -pyjwt>=1.6.4 - -# SmartHomeNG-lib -python-dateutil>=2.5.3 - -# SmartHomeNG-lib -requests>=2.20.0 - -# SmartHomeNG-lib -ruamel.yaml>=0.13.7,<=0.15.74;python_version<'3.7' - -# SmartHomeNG-lib -ruamel.yaml>0.15.0,<=0.15.74;python_version>='3.7' - diff --git a/tests/resources/etc/logic.yaml b/tests/resources/etc/logic.yaml deleted file mode 100755 index 7d0eb17de9..0000000000 --- a/tests/resources/etc/logic.yaml +++ /dev/null @@ -1,30 +0,0 @@ -%YAML 1.1 ---- -# Logic without .py file -logic1: - filename: logic1.py - crontab: init - -# Logic with .py file -logic2: - filename: logic2.py - crontab: init - -# Logic with .py and .xml file -logic3: - filename: logic3.py - crontab: init - -logic_up3: - filename: logic_up.py # Test for section update - crontab: init = Init # Execute at initialization - watch_item: - - beleuchtung.automatik_wuerfel.onoff # Ausführen wenn sich der Würfel ändert - - fenster.bad.fenster_nord # Ausführen wenn das Fenster sich ändert - -logic_up2: - filename: logic_up2.py # Test for section update - crontab: init = Init # Execute at initialization - watchitem: - - beleuchtung.automatik_wuerfel.offon # Ausführen wenn sich der Würfel ändert - - fenster.bad.fenster_sued # Ausführen wenn das Fenster sich ändert From 599decfdbe111be7fd26e45d5efa77e0df30dacb Mon Sep 17 00:00:00 2001 From: bmxp Date: Sat, 18 Apr 2020 15:18:54 +0200 Subject: [PATCH 014/126] More Logo variants --- media/logo_Forum_white.png | Bin 0 -> 752 bytes media/logo_Forum_white.svg | 24 +++++++++++++++++++ media/showme.html | 47 +++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 media/logo_Forum_white.png create mode 100644 media/logo_Forum_white.svg create mode 100644 media/showme.html diff --git a/media/logo_Forum_white.png b/media/logo_Forum_white.png new file mode 100644 index 0000000000000000000000000000000000000000..68d7fe7a17b933a8a601ea75b0ca643422a23b26 GIT binary patch literal 752 zcmVaiqlQtzt++1Nl9H&v6jZWx|#>QuEA zxB>J6OCzEgSOoL{H`NR3%xd6;QrD{c)PD7~x~+_Fllol!q#jbo{4H>``b7PlB^vt& z|LE);e^fiw4b{MAsOK!{vO2rUVyEZkb{r|!=x?NHZM11re4N`0KI)Dd-j-mpo1 zk-U@9{{l?%)@MuJr*{9`6Kb3KT|J{V)B;ujZ^-h0SKC6}3Uo!poy^b#tO4c#V}SQS zH*gQQ7ZD$lWX(Wh7CwxKYdP3TU_}=80MCKBsUg(kR@Tv6(ksbWYrzv9PR82@`|A@= zGq5X(dw@4U127GU%8NLBrO?euy9GE95oQ%n%8DAOHFR>)?id6DL_|MususXJv@2;#scv_eJ^Z62oqF zi$kv;{lJ$b{=z>hebVK?cHp&o9e4?h0ya|mKmdFN?$#1Is9C^{GX9o`cvnm40pJd> zp3-}p4oskQCwc&!h=>ch`A>m~S-Xp&dIj7{y#F=w`uTUIwgC%9kkuX$JK^_@)Cepb iLFn7T#&B- + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/media/showme.html b/media/showme.html new file mode 100644 index 0000000000..06caa6083d --- /dev/null +++ b/media/showme.html @@ -0,0 +1,47 @@ + + + + Provided Media + + + + + +

Provided Media

+

knxuf

+

+ Color for blue is #236aaa like

 
+

+

+ Color for grey is #999999 like

 
+

+ logo for use @knxuf in blue + logo for use @knxuf in blue as svg + logo for use @knxuf in gray + logo for use @knxuf in gray as svg +

SmartVISU

+

use the images for knxuf or SmartVISU in your SmartVISU

+
+ logo for use @knxuf in gray as svg +
+
+ logo for use @knxuf in gray as svg +
+

SmartHomeNG

+

+ Color for darker blue is #236aaa like

 
+

+

+ Color for brighter blue is #b4cee2 like

 
+

+ logo for SmartHomeNG with path + logo for SmartHomeNG with font +
+ logo small for SmartHomeNG with font + + From a53a9117d942d3b554a297f03aae455996ac3cea Mon Sep 17 00:00:00 2001 From: msinn Date: Sat, 18 Apr 2020 15:29:57 +0200 Subject: [PATCH 015/126] Added private tools folder to .gitignore --- .gitignore | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index bfe2a21db4..0e7c1e1180 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ .tox nosetests.xml *.egg-info -test.cache +test.cache /.pytest_cache # OSX specific files @@ -35,12 +35,10 @@ Thumbs.db # Don't check in plugins to core repository /plugins -# don't check in requirements for actual configured plugins -requirements/conf_all.txt - # don't check in requirements that are built each time SHNG starts requirements/all.txt requirements/base.txt +requirements/conf_all.txt # don't check in directories under /var beside listed exeptions /var @@ -55,4 +53,5 @@ requirements/base.txt /.idea /.vscode /custom_plugins +/priv_tools From 39a56ee9ea4b9ee6ba85b98a9760b7b829e0d6fe Mon Sep 17 00:00:00 2001 From: msinn Date: Sun, 19 Apr 2020 11:26:02 +0200 Subject: [PATCH 016/126] class SmartPlugin: variable self.alive is initialized (even before __init__ is called) --- lib/model/smartplugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/model/smartplugin.py b/lib/model/smartplugin.py index feaeb36d1f..0667355513 100644 --- a/lib/model/smartplugin.py +++ b/lib/model/smartplugin.py @@ -58,6 +58,8 @@ class SmartPlugin(SmartObject, Utils): logger = logging.getLogger(__name__) + alive = False + # Initialization of SmartPlugin class called by super().__init__() from the plugin's __init__() method def __init__(self, **kwargs): From 6adbb268cd73d64873e2ce29c7523e64c5d3273c Mon Sep 17 00:00:00 2001 From: msinn Date: Tue, 21 Apr 2020 10:08:29 +0200 Subject: [PATCH 017/126] Documentation updates --- dev/sample_module/README.md | 115 ++++-------------- doc/user/source/index.rst | 2 +- .../logiken/objekteundmethoden_scheduler.rst | 2 + 3 files changed, 25 insertions(+), 94 deletions(-) diff --git a/dev/sample_module/README.md b/dev/sample_module/README.md index 40cda2362b..b99d0021b8 100644 --- a/dev/sample_module/README.md +++ b/dev/sample_module/README.md @@ -1,11 +1,11 @@ -# Module mqtt +# Module sample -This module allows plugins to utilize the MQTT protocol. The API is described below. +This module allows plugins to do something. The API is described below. ## Requirements -This module is running under SmmartHomeNG versions beyond v1.3. It requires Python >= 3.4. +This module is running under SmmartHomeNG versions beyond v1.6. It requires Python >= 3.5. > Note: This module needs the module handling in SmartHomeNG to be activated. Make sure, that `use_modules`in `etc/smarthome.yaml` is **not** set to False! @@ -17,121 +17,50 @@ This module is running under SmmartHomeNG versions beyond v1.3. It requires Pyth ```yaml # etc/module.yaml -http: - module_name: mqtt -# port: 8383 -# servicesport: 8384 -# showpluginlist: False -# showservicelist: True -# starturl: backend -# threads: 8 -# showtraceback: True +sample: + module_name: sample +# param1: 42 +# param2: 'example' ``` -#### user (optional +#### param1 -username for the web access. By default username `admin` is used. +This parameter ... -#### password (optional) +#### param2 (optional) -password for the web access. By default empty. Without a password access is available for everyone. +This parameter ... -#### hashed_password (optional) -hashed password for the web access. By default empty. Without a hashed password the parameter password is used. - -#### service_user (optional - -username for the access to webervices. By default username `serviceuser` is used. - -#### service_password (optional) - -password for the access to the web services. By default empty. Without a password access is available for everyone. - -#### service_hashed_password (optional) - -hashed password for access to the web services. By default empty. Without a hashed password the parameter Service_password is used. - -#### port (optional) -The port on which the html interface listens. By default port **`8383`** is used. - -#### servicesport (optional) -The port on which the html interface listens. By default port **`8384`** is used. - -#### showpluginlist -If set to `False` no list of pluins with web interface is shown under `smarthomeNG.local:8383/plugins`. By default, **showpluginlist** is **True**. - -#### showservicelist -If set to `True` a list of webservices is shown under `smarthomeNG.local:8384/services`. By default, ** showservicelist** is **False**. - -#### starturl (optional) -The name of the plugin that is started when calling url `smarthomeNG.local:8383` without further detailing that url. If you want to startup the **backend** plugin for example: You set `starturl: backend`. That results in a redirect which redirects `smarthomeNG.local:8383` to `smarthomeNG.local:8383/backend`. - -if `starturl` is not specified or point to an url that does not exist, a redirect to `smarthomeNG.local:8383/plugins` will take place (if ** showpluginlist** is **True**). It points to a page that lists all plugins that have registered a html interface and allows you to start those interfaces. - -> Note: If you have redirected to a specific plugin, you can always get to the page with the list of all plugins that have registered a html interface, by entering the url `smarthomeNG.local:8383/plugins`. - -#### threads (optional) -Number of worker threads to start by cherrypy (default 8, which may be too much for slow CPUs) - -#### showtraceback -If set to **True, error-pages (except for error 404) will show the Python traceback for that error. - - -## API of module mqtt +## API of module sample ### Test if module mqtt is loaded -`mqtt` is a loadlable module. Therefore there is no guarantiee that it is present in every system. Before you can use this module, you have to make sure ist is loaded. You can do it by calling a method of the main smarthome object. Do it like this: +`sample` is a loadlable module. Therefore there is no guarantiee that it is present in every system. Before you can use this module, you have to make sure ist is loaded. You can do it by calling a method of the main smarthome object. Do it like this: ``` self.classname = self.__class__.__name__ try: - self.mod_mqtt = self._sh.get_module('mqtt') + self.mod_sample = self._sh.get_module('sample') except: - self.mod_mqtt = None + self.mod_sample = None -if self.mod_mqtt == None: - # Do what is necessary if you can't use the mqtt protocol +if self.mod_sample == None: + # Do what is necessary if you can't use the sample module # for your plugin. For example: - self.logger.error('{}: Module ''mqtt'' not loaded - Abort loading of plugin {0}'.format(self.classname)) + self.logger.error('{}: Module ''sample'' not loaded - Abort loading of plugin {0}'.format(self.classname)) return ``` ### Methods for implementing a web interface -#### get_local_ip_address() -Returns the ip address under which the web interface is listening. - -#### get_local_hostname() -Returns the hostname (with domain) under which the web interface is listening. - -#### get_local_port() -Returns the port under which the implemented web interfaces can be reached. - -#### get_local_servicesport( ... ) -Returns the port under which the implemented webservices can be reached. - -#### register_app() - -##### Parameters -- **app** - Instance of the CherryPy App -- **pluginname** - Standard would be: Shortname of the plugin (name of the plugin's directory) -- **conf** - dict with CherryPy App-Config -- **pluginclass** - Class of the plugin -- **instance** - Optional: Instance of the plugin (if multi-instance) -- **description** - Optional: Description to be shown on page with plugin-list - -#### register_service( ... ) +#### get_...() +Returns ... ##### Parameters -- **service** - Instance of the CherryPy App -- **servicename** - Standard would be: Shortname of the plugin (name of the plugin's directory) -- **conf** - dict with CherryPy App-Config -- **pluginclass** - Class of the plugin -- **instance** - Optional: Instance of the plugin (if multi-instance) -- **description** - Optional: Description to be shown on page with services-list +- **param_a** - ... +- **param_b** - ... diff --git a/doc/user/source/index.rst b/doc/user/source/index.rst index 3b33b2cefe..19f4975716 100755 --- a/doc/user/source/index.rst +++ b/doc/user/source/index.rst @@ -15,7 +15,7 @@ oder bei Abwesenheit eine Nachricht per Email verschickt. Das System kann flexibel durch Plugins erweitert werden, wobei die Plugins in folgende Kategorien klassifiziert sind: -- **Gateway**: Anbindung von Devices eines Bus-Systems wie KNX, HomeMatic, EnOcean, 1-Wire, DMX, Philips Hue, ... +- **Gateway**: Anbindung von Devices eines Bus-Systems wie KNX, HomeMatic, EnOcean, 1-wire, DMX, Philips Hue, ... - **Interface**: Anbindung einzelner Devices wie AVM Fritzboxen, Heizungssteuerungen, div. AV Devices, ... - **Web-/Cloud-Dienst**: Anbindung an diverse Web- bzw. Cloud-Dienste, wie Mail, Prowl, Wetter-Dienste, Alexa, ... - **Protokoll**: Unterstützung diverser Protokolle wie TCP/IP, MQTT, XMPP diff --git a/doc/user/source/logiken/objekteundmethoden_scheduler.rst b/doc/user/source/logiken/objekteundmethoden_scheduler.rst index 179b2316bf..2743e5fb7e 100755 --- a/doc/user/source/logiken/objekteundmethoden_scheduler.rst +++ b/doc/user/source/logiken/objekteundmethoden_scheduler.rst @@ -23,6 +23,8 @@ Diese globale Funktion triggert eine Logic durch die Angabe ihres Namens. Namensräume für die Trigger stattgefunden hat. Wenn sh.trigger genutzt wird, muss dem Namen **logics.** vorangestellt werden. + Also: statt ```sh.trigger('my_logic')`` --> ```sh.sh.trigger('logics.my_logic')``` + sh.scheduler.change() From d291cba737947cf5a2791814bb68bc13de0063c7 Mon Sep 17 00:00:00 2001 From: msinn Date: Tue, 21 Apr 2020 12:34:37 +0200 Subject: [PATCH 018/126] Documentation changes (functions in logics) --- doc/TO DO | 21 + doc/user/source/logiken/funktions_nutzung.rst | 21 +- lib/config_work.py | 793 ++++++++++++++++++ 3 files changed, 824 insertions(+), 11 deletions(-) create mode 100644 doc/TO DO create mode 100644 lib/config_work.py diff --git a/doc/TO DO b/doc/TO DO new file mode 100644 index 0000000000..866d9ff4e0 --- /dev/null +++ b/doc/TO DO @@ -0,0 +1,21 @@ + +Beim Bau der v1.7.1-master Dokumentation: + +Developer Doku: +conf_to_yaml_converter.py - tool to convert shng .conf files to yaml + + +WARNING: invalid signature for automethod ('modules.admin::WebApi.') +WARNING: don't know which module to import for autodocumenting 'modules.admin::WebApi.' (try placing a "module" or "currentmodule" directive in the document, or giving an explicit module name) +looking for now-outdated files... none found + + + +User Doku: +reading sources... [100%] visualisierung/visualisierung_widgets +/usr/local/shng_doc/work/doc/user/source/konfiguration/konfigurationsdateien/scenes.rst:209: WARNING: Explicit markup ends without a blank line; unexpected unindent. +/usr/local/shng_doc/work/doc/user/source/konfiguration/konfigurationsdateien/scenes.rst:220: WARNING: Explicit markup ends without a blank line; unexpected unindent. +/usr/local/shng_doc/work/doc/user/source/plugins_doc/config/ical.rst:86: WARNING: Inline strong start-string without end-string. +/usr/local/shng_doc/work/doc/user/source/plugins_doc/config/ical.rst:86: WARNING: Inline emphasis start-string without end-string. +/usr/local/shng_doc/work/doc/user/source/plugins_doc/config/yamahayxc.rst:36: WARNING: Block quote ends without a blank line; unexpected unindent. +looking for now-outdated files... none found diff --git a/doc/user/source/logiken/funktions_nutzung.rst b/doc/user/source/logiken/funktions_nutzung.rst index de51361c7d..3ccd338782 100644 --- a/doc/user/source/logiken/funktions_nutzung.rst +++ b/doc/user/source/logiken/funktions_nutzung.rst @@ -32,26 +32,25 @@ Das folgende Beispiel verdeutlicht das Vorgehen: .. code-block:: python - # Funktionen definieren + # Variablen, die in Funktionen genutzt werden sollen, müssen dem logic Objekt zugewiesen werden + logic.sh = sh + logic.myvar1 = 5 + logic.myvar2 = False + + # Funktionen definieren und anschließend dem logic Objekt zuweisen def func1(wert, logic=logic): logger.warning("Funktion 1: wert = {}".format(wert)) + logic.func1 = func1 def func2(logic=logic): logger.warning("Funktion 2") logic.func1(2) - - # Funktionen, welche in Logiken genutzt werden sollen, dem logic Objekt zuweisen - logic.func1 = func1 logic.func2 = func2 - # Variablen, die in Logiken genutzt werden sollen, dem logic Objekt zuweisen - logic.sh = sh - logic.myvar1 = 5 - logic.myvar2 = False - # Code der Logik - func1(1) - func2() + # Main Routine der Logik + logic.func1(1) + logic.func2() Um aus Funktionen heraus auf das **sh** Objekt zugreifen zu können, solte auch dieses (wie im obigen Beispiel) als Variable im **logic** Objekt abgelegt werden. diff --git a/lib/config_work.py b/lib/config_work.py new file mode 100644 index 0000000000..e982f72c11 --- /dev/null +++ b/lib/config_work.py @@ -0,0 +1,793 @@ +#!/usr/bin/env python3 +# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab +######################################################################### +# Copyright 2013 Marcus Popp marcus@popp.mx +# Copyright 2016 The SmartHomeNG team +######################################################################### +# This file is part of SmartHomeNG. +# +# SmartHomeNG is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SmartHomeNG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with SmartHomeNG. If not, see . +######################################################################### + +""" +This library does the handling and parsing of the configuration of SmartHomeNG. + + +:Warning: This library is part of the core of SmartHomeNG. It **should not be called directly** from plugins! + +""" + +import copy +import logging +import collections +import keyword +import os + +from lib.utils import Utils +import lib.shyaml as shyaml +from lib.constants import (YAML_FILE, CONF_FILE) +logger = logging.getLogger(__name__) + +valid_item_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' +valid_attr_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_@*' +digits = '0123456789' +reserved = ['set', 'get', 'property'] + +REMOVE_ATTR = 'attr' +REMOVE_PATH = 'path' + +def parse_basename(basename, configtype=''): + ''' + Load and parse a single configuration and merge it to the configuration tree + The configuration is only specified by the basename. + At the moment it looks for a .yaml file or a .conf file + .yaml files take preference + + :param basename: Name of the configuration + :param configtype: Optional string with config type (only used for log output) + :type basename: str + :type configtype: str + + :return: The resulting merged OrderedDict tree + :rtype: OrderedDict + + ''' + config = parse(basename+YAML_FILE) + if config == {}: + config = parse(basename+CONF_FILE) + if config == {}: + if not (configtype == 'logics'): + logger.critical("No file '{}.*' found with {} configuration".format(basename, configtype)) + return config + + +def parse_itemsdir(itemsdir, item_conf, addfilenames=False, struct_dict={}): + ''' + Load and parse item configurations and merge it to the configuration tree + The configuration is only specified by the name of the directory. + At the moment it looks for .yaml files and a .conf files + Both filetypes are read, even if they have the same basename + + :param itemsdir: Name of folder containing the configuration files + :param item_conf: Optional OrderedDict tree, into which the configuration should be merged + :param addfilenames: + :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) + :type itemsdir: str + :type item_conf: OrderedDict + :type addfilenames: + :type struct_dict: dict / OrderedDict + + :return: The resulting merged OrderedDict tree + :rtype: OrderedDict + + ''' + logger.info("parse_itemsdir: Beginning to parse items directory {}".format(itemsdir)) + for item_file in sorted(os.listdir(itemsdir)): + if not item_file.startswith('.'): + if item_file.endswith(CONF_FILE) or item_file.endswith(YAML_FILE): + if item_file == 'logic'+YAML_FILE and itemsdir.find('lib/env/') > -1: + logger.info("parse_itemsdir: skipping logic definition file = {}".format( itemsdir+item_file )) + else: + try: + item_conf = parse(itemsdir + item_file, item_conf, addfilenames, parseitems=True, struct_dict=struct_dict) + except Exception as e: + logger.exception("Problem reading {0}: {1}".format(item_file, e)) + continue + logger.info("parse_itemsdir: Finished parsing items directory {}".format(itemsdir)) + return item_conf + + +def parse(filename, config=None, addfilenames=False, parseitems=False, struct_dict={}): + ''' + Load and parse a configuration file and merge it to the configuration tree + Depending on the extension of the filename, the apropriate parser is called + + :param filename: Name of the configuration file + :param config: Optional OrderedDict tree, into which the configuration should be merged + + :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) + :type filename: str + :type config: OrderedDict + + :return: The resulting merged OrderedDict tree + :rtype: OrderedDict + + ''' + if not filename.startswith('.'): + if filename.endswith(YAML_FILE) and os.path.isfile(filename): + return parse_yaml(filename, config, addfilenames, parseitems, struct_dict) + elif filename.endswith(CONF_FILE) and os.path.isfile(filename): + return parse_conf(filename, config) + return {} + + +# -------------------------------------------------------------------------------------- + +def remove_keys(ydata, func, remove=[REMOVE_ATTR], level=0, msg=None, key_prefix=''): + ''' + Removes given keys from a dict or OrderedDict structure + + :param ydata: configuration (sub)tree to work on + :param func: the function to call to check for removal (Example: lambda k: k.startswith('comment')) + :param level: optional subtree level (used for recursion) + :type ydata: OrderedDict + :type func: function + :type level: int + + ''' + try: + level_keys = list(ydata.keys()) + for key in level_keys: + key_str = str(key) + key_dict = type(ydata[key]).__name__ in ['dict','OrderedDict'] + if not key_dict: + key_remove = REMOVE_ATTR in remove and func(key_str) + else: + key_remove = REMOVE_PATH in remove and func(key_str) + if key_remove: + if msg: + logger.warning(msg.format(key_prefix+key_str)) + ydata.pop(key) + elif key_dict: + remove_keys(ydata[key], func, remove, level+1, msg, key_prefix+key_str+'.') + except Exception as e: + logger.error("Problem removing key from '{}', probably invalid YAML file: {}".format(str(ydata), e)) + + + +def remove_comments(ydata, filename=''): + ''' + Removes comments from a dict or OrderedDict structure + + :param ydata: configuration (sub)tree to work on + :type ydata: OrderedDict + + ''' + remove_keys(ydata, lambda k: k.startswith('comment'), [REMOVE_ATTR]) + + +def remove_digits(ydata, filename=''): + ''' + Removes keys starting with digits from a dict or OrderedDict structure + + :param ydata: configuration (sub)tree to work on + :type ydata: OrderedDict + + ''' + remove_keys(ydata, lambda k: k[0] in digits, [REMOVE_ATTR, REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': item starts with digits") + + +def remove_reserved(ydata, filename=''): + ''' + Removes keys that are reserved keywords from a dict or OrderedDict structure + + :param ydata: configuration (sub)tree to work on + :type ydata: OrderedDict + + ''' + remove_keys(ydata, lambda k: k in reserved, [REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': item using reserved word set/get") + + +def remove_keyword(ydata, filename=''): + ''' + Removes keys that are reserved Python keywords from a dict or OrderedDict structure + + :param ydata: configuration (sub)tree to work on + :type ydata: OrderedDict + + ''' + remove_keys(ydata, lambda k: keyword.iskeyword(k), [REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': item using reserved Python keyword") + + +def remove_invalid(ydata, filename=''): + ''' + Removes invalid chars in item from a dict or OrderedDict structure + + :param ydata: configuration (sub)tree to work on + :type ydata: OrderedDict + + ''' + valid_chars = valid_item_chars + valid_attr_chars + remove_keys(ydata, lambda k: True if True in [True for i in range(len(k)) if k[i] not in valid_chars] else False, [REMOVE_ATTR, REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': Invalid character. Valid characters are: " + str(valid_chars)) + + +struct_merging_active = False +struct_merge_lists = True +special_listentry_found = False + + +def merge_structlists(l1, l2, key=''): + + if not struct_merging_active: + global special_listentry_found + # merge* or merge_unique* + if (len(l1) > 0 and l1[0] == 'merge_unique*') and (len(l2) > 0 and l2[0] == 'merge_unique*'): + logger.debug("merge_structlists: merge_unique* l1={}, l2={}".format(l1,l2)) + logger.debug("merge_structlists: both lists contains 'merge_unique*' - l1={}, l2={}, key={}".format(l1, l2, key)) + special_listentry_found = True + l1 = list(collections.OrderedDict.fromkeys(l1)) + return l1 + + if (len(l1) > 0 and l1[0] == 'merge*') and (len(l2) > 0 and l2[0] == 'merge*'): + logger.debug("merge_structlists: merge* l1={}, l2={}".format(l1,l2)) + logger.debug("merge_structlists: both lists contains 'merge*' - l1={}, l2={}, key={}".format(l1, l2, key)) + special_listentry_found = True + return l1 + + if (len(l2) > 0 and l2[0] == 'merge*'): + logger.debug("merge_structlists: l2 contains merge* l1={}, l2={}".format(l1,l2)) + logger.debug("merge_structlists: list l2 contains 'merge*' - l1={}, l2={}, key={}".format(l1, l2, key)) + del l2[0] + l1 = ['merge*'] + l1 + l2 + l2 = ['merge*'] + l2 + return l1 + + if (len(l1) > 0 and l1[0] == 'merge*') or (len(l2) > 0 and l2[0] == 'merge*'): + logger.debug("merge_structlists: l1 or l2 contain merge* l1={}, l2={}".format(l1,l2)) + logger.warning("merge_structlists: a list contains 'merge*' - l1={}, l2={}, key={}".format(l1, l2, key)) + pass + return l2 # Last wins + + if not struct_merge_lists: + #logger.warning("merge_structlists: Not merging lists, key '{}' value '{}' is ignored'".format(key, l2)) + return l1 # First wins + else: + if not isinstance(l1, list): + l1 = [l1] + if not isinstance(l2, list): + l2 = [l2] + return l1 + l2 + + +def merge(source, destination, source_name='', dest_name='', filename=''): + ''' + Merges an OrderedDict Tree into another one + + :param source: source tree to merge into another one + :param destination: destination tree to merge into + :type source: OrderedDict + :type destination: OrderedDict + + :return: Merged configuration tree + :rtype: OrderedDict + + :Example: Run me with nosetests --with-doctest file.py + + .. code-block:: python + + >>> a = { 'first' : { 'all_rows' : { 'pass' : 'dog', 'number' : '1' } } } + >>> b = { 'first' : { 'all_rows' : { 'fail' : 'cat', 'number' : '5' } } } + >>> merge(b, a) == { 'first' : { 'all_rows' : { 'pass' : 'dog', 'fail' : 'cat', 'number' : '5' } } } + True + + ''' + +# if struct_merging_active: + if source.get('_filename', '') == 'test_struct.yaml': + logger.warning("merge {}: source={}, destination={}, source_name={}, dest_name={}".format(source.get('_filename', ''), dict(source), dict(destination), source_name, dest_name)) + ext_logging = True + else: + ext_logging = False + for key, value in source.items(): + try: + if isinstance(value, collections.OrderedDict): + # get node or create one + node = destination.setdefault(key, collections.OrderedDict()) + if node == 'None': + destination[key] = value + else: + merge(value, node, source_name, dest_name) + else: +# if struct_merging_active: +# logger.warning("merge: - value={}, destination.get(key, None)={}".format(value, destination.get(key, None))) + if isinstance(value, list) or isinstance(destination.get(key, None), list): + if destination.get(key, None) is None: + destination[key] = value + else: + if ext_logging: + logger.info("merge: call merge_structlists - key={}, value={}, destination.get(key, None)={}".format(key, value, destination.get(key, None))) + destination[key] = merge_structlists(destination[key], value, key) + else: + # convert to string and remove newlines from multiline attributes + destination[key] = str(value).replace('\n', '') + # if destination.get(key, None) is None: + # destination[key] = str(value).replace('\n', '') + + # if type(value).__name__ == 'list': + # destination[key] = value + # else: + # # convert to string and remove newlines from multiline attributes + # destination[key] = str(value).replace('\n','') +# if struct_merging_active: +# logger.warning("merge: - destination={}".format(dict(destination))) + except Exception as e: + logger.error("Problem merging subtrees (key={}), probably invalid YAML file '{}' with entry '{}'. Error: {}".format(key, source_name, destination, e)) + + return destination + + +#------------------------------------------------------------------------------------- +# Handling of structs while loading item tree from yaml files +# + + +def nested_get(input_dict, path): + internal_dict_value = input_dict + nested_key = path.split('.') + for k in nested_key: + internal_dict_value = internal_dict_value.get(k, None) + if internal_dict_value is None: + return None + return internal_dict_value + + +def nested_put(output_dict, path, value): + ''' + + :param output_dict: dict structure to write to + :param path: path to write to + :param value: value to write to the nested key + :return: + ''' + internal_dict_value = output_dict + nested_key = path.split('.') + internal_last_dict_value = None + # if struct_merging_active: + # logger.warning("nested_put: path = {}, value = {} - nested_key = {}".format(path, value, nested_key)) + # logger.warning("nested_put: - output_dict = {}".format(dict(output_dict))) + for k in nested_key: + if internal_dict_value.get(k, None) is None: + if isinstance(output_dict, collections.OrderedDict): + internal_dict_value[k] = collections.OrderedDict() + else: + internal_dict_value[k] = {} + internal_last_dict_value = internal_dict_value + internal_dict_value = internal_dict_value.get(k, None) + + if internal_last_dict_value is not None: + # if struct_merging_active: + # logger.warning("nested_put: - dest subtree = {}".format(dict(internal_last_dict_value[nested_key[len(nested_key)-1]]))) + # logger.warning("nested_put: - merge struct = {}".format(dict(value))) + + #internal_last_dict_value[nested_key[len(nested_key)-1]] = value + merge(value, internal_last_dict_value[nested_key[len(nested_key)-1]], 'struct-tree', 'sub-tree') + + # if struct_merging_active: + # logger.warning("nested_put: - dest result = {}".format(dict(internal_last_dict_value[nested_key[len(nested_key)-1]]))) + + # if struct_merging_active: + # logger.warning("nested_put: - internal_last_dict_value = {}".format(internal_last_dict_value)) + return + + +def search_for_struct_in_items(items, struct_dict, config, source_name='', parent='', level=0): + """ + Test if the loaded file contains items with 'struct' attribute. + + This function is (recursively) called before merging the loaded file into the item tree + + :param items: tree content of a single items.yaml file (or part of it during recursion) + :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) + :param config: tree, into which the configuration should be merged + :param parent: + :type items: OrderedDict + :type config: OrderedDict + :return: True, if a struct attribute was expanded + """ + + for key in items: + value = items[key] + if key == 'struct': + # item is a struct + struct_names = value + # ensure, struct_names is a list + if isinstance(struct_names, str): + struct_names = [struct_names] + + instance = items.get('instance', '') + template = collections.OrderedDict() + + global struct_merging_active + struct_merging_active = True + for struct_name in struct_names: + wrk = struct_name.find('@') + if wrk > -1: + add_struct_to_template(parent, struct_name[:wrk], template, struct_dict, struct_name[wrk+1:]) + else: + add_struct_to_template(parent, struct_name, template, struct_dict, instance) + if template != {}: + config = merge(template, config, source_name, 'Item-Tree') + struct_merging_active = False + + else: + #item is no struct + if isinstance(value, collections.OrderedDict): + # treat value as node + if parent == '': + path = key + else: + path = parent+'.'+key + # test if a aub-item is a struct + search_for_struct_in_items(value, struct_dict, config, source_name, parent=path, level=level+1) + template = collections.OrderedDict() + nested_put(template, path, value) + config = merge(template, config, source_name, 'Item-Tree') + + return + + +def remove_special_listentries(config, filename=''): + for k, v in config.items(): + if isinstance(v, dict): + remove_special_listentries(v, filename) + else: + if isinstance(v, list): + if len(v) > 0 and v[0] in ['merge*','merge_unique*']: + #logger.warning("remove_special_listentries: a list={} -> {} - {}".format(k, v, filename)) + del v[0] + +def set_attr_for_subtree(subtree, attr, value, indent=0): + ''' + + :param subtree: dict (subtree) to operate on + :param attr: Attribute to set for every item + :param value: Value to set the attribute to + :param indent: indent level (only for debug-logging) + + :return: + ''' + for k, v in subtree.items(): + if isinstance(v, dict): + v[attr] = value + spc = " " * 2 * indent + logger.debug("set_attr_for_subtree:{} node: {} => {}".format(spc, k, v)) + set_attr_for_subtree(v, attr, value, indent+1) + return + + +def add_struct_to_template(path, struct_name, template, struct_dict, instance): + ''' + Add the referenced struct to the items_template subtree + + :param path: Path of the item which references a struct (template) + :param struct_name: Name of the to use for the item + :param template: Template dict to be merged into the item tree + :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) + :param instance: For multi instance plugins: instance for which the items work (is derived from item with struct attribute) + + :return: + ''' + struct = struct_dict.get(struct_name, None) + if struct is None: + # no struct/template with this name + nf = collections.OrderedDict() + nf['name'] = "ERROR: struct '" + struct_name+"' not found!" + # nf['value'] = nf['name'] + nested_put(template, path, nf) + logger.error("add_struct_to_template: Struct definition for '{}' not found (referenced in item {})".format(struct_name, path)) + else: + # add struct/template to temporary item(template) tree + #logger.debug("- add_struct_to_template: struct_dict = {}".format(dict(struct_dict))) + logger.debug("- add_struct_to_template: {} <- struct = {}".format(path, struct_name)) + nested_put(template, path, copy.deepcopy(struct)) + if instance != '' or True: + # add instance to items added by template struct + subtree = nested_get(template, path) + # logger.info("add_struct_to_template: Adding 'instance: {}' to template for subtree '{}'".format(instance, path)) + # add instance name to attributes which carry '@instance' + logger.debug("- add_struct_to_template: subtree={}, instance={}".format(subtree, instance)) + replace_struct_instance(path, subtree, instance) + + return + + +def replace_struct_instance(path, subtree, instance): + """ + Replace the constant string '@instance' in attribute names with the real instance + (or remove the constant string '@instance', if the struct has no instace reference) + + :param path: + :param subtree: + :param instance: + :return: + """ + keys = list(subtree.keys()) + logger.info("replace_struct_instance: Setting instance to {} for subtree {}".format(instance, subtree)) + for key in keys: + # replace recursively + if Utils.get_type(subtree[key]) == 'collections.OrderedDict': + replace_struct_instance(path, subtree[key], instance) + if key.endswith('@instance'): + if instance == '': + newkey = key[:-9] + else: + newkey = key[:-9] + '@' + instance + #logger.debug("replace_struct_instance: - path {}: key '{}' --> newkey '{}'".format(path, key, newkey)) + subtree[newkey] = subtree.pop(key) + # logger.info("replace_struct_instance: Done set instance to {} for subtree {}".format(instance, subtree)) + return + + +def parse_yaml(filename, config=None, addfilenames=False, parseitems=False, struct_dict={}): + """ + Load and parse a yaml configuration file and merge it to the configuration tree + + :param filename: Name of the configuration file + :param config: Optional OrderedDict tree, into which the configuration should be merged + :param addfilenames: x + :param parseitems: x + :param struct_dict: dictionary with stuct definitions (templates) for reading item tree + :type filename: str + :type config: bool + :type addfilenames: bool + :type parseitems: bool + :type struct_dict: dict + + :return: The resulting merged OrderedDict tree + :rtype: OrderedDict + + + The config file should stick to the following setup: + + .. code-block:: yaml + + firstlevel: + attribute1: xyz + attribute2: foo + attribute3: bar + + secondlevel: + attribute1: abc + attribute2: bar + attribute3: foo + + thirdlevel: + attribute1: def + attribute2: barfoo + attribute3: foobar + + anothersecondlevel: + attribute1: and so on + + where firstlevel, secondlevel, thirdlevel and anothersecondlevel are defined as items and attribute are their respective attribute - value pairs + + Valid characters for the items are a-z and A-Z plus any digit and underscore as second or further characters. + Valid characters for the attributes are the same as for an item plus @ and * + + """ + logger.info("parse_yaml: Parsing file {}".format(os.path.basename(filename))) + if config is None: + config = collections.OrderedDict() + + items = shyaml.yaml_load(filename, ordered=True) + if items is not None: + remove_comments(items, filename) + remove_digits(items, filename) + remove_reserved(items, filename) + remove_keyword(items, filename) + remove_invalid(items, filename) + + if addfilenames: + #logger.debug("parse_yaml: Add filename = {} to items".format(os.path.basename(filename))) + _add_filenames_to_config(items, os.path.basename(filename)) + + if parseitems: + # test if file contains 'struct' attribute and merge all items into config + #logger.debug("parse_yaml: Checking if file {} contains 'struct' attribute".format(os.path.basename(filename))) + + search_for_struct_in_items(items, struct_dict, config, os.path.basename(filename)) + + global special_listentry_found + if special_listentry_found: + remove_special_listentries(config, os.path.basename(filename)) + special_listentry_found = False + + if not parseitems: + # if not parsing items + config = merge(items, config, os.path.basename(filename), 'Config-Tree') + return config + + +def _add_filenames_to_config(items, filename, level=0): + """ + Adds the name of the config file to the config items + + This routine is used to add the source filename to: + - be able to display the file an item is defined in (backend page items) + - to enable editing and storing back of item definitions + + This function calls itself recurselively + + """ + for attr, value in items.items(): + if isinstance(value, dict): + child_path = dict(value) + if (filename != ''): + value['_filename'] = filename + _add_filenames_to_config(child_path, filename, level+1) + return + + +# -------------------------------------------------------------------------------------- + + +def strip_quotes(string): + """ + Strip single-quotes or double-quotes from string beggining and end + + :param string: String to strip the quotes from + :type string: str + + :return: Stripped string + :rtype: str + + """ + string = string.strip() + if len(string) > 0: + if string[0] in ['"', "'"]: # check if string starts with ' or " + if string[0] == string[-1]: # and end with it + if string.count(string[0]) == 2: # if they are the only one + string = string[1:-1] # remove them + return string + + +def parse_conf(filename, config=None): + """ + Load and parse a configuration file which is in the old .conf format of smarthome.py + and merge it to the configuration tree + + :param filename: Name of the configuration file + :param config: Optional OrderedDict tree, into which the configuration should be merged + :type filename: str + :type config: bool + + :return: The resulting merged OrderedDict tree + :rtype: OrderedDict + + + The config file should stick to the following setup: + + .. code-block:: ini + + [firstlevel] + attribute1 = xyz + attribute2 = foo + attribute3 = bar + + [[secondlevel]] + attribute1 = abc + attribute2 = bar + attribute3 = foo + + [[[thirdlevel]]] + attribute1 = def + attribute2 = barfoo + attribute3 = foobar + + [[anothersecondlevel]] + attribute1 = and so on + + where firstlevel, secondlevel, thirdlevel and anothersecondlevel are defined as items and attribute are their respective attribute - value pairs + + Valid characters for the items are a-z and A-Z plus any digit and underscore as second or further characters. + Valid characters for the attributes are the same as for an item plus @ and * + + """ + + valid_set = set(valid_attr_chars) + if config is None: + config = collections.OrderedDict() + item = config + with open(filename, 'r', encoding='UTF-8') as f: + linenu = 0 + parent = collections.OrderedDict() + lines = iter(f.readlines()) + for raw in lines: + linenu += 1 + line = raw.lstrip('\ufeff') # remove BOM + while line.rstrip().endswith('\\'): + linenu += 1 + line = line.rstrip().rstrip('\\') + next(lines, '').lstrip() + line = line.partition('#')[0].strip() + if line is '': + continue + if line[0] == '[': # item + brackets = 0 + level = 0 + closing = False + for index in range(len(line)): + if line[index] == '[' and not closing: + brackets += 1 + level += 1 + elif line[index] == ']': + closing = True + brackets -= 1 + else: + closing = True + if line[index] not in valid_item_chars + "'": + logger.error("Problem parsing '{}' invalid character in line {}: {}. Valid characters are: {}".format(filename, linenu, line, valid_item_chars)) + return config + if brackets != 0: + logger.error("Problem parsing '{}' unbalanced brackets in line {}: {}".format(filename, linenu, line)) + return config + name = line.strip("[]") + name = strip_quotes(name) + + if len(name) == 0: + logger.error("Problem parsing '{}' tried to use an empty item name in line {}: {}".format(filename, linenu, line)) + return config + elif name[0] in digits: + logger.error("Problem parsing '{}': item starts with digit '{}' in line {}: {}".format(filename, name[0], linenu, line)) + return config + elif name in reserved: + logger.error("Problem parsing '{}': item using reserved word set/get in line {}: {}".format(filename, linenu, line)) + return config + elif keyword.iskeyword(name): + logger.error("Problem parsing '{}': item using reserved Python keyword {} in line {}: {}".format(filename, name, linenu, line)) + return config + + if level == 1: + if name not in config: + config[name] = collections.OrderedDict() + item = config[name] + parents = collections.OrderedDict() + parents[level] = item + else: + if level - 1 not in parents: + logger.error("Problem parsing '{}' no parent item defined for item in line {}: {}".format(filename, linenu, line)) + return config + parent = parents[level - 1] + if name not in parent: + parent[name] = collections.OrderedDict() + item = parent[name] + parents[level] = item + + else: # attribute + attr, __, value = line.partition('=') + if not value: + continue + attr = attr.strip() + if not set(attr).issubset(valid_set): + logger.error("Problem parsing '{}' invalid character in line {}: {}. Valid characters are: {}".format(filename, linenu, attr, valid_attr_chars)) + continue + + if len(attr) > 0: + if attr[0] in digits: + logger.error("Problem parsing '{}' attrib starts with a digit '{}' in line {}: {}.".format(filename, attr[0], linenu, attr )) + continue + if '|' in value: + item[attr] = [strip_quotes(x) for x in value.split('|')] + else: + item[attr] = strip_quotes(value) + return config From 1d16c21dfa471bd01ebff84ca26ea6c6ace01340 Mon Sep 17 00:00:00 2001 From: msinn Date: Tue, 21 Apr 2020 12:38:12 +0200 Subject: [PATCH 019/126] Documentation changes --- lib/{config_work.py => config_work copy.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/{config_work.py => config_work copy.py} (100%) diff --git a/lib/config_work.py b/lib/config_work copy.py similarity index 100% rename from lib/config_work.py rename to lib/config_work copy.py From 5083a01fc71c120703c215c5f3517f6e997347be Mon Sep 17 00:00:00 2001 From: msinn Date: Tue, 21 Apr 2020 12:44:46 +0200 Subject: [PATCH 020/126] documentation changes --- lib/config_work copy.py | 793 ---------------------------------------- 1 file changed, 793 deletions(-) delete mode 100644 lib/config_work copy.py diff --git a/lib/config_work copy.py b/lib/config_work copy.py deleted file mode 100644 index e982f72c11..0000000000 --- a/lib/config_work copy.py +++ /dev/null @@ -1,793 +0,0 @@ -#!/usr/bin/env python3 -# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab -######################################################################### -# Copyright 2013 Marcus Popp marcus@popp.mx -# Copyright 2016 The SmartHomeNG team -######################################################################### -# This file is part of SmartHomeNG. -# -# SmartHomeNG is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# SmartHomeNG is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with SmartHomeNG. If not, see . -######################################################################### - -""" -This library does the handling and parsing of the configuration of SmartHomeNG. - - -:Warning: This library is part of the core of SmartHomeNG. It **should not be called directly** from plugins! - -""" - -import copy -import logging -import collections -import keyword -import os - -from lib.utils import Utils -import lib.shyaml as shyaml -from lib.constants import (YAML_FILE, CONF_FILE) -logger = logging.getLogger(__name__) - -valid_item_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' -valid_attr_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_@*' -digits = '0123456789' -reserved = ['set', 'get', 'property'] - -REMOVE_ATTR = 'attr' -REMOVE_PATH = 'path' - -def parse_basename(basename, configtype=''): - ''' - Load and parse a single configuration and merge it to the configuration tree - The configuration is only specified by the basename. - At the moment it looks for a .yaml file or a .conf file - .yaml files take preference - - :param basename: Name of the configuration - :param configtype: Optional string with config type (only used for log output) - :type basename: str - :type configtype: str - - :return: The resulting merged OrderedDict tree - :rtype: OrderedDict - - ''' - config = parse(basename+YAML_FILE) - if config == {}: - config = parse(basename+CONF_FILE) - if config == {}: - if not (configtype == 'logics'): - logger.critical("No file '{}.*' found with {} configuration".format(basename, configtype)) - return config - - -def parse_itemsdir(itemsdir, item_conf, addfilenames=False, struct_dict={}): - ''' - Load and parse item configurations and merge it to the configuration tree - The configuration is only specified by the name of the directory. - At the moment it looks for .yaml files and a .conf files - Both filetypes are read, even if they have the same basename - - :param itemsdir: Name of folder containing the configuration files - :param item_conf: Optional OrderedDict tree, into which the configuration should be merged - :param addfilenames: - :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) - :type itemsdir: str - :type item_conf: OrderedDict - :type addfilenames: - :type struct_dict: dict / OrderedDict - - :return: The resulting merged OrderedDict tree - :rtype: OrderedDict - - ''' - logger.info("parse_itemsdir: Beginning to parse items directory {}".format(itemsdir)) - for item_file in sorted(os.listdir(itemsdir)): - if not item_file.startswith('.'): - if item_file.endswith(CONF_FILE) or item_file.endswith(YAML_FILE): - if item_file == 'logic'+YAML_FILE and itemsdir.find('lib/env/') > -1: - logger.info("parse_itemsdir: skipping logic definition file = {}".format( itemsdir+item_file )) - else: - try: - item_conf = parse(itemsdir + item_file, item_conf, addfilenames, parseitems=True, struct_dict=struct_dict) - except Exception as e: - logger.exception("Problem reading {0}: {1}".format(item_file, e)) - continue - logger.info("parse_itemsdir: Finished parsing items directory {}".format(itemsdir)) - return item_conf - - -def parse(filename, config=None, addfilenames=False, parseitems=False, struct_dict={}): - ''' - Load and parse a configuration file and merge it to the configuration tree - Depending on the extension of the filename, the apropriate parser is called - - :param filename: Name of the configuration file - :param config: Optional OrderedDict tree, into which the configuration should be merged - - :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) - :type filename: str - :type config: OrderedDict - - :return: The resulting merged OrderedDict tree - :rtype: OrderedDict - - ''' - if not filename.startswith('.'): - if filename.endswith(YAML_FILE) and os.path.isfile(filename): - return parse_yaml(filename, config, addfilenames, parseitems, struct_dict) - elif filename.endswith(CONF_FILE) and os.path.isfile(filename): - return parse_conf(filename, config) - return {} - - -# -------------------------------------------------------------------------------------- - -def remove_keys(ydata, func, remove=[REMOVE_ATTR], level=0, msg=None, key_prefix=''): - ''' - Removes given keys from a dict or OrderedDict structure - - :param ydata: configuration (sub)tree to work on - :param func: the function to call to check for removal (Example: lambda k: k.startswith('comment')) - :param level: optional subtree level (used for recursion) - :type ydata: OrderedDict - :type func: function - :type level: int - - ''' - try: - level_keys = list(ydata.keys()) - for key in level_keys: - key_str = str(key) - key_dict = type(ydata[key]).__name__ in ['dict','OrderedDict'] - if not key_dict: - key_remove = REMOVE_ATTR in remove and func(key_str) - else: - key_remove = REMOVE_PATH in remove and func(key_str) - if key_remove: - if msg: - logger.warning(msg.format(key_prefix+key_str)) - ydata.pop(key) - elif key_dict: - remove_keys(ydata[key], func, remove, level+1, msg, key_prefix+key_str+'.') - except Exception as e: - logger.error("Problem removing key from '{}', probably invalid YAML file: {}".format(str(ydata), e)) - - - -def remove_comments(ydata, filename=''): - ''' - Removes comments from a dict or OrderedDict structure - - :param ydata: configuration (sub)tree to work on - :type ydata: OrderedDict - - ''' - remove_keys(ydata, lambda k: k.startswith('comment'), [REMOVE_ATTR]) - - -def remove_digits(ydata, filename=''): - ''' - Removes keys starting with digits from a dict or OrderedDict structure - - :param ydata: configuration (sub)tree to work on - :type ydata: OrderedDict - - ''' - remove_keys(ydata, lambda k: k[0] in digits, [REMOVE_ATTR, REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': item starts with digits") - - -def remove_reserved(ydata, filename=''): - ''' - Removes keys that are reserved keywords from a dict or OrderedDict structure - - :param ydata: configuration (sub)tree to work on - :type ydata: OrderedDict - - ''' - remove_keys(ydata, lambda k: k in reserved, [REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': item using reserved word set/get") - - -def remove_keyword(ydata, filename=''): - ''' - Removes keys that are reserved Python keywords from a dict or OrderedDict structure - - :param ydata: configuration (sub)tree to work on - :type ydata: OrderedDict - - ''' - remove_keys(ydata, lambda k: keyword.iskeyword(k), [REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': item using reserved Python keyword") - - -def remove_invalid(ydata, filename=''): - ''' - Removes invalid chars in item from a dict or OrderedDict structure - - :param ydata: configuration (sub)tree to work on - :type ydata: OrderedDict - - ''' - valid_chars = valid_item_chars + valid_attr_chars - remove_keys(ydata, lambda k: True if True in [True for i in range(len(k)) if k[i] not in valid_chars] else False, [REMOVE_ATTR, REMOVE_PATH], msg="Problem parsing '{}' in file '"+filename+"': Invalid character. Valid characters are: " + str(valid_chars)) - - -struct_merging_active = False -struct_merge_lists = True -special_listentry_found = False - - -def merge_structlists(l1, l2, key=''): - - if not struct_merging_active: - global special_listentry_found - # merge* or merge_unique* - if (len(l1) > 0 and l1[0] == 'merge_unique*') and (len(l2) > 0 and l2[0] == 'merge_unique*'): - logger.debug("merge_structlists: merge_unique* l1={}, l2={}".format(l1,l2)) - logger.debug("merge_structlists: both lists contains 'merge_unique*' - l1={}, l2={}, key={}".format(l1, l2, key)) - special_listentry_found = True - l1 = list(collections.OrderedDict.fromkeys(l1)) - return l1 - - if (len(l1) > 0 and l1[0] == 'merge*') and (len(l2) > 0 and l2[0] == 'merge*'): - logger.debug("merge_structlists: merge* l1={}, l2={}".format(l1,l2)) - logger.debug("merge_structlists: both lists contains 'merge*' - l1={}, l2={}, key={}".format(l1, l2, key)) - special_listentry_found = True - return l1 - - if (len(l2) > 0 and l2[0] == 'merge*'): - logger.debug("merge_structlists: l2 contains merge* l1={}, l2={}".format(l1,l2)) - logger.debug("merge_structlists: list l2 contains 'merge*' - l1={}, l2={}, key={}".format(l1, l2, key)) - del l2[0] - l1 = ['merge*'] + l1 + l2 - l2 = ['merge*'] + l2 - return l1 - - if (len(l1) > 0 and l1[0] == 'merge*') or (len(l2) > 0 and l2[0] == 'merge*'): - logger.debug("merge_structlists: l1 or l2 contain merge* l1={}, l2={}".format(l1,l2)) - logger.warning("merge_structlists: a list contains 'merge*' - l1={}, l2={}, key={}".format(l1, l2, key)) - pass - return l2 # Last wins - - if not struct_merge_lists: - #logger.warning("merge_structlists: Not merging lists, key '{}' value '{}' is ignored'".format(key, l2)) - return l1 # First wins - else: - if not isinstance(l1, list): - l1 = [l1] - if not isinstance(l2, list): - l2 = [l2] - return l1 + l2 - - -def merge(source, destination, source_name='', dest_name='', filename=''): - ''' - Merges an OrderedDict Tree into another one - - :param source: source tree to merge into another one - :param destination: destination tree to merge into - :type source: OrderedDict - :type destination: OrderedDict - - :return: Merged configuration tree - :rtype: OrderedDict - - :Example: Run me with nosetests --with-doctest file.py - - .. code-block:: python - - >>> a = { 'first' : { 'all_rows' : { 'pass' : 'dog', 'number' : '1' } } } - >>> b = { 'first' : { 'all_rows' : { 'fail' : 'cat', 'number' : '5' } } } - >>> merge(b, a) == { 'first' : { 'all_rows' : { 'pass' : 'dog', 'fail' : 'cat', 'number' : '5' } } } - True - - ''' - -# if struct_merging_active: - if source.get('_filename', '') == 'test_struct.yaml': - logger.warning("merge {}: source={}, destination={}, source_name={}, dest_name={}".format(source.get('_filename', ''), dict(source), dict(destination), source_name, dest_name)) - ext_logging = True - else: - ext_logging = False - for key, value in source.items(): - try: - if isinstance(value, collections.OrderedDict): - # get node or create one - node = destination.setdefault(key, collections.OrderedDict()) - if node == 'None': - destination[key] = value - else: - merge(value, node, source_name, dest_name) - else: -# if struct_merging_active: -# logger.warning("merge: - value={}, destination.get(key, None)={}".format(value, destination.get(key, None))) - if isinstance(value, list) or isinstance(destination.get(key, None), list): - if destination.get(key, None) is None: - destination[key] = value - else: - if ext_logging: - logger.info("merge: call merge_structlists - key={}, value={}, destination.get(key, None)={}".format(key, value, destination.get(key, None))) - destination[key] = merge_structlists(destination[key], value, key) - else: - # convert to string and remove newlines from multiline attributes - destination[key] = str(value).replace('\n', '') - # if destination.get(key, None) is None: - # destination[key] = str(value).replace('\n', '') - - # if type(value).__name__ == 'list': - # destination[key] = value - # else: - # # convert to string and remove newlines from multiline attributes - # destination[key] = str(value).replace('\n','') -# if struct_merging_active: -# logger.warning("merge: - destination={}".format(dict(destination))) - except Exception as e: - logger.error("Problem merging subtrees (key={}), probably invalid YAML file '{}' with entry '{}'. Error: {}".format(key, source_name, destination, e)) - - return destination - - -#------------------------------------------------------------------------------------- -# Handling of structs while loading item tree from yaml files -# - - -def nested_get(input_dict, path): - internal_dict_value = input_dict - nested_key = path.split('.') - for k in nested_key: - internal_dict_value = internal_dict_value.get(k, None) - if internal_dict_value is None: - return None - return internal_dict_value - - -def nested_put(output_dict, path, value): - ''' - - :param output_dict: dict structure to write to - :param path: path to write to - :param value: value to write to the nested key - :return: - ''' - internal_dict_value = output_dict - nested_key = path.split('.') - internal_last_dict_value = None - # if struct_merging_active: - # logger.warning("nested_put: path = {}, value = {} - nested_key = {}".format(path, value, nested_key)) - # logger.warning("nested_put: - output_dict = {}".format(dict(output_dict))) - for k in nested_key: - if internal_dict_value.get(k, None) is None: - if isinstance(output_dict, collections.OrderedDict): - internal_dict_value[k] = collections.OrderedDict() - else: - internal_dict_value[k] = {} - internal_last_dict_value = internal_dict_value - internal_dict_value = internal_dict_value.get(k, None) - - if internal_last_dict_value is not None: - # if struct_merging_active: - # logger.warning("nested_put: - dest subtree = {}".format(dict(internal_last_dict_value[nested_key[len(nested_key)-1]]))) - # logger.warning("nested_put: - merge struct = {}".format(dict(value))) - - #internal_last_dict_value[nested_key[len(nested_key)-1]] = value - merge(value, internal_last_dict_value[nested_key[len(nested_key)-1]], 'struct-tree', 'sub-tree') - - # if struct_merging_active: - # logger.warning("nested_put: - dest result = {}".format(dict(internal_last_dict_value[nested_key[len(nested_key)-1]]))) - - # if struct_merging_active: - # logger.warning("nested_put: - internal_last_dict_value = {}".format(internal_last_dict_value)) - return - - -def search_for_struct_in_items(items, struct_dict, config, source_name='', parent='', level=0): - """ - Test if the loaded file contains items with 'struct' attribute. - - This function is (recursively) called before merging the loaded file into the item tree - - :param items: tree content of a single items.yaml file (or part of it during recursion) - :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) - :param config: tree, into which the configuration should be merged - :param parent: - :type items: OrderedDict - :type config: OrderedDict - :return: True, if a struct attribute was expanded - """ - - for key in items: - value = items[key] - if key == 'struct': - # item is a struct - struct_names = value - # ensure, struct_names is a list - if isinstance(struct_names, str): - struct_names = [struct_names] - - instance = items.get('instance', '') - template = collections.OrderedDict() - - global struct_merging_active - struct_merging_active = True - for struct_name in struct_names: - wrk = struct_name.find('@') - if wrk > -1: - add_struct_to_template(parent, struct_name[:wrk], template, struct_dict, struct_name[wrk+1:]) - else: - add_struct_to_template(parent, struct_name, template, struct_dict, instance) - if template != {}: - config = merge(template, config, source_name, 'Item-Tree') - struct_merging_active = False - - else: - #item is no struct - if isinstance(value, collections.OrderedDict): - # treat value as node - if parent == '': - path = key - else: - path = parent+'.'+key - # test if a aub-item is a struct - search_for_struct_in_items(value, struct_dict, config, source_name, parent=path, level=level+1) - template = collections.OrderedDict() - nested_put(template, path, value) - config = merge(template, config, source_name, 'Item-Tree') - - return - - -def remove_special_listentries(config, filename=''): - for k, v in config.items(): - if isinstance(v, dict): - remove_special_listentries(v, filename) - else: - if isinstance(v, list): - if len(v) > 0 and v[0] in ['merge*','merge_unique*']: - #logger.warning("remove_special_listentries: a list={} -> {} - {}".format(k, v, filename)) - del v[0] - -def set_attr_for_subtree(subtree, attr, value, indent=0): - ''' - - :param subtree: dict (subtree) to operate on - :param attr: Attribute to set for every item - :param value: Value to set the attribute to - :param indent: indent level (only for debug-logging) - - :return: - ''' - for k, v in subtree.items(): - if isinstance(v, dict): - v[attr] = value - spc = " " * 2 * indent - logger.debug("set_attr_for_subtree:{} node: {} => {}".format(spc, k, v)) - set_attr_for_subtree(v, attr, value, indent+1) - return - - -def add_struct_to_template(path, struct_name, template, struct_dict, instance): - ''' - Add the referenced struct to the items_template subtree - - :param path: Path of the item which references a struct (template) - :param struct_name: Name of the to use for the item - :param template: Template dict to be merged into the item tree - :param struct_dict: dict with all defined structs (from /etc/structs.yaml and from loaded plugins) - :param instance: For multi instance plugins: instance for which the items work (is derived from item with struct attribute) - - :return: - ''' - struct = struct_dict.get(struct_name, None) - if struct is None: - # no struct/template with this name - nf = collections.OrderedDict() - nf['name'] = "ERROR: struct '" + struct_name+"' not found!" - # nf['value'] = nf['name'] - nested_put(template, path, nf) - logger.error("add_struct_to_template: Struct definition for '{}' not found (referenced in item {})".format(struct_name, path)) - else: - # add struct/template to temporary item(template) tree - #logger.debug("- add_struct_to_template: struct_dict = {}".format(dict(struct_dict))) - logger.debug("- add_struct_to_template: {} <- struct = {}".format(path, struct_name)) - nested_put(template, path, copy.deepcopy(struct)) - if instance != '' or True: - # add instance to items added by template struct - subtree = nested_get(template, path) - # logger.info("add_struct_to_template: Adding 'instance: {}' to template for subtree '{}'".format(instance, path)) - # add instance name to attributes which carry '@instance' - logger.debug("- add_struct_to_template: subtree={}, instance={}".format(subtree, instance)) - replace_struct_instance(path, subtree, instance) - - return - - -def replace_struct_instance(path, subtree, instance): - """ - Replace the constant string '@instance' in attribute names with the real instance - (or remove the constant string '@instance', if the struct has no instace reference) - - :param path: - :param subtree: - :param instance: - :return: - """ - keys = list(subtree.keys()) - logger.info("replace_struct_instance: Setting instance to {} for subtree {}".format(instance, subtree)) - for key in keys: - # replace recursively - if Utils.get_type(subtree[key]) == 'collections.OrderedDict': - replace_struct_instance(path, subtree[key], instance) - if key.endswith('@instance'): - if instance == '': - newkey = key[:-9] - else: - newkey = key[:-9] + '@' + instance - #logger.debug("replace_struct_instance: - path {}: key '{}' --> newkey '{}'".format(path, key, newkey)) - subtree[newkey] = subtree.pop(key) - # logger.info("replace_struct_instance: Done set instance to {} for subtree {}".format(instance, subtree)) - return - - -def parse_yaml(filename, config=None, addfilenames=False, parseitems=False, struct_dict={}): - """ - Load and parse a yaml configuration file and merge it to the configuration tree - - :param filename: Name of the configuration file - :param config: Optional OrderedDict tree, into which the configuration should be merged - :param addfilenames: x - :param parseitems: x - :param struct_dict: dictionary with stuct definitions (templates) for reading item tree - :type filename: str - :type config: bool - :type addfilenames: bool - :type parseitems: bool - :type struct_dict: dict - - :return: The resulting merged OrderedDict tree - :rtype: OrderedDict - - - The config file should stick to the following setup: - - .. code-block:: yaml - - firstlevel: - attribute1: xyz - attribute2: foo - attribute3: bar - - secondlevel: - attribute1: abc - attribute2: bar - attribute3: foo - - thirdlevel: - attribute1: def - attribute2: barfoo - attribute3: foobar - - anothersecondlevel: - attribute1: and so on - - where firstlevel, secondlevel, thirdlevel and anothersecondlevel are defined as items and attribute are their respective attribute - value pairs - - Valid characters for the items are a-z and A-Z plus any digit and underscore as second or further characters. - Valid characters for the attributes are the same as for an item plus @ and * - - """ - logger.info("parse_yaml: Parsing file {}".format(os.path.basename(filename))) - if config is None: - config = collections.OrderedDict() - - items = shyaml.yaml_load(filename, ordered=True) - if items is not None: - remove_comments(items, filename) - remove_digits(items, filename) - remove_reserved(items, filename) - remove_keyword(items, filename) - remove_invalid(items, filename) - - if addfilenames: - #logger.debug("parse_yaml: Add filename = {} to items".format(os.path.basename(filename))) - _add_filenames_to_config(items, os.path.basename(filename)) - - if parseitems: - # test if file contains 'struct' attribute and merge all items into config - #logger.debug("parse_yaml: Checking if file {} contains 'struct' attribute".format(os.path.basename(filename))) - - search_for_struct_in_items(items, struct_dict, config, os.path.basename(filename)) - - global special_listentry_found - if special_listentry_found: - remove_special_listentries(config, os.path.basename(filename)) - special_listentry_found = False - - if not parseitems: - # if not parsing items - config = merge(items, config, os.path.basename(filename), 'Config-Tree') - return config - - -def _add_filenames_to_config(items, filename, level=0): - """ - Adds the name of the config file to the config items - - This routine is used to add the source filename to: - - be able to display the file an item is defined in (backend page items) - - to enable editing and storing back of item definitions - - This function calls itself recurselively - - """ - for attr, value in items.items(): - if isinstance(value, dict): - child_path = dict(value) - if (filename != ''): - value['_filename'] = filename - _add_filenames_to_config(child_path, filename, level+1) - return - - -# -------------------------------------------------------------------------------------- - - -def strip_quotes(string): - """ - Strip single-quotes or double-quotes from string beggining and end - - :param string: String to strip the quotes from - :type string: str - - :return: Stripped string - :rtype: str - - """ - string = string.strip() - if len(string) > 0: - if string[0] in ['"', "'"]: # check if string starts with ' or " - if string[0] == string[-1]: # and end with it - if string.count(string[0]) == 2: # if they are the only one - string = string[1:-1] # remove them - return string - - -def parse_conf(filename, config=None): - """ - Load and parse a configuration file which is in the old .conf format of smarthome.py - and merge it to the configuration tree - - :param filename: Name of the configuration file - :param config: Optional OrderedDict tree, into which the configuration should be merged - :type filename: str - :type config: bool - - :return: The resulting merged OrderedDict tree - :rtype: OrderedDict - - - The config file should stick to the following setup: - - .. code-block:: ini - - [firstlevel] - attribute1 = xyz - attribute2 = foo - attribute3 = bar - - [[secondlevel]] - attribute1 = abc - attribute2 = bar - attribute3 = foo - - [[[thirdlevel]]] - attribute1 = def - attribute2 = barfoo - attribute3 = foobar - - [[anothersecondlevel]] - attribute1 = and so on - - where firstlevel, secondlevel, thirdlevel and anothersecondlevel are defined as items and attribute are their respective attribute - value pairs - - Valid characters for the items are a-z and A-Z plus any digit and underscore as second or further characters. - Valid characters for the attributes are the same as for an item plus @ and * - - """ - - valid_set = set(valid_attr_chars) - if config is None: - config = collections.OrderedDict() - item = config - with open(filename, 'r', encoding='UTF-8') as f: - linenu = 0 - parent = collections.OrderedDict() - lines = iter(f.readlines()) - for raw in lines: - linenu += 1 - line = raw.lstrip('\ufeff') # remove BOM - while line.rstrip().endswith('\\'): - linenu += 1 - line = line.rstrip().rstrip('\\') + next(lines, '').lstrip() - line = line.partition('#')[0].strip() - if line is '': - continue - if line[0] == '[': # item - brackets = 0 - level = 0 - closing = False - for index in range(len(line)): - if line[index] == '[' and not closing: - brackets += 1 - level += 1 - elif line[index] == ']': - closing = True - brackets -= 1 - else: - closing = True - if line[index] not in valid_item_chars + "'": - logger.error("Problem parsing '{}' invalid character in line {}: {}. Valid characters are: {}".format(filename, linenu, line, valid_item_chars)) - return config - if brackets != 0: - logger.error("Problem parsing '{}' unbalanced brackets in line {}: {}".format(filename, linenu, line)) - return config - name = line.strip("[]") - name = strip_quotes(name) - - if len(name) == 0: - logger.error("Problem parsing '{}' tried to use an empty item name in line {}: {}".format(filename, linenu, line)) - return config - elif name[0] in digits: - logger.error("Problem parsing '{}': item starts with digit '{}' in line {}: {}".format(filename, name[0], linenu, line)) - return config - elif name in reserved: - logger.error("Problem parsing '{}': item using reserved word set/get in line {}: {}".format(filename, linenu, line)) - return config - elif keyword.iskeyword(name): - logger.error("Problem parsing '{}': item using reserved Python keyword {} in line {}: {}".format(filename, name, linenu, line)) - return config - - if level == 1: - if name not in config: - config[name] = collections.OrderedDict() - item = config[name] - parents = collections.OrderedDict() - parents[level] = item - else: - if level - 1 not in parents: - logger.error("Problem parsing '{}' no parent item defined for item in line {}: {}".format(filename, linenu, line)) - return config - parent = parents[level - 1] - if name not in parent: - parent[name] = collections.OrderedDict() - item = parent[name] - parents[level] = item - - else: # attribute - attr, __, value = line.partition('=') - if not value: - continue - attr = attr.strip() - if not set(attr).issubset(valid_set): - logger.error("Problem parsing '{}' invalid character in line {}: {}. Valid characters are: {}".format(filename, linenu, attr, valid_attr_chars)) - continue - - if len(attr) > 0: - if attr[0] in digits: - logger.error("Problem parsing '{}' attrib starts with a digit '{}' in line {}: {}.".format(filename, attr[0], linenu, attr )) - continue - if '|' in value: - item[attr] = [strip_quotes(x) for x in value.split('|')] - else: - item[attr] = strip_quotes(value) - return config From fd90e765241b187873c2aa02365a2b22f15a087a Mon Sep 17 00:00:00 2001 From: msinn Date: Tue, 21 Apr 2020 17:17:46 +0200 Subject: [PATCH 021/126] logics: Added sh, items, shtime to context 'logic' to increase support for functions in logics --- lib/logic.py | 5 +++-- lib/scheduler.py | 15 +++++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/logic.py b/lib/logic.py index 309bfd2edd..59a9cadaf1 100644 --- a/lib/logic.py +++ b/lib/logic.py @@ -939,11 +939,12 @@ class Logic(): _logicname_prefix = 'logics.' def __init__(self, smarthome, name, attributes, logics): - self._sh = smarthome + self.sh = smarthome # initialize to use 'logic.sh' in logics + self.logger = logger # initialize to use 'logic.logger' in logics self.name = name + self.shtime = logics.shtime self.lname = "Logic '"+name+"'" # string is to be used in item assignements sh.xxx(, logic.lname) self._logics = logics # access to the logics api - self.shtime = self._logics.shtime self.enabled = True if 'enabled' not in attributes else Utils.to_bool(attributes['enabled']) self.crontab = None self.cycle = None diff --git a/lib/scheduler.py b/lib/scheduler.py index 5237a1482d..03f679daff 100644 --- a/lib/scheduler.py +++ b/lib/scheduler.py @@ -326,10 +326,10 @@ def add(self, name, obj, prio=3, cron=None, cycle=None, value=None, offset=None, :param next: :param from_smartplugin: Only to set to True, if called from the internal method in SmartPlugin class """ - # Todo: Why the following 4 lines? self.shtime is set within __init__ + # set shtime and items if they were initialized to None in __init__ (potenital timing problem in init of shng) if self.shtime == None: self.shtime = Shtime.get_instance() - if self.shtime == None: + if self.items == None: self.items = Items.get_instance() self._lock.acquire() if isinstance(cron, str): @@ -509,14 +509,21 @@ def _task(self, name, obj, by, source, dest, value): source_details = source.get('details', '') source = source.get('item', '') trigger = {'by': by, 'source': source, 'source_details': source_details, 'dest': dest, 'value': value} # noqa - logic = obj # noqa - logics = obj._logics #following variables are assigned to be available during logic execution sh = self._sh # noqa shtime = self.shtime items = self.items + # set the logic environment here (for use within functions in logics): + logic = obj # noqa + logic.sh = sh + logic.logger = logger + logic.shtime = shtime + logic.items = items + + logics = obj._logics + if not self.mqtt: if _lib_modules_found: self.mqtt = Modules.get_instance().get_module('mqtt') From b405cba3cdc82a75afea4d99985d60418345364e Mon Sep 17 00:00:00 2001 From: msinn Date: Sat, 25 Apr 2020 10:41:43 +0200 Subject: [PATCH 022/126] Added Badges to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d9cb5bbf75..725d966da5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # SmartHomeNG + +![Github Tag](https://img.shields.io/github/tag/smarthomeNG/smarthome.svg) +![Made with Python](https://img.shields.io/badge/made%20with-python-blue.svg) [![Build Status on TravisCI](https://travis-ci.org/smarthomeNG/smarthome.svg?branch=develop)](https://travis-ci.org/smarthomeNG/smarthome) [![Join the chat at https://gitter.im/smarthomeNG/smarthome](https://badges.gitter.im/smarthomeNG/smarthome.svg)](https://gitter.im/smarthomeNG/smarthome?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) From 4a9c1ca9cfc0f285e2a04c681a5ef650664fd0a6 Mon Sep 17 00:00:00 2001 From: msinn Date: Sat, 25 Apr 2020 11:15:02 +0200 Subject: [PATCH 023/126] Removed folder 'examples' which only contained deprecated stuff --- README.md | 61 ++- examples/items/smartvisu.conf | 212 -------- examples/items/smartvisu.yaml | 271 ---------- examples/old/css/images/ajax-loader.gif | Bin 7825 -> 0 bytes examples/old/css/images/icons-18-black.png | Bin 1767 -> 0 bytes examples/old/css/images/icons-18-white.png | Bin 1806 -> 0 bytes examples/old/css/images/icons-36-black.png | Bin 3611 -> 0 bytes examples/old/css/images/icons-36-white.png | Bin 3648 -> 0 bytes examples/old/css/jquery.mobile.min.css | 2 - examples/old/css/my.css | 32 -- examples/old/example.html | 200 ------- examples/old/gen/.gitignore | 4 - examples/old/img/example.png | Bin 3717 -> 0 bytes examples/old/img/off.png | Bin 3229 -> 0 bytes examples/old/img/on.png | Bin 3291 -> 0 bytes examples/old/js/jquery.flot.min.js | 1 - examples/old/js/jquery.flot.time.min.js | 1 - examples/old/js/jquery.min.js | 5 - examples/old/js/jquery.mobile.min.js | 2 - examples/old/js/my.smarthome.js | 8 - examples/old/js/smarthome.js | 594 --------------------- examples/old/js/smarthome.min.js | 1 - examples/old/tpl/footer.html | 16 - examples/old/tpl/header.html | 18 - examples/smarthome.service | 13 - 25 files changed, 44 insertions(+), 1397 deletions(-) delete mode 100644 examples/items/smartvisu.conf delete mode 100644 examples/items/smartvisu.yaml delete mode 100644 examples/old/css/images/ajax-loader.gif delete mode 100644 examples/old/css/images/icons-18-black.png delete mode 100644 examples/old/css/images/icons-18-white.png delete mode 100644 examples/old/css/images/icons-36-black.png delete mode 100644 examples/old/css/images/icons-36-white.png delete mode 100644 examples/old/css/jquery.mobile.min.css delete mode 100644 examples/old/css/my.css delete mode 100755 examples/old/example.html delete mode 100644 examples/old/gen/.gitignore delete mode 100644 examples/old/img/example.png delete mode 100644 examples/old/img/off.png delete mode 100644 examples/old/img/on.png delete mode 100644 examples/old/js/jquery.flot.min.js delete mode 100644 examples/old/js/jquery.flot.time.min.js delete mode 100644 examples/old/js/jquery.min.js delete mode 100644 examples/old/js/jquery.mobile.min.js delete mode 100644 examples/old/js/my.smarthome.js delete mode 100644 examples/old/js/smarthome.js delete mode 100644 examples/old/js/smarthome.min.js delete mode 100755 examples/old/tpl/footer.html delete mode 100755 examples/old/tpl/header.html delete mode 100644 examples/smarthome.service diff --git a/README.md b/README.md index 725d966da5..aa9b644330 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ Additional information / documentation can be found in the [SmartHomeNG Wiki](ht |dev | if you plan to create a plugin then this is the folder you want to have a closer look at | |doc | Source files for the user- and developer documentation | |etc | the three basic configuration files smarthome.yaml, module.yaml, plugin.yaml, logic.yaml and logging.yaml are located here, you will edit these files to reflect your basic settings| -|examples | some examples of items, etc. this is only for informational purpose | |items | put here your own files for your items | |lib | some more core python modules are in this directory. You won't need to change anything here |logics | here your logic files are put @@ -57,41 +56,69 @@ elev: 36 tz: Europe/Berlin ``` +### etc/module.yaml +Upon installation you will need to create this file and configure the modules and their parameters. On first start of SmartHomeNG this file is created from ```etc/module.yaml.default```. + +An example is shown below: + +```yaml +# module.yaml +http: + module_name: http + starturl: admin + +admin: + module_name: admin + +#enable, if mqtt protocol is going to be used +#mqtt: +# module_name: mqtt + +``` ### etc/plugin.yaml -Upon installation you will need to create this file and configure the plugins and their attributes. -An example is shown below +Upon installation you will need to create this file and configure the plugins and their parameters. On first start of SmartHomeNG this file is created from ```etc/plugin.yaml.default```. + + +An example is shown below: ```yaml # plugin.yaml +database: + plugin_name: database + driver: sqlite3 + connect: + - database:./var/db/smarthomeng.db + - check_same_thread:0 + +cli: + plugin_name: cli + ip: 0.0.0.0 + update: True + +websocket: + plugin_name: visu_websocket + + knx: plugin_name: knx host: 127.0.0.1 port: 6720 -# send_time: 600 # update date/time every 600 seconds, default none -# time_ga: 1/1/1 # default none -# date_ga: 1/1/2 # default none ow: plugin_name: onewire -visu: - plugin_name: visu_websocket - smartvisu: plugin_name: visu_smartvisu smartvisu_dir: /var/www/html/smartVISU -cli: - plugin_name: cli - ip: 0.0.0.0 - update: 'True' -sql: - plugin_name: database ``` ### etc/logic.yaml -In the logic.conf you specify your logics and when they will be run. An example is shown below +In the logic.conf you specify your logics and when they will be run. +On first start of SmartHomeNG this file is created from ```etc/logic.yaml.default```. + + An example is shown below ```yaml # etc/logic.yaml @@ -117,7 +144,7 @@ global: This directory contains your logic files. Simple or sophisitcated python scripts. You could address your smarthome item by `sh.item.path`. If you want to read an item call `sh.item.path()` or to set an item `sh.item.path(Value)`. -``` +```python # logics/sunset.py if sh.global.sun(): # if sh.global.sun() == True: sh.gloabl.sun(False) # set it to False diff --git a/examples/items/smartvisu.conf b/examples/items/smartvisu.conf deleted file mode 100644 index 772df59ed9..0000000000 --- a/examples/items/smartvisu.conf +++ /dev/null @@ -1,212 +0,0 @@ - -[first] - [[hallway]] - name = Hallway - sv_page = room - sv_img = scene_stairs.png - [[[light]]] - name = Light - type = bool - visu_acl = rw - sv_widget = {{ basic.switch('item', 'item') }} - [[[door]]] - name = Door - type = bool - [[living]] - name = Living Room - sv_page = room - sv_img = scene_livingroom.png - [[[light]]] - [[[ceiling]]] - name = Ceiling Light - type = bool - visu_acl = rw - sv_widget = {{ device.dimmer('item', 'item.name', 'item', 'item.level') }} - [[[[level]]]] - type = num - visu_acl = rw - [[[ambiant]]] - name = Ambiant Light - type = bool - visu_acl = rw - sv_widget = {{ basic.colordisc('item', 'item.r', 'item.g', 'item.b') }} - [[[[r]]]] - type = num - visu_acl = rw - [[[[g]]]] - type = num - visu_acl = rw - [[[[b]]]] - type = num - visu_acl = rw - [[[temperature]]] - name = Temperature - type = num - value = 21 - sqlite = yes -# ow_addr = 28.8DEAAA030000 -# ow_sensor = T - sv_widget = {{ device.rtr('item', 'item.name', 'item', 'item.set', 'item.mode', 'item.night', 'item.frost', 'item.state') }} - [[[[set]]]] - type = num - value = 20.5 - visu_acl = rw - cache = yes - [[[[mode]]]] - type = num - visu_acl = rw - [[[[night]]]] - type = num - visu_acl = rw - [[[[frost]]]] - type = num - visu_acl = rw - [[[[state]]]] - type = num - visu_acl = rw - [[[humidity]]] - name = Humidity - type = num - value = 50 - sqlite = yes -# ow_addr = 26.8DD76B010000 -# ow_sensor = H - sv_widget = {{ plot.comfortchart('item', 'first.living.temperature', 'item') }} - [[[blind]]] - name = Shutter - sv_widget = {{ device.shutter('item', 'item.name', 'item.move', 'item.stop', 'item.pos', '', 'item.tilt') }} - [[[[move]]]] - type = num - visu_acl = rw - [[[[stop]]]] - type = num - visu_acl = rw - [[[[pos]]]] - type = num - visu_acl = rw - [[[[tilt]]]] - type = num - visu_acl = rw - [[[window]]] - name = Window - type = bool - [[[door]]] - name = Door - type = bool - -[second] - [[sleeping]] - name = Sleeping Room - sv_page = room - sv_img = scene_sleeping.png - [[[light]]] - name = Light - type = bool - visu_acl = rw - sv_widget = {{ device.dimmer('item', 'item.name', 'item', 'item.level') }} - knx_dpt = 1 - knx_listen = 3/2/12 - knx_send = 3/2/12 - [[[[level]]]] - type = num - visu_acl = rw - knx_dpt = 5 - knx_listen = 3/2/14 - knx_send = 3/2/14 - [[[scence]]] - name = Scene - type = str - visu_acl = rw - sv_widget = {{ basic.button('item', 'item', 'item.name') }} - [[[temperature]]] - name = Temperature - type = num - sqlite = yes - sv_widget = {{ device.rtr('item', 'item.name', 'item', 'item.set', 'item.mode', 'item.night', 'item.frost', 'item.state') }} | {{ plot.period('item-plot', 'item', 'avg') }} - [[[[set]]]] - type = num - visu_acl = rw - cache = yes - [[[[mode]]]] - type = num - visu_acl = rw - [[[[night]]]] - type = num - visu_acl = rw - [[[[frost]]]] - type = num - visu_acl = rw - [[[[state]]]] - type = num - visu_acl = rw - [[[blind]]] - name = Shutter - sv_widget = {{ device.shutter('item', 'item.name', 'item.move', 'item.stop', 'item.pos', '', 'item.tilt') }} - [[[[move]]]] - type = num - visu_acl = rw - [[[[stop]]]] - type = num - visu_acl = rw - [[[[pos]]]] - type = num - visu_acl = rw - [[[[tilt]]]] - type = num - visu_acl = rw - [[[window]]] - name = Window - type = bool - [[bath]] - name = Bath Room - sv_page = room - sv_img = scene_bath.png - [[[light]]] - name = Light - type = bool - visu_acl = rw - sv_widget = {{ device.dimmer('item', 'item.name', 'item', 'item.level') }} - [[[[level]]]] - type = num - visu_acl = rw - [[[temperature]]] - name = Temperature - type = num - sqlite = yes - sv_widget = {{ device.rtr('item', 'item.name', 'item', 'item.set', 'item.mode', 'item.night', 'item.frost', 'item.state') }} - [[[[set]]]] - type = num - visu_acl = rw - cache = yes - [[[[mode]]]] - type = num - visu_acl = rw - [[[[night]]]] - type = num - visu_acl = rw - [[[[frost]]]] - type = num - visu_acl = rw - [[[[state]]]] - type = num - visu_acl = rw - [[[scence]]] - name = Scene - type = str - visu_acl = rw - sv_widget = {{ basic.button('item', 'item', 'item.name') }} - [[[blind]]] - name = Shutter - sv_widget = {{ device.shutter('item', 'item.name', 'item.move', 'item.stop', 'item.pos', '', 'item.tilt') }} - [[[[move]]]] - type = num - visu_acl = rw - [[[[stop]]]] - type = num - visu_acl = rw - [[[[pos]]]] - type = num - visu_acl = rw - [[[[tilt]]]] - type = num - visu_acl = rw diff --git a/examples/items/smartvisu.yaml b/examples/items/smartvisu.yaml deleted file mode 100644 index da8d3b9c8c..0000000000 --- a/examples/items/smartvisu.yaml +++ /dev/null @@ -1,271 +0,0 @@ -%YAML 1.1 ---- - -first: - - hallway: - name: Hallway - sv_page: room - sv_img: scene_stairs.png - - light: - name: Light - type: bool - visu_acl: rw - sv_widget: "{{ basic.switch('item', 'item') }}" - - door: - name: Door - type: bool - - living: - name: Living Room - sv_page: room - sv_img: scene_livingroom.png - light: {} - - ceiling: - name: Ceiling Light - type: bool - visu_acl: rw - sv_widget: "{{ device.dimmer('item', 'item.name', 'item', 'item.level') }}" - - level: - type: num - visu_acl: rw - - ambiant: - name: Ambiant Light - type: bool - visu_acl: rw - sv_widget: "{{ basic.colordisc('item', 'item.r', 'item.g', 'item.b') }}" - - r: - type: num - visu_acl: rw - - g: - type: num - visu_acl: rw - - b: - type: num - visu_acl: rw - - temperature: - name: Temperature - type: num - value: 21 - sqlite: 'yes' - # ow_addr = 28.8DEAAA030000 - # ow_sensor = T - sv_widget: "{{ device.rtr('item', 'item.name', 'item', 'item.setpoint', 'item.mode', 'item.night', 'item.frost', 'item.state') }}" - - setpoint: - type: num - value: '20.5' - visu_acl: rw - cache: 'yes' - - mode: - type: num - visu_acl: rw - - night: - type: num - visu_acl: rw - - frost: - type: num - visu_acl: rw - - state: - type: num - visu_acl: rw - - humidity: - name: Humidity - type: num - value: 50 - sqlite: 'yes' - # ow_addr = 26.8DD76B010000 - # ow_sensor = H - sv_widget: "{{ plot.comfortchart('item', 'first.living.temperature', 'item') }}" - - blind: - name: Shutter - sv_widget: "{{ device.shutter('item', 'item.name', 'item.move', 'item.stop', 'item.pos', '', 'item.tilt') }}" - - move: - type: num - visu_acl: rw - - stop: - type: num - visu_acl: rw - - pos: - type: num - visu_acl: rw - - tilt: - type: num - visu_acl: rw - - window: - name: Window - type: bool - - door: - name: Door - type: bool - -second: - - sleeping: - name: Sleeping Room - sv_page: room - sv_img: scene_sleeping.png - - light: - name: Light - type: bool - visu_acl: rw - sv_widget: "{{ device.dimmer('item', 'item.name', 'item', 'item.level') }}" - knx_dpt: 1 - knx_listen: 3/2/12 - knx_send: 3/2/12 - - level: - type: num - visu_acl: rw - knx_dpt: 5 - knx_listen: 3/2/14 - knx_send: 3/2/14 - - scence: - name: Scene - type: str - visu_acl: rw - sv_widget: "{{ basic.button('item', 'item', 'item.name') }}" - - temperature: - name: Temperature - type: num - sqlite: 'yes' - sv_widget: - - "{{ device.rtr('item', 'item.name', 'item', 'item.setpoint', 'item.mode', 'item.night', 'item.frost', 'item.state') }}" - - "{{ plot.period('item-plot', 'item', 'avg') }}" - - setpoint: - type: num - visu_acl: rw - cache: 'yes' - - mode: - type: num - visu_acl: rw - - night: - type: num - visu_acl: rw - - frost: - type: num - visu_acl: rw - - state: - type: num - visu_acl: rw - - blind: - name: Shutter - sv_widget: "{{ device.shutter('item', 'item.name', 'item.move', 'item.stop', 'item.pos', '', 'item.tilt') }}" - - move: - type: num - visu_acl: rw - - stop: - type: num - visu_acl: rw - - pos: - type: num - visu_acl: rw - - tilt: - type: num - visu_acl: rw - - window: - name: Window - type: bool - - bath: - name: Bath Room - sv_page: room - sv_img: scene_bath.png - - light: - name: Light - type: bool - visu_acl: rw - sv_widget: "{{ device.dimmer('item', 'item.name', 'item', 'item.level') }}" - - level: - type: num - visu_acl: rw - - temperature: - name: Temperature - type: num - sqlite: 'yes' - sv_widget: "{{ device.rtr('item', 'item.name', 'item', 'item.setpoint', 'item.mode', 'item.night', 'item.frost', 'item.state') }}" - - setpoint: - type: num - visu_acl: rw - cache: 'yes' - - mode: - type: num - visu_acl: rw - - night: - type: num - visu_acl: rw - - frost: - type: num - visu_acl: rw - - state: - type: num - visu_acl: rw - - scence: - name: Scene - type: str - visu_acl: rw - sv_widget: "{{ basic.button('item', 'item', 'item.name') }}" - - blind: - name: Shutter - sv_widget: "{{ device.shutter('item', 'item.name', 'item.move', 'item.stop', 'item.pos', '', 'item.tilt') }}" - - move: - type: num - visu_acl: rw - - stop: - type: num - visu_acl: rw - - pos: - type: num - visu_acl: rw - - tilt: - type: num - visu_acl: rw diff --git a/examples/old/css/images/ajax-loader.gif b/examples/old/css/images/ajax-loader.gif deleted file mode 100644 index fd1a189c21fed1c7ba00c4bb4fad407bd6d1e5f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7825 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 LHfkt@K(PD|Q{O_Y diff --git a/examples/old/css/images/icons-18-black.png b/examples/old/css/images/icons-18-black.png deleted file mode 100644 index ce1b758ad580663f92c36fb0902afb677ded0b11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1767 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 diff --git a/examples/old/css/images/icons-36-black.png b/examples/old/css/images/icons-36-black.png deleted file mode 100644 index 1a59d7c375d6611262a9ac86db23eb94570d7319..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3611 zcmYk9c{J4BAIHu1#h4k}&`?QZ--jkk*(PIOq7W6Pgt3mE#3ea=1ibMEV!vy(LvE(;eB5J1}65RV85 z0Ej)@wfhP#Gmy^TOz@g>b;n&Lm9ObYZdgS?g0Ef`793E(^K(2U#a*o>x~G) zPGk!PFYlJOw~TE&h0=^5<>xKGXZr@kOqE2Mj8MB$$ATv{K9QH6{fLeX#n>rITq9yr zZT`Q&ex_7_?Q3rEgcD58{zzKLUpIJ19ecq3%jO|1k^_G&zi<984Pc%UmQV{wNoWI z+^B#Jv;$lq0cJXA#suiF^HXTvm*mF^B%1XQm$m~*ZpMiRJC<oyc4QEr%cc1r5~?!E8Q5%-G%^e> znqkD+Sj;?1W5{yp*)Zho-)}4Is|rpLaO8Z>){OO|S8Ml->M!KXUnO;$Jzrm4$n7~y zoFT%LPq)%Bnk$~;P4;P`96gz)Y_0IuFxX+?i=F- z9S4=(rhI`D80+~ZQMKCA)PUwI8Pqr!azWlP{`{$s9f|T1cNApQZ3rTmyJc>|#EuH8 z_#0cHWn)E6{*CBo)l7}50$MC3c8X#-+ULtoTH7fADL)iU1XJph#6-R2YGNdK7w#00 zwR@3%A3V&issXwqEbeFG*1Ka^k~u40cVAWW ztO|GC@cu5N{ud|5;6^f~g*cBu9sh z*O)4sxQ+MjmA$E1z_S*{bQDqP0O|@ORAs6=bMO|jW8T%>uwaDG%ix<(|?Rj{Cz9aaEw(Gy6_oRY{ z>E+y5WcYC!Ip6)+OJS$?YML(}(Fudw7jn89u9ub0N9@=wcdo=tA9Gh!qwf?q)LXK6 zSUV`V_hZ_+5q&TX*f&sql%al8+E9rs2BX82$lHOS z6{y0c6-s+Zz$Ga{QQY}fif-9axY3l%1$$ERrn)%_6sVZ$7h3c|Xj*;fAzpF2|3ov0 zZB&HFfJRpOt8Cm7s-`sx)CHvl)#lj@WFO3ZbZ&G5hA0;VEjKS-PBimdH8)Gl9kC9D z#9XdAuGbl&0|$~v-Zb&rE;-G+u!}0PDw6_hG(~}PCc1n1+64z>M>-0o?u^8ua!wW3qpT_e(Gv_|_E>L%A^L6`5i;aCcv|FUYH( za>$0*L;KMM0Oe69ghxC#4^&*b?{p3>oOyU$waki}FW~KIBM-Euz+&?Wk*CFP9U^&% zAdIDn2cvEo502M(Ef@?m&isDu>$d*gV{sCqPu1LbMWWT|?#66Hb1NUp^;>*CE6k-8 z2{#`Q52UgOS?-`>f*KLRVls~=UI{WUh3!2B8d0>cIM31+etoBs*q?r})xDtwxcDXuC zZ+wpojT>~8z(}9r#&n-h{cN1zATlsYo3&x2>1rvkBu^YO;&5)EMd(IeT zrnZ%Qz+s&66YXH+ei&pe-sftEFytke$WD%prNro*Hs0fXJ3yvr>Mc`DXu#n@HS-&T5^JYkN}>+g(6p zCTnqC7^k{v3F0xj)?h_%+{d&`G7Ff|k?x7@(ZpS+8ysG>yY&VWiCaw3pD^$k5Wg1I|fDkRag8Q_TzvWct zy_)fDs<#jUW}D%~aMEkzeOpV$PXqz!CgSvqTCC%YRVfUO#Q2yfWl862Dwun!s#MeV zAQ3AjXfc#}+r`>+!&ubLj%H2zlf}3dDjn1M04caz_xSJB34@+{8 z4njrN4!l&pRn+NXFz{VN!TL z$-HL*E90F!R}hjRzE?T~g1Ed(qi>+3q6>sF4Onlrh~|5py|W>inR8KxVGx}l<$kisNU@!wIO-8y-A9rsebH;;8m;(@pSAy1v9nY%^%;N9xx$>)3 z8l;I=QFKNc=!;l*DffgfouEuIFZzXLZ}`n`sgr3W8nVh{Ww!N-bc9UmFb2c>(kF}` zYJb`#2e+!8uo}$tV;e6U%w!1zSO{$R%=M#?ci&@@aN&vKyJTJI>9wB}`@muNvZ3DY z%?&I@u{>(S?M!-Vtbbbro{UpX8B!$Oq^dekOSusm^?r_w*ZSwa95Hv=YK1<~6S7`f ze)mbczu0PLXd}?@taHu!hDW%Of8CkvVQ(~*QmyUfCu=Q->hAGOg01l}<-LcIWw4c| z@yyv@B=eC2fpcvXowSX!x(WDcg6UxD=&7AwP(;kavxow)lsS%n^J~M z24k_I8gzS(ckrZbu6Mx^l-fB*ep`SDAq;}*6RC?dP-v@(T&Awq1yyR`3z3(9Zi(}kU&Ny{y7K%@ zWj|~{nSx{@z3p-jic5c%5%6L8t-^m8WKuRiOyZ08Ipe9ljP{tanp$TTha-az>SeFCnqcU`!aom@$6~Ma8kXJ<=c=NWL8VcP=ROPg>sC?x!h1Me_S7 zO_6^LnK9RB?KFjOtRat{>Z_7mnQ}z4g9q{NFgln=630C`nt$MRpF`;x84DEIxn7UNU_ z6tT*gS-ldTlExL>hU)bG11B2YvhUhQ{qjshLpABhRI9D#W+8k*r*r_uQ{Zrz{4aV zlr@VmZ-646-rD`G^w%od=hofo=(z$;GT6o88_PLroV5hYPjMAS5nrDuz7Y%k^5NrM z9ZZYvxYDqN=?c}-DH;DdhFwRTxNR^ku{+%yRi)EhCZ3JSkcJg+_RPvDpL32?9R~|@ z*&Sc>Rb?fka$fIKPgucI2?VfZV}w(Gh;ua=Lx@gl;AGW!{4}f+jHXKOV@zN@U;JK@ za=yz_*qZEI@Mu`7-5Y_#3JB8f{Uw{ojV(8pz|1TYeCT9F4M4AUjz5KM$w=l25sYxr z_sc!A{!?PlEf&sQS$Rne7@Q!Z*2`%z;p`TfLj>@$dP|fkr`&Y8uzq^4*wgbtd)a*%a8~kzL&b z#Hg6&D7OxIX`%a)swjeE#!zLnqvh%E^KML#qSn}Y#%-ziAeU1$BE3A~FSyae*=*cTSWDO58VS@rhGEgg2Y}bC06fiuclI z#o2-pZCeg0iV^g=^#ro`myOz0l2ne>W*L^l)h>(%z=a(=E}m=n5H0>&#q4Cq*AI|I zkBk(*O)3A6?)=2Q21t|7OygjB8NQe=y-NMPCx8FfonB$m3Dk8}xIXJeauC@ZLOt1_ zoJ6oeMzQmMm(Afhmx3CkHx6bLz+qg(uh$FdG|lWdyfqpzzXWq-wKKpn#y{_V(aiZV z0Vmb^x&WxQ2JYpWn{Q{F>E$pRi6GNeCGqh!rZ?V5J$O$BqD!nSD%#HL>Bb@b!4)Qo z0hEKU8dFS$H`9N;I`NhbSoDZgV}D%xoL%}dPpPYCSTvkVWr;V`S;E785yG0yd~TeT z-$UHRX((=f+f3R-eQGJQRMr~ze{g}+tnTDGW_e3bV`QX+=0L{Yw_i6Uf@MJpN)1L@R$^ZVTFTW?Up6Z*N&=Td;1kT^#6ZYd8io<9! zFLMoOSi6SUw67H=+=Q-JAGu14+p9Q)KLl&0zS_4_i{%Qm+rt#?S8JvjjyHZ*hm+#N zZ(m6`k$4MwZ5mnJ-=46yUNUovM1>rVN61ok>gIVJo$B83KHZ%pb(Jmg7O66$4(|6y z5uE@u>t0N!rul9y=MyX*=5jwIFuhki#vdi45vhvC(SS)YF$3yBC9u3N~)dXvyJaHl{B;>$v2 zMI(ei)pg|f-CS4G*sOjO6U190q}Dk%Zl5)=aWMI5_~xX0bZwanR+SLl{-d{_aR$zG z=Q=*)qZpiYec1J0*xHLaa<{I**3xTNMYT1DgLz{^XpQq#2)H~Sg)dnG6%NMNp05(pk5N0TwPGYisyl!OOc z>!+Chs%vh7`)mqvq`F(8&7lvS%o4J>CB*>T1AKasmVoXfLTkH`&~RWaUWb^T2*<80 zQOkhk$3KLaq^3meE7`WHuWDYgrUl8MB%fTJ`4I{u6?x6?l$MNa+B7Fuc|=@9wN>Cu zU6sV)<7-Y742(3QM((~PH&s!adV6Rs^`Wg8WzIL)fMeb=gag~z>5h)lPs$aLRzW#* z`qmh}xB)Gt!lTO!6bL&PczNE{scVum>Qu;E{g!?S-TTTJC0R7UV{qTpX^|@m`lArCv&uZ z?bu?#r2=nVY;FWC+q)xWleBpGhLnt4JEq45m~Tig@l3u78eSGGCaB5*wu*QvU3lws zY-xhVrwe%46mnr*TM&yKA;-WyF&tVVL?ziX>;+8}4RV>=#eKYwKJUxplaZjbFHhYm zcA`I54%XdIt4_-wO)-b!RTw|_v71-1obV(aQN24?p$F4ljaquqgj8&e1A(To|Gve2 zZ1T^_NI@JAP2oCApa4GVgp=$!IW($B47l_P`b4mR#ql*Ssp!a#r1LC!LlJ7%$cAo< z9D2c_L<;i`?zf729`GtNESFD+xKH|L9Xon`4#(+j2#MUclblK3v*6_T==xCc!e&`^ z;T29PmIxIpacBLM6Tg<8;nTZ}+5D%9!%~=Zu+R$g&z~A>tFSqOSh=mdB`hLv^&8^8 z{=z-u3;G-aJfcEn!&!v|)D*=hN%UV_NiN0Qd&vua-gi(61OF{LZi`U$ymSKr6@ndB zBi7vnR*3|{J8=mm+j! zuNKo=V0f9RW5L!)?_IBOy;)_bbfchDsH;mqroCGeV6LE#Lh}Wx?q6&wBzJF7ZjO)Q ze7x+>qLC`I3m3m5R^M%Y2~}@-wg4kp+yo{^9c(m|5j&6Oc#obTt6pJ>weBNivnC!K zXc%%ZEBihY)SdweXCIy^u}u^YsHk)9uT_dWl~^85%&UaFvanU~e0ij*QQO0v{U}g$ z)hxlOn+J`Q#3bRBy~k(2#@@2Ua*VrK^)hYuMw-rAPa(;e2f)m#ymmy0O=mK>*+CG$ zeT2(rgG=JT!eD#Y6J~pRn9W(QXS^nPs$esPK-{`v!+18kiBoJdIOi| zImTWZxC}*PgaydUTvcIst1KJUSw>YE8gk_HG*w5+%6v$QhCYiQ5`KyL*_1YCJLk@a7=|a<3Fxw7liQNo6AM$gy-T&;Z1^KM%~7!gDOnB zY|g~RnB6=XpcF8BHk4ZdY)c)&9qByc=T){#vwcU5U&Uajy8K;EYY*^YhYn+JRS~i+ zF-jhVrgj|jB-I2&CdSWtKVjELrZ)213;Kim2eS8|krIBznUcH?zmM7%Q=Uxn7!;I% zE4&_eea~-ZtXWn4^MSE%9hJz@fSlXuOo_i9&cr;pbJF_5*{`XlYkR5Gu(zUs<@K|i zMR&ChCF!LOMBYuFiPP1X!W&(( zuJauxEO0sA{k@Aw<<3Z65wA$p;sz=KyhGC#s?qhM_am7*O}md1Zu9J>NY2DM1+scy z>zGrjPCCw*>KwyJn|14jR4Rbsda_aQRxtb`??2Vs%Eupqmq}e;6IeOyd}_5f1_<_z zo?5NmX~FNs|I0XJM7j`S+Ye*uq~ A8~^|S diff --git a/examples/old/css/jquery.mobile.min.css b/examples/old/css/jquery.mobile.min.css deleted file mode 100644 index 1ab3c2bf8e..0000000000 --- a/examples/old/css/jquery.mobile.min.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery Mobile vGit Build: SHA1: b49cc06499abf8f987cf90f35349cfac0918c939 <> Date: Tue Oct 2 11:22:34 2012 -0700 jquerymobile.com | jquery.org/license !*/ -.ui-bar-a{border:1px solid #333;background:#111;color:#fff;font-weight:bold;text-shadow:0 -1px 1px #000;background-image:-webkit-gradient(linear,left top,left bottom,from( #3c3c3c ),to( #111 ));background-image:-webkit-linear-gradient( #3c3c3c,#111 );background-image:-moz-linear-gradient( #3c3c3c,#111 );background-image:-ms-linear-gradient( #3c3c3c,#111 );background-image:-o-linear-gradient( #3c3c3c,#111 );background-image:linear-gradient( #3c3c3c,#111 )}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a a.ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-a a.ui-link:visited{color:#2489ce}.ui-bar-a a.ui-link:hover{color:#2489ce}.ui-bar-a a.ui-link:active{color:#2489ce}.ui-body-a,.ui-overlay-a{border:1px solid #444;background:#222;color:#fff;text-shadow:0 1px 1px #111;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from( #444 ),to( #222 ));background-image:-webkit-linear-gradient( #444,#222 );background-image:-moz-linear-gradient( #444,#222 );background-image:-ms-linear-gradient( #444,#222 );background-image:-o-linear-gradient( #444,#222 );background-image:linear-gradient( #444,#222 )}.ui-overlay-a{background-image:none;border-width:0}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:bold}.ui-body-a .ui-link:visited{color:#2489ce}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-btn-up-a{border:1px solid #111;background:#333;font-weight:bold;color:#fff;text-shadow:0 1px 1px #111;background-image:-webkit-gradient(linear,left top,left bottom,from( #444 ),to( #2d2d2d ));background-image:-webkit-linear-gradient( #444,#2d2d2d );background-image:-moz-linear-gradient( #444,#2d2d2d );background-image:-ms-linear-gradient( #444,#2d2d2d );background-image:-o-linear-gradient( #444,#2d2d2d );background-image:linear-gradient( #444,#2d2d2d )}.ui-btn-up-a:visited,.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:bold;color:#fff;text-shadow:0 1px 1px #111;background-image:-webkit-gradient(linear,left top,left bottom,from( #555 ),to( #383838 ));background-image:-webkit-linear-gradient( #555,#383838 );background-image:-moz-linear-gradient( #555,#383838 );background-image:-ms-linear-gradient( #555,#383838 );background-image:-o-linear-gradient( #555,#383838 );background-image:linear-gradient( #555,#383838 )}.ui-btn-hover-a:visited,.ui-btn-hover-a:hover,.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#222;font-weight:bold;color:#fff;text-shadow:0 1px 1px #111;background-image:-webkit-gradient(linear,left top,left bottom,from( #202020 ),to( #2c2c2c ));background-image:-webkit-linear-gradient( #202020,#2c2c2c );background-image:-moz-linear-gradient( #202020,#2c2c2c );background-image:-ms-linear-gradient( #202020,#2c2c2c );background-image:-o-linear-gradient( #202020,#2c2c2c );background-image:linear-gradient( #202020,#2c2c2c )}.ui-btn-down-a:visited,.ui-btn-down-a:hover,.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:bold;text-shadow:0 1px 1px #3e6790;background-image:-webkit-gradient(linear,left top,left bottom,from( #6facd5 ),to( #497bae ));background-image:-webkit-linear-gradient( #6facd5,#497bae );background-image:-moz-linear-gradient( #6facd5,#497bae );background-image:-ms-linear-gradient( #6facd5,#497bae );background-image:-o-linear-gradient( #6facd5,#497bae );background-image:linear-gradient( #6facd5,#497bae )}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b a.ui-link{color:#ddf0f8;font-weight:bold}.ui-bar-b a.ui-link:visited{color:#ddf0f8}.ui-bar-b a.ui-link:hover{color:#ddf0f8}.ui-bar-b a.ui-link:active{color:#ddf0f8}.ui-body-b,.ui-overlay-b{border:1px solid #999;background:#f3f3f3;color:#222;text-shadow:0 1px 0 #fff;font-weight:normal;background-image:-webkit-gradient(linear,left top,left bottom,from( #ddd ),to( #ccc ));background-image:-webkit-linear-gradient( #ddd,#ccc );background-image:-moz-linear-gradient( #ddd,#ccc );background-image:-ms-linear-gradient( #ddd,#ccc );background-image:-o-linear-gradient( #ddd,#ccc );background-image:linear-gradient( #ddd,#ccc )}.ui-overlay-b{background-image:none;border-width:0}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:bold}.ui-body-b .ui-link:visited{color:#2489ce}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-btn-up-b{border:1px solid #044062;background:#396b9e;font-weight:bold;color:#fff;text-shadow:0 1px 1px #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from( #5f9cc5 ),to( #396b9e ));background-image:-webkit-linear-gradient( #5f9cc5,#396b9e );background-image:-moz-linear-gradient( #5f9cc5,#396b9e );background-image:-ms-linear-gradient( #5f9cc5,#396b9e );background-image:-o-linear-gradient( #5f9cc5,#396b9e );background-image:linear-gradient( #5f9cc5,#396b9e )}.ui-btn-up-b:visited,.ui-btn-up-b a.ui-link-inherit{color:#fff}.ui-btn-hover-b{border:1px solid #00415e;background:#4b88b6;font-weight:bold;color:#fff;text-shadow:0 1px 1px #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from( #6facd5 ),to( #4272a4 ));background-image:-webkit-linear-gradient( #6facd5,#4272a4 );background-image:-moz-linear-gradient( #6facd5,#4272a4 );background-image:-ms-linear-gradient( #6facd5,#4272a4 );background-image:-o-linear-gradient( #6facd5,#4272a4 );background-image:linear-gradient( #6facd5,#4272a4 )}.ui-btn-hover-b:visited,.ui-btn-hover-b:hover,.ui-btn-hover-b a.ui-link-inherit{color:#fff}.ui-btn-down-b{border:1px solid #225377;background:#4e89c5;font-weight:bold;color:#fff;text-shadow:0 1px 1px #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from( #295b8e ),to( #3e79b5 ));background-image:-webkit-linear-gradient( #295b8e,#3e79b5 );background-image:-moz-linear-gradient( #295b8e,#3e79b5 );background-image:-ms-linear-gradient( #295b8e,#3e79b5 );background-image:-o-linear-gradient( #295b8e,#3e79b5 );background-image:linear-gradient( #295b8e,#3e79b5 )}.ui-btn-down-b:visited,.ui-btn-down-b:hover,.ui-btn-down-b a.ui-link-inherit{color:#fff}.ui-btn-up-b,.ui-btn-hover-b,.ui-btn-down-b{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-c{border:1px solid #b3b3b3;background:#eee;color:#3e3e3e;font-weight:bold;text-shadow:0 1px 1px #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #f0f0f0 ),to( #ddd ));background-image:-webkit-linear-gradient( #f0f0f0,#ddd );background-image:-moz-linear-gradient( #f0f0f0,#ddd );background-image:-ms-linear-gradient( #f0f0f0,#ddd );background-image:-o-linear-gradient( #f0f0f0,#ddd );background-image:linear-gradient( #f0f0f0,#ddd )}.ui-bar-c .ui-link-inherit{color:#3e3e3e}.ui-bar-c a.ui-link{color:#7cc4e7;font-weight:bold}.ui-bar-c a.ui-link:visited{color:#2489ce}.ui-bar-c a.ui-link:hover{color:#2489ce}.ui-bar-c a.ui-link:active{color:#2489ce}.ui-bar-c,.ui-bar-c input,.ui-bar-c select,.ui-bar-c textarea,.ui-bar-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c,.ui-overlay-c{border:1px solid #aaa;color:#333;text-shadow:0 1px 0 #fff;background:#f9f9f9;background-image:-webkit-gradient(linear,left top,left bottom,from( #f9f9f9 ),to( #eee ));background-image:-webkit-linear-gradient( #f9f9f9,#eee );background-image:-moz-linear-gradient( #f9f9f9,#eee );background-image:-ms-linear-gradient( #f9f9f9,#eee );background-image:-o-linear-gradient( #f9f9f9,#eee );background-image:linear-gradient( #f9f9f9,#eee )}.ui-overlay-c{background-image:none;border-width:0}.ui-body-c,.ui-body-c input,.ui-body-c select,.ui-body-c textarea,.ui-body-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c .ui-link-inherit{color:#333}.ui-body-c .ui-link{color:#2489ce;font-weight:bold}.ui-body-c .ui-link:visited{color:#2489ce}.ui-body-c .ui-link:hover{color:#2489ce}.ui-body-c .ui-link:active{color:#2489ce}.ui-btn-up-c{border:1px solid #ccc;background:#eee;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fff ),to( #f1f1f1 ));background-image:-webkit-linear-gradient( #fff,#f1f1f1 );background-image:-moz-linear-gradient( #fff,#f1f1f1 );background-image:-ms-linear-gradient( #fff,#f1f1f1 );background-image:-o-linear-gradient( #fff,#f1f1f1 );background-image:linear-gradient( #fff,#f1f1f1 )}.ui-btn-up-c:visited,.ui-btn-up-c a.ui-link-inherit{color:#2f3e46}.ui-btn-hover-c{border:1px solid #bbb;background:#dfdfdf;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #f6f6f6 ),to( #e0e0e0 ));background-image:-webkit-linear-gradient( #f6f6f6,#e0e0e0 );background-image:-moz-linear-gradient( #f6f6f6,#e0e0e0 );background-image:-ms-linear-gradient( #f6f6f6,#e0e0e0 );background-image:-o-linear-gradient( #f6f6f6,#e0e0e0 );background-image:linear-gradient( #f6f6f6,#e0e0e0 )}.ui-btn-hover-c:visited,.ui-btn-hover-c:hover,.ui-btn-hover-c a.ui-link-inherit{color:#2f3e46}.ui-btn-down-c{border:1px solid #bbb;background:#d6d6d6;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #d0d0d0 ),to( #dfdfdf ));background-image:-webkit-linear-gradient( #d0d0d0,#dfdfdf );background-image:-moz-linear-gradient( #d0d0d0,#dfdfdf );background-image:-ms-linear-gradient( #d0d0d0,#dfdfdf );background-image:-o-linear-gradient( #d0d0d0,#dfdfdf );background-image:linear-gradient( #d0d0d0,#dfdfdf )}.ui-btn-down-c:visited,.ui-btn-down-c:hover,.ui-btn-down-c a.ui-link-inherit{color:#2f3e46}.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-d{border:1px solid #bbb;background:#bbb;color:#333;font-weight:bold;text-shadow:0 1px 0 #eee;background-image:-webkit-gradient(linear,left top,left bottom,from( #ddd ),to( #bbb ));background-image:-webkit-linear-gradient( #ddd,#bbb );background-image:-moz-linear-gradient( #ddd,#bbb );background-image:-ms-linear-gradient( #ddd,#bbb );background-image:-o-linear-gradient( #ddd,#bbb );background-image:linear-gradient( #ddd,#bbb )}.ui-bar-d,.ui-bar-d input,.ui-bar-d select,.ui-bar-d textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif}.ui-bar-d .ui-link-inherit{color:#333}.ui-bar-d a.ui-link{color:#2489ce;font-weight:bold}.ui-bar-d a.ui-link:visited{color:#2489ce}.ui-bar-d a.ui-link:hover{color:#2489ce}.ui-bar-d a.ui-link:active{color:#2489ce}.ui-body-d,.ui-overlay-d{border:1px solid #bbb;color:#333;text-shadow:0 1px 0 #fff;background:#fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fff ),to( #fff ));background-image:-webkit-linear-gradient( #fff,#fff );background-image:-moz-linear-gradient( #fff,#fff );background-image:-ms-linear-gradient( #fff,#fff );background-image:-o-linear-gradient( #fff,#fff );background-image:linear-gradient( #fff,#fff )}.ui-overlay-d{background-image:none;border-width:0}.ui-body-d,.ui-body-d input,.ui-body-d select,.ui-body-d textarea,.ui-body-d button{font-family:Helvetica,Arial,sans-serif}.ui-body-d .ui-link-inherit{color:#333}.ui-body-d .ui-link{color:#2489ce;font-weight:bold}.ui-body-d .ui-link:visited{color:#2489ce}.ui-body-d .ui-link:hover{color:#2489ce}.ui-body-d .ui-link:active{color:#2489ce}.ui-btn-up-d{border:1px solid #bbb;background:#fff;font-weight:bold;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fafafa ),to( #f6f6f6 ));background-image:-webkit-linear-gradient( #fafafa,#f6f6f6 );background-image:-moz-linear-gradient( #fafafa,#f6f6f6 );background-image:-ms-linear-gradient( #fafafa,#f6f6f6 );background-image:-o-linear-gradient( #fafafa,#f6f6f6 );background-image:linear-gradient( #fafafa,#f6f6f6 )}.ui-btn-up-d:visited,.ui-btn-up-d a.ui-link-inherit{color:#333}.ui-btn-hover-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#333;cursor:pointer;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #eee ),to( #fff ));background-image:-webkit-linear-gradient( #eee,#fff );background-image:-moz-linear-gradient( #eee,#fff );background-image:-ms-linear-gradient( #eee,#fff );background-image:-o-linear-gradient( #eee,#fff );background-image:linear-gradient( #eee,#fff )}.ui-btn-hover-d:visited,.ui-btn-hover-d:hover,.ui-btn-hover-d a.ui-link-inherit{color:#333}.ui-btn-down-d{border:1px solid #aaa;background:#eee;font-weight:bold;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #e5e5e5 ),to( #f2f2f2 ));background-image:-webkit-linear-gradient( #e5e5e5,#f2f2f2 );background-image:-moz-linear-gradient( #e5e5e5,#f2f2f2 );background-image:-ms-linear-gradient( #e5e5e5,#f2f2f2 );background-image:-o-linear-gradient( #e5e5e5,#f2f2f2 );background-image:linear-gradient( #e5e5e5,#f2f2f2 )}.ui-btn-down-d:visited,.ui-btn-down-d:hover,.ui-btn-down-d a.ui-link-inherit{color:#333}.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-e{border:1px solid #f7c942;background:#fadb4e;color:#333;font-weight:bold;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fceda7 ),to( #fbef7e ));background-image:-webkit-linear-gradient( #fceda7,#fbef7e );background-image:-moz-linear-gradient( #fceda7,#fbef7e );background-image:-ms-linear-gradient( #fceda7,#fbef7e );background-image:-o-linear-gradient( #fceda7,#fbef7e );background-image:linear-gradient( #fceda7,#fbef7e )}.ui-bar-e,.ui-bar-e input,.ui-bar-e select,.ui-bar-e textarea,.ui-bar-e button{font-family:Helvetica,Arial,sans-serif}.ui-bar-e .ui-link-inherit{color:#333}.ui-bar-e a.ui-link{color:#2489ce;font-weight:bold}.ui-bar-e a.ui-link:visited{color:#2489ce}.ui-bar-e a.ui-link:hover{color:#2489ce}.ui-bar-e a.ui-link:active{color:#2489ce}.ui-body-e,.ui-overlay-e{border:1px solid #f7c942;color:#222;text-shadow:0 1px 0 #fff;background:#fff9df;background-image:-webkit-gradient(linear,left top,left bottom,from( #fffadf ),to( #fff3a5 ));background-image:-webkit-linear-gradient( #fffadf,#fff3a5 );background-image:-moz-linear-gradient( #fffadf,#fff3a5 );background-image:-ms-linear-gradient( #fffadf,#fff3a5 );background-image:-o-linear-gradient( #fffadf,#fff3a5 );background-image:linear-gradient( #fffadf,#fff3a5 )}.ui-overlay-e{background-image:none;border-width:0}.ui-body-e,.ui-body-e input,.ui-body-e select,.ui-body-e textarea,.ui-body-e button{font-family:Helvetica,Arial,sans-serif}.ui-body-e .ui-link-inherit{color:#222}.ui-body-e .ui-link{color:#2489ce;font-weight:bold}.ui-body-e .ui-link:visited{color:#2489ce}.ui-body-e .ui-link:hover{color:#2489ce}.ui-body-e .ui-link:active{color:#2489ce}.ui-btn-up-e{border:1px solid #f4c63f;background:#fadb4e;font-weight:bold;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #ffefaa ),to( #ffe155 ));background-image:-webkit-linear-gradient( #ffefaa,#ffe155 );background-image:-moz-linear-gradient( #ffefaa,#ffe155 );background-image:-ms-linear-gradient( #ffefaa,#ffe155 );background-image:-o-linear-gradient( #ffefaa,#ffe155 );background-image:linear-gradient( #ffefaa,#ffe155 )}.ui-btn-up-e:visited,.ui-btn-up-e a.ui-link-inherit{color:#222}.ui-btn-hover-e{border:1px solid #f2c43d;background:#fbe26f;font-weight:bold;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #fff5ba ),to( #fbdd52 ));background-image:-webkit-linear-gradient( #fff5ba,#fbdd52 );background-image:-moz-linear-gradient( #fff5ba,#fbdd52 );background-image:-ms-linear-gradient( #fff5ba,#fbdd52 );background-image:-o-linear-gradient( #fff5ba,#fbdd52 );background-image:linear-gradient( #fff5ba,#fbdd52 )}.ui-btn-hover-e:visited,.ui-btn-hover-e:hover,.ui-btn-hover-e a.ui-link-inherit{color:#333}.ui-btn-down-e{border:1px solid #f2c43d;background:#fceda7;font-weight:bold;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from( #f8d94c ),to( #fadb4e ));background-image:-webkit-linear-gradient( #f8d94c,#fadb4e );background-image:-moz-linear-gradient( #f8d94c,#fadb4e );background-image:-ms-linear-gradient( #f8d94c,#fadb4e );background-image:-o-linear-gradient( #f8d94c,#fadb4e );background-image:linear-gradient( #f8d94c,#fadb4e )}.ui-btn-down-e:visited,.ui-btn-down-e:hover,.ui-btn-down-e a.ui-link-inherit{color:#333}.ui-btn-up-e,.ui-btn-hover-e,.ui-btn-down-e{font-family:Helvetica,Arial,sans-serif;text-decoration:none}a.ui-link-inherit{text-decoration:none!important}.ui-btn-active{border:1px solid #2373a5;background:#5393c5;font-weight:bold;color:#fff;cursor:pointer;text-shadow:0 1px 1px #3373a5;text-decoration:none;background-image:-webkit-gradient(linear,left top,left bottom,from( #5393c5 ),to( #6facd5 ));background-image:-webkit-linear-gradient( #5393c5,#6facd5 );background-image:-moz-linear-gradient( #5393c5,#6facd5 );background-image:-ms-linear-gradient( #5393c5,#6facd5 );background-image:-o-linear-gradient( #5393c5,#6facd5 );background-image:linear-gradient( #5393c5,#6facd5 );font-family:Helvetica,Arial,sans-serif}.ui-btn-active:visited,.ui-btn-active:hover,.ui-btn-active a.ui-link-inherit{color:#fff}.ui-btn-inner{border-top:1px solid #fff;border-color:rgba(255,255,255,.3)}.ui-corner-tl{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em}.ui-corner-tr{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bl{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-br{-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-top{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em}.ui-corner-bottom{-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-right{-moz-border-radius-topright:.6em;-webkit-border-top-right-radius:.6em;border-top-right-radius:.6em;-moz-border-radius-bottomright:.6em;-webkit-border-bottom-right-radius:.6em;border-bottom-right-radius:.6em}.ui-corner-left{-moz-border-radius-topleft:.6em;-webkit-border-top-left-radius:.6em;border-top-left-radius:.6em;-moz-border-radius-bottomleft:.6em;-webkit-border-bottom-left-radius:.6em;border-bottom-left-radius:.6em}.ui-corner-all{-moz-border-radius:.6em;-webkit-border-radius:.6em;border-radius:.6em}.ui-corner-none{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.ui-br{border-bottom:rgb(130,130,130);border-bottom:rgba(130,130,130,.3);border-bottom-width:1px;border-bottom-style:solid}.ui-disabled{filter:Alpha(Opacity=30);opacity:.3;zoom:1}.ui-disabled,.ui-disabled a{cursor:default!important;pointer-events:none}.ui-icon,.ui-icon-searchfield:after{background:#666;background:rgba(0,0,0,.4);background-image:url(images/icons-18-white.png);background-repeat:no-repeat;-moz-border-radius:9px;-webkit-border-radius:9px;border-radius:9px}.ui-icon-alt{background:#fff;background:rgba(255,255,255,.3);background-image:url(images/icons-18-black.png);background-repeat:no-repeat}@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min--moz-device-pixel-ratio:1.5),only screen and (min-resolution:240dpi){.ui-icon-plus,.ui-icon-minus,.ui-icon-delete,.ui-icon-arrow-r,.ui-icon-arrow-l,.ui-icon-arrow-u,.ui-icon-arrow-d,.ui-icon-check,.ui-icon-gear,.ui-icon-refresh,.ui-icon-forward,.ui-icon-back,.ui-icon-grid,.ui-icon-star,.ui-icon-alert,.ui-icon-info,.ui-icon-home,.ui-icon-search,.ui-icon-searchfield:after,.ui-icon-checkbox-off,.ui-icon-checkbox-on,.ui-icon-radio-off,.ui-icon-radio-on{background-image:url(images/icons-36-white.png);-moz-background-size:776px 18px;-o-background-size:776px 18px;-webkit-background-size:776px 18px;background-size:776px 18px}.ui-icon-alt{background-image:url(images/icons-36-black.png)}}.ui-icon-plus{background-position:-0 50%}.ui-icon-minus{background-position:-36px 50%}.ui-icon-delete{background-position:-72px 50%}.ui-icon-arrow-r{background-position:-108px 50%}.ui-icon-arrow-l{background-position:-144px 50%}.ui-icon-arrow-u{background-position:-180px 50%}.ui-icon-arrow-d{background-position:-216px 50%}.ui-icon-check{background-position:-252px 50%}.ui-icon-gear{background-position:-288px 50%}.ui-icon-refresh{background-position:-324px 50%}.ui-icon-forward{background-position:-360px 50%}.ui-icon-back{background-position:-396px 50%}.ui-icon-grid{background-position:-432px 50%}.ui-icon-star{background-position:-468px 50%}.ui-icon-alert{background-position:-504px 50%}.ui-icon-info{background-position:-540px 50%}.ui-icon-home{background-position:-576px 50%}.ui-icon-search,.ui-icon-searchfield:after{background-position:-612px 50%}.ui-icon-checkbox-off{background-position:-684px 50%}.ui-icon-checkbox-on{background-position:-648px 50%}.ui-icon-radio-off{background-position:-756px 50%}.ui-icon-radio-on{background-position:-720px 50%}.ui-checkbox .ui-icon,.ui-selectmenu-list .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px}.ui-icon-checkbox-off,.ui-icon-radio-off{background-color:transparent}.ui-checkbox-on .ui-icon,.ui-radio-on .ui-icon{background-color:#4596ce}.ui-icon-loading{background:url(images/ajax-loader.gif);background-size:46px 46px}.ui-btn-corner-tl{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em}.ui-btn-corner-tr{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bl{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-br{-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-top{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em}.ui-btn-corner-bottom{-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-right{-moz-border-radius-topright:1em;-webkit-border-top-right-radius:1em;border-top-right-radius:1em;-moz-border-radius-bottomright:1em;-webkit-border-bottom-right-radius:1em;border-bottom-right-radius:1em}.ui-btn-corner-left{-moz-border-radius-topleft:1em;-webkit-border-top-left-radius:1em;border-top-left-radius:1em;-moz-border-radius-bottomleft:1em;-webkit-border-bottom-left-radius:1em;border-bottom-left-radius:1em}.ui-btn-corner-all{-moz-border-radius:1em;-webkit-border-radius:1em;border-radius:1em}.ui-corner-tl,.ui-corner-tr,.ui-corner-bl,.ui-corner-br,.ui-corner-top,.ui-corner-bottom,.ui-corner-right,.ui-corner-left,.ui-corner-all,.ui-btn-corner-tl,.ui-btn-corner-tr,.ui-btn-corner-bl,.ui-btn-corner-br,.ui-btn-corner-top,.ui-btn-corner-bottom,.ui-btn-corner-right,.ui-btn-corner-left,.ui-btn-corner-all{-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.ui-overlay{background:#666;filter:Alpha(Opacity=50);opacity:.5;position:absolute;width:100%;height:100%}.ui-overlay-shadow{-moz-box-shadow:0 0 12px rgba(0,0,0,.6);-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6)}.ui-shadow{-moz-box-shadow:0 1px 4px rgba(0,0,0,.3);-webkit-box-shadow:0 1px 4px rgba(0,0,0,.3);box-shadow:0 1px 4px rgba(0,0,0,.3)}.ui-bar-a .ui-shadow,.ui-bar-b .ui-shadow,.ui-bar-c .ui-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3)}.ui-shadow-inset{-moz-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);box-shadow:inset 0 1px 4px rgba(0,0,0,.2)}.ui-icon-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.4);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.4);box-shadow:0 1px 0 rgba(255,255,255,.4)}.ui-btn:focus,.ui-link-inherit:focus{outline:0}.ui-btn.ui-focus{z-index:1}.ui-focus,.ui-btn:focus{-moz-box-shadow:inset 0 0 3px #387bbe,0px 0 9px #387bbe;-webkit-box-shadow:inset 0 0 3px #387bbe,0px 0 9px #387bbe;box-shadow:inset 0 0 3px #387bbe,0px 0 9px #387bbe}.ui-input-text.ui-focus,.ui-input-search.ui-focus{-moz-box-shadow:0 0 12px #387bbe;-webkit-box-shadow:0 0 12px #387bbe;box-shadow:0 0 12px #387bbe}.ui-mobile-nosupport-boxshadow *{-moz-box-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}.ui-mobile-nosupport-boxshadow .ui-focus,.ui-mobile-nosupport-boxshadow .ui-btn:focus,.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus{outline-width:1px;outline-style:auto}.ui-mobile,.ui-mobile body{height:99.9%}.ui-mobile fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border-width:0}.ui-mobile-viewport{margin:0;overflow-x:visible;-webkit-text-size-adjust:100%;-ms-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}body.ui-mobile-viewport,div.ui-mobile-viewport{overflow-x:hidden}.ui-mobile [data-role=page],.ui-mobile [data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-mobile .ui-page-active{display:block;overflow:visible}.ui-page{outline:none}@media screen and (orientation:portrait){.ui-mobile,.ui-mobile .ui-page{min-height:420px}}@media screen and (orientation:landscape){.ui-mobile,.ui-mobile .ui-page{min-height:300px}}.ui-loading .ui-loader{display:block}.ui-loader{display:none;z-index:9999999;position:fixed;top:50%;left:50%;border:0}.ui-loader-default{background:none;filter:Alpha(Opacity=18);opacity:.18;width:46px;height:46px;margin-left:-23px;margin-top:-23px}.ui-loader-verbose{width:200px;filter:Alpha(Opacity=88);opacity:.88;box-shadow:0 1px 1px -1px #fff;height:auto;margin-left:-110px;margin-top:-43px;padding:10px}.ui-loader-default h1{font-size:0;width:0;height:0;overflow:hidden}.ui-loader-verbose h1{font-size:16px;margin:0;text-align:center}.ui-loader .ui-icon{background-color:#000;display:block;margin:0;width:44px;height:44px;padding:1px;-webkit-border-radius:36px;-moz-border-radius:36px;border-radius:36px}.ui-loader-verbose .ui-icon{margin:0 auto 10px;filter:Alpha(Opacity=75);opacity:.75}.ui-loader-textonly{padding:15px;margin-left:-115px}.ui-loader-textonly .ui-icon{display:none}.ui-loader-fakefix{position:absolute}.ui-mobile-rendering > *{visibility:hidden}.ui-bar,.ui-body{position:relative;padding:.4em 15px;overflow:hidden;display:block;clear:both}.ui-bar{font-size:16px;margin:0}.ui-bar h1,.ui-bar h2,.ui-bar h3,.ui-bar h4,.ui-bar h5,.ui-bar h6{margin:0;padding:0;font-size:16px;display:inline-block}.ui-header,.ui-footer{position:relative;border-left-width:0;border-right-width:0;zoom:1}.ui-header .ui-btn-left,.ui-header .ui-btn-right,.ui-footer .ui-btn-left,.ui-footer .ui-btn-right{position:absolute;top:3px}.ui-header .ui-btn-left,.ui-footer .ui-btn-left{left:5px}.ui-header .ui-btn-right,.ui-footer .ui-btn-right{right:5px}.ui-footer .ui-btn-icon-notext,.ui-header .ui-btn-icon-notext{top:6px}.ui-header .ui-title,.ui-footer .ui-title{min-height:1.1em;text-align:center;font-size:16px;display:block;margin:.6em 30% .8em;padding:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;outline:0!important}.ui-footer .ui-title{margin:.6em 15px .8em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:15px}.ui-icon{width:18px;height:18px}.ui-nojs{position:absolute;left:-9999px}.ui-hide-label label.ui-input-text,.ui-hide-label label.ui-select,.ui-hide-label label.ui-slider,.ui-hide-label label.ui-submit,.ui-hide-label .ui-controlgroup-label,.ui-hidden-accessible{position:absolute!important;left:-9999px;clip:rect(1px);clip:rect(1px,1px,1px,1px)}.ui-mobile-viewport-transitioning,.ui-mobile-viewport-transitioning .ui-page{width:100%;height:100%;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ui-page-pre-in{opacity:0}.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms}.out{-webkit-animation-timing-function:ease-in;-webkit-animation-duration:225ms;-moz-animation-timing-function:ease-in;-moz-animation-duration:225ms}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-moz-keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeout{from{opacity:1}to{opacity:0}}@-moz-keyframes fadeout{from{opacity:1}to{opacity:0}}.fade.out{opacity:0;-webkit-animation-duration:125ms;-webkit-animation-name:fadeout;-moz-animation-duration:125ms;-moz-animation-name:fadeout}.fade.in{opacity:1;-webkit-animation-duration:225ms;-webkit-animation-name:fadein;-moz-animation-duration:225ms;-moz-animation-name:fadein}.pop{-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%}.pop.in{-webkit-transform:scale(1);-moz-transform:scale(1);opacity:1;-webkit-animation-name:popin;-moz-animation-name:popin;-webkit-animation-duration:350ms;-moz-animation-duration:350ms}.pop.out{-webkit-animation-name:fadeout;-moz-animation-name:fadeout;opacity:0;-webkit-animation-duration:100ms;-moz-animation-duration:100ms}.pop.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein}.pop.out.reverse{-webkit-transform:scale(.8);-moz-transform:scale(.8);-webkit-animation-name:popout;-moz-animation-name:popout}@-webkit-keyframes popin{from{-webkit-transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-moz-keyframes popin{from{-moz-transform:scale(.8);opacity:0}to{-moz-transform:scale(1);opacity:1}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.8);opacity:0}}@-moz-keyframes popout{from{-moz-transform:scale(1);opacity:1}to{-moz-transform:scale(.8);opacity:0}}@-webkit-keyframes slideinfromright{from{-webkit-transform:translateX(100%)}to{-webkit-transform:translateX(0)}}@-moz-keyframes slideinfromright{from{-moz-transform:translateX(100%)}to{-moz-transform:translateX(0)}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translateX(-100%)}to{-webkit-transform:translateX(0)}}@-moz-keyframes slideinfromleft{from{-moz-transform:translateX(-100%)}to{-moz-transform:translateX(0)}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(-100%)}}@-moz-keyframes slideouttoleft{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(-100%)}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translateX(0)}to{-webkit-transform:translateX(100%)}}@-moz-keyframes slideouttoright{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(100%)}}.slide.out,.slide.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms}.slide.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft}.slide.in{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromright;-moz-transform:translateX(0);-moz-animation-name:slideinfromright}.slide.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright}.slide.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:slideinfromleft;-moz-transform:translateX(0);-moz-animation-name:slideinfromleft}.slidefade.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;-webkit-animation-duration:225ms;-moz-animation-duration:225ms}.slidefade.in{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-moz-transform:translateX(0);-moz-animation-name:fadein;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}.slidefade.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}.slidefade.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-moz-transform:translateX(0);-moz-animation-name:fadein;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}.slidedown.out{-webkit-animation-name:fadeout;-moz-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-duration:100ms}.slidedown.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfromtop;-moz-transform:translateY(0);-moz-animation-name:slideinfromtop;-webkit-animation-duration:250ms;-moz-animation-duration:250ms}.slidedown.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-duration:150ms}.slidedown.out.reverse{-webkit-transform:translateY(-100%);-moz-transform:translateY(-100%);-webkit-animation-name:slideouttotop;-moz-animation-name:slideouttotop;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}@-webkit-keyframes slideinfromtop{from{-webkit-transform:translateY(-100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfromtop{from{-moz-transform:translateY(-100%)}to{-moz-transform:translateY(0)}}@-webkit-keyframes slideouttotop{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(-100%)}}@-moz-keyframes slideouttotop{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(-100%)}}.slideup.out{-webkit-animation-name:fadeout;-moz-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-duration:100ms}.slideup.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfrombottom;-moz-transform:translateY(0);-moz-animation-name:slideinfrombottom;-webkit-animation-duration:250ms;-moz-animation-duration:250ms}.slideup.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-duration:150ms}.slideup.out.reverse{-webkit-transform:translateY(100%);-moz-transform:translateY(100%);-webkit-animation-name:slideouttobottom;-moz-animation-name:slideouttobottom;-webkit-animation-duration:200ms;-moz-animation-duration:200ms}@-webkit-keyframes slideinfrombottom{from{-webkit-transform:translateY(100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfrombottom{from{-moz-transform:translateY(100%)}to{-moz-transform:translateY(0)}}@-webkit-keyframes slideouttobottom{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(100%)}}@-moz-keyframes slideouttobottom{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(100%)}}.viewport-flip{-webkit-perspective:1000;-moz-perspective:1000;position:absolute}.flip{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-moz-backface-visibility:hidden;-moz-transform:translateX(0)}.flip.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:175ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:175ms}.flip.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:225ms;-moz-animation-name:flipintoright;-moz-animation-duration:225ms}.flip.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright}.flip.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}.viewport-turn{-webkit-perspective:1000;-moz-perspective:1000;position:absolute}.turn{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-webkit-transform-origin:0;-moz-backface-visibility:hidden;-moz-transform:translateX(0);-moz-transform-origin:0}.turn.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-webkit-animation-duration:125ms;-moz-animation-duration:125ms}.turn.in{-webkit-animation-name:flipintoright;-moz-animation-name:flipintoright;-webkit-animation-duration:250ms;-moz-animation-duration:250ms}.turn.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright}.turn.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}.flow{-webkit-transform-origin:50% 30%;-moz-transform-origin:50% 30%;-webkit-box-shadow:0 0 20px rgba(0,0,0,.4);-moz-box-shadow:0 0 20px rgba(0,0,0,.4)}.ui-dialog.flow{-webkit-transform-origin:none;-moz-transform-origin:none;-webkit-box-shadow:none;-moz-box-shadow:none}.flow.out{-webkit-transform:translateX(-100%) scale(.7);-webkit-animation-name:flowouttoleft;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(-100%) scale(.7);-moz-animation-name:flowouttoleft;-moz-animation-timing-function:ease;-moz-animation-duration:350ms}.flow.in{-webkit-transform:translateX(0) scale(1);-webkit-animation-name:flowinfromright;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(0) scale(1);-moz-animation-name:flowinfromright;-moz-animation-timing-function:ease;-moz-animation-duration:350ms}.flow.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:flowouttoright;-moz-transform:translateX(100%);-moz-animation-name:flowouttoright}.flow.in.reverse{-webkit-animation-name:flowinfromleft;-moz-animation-name:flowinfromleft}@-webkit-keyframes flowouttoleft{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(-100%) scale(.7)}}@-moz-keyframes flowouttoleft{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(-100%) scale(.7)}}@-webkit-keyframes flowouttoright{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(100%) scale(.7)}}@-moz-keyframes flowouttoright{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(100%) scale(.7)}}@-webkit-keyframes flowinfromleft{0%{-webkit-transform:translateX(-100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromleft{0%{-moz-transform:translateX(-100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@-webkit-keyframes flowinfromright{0%{-webkit-transform:translateX(100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromright{0%{-moz-transform:translateX(100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}.ui-grid-a,.ui-grid-b,.ui-grid-c,.ui-grid-d{overflow:hidden}.ui-block-a,.ui-block-b,.ui-block-c,.ui-block-d,.ui-block-e{margin:0;padding:0;border:0;float:left;min-height:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-grid-solo .ui-block-a{display:block;float:none}.ui-grid-a .ui-block-a,.ui-grid-a .ui-block-b{width:49.95%}.ui-grid-a >:nth-child(n){width:50%;margin-right:-.5px}.ui-grid-a .ui-block-a{clear:left}.ui-grid-b .ui-block-a,.ui-grid-b .ui-block-b,.ui-grid-b .ui-block-c{width:33.25%}.ui-grid-b >:nth-child(n){width:33.333%;margin-right:-.5px}.ui-grid-b .ui-block-a{clear:left}.ui-grid-c .ui-block-a,.ui-grid-c .ui-block-b,.ui-grid-c .ui-block-c,.ui-grid-c .ui-block-d{width:24.925%}.ui-grid-c >:nth-child(n){width:25%;margin-right:-.5px}.ui-grid-c .ui-block-a{clear:left}.ui-grid-d .ui-block-a,.ui-grid-d .ui-block-b,.ui-grid-d .ui-block-c,.ui-grid-d .ui-block-d,.ui-grid-d .ui-block-e{width:19.925%}.ui-grid-d >:nth-child(n){width:20%}.ui-grid-d .ui-block-a{clear:left}.ui-header-fixed,.ui-footer-fixed{left:0;right:0;width:100%;position:fixed;z-index:1000}.ui-header-fixed{top:0}.ui-footer-fixed{bottom:0}.ui-header-fullscreen,.ui-footer-fullscreen{filter:Alpha(Opacity=90);opacity:.9}.ui-page-header-fixed{padding-top:2.6875em}.ui-page-footer-fixed{padding-bottom:2.6875em}.ui-page-header-fullscreen .ui-content,.ui-page-footer-fullscreen .ui-content{padding:0}.ui-fixed-hidden{position:absolute}.ui-page-header-fullscreen .ui-fixed-hidden,.ui-page-footer-fullscreen .ui-fixed-hidden{left:-9999px}.ui-header-fixed .ui-btn,.ui-footer-fixed .ui-btn{z-index:10}.ui-navbar{max-width:100%}.ui-navbar.ui-mini{margin:0}.ui-navbar ul:before,.ui-navbar ul:after{content:" ";display:table}.ui-navbar ul:after{clear:both}.ui-navbar ul{list-style:none;margin:0;padding:0;position:relative;display:block;border:0;max-width:100%;overflow:visible;zoom:1}.ui-navbar li .ui-btn{display:block;text-align:center;margin:0 -1px 0 0;border-right-width:0}.ui-navbar li .ui-btn-icon-right .ui-icon{right:6px}.ui-navbar li:last-child .ui-btn,.ui-navbar .ui-grid-duo .ui-block-b .ui-btn{margin-right:0;border-right-width:1px}.ui-header .ui-navbar li:last-child .ui-btn,.ui-footer .ui-navbar li:last-child .ui-btn,.ui-header .ui-navbar .ui-grid-duo .ui-block-b .ui-btn,.ui-footer .ui-navbar .ui-grid-duo .ui-block-b .ui-btn{margin-right:-1px;border-right-width:0}.ui-navbar .ui-grid-duo li.ui-block-a:last-child .ui-btn{margin-right:-1px;border-right-width:1px}.ui-header .ui-navbar li .ui-btn,.ui-footer .ui-navbar li .ui-btn{border-top-width:0;border-bottom-width:0}.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn,.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn{margin-right:-5px}.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn,.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn{margin-right:-4px}.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon{right:8px}.ui-navbar li .ui-btn .ui-btn-inner{padding-top:.7em;padding-bottom:.8em}.ui-navbar li .ui-btn-icon-top .ui-btn-inner{padding-top:30px}.ui-navbar li .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:30px}.ui-btn{display:block;text-align:center;cursor:pointer;position:relative;margin:.5em 0;padding:0}.ui-mini{margin-top:.25em;margin-bottom:.25em}.ui-btn-left,.ui-btn-right,.ui-input-clear,.ui-btn-inline,.ui-grid-a .ui-btn,.ui-grid-b .ui-btn,.ui-grid-c .ui-btn,.ui-grid-d .ui-btn,.ui-grid-e .ui-btn,.ui-grid-solo .ui-btn{margin-right:5px;margin-left:5px}.ui-btn-inner{font-size:16px;padding:.6em 20px;min-width:.75em;display:block;position:relative;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;zoom:1}.ui-btn input,.ui-btn button{z-index:2}.ui-btn-left,.ui-btn-right,.ui-btn-inline{display:inline-block;vertical-align:middle}.ui-mobile .ui-btn-left,.ui-mobile .ui-btn-right{margin:0}.ui-btn-block{display:block}.ui-header > .ui-btn,.ui-footer > .ui-btn{display:inline-block;margin:0}.ui-header .ui-btn-block,.ui-footer .ui-btn-block{display:block}.ui-header .ui-btn-inner,.ui-footer .ui-btn-inner,.ui-mini .ui-btn-inner{font-size:12.5px;padding:.55em 11px .5em}.ui-fullsize .ui-btn-inner,.ui-fullsize .ui-btn-inner{font-size:16px;padding:.6em 20px}.ui-btn-icon-notext{width:24px;height:24px}.ui-btn-icon-notext .ui-btn-inner{padding:0;height:100%}.ui-btn-icon-notext .ui-btn-inner .ui-icon{margin:2px 1px 2px 3px;float:left}.ui-btn-text{position:relative;z-index:1;width:100%;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.ui-btn-icon-notext .ui-btn-text{position:absolute;left:-9999px}.ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-btn-icon-right .ui-btn-inner{padding-right:40px}.ui-btn-icon-top .ui-btn-inner{padding-top:40px}.ui-btn-icon-bottom .ui-btn-inner{padding-bottom:40px}.ui-header .ui-btn-icon-left .ui-btn-inner,.ui-footer .ui-btn-icon-left .ui-btn-inner,.ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-mini .ui-btn-icon-left .ui-btn-inner{padding-left:30px}.ui-header .ui-btn-icon-right .ui-btn-inner,.ui-footer .ui-btn-icon-right .ui-btn-inner,.ui-mini.ui-btn-icon-right .ui-btn-inner,.ui-mini .ui-btn-icon-right .ui-btn-inner{padding-right:30px}.ui-header .ui-btn-icon-top .ui-btn-inner,.ui-footer .ui-btn-icon-top .ui-btn-inner{padding:30px 3px .5em 3px}.ui-mini.ui-btn-icon-top .ui-btn-inner,.ui-mini .ui-btn-icon-top .ui-btn-inner{padding-top:30px}.ui-header .ui-btn-icon-bottom .ui-btn-inner,.ui-footer .ui-btn-icon-bottom .ui-btn-inner{padding:.55em 3px 30px 3px}.ui-mini.ui-btn-icon-bottom .ui-btn-inner,.ui-mini .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:30px}.ui-btn-icon-notext .ui-icon{display:block;z-index:0}.ui-btn-icon-left > .ui-btn-inner > .ui-icon,.ui-btn-icon-right > .ui-btn-inner > .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-btn-icon-top .ui-btn-inner .ui-icon,.ui-btn-icon-bottom .ui-btn-inner .ui-icon{position:absolute;left:50%;margin-left:-9px}.ui-btn-icon-left .ui-icon{left:10px}.ui-btn-icon-right .ui-icon{right:10px}.ui-btn-icon-top .ui-icon{top:10px}.ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-header .ui-btn-icon-left .ui-icon,.ui-footer .ui-btn-icon-left .ui-icon,.ui-mini.ui-btn-icon-left .ui-icon,.ui-mini .ui-btn-icon-left .ui-icon{left:5px}.ui-header .ui-btn-icon-right .ui-icon,.ui-footer .ui-btn-icon-right .ui-icon,.ui-mini.ui-btn-icon-right .ui-icon,.ui-mini .ui-btn-icon-right .ui-icon{right:5px}.ui-header .ui-btn-icon-top .ui-icon,.ui-footer .ui-btn-icon-top .ui-icon,.ui-mini.ui-btn-icon-top .ui-icon,.ui-mini .ui-btn-icon-top .ui-icon{top:5px}.ui-header .ui-btn-icon-bottom .ui-icon,.ui-footer .ui-btn-icon-bottom .ui-icon,.ui-mini.ui-btn-icon-bottom .ui-icon,.ui-mini .ui-btn-icon-bottom .ui-icon{bottom:5px}.ui-btn-hidden{position:absolute;top:0;left:0;width:100%;height:100%;-webkit-appearance:none;cursor:pointer;background:#fff;background:rgba(255,255,255,0);filter:Alpha(Opacity=0);opacity:.1;font-size:1px;border:none;text-indent:-9999px}.ui-disabled .ui-btn-hidden{display:none}.ui-disabled{z-index:1}.ui-field-contain .ui-btn.ui-submit{margin:0}label.ui-submit{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}@media all and (min-width:450px){.ui-field-contain label.ui-submit{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-btn.ui-submit{width:78%;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-hide-label .ui-btn.ui-submit{width:auto;display:block}}.ui-collapsible-inset{margin:.5em 0}.ui-collapsible-heading{font-size:16px;display:block;margin:0 -15px;padding:0;position:relative}.ui-collapsible-inset .ui-collapsible-heading{margin:0}.ui-collapsible-heading .ui-btn{text-align:left;margin:0;border-left-width:0;border-right-width:0}.ui-collapsible-inset .ui-collapsible-heading .ui-btn{border-right-width:1px;border-left-width:1px}.ui-collapsible-collapsed + .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn{border-top-width:0}.ui-collapsible-set .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn{border-top-width:1px}.ui-collapsible-heading .ui-btn-inner,.ui-collapsible-heading .ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-collapsible-heading .ui-btn-icon-right .ui-btn-inner{padding-left:12px;padding-right:40px}.ui-collapsible-heading .ui-btn-icon-top .ui-btn-inner,.ui-collapsible-heading .ui-btn-icon-bottom .ui-btn-inner{padding-right:40px;text-align:center}.ui-collapsible-heading .ui-btn span.ui-btn{position:absolute;left:6px;top:50%;margin:-12px 0 0 0;width:20px;height:20px;padding:1px 0 1px 2px;text-indent:-9999px}.ui-collapsible-heading .ui-btn span.ui-btn .ui-btn-inner{padding:10px 0}.ui-collapsible-heading .ui-btn span.ui-btn .ui-icon{left:0;margin-top:-10px}.ui-collapsible-heading-status{position:absolute;top:-9999px;left:0}.ui-collapsible-content{display:block;margin:0 -15px;padding:10px 15px;border-left-width:0;border-right-width:0;border-top:none;background-image:none}.ui-collapsible-inset .ui-collapsible-content{margin:0;border-right-width:1px;border-left-width:1px}.ui-collapsible-content-collapsed{display:none}.ui-collapsible-set{margin:.5em 0}.ui-collapsible-set .ui-collapsible{margin:-1px 0 0}.ui-collapsible-set .ui-collapsible:first-child{margin-top:0}.ui-controlgroup,fieldset.ui-controlgroup{padding:0;margin:.5em 0;zoom:1}.ui-controlgroup.ui-mini,fieldset.ui-controlgroup.ui-mini{margin:.25em 0}.ui-field-contain .ui-controlgroup,.ui-field-contain fieldset.ui-controlgroup{margin:0}.ui-bar .ui-controlgroup{margin:0 5px}.ui-controlgroup-label{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .4em}.ui-controlgroup li{list-style:none}.ui-controlgroup-vertical .ui-btn,.ui-controlgroup-vertical .ui-checkbox,.ui-controlgroup-vertical .ui-radio{margin:0;border-bottom-width:0}.ui-controlgroup-vertical .ui-controlgroup-last{border-bottom-width:1px}.ui-controlgroup-controls label.ui-select{position:absolute;left:-9999px}.ui-controlgroup .ui-btn-icon-notext{width:auto;height:auto;top:auto}.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner{height:20px;padding:.6em 20px .6em 20px}.ui-controlgroup-horizontal .ui-btn-icon-notext .ui-btn-inner{width:18px}.ui-controlgroup.ui-mini .ui-btn-icon-notext .ui-btn-inner,.ui-header .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner,.ui-footer .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner{height:16px;padding:.55em 11px .5em 11px}.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner .ui-icon{position:absolute;top:50%;right:50%;margin:-9px -9px 0 0}.ui-controlgroup-horizontal .ui-controlgroup-controls:before,.ui-controlgroup-horizontal .ui-controlgroup-controls:after{content:"";display:table}.ui-controlgroup-horizontal .ui-controlgroup-controls:after{clear:both}.ui-controlgroup-horizontal .ui-controlgroup-controls{display:inline-block;vertical-align:middle;zoom:1}.ui-controlgroup-horizontal .ui-btn-inner{text-align:center}.ui-controlgroup-horizontal.ui-mini .ui-btn-inner{height:16px;line-height:16px}.ui-controlgroup-horizontal .ui-btn,.ui-controlgroup-horizontal .ui-select,.ui-controlgroup-horizontal .ui-checkbox,.ui-controlgroup-horizontal .ui-radio{float:left;clear:none;margin:0 -1px 0 0}.ui-controlgroup-horizontal .ui-select .ui-btn,.ui-controlgroup-horizontal .ui-checkbox .ui-btn,.ui-controlgroup-horizontal .ui-radio .ui-btn{float:none;margin:0}.ui-controlgroup-horizontal .ui-controlgroup-last,.ui-controlgroup-horizontal .ui-select:last-child,.ui-controlgroup-horizontal .ui-checkbox:last-child,.ui-controlgroup-horizontal .ui-radio:last-child{margin-right:0}.ui-controlgroup .ui-checkbox label,.ui-controlgroup .ui-radio label{font-size:16px}@media all and (min-width:450px){.ui-field-contain .ui-controlgroup-label{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-controlgroup-controls{width:78%;display:inline-block}.ui-field-contain .ui-controlgroup .ui-select{width:100%;display:block}.ui-field-contain .ui-controlgroup-horizontal .ui-select{width:auto}.ui-hide-label .ui-controlgroup-controls{width:100%}}.ui-dialog{background:none!important}.ui-dialog-contain{width:92.5%;max-width:500px;margin:10% auto 15px auto;padding:0;position:relative;top:-15px}.ui-dialog-contain > .ui-header,.ui-dialog-contain > .ui-content,.ui-dialog-contain > .ui-footer{display:block;position:relative;width:auto;margin:0}.ui-dialog-contain > .ui-header{border:none;overflow:hidden;z-index:10;padding:0}.ui-dialog-contain > .ui-content{padding:15px}.ui-dialog-contain > .ui-footer{z-index:10;padding:0 15px}.ui-popup-open .ui-header-fixed,.ui-popup-open .ui-footer-fixed{position:absolute!important}.ui-popup-screen{background-image:url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==);top:0;left:0;right:0;bottom:1px;position:absolute;filter:Alpha(Opacity=0);opacity:0;z-index:1099}.ui-popup-screen.in{opacity:0.5;filter:Alpha(Opacity=50)}.ui-popup-screen.out{opacity:0;filter:Alpha(Opacity=0)}.ui-popup-container{z-index:1100;display:inline-block;position:absolute;padding:0;outline:0}.ui-popup{position:relative}.ui-popup.ui-content,.ui-popup .ui-content{overflow:visible}.ui-popup > p,.ui-popup > h1,.ui-popup > h2,.ui-popup > h3,.ui-popup > h4,.ui-popup > h5,.ui-popup > h6{margin:.5em 7px}.ui-popup > span{display:block;margin:.5em 7px}.ui-popup .ui-title{font-size:16px;font-weight:bold;margin-top:.5em;margin-bottom:.5em}.ui-popup-container .ui-content > p,.ui-popup-container .ui-content > h1,.ui-popup-container .ui-content > h2,.ui-popup-container .ui-content > h3,.ui-popup-container .ui-content > h4,.ui-popup-container .ui-content > h5,.ui-popup-container .ui-content > h6{margin:.5em 0}.ui-popup-container .ui-content > span{margin:0}.ui-popup-container .ui-content > p:first-child,.ui-popup-container .ui-content > h1:first-child,.ui-popup-container .ui-content > h2:first-child,.ui-popup-container .ui-content > h3:first-child,.ui-popup-container .ui-content > h4:first-child,.ui-popup-container .ui-content > h5:first-child,.ui-popup-container .ui-content > h6:first-child{margin-top:0}.ui-popup-container .ui-content > p:last-child,.ui-popup-container .ui-content > h1:last-child,.ui-popup-container .ui-content > h2:last-child,.ui-popup-container .ui-content > h3:last-child,.ui-popup-container .ui-content > h4:last-child,.ui-popup-container .ui-content > h5:last-child,.ui-popup-container .ui-content > h6:last-child{margin-bottom:0}.ui-popup > img{width:auto;height:auto;max-width:100%;max-height:100%;vertical-align:middle}.ui-popup iframe{vertical-align:middle}@media all and (min-width:450px){.ui-popup .ui-field-contain label.ui-submit,.ui-popup .ui-field-contain .ui-controlgroup-label,.ui-popup .ui-field-contain label.ui-select,.ui-popup .ui-field-contain label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:normal;margin:0 0 .3em}.ui-popup .ui-field-contain .ui-btn.ui-submit,.ui-popup .ui-field-contain .ui-controlgroup-controls,.ui-popup .ui-field-contain .ui-select,.ui-popup .ui-field-contain input.ui-input-text,.ui-popup .ui-field-contain textarea.ui-input-text,.ui-popup .ui-field-contain .ui-input-search{width:100%;display:block}}.ui-popup > .ui-btn-left,.ui-popup > .ui-btn-right{position:absolute;top:-9px;margin:0;z-index:1101}.ui-popup > .ui-btn-left{left:-9px}.ui-popup > .ui-btn-right{right:-9px}.ui-popup.ui-corner-all > .ui-header,.ui-popup.ui-corner-all ~ .ui-content,.ui-popup.ui-corner-all > .ui-content:first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-popup.ui-corner-all > .ui-content,.ui-popup.ui-corner-all > .ui-footer,.ui-popup.ui-corner-all > .ui-header:nth-child(n):last-child{-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-popup.ui-corner-all > .ui-content:nth-child(2),.ui-popup.ui-corner-all > .ui-header:nth-child(2){-webkit-border-top-left-radius:0;border-top-left-radius:0;-webkit-border-top-right-radius:0;border-top-right-radius:0}.ui-popup.ui-corner-all > .ui-content:nth-last-child(1n+2),.ui-popup.ui-corner-all > .ui-footer:nth-last-child(1n+2){-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0}.ui-popup.ui-corner-all > .ui-header:only-child,.ui-popup.ui-corner-all > .ui-footer:only-child{-webkit-border-radius:inherit;border-radius:inherit}.ui-checkbox,.ui-radio{position:relative;clear:both;margin:0;z-index:1}.ui-checkbox .ui-btn,.ui-radio .ui-btn{margin-top:.5em;margin-bottom:.5em;text-align:left;z-index:2}.ui-checkbox .ui-btn.ui-mini,.ui-radio .ui-btn.ui-mini{margin:.25em 0}.ui-controlgroup .ui-checkbox .ui-btn,.ui-controlgroup .ui-radio .ui-btn{margin:0}.ui-checkbox .ui-btn-inner,.ui-radio .ui-btn-inner{white-space:normal}.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner{padding-left:45px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-left .ui-btn-inner{padding-left:36px}.ui-checkbox .ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-right .ui-btn-inner{padding-right:36px}.ui-checkbox .ui-btn-icon-top .ui-btn-inner,.ui-radio .ui-btn-icon-top .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-btn-icon-bottom .ui-btn-inner,.ui-radio .ui-btn-icon-bottom .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-icon,.ui-radio .ui-icon{top:1.1em}.ui-checkbox .ui-btn-icon-left .ui-icon,.ui-radio .ui-btn-icon-left .ui-icon{left:15px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-icon,.ui-radio .ui-mini.ui-btn-icon-left .ui-icon{left:9px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-checkbox .ui-btn-icon-top .ui-icon,.ui-radio .ui-btn-icon-top .ui-icon{top:10px}.ui-checkbox .ui-btn-icon-bottom .ui-icon,.ui-radio .ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-checkbox input,.ui-radio input{position:absolute;left:20px;top:50%;width:10px;height:10px;margin:-5px 0 0 0;outline:0!important;z-index:1}.ui-field-contain,fieldset.ui-field-contain{padding:.8em 0;margin:0;border-width:0 0 1px 0;overflow:visible}.ui-field-contain:last-child{border-bottom-width:0}.ui-field-contain{max-width:100%}@media all and (min-width:450px){.ui-field-contain,.ui-mobile fieldset.ui-field-contain{border-width:0;padding:0;margin:1em 0}}.ui-select{display:block;position:relative}.ui-select select{position:absolute;left:-9999px;top:-9999px}.ui-select .ui-btn{overflow:hidden;opacity:1}.ui-field-contain .ui-select .ui-btn{margin:0}.ui-select .ui-btn select{cursor:pointer;-webkit-appearance:none;left:0;top:0;width:100%;min-height:1.5em;min-height:100%;height:3em;max-height:100%;filter:Alpha(Opacity=0);opacity:0;z-index:2}.ui-select .ui-disabled{opacity:.3}.ui-select .ui-disabled select{display:none}@-moz-document url-prefix(){.ui-select .ui-btn select{opacity:0.0001}}.ui-select .ui-btn.ui-select-nativeonly{border-radius:0;border:0}.ui-select .ui-btn.ui-select-nativeonly select{opacity:1;text-indent:0;display:block}.ui-select .ui-disabled.ui-select-nativeonly .ui-btn-inner{opacity:0}.ui-select .ui-btn-icon-right .ui-btn-inner,.ui-select .ui-li-has-count .ui-btn-inner{padding-right:45px}.ui-select .ui-mini.ui-btn-icon-right .ui-btn-inner{padding-right:32px}.ui-select .ui-btn-icon-right.ui-li-has-count .ui-btn-inner{padding-right:80px}.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-btn-inner{padding-right:67px}.ui-select .ui-btn-icon-right .ui-icon{right:15px}.ui-select .ui-mini.ui-btn-icon-right .ui-icon{right:7px}.ui-select .ui-btn-icon-right.ui-li-has-count .ui-li-count{right:45px}.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-li-count{right:32px}label.ui-select{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}.ui-select .ui-btn-text,.ui-selectmenu .ui-btn-text{display:block;min-height:1em;overflow:hidden!important}.ui-select .ui-btn-text{text-overflow:ellipsis}.ui-selectmenu{padding:6px;min-width:160px}.ui-selectmenu .ui-listview{margin:0}.ui-selectmenu .ui-btn.ui-li-divider{cursor:default}.ui-selectmenu-hidden{top:-99999px;left:-9999px}.ui-screen-hidden,.ui-selectmenu-list .ui-li .ui-icon{display:none}.ui-selectmenu-list .ui-li .ui-icon{display:block}.ui-li.ui-selectmenu-placeholder{display:none}.ui-selectmenu .ui-header{margin:0;padding:0}.ui-selectmenu .ui-header .ui-title{margin:0.6em 46px 0.8em}@media all and (min-width:450px){.ui-field-contain label.ui-select{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-select{width:78%;display:inline-block}.ui-hide-label .ui-select{width:100%}}.ui-selectmenu .ui-header h1:after{content:'.';visibility:hidden}label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:normal;margin:0 0 .3em}input.ui-input-text,textarea.ui-input-text{background-image:none;padding:.4em;margin:.5em 0;line-height:1.4;font-size:16px;display:block;width:100%;outline:0}input.ui-input-text.ui-mini,textarea.ui-input-text.ui-mini{margin:.25em 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text{margin:0}input.ui-input-text,textarea.ui-input-text,.ui-input-search{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}input.ui-input-text{-webkit-appearance:none}textarea.ui-input-text{height:50px;-webkit-transition:height 200ms linear;-moz-transition:height 200ms linear;-o-transition:height 200ms linear;transition:height 200ms linear}.ui-input-search{padding:0 30px;margin:.5em 0;background-image:none;position:relative}.ui-input-search.ui-mini{margin:.25em 0}.ui-field-contain .ui-input-search{margin:0}.ui-icon-searchfield:after{position:absolute;left:7px;top:50%;margin-top:-9px;content:"";width:18px;height:18px;opacity:.5}.ui-input-search input.ui-input-text{border:none;width:98%;padding:.4em 0;margin:0;display:block;background:transparent none;outline:0!important}.ui-input-search .ui-input-clear{position:absolute;right:0;top:50%;margin-top:-13px}.ui-mini .ui-input-clear{right:-3px}.ui-input-search .ui-input-clear-hidden{display:none}input.ui-mini,.ui-mini input,textarea.ui-mini{font-size:14px}textarea.ui-mini{height:45px}@media all and (min-width:450px){.ui-field-contain label.ui-input-text{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text,.ui-field-contain .ui-input-search{width:78%;display:inline-block}.ui-hide-label input.ui-input-text,.ui-hide-label textarea.ui-input-text,.ui-hide-label .ui-input-search{width:100%}.ui-input-search input.ui-input-text{width:98%}}.ui-listview{margin:0}ol.ui-listview,ol.ui-listview .ui-li-divider{counter-reset:listnumbering}.ui-content .ui-listview{margin:-15px}.ui-collapsible-content > .ui-listview{margin:-10px -15px}.ui-content .ui-listview-inset{margin:1em 0}.ui-collapsible-content .ui-listview-inset{margin:.5em 0}.ui-listview,.ui-li{list-style:none;padding:0}.ui-li,.ui-li.ui-field-contain{display:block;margin:0;position:relative;overflow:visible;text-align:left;border-width:0;border-top-width:1px}.ui-li.ui-btn{margin:0}.ui-li .ui-btn-text a.ui-link-inherit{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-static{background-image:none}.ui-li-divider{padding:.5em 15px;font-size:14px;font-weight:bold}ol.ui-listview .ui-link-inherit:before,ol.ui-listview .ui-li-static:before,.ui-li-dec{font-size:.8em;display:inline-block;padding-right:.3em;font-weight:normal;counter-increment:listnumbering;content:counter(listnumbering) ". "}ol.ui-listview .ui-li-jsnumbering:before{content:""!important}.ui-listview-inset .ui-li{border-right-width:1px;border-left-width:1px}.ui-li-last,.ui-li.ui-field-contain.ui-li-last{border-bottom-width:1px}.ui-collapsible [class*="ui-body"] > .ui-listview:not(.ui-listview-inset) .ui-li-last{border-bottom-width:0}.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) .ui-li:first-child{border-top-width:0}.ui-collapsible-content > .ui-listview:not(.ui-listview-inset),.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) .ui-li-last{-webkit-border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) .ui-li-last .ui-li-link-alt{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-li>.ui-btn-inner{display:block;position:relative;padding:0}.ui-li .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li{padding:.7em 15px;display:block}.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-thumb{min-height:60px;padding-left:100px}.ui-li-has-icon .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-icon{min-height:20px;padding-left:40px}.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-count,.ui-li-divider.ui-li-has-count{padding-right:45px}.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow{padding-right:40px}.ui-li-has-arrow.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow.ui-li-has-count{padding-right:75px}.ui-li-heading{font-size:16px;font-weight:bold;display:block;margin:.6em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-desc{font-size:12px;font-weight:normal;display:block;margin:-.5em 0 .6em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-thumb,.ui-listview .ui-li-icon{position:absolute;left:1px;top:0;max-height:80px;max-width:80px}.ui-listview .ui-li-icon{max-height:16px;max-width:16px;left:10px;top:.9em}.ui-li-thumb,.ui-listview .ui-li-icon,.ui-li-content{float:left;margin-right:10px}.ui-li-aside{float:right;width:50%;text-align:right;margin:.3em 0}@media all and (min-width:480px){.ui-li-aside{width:45%}}.ui-li-divider{cursor:default}.ui-li-has-alt .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt{padding-right:53px}.ui-li-has-alt.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt.ui-li-has-count{padding-right:88px}.ui-li-has-count .ui-li-count{position:absolute;font-size:11px;font-weight:bold;padding:.2em .5em;top:50%;margin-top:-.9em;right:10px}.ui-li-has-count.ui-li-divider .ui-li-count,.ui-li-has-count .ui-link-inherit .ui-li-count{margin-top:-.95em}.ui-li-has-arrow.ui-li-has-count .ui-li-count{right:40px}.ui-li-has-alt.ui-li-has-count .ui-li-count{right:53px}.ui-li-link-alt{position:absolute;width:40px;height:100%;border-width:0;border-left-width:1px;top:0;right:0;margin:0;padding:0;z-index:2}.ui-li-link-alt .ui-btn{overflow:hidden;position:absolute;right:8px;top:50%;margin:-13px 0 0 0;border-bottom-width:1px;z-index:-1}.ui-li-link-alt .ui-btn-inner{padding:0;height:100%;position:absolute;width:100%;top:0;left:0}.ui-li-link-alt .ui-btn .ui-icon{right:50%;margin-right:-9px}.ui-li-link-alt .ui-btn-icon-notext .ui-btn-inner .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-listview * .ui-btn-inner > .ui-btn > .ui-btn-inner{border-top:0}.ui-listview-filter{border-width:0;overflow:hidden;margin:-15px -15px 15px -15px}.ui-collapsible-content .ui-listview-filter{margin:-10px -15px 10px -15px;border-bottom:inherit}.ui-listview-filter-inset{margin:-15px -5px;background:transparent}.ui-collapsible-content .ui-listview-filter-inset{margin:-5px;border-bottom-width:0}.ui-listview-filter .ui-input-search{margin:5px;width:auto;display:block}.ui-li.ui-screen-hidden{display:none}@media only screen and (min-device-width:768px) and (max-device-width:1024px){.ui-li .ui-btn-text{overflow:visible}}label.ui-slider{font-size:16px;line-height:1.4;font-weight:normal;margin:0 0 .3em;display:block}input.ui-slider-input,.ui-field-contain input.ui-slider-input{display:inline-block;width:50px;background-image:none;padding:.4em;margin:.5em 0;line-height:1.4;font-size:16px;outline:0}input.ui-slider-input.ui-mini,.ui-field-contain input.ui-slider-input.ui-mini{width:45px;margin:.25em 0;font-size:14px}.ui-field-contain input.ui-slider-input{margin:0}input.ui-slider-input,.ui-field-contain input.ui-slider-input{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;box-sizing:content-box}.ui-slider-input::-webkit-outer-spin-button{margin:0}select.ui-slider-switch{display:none}div.ui-slider{position:relative;display:inline-block;overflow:visible;height:15px;padding:0;margin:0 2% 0 20px;top:4px;width:65%}div.ui-slider-mini{height:12px;margin-left:10px;top:2px}div.ui-slider-bg{border:none;height:100%;padding-right:8px}.ui-controlgroup a.ui-slider-handle,a.ui-btn.ui-slider-handle{position:absolute;z-index:1;top:50%;width:28px;height:28px;margin:-15px 0 0 -15px;outline:0}a.ui-btn.ui-slider-handle .ui-btn-inner{padding:0;height:100%}div.ui-slider-mini a.ui-slider-handle{height:14px;width:14px;margin:-8px 0 0 -7px}div.ui-slider-mini a.ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:-9px 0 0 -9px;border-top:none}@media all and (min-width:450px){.ui-field-contain label.ui-slider{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain div.ui-slider{width:43%}.ui-field-contain div.ui-slider-switch{width:5.5em}}div.ui-slider-switch{height:32px;margin-left:0;width:5.8em}a.ui-slider-handle-snapping{-webkit-transition:left 70ms linear;-moz-transition:left 70ms linear}div.ui-slider-switch .ui-slider-handle{margin:1px 0 0 -15px}.ui-slider-inneroffset{margin:0 16px;position:relative;z-index:1}div.ui-slider-switch.ui-slider-mini{width:5em;height:29px}div.ui-slider-switch.ui-slider-mini .ui-slider-inneroffset{margin:0 15px 0 14px}div.ui-slider-switch.ui-slider-mini .ui-slider-handle{width:25px;height:25px;margin:1px 0 0 -13px}div.ui-slider-switch.ui-slider-mini a.ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:0}span.ui-slider-label{position:absolute;text-align:center;width:100%;overflow:hidden;font-size:16px;top:0;line-height:2;min-height:100%;border-width:0;white-space:nowrap}.ui-slider-mini span.ui-slider-label{font-size:14px}span.ui-slider-label-a{z-index:1;left:0;text-indent:-1.5em}span.ui-slider-label-b{z-index:0;right:0;text-indent:1.5em}.ui-slider-inline{width:120px;display:inline-block} \ No newline at end of file diff --git a/examples/old/css/my.css b/examples/old/css/my.css deleted file mode 100644 index 9c998ebd7b..0000000000 --- a/examples/old/css/my.css +++ /dev/null @@ -1,32 +0,0 @@ -.cold { - color: #3399FF; -} -.hot { - color: #FF3333; -} - -/* JQuery mobile settings */ -input.ui-slider-input { - display:none !important; -} - -/* */ -img.push { - border-radius:10px; -} -img.switch { - border-radius:10px; -} -img.trigger { - border-radius:10px; -} -img.push:hover { - cursor: pointer; -} -img.switch:hover { - cursor: pointer; -} -img.trigger:hover { - cursor: pointer; -} - diff --git a/examples/old/example.html b/examples/old/example.html deleted file mode 100755 index 146731579b..0000000000 --- a/examples/old/example.html +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - SmartHomeNG - Example - - - - - - - - - - - -
- -
-

Basic HTML Elements

-
- -
-

Text elements

-
-
Div: Enter content here...
- Span: Enter content here... -
-

Image element

-
- -

A string item which could be set with sh.example.img("/new/path.png")

-

You could specify a visu_img attribute to map a postive integer value to an image.
list for the item.

-
-# smarthome.conf
-['example']
-    [['img']]
-        value = True
-        type = num # or bool for a switch
-        visu = true
-        visu_img = /img/off.png, /img/on.png
-
-# yourlogic.py
-sh.example.img(1) # or sh.example.img(True) would change the displayed image to /img/on.png
-
-
-

Interactive Images

-

Switch/Push

-
-

 

-

The switch class provides a basic switch. Depending on the current value it will send 'True' or 'False'. For visual feedback you would like to specify 'visu_img' as in the example above.
- The push class is similar to the switch, but it sends 'True' if you push the button and 'False' if you release it.

-
-

Set

-
-

Value of example.set =

-

This button sets the value of the item to the specified value. Currently only numeric (integer and float) values are supported!

-
-

RRD Graphs

-
-
-

Print a graph for the item with the specified timeframe. For the frame you could choose beetwen 'h' = hour, 'd' = day, 'm' = month and 'y' = year.

-

You could specify options as described at the flot homepage in the 'data-options' attribute: -

Simply place multiple items into one graph:

-
-
-

Lists

-
-
    -

    It fills an unsorted list ul with the elements specified in the item array.

    -
    -

    Logs

    -
    -
      -

      Shows the the entries of the log file for the number of data-max.

      -
      -
      - -
      - -
      -
      - -
      - -
      -

      Trigger logics

      -
      - -
      - -
      - - -
      -
      - -
      - -
      -
      - -
      - -
      -

      Form Elements

      -
      - -
      -
      -
      - - -
      -
      -
      -
      - - -
      -
      -
      -
      - - -
      -
      -
      - - -
      -
      - - -
      -
      -
      - Radio - - - - - - -
      -
      -
      -
      - Checkbox - - - - -
      -
      - -
      - -
      - -
      -
      - - - diff --git a/examples/old/gen/.gitignore b/examples/old/gen/.gitignore deleted file mode 100644 index 6c22af6ce7..0000000000 --- a/examples/old/gen/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# ignore everything -* -# except .gitignore -!.gitignore diff --git a/examples/old/img/example.png b/examples/old/img/example.png deleted file mode 100644 index 7636719127d4b9b4aea3689571b328a6a4c9d158..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3717 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 U1IjkB>c`Kbk)FA31Ii`#UmE$vPyhe` diff --git a/examples/old/img/off.png b/examples/old/img/off.png deleted file mode 100644 index 3c8f5680a62074894e09169a838c7c4074ed994e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3229 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 z

      @^gSl9{x-yEbSIkSRuO{(Cw=XR(&nYPh#&$b<*H4PT?=oP)4h}7ggv@T|J?@5&oNrJ-Uv{dOGHv^b@cN+&{VYirTRV_O}7^|xNn zl;1V^tDISP1(zPn7Z%&yX#Uj7xtN%k>gwu{G~;X6t{IcyFgQGC?^4wwd$giJY{zka zP=o*W(&w&ZGMS78!E|+X4Gj%FUj^Xt!6> xd-lvF8mMNKvi$>97=-B6|3BRT|F}awsSgA41)g;%V-Fq?2wfwcQZ0wje*tzV@}vL& diff --git a/examples/old/img/on.png b/examples/old/img/on.png deleted file mode 100644 index dc603cd9aa4ddab3252bad4f97aa4884258b99d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3291 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"rgb("+[c.r,c.g,c.b].join(",")+")"}else{return"rgba("+[c.r,c.g,c.b,c.a].join(",")+")"}};c.normalize=function(){function h(j,i,k){return ik?k:i)}c.r=h(0,parseInt(c.r),255);c.g=h(0,parseInt(c.g),255);c.b=h(0,parseInt(c.b),255);c.a=h(0,c.a,1);return c};c.clone=function(){return b.color.make(c.r,c.b,c.g,c.a)};return c.normalize()};b.color.extract=function(d,e){var c;do{c=d.css(e).toLowerCase();if(c!=""&&c!="transparent"){break}d=d.parent()}while(!b.nodeName(d.get(0),"body"));if(c=="rgba(0, 0, 0, 0)"){c="transparent"}return b.color.parse(c)};b.color.parse=function(c){var d,f=b.color.make;if(d=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10))}if(d=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseInt(d[1],10),parseInt(d[2],10),parseInt(d[3],10),parseFloat(d[4]))}if(d=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55)}if(d=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(c)){return f(parseFloat(d[1])*2.55,parseFloat(d[2])*2.55,parseFloat(d[3])*2.55,parseFloat(d[4]))}if(d=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c)){return f(parseInt(d[1],16),parseInt(d[2],16),parseInt(d[3],16))}if(d=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c)){return f(parseInt(d[1]+d[1],16),parseInt(d[2]+d[2],16),parseInt(d[3]+d[3],16))}var e=b.trim(c).toLowerCase();if(e=="transparent"){return f(255,255,255,0)}else{d=a[e]||[0,0,0];return f(d[0],d[1],d[2])}};var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);(function(c){function b(aw,aj,H,ag){var P=[],N={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:0.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,timezone:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null,monthNames:null,timeformat:null,twelveHourClock:false},yaxis:{autoscaleMargin:0.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false},shadowSize:3,highlightColor:null},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1000/60},hooks:{}},aA=null,ae=null,w=null,F=null,y=null,n=[],ax=[],o={left:0,right:0,top:0,bottom:0},E=0,G=0,h=0,u=0,al={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},ar=this;ar.setData=ak;ar.setupGrid=r;ar.draw=W;ar.getPlaceholder=function(){return aw};ar.getCanvas=function(){return aA};ar.getPlotOffset=function(){return o};ar.width=function(){return h};ar.height=function(){return u};ar.offset=function(){var aC=w.offset();aC.left+=o.left;aC.top+=o.top;return aC};ar.getData=function(){return P};ar.getAxes=function(){var aD={},aC;c.each(n.concat(ax),function(aE,aF){if(aF){aD[aF.direction+(aF.n!=1?aF.n:"")+"axis"]=aF}});return aD};ar.getXAxes=function(){return n};ar.getYAxes=function(){return ax};ar.c2p=A;ar.p2c=at;ar.getOptions=function(){return N};ar.highlight=v;ar.unhighlight=T;ar.triggerRedrawOverlay=f;ar.pointOffset=function(aC){return{left:parseInt(n[aB(aC,"x")-1].p2c(+aC.x)+o.left,10),top:parseInt(ax[aB(aC,"y")-1].p2c(+aC.y)+o.top,10)}};ar.shutdown=ah;ar.resize=function(){z();g(aA);g(ae)};ar.hooks=al;D(ar);Z(H);X();ak(aj);r();W();ai();function ao(aE,aC){aC=[ar].concat(aC);for(var aD=0;aDaE){aE=aK}}}if(aN<=aE){aN=aE+1}var aJ,aC=[],aI=N.colors,aH=aI.length,aD=0;for(aF=0;aF=0){if(aD<0.5){aD=-aD-0.2}else{aD=0}}else{aD=-aD}}aC[aF]=aJ.scale("rgb",1+aD)}var aG=0,aO;for(aF=0;aFa5.datamax&&a3!=aC){a5.datamax=a3}}c.each(k(),function(a3,a4){a4.datamin=aQ;a4.datamax=aK;a4.used=false});for(aW=0;aW0&&aV[aT-aR]!=null&&aV[aT-aR]!=aV[aT]&&aV[aT-aR+1]!=aV[aT+1]){for(aP=0;aPaO){aO=a2}}if(aZ.y){if(a2aX){aX=a2}}}}if(aL.bars.show){var a0;switch(aL.bars.align){case"left":a0=0;break;case"right":a0=-aL.bars.barWidth;break;case"center":a0=-aL.bars.barWidth/2;break;default:throw new Error("Invalid bar alignment: "+aL.bars.align)}if(aL.bars.horizontal){aS+=a0;aX+=a0+aL.bars.barWidth}else{aM+=a0;aO+=a0+aL.bars.barWidth}}aG(aL.xaxis,aM,aO);aG(aL.yaxis,aS,aX)}c.each(k(),function(a3,a4){if(a4.datamin==aQ){a4.datamin=null}if(a4.datamax==aK){a4.datamax=null}})}function ad(aD){var aC=window.devicePixelRatio||1;var aE=aD.webkitBackingStorePixelRatio||aD.mozBackingStorePixelRatio||aD.msBackingStorePixelRatio||aD.oBackingStorePixelRatio||aD.backingStorePixelRatio||1;return aC/aE}function i(aD){var aF=document.createElement("canvas");aF.className=aD;c(aF).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(aw);if(!aF.getContext){if(window.G_vmlCanvasManager){aF=window.G_vmlCanvasManager.initElement(aF)}else{throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.")}}var aC=aF.getContext("2d");var aE=ad(aC);aF.width=E*aE;aF.height=G*aE;aF.style.width=E+"px";aF.style.height=G+"px";aC.save();aC.scale(aE,aE);return aF}function z(){E=aw.width();G=aw.height();if(E<=0||G<=0){throw new Error("Invalid dimensions for plot, width = "+E+", height = "+G)}}function g(aE){var aC=aE.getContext("2d");var aD=ad(aC);if(aE.style.width!=E){aE.width=E*aD;aE.style.width=E+"px"}if(aE.style.height!=G){aE.height=G*aD;aE.style.height=G+"px"}aC.restore();aC.save();aC.scale(aD,aD)}function X(){var aD,aC=aw.children("canvas.flot-base"),aE=aw.children("canvas.flot-overlay");if(aC.length==0||aE==0){aw.html("");aw.css({padding:0});if(aw.css("position")=="static"){aw.css("position","relative")}z();aA=i("flot-base");ae=i("flot-overlay");aD=false}else{aA=aC.get(0);ae=aE.get(0);aD=true}F=aA.getContext("2d");y=ae.getContext("2d");w=c(ae);if(aD){aw.data("plot").shutdown();ar.resize();y.clearRect(0,0,E,G);w.unbind();aw.children().not([aA,ae]).remove()}aw.data("plot",ar)}function ai(){if(N.grid.hoverable){w.mousemove(aa);w.mouseleave(j)}if(N.grid.clickable){w.click(Q)}ao(al.bindEvents,[w])}function ah(){if(K){clearTimeout(K)}w.unbind("mousemove",aa);w.unbind("mouseleave",j);w.unbind("click",Q);ao(al.shutdown,[w])}function p(aH){function aD(aI){return aI}var aG,aC,aE=aH.options.transform||aD,aF=aH.options.inverseTransform;if(aH.direction=="x"){aG=aH.scale=h/Math.abs(aE(aH.max)-aE(aH.min));aC=Math.min(aE(aH.max),aE(aH.min))}else{aG=aH.scale=u/Math.abs(aE(aH.max)-aE(aH.min));aG=-aG;aC=Math.max(aE(aH.max),aE(aH.min))}if(aE==aD){aH.p2c=function(aI){return(aI-aC)*aG}}else{aH.p2c=function(aI){return(aE(aI)-aC)*aG}}if(!aF){aH.c2p=function(aI){return aC+aI/aG}}else{aH.c2p=function(aI){return aF(aC+aI/aG)}}}function J(aE){var aC=aE.options,aJ=aE.ticks||[],aK=aC.labelWidth||0,aI=aC.labelHeight||0,aH=aE.font;F.save();F.font=aH.style+" "+aH.variant+" "+aH.weight+" "+aH.size+"px '"+aH.family+"'";for(var aG=0;aG|\r\n|\r/g,"\n").split("\n");for(var aF=0;aF=0;--aE){av(aC[aE])}L();c.each(aC,function(aJ,aK){U(aK)})}h=E-o.left-o.right;u=G-o.bottom-o.top;c.each(aH,function(aJ,aK){p(aK)});m()}function l(aF){var aG=aF.options,aE=+(aG.min!=null?aG.min:aF.datamin),aC=+(aG.max!=null?aG.max:aF.datamax),aI=aC-aE;if(aI==0){var aD=aC==0?1:0.01;if(aG.min==null){aE-=aD}if(aG.max==null||aG.min!=null){aC+=aD}}else{var aH=aG.autoscaleMargin;if(aH!=null){if(aG.min==null){aE-=aI*aH;if(aE<0&&aF.datamin!=null&&aF.datamin>=0){aE=0}}if(aG.max==null){aC+=aI*aH;if(aC>0&&aF.datamax!=null&&aF.datamax<=0){aC=0}}}}aF.min=aE;aF.max=aC}function R(aH){var aD=aH.options;var aG;if(typeof aD.ticks=="number"&&aD.ticks>0){aG=aD.ticks}else{aG=0.3*Math.sqrt(aH.direction=="x"?E:G)}aH.delta=(aH.max-aH.min)/aG;if(aD.mode=="time"&&!aH.tickGenerator){throw new Error("Time mode requires the flot.time plugin.")}if(!aH.tickGenerator){var aF=aD.tickDecimals;var aI=-Math.floor(Math.log(aH.delta)/Math.LN10);if(aF!=null&&aI>aF){aI=aF}var aC=Math.pow(10,-aI);var aE=aH.delta/aC;var aN;if(aE<1.5){aN=1}else{if(aE<3){aN=2;if(aE>2.25&&(aF==null||aI+1<=aF)){aN=2.5;++aI}}else{if(aE<7.5){aN=5}else{aN=10}}}aN*=aC;if(aD.minTickSize!=null&&aN0){if(aD.min==null){aH.min=Math.min(aH.min,aM[0])}if(aD.max==null&&aM.length>1){aH.max=Math.max(aH.max,aM[aM.length-1])}}aH.tickGenerator=function(aQ){var aR=[],aO,aP;for(aP=0;aP1&&/\..*0$/.test((aK[1]-aK[0]).toFixed(aL)))){aH.tickDecimals=aL}}}}}function O(aG){var aI=aG.options.ticks,aH=[];if(aI==null||(typeof aI=="number"&&aI>0)){aH=aG.tickGenerator(aG)}else{if(aI){if(c.isFunction(aI)){aH=aI(aG)}else{aH=aI}}}var aF,aC;aG.ticks=[];for(aF=0;aF1){aD=aE[1]}}else{aC=+aE}if(aD==null){aD=aG.tickFormatter(aC,aG)}if(!isNaN(aC)){aG.ticks.push({v:aC,label:aD})}}}function aq(aC,aD){if(aC.options.autoscaleMargin&&aD.length>0){if(aC.options.min==null){aC.min=Math.min(aC.min,aD[0].v)}if(aC.options.max==null&&aD.length>1){aC.max=Math.max(aC.max,aD[aD.length-1].v)}}}function W(){F.clearRect(0,0,E,G);ao(al.drawBackground,[F]);var aD=N.grid;if(aD.show&&aD.backgroundColor){M()}if(aD.show&&!aD.aboveData){ac();S()}for(var aC=0;aCaJ){var aE=aI;aI=aJ;aJ=aE}return{from:aI,to:aJ,axis:aD}}function M(){F.save();F.translate(o.left,o.top);F.fillStyle=an(N.grid.backgroundColor,u,0,"rgba(255, 255, 255, 0)");F.fillRect(0,0,h,u);F.restore()}function ac(){var aG,aM,aO,aK;F.save();F.translate(o.left,o.top);var aI=N.grid.markings;if(aI){if(c.isFunction(aI)){aM=ar.getAxes();aM.xmin=aM.xaxis.min;aM.xmax=aM.xaxis.max;aM.ymin=aM.yaxis.min;aM.ymax=aM.yaxis.max;aI=aI(aM)}for(aG=0;aGaD.axis.max||aJ.toaJ.axis.max){continue}aD.from=Math.max(aD.from,aD.axis.min);aD.to=Math.min(aD.to,aD.axis.max);aJ.from=Math.max(aJ.from,aJ.axis.min);aJ.to=Math.min(aJ.to,aJ.axis.max);if(aD.from==aD.to&&aJ.from==aJ.to){continue}aD.from=aD.axis.p2c(aD.from);aD.to=aD.axis.p2c(aD.to);aJ.from=aJ.axis.p2c(aJ.from);aJ.to=aJ.axis.p2c(aJ.to);if(aD.from==aD.to||aJ.from==aJ.to){F.beginPath();F.strokeStyle=aE.color||N.grid.markingsColor;F.lineWidth=aE.lineWidth||N.grid.markingsLineWidth;F.moveTo(aD.from,aJ.from);F.lineTo(aD.to,aJ.to);F.stroke()}else{F.fillStyle=aE.color||N.grid.markingsColor;F.fillRect(aD.from,aJ.to,aD.to-aD.from,aJ.from-aJ.to)}}}aM=k();aO=N.grid.borderWidth;for(var aF=0;aFaC.max||(aS=="full"&&((typeof aO=="object"&&aO[aC.position]>0)||aO>0)&&(aQ==aC.min||aQ==aC.max))){continue}if(aC.direction=="x"){aP=aC.p2c(aQ);aL=aS=="full"?-u:aS;if(aC.position=="top"){aL=-aL}}else{aN=aC.p2c(aQ);aR=aS=="full"?-h:aS;if(aC.position=="left"){aR=-aR}}if(F.lineWidth==1){if(aC.direction=="x"){aP=Math.floor(aP)+0.5}else{aN=Math.floor(aN)+0.5}}F.moveTo(aP,aN);F.lineTo(aP+aR,aN+aL)}F.stroke()}if(aO){aK=N.grid.borderColor;if(typeof aO=="object"||typeof aK=="object"){if(typeof aO!=="object"){aO={top:aO,right:aO,bottom:aO,left:aO}}if(typeof aK!=="object"){aK={top:aK,right:aK,bottom:aK,left:aK}}if(aO.top>0){F.strokeStyle=aK.top;F.lineWidth=aO.top;F.beginPath();F.moveTo(0-aO.left,0-aO.top/2);F.lineTo(h,0-aO.top/2);F.stroke()}if(aO.right>0){F.strokeStyle=aK.right;F.lineWidth=aO.right;F.beginPath();F.moveTo(h+aO.right/2,0-aO.top);F.lineTo(h+aO.right/2,u);F.stroke()}if(aO.bottom>0){F.strokeStyle=aK.bottom;F.lineWidth=aO.bottom;F.beginPath();F.moveTo(h+aO.right,u+aO.bottom/2);F.lineTo(0,u+aO.bottom/2);F.stroke()}if(aO.left>0){F.strokeStyle=aK.left;F.lineWidth=aO.left;F.beginPath();F.moveTo(0-aO.left/2,u+aO.bottom);F.lineTo(0-aO.left/2,0);F.stroke()}}else{F.lineWidth=aO;F.strokeStyle=N.grid.borderColor;F.strokeRect(-aO/2,-aO/2,h+aO,u+aO)}}F.restore()}function S(){F.save();c.each(k(),function(aL,aC){if(!aC.show||aC.ticks.length==0){return}var aG=aC.box,aI=aC.font;F.fillStyle=aC.options.color;F.font=aI.style+" "+aI.variant+" "+aI.weight+" "+aI.size+"px "+aI.family;F.textAlign="start";F.textBaseline="middle";for(var aF=0;aFaC.max){continue}var aK,aJ,aE=0,aM;for(var aD=0;aD=aS&&aT>aU.max){if(aS>aU.max){continue}aM=(aU.max-aT)/(aS-aT)*(aL-aM)+aM;aT=aU.max}else{if(aS>=aT&&aS>aU.max){if(aT>aU.max){continue}aL=(aU.max-aT)/(aS-aT)*(aL-aM)+aM;aS=aU.max}}if(aM<=aL&&aM=aL&&aM>aV.max){if(aL>aV.max){continue}aT=(aV.max-aM)/(aL-aM)*(aS-aT)+aT;aM=aV.max}else{if(aL>=aM&&aL>aV.max){if(aM>aV.max){continue}aS=(aV.max-aM)/(aL-aM)*(aS-aT)+aT;aL=aV.max}}if(aM!=aO||aT!=aN){F.moveTo(aV.p2c(aM)+aR,aU.p2c(aT)+aJ)}aO=aL;aN=aS;F.lineTo(aV.p2c(aL)+aR,aU.p2c(aS)+aJ)}F.stroke()}function aG(aJ,aR,aQ){var aX=aJ.points,aW=aJ.pointsize,aO=Math.min(Math.max(0,aQ.min),aQ.max),aY=0,aV,aU=false,aN=1,aM=0,aS=0;while(true){if(aW>0&&aY>aX.length+aW){break}aY+=aW;var a0=aX[aY-aW],aL=aX[aY-aW+aN],aZ=aX[aY],aK=aX[aY+aN];if(aU){if(aW>0&&a0!=null&&aZ==null){aS=aY;aW=-aW;aN=2;continue}if(aW<0&&aY==aM+aW){F.fill();aU=false;aW=-aW;aN=1;aY=aM=aS+aW;continue}}if(a0==null||aZ==null){continue}if(a0<=aZ&&a0=aZ&&a0>aR.max){if(aZ>aR.max){continue}aL=(aR.max-a0)/(aZ-a0)*(aK-aL)+aL;a0=aR.max}else{if(aZ>=a0&&aZ>aR.max){if(a0>aR.max){continue}aK=(aR.max-a0)/(aZ-a0)*(aK-aL)+aL;aZ=aR.max}}if(!aU){F.beginPath();F.moveTo(aR.p2c(a0),aQ.p2c(aO));aU=true}if(aL>=aQ.max&&aK>=aQ.max){F.lineTo(aR.p2c(a0),aQ.p2c(aQ.max));F.lineTo(aR.p2c(aZ),aQ.p2c(aQ.max));continue}else{if(aL<=aQ.min&&aK<=aQ.min){F.lineTo(aR.p2c(a0),aQ.p2c(aQ.min));F.lineTo(aR.p2c(aZ),aQ.p2c(aQ.min));continue}}var aP=a0,aT=aZ;if(aL<=aK&&aL=aQ.min){a0=(aQ.min-aL)/(aK-aL)*(aZ-a0)+a0;aL=aQ.min}else{if(aK<=aL&&aK=aQ.min){aZ=(aQ.min-aL)/(aK-aL)*(aZ-a0)+a0;aK=aQ.min}}if(aL>=aK&&aL>aQ.max&&aK<=aQ.max){a0=(aQ.max-aL)/(aK-aL)*(aZ-a0)+a0;aL=aQ.max}else{if(aK>=aL&&aK>aQ.max&&aL<=aQ.max){aZ=(aQ.max-aL)/(aK-aL)*(aZ-a0)+a0;aK=aQ.max}}if(a0!=aP){F.lineTo(aR.p2c(aP),aQ.p2c(aL))}F.lineTo(aR.p2c(a0),aQ.p2c(aL));F.lineTo(aR.p2c(aZ),aQ.p2c(aK));if(aZ!=aT){F.lineTo(aR.p2c(aZ),aQ.p2c(aK));F.lineTo(aR.p2c(aT),aQ.p2c(aK))}}}F.save();F.translate(o.left,o.top);F.lineJoin="round";var aH=aF.lines.lineWidth,aC=aF.shadowSize;if(aH>0&&aC>0){F.lineWidth=aC;F.strokeStyle="rgba(0,0,0,0.1)";var aI=Math.PI/18;aE(aF.datapoints,Math.sin(aI)*(aH/2+aC/2),Math.cos(aI)*(aH/2+aC/2),aF.xaxis,aF.yaxis);F.lineWidth=aC/2;aE(aF.datapoints,Math.sin(aI)*(aH/2+aC/4),Math.cos(aI)*(aH/2+aC/4),aF.xaxis,aF.yaxis)}F.lineWidth=aH;F.strokeStyle=aF.color;var aD=af(aF.lines,aF.color,0,u);if(aD){F.fillStyle=aD;aG(aF.datapoints,aF.xaxis,aF.yaxis)}if(aH>0){aE(aF.datapoints,0,0,aF.xaxis,aF.yaxis)}F.restore()}function ap(aF){function aI(aO,aN,aV,aL,aT,aU,aR,aK){var aS=aO.points,aJ=aO.pointsize;for(var aM=0;aMaU.max||aPaR.max){continue}F.beginPath();aQ=aU.p2c(aQ);aP=aR.p2c(aP)+aL;if(aK=="circle"){F.arc(aQ,aP,aN,0,aT?Math.PI:Math.PI*2,false)}else{aK(F,aQ,aP,aN,aT)}F.closePath();if(aV){F.fillStyle=aV;F.fill()}F.stroke()}}F.save();F.translate(o.left,o.top);var aH=aF.points.lineWidth,aD=aF.shadowSize,aC=aF.points.radius,aG=aF.points.symbol;if(aH>0&&aD>0){var aE=aD/2;F.lineWidth=aE;F.strokeStyle="rgba(0,0,0,0.1)";aI(aF.datapoints,aC,null,aE+aE/2,true,aF.xaxis,aF.yaxis,aG);F.strokeStyle="rgba(0,0,0,0.2)";aI(aF.datapoints,aC,null,aE/2,true,aF.xaxis,aF.yaxis,aG)}F.lineWidth=aH;F.strokeStyle=aF.color;aI(aF.datapoints,aC,af(aF.points,aF.color),0,false,aF.xaxis,aF.yaxis,aG);F.restore()}function C(aO,aN,aW,aJ,aR,aG,aE,aM,aL,aV,aS,aD){var aF,aU,aK,aQ,aH,aC,aP,aI,aT;if(aS){aI=aC=aP=true;aH=false;aF=aW;aU=aO;aQ=aN+aJ;aK=aN+aR;if(aUaM.max||aQaL.max){return}if(aFaM.max){aU=aM.max;aC=false}if(aKaL.max){aQ=aL.max;aP=false}aF=aM.p2c(aF);aK=aL.p2c(aK);aU=aM.p2c(aU);aQ=aL.p2c(aQ);if(aE){aV.beginPath();aV.moveTo(aF,aK);aV.lineTo(aF,aQ);aV.lineTo(aU,aQ);aV.lineTo(aU,aK);aV.fillStyle=aE(aK,aQ);aV.fill()}if(aD>0&&(aH||aC||aP||aI)){aV.beginPath();aV.moveTo(aF,aK+aG);if(aH){aV.lineTo(aF,aQ+aG)}else{aV.moveTo(aF,aQ+aG)}if(aP){aV.lineTo(aU,aQ+aG)}else{aV.moveTo(aU,aQ+aG)}if(aC){aV.lineTo(aU,aK+aG)}else{aV.moveTo(aU,aK+aG)}if(aI){aV.lineTo(aF,aK+aG)}else{aV.moveTo(aF,aK+aG)}aV.stroke()}}function e(aE){function aD(aK,aJ,aM,aH,aL,aO,aN){var aP=aK.points,aG=aK.pointsize;for(var aI=0;aI")}aK.push("");aI=true}aK.push('

      '+aO.label+"")}if(aI){aK.push("")}if(aK.length==0){return}var aP=''+aK.join("")+"
      ";if(N.legend.container!=null){c(N.legend.container).html(aP)}else{var aL="",aD=N.legend.position,aE=N.legend.margin;if(aE[0]==null){aE=[aE,aE]}if(aD.charAt(0)=="n"){aL+="top:"+(aE[1]+o.top)+"px;"}else{if(aD.charAt(0)=="s"){aL+="bottom:"+(aE[1]+o.bottom)+"px;"}}if(aD.charAt(1)=="e"){aL+="right:"+(aE[0]+o.right)+"px;"}else{if(aD.charAt(1)=="w"){aL+="left:"+(aE[0]+o.left)+"px;"}}var aN=c('
      '+aP.replace('style="','style="position:absolute;'+aL+";")+"
      ").appendTo(aw);if(N.legend.backgroundOpacity!=0){var aJ=N.legend.backgroundColor;if(aJ==null){aJ=N.grid.backgroundColor;if(aJ&&typeof aJ=="string"){aJ=c.color.parse(aJ)}else{aJ=c.color.extract(aN,"background-color")}aJ.a=1;aJ=aJ.toString()}var aC=aN.children();c('
      ').prependTo(aN).css("opacity",N.legend.backgroundOpacity)}}}var ab=[],K=null;function I(aJ,aH,aE){var aP=N.grid.mouseActiveRadius,a1=aP*aP+1,aZ=null,aS=false,aX,aV,aU;for(aX=P.length-1;aX>=0;--aX){if(!aE(P[aX])){continue}var aQ=P[aX],aI=aQ.xaxis,aG=aQ.yaxis,aW=aQ.datapoints.points,aR=aI.c2p(aJ),aO=aG.c2p(aH),aD=aP/aI.scale,aC=aP/aG.scale;aU=aQ.datapoints.pointsize;if(aI.options.inverseTransform){aD=Number.MAX_VALUE}if(aG.options.inverseTransform){aC=Number.MAX_VALUE}if(aQ.lines.show||aQ.points.show){for(aV=0;aVaD||aL-aR<-aD||aK-aO>aC||aK-aO<-aC){continue}var aN=Math.abs(aI.p2c(aL)-aJ),aM=Math.abs(aG.p2c(aK)-aH),aT=aN*aN+aM*aM;if(aT=Math.min(a0,aL)&&aO>=aK+aF&&aO<=aK+aY):(aR>=aL+aF&&aR<=aL+aY&&aO>=Math.min(a0,aK)&&aO<=Math.max(a0,aK))){aZ=[aX,aV/aU]}}}}if(aZ){aX=aZ[0];aV=aZ[1];aU=P[aX].datapoints.pointsize;return{datapoint:P[aX].datapoints.points.slice(aV*aU,(aV+1)*aU),dataIndex:aV,series:P[aX],seriesIndex:aX}}return null}function aa(aC){if(N.grid.hoverable){s("plothover",aC,function(aD){return aD.hoverable!=false})}}function j(aC){if(N.grid.hoverable){s("plothover",aC,function(aD){return false})}}function Q(aC){s("plotclick",aC,function(aD){return aD.clickable!=false})}function s(aD,aC,aE){var aF=w.offset(),aI=aC.pageX-aF.left-o.left,aG=aC.pageY-aF.top-o.top,aK=A({left:aI,top:aG});aK.pageX=aC.pageX;aK.pageY=aC.pageY;var aL=I(aI,aG,aE);if(aL){aL.pageX=parseInt(aL.series.xaxis.p2c(aL.datapoint[0])+aF.left+o.left,10);aL.pageY=parseInt(aL.series.yaxis.p2c(aL.datapoint[1])+aF.top+o.top,10)}if(N.grid.autoHighlight){for(var aH=0;aHaJ.max||aEaH.max){return}var aF=aC.points.radius+aC.points.lineWidth/2;y.lineWidth=aF;y.strokeStyle=aK;var aD=1.5*aF;aG=aJ.p2c(aG);aE=aH.p2c(aE);y.beginPath();if(aC.points.symbol=="circle"){y.arc(aG,aE,aD,0,2*Math.PI,false)}else{aC.points.symbol(y,aG,aE,aD,false)}y.closePath();y.stroke()}function t(aF,aC){var aG=(typeof aF.highlightColor==="string")?aF.highlightColor:c.color.parse(aF.color).scale("a",0.5).toString(),aE=aG,aD=aF.bars.align=="left"?0:-aF.bars.barWidth/2;y.lineWidth=aF.bars.lineWidth;y.strokeStyle=aG;C(aC[0],aC[1],aC[2]||0,aD,aD+aF.bars.barWidth,0,function(){return aE},aF.xaxis,aF.yaxis,y,aF.bars.horizontal,aF.bars.lineWidth)}function an(aK,aC,aI,aD){if(typeof aK=="string"){return aK}else{var aJ=F.createLinearGradient(0,aI,0,aC);for(var aF=0,aE=aK.colors.length;aF12){o=v-12}else{if(v==0){o=12}else{o=v}}for(var p=0;p=w){break}}var J=H[C][0];var F=H[C][1];if(F=="year"){if(q.minTickSize!=null&&q.minTickSize[1]=="year"){J=Math.floor(q.minTickSize[0])}else{var t=Math.pow(10,Math.floor(Math.log(y.delta/c.year)/Math.LN10));var s=(y.delta/c.year)/t;if(s<1.5){J=1}else{if(s<3){J=2}else{if(s<7.5){J=5}else{J=10}}}J*=t}if(J<1){J=1}}y.tickSize=q.tickSize||[J,F];var B=y.tickSize[0];F=y.tickSize[1];var x=B*c[F];if(F=="second"){D.setSeconds(g(D.getSeconds(),B))}else{if(F=="minute"){D.setMinutes(g(D.getMinutes(),B))}else{if(F=="hour"){D.setHours(g(D.getHours(),B))}else{if(F=="month"){D.setMonth(g(D.getMonth(),B))}else{if(F=="quarter"){D.setMonth(3*g(D.getMonth()/3,B))}else{if(F=="year"){D.setFullYear(g(D.getFullYear(),B))}}}}}}D.setMilliseconds(0);if(x>=c.minute){D.setSeconds(0)}else{if(x>=c.hour){D.setMinutes(0)}else{if(x>=c.day){D.setHours(0)}else{if(x>=c.day*4){D.setDate(1)}else{if(x>=c.month*2){D.setMonth(g(D.getMonth(),3))}else{if(x>=c.quarter*2){D.setMonth(g(D.getMonth(),6))}else{if(x>=c.year){D.setMonth(0)}}}}}}}var I=0;var G=Number.NaN;var z;do{z=G;G=D.getTime();E.push(G);if(F=="month"||F=="quarter"){if(B<1){D.setDate(1);var u=D.getTime();D.setMonth(D.getMonth()+(F=="quarter"?3:1));var A=D.getTime();D.setTime(G+I*c.hour+(A-u)*B);I=D.getHours();D.setHours(0)}else{D.setMonth(D.getMonth()+B*(F=="quarter"?3:1))}}else{if(F=="year"){D.setFullYear(D.getFullYear()+B)}else{D.setTime(G+x)}}}while(G)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
      a",n=d.getElementsByTagName("*"),r=d.getElementsByTagName("a")[0],!n||!r||!n.length)return{};s=o.createElement("select"),l=s.appendChild(o.createElement("option")),a=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={getSetAttribute:"t"!==d.className,leadingWhitespace:3===d.firstChild.nodeType,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:"/a"===r.getAttribute("href"),opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:!!a.value,optSelected:l.selected,enctype:!!o.createElement("form").enctype,html5Clone:"<:nav>"!==o.createElement("nav").cloneNode(!0).outerHTML,boxModel:"CSS1Compat"===o.compatMode,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!l.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}a=o.createElement("input"),a.setAttribute("value",""),t.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),t.radioValue="t"===a.value,a.setAttribute("checked","t"),a.setAttribute("name","t"),u=o.createDocumentFragment(),u.appendChild(a),t.appendChecked=a.checked,t.checkClone=u.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;return d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip,b(function(){var n,r,a,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",u=o.getElementsByTagName("body")[0];u&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",u.appendChild(n).appendChild(d),d.innerHTML="
      t
      ",a=d.getElementsByTagName("td"),a[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===a[0].offsetHeight,a[0].style.display="",a[1].style.display="none",t.reliableHiddenOffsets=p&&0===a[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=4===d.offsetWidth,t.doesNotIncludeMarginInBodyOffset=1!==u.offsetTop,e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(o.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
      ",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(u.style.zoom=1)),u.removeChild(n),n=d=a=r=null)}),n=s=u=l=r=a=null,t}();var O=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,B=/([A-Z])/g;function P(e,n,r,i){if(b.acceptData(e)){var o,a,s=b.expando,u="string"==typeof n,l=e.nodeType,p=l?b.cache:e,f=l?e[s]:e[s]&&s;if(f&&p[f]&&(i||p[f].data)||!u||r!==t)return f||(l?e[s]=f=c.pop()||b.guid++:f=s),p[f]||(p[f]={},l||(p[f].toJSON=b.noop)),("object"==typeof n||"function"==typeof n)&&(i?p[f]=b.extend(p[f],n):p[f].data=b.extend(p[f].data,n)),o=p[f],i||(o.data||(o.data={}),o=o.data),r!==t&&(o[b.camelCase(n)]=r),u?(a=o[n],null==a&&(a=o[b.camelCase(n)])):a=o,a}}function R(e,t,n){if(b.acceptData(e)){var r,i,o,a=e.nodeType,s=a?b.cache:e,u=a?e[b.expando]:b.expando;if(s[u]){if(t&&(o=n?s[u]:s[u].data)){b.isArray(t)?t=t.concat(b.map(t,b.camelCase)):t in o?t=[t]:(t=b.camelCase(t),t=t in o?[t]:t.split(" "));for(r=0,i=t.length;i>r;r++)delete o[t[r]];if(!(n?$:b.isEmptyObject)(o))return}(n||(delete s[u].data,$(s[u])))&&(a?b.cleanData([e],!0):b.support.deleteExpando||s!=s.window?delete s[u]:s[u]=null)}}}b.extend({cache:{},expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?b.cache[e[b.expando]]:e[b.expando],!!e&&!$(e)},data:function(e,t,n){return P(e,t,n)},removeData:function(e,t){return R(e,t)},_data:function(e,t,n){return P(e,t,n,!0)},_removeData:function(e,t){return R(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&b.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),b.fn.extend({data:function(e,n){var r,i,o=this[0],a=0,s=null;if(e===t){if(this.length&&(s=b.data(o),1===o.nodeType&&!b._data(o,"parsedAttrs"))){for(r=o.attributes;r.length>a;a++)i=r[a].name,i.indexOf("data-")||(i=b.camelCase(i.slice(5)),W(o,i,s[i]));b._data(o,"parsedAttrs",!0)}return s}return"object"==typeof e?this.each(function(){b.data(this,e)}):b.access(this,function(n){return n===t?o?W(o,e,b.data(o,e)):null:(this.each(function(){b.data(this,e,n)}),t)},null,n,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){b.removeData(this,e)})}});function W(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(B,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:O.test(r)?b.parseJSON(r):r}catch(o){}b.data(e,n,r)}else r=t}return r}function $(e){var t;for(t in e)if(("data"!==t||!b.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}b.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=b._data(e,n),r&&(!i||b.isArray(r)?i=b._data(e,n,b.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=b.queue(e,t),r=n.length,i=n.shift(),o=b._queueHooks(e,t),a=function(){b.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return b._data(e,n)||b._data(e,n,{empty:b.Callbacks("once memory").add(function(){b._removeData(e,t+"queue"),b._removeData(e,n)})})}}),b.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?b.queue(this[0],e):n===t?this:this.each(function(){var t=b.queue(this,e,n);b._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&b.dequeue(this,e)})},dequeue:function(e){return this.each(function(){b.dequeue(this,e)})},delay:function(e,t){return e=b.fx?b.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=b.Deferred(),a=this,s=this.length,u=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=b._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(u));return u(),o.promise(n)}});var I,z,X=/[\t\r\n]/g,U=/\r/g,V=/^(?:input|select|textarea|button|object)$/i,Y=/^(?:a|area)$/i,J=/^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,G=/^(?:checked|selected)$/i,Q=b.support.getSetAttribute,K=b.support.input;b.fn.extend({attr:function(e,t){return b.access(this,b.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){b.removeAttr(this,e)})},prop:function(e,t){return b.access(this,b.prop,e,t,arguments.length>1)},removeProp:function(e){return e=b.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,u="string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=b.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,u=0===arguments.length||"string"==typeof e&&e;if(b.isFunction(e))return this.each(function(t){b(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(X," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?b.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,r="boolean"==typeof t;return b.isFunction(e)?this.each(function(n){b(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,a=0,s=b(this),u=t,l=e.match(w)||[];while(o=l[a++])u=r?u:!s.hasClass(o),s[u?"addClass":"removeClass"](o)}else(n===i||"boolean"===n)&&(this.className&&b._data(this,"__className__",this.className),this.className=this.className||e===!1?"":b._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(X," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=b.isFunction(e),this.each(function(n){var o,a=b(this);1===this.nodeType&&(o=i?e.call(this,n,a.val()):e,null==o?o="":"number"==typeof o?o+="":b.isArray(o)&&(o=b.map(o,function(e){return null==e?"":e+""})),r=b.valHooks[this.type]||b.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=b.valHooks[o.type]||b.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(U,""):null==n?"":n)}}}),b.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,u=0>i?s:o?i:0;for(;s>u;u++)if(n=r[u],!(!n.selected&&u!==i||(b.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&b.nodeName(n.parentNode,"optgroup"))){if(t=b(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n=b.makeArray(t);return b(e).find("option").each(function(){this.selected=b.inArray(b(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attr:function(e,n,r){var o,a,s,u=e.nodeType;if(e&&3!==u&&8!==u&&2!==u)return typeof e.getAttribute===i?b.prop(e,n,r):(a=1!==u||!b.isXMLDoc(e),a&&(n=n.toLowerCase(),o=b.attrHooks[n]||(J.test(n)?z:I)),r===t?o&&a&&"get"in o&&null!==(s=o.get(e,n))?s:(typeof e.getAttribute!==i&&(s=e.getAttribute(n)),null==s?t:s):null!==r?o&&a&&"set"in o&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r):(b.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=b.propFix[n]||n,J.test(n)?!Q&&G.test(n)?e[b.camelCase("default-"+n)]=e[r]=!1:e[r]=!1:b.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!b.support.radioValue&&"radio"===t&&b.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!b.isXMLDoc(e),a&&(n=b.propFix[n]||n,o=b.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):V.test(e.nodeName)||Y.test(e.nodeName)&&e.href?0:t}}}}),z={get:function(e,n){var r=b.prop(e,n),i="boolean"==typeof r&&e.getAttribute(n),o="boolean"==typeof r?K&&Q?null!=i:G.test(n)?e[b.camelCase("default-"+n)]:!!i:e.getAttributeNode(n);return o&&o.value!==!1?n.toLowerCase():t},set:function(e,t,n){return t===!1?b.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&b.propFix[n]||n,n):e[b.camelCase("default-"+n)]=e[n]=!0,n}},K&&Q||(b.attrHooks.value={get:function(e,n){var r=e.getAttributeNode(n);return b.nodeName(e,"input")?e.defaultValue:r&&r.specified?r.value:t},set:function(e,n,r){return b.nodeName(e,"input")?(e.defaultValue=n,t):I&&I.set(e,n,r)}}),Q||(I=b.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&("id"===n||"name"===n||"coords"===n?""!==r.value:r.specified)?r.value:t},set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},b.attrHooks.contenteditable={get:I.get,set:function(e,t,n){I.set(e,""===t?!1:t,n)}},b.each(["width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}})})),b.support.hrefNormalized||(b.each(["href","src","width","height"],function(e,n){b.attrHooks[n]=b.extend(b.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return null==r?t:r}})}),b.each(["href","src"],function(e,t){b.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}})),b.support.style||(b.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),b.support.optSelected||(b.propHooks.selected=b.extend(b.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),b.support.enctype||(b.propFix.enctype="encoding"),b.support.checkOn||b.each(["radio","checkbox"],function(){b.valHooks[this]={get:function(e){return null===e.getAttribute("value")?"on":e.value}}}),b.each(["radio","checkbox"],function(){b.valHooks[this]=b.extend(b.valHooks[this],{set:function(e,n){return b.isArray(n)?e.checked=b.inArray(b(e).val(),n)>=0:t}})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}b.event={global:{},add:function(e,n,r,o,a){var s,u,l,c,p,f,d,h,g,m,y,v=b._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=b.guid++),(u=v.events)||(u=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof b===i||e&&b.event.triggered===e.type?t:b.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(w)||[""],l=n.length;while(l--)s=rt.exec(n[l])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),p=b.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=b.event.special[g]||{},d=b.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&b.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=u[g])||(h=u[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),b.event.global[g]=!0;e=null}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,p,f,d,h,g,m=b.hasData(e)&&b._data(e);if(m&&(c=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(s=rt.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=b.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),u=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));u&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||b.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)b.event.remove(e,d+t[l],n,r,!0);b.isEmptyObject(c)&&(delete m.handle,b._removeData(e,"events"))}},trigger:function(n,r,i,a){var s,u,l,c,p,f,d,h=[i||o],g=y.call(n,"type")?n.type:n,m=y.call(n,"namespace")?n.namespace.split("."):[];if(l=f=i=i||o,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+b.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),u=0>g.indexOf(":")&&"on"+g,n=n[b.expando]?n:new b.Event(g,"object"==typeof n&&n),n.isTrigger=!0,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:b.makeArray(r,[n]),p=b.event.special[g]||{},a||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!a&&!p.noBubble&&!b.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(l=l.parentNode);l;l=l.parentNode)h.push(l),f=l;f===(i.ownerDocument||o)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((l=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(b._data(l,"events")||{})[n.type]&&b._data(l,"handle"),s&&s.apply(l,r),s=u&&l[u],s&&b.acceptData(l)&&s.apply&&s.apply(l,r)===!1&&n.preventDefault();if(n.type=g,!(a||n.isDefaultPrevented()||p._default&&p._default.apply(i.ownerDocument,r)!==!1||"click"===g&&b.nodeName(i,"a")||!b.acceptData(i)||!u||!i[g]||b.isWindow(i))){f=i[u],f&&(i[u]=null),b.event.triggered=g;try{i[g]()}catch(v){}b.event.triggered=t,f&&(i[u]=f)}return n.result}},dispatch:function(e){e=b.event.fix(e);var n,r,i,o,a,s=[],u=h.call(arguments),l=(b._data(this,"events")||{})[e.type]||[],c=b.event.special[e.type]||{};if(u[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=b.event.handlers.call(this,e,l),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((b.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,u),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],u=n.delegateCount,l=e.target;if(u&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!=this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(o=[],a=0;u>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?b(r,this).index(l)>=0:b.find(r,this,null,[l]).length),o[r]&&o.push(i);o.length&&s.push({elem:l,handlers:o})}return n.length>u&&s.push({elem:this,handlers:n.slice(u)}),s},fix:function(e){if(e[b.expando])return e;var t,n,r,i=e.type,a=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new b.Event(a),t=r.length;while(t--)n=r[t],e[n]=a[n];return e.target||(e.target=a.srcElement||o),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,a):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,a,s=n.button,u=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||o,a=i.documentElement,r=i.body,e.pageX=n.clientX+(a&&a.scrollLeft||r&&r.scrollLeft||0)-(a&&a.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(a&&a.scrollTop||r&&r.scrollTop||0)-(a&&a.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&u&&(e.relatedTarget=u===e.target?n.toElement:u),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},click:{trigger:function(){return b.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t}},focus:{trigger:function(){if(this!==o.activeElement&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===o.activeElement&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=b.extend(new b.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?b.event.trigger(i,null,t):b.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},b.removeEvent=o.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},b.Event=function(e,n){return this instanceof b.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&b.extend(this,n),this.timeStamp=e&&e.timeStamp||b.now(),this[b.expando]=!0,t):new b.Event(e,n)},b.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},b.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){b.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj; -return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>i.cacheLength&&delete e[t.shift()],e[n]=r}}function ot(e){return e[x]=!0,e}function at(e){var t=p.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}}function st(e,t,n,r){var i,o,a,s,u,l,f,g,m,v;if((t?t.ownerDocument||t:w)!==p&&c(t),t=t||p,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(!d&&!r){if(i=J.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&y(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return H.apply(n,q.call(t.getElementsByTagName(e),0)),n;if((a=i[3])&&T.getByClassName&&t.getElementsByClassName)return H.apply(n,q.call(t.getElementsByClassName(a),0)),n}if(T.qsa&&!h.test(e)){if(f=!0,g=x,m=t,v=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){l=ft(e),(f=t.getAttribute("id"))?g=f.replace(K,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=l.length;while(u--)l[u]=g+dt(l[u]);m=V.test(e)&&t.parentNode||t,v=l.join(",")}if(v)try{return H.apply(n,q.call(m.querySelectorAll(v),0)),n}catch(b){}finally{f||t.removeAttribute("id")}}}return wt(e.replace(W,"$1"),t,n,r)}a=st.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},c=st.setDocument=function(e){var n=e?e.ownerDocument||e:w;return n!==p&&9===n.nodeType&&n.documentElement?(p=n,f=n.documentElement,d=a(n),T.tagNameNoComments=at(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),T.attributes=at(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),T.getByClassName=at(function(e){return e.innerHTML="",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),T.getByName=at(function(e){e.id=x+0,e.innerHTML="
      ",f.insertBefore(e,f.firstChild);var t=n.getElementsByName&&n.getElementsByName(x).length===2+n.getElementsByName(x+0).length;return T.getIdNotName=!n.getElementById(x),f.removeChild(e),t}),i.attrHandle=at(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==A&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},T.getIdNotName?(i.find.ID=function(e,t){if(typeof t.getElementById!==A&&!d){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){return e.getAttribute("id")===t}}):(i.find.ID=function(e,n){if(typeof n.getElementById!==A&&!d){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==A&&r.getAttributeNode("id").value===e?[r]:t:[]}},i.filter.ID=function(e){var t=e.replace(et,tt);return function(e){var n=typeof e.getAttributeNode!==A&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=T.tagNameNoComments?function(e,n){return typeof n.getElementsByTagName!==A?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.NAME=T.getByName&&function(e,n){return typeof n.getElementsByName!==A?n.getElementsByName(name):t},i.find.CLASS=T.getByClassName&&function(e,n){return typeof n.getElementsByClassName===A||d?t:n.getElementsByClassName(e)},g=[],h=[":focus"],(T.qsa=rt(n.querySelectorAll))&&(at(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||h.push("\\["+_+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){e.innerHTML="",e.querySelectorAll("[i^='']").length&&h.push("[*^$]="+_+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(T.matchesSelector=rt(m=f.matchesSelector||f.mozMatchesSelector||f.webkitMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){T.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",R)}),h=RegExp(h.join("|")),g=RegExp(g.join("|")),y=rt(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},v=f.compareDocumentPosition?function(e,t){var r;return e===t?(u=!0,0):(r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t))?1&r||e.parentNode&&11===e.parentNode.nodeType?e===n||y(w,e)?-1:t===n||y(w,t)?1:0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return u=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:0;if(o===a)return ut(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?ut(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},u=!1,[0,0].sort(v),T.detectDuplicates=u,p):p},st.matches=function(e,t){return st(e,null,null,t)},st.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Z,"='$1']"),!(!T.matchesSelector||d||g&&g.test(t)||h.test(t)))try{var n=m.call(e,t);if(n||T.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return st(t,p,null,[e]).length>0},st.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},st.attr=function(e,t){var n;return(e.ownerDocument||e)!==p&&c(e),d||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):d||T.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},st.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},st.uniqueSort=function(e){var t,n=[],r=1,i=0;if(u=!T.detectDuplicates,e.sort(v),u){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e};function ut(e,t){var n=t&&e,r=n&&(~t.sourceIndex||j)-(~e.sourceIndex||j);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function lt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ct(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function pt(e){return ot(function(t){return t=+t,ot(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}o=st.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=st.selectors={cacheLength:50,createPseudo:ot,match:U,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(et,tt),e[3]=(e[4]||e[5]||"").replace(et,tt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||st.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&st.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return U.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&z.test(n)&&(t=ft(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(et,tt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[e+" "];return t||(t=RegExp("(^|"+_+")"+e+"("+_+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==A&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=st.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[x]||(m[x]={}),l=c[e]||[],d=l[0]===N&&l[1],f=l[0]===N&&l[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[N,d,f];break}}else if(v&&(l=(t[x]||(t[x]={}))[e])&&l[0]===N)f=l[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[x]||(p[x]={}))[e]=[N,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||st.error("unsupported pseudo: "+e);return r[x]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?ot(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=M.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:ot(function(e){var t=[],n=[],r=s(e.replace(W,"$1"));return r[x]?ot(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:ot(function(e){return function(t){return st(e,t).length>0}}),contains:ot(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:ot(function(e){return X.test(e||"")||st.error("unsupported lang: "+e),e=e.replace(et,tt).toLowerCase(),function(t){var n;do if(n=d?t.getAttribute("xml:lang")||t.getAttribute("lang"):t.lang)return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return Q.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:pt(function(){return[0]}),last:pt(function(e,t){return[t-1]}),eq:pt(function(e,t,n){return[0>n?n+t:n]}),even:pt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:pt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:pt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:pt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[n]=lt(n);for(n in{submit:!0,reset:!0})i.pseudos[n]=ct(n);function ft(e,t){var n,r,o,a,s,u,l,c=E[e+" "];if(c)return t?0:c.slice(0);s=e,u=[],l=i.preFilter;while(s){(!n||(r=$.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),u.push(o=[])),n=!1,(r=I.exec(s))&&(n=r.shift(),o.push({value:n,type:r[0].replace(W," ")}),s=s.slice(n.length));for(a in i.filter)!(r=U[a].exec(s))||l[a]&&!(r=l[a](r))||(n=r.shift(),o.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?st.error(e):E(e,u).slice(0)}function dt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function ht(e,t,n){var i=t.dir,o=n&&"parentNode"===i,a=C++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,s){var u,l,c,p=N+" "+a;if(s){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[x]||(t[x]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,s)||r,l[1]===!0)return!0}}function gt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function mt(e,t,n,r,i){var o,a=[],s=0,u=e.length,l=null!=t;for(;u>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),l&&t.push(s));return a}function yt(e,t,n,r,i,o){return r&&!r[x]&&(r=yt(r)),i&&!i[x]&&(i=yt(i,o)),ot(function(o,a,s,u){var l,c,p,f=[],d=[],h=a.length,g=o||xt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:mt(g,f,e,s,u),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,u),r){l=mt(y,d),r(l,[],s,u),c=l.length;while(c--)(p=l[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?M.call(o,p):f[c])>-1&&(o[l]=!(a[l]=p))}}else y=mt(y===a?y.splice(h,y.length):y),i?i(null,a,y,u):H.apply(a,y)})}function vt(e){var t,n,r,o=e.length,a=i.relative[e[0].type],s=a||i.relative[" "],u=a?1:0,c=ht(function(e){return e===t},s,!0),p=ht(function(e){return M.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>u;u++)if(n=i.relative[e[u].type])f=[ht(gt(f),n)];else{if(n=i.filter[e[u].type].apply(null,e[u].matches),n[x]){for(r=++u;o>r;r++)if(i.relative[e[r].type])break;return yt(u>1&>(f),u>1&&dt(e.slice(0,u-1)).replace(W,"$1"),n,r>u&&vt(e.slice(u,r)),o>r&&vt(e=e.slice(r)),o>r&&dt(e))}f.push(n)}return gt(f)}function bt(e,t){var n=0,o=t.length>0,a=e.length>0,s=function(s,u,c,f,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,T=l,C=s||a&&i.find.TAG("*",d&&u.parentNode||u),k=N+=null==T?1:Math.random()||.1;for(w&&(l=u!==p&&u,r=n);null!=(h=C[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,u,c)){f.push(h);break}w&&(N=k,r=++n)}o&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,o&&b!==v){g=0;while(m=t[g++])m(x,y,u,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=L.call(f));y=mt(y)}H.apply(f,y),w&&!s&&y.length>0&&v+t.length>1&&st.uniqueSort(f)}return w&&(N=k,l=T),x};return o?ot(s):s}s=st.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=ft(e)),n=t.length;while(n--)o=vt(t[n]),o[x]?r.push(o):i.push(o);o=S(e,bt(i,r))}return o};function xt(e,t,n){var r=0,i=t.length;for(;i>r;r++)st(e,t[r],n);return n}function wt(e,t,n,r){var o,a,u,l,c,p=ft(e);if(!r&&1===p.length){if(a=p[0]=p[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&!d&&i.relative[a[1].type]){if(t=i.find.ID(u.matches[0].replace(et,tt),t)[0],!t)return n;e=e.slice(a.shift().value.length)}o=U.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],i.relative[l=u.type])break;if((c=i.find[l])&&(r=c(u.matches[0].replace(et,tt),V.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=r.length&&dt(a),!e)return H.apply(n,q.call(r,0)),n;break}}}return s(e,p)(r,t,d,n,V.test(e)),n}i.pseudos.nth=i.pseudos.eq;function Tt(){}i.filters=Tt.prototype=i.pseudos,i.setFilters=new Tt,c(),st.attr=b.attr,b.find=st,b.expr=st.selectors,b.expr[":"]=b.expr.pseudos,b.unique=st.uniqueSort,b.text=st.getText,b.isXMLDoc=st.isXML,b.contains=st.contains}(e);var at=/Until$/,st=/^(?:parents|prev(?:Until|All))/,ut=/^.[^:#\[\.,]*$/,lt=b.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};b.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return r=this,this.pushStack(b(e).filter(function(){for(t=0;i>t;t++)if(b.contains(r[t],this))return!0}));for(n=[],t=0;i>t;t++)b.find(e,this[t],n);return n=this.pushStack(i>1?b.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t,n=b(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(b.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1))},filter:function(e){return this.pushStack(ft(this,e,!0))},is:function(e){return!!e&&("string"==typeof e?lt.test(e)?b(e,this.context).index(this[0])>=0:b.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],a=lt.test(e)||"string"!=typeof e?b(e,t||this.context):0;for(;i>r;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&11!==n.nodeType){if(a?a.index(n)>-1:b.find.matchesSelector(n,e)){o.push(n);break}n=n.parentNode}}return this.pushStack(o.length>1?b.unique(o):o)},index:function(e){return e?"string"==typeof e?b.inArray(this[0],b(e)):b.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?b(e,t):b.makeArray(e&&e.nodeType?[e]:e),r=b.merge(this.get(),n);return this.pushStack(b.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),b.fn.andSelf=b.fn.addBack;function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}b.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return b.dir(e,"parentNode")},parentsUntil:function(e,t,n){return b.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return b.dir(e,"nextSibling")},prevAll:function(e){return b.dir(e,"previousSibling")},nextUntil:function(e,t,n){return b.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return b.dir(e,"previousSibling",n)},siblings:function(e){return b.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return b.sibling(e.firstChild)},contents:function(e){return b.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:b.merge([],e.childNodes)}},function(e,t){b.fn[e]=function(n,r){var i=b.map(this,t,n);return at.test(e)||(r=n),r&&"string"==typeof r&&(i=b.filter(r,i)),i=this.length>1&&!ct[e]?b.unique(i):i,this.length>1&&st.test(e)&&(i=i.reverse()),this.pushStack(i)}}),b.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?b.find.matchesSelector(t[0],e)?[t[0]]:[]:b.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!b(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(t=t||0,b.isFunction(t))return b.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return b.grep(e,function(e){return e===t===n});if("string"==typeof t){var r=b.grep(e,function(e){return 1===e.nodeType});if(ut.test(t))return b.filter(t,r,!n);t=b.filter(t,r)}return b.grep(e,function(e){return b.inArray(e,t)>=0===n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
      ","
      "],area:[1,"",""],param:[1,"",""],thead:[1,"","
      "],tr:[2,"","
      "],col:[2,"","
      "],td:[3,"","
      "],_default:b.support.htmlSerialize?[0,"",""]:[1,"X
      ","
      "]},jt=dt(o),Dt=jt.appendChild(o.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,b.fn.extend({text:function(e){return b.access(this,function(e){return e===t?b.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(b.isFunction(e))return this.each(function(t){b(this).wrapAll(e.call(this,t))});if(this[0]){var t=b(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return b.isFunction(e)?this.each(function(t){b(this).wrapInner(e.call(this,t))}):this.each(function(){var t=b(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=b.isFunction(e);return this.each(function(n){b(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){b.nodeName(this,"body")||b(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&this.insertBefore(e,this.firstChild)})},before:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,!1,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=0;for(;null!=(n=this[r]);r++)(!e||b.filter(e,[n]).length>0)&&(t||1!==n.nodeType||b.cleanData(Ot(n)),n.parentNode&&(t&&b.contains(n.ownerDocument,n)&&Mt(Ot(n,"script")),n.parentNode.removeChild(n)));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&b.cleanData(Ot(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&b.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return b.clone(this,e,t)})},html:function(e){return b.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!b.support.htmlSerialize&&mt.test(e)||!b.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(b.cleanData(Ot(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){var t=b.isFunction(e);return t||"string"==typeof e||(e=b(e).not(this).detach()),this.domManip([e],!0,function(e){var t=this.nextSibling,n=this.parentNode;n&&(b(this).remove(),n.insertBefore(e,t))})},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=f.apply([],e);var i,o,a,s,u,l,c=0,p=this.length,d=this,h=p-1,g=e[0],m=b.isFunction(g);if(m||!(1>=p||"string"!=typeof g||b.support.checkClone)&&Ct.test(g))return this.each(function(i){var o=d.eq(i);m&&(e[0]=g.call(this,i,n?o.html():t)),o.domManip(e,n,r)});if(p&&(l=b.buildFragment(e,this[0].ownerDocument,!1,this),i=l.firstChild,1===l.childNodes.length&&(l=i),i)){for(n=n&&b.nodeName(i,"tr"),s=b.map(Ot(l,"script"),Ht),a=s.length;p>c;c++)o=l,c!==h&&(o=b.clone(o,!0,!0),a&&b.merge(s,Ot(o,"script"))),r.call(n&&b.nodeName(this[c],"table")?Lt(this[c],"tbody"):this[c],o,c);if(a)for(u=s[s.length-1].ownerDocument,b.map(s,qt),c=0;a>c;c++)o=s[c],kt.test(o.type||"")&&!b._data(o,"globalEval")&&b.contains(u,o)&&(o.src?b.ajax({url:o.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):b.globalEval((o.text||o.textContent||o.innerHTML||"").replace(St,"")));l=i=null}return this}});function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function Ht(e){var t=e.getAttributeNode("type");return e.type=(t&&t.specified)+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function Mt(e,t){var n,r=0;for(;null!=(n=e[r]);r++)b._data(n,"globalEval",!t||b._data(t[r],"globalEval"))}function _t(e,t){if(1===t.nodeType&&b.hasData(e)){var n,r,i,o=b._data(e),a=b._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)b.event.add(t,n,s[n][r])}a.data&&(a.data=b.extend({},a.data))}}function Ft(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!b.support.noCloneEvent&&t[b.expando]){i=b._data(t);for(r in i.events)b.removeEvent(t,r,i.handle);t.removeAttribute(b.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),b.support.html5Clone&&e.innerHTML&&!b.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Nt.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}b.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){b.fn[e]=function(e){var n,r=0,i=[],o=b(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),b(o[r])[t](n),d.apply(i,n.get());return this.pushStack(i)}});function Ot(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||b.nodeName(o,n)?s.push(o):b.merge(s,Ot(o,n));return n===t||n&&b.nodeName(e,n)?b.merge([e],s):s}function Bt(e){Nt.test(e.type)&&(e.defaultChecked=e.checked)}b.extend({clone:function(e,t,n){var r,i,o,a,s,u=b.contains(e.ownerDocument,e);if(b.support.html5Clone||b.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(b.support.noCloneEvent&&b.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||b.isXMLDoc(e)))for(r=Ot(o),s=Ot(e),a=0;null!=(i=s[a]);++a)r[a]&&Ft(i,r[a]);if(t)if(n)for(s=s||Ot(e),r=r||Ot(o),a=0;null!=(i=s[a]);a++)_t(i,r[a]);else _t(e,o);return r=Ot(o,"script"),r.length>0&&Mt(r,!u&&Ot(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,u,l,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===b.type(o))b.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),u=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[u]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!b.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!b.support.tbody){o="table"!==u||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)b.nodeName(l=o.childNodes[i],"tbody")&&!l.childNodes.length&&o.removeChild(l) -}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function un(e){var t=o,n=Gt[e];return n||(n=ln(e,t),"none"!==n&&n||(Pt=(Pt||b("