UNPKG

iobroker.vis

Version:

Graphical user interface for iobroker.

3,125 lines 167 kB
<link rel="stylesheet" type="text/css" href="widgets/basic/css/table.css" />
<script type="text/javascript" src="widgets/basic/js/table.js"></script>

<script type="text/javascript">
    'use strict';

    if (vis.editMode) {
        // Add words for basic widgets
        $.extend(true, systemDictionary, {
            // Bars
            "src":              {"en": "Source",                    "de": "Quelle",                 "ru": "Адрес"},
            "refreshInterval":  {"en": "Refresh interval(ms)",      "de": "Updatezeit(ms)",         "ru": "Интервал обновления(ms)"},
            "is_comma":         {"en": "Divider comma",             "de": "Komme als Trennung",     "ru": "Запятая-разделитель"},
            "is_tdp":           {"en": "Use thousands separator",  "de": "Tausender Trennzeichen",  "ru": "Use thousands separator"},
            "digits":           {"en": "Digits after comma",        "de": "Zeichen nach Komma",     "ru": "Знаков после запятой"},
            "oid":              {"en": "Object ID",                 "de": "Object ID",              "ru": "ID Объекта"},
            "html_prepend":     {"en": "Prepend value",             "de": "Voranstellen HTML",      "ru": "Префикс значения"},
            "html_append":      {"en": "Append to value",           "de": "HTML anhängen",          "ru": "Суффикс значения"},
            "html_append_singular": {
                "en": "Append to value (Singular)",
                "de": "HTML anhängen (Singulär)",
                "ru": "Суффикс значения(един.ч.)"
            },
            "html_append_plural": {
                "en": "Append to value (Plural)",
                "de": "HTML anhängen(Plüral)",
                "ru": "Суффикс значения(множ.ч.)"
            },
            "html_prepend_tooltip":    {
                "en": "Write HTML code here that will be placed before,\x0Ae.g. <b> ",
                "de": "HTML Kod, der wird vom dem Wert platziert,\x0Az.B. <b>",
                "ru": "HTML код будет помещён перед значением,\x0Aнапример <b>"
            },
            "html_append_tooltip":     {
                "en": "Write HTML code here that will be placed before,\x0Ae.g. </b>",
                "de": "HTML Kod, der wird vom dem Wert platziert,\x0Az.B. </b>",
                "ru": "HTML код будет помещён после значения,\x0Aнапример </b>"
            },
            "stretch":          {"en": "Stretch",                   "de": "Strecken",               "ru": "Растянуть"},
            "factor":           {"en": "Multiplex factor",          "de": "Multiplikation",         "ru": "Множитеть"},
            "class_true":       {"en": "Class if quality 'true'",   "de": "Klasse bei Qualität 'true'", "ru": "Класс, если качество 'true'"},
            "class_false":      {"en": "Class if quality 'false'",  "de": "Klasse bei Qualität 'false'", "ru": "Класс, если качество 'false'"},
            "test_html":        {"en": "Text for test",             "de": "Testtext",               "ru": "Тестовый текст"},
            "test_html_tooltip": {
                "en": "You can specify the test text if value is now empty to visualise settings.\x0AIt is valid only during edit.",
                "de": "Man kann noch Testtext setzen um die Einstellungen visuell zu sehen.\x0ADas ist nur während Edit gültig.",
                "ru": "Можно задать тестовый текст, что бы видеть настройки визуально.\x0AОн действителен только во время редактирования."
            },
            "html":             {"en": "HTML",                      "de": "HTML",                   "ru": "HTML"},
            "oid-quality":      {"en": "Quality ID",                "de": "Qualität ID",            "ru": "ID-Качество"},
            "oid-quality_tooltip":     {
                "en": "You can set additionally Quality ID to indicate if the value valid or not.",
                "de": "Man kann noch zusätzlich Qualität ID setzetn um zu zeigen ob das Wert aktuell ist.",
                "ru": "Можно дополнительно установить ID-Качества, что бы показать актуальное значение или нет."},
            "title":            {"en": "Title",                     "de": "Titel",                  "ru": "Заголовок"},
            "title_font":       {"en": "Title font name",           "de": "Titelschriftname",       "ru": "Шрифт заголовка"},
            "title_color":      {"en": "Title color",               "de": "Titelfarbe",             "ru": "Цвет заголовка"},
            "title_back":       {"en": "Title backg. color",        "de": "Titelhintergrund",       "ru": "Цвет фона текста"},
            "title_top":        {"en": "Title top padding",         "de": "Titel-Oben-Abstand",     "ru": "Отступ заголовка сверху"},
            "title_left":       {"en": "Title left padding",        "de": "Titel-Links-Abstand",    "ru": "Отступ заголовка слева"},
            "header_height":    {"en": "Header height",             "de": "Kopfhöhe",               "ru": "Высота заголовока"},
            "header_color":     {"en": "Header color",              "de": "Kopffarbe",              "ru": "Цвет фона заголовка"},
            "refreshOnWakeUp":  {"en": "Refresh on wake up",        "de": "Update bei Aufwachen",   "ru": "Обновлять при выходе из сна"},
            "refreshOnViewChange": {"en": "Refresh on view change", "de": "Update bei Viewwechsel", "ru": "Обновлять при смене страницы"},
            "refreshWithNoQuery": {"en": "Do not add anything to URL", "de": "Addiere nichst zu URL", "ru": "Ничего не добавлять к URL"},
            "src_":             {"en": "URL, by value=",            "de": "URL falls Wert=",        "ru": "Адрес при значении "},
            "nav_view":         {"en": "View to navigate",          "de": "View zum Navigieren",    "ru": "Перейти на страницу"},
            "group_effects":    {"en": "Show/Hide Effects",         "de": "Anzeige Effekte",        "ru": "Эффекты появления/исчезновения"},
            "group_extended":   {"en": "Extended settings",         "de": "Erweiterte Eistellungen", "ru": "Расширенные настройки"},
            "body-background":  {"en": "Background color by changing", "de": "Hintegrund by Wechsel", "ru": "Фон при смене страниц"},
            "sync":             {"en": "Hide and show together:",   "de": "Anzeigen und verbergen gleichzeitig", "ru": "Появления и исчезновение вместе"},
            // Effects
            "show":             {"en": "show",                      "de": "show",                   "ru": "show"},
            "blind":            {"en": "blind",                     "de": "blind",                  "ru": "blind"},
            "bounce":           {"en": "bounce",                    "de": "bounce",                 "ru": "bounce"},
            "clip":             {"en": "clip",                      "de": "clip",                   "ru": "clip"},
            "drop":             {"en": "drop",                      "de": "drop",                   "ru": "drop"},
            "explode":          {"en": "explode",                   "de": "explode",                "ru": "explode"},
            "fade":             {"en": "fade",                      "de": "fade",                   "ru": "fade"},
            "fold":             {"en": "fold",                      "de": "fold",                   "ru": "fold"},
            "highlight":        {"en": "highlight",                 "de": "highlight",              "ru": "highlight"},
            "puff":             {"en": "puff",                      "de": "puff",                   "ru": "puff"},
            "pulsate":          {"en": "pulsate",                   "de": "pulsate",                "ru": "pulsate"},
            "scale":            {"en": "scale",                     "de": "scale",                  "ru": "scale"},
            "shake":            {"en": "shake",                     "de": "shake",                  "ru": "shake"},
            "size":             {"en": "size",                      "de": "size",                   "ru": "size"},
            "slide":            {"en": "slide",                     "de": "slide",                  "ru": "slide"},
            "is_milliseconds":  {"en": "Milliseconds",              "de": "Millisekunden",          "ru": "Миллисекунды"},
            "is_milliseconds_tooltip": {
                "en": "Is object is milliseconds from 1970.01.01 00:00:00. Normally no.",
                "de": "Ob das Wert die Milleskunden seit 1970.01.01 00:00:00 ist. Normalerweise nicht.",
                "ru": "Является ли значение объекта миллисекундами с 1970.01.01 00:00:00. Обычно нет."
            },
            "format_date":      {"en": "Dateformat",                "de": "Datumformat",            "ru": "Формат даты"},
            "format_date_tooltip": {
                "en": "Dateformat",
                "de": "Datumformat",
                "ru": "Формат даты"
            },
            "show_interval":    {"en": "As interval",               "de": "Als Intervall",          "ru": "Как интервал"},
            "hide_effect":      {"en": "Hide effect",               "de": "Verbergeneffekt",        "ru": "Эффект скрытия"},
            "hide_duration":    {"en": "Hide duration(ms)",         "de": "Verbergendauer",         "ru": "Длительность скрытия(мс)"},
            "hide_options":     {"en": "Hide options",              "de": "Verbergenoptionen",      "ru": "Опции скрытия"},
            "show_effect":      {"en": "Show effect",               "de": "Anzeigeeffekt",          "ru": "Эффект появления"},
            "show_duration":    {"en": "Show duration(ms)",         "de": "Anzeigedauer",           "ru": "Длительность появления(мс)"},
            "show_options":     {"en": "Show options",              "de": "Anzeigeoptionen",        "ru": "Опции появления"},
            "left":             {"en": "left",                      "de": "links",                  "ru": "лево"},
            "right":            {"en": "right",                     "de": "rechts",                 "ru": "право"},
            "top":              {"en": "top",                       "de": "oben",                   "ru": "верх"},
            "bottom":           {"en": "bottom",                    "de": "unten",                  "ru": "низ"},

            "contains_view":    {"en": "Contains view",             "de": "Viewname",               "ru": "Имя страницы"},
            "persistent":       {"en": "Persistent",                "de": "Bleibend",               "ru": "Постоянно"},
            "persistent_tooltip": {
                "en": "If persistent the view will not be destroyed when inactive, just hide.\nElsewise the view will be destroyed, if inactive.",
                "de": "Falls 'Bleibend', dann wird die View nicht zerstört, sondern nur versteckt wenn inaktive. Sonst wird die View immer wieder kreiert und zerstört.",
                "ru": "Если выбранно 'Постоянно', то страница не будет уничтожаться, если она не активна. В противном случае страница будет создаваться и разрушаться."},
            "notIfInvisible":       {"en": "Only if visible",                "de": "Nur falls sichtbar",               "ru": "Только если видимо"},
            "notIfInvisible_tooltip": {
                "en": "View will be used only if this widget is visible",
                "de": "Die View wird nur benutzt, wenn dieses Widget sichtbar ist",
                "ru": "Страница будет использоваться только в том случае, если виден этот виджет"
            },
            "valuelist":        {"en": "Values list",               "de": "Wertenliste",            "ru": "Список значений"},
            "valuelist_tooltip": {
                "en": "Divide values with semicolon, like 'ok;warning;alram'. Every text accordingly for value 0,1,2 and so on\nTo have ';' in text use §§ instead.",
                "de": "Die Werte mit Semikolon trennen, wie 'ok;Warnung;Alarm'. Jeder Text ist entsprechend für das Wert 0,1,2 usw.\nUm ';' im Text zu haben, schrein '§§'.",
                "ru": "Разделять значения точкой запятой, например 'ok;Внимание;Тревога'. Каждый текст соответственно для значения 0,1,2 итд.\nДля написания ';' в тексте используй '§§'."
            },
            "html_false":       {"en": "HTML by 'false'",           "de": "HTML bei 'false'",       "ru": "HTML если 0"},
            "html_true":        {"en": "HTML by 'true'",            "de": "HTML bei 'true'",        "ru": "HTML если 1"},
            "text_false":       {"en": "Text by 'false'",           "de": "Text bei 'false'",       "ru": "Текст если 0"},
            "text_true":        {"en": "Text by 'true'",            "de": "Text bei 'true'",        "ru": "Текст если 1"},
            "svg_false":        {"en": "SVG by 'false'",            "de": "SVG bei 'false'",        "ru": "SVG если 0"},
            "svg_true":         {"en": "SVG by 'true'",             "de": "SVG bei 'true'",         "ru": "SVG если 1"},
            "svg_opacity":      {"en": "Opacity",                   "de": "Durchsichtigkeit",       "ru": "Прозрачность"},
            "html_closed":      {"en": "HTML by 'closed'",          "de": "HTML bei 'zu'",          "ru": "HTML если закрыто"},
            "html_open":        {"en": "HTML by 'open'",            "de": "HTML bei 'auf'",         "ru": "HTML если открыто"},
            "html_tilt":        {"en": "HTML by 'tilted'",          "de": "HTML bei 'gekippt'",     "ru": "HTML если наклоненно"},
            "html_tilt_tooltip": {
                "en": "0 - Closed, 1 - tilt, 2 - open",
                "de": "0- Zu, 1 - gekippt, 2 - auf",
                "ru": "0 - закрыто, 1 - откинуто, 2 - открыто"
            },
            "color":            {"en": "Color",                     "de": "Farbe",                  "ru": "Цвет"},
            "shadow":           {"en": "Opacity",                   "de": "Durchsichtigkeit",       "ru": "Тень"},
            "shadow_tooltip":   {
                "en": "CSS Shadow, like '10px 10px 5px #888888'",
                "de": "CSS Shatten, wie '10px 10px 5px #888888'",
                "ru": "CSS Тень, как '10px 10px 5px #888888'"
            },
            "reverse":          {"en": "Revers value",              "de": "Wert umkehren",          "ru": "Перевернуть значение"},
            "border":           {"en": "Border",                    "de": "Rand",                   "ru": "Окантовка"},
            "border_tooltip":   {
                "en": "CSS border, like 'green 5px solid'",
                "de": "CSS Rand, wie 'green 5px solid'",
                "ru": "CSS бордюр, как 'green 5px solid'"
            },
            "test_text":        {"en": "Test text",                 "de": "Testtext",               "ru": "Тестовый текст"},
            "max_width":        {"en": "Max. width",                "de": "Maximale Breite",        "ru": "Максимальная ширина"},
            "style":            {"en": "Style for ",                "de": "Stil für ",              "ru": "Стиль для "},
            "style_tooltip":    {
                "en": "Write here css style, like: 'color:red;background:white'",
                "de": "Hier muss CSS Stil stehen, wie 'color:red;background:white'",
                "ru": "CSS Стиль, например: 'color:red;background:white'"},
            "count":            {"en": "Values number to",          "de": "Wertsanzahl bis",        "ru": "Количество значений до"},
            "test_list":        {"en": "Test value",                "de": "Testwert",               "ru": "Тестовое значение"},
            "urlValue":         {"en": "Call URL on click",         "de": "Rufe URL bei click",     "ru": "Вызвать URL при нажатии"},
            "group_ccontrol":   {"en": "Advanced control",          "de": "Extrasteuerung",         "ru": "Продвинутое управление"},
            "urlFalse":         {"en": "URL on false",              "de": "URL bei false",          "ru": "URL при false"},
            "urlTrue":          {"en": "URL on true",               "de": "URL bei true",           "ru": "URL при true"},
            "oidFalse":         {"en": "Object ID on false",        "de": "Objekt ID bei false",    "ru": "ID объекта при false"},
            "oidTrue":          {"en": "Object ID on true",         "de": "Objekt ID bei true",     "ru": "ID объекта при true"},
            "oidTrueValue":     {"en": "Value for OÍD on true",     "de": "Wert für ID bei false",  "ru": "Значение для ID при false"},
            "oidFalseValue":    {"en": "Value for OÍD on false",    "de": "Wert für ID bei true",   "ru": "Значение для ID при true"},
            "square":           {"en": "square",                    "de": "square",                 "ru": "квадрат"},
            "pentagone":        {"en": "pentagone",                 "de": "pentagone",              "ru": "Пятиуголник"},
            "hexagone":         {"en": "hexagone",                  "de": "hexagone",               "ru": "Шестиугольник"},
            "octagone":         {"en": "octagone",                  "de": "octagone",               "ru": "Восьмиугольник"},
            "circle":           {"en": "circle",                    "de": "Kreis",                  "ru": "Круг"},
            "svgType":          {"en": "Type",                      "de": "Typ",                    "ru": "Тип"},
            "strokeColor":      {"en": "Stroke color",              "de": "Liniefarbe",             "ru": "Цвет линии"},
            "fill":             {"en": "Fill color",                "de": "Füllfarbe",              "ru": "Цвет заливки"},
            "strokeWidth":      {"en": "Stroke width",              "de": "Liniebreite",            "ru": "Ширина линии"},
            "rotate":           {"en": "Rotate",                    "de": "Drehen",                 "ru": "Повернуть на"},
            "no_control":       {"en": "Read only",                 "de": "Nur Anzeige",            "ru": "Только показывать"},
            "numeric":          {"en": "Number",                    "de": "Nummer",                 "ru": "Число"},
            "autoSet":          {"en": "Auto set",                  "de": "Auto-setzen",            "ru": "Авто запись"},
            "autoSet_tooltip":  {
                "en": "Without 'Auto set' you must press ENTER,\x0ato write the value.",
                "de": "Ohne 'Auto-setzen' man muss danach ENTER drucken,\x0A um das Wert zu schreiben.",
                "ru": "Без 'Авто записи' нужно нажать ENTER,\x0Aчто бы записать значение."
            },
            "group_views":      {"en": "Views",                     "de": "Views",                  "ru": "Страницы"},
            "group_frames":     {"en": "iFrames",                   "de": "iFrames",                "ru": "iFrames"},
            "horizontal":       {"en": "horizontal",                "de": "horizontal",             "ru": "горизонтально"},
            "vertical":         {"en": "vertical",                  "de": "senkrecht",              "ru": "вертикально"},
            "orientation":      {"en": "Orientation",               "de": "Ausrichtung ",           "ru": "Направление"},
            "noSandbox":        {"en": "No sandbox",                "de": "Kein Sandkasten",        "ru": "Не запускать в песочнице"},
            "scrollX":          {"en": "Scroll X",                  "de": "Scroll X",               "ru": "Scroll X"},
            "scrollY":          {"en": "Scroll Y",                  "de": "Scroll Y",               "ru": "Scroll Y"},
            "seamless":         {"en": "Seamless",                  "de": "Kein Rahmen",            "ru": "Без рамки"},
            "filters":          {"en": "Filters",                   "de": "Filter",                 "ru": "Фильтры"},
            "filters_Tooltip":  {
                "en": "Divided by semicolon,\x0Ae.g: light;control",
                "de": "Geteilt mir Semikolon\x0Az.B.: Licht;Steuerung",
                "ru": "Разделять точкой запятой\x0Aнапример: Свет;Управление"
            },
            "Select ID":        {"en": "Select ID",                 "de": "ID auswählen",           "ru": "Выбрать ID"},
            "redirect_url":     {"en": "Redirect URL",              "de": "Weiterleiten nach Logout", "ru": "Перейти на URL после выхода"},
            "in_app_close":     {"en": "Close mobile APP",          "de": "Mobiles APP schliessen", "ru": "Закрыть мобильное приложение"},
            "en-US":            {"en": "english",                   "de": "Englisch",               "ru": "английский"},
            "ru-RU":            {"en": "russian",                   "de": "Russisch",               "ru": "русский"},
            "continuous":       {"en": "Continuous",                "de": "Immer zuhören",          "ru": "Непрерывно"},
            "keywords":         {"en": "Keywords",                  "de": "Schlüsselworte",         "ru": "Ключевые слова"},
            "noImage":          {"en": "No image",                  "de": "Kein Bild",              "ru": "Без картинки"},
            "imageInactive":    {"en": "Inactive",                  "de": "Inaktiv",                "ru": "Не активно"},
            "imageActive":      {"en": "Active",                    "de": "Aktiv",                  "ru": "Активно"},
            "imageStarted":     {"en": "Started",                   "de": "Gestartet",              "ru": "Запущено"},
            "imageDetected":    {"en": "Detected",                  "de": "Gefunden",               "ru": "Обнаружено"},
            "imageSent":        {"en": "Sent",                      "de": "Gesedet",                "ru": "Отослано"},
            "imageHeightPx":    {"en": "Height (px)",               "de": "Höhe (px)",              "ru": "Высота (px)"},
            "imageWidthPx":     {"en": "Width (px)",                "de": "Breite (px)",            "ru": "Ширина (px)"},
            "noText":           {"en": "No help text",              "de": "Keine Hilfetext",        "ru": "Без текста помощи"},
            "noResults":        {"en": "No results",                "de": "Keine Ergebnise",        "ru": "Без результатов"},
            "keyWordColor":     {"en": "Key word color",            "de": "Schlüsselworte-Farbe",   "ru": "Цвет ключевых слов"},
            "keyWordColor_tooltip": {
                "en": "Text color, if key word found",
                "de": "Textfarbe, wenn im Text Schlüsselwort gefunden ist.",
                "ru": "Цвет текста, когда обнаружено ключевое слово"
            },
            "textSentColor":    {"en": "Text sent color",           "de": "Gesendet-Farbe",         "ru": "Цвет отосланного текста"},
            "textSentColor_tooltip": {
                "en": "Text color, when text sent to processing it",
                "de": "Textfarbe, wenn Text ist für Abarbeitung gesendet.",
                "ru": "Цвет текста, когда текст отослан на обработку"
            },
            "speechMode":       {"en": "Speech mode",               "de": "Sprachmodus",            "ru": "Режим речи"},
            "single":           {"en": "single",                    "de": "Ein mal",                "ru": "Одиночный"},
            "startstop":        {"en": "start/stop",                "de": "Start/Stop",             "ru": "Старт/стоп"},
            "line":             {"en": "line",                      "de": "Linie",                  "ru": "линия"},
            "triangle":         {"en": "triangle",                  "de": "Dreieck",                "ru": "треугольник"},
            "star":             {"en": "star",                      "de": "Stern",                  "ru": "звезда"},
            "arrow":            {"en": "arrow",                     "de": "Pfeil",                  "ru": "стрела"},
            "scaleWidth":       {"en": "Scale width",               "de": "breiten Skala",          "ru": "Масштаб по ширине"},
            "scaleHeight":      {"en": "Scale height",              "de": "höhen Skala",            "ru": "Масштаб по высоте"}
        });
    }

    $.extend(true, systemDictionary, {
        "Edit note":    {"en": "Edit note",     "de": "Meldung eingeben",   "ru": "Сообщение"},
        "Clear":        {"en": "Clear",         "de": "Löschen",            "ru": "Очистить"},
        "Ok":           {"en": "Ok",            "de": "Ok",                 "ru": "Ok"},
        "Cancel":       {"en": "Cancel",        "de": "Abbrechen",          "ru": "Отмена"},
        "all":          {"en": "all",           "de": "Alle",               "ru": "Все"},
        "just&nbsp;now":  {"en": "just&nbsp;now", "de": "gerade&nbsp;jetzt", "ru": "только&nbsp;что"},
        "for&nbsp;%s&nbsp;min.":  {"en": "for&nbsp;%s&nbsp;min.", "de": "vor&nbsp;%s&nbsp;Min.", "ru": "%s&nbsp;мин. назад"},
        "for&nbsp;%s&nbsp;hr.&nbsp;and&nbsp;%s&nbsp;min.": {
            "en": "for&nbsp;%s&nbsp;hr.&nbsp;and&nbsp;%s&nbsp;min.",
            "de": "vor&nbsp;%s&nbsp;St.&nbsp;und&nbsp;%s&nbsp;Min.",
            "ru": "%s&nbsp;часов&nbsp;и&nbsp;%s&nbsp;мин. назад"
        },
        "yesterday":              {"en": "yesterday", "de": "gestern", "ru": "вчера"},
        "for&nbsp;%s&nbsp;hours": {"en": "for&nbsp;%s&nbsp;hours", "de": "vor&nbsp;%s&nbsp;Stunden", "ru": "%s&nbsp;часов назад"},
        "click to create":        {"en": "click to create", "de": "klicken um zu erzeugen", "ru": "нажать что бы создать"},
        "This option works only in APP": {
            "en": "This option works only in APP",
            "de": "Funktioniert nur im APP",
            "ru": "Работает только в мобильном приложении"
        },
        "info_start": {
            "en": "Click on the microphone icon and begin speaking.",
            "de": "Klicken Sie das Mikrophon an und sagen Sie etwas.",
            "ru": "Нажмите на микрофон и начинайте говорить."
        },
        "info_speak_now": {
            "en": "Speak now.",
            "de": "Sage etwas.",
            "ru": "Говорите."
        },
        "info_no_speech": {
            "en": "No speech was detected. You may need to adjust your <a href=\"//support.google.com/chrome/bin/answer.py?hl=en&amp;answer=1407892\">microphone settings</a>.",
            "de": "No speech was detected. You may need to adjust your <a href=\"//support.google.com/chrome/bin/answer.py?hl=en&amp;answer=1407892\">microphone settings</a>.",
            "ru": "Речи не обнаружено. Может надо настроить микрофон <a href=\"//support.google.com/chrome/bin/answer.py?hl=en&amp;answer=1407892\">Настройки микрофона</a>."
        },
        "info_no_microphone": {
            "en": "No microphone was found. Ensure that a microphone is installed and that <a href=\"//support.google.com/chrome/bin/answer.py?hl=en&amp;answer=1407892\"> microphone settings</a> are configured correctly.",
            "de": "No microphone was found. Ensure that a microphone is installed and that <a href=\"//support.google.com/chrome/bin/answer.py?hl=en&amp;answer=1407892\"> microphone settings</a> are configured correctly.",
            "ru": "No microphone was found. Ensure that a microphone is installed and that <a href=\"//support.google.com/chrome/bin/answer.py?hl=en&amp;answer=1407892\"> microphone settings</a> are configured correctly."
        },
        "info_allow": {
            "en": "Click the \"Allow\" button above to enable your microphone.",
            "de": "Click the \"Allow\" button above to enable your microphone.",
            "ru": "Нажмите на кнопку \"разрешить\" сверху, что бы активировать микрофон."
        },
        "info_denied": {
            "en": "Permission to use microphone was denied.",
            "de": "Permission to use microphone was denied.",
            "ru": "Доступ к микрофону был запрещён."
        },
        "info_blocked": {
            "en": "Permission to use microphone is blocked. To change, go to chrome://settings/contentExceptions#media-stream",
            "de": "Permission to use microphone is blocked. To change, go to chrome://settings/contentExceptions#media-stream",
            "ru": "Доступ к микрофону блокирован. Что бы изменить настройки идите <a href=\"chrome://settings/contentExceptions#media-stream\">сюда</a>"
        },
        "info_upgrade": {
            "en": "Web Speech API is not supported by this browser. Upgrade to<a href=\"//www.google.com/chrome\">Chrome</a> version 25 or later.",
            "de": "Web Speech API is not supported by this browser. Upgrade to<a href=\"//www.google.com/chrome\">Chrome</a> version 25 or later.",
            "ru": "Web Speech API не поддерживается этим браузером. Обновите до <a href=\"//www.google.com/chrome\">Chrome</a> версии 25 или новее."
        }
    });

    vis.binds.stateful = {
        view: function (el, viewArr, persistent, notIfInvisible) {
            var $this = $(el);
            var oid   = $this.attr('data-oid');
            var timer = null;

            function draw(val) {
                timer = null;
                var view = viewArr[val];
                if (!persistent) {
                    $this.parent().find('div.vis-view').remove();
                } else {
                    $this.parent().find('div.vis-view').hide().appendTo($('#vis_container'));
                }
                if (vis.views[view]) {
                    vis.renderView(view, view, true, function (_view) {
                        var $view = $('#visview_' + _view);
                        $view.show().data('persistent', persistent);
                        if (!$this.find('#visview_' + _view).length) {
                            $view.appendTo($this);
                        }
                    });
                }
                vis.destroyUnusedViews();
            }

            function onChange(e, newVal) {
                if (newVal === 'true'  || newVal === true)  newVal = 1;
                if (newVal === 'false' || newVal === false) newVal = 0;
                if (notIfInvisible && !$this.is(':visible')) {
                    return;
                }

                if (timer) {
                    clearTimeout(timer)
                }
                timer = setTimeout(function () {
                    draw(newVal);
                }, 50);
            }

            if (oid) {
                vis.states.bind(oid + '.val', onChange);

                // remember all ids, that bound
                $this.parent().parent()
                    .data('bound', [oid + '.val'])
                    // remember bind handler
                    .data('bindHandler', onChange);
            }
        },
        iframe: function (el, srcArr, refreshInterval) {
            var $this = $(el).parent().find('iframe');
            var oid   = $this.attr('data-oid');
            refreshInterval = parseInt(refreshInterval, 10) || 0;

            function onChange (e, newVal) {
                if (newVal === 'true'  || newVal === true)  newVal = 1;
                if (newVal === 'false' || newVal === false) newVal = 0;
                $this.attr('src', srcArr[newVal]);
            }

            if (oid) {
                vis.states.bind(oid + '.val', onChange);

                // remember all ids, that bound
                $this.parent().parent()
                    .data('bound', [oid + '.val'])
                    // remember bind handler
                    .data('bindHandler', onChange);

                if (vis.states[oid + '.val'] !== undefined) {
                    var val = vis.states[oid + '.val'];
                    if (val === 'true'  || val === true)  val = 1;
                    if (val === 'false' || val === false) val = 0;
                    $this.attr('src', srcArr[val]);
                }

                if (refreshInterval > 0) {
                    setInterval(function () {
                        var val = vis.states[oid + '.val'] || 0;
                        if (val === 'true'  || val === true)  val = 1;
                        if (val === 'false' || val === false) val = 0;
                        var src = srcArr[val];
                        $this.attr('src', src + (src.match(/\?/) ? '&' : '?') + '_vis_refts=' + ((new Date()).getTime()));
                    }, refreshInterval);
                }
            }
        },
        image: function (el, srcArr, refreshInterval) {
            var $this = $(el).parent().find('img');
            var oid = $this.attr('data-oid');
            refreshInterval = parseInt(refreshInterval, 10) || 0;

            function onChange (e, newVal) {
                if (newVal === 'true'  || newVal === true)  newVal = 1;
                if (newVal === 'false' || newVal === false) newVal = 0;
                $this.attr('src', srcArr[newVal]);
            }

            if (oid) {
                vis.states.bind(oid + '.val', onChange);

                // remember all ids, that bound
                $this.parent().parent()
                    .data('bound', [oid + '.val'])
                    // remember bind handler
                    .data('bindHandler', onChange);

                if (vis.states[oid + '.val'] !== undefined) {
                    var val = vis.states[oid + '.val'];
                    if (val === 'true'  || val === true)  val = 1;
                    if (val === 'false' || val === false) val = 0;
                    $this.attr('src', srcArr[val]);
                }

                if (refreshInterval > 0) {
                    setInterval(function () {
                        var val = vis.states[oid + '.val'] || 0;
                        if (val === 'true'  || val === true)  val = 1;
                        if (val === 'false' || val === false) val = 0;

                        var src = srcArr[val];
                        if (src) $this.attr('src', src + ((src.indexOf('?') !== -1) ? '&' : '?') + '_vis_refts=' + ((new Date()).getTime()));
                    }, refreshInterval);
                }
            }

        },
        value: function (values, oid) {
            if (oid !== 'nothing_selected' && vis.states.attr(oid + '.val') !== undefined) {
                var val = vis.states.attr(oid + '.val');
                if (val === 'true'  || val === true)  val = 1;
                if (val === 'false' || val === false) val = 0;
                return values[val];
            } else {
                return values[0];
            }
        }
    };
    vis.binds.container = function (el, view) {
        var $this = $(el);
        if (vis.views[view]) {
            vis.renderView(view, view, true, function (_view) {
                $('#visview_' + _view).appendTo($this).show();
            });
        }
    };
    vis.binds.basic = {
        isFullScreen: false,
        filterDropdown: function (el, filters, hideEffect, hideDuration, showEffect, showDuration) {
            var $this = $(el);
            if (filters) {
                filters = filters.split(';');
                for (var i = 0; i < filters.length; i++) {
                    $this.find('select').append('<option value="' + filters[i] + '">' + filters[i] + '</option>');
                }
            }

            if (vis.viewsActiveFilter[vis.activeView]) {
                $this.find('select option[value="' + vis.viewsActiveFilter[vis.activeView] + '"]').attr('selected', true);
            }

            $this.find('select').change(function () {
                vis.changeFilter(null, $this.find('select option:selected').val(), hideEffect, hideDuration, showEffect, showDuration);
            });
        },
        state: function (el, oid) {
            var $this = $(el);
            oid = oid ? oid : $this.attr('data-oid');
            var val = $this.attr('data-val');

            if (oid) {
                $this.attr('data-ctrl-oid', oid);
            }

            if (val === 'true')  val = true;
            if (val === 'false') val = false;

            if (!vis.editMode) {
				var moved = false;
                $this.on('click touchend', function (e) {
                    // Protect against two events
                    if (vis.detectBounce(this)) return;

					if (moved) return;

                    var oid = $(this).attr('data-ctrl-oid');

                    if ($(this).attr('url-value')) {
                        vis.conn.httpGet($(this).attr('url-value'));
                    }

                    if (oid) {
                        var val = $(this).attr('data-val');
                        if (val === undefined || val === null) val = false;
                        if (val === 'true')  val = true;
                        if (val === 'false') val = false;
                        if (parseFloat(val).toString() == val) val = parseFloat(val);

                        if (oid) vis.setValue(oid, val);
                    }
                }).on('touchmove', function () {
					moved = true;
				}).on('touchstart', function () {
					moved = false;
				});
            }
        },
        pressed: null,
        pressedNext: null,
        increment: function (el, minmax, delay, interval) {

            function fInterval($that) {
                vis.binds.basic.pressedNext = true;
                vis.binds.basic.pressed = null;
                var oid = $that.attr('data-oid');
                if (!vis.editMode) {
                    var step = parseFloat($that.attr('data-vis-step'));
                    var tmp  = parseFloat(vis.states[oid + '.val']) + step;
                    if (step < 0) {
                        if (tmp >= minmax) {
                            vis.setValue($that.attr('data-oid'), tmp);
                            vis.binds.basic.pressed = _setTimeout(fInterval, interval, $that);
                        }
                    } else {
                        if (tmp <= minmax) {
                            vis.setValue($that.attr('data-oid'), tmp);
                            vis.binds.basic.pressed = _setTimeout(fInterval, interval, $that);
                        }
                    }
                }
            }

            function intervalStart(e) {
                vis.binds.basic.pressedNext = false;
                var $this = $(this);
                var oid = $this.attr('data-oid');

                if (vis.binds.basic.pressed) {
                    clearInterval(vis.binds.basic.pressed);
                    vis.binds.basic.pressed = null;
                }

                vis.binds.basic.pressed = setTimeout(fInterval, delay, $this);
            }

            if (!vis.editMode) {
				var moved = false;
                $(el).on('click touchend', function (e) {
                    // Protect against two events
                    if (vis.detectBounce(this)) return;
					
					if (moved) return;

                    if (vis.binds.basic.pressed) {
                        clearInterval(vis.binds.basic.pressed);
                        vis.binds.basic.pressed = null;
                    }

                    if (vis.binds.basic.pressedNext) {
                        vis.binds.basic.pressedNext = false;
                        return;
                    }
                    var $this = $(this);
                    var oid = $this.attr('data-oid');
                    var step = parseFloat($this.attr('data-vis-step'));
                    var tmp  = parseFloat(vis.states[oid + '.val']) + step;
                    if (step < 0) {
                        if (minmax === undefined || tmp >= minmax) {
                            vis.setValue($this.attr('data-oid'), tmp);
                        }
                    } else {
                        if (minmax === undefined || tmp <= minmax) {
                            vis.setValue($this.attr('data-oid'), tmp);
                        }
                    }
                }).on('touchmove', function () {
					moved = true;
				}).on('touchstart', function () {
					moved = false;
				});
            }

            if (interval) {
                $(el).on('mousedown', intervalStart)
                    .on('touchstart', intervalStart)
                    .on('touchend', function () {
                        if (vis.binds.basic.pressed) {
                            clearInterval(vis.binds.basic.pressed);
                            vis.binds.basic.pressed = null;
                        }
                    })
                    .on('mouseup', function () {
                        if (vis.binds.basic.pressed) {
                            clearInterval(vis.binds.basic.pressed);
                            vis.binds.basic.pressed = null;
                        }
                    }).data('destroy', function (id, $widget) {
                        $widget && $widget.off('mousedown').off('touchstart').off('touchend').off('mouseup');
                    });
            }
        },
        navigation: function (el, options) {
            if (!vis.editMode && options.nav_view) {
                var $this = $(el);
				var moved = false;
                $this.on('click touchend', function (e) {
                    // Protect against two events
                    if (vis.detectBounce(this)) return;
					
					if (moved) return;

                    if (options.background) $('body').css({background: options.background});

                    vis.changeView(options.nav_view, options.nav_view, options.hideOptions, options.showOptions, options.sync);
                    //e.preventDefault();
                    //return false;
                }).on('touchmove', function () {
					moved = true;
				}).on('touchstart', function () {
					moved = false;
				});
            }
        },
        hideOnFalse: function (el) {
            var $this = $(el);
            var oid   = $this.attr('data-oid');

            function onChange (e, newVal) {
                if (newVal === null || newVal === false || newVal === 0 || newVal === 'false' || !parseInt(newVal, 10)) {
                    if (!vis.editMode) {
                        $this.hide();
                    }
                } else {
                    $this.show();
                }
            }

            if (oid) {
                vis.states.bind(oid + '.val', onChange);

                // remember all ids, that bound
                $this.data('bound', [oid + '.val'])
                    // remember bind handler
                    .data('bindHandler', onChange);

                if (!vis.editMode) {
                    var newVal = vis.states.attr(oid + '.val');
                    if (newVal === null || newVal === false || newVal === 0 || newVal === 'false' || parseInt(newVal, 10) === 0) {
                        $this.hide();
                    }
                }
            }

        },
        /*hideOnTrue: function (el) {
            var $this = $(el);
            var oid = $this.attr('data-oid');
            vis.states.bind(oid + '.val', function (e, newVal, oldVal) {
                if (newVal === true || parseFloat(newVal) > 0) {
                    if (!vis.editMode) {
                        $this.hide();
                    }
                } else {
                    $this.show();
                }
            });
            if (!vis.editMode) {
                if (parseFloat(vis.states.attr(oid + '.val')) !== 0 && vis.states.attr(oid + '.val') !== false) {
                    $this.hide();
                }
            }
        },
        showOnValue: function (el, val) {
            var $this = $(el);
            var oid = $this.attr('data-oid');
            vis.states.bind(oid + '.val', function (e, newVal, oldVal) {
                if (newVal != val) {
                    if (!vis.editMode) {
                        $this.hide();
                    }
                } else {
                    $this.show();
                }
            });
            if (!vis.editMode) {
                if (vis.states.attr(oid + '.val') != val) {
                    $this.hide();
                }
            }
        },*/
        _onChange: function (el, oid, wid) {
            var $this = $(el);
            // If still working
            //console.log(oid + ' ' + vis.states.attr(oid + '.val') + ' (' + vis.states.attr(oid + '.ack') + ') - ' + wid + ' ' + vis.states.attr(wid + '.val') + ' (' + vis.states.attr(wid + '.ack') + ')');

            if (wid && (vis.states.attr(wid + '.val') === true)) return;

            var val = vis.states.attr(oid + '.val');

            if (val === 'false') {
                val = false;
            } else if (val === 'true') {
                val = true;
            } else if (typeof val === 'string') {
                var f = parseFloat(val);
                if (f == val) {
                    val = f;
                } else if (val !== '') {
                    val = true;
                } else {
                    val = false;
                }
            }

            if ($this.data('data-numeric')) {
                $this.prop('checked', (val > (($this.data('data-max') - $this.data('data-min')) / 2)));
            } else {
                $this.prop('checked', val);
            }
        },
        checkbox: function (el, numeric, min, max) {
            var $this = $(el);
            var oid   = $this.data('oid'); // Object ID
            var wid   = $this.data('oid-working'); // Work ID

            function onChange() {
                vis.binds.basic._onChange(el, oid, wid);
            }
            if (oid) {
                var bound = [];
                vis.states.bind(oid + '.val', onChange);
                bound.push(oid + '.val');
                if (wid) {
                    vis.states.bind(wid + '.val', onChange);
                    bound.push(wid + '.val');
                }

                // remember all ids, that bound
                $this.closest('.vis-widget')
                    .data('bound', bound)
                    // remember bind handler
                    .data('bindHandler', onChange);
            }

            if (numeric) {
                if (min !== undefined && min !== null && min !== '') {
                    min = parseFloat(min);
                } else {
                    min = 0;
                }

                if (max !== undefined && max !== null && max !== '') {
                    max = parseFloat(max);
                } else {
                    max = 1;
                }
            } else {
                min = false;
                max = true;
            }

            $this.data('min',     min);
            $this.data('max',     max);
            $this.data('numeric', numeric);

            vis.binds.basic._onChange(el, oid, wid);

            if (!vis.editMode) {
                $this.change(function () {
                    var $this_ = $(this);
                    if ($this_.prop('checked')) {
                        vis.setValue($this_.data('oid'), $this_.data('max'));
                    } else {
                        vis.setValue($this_.data('oid'), $this_.data('min'));
                    }
                });
            }
        },
        input: function (el, data) {
            var $this = $(el);
            var oid   = $this.data('oid'); // Object ID
            var wid   = $this.data('oid-working'); // Work ID

            function onChange(e, val) {
                $this.val(val);
            }

            if (oid) {
                var bound = [oid + '.val'];
                vis.states.bind(oid + '.val', onChange);
                if (wid) {
                    bound.push(wid + '.val');
                    vis.states.bind(wid + '.val', onChange);
                }
                // remember all ids, that bound
                $this.closest('.vis-widget')
                    .data('bound', bound)
                    // remember bind handler
                    .data('bindHandler', onChange);
            }

            if (data.numeric) {
                $this.attr('type', 'number');
                if (data.min !== undefined && data.min !== null && data.min !== '') {
                    data.min = parseFloat(data.min);
                } else {
                    data.min = null;
                }

                if (data.max !== undefined && data.max !== null && data.max !== '') {
                    data.max = parseFloat(data.max);
                } else {
                    data.max = null;
                }
            }

            $this.val(vis.states[oid + '.val'] === undefined ? '' : vis.states[oid + '.val']);

            setTimeout(function () {
                $this.css('text-align', $this.parent().parent().css('text-align'));
                $this.css('color', $this.parent().parent().css('color'));
                $this.css('background', $this.parent().parent().css('background'));
                $this.css('border', '0');
                $this.css('text-font', $this.parent().parent().css('text-font'));
            }, 0);

            if (!vis.editMode) {
                $this.change(function () {
                    var $this_ = $(this);
                    if (data.numeric) {
                        var value = parseFloat($this_.val());
                        if (data.min !== null && value < data.min) {
                            value = data.min;
                            $this_.val(value);
                        } else if (data.max !== null && value > data.max) {
                            value = data.max;
                            $this_.val(value);
                        }
                        vis.setValue($this_.data('oid'), value);
                    } else {
                        vis.setValue($this_.data('oid'), $this_.val());
                    }
                });
                if (data.autoSet) {
                    $this.keyup(function(e) {
                        var timer = $this.data('timer');
                        if (timer) clearTimeout(timer);
                        $this.data('timer', setTimeout(function () {
                            $this.trigger('change');
                        }), 1000);
                    });
                }
            }
        },
        select: function (el, invert) {
            var $this = $(el).prev();
            var oid   = $this.attr('data-oid');
            var val   = vis.states[oid + '.val'];

            if (val === 'false') {
                val = false;
            } else if (val === 'true') {
                val = true;
            } else if (typeof val === 'string') {
                var f = parseFloat(val);
                if (f == val) {
                    val = f;
                } else if (val !== '') {
                    val = true;
                } else {
                    val = false;
                }
            }

            if (invert) val = !val;

            $this.val(val ? 1 : 0);

            if (!vis.editMode) {
                if (oid !== 'nothing_selected') {
                    $this.change(function () {
                        var val = $this.find('option:selected').val();
                        if (invert) val = !val;
                        vis.setValue(oid, val);
                    });
                }
            }
            if (oid !== 'nothing_selected') {

            }
            function onChange(e, newVal, oldVal) {
                if (newVal === 'false') {
                    newVal = false;
                } else if (newVal === 'true') {
                    newVal = true;
                } else if (typeof newVal === 'string') {
                    var f = parseFloat(newVal);
                    if (f == newVal) {
                        newVal = f;
                    } else if (newVal !== '') {
                        newVal = true;
                    } else {
                        newVal = false;
                    }
                }
                if (oldVal === 'false') {
                    oldVal = false;
                } else if (oldVal === 'true') {
                    oldVal = true;
                } else if (typeof oldVal === 'string') {
                    var f = parseFloat(oldVal);
                    if (f == oldVal) {
                        oldVal = f;
                    } else if (oldVal !== '') {
                        oldVal = true;
                    } else {
                        oldVal = false;
                    }
                }

                if (newVal == oldVal) return;

                if (newVal === 'false' || newVal === false || parseFloat(newVal) === 0) {
                    if ($this.find('option[value="1"]').prop('selected')) {
                        $this.find('option[value="1"]').prop('selected', false);
                        $this.find('option[value="0"]').prop('selected', true);
                        $this.trigger('change');
                    }
                } else {
                    if ($this.find('option[value="0"]').prop('selected')) {
                        $this.find('option[value="0"]').prop('selected', false);
                        $this.find('option[value="1"]').prop('selected', true);
                        $this.trigger('change');
                    }
                }
            }

            if (oid) {
                vis.states.bind(oid + '.val', onChange);
                // remember all ids, that bound
                $this.closest('.vis-widget')
                    .data('bound', [oid + '.val'])
                    // remember bind handler
                    .data('bindHandler', onChange);
            }
        },
        toggle: function (el, oid) {
            var $this = $(el);
            oid = oid || $this.data('oid');
            var min = $this.data('min');
            var max = $this.data('max');

            var urlTrue     = $this.data('url-true');
            var urlFalse    = $this.data('url-false');
            var oidTrue     = $this.data('oid-true');
            var oidFalse    = $this.data('oid-false');
            var oidTrueVal  = $this.data('oid-true-value');
            var oidFalseVal = $this.data('oid-false-value');
            var readOnly    = $this.data('read-only');

            if (min === '') min = undefined;
            if (max === '') max = undefined;

            if ((oid || oidTrue || urlTrue) && !vis.editMode && !readOnly) {
				var moved = false;
                $this.on('click touchend', function () {			
                    // Protect against two events
                    if (vis.detectBounce(this)) return;
					
					if (moved) return;
					
                    var val;

                    if (oidTrue || urlTrue) {
                        if (!oidFalse && oidTrue) oidFalse = oidTrue;
                        if (!urlFalse && urlTrue) urlFalse = urlTrue;

                        if (!oid || oid === 'nothing_selected') {
                            val = !$(this).data('state');
                            // remember state
                            $(this).data('state', val);
                        } else {
                            val = vis.states[oid + '.val'];
                            if (max !== undefined) {
                                val = (val == max);
                            } else {
                                val = (val === 1 || val === '1' || val === true || val === 'true');
                            }
                            val = !val; // invert
                        }
                        if (min === undefined || min === 'false' || min === null) min = false;
                        if (max === undefined || max === 'true'  || max === null) max = true;

                        if (oidTrue) {
                            if (val) {
                                if (oidTrueVal === undefined || oidTrueVal === null) oidTrueVal = max;
                                if (oidTrueVal === 'false') oidTrueVal = false;
                                if (oidTrueVal === 'true')  oidTrueVal = true;
                                var f = parseFloat(oidTrueVal);
                                if (f.toString() == oidTrueVal) oidTrueVal = f;
                                vis.setValue(oidTrue,  oidTrueVal);
                            } else {
                                if (oidFalseVal === undefined || oidFalseVal === null) oidFalseVal = min;
                                if (oidFalseVal === 'false') oidFalseVal = false;
                                if (oidFalseVal === 'true')  oidFalseVal = true;
                                var f = parseFloat(oidFalseVal);
                                if (f.toString() == oidFalseVal) oidFalseVal = f;
                                vis.setValue(oidFalse, oidFalseVal);
                            }
                        }

                        if (urlTrue) {
                            if (val) {
                                vis.conn.httpGet(urlTrue)
                            } else {
                                vis.conn.httpGet(urlFalse);
                            }
                        }

                        // show new state
                        if (!oid || oid === 'nothing_selected') {
                            var img = $(this).data('img-class');
                            if (val) {
                                if ($(this).data('as-button')) $(this).addClass('ui-state-active');
                                val = $(this).data('img-true');
                            } else {
                                val = $(this).data('img-false');
                                if ($(this).data('as-button')) $(this).removeClass('ui-state-active');
                            }
                            $(this).find('.' + img).attr('src', val);
                        }
                    } else {
                        var val = vis.states[oid + '.val'];
                        if ((min === undefined && (val === null || val === '' || val === undefined || val === false || val === 'false')) ||
                                (min !== undefined && min == val)) {
                            vis.setValue(oid, max !== undefined ? max : true);
                        } else
                        if ((max === undefined && (val === true || val === 'true')) ||
                                (max !== undefined && val == max))
                        {
                            vis.setValue(oid, min !== undefined ? min : false);
                        } else {
                            val = parseFloat(val);
                            if (min !== undefined && max !== undefined) {
                                if (val >= (max - min) / 2) {
                                    val = min;
                                } else {
                                    val = max;
                                }
                            } else {
                                if (val >= 0.5) {
                                    val = 0;
                                } else {
                                    val = 1;
                                }
                            }
                            vis.setValue(oid, val);
                        }
                    }
                }).on('touchmove', function () {
					moved = true;
				}).on('touchstart', function () {
					moved = false;
				}).data('destroy', function (id, $widget) {
				    $widget.off('click touchend').off('touchmove').off('touchstart');
                });
            }
        },
        iframeRefresh: function (el, src, refreshInterval, refreshOnWakeUp, refreshOnViewChange, refreshWithNoQuery) {
            var widgetView;
            if (src && typeof src === 'object') {
                widgetView = refreshInterval;
                refreshInterval     = src.refreshInterval;
                refreshOnWakeUp     = src.refreshOnWakeUp;
                refreshOnViewChange = src.refreshOnViewChange;
                refreshWithNoQuery  = src.refreshWithNoQuery;
                src                 = src.src;
            } else if (refreshInterval && typeof refreshInterval === 'object') {
                widgetView = refreshOnWakeUp;
                refreshInterval     = refreshInterval.refreshInterval;
                refreshOnWakeUp     = refreshInterval.refreshOnWakeUp;
                refreshOnViewChange = refreshInterval.refreshOnViewChange;
                refreshWithNoQuery  = refreshInterval.refreshWithNoQuery;
            }
            refreshOnViewChange = refreshOnViewChange === true || refreshOnViewChange === 'true';
            refreshOnWakeUp     = refreshOnWakeUp     === true || refreshOnWakeUp     === 'true';
            refreshWithNoQuery  = refreshWithNoQuery  === true || refreshWithNoQuery  === 'true';

            if (!vis.editMode && src) {
                var $this = $(el).parent().find('iframe');
                refreshInterval = parseInt(refreshInterval, 10) || 0;

                if (refreshOnViewChange) {
                    widgetView = widgetView || vis.activeView;
                    vis.navChangeCallbacks.push(function (view) {
                        if (view === widgetView) {
                            $this.attr('src', src + (refreshWithNoQuery ? '' : ((src.indexOf('?') !== -1) ? '&' : '?') + '_refts=' + ((new Date()).getTime())));
                        }
                    });
                }
                if (refreshInterval > 0) {
                    setInterval(function () {
                        if ($this.is(':visible')) {
                            var p = $this.parents(':hidden');
                            if (!p.length || p[0].tagName === 'BODY') {
                                $this.attr('src', src + (refreshWithNoQuery ? '' : ((src.indexOf('?') !== -1) ? '&' : '?') + '_refts=' + ((new Date()).getTime())));
                            }
                        }
                    }, refreshInterval);
                }
                if (refreshOnWakeUp) {
                    vis.onWakeUp(function () {
                        // TODO this does not work. :(
                        $this.attr('src', src + (refreshWithNoQuery ? '' : ((src.indexOf('?') !== -1) ? '&' : '?') + '_refts=' + ((new Date()).getTime())));
                    });
                }
            }
        },
        htmlRefresh: function (el, html, refreshInterval) {
            refreshInterval = parseInt(refreshInterval, 10) || 0;
            if (html && !vis.editMode && refreshInterval > 0) {
                var $this = $(el);
                setInterval(function () {
                    if ($this.is(':visible')) {
                        var p = $this.parents(':hidden');
                        if (!p.length || p[0].tagName === 'BODY') {
                            $this.html(html);
                        }
                    }
                }, refreshInterval);
            }
        },
        imgRefresh: function (el, src, refreshInterval, refreshOnWakeUp, refreshOnViewChange, refreshWithNoQuery) {
            var widgetView;
            if (src && typeof src === 'object') {
                widgetView = refreshInterval;
                refreshInterval     = src.refreshInterval;
                refreshOnWakeUp     = src.refreshOnWakeUp;
                refreshOnViewChange = src.refreshOnViewChange;
                refreshWithNoQuery  = src.refreshWithNoQuery;
                src                 = src.src;
            } else if (refreshInterval && typeof refreshInterval === 'object') {
                widgetView = refreshOnWakeUp;
                refreshInterval     = refreshInterval.refreshInterval;
                refreshOnWakeUp     = refreshInterval.refreshOnWakeUp;
                refreshOnViewChange = refreshInterval.refreshOnViewChange;
                refreshWithNoQuery  = refreshInterval.refreshWithNoQuery;
            }
            refreshOnViewChange = refreshOnViewChange === true || refreshOnViewChange === 'true';
            refreshOnWakeUp     = refreshOnWakeUp     === true || refreshOnWakeUp     === 'true';
            refreshWithNoQuery  = refreshWithNoQuery  === true || refreshWithNoQuery  === 'true';

            if (!vis.editMode && src) {
                var $this = $(el).parent().find('img');
                refreshInterval = parseInt(refreshInterval, 10) || 0;

                if (refreshOnViewChange) {
                    widgetView = widgetView || vis.activeView;
                    vis.navChangeCallbacks.push(function (view) {
                        if (view === widgetView) {
                            $this.attr('src', src + (refreshWithNoQuery ? '' : ((src.indexOf('?') !== -1) ? '&' : '?') + '_refts=' + ((new Date()).getTime())));
                        }
                    });
                }
                if (refreshInterval > 0) {
                    setInterval(function () {
                        if ($this.is(':visible')) {
                            var p = $this.parents(':hidden');
                            if (!p.length || p[0].tagName === 'BODY') {
                                $this[0].src = src + (refreshWithNoQuery ? '' : ((src.indexOf('?') !== -1) ? '&' : '?') + '_refts=' + ((new Date()).getTime()));
                            }
                        }
                    }, refreshInterval);
                }
                if (refreshOnWakeUp) {
                    //console.log("refreshOnWakeUp!");
                    vis.onWakeUp(function () {
                        // TODO this does not work. :(
                        //console.log("wakeup refresh!");
                        $this[0].src = src + (refreshWithNoQuery ? '' : ((src.indexOf('?') !== -1) ? '&' : '?') + '_refts=' + ((new Date()).getTime()));
                        //console.log($this.attr('src'));
                    });
                }
            }
        },
        showSvg: function (myClass, view, wid, oid, opacity, svg_false, svg_true, style, no_control) {
            var $wid = $('#' + wid);

            var id = $wid.attr('id');
            if (id && id.match(/_removed$/)) return;

            if (!$wid.length) {
                return setTimeout(function () {
                    vis.binds.basic.showSvg(myClass, view, wid, oid, opacity, svg_false, svg_true, style, no_control);
                }, 100);
            }

            $wid.find('svg').remove();
            var str = vis.states.attr(oid + '.val');
            if (typeof str === 'string') str = str.toLowerCase();
            var val = parseFloat(str);
            var sText = '<svg version="1.1" style="width:100%;height:100%" xmlns="http://www.w3.org/2000/svg" data-oid="' + oid + '">';
            if (vis.editMode) {
                if (opacity === undefined || opacity === null || opacity === '') opacity = 1;

                if (parseFloat(opacity) < 0.2) opacity = 0.2;
            }
            if (val === 0 || str === 'false' || str === '0' || str === 'off' || str === false || str === null || str === undefined) {
                // try to analyse
                sText += svg_false;
            } else {
                sText += svg_true;
            }
            sText += '</svg>';
            $wid.find('.vis-widget-body').append(sText);

            if (style) $wid.css(style);

			var moved = false;

            function onSvgClick() {
                // Protect against two events
                if (vis.detectBounce(this)) return;

				if (moved) return;
				
                var val = vis.states[oid + '.val'];
                if (val === null || val === '' || val === undefined || val === false || val === "false") {
                    vis.setValue(oid, true);
                } else if (val === true || val === "true") {
                    vis.setValue(oid, false);
                } else {
                    val = parseFloat(val);
                    if (val >= 0.5) {
                        val = 1;
                    } else {
                        val = 0;
                    }
                    vis.setValue(oid, 1 - val);
                }
            }

            function onChange (e, newVal) {
                if (newVal === 'true'  || newVal === true)  newVal = 1;
                if (newVal === 'false' || newVal === false || newVal === '0') newVal = 0;
                var $svg = $('#' + wid).find('svg');

                $svg.html(newVal ? svg_true : svg_false);

                if (!vis.editMode && !no_control) {
                    $svg.children().unbind('click touchend touchmove touchstart').on('click touchend', onSvgClick)
                        .on('touchmove', function () {
                            moved = true;
                        }).on('touchstart', function () {
                            moved = false;
                        });
                } else if (vis.editMode){
                    $svg.children().unbind('click touchstart').on('click touchstart', function () {
                        vis.inspectWidgets([wid]);
                    });
                }
            }

            if (oid) {
                vis.states.bind(oid + '.val', onChange);
                // remember all ids, that bound
                $wid.data('bound', [oid + '.val'])
                    // remember bind handler
                    .data('bindHandler', onChange);
            }
            var $svg = $wid.find('svg');
            if (!vis.editMode && !no_control) {
                $svg.children().off('click touchend').on('click touchend', onSvgClick).off('touchmove').on('touchmove', function () {
					moved = true;
				}).on('touchstart', function () {
					moved = false;
				});
            } else if (vis.editMode){
                $svg.children().off('click touchstart').on('click touchstart', function () {
                    vis.inspectWidgets([wid]);
                });
            }
            $wid.data('destroy', function (id, $widget) {
                $widget.find('svg').children().off('click touchend').off('touchmove').off('click touchstart');
            });
        },
        editNote: function (wid, max_width, min_width, min_height, oid) {
            if (vis.editMode) return;

            max_width  = max_width  ? parseInt(max_width,  10) : 400;
            min_width  = min_width  ? parseInt(min_width,  10) : 40;
            min_height = min_height ? parseInt(min_height, 10) : 15;

            var $this = $('#div_' + wid);
            $('body').append('<div id="dlg_' + wid + '" title="' + _('Edit note') + '">' +
            '<textarea style="resize: none; width:95%; height:92%" id="text_' + wid + '">' + $this.text().trim() + '</textarea></div>');

            var buttons = {};
            buttons[_('Clear')] = function () {
                $('#text_' + $(this).attr('data-wid')).val("");
            };

            buttons[_('Ok')] = function () {
                var dlg  = $(this);
                var oid  = dlg.attr('data-oid');
                var wid  = dlg.attr('data-wid');
                var text = $('#text_' + wid).val();
                text = text.replace('\n', '<br>\n');

                if (!oid) $('#div_' + wid).html(text);
                /*if (!text) {
                 $('#' + wid).css({width: min_width, height: min_height});
                 }
                 else {
                 $('#' + wid).css({width: max_width, height: 'auto'});
                 }*/

                if (oid) vis.setValue(oid, text);

                dlg.dialog('close');
                dlg.remove();
            };

            buttons[_('Cancel')] = function () {
                $(this).dialog('close');
                $(this).remove();
            };

            $('#dlg_' + wid).attr('data-oid', oid).attr('data-wid', wid).dialog({
                width:   500,
                height:  300,
                modal:   true,
                buttons: buttons
            });
        },
        formatFloat: function (data, val) {
            if (vis.editMode && data.attr('test_html') !== undefined && data.attr('test_html') !== '') {
                val = parseFloat(data.attr('test_html'));
            } else if(val === undefined || val === null){
                val = parseFloat(vis.states.attr(data.oid + '.val'));
            }else {
                val = parseFloat(val);
            }
            if (data.factor !== undefined && data.factor !== '') val = val * parseFloat(data.factor);
            if (data.digits !== undefined && data.digits !== '') val = val.toFixed(parseFloat(data.digits, 10));

            if (data.attr('is_tdp')) {
                val = this.formatValue(val, data.digits ? parseInt(data.digits) : 2, data.attr('is_comma') ? ".," : ",.");
            } else if (data.attr('is_comma')) {
                val = '' + val;
                val = val.replace('.', ',');
            }

            return val;
        },
        extractWidth: function (css, multiplier) {
            // extract from "2px solid #aabbcc" => 2px
            var m = css.match(/([0-9])+(px|em)?/);
            if (m) {
                if (m[1] && m[2]) {
                    return parseInt(m[1], 10) * (multiplier || 1) + m[2];
                } else {
                    return parseInt(m[1], 10) * (multiplier || 1);
                }
            }
        },
        getCalc: function (data, val) {
            var min = (data.min || data.min === 0) ? parseFloat(data.min) : 0;
            var max = (data.max || data.max === 0) ? parseFloat(data.max) : 100;
            val = parseFloat(vis.states.attr(data.oid + '.val')) || 0;
            val = (val - min) / (max - min);
            return (data.border) ? ('calc(' + Math.round(val * 100) + '% - ' + vis.binds.basic.extractWidth(data.border, 2) + ')') : (Math.round(val * 100) + '%');
        },

        formatValue: function formatValue(value, decimals, _format) {
	        if (typeof decimals !== 'number') {
	            decimals = 2;
	            _format = decimals;
	        }
	        var format = (_format === undefined) ? '.,' : _format;
	        if (typeof value !== 'number') value = parseFloat(value);
	        return isNaN(value) ? '' : value.toFixed(decimals || 0).replace(format[0], format[1]).replace(/\B(?=(\d{3})+(?!\d))/g, format[0]);
	    },

        formatIntervalHelper: function (value, type) {
            var singular;
	        var plural;
            var special24;
            if (vis.language === 'de') {
                if (type === 'seconds') {
                    singular = 'Sekunde';
                    plural   = 'Sekunden';
                } else if (type === 'minutes') {
                    singular = 'Minute';
                    plural   = 'Minuten';
                } else if (type === 'hours') {
                    singular = 'Stunde';
                    plural   = 'Stunden';
                } else if (type === 'days') {
                    singular = 'Tag';
                    plural   = 'Tagen';
                }
            } else
            if (vis.language === 'ru') {
                if (type === 'seconds') {
                    singular  = 'секунду';
                    plural    = 'секунд';
                    special24 = 'секунды';
                } else if (type === 'minutes') {
                    singular  = 'минуту';
                    plural    = 'минут';
                    special24 = 'минуты';
                } else if (type === 'hours') {
                    singular  = 'час';
                    plural    = 'часов';
                    special24 = 'часа';
                } else if (type === 'days') {
                    singular  = 'день';
                    plural    = 'дней';
                    special24 = 'дня';
                }
            } else {
                if (type === 'seconds') {
                    singular = 'second';
                    plural   = 'seconds';
                } else if (type === 'minutes') {
                    singular = 'minute';
                    plural   = 'minutes';
                } else if (type === 'hours') {
                    singular = 'hour';
                    plural   = 'hours';
                } else if (type === 'days') {
                    singular = 'day';
                    plural   = 'days';
                }
            }

	        if (value === 1) {
                if (vis.language === 'de') {
                    return 'einer ' + singular;
                } else if (vis.language === 'ru') {
                    if (type === 'days' || type === 'hours') {
                        return 'один ' + singular;
                    } else {
                        return 'одну ' + singular;
                    }
                } else {
                    return 'one ' + singular;
                }
            } else {
                if (vis.language === 'de') {
                    return value + ' ' + plural;
                } else if (vis.language === 'ru') {
                    var d = value % 10;
                    if (d === 1 && value !== 11) {
                        return value + ' ' + singular;
                    } else
                    if (d >= 2 && d <= 4 && (value > 20 || value < 10)) {
                        return value + ' ' + special24;
                    } else {
                        return value + ' ' + plural;
                    }
                } else {
                    return value + ' ' + plural;
                }
            }
        },
        formatInterval: function (timestamp, isMomentJs) {
            if (isMomentJs && typeof moment !== 'undefined') {
                return moment(new Date(timestamp)).fromNow();
            }
            var diff = new Date().getTime() - timestamp;
            diff = Math.round(diff / 1000);
            var text;
            if (diff <= 60) {
                if (vis.language === 'de') {
                    text = 'vor ' + vis.binds.basic.formatIntervalHelper(diff, 'seconds');
                } else if (vis.language === 'ru') {
                    text = vis.binds.basic.formatIntervalHelper(diff, 'seconds') + ' назад';
                } else {
                    text = vis.binds.basic.formatIntervalHelper(diff, 'seconds') + ' ago';
                }
            } else if (diff < 3600) {
                var m = Math.floor(diff / 60);
                var s = diff - m * 60;
                text = '';
                if (vis.language === 'de') {
                    text = 'vor ' + vis.binds.basic.formatIntervalHelper(m, 'minutes');
                } else if (vis.language === 'ru') {
                    text = vis.binds.basic.formatIntervalHelper(m, 'minutes');
                } else {
                    text = vis.binds.basic.formatIntervalHelper(m, 'minutes');
                }

                if (m < 5) {
                    // add seconds
                    if (vis.language === 'de') {
                        text += ' und ' + vis.binds.basic.formatIntervalHelper(s, 'seconds');
                    } else if (vis.language === 'ru') {
                        text += ' и ' + vis.binds.basic.formatIntervalHelper(s, 'seconds');
                    } else {
                        text += ' and ' + vis.binds.basic.formatIntervalHelper(s, 'seconds');
                    }
                }

                if (vis.language === 'de') {
                    // nothing
                } else if (vis.language === 'ru') {
                    text += ' назад';
                } else {
                    text += ' ago';
                }
            } else if (diff < 3600 * 24) {
                var h = Math.floor(diff / 3600);
                var m = Math.floor((diff - h * 3600) / 60);
                text = '';
                if (vis.language === 'de') {
                    text = 'vor ' + vis.binds.basic.formatIntervalHelper(h, 'hours');
                } else if (vis.language === 'ru') {
                    text = vis.binds.basic.formatIntervalHelper(h, 'hours');
                } else {
                    text = vis.binds.basic.formatIntervalHelper(h, 'hours');
                }

                if (h < 10) {
                    // add seconds
                    if (vis.language === 'de') {
                        text += ' und ' + vis.binds.basic.formatIntervalHelper(m, 'minutes');
                    } else if (vis.language === 'ru') {
                        text += ' и ' + vis.binds.basic.formatIntervalHelper(m, 'minutes');
                    } else {
                        text += ' and ' + vis.binds.basic.formatIntervalHelper(m, 'minutes');
                    }
                }

                if (vis.language === 'de') {
                    // nothing
                } else if (vis.language === 'ru') {
                    text += ' назад';
                } else {
                    text += ' ago';
                }
            } else {
                var d = Math.floor(diff / (3600 * 24));
                var h = Math.floor((diff - d * (3600 * 24)) / 3600);
                text = '';
                if (vis.language === 'de') {
                    text = 'vor ' + vis.binds.basic.formatIntervalHelper(d, 'days');
                } else if (vis.language === 'ru') {
                    text = vis.binds.basic.formatIntervalHelper(d, 'days');
                } else {
                    text = vis.binds.basic.formatIntervalHelper(d, 'days');
                }

                if (d < 3) {
                    // add seconds
                    if (vis.language === 'de') {
                        text += ' und ' + vis.binds.basic.formatIntervalHelper(h, 'hours');
                    } else if (vis.language === 'ru') {
                        text += ' и ' + vis.binds.basic.formatIntervalHelper(h, 'hours');
                    } else {
                        text += ' and ' + vis.binds.basic.formatIntervalHelper(h, 'hours');
                    }
                }

                if (vis.language === 'de') {
                    // nothing
                } else if (vis.language === 'ru') {
                    text += ' назад';
                } else {
                    text += ' ago';
                }
            }
            return text;
        },
        startUpdateInterval: function () {
            if (vis.binds.basic.updateInterval) return;
            vis.binds.basic.updateInterval = setInterval(function () {
                $('.time-interval').each(function () {
                    $(this).html(vis.binds.basic.formatInterval($(this).data('time'), $(this).data('moment')))
                });
            }, 15000);
        },
        formatDate: function (dateObj, format, interval, isMomentJs) {
            if (typeof format === 'boolean') {
                interval = format;
                format = 'auto';
            }

            if (format === 'auto') format = (vis.dateFormat || 'DD.MM.YYYY') + ' hh:mm:ss';

            format = format || vis.dateFormat || 'DD.MM.YYYY';

            if (!dateObj) return '';
            var text = typeof dateObj;
            if (text === 'string') {
                var pos = dateObj.indexOf('.');
                if (pos !== -1) dateObj = dateObj.substring(0, pos);
                return dateObj;
            }
            if (text !== 'object') {
                var i = parseInt(dateObj, 10);
                if (i == dateObj) {
                    i = dateObj;
                    // if greater than 2000.01.01 00:00:00
                    if (i > 946681200000) {
                        dateObj = new Date(dateObj);
                    } else {
                        dateObj = new Date(dateObj * 1000);
                    }
                } else {
                    dateObj = new Date(dateObj);
                }
            }
            if (interval) {
                vis.binds.basic.startUpdateInterval();
                return '<span class="time-interval" data-time="' + dateObj.getTime() + '" data-moment="' + (isMomentJs || false) + '">' + vis.binds.basic.formatInterval(dateObj.getTime(), isMomentJs) + '</span>';
            }

            var v;

            // Year
            if (format.indexOf('YYYY') !== -1 || format.indexOf('JJJJ') !== -1 || format.indexOf('ГГГГ') !== -1) {
                v = dateObj.getFullYear();
                format = format.replace('YYYY', v);
                format = format.replace('JJJJ', v);
                format = format.replace('ГГГГ', v);
            } else if (format.indexOf('YY') !== -1 || format.indexOf('JJ') !== -1 || format.indexOf('ГГ') !== -1) {
                v = dateObj.getFullYear() % 100;
                format = format.replace('YY', v);
                format = format.replace('JJ', v);
                format = format.replace('ГГ', v);
            }
            // Month
            if (format.indexOf('MM') !== -1 || format.indexOf('ММ') !== -1) {
                v =  dateObj.getMonth() + 1;
                if (v < 10) v = '0' + v;
                format = format.replace('MM', v);
                format = format.replace('ММ', v);
            } else if (format.indexOf('M') !== -1 || format.indexOf('М') !== -1) {
                v =  dateObj.getMonth() + 1;
                format = format.replace('M', v);
                format = format.replace('М', v);
            }

            // Day
            if (format.indexOf('DD') !== -1 || format.indexOf('TT') !== -1 || format.indexOf('ДД') !== -1) {
                v =  dateObj.getDate();
                if (v < 10) v = '0' + v;
                format = format.replace('DD', v);
                format = format.replace('TT', v);
                format = format.replace('ДД', v);
            } else if (format.indexOf('D') !== -1 || format.indexOf('TT') !== -1 || format.indexOf('Д') !== -1) {
                v =  dateObj.getDate();
                format = format.replace('D', v);
                format = format.replace('T', v);
                format = format.replace('Д', v);
            }

            // hours
            if (format.indexOf('hh') !== -1 || format.indexOf('SS') !== -1 || format.indexOf('чч') !== -1) {
                v =  dateObj.getHours();
                if (v < 10) v = '0' + v;
                format = format.replace('hh', v);
                format = format.replace('SS', v);
                format = format.replace('чч', v);
            } else if (format.indexOf('h') !== -1 || format.indexOf('S') !== -1 || format.indexOf('ч') !== -1) {
                v =  dateObj.getHours();
                format = format.replace('h', v);
                format = format.replace('S', v);
                format = format.replace('ч', v);
            }

            // minutes
            if (format.indexOf('mm') !== -1 || format.indexOf('мм') !== -1) {
                v =  dateObj.getMinutes();
                if (v < 10) v = '0' + v;
                format = format.replace('mm', v);
                format = format.replace('мм', v);
            } else if (format.indexOf('m') !== -1 ||  format.indexOf('м') !== -1) {
                v =  dateObj.getMinutes();
                format = format.replace('m', v);
                format = format.replace('v', v);
            }

            // milliseconds
            if (format.indexOf('sss') !== -1 || format.indexOf('ссс') !== -1) {
                v =  dateObj.getMilliseconds();
                if (v < 10) {
                    v = '00' + v;
                } else if (v < 100) {
                    v = '0' + v;
                }
                format = format.replace('sss', v);
                format = format.replace('ссс', v);
            }

            // seconds
            if (format.indexOf('ss') !== -1 || format.indexOf('сс') !== -1) {
                v =  dateObj.getSeconds();
                if (v < 10) v = '0' + v;
                format = format.replace('ss', v);
                format = format.replace('cc', v);
            } else if (format.indexOf('s') !== -1 || format.indexOf('с') !== -1) {
                v =  dateObj.getHours();
                format = format.replace('s', v);
                format = format.replace('с', v);
            }

            return format;
        },
        detectScreen: function (wid) {
            if (vis.navChangeCallbacks.indexOf(vis.binds.basic.detectScreen) === -1) {
                vis.navChangeCallbacks.push(vis.binds.basic.detectScreen);
            }

            function onResize () {
                if (vis.editMode) {
                    $('.vis-resolution-width').html(vis.views[vis.activeView].settings.sizex  || $(window).width());
                    $('.vis-resolution-height').html(vis.views[vis.activeView].settings.sizey || $(window).height());
                    $('.vis-resolution-default-view').html(vis.findNearestResolution(vis.views[vis.activeView].settings.sizex || $(window).width(), vis.views[vis.activeView].settings.sizey || $(window).height()));
                } else {
                    $('.vis-resolution-width').html($(window).width());
                    $('.vis-resolution-height').html($(window).height());
                    $('.vis-resolution-default-view').html(vis.findNearestResolution());
                }
            }

            setTimeout(function () {
                $(window).bind('resize', onResize);
                if (vis.editMode) {
                    $('.vis-resolution-width').html(vis.views[vis.activeView].settings.sizex  || $(window).width());
                    $('.vis-resolution-height').html(vis.views[vis.activeView].settings.sizey || $(window).height());
                    $('.vis-resolution-default-view').html(vis.findNearestResolution(vis.views[vis.activeView].settings.sizex || $(window).width(), vis.views[vis.activeView].settings.sizey || $(window).height()));
                } else {
                    $('.vis-resolution-width').html($(window).width());
                    $('.vis-resolution-height').html($(window).height());
                    $('.vis-resolution-default-view').html(vis.findNearestResolution());
                }
            }, 100);

            if (vis.editMode) {
                $('#' + wid).data('destroy', function () {
                    $(window).unbind('resize', onResize);
                });
            }
        },
        createScreenText: function () {
            setTimeout(function () {
                $('.basic-click-create-instance').unbind('click').click(function () {
                    if (!vis.instance) {
                        vis.generateInstance();
                        if (vis.instance) {
                            $(this).html(vis.instance).removeClass('basic-click-create-instance').css({
                                'font-weight': 'inherit',
                                cursor: 'inherit'
                            });
                        } else {
                            window.alert('Cannot generate!');
                        }
                    }
                });
            }, 500);
            return '<span class="basic-click-create-instance" style="font-weight: bold; cursor: pointer">' + _('click to create') + '</span>';
        },
        isFalse: function (val, min, max) {
            if (min !== undefined && min !== null && min !== '') {
                if (max !== undefined && max !== null && max !== '') {
                    return val != max;
                } else {
                    return val == min;
                }
            }
            if (val === undefined || val === null || val === false || val === 'false' || val === 'FALSE' || val === 'False' || val === 'OFF' || val === 'Off' || val === 'off' || val === '') return true;
            if (val === '0' || val === 0) return true;
            var f = parseFloat(val);
            if (f.toString() !== 'NaN') return !f;
            return false;
        },
        circlePoints: function (radius, num, step) {
            var isArray = false;
            if (step === true) {
                isArray = true;
                step = 0;
            }
            step = step || 360 / num;
            var points = [];
            var text = '';
            for (var i = 0; i < num; i++) {
                var point = {x:Math.sin(Math.PI / 180 * (i * step - 180)) * radius, y:Math.cos(Math.PI / 180 * (i * step - 180)) * radius};
                points.push(point);
                text += point.x + ', ' + point.y + ' ';
            }
            if (isArray) return points;
            return text;
        },
        createValueGesture: function (widgetID, view, data, style) {
            var $div = $('#' + widgetID);
            // if nothing found => wait
            if (!$div.length) {
                return setTimeout(function () {
                    vis.binds.basic.createValueGesture(widgetID, view, data, style);
                }, 100);
            }
            var $content = $('#' + widgetID + ' .vis-widget-body');
            function refresh(val, x, y) {
                var text;
                if (val === null){
                    $div.hide();
                    return;
                }
                text = data.html_prepend || '';
                text += vis.binds.basic.formatFloat(data,val);
                text += parseFloat(vis.binds.basic.formatFloat(data,val)) === 1 ? data.html_append_singular || '' : data.html_append_plural || '';
                $content.html(text);
                $div.css({left: parseInt(x)  -$div.width() / 2 + 'px', top: parseInt(y) - $div.height() / 2 + 'px'}).show();
            }
            if (vis.editMode){
                refresh(data.test_html || 0, $div.position().left + $div.width() / 2, $div.position().top + $div.height() / 2);
            } else {
                refresh(null, 0, 0);
            }

            // subscribe top value updates
            $div.on('gestureUpdate', function(event, evData){
                refresh(evData.val, evData.x, evData.y);
            });
        },
        speech2text: function (wid, view, data, style) {
            var $div = $('#' + wid);
            // if nothing found => wait
            if (!$div.length) {
                return setTimeout(function () {
                    vis.binds.basic.speech2text(wid, view, data, style);
                }, 100);
            }

            if (typeof webkitSpeechRecognition === 'undefined') {
                console.error('Browser does not support speech 2 text');
                $div.find('.mic-info-text').html(_('info_upgrade'));
                return;
            }

            var _data ={
                continuous:     data.speechMode === 'continuous' || data.speechMode === 'startstop',
                speechMode:     data.speechMode,
                oid:            data.oid,
                language:       data.language,
                finalTranscript: '',
                lastText:       '',
                recognition:    null,
                ignoreOnEnd:    false,
                timer:          null,
                words:          data.keywords ? data.keywords.toLowerCase().split(/[\s,;]+/g) : null,
                textSentColor:  data.textSentColor,
                keyWordColor:   data.keyWordColor,
                imageInactive:  data.imageInactive,
                imageActive:    data.imageActive    || data.imageInactive,
                imageStarted:   data.imageStarted   || data.imageInactive,
                imageDetected:  data.imageDetected  || data.imageInactive,
                imageSent:      data.imageSent      || data.imageInactive,
                $text:          $div.find('.mic-info-text'),
                $result:        $div.find('.mic-results'),
                $image:         $div.find('.mic-image')
            };
            data = null;

            function findKeyWord(text) {
                var found = false;
                if (_data.words) {
                    found = false;
                    var wwords = text.toLowerCase().split(' ');
                    for (var w = 0; w < _data.words.length; w++) {
                        var pos = wwords.indexOf(_data.words[w]);
                        if (pos !== -1) {
                            var offset = 0;
                            for (var p = 0; p < pos; p++) {
                                offset += wwords[p].length + 1;
                            }
                            text = text.substring(0, offset) + '<b>' + text.substring(offset, offset + wwords[pos].length) + '</b>' + text.substring(offset + wwords[pos].length);
                            found = true;
                            break;
                        }
                    }
                } else {
                    return true;
                }
                return found ? text : false;
            }

            function startRecognition() {
                if (_data.recognition) {
                    if (_data.speechMode === 'startstop') {
                        _data.recognition.onend = null;
                        _data.recognition.stop();
                        _data.recognition = null;
                        _data.$text.html(_('info_start')).show();
                        _data.$image.attr('src', _data.imageInactive);
                        _data.$result.hide();
                    }
                    return;
                }

                _data.recognition                 = new webkitSpeechRecognition();
                _data.recognition.continuous      = _data.continuous;
                _data.recognition.interimResults  = true;
                _data.recognition.maxAlternatives = 1;
                var startTimestamp = new Date();


                _data.recognition.onstart = function() {
                    _data.$text.html(_('info_speak_now')).show();
                    _data.$image.attr('src', _data.imageActive);
                    _data.$result.hide();
                };

                _data.recognition.onerror  = function(event) {
                    _data.$result.hide();
                    _data.$text.show();
                    _data.$image.attr('src', _data.imageInactive);
                    if (event.error === 'no-speech') {
                        _data.$text.html(_('info_no_speech'));
                        //_data.ignoreOnEnd = true;
                    }
                    if (event.error === 'audio-capture') {
                        _data.$text.html(_('info_no_microphone'));
                        _data.ignoreOnEnd = true;
                    }
                    if (event.error === 'not-allowed') {
                        if (event.timeStamp - startTimestamp < 100) {
                            _data.$text.html(_('info_blocked'));
                        } else {
                            _data.$text.html(_('info_denied'));
                        }
                        _data.ignoreOnEnd = true;
                    }
                };

                _data.recognition.onend    = function() {
                    // console.log('onend');
                    _data.recognition.stop();
                    _data.recognition = null;
                    if (!_data.ignoreOnEnd) {
                        setTimeout(function () {
                            _data.$image.attr('src', _data.imageInactive);
                            if (_data.continuous) {
                                _data.$result.hide();
                                _data.$text.html(_('info_speak_now')).show();
                                startRecognition();
                            } else {
                                _data.$result.hide();
                                _data.$text.html(_('info_start')).show();
                            }
                        }, 1000);
                    }
                };

                _data.recognition.onresult = function(event) {
                    var interimTranscript = '';

                    if (typeof event.results === 'undefined') {
                        _data.recognition.onend = null;
                        _data.recognition.stop();
                        return;
                    }

                    for (var i = event.resultIndex; i < event.results.length; ++i) {
                        if (event.results[i].isFinal) {
                            _data.finalTranscript += event.results[i][0].transcript;
                        } else {
                            interimTranscript += event.results[i][0].transcript;
                        }
                    }

                    if (_data.$image.attr('src') === _data.imageActive) _data.$image.attr('src', _data.imageStarted);

                    //final_transcript = capitalize(final_transcript);
                    _data.$text.hide();
                    var text = _data.finalTranscript || interimTranscript;
                    var found = findKeyWord(text);

                    if (!_data.originalColor) _data.originalColor = _data.$result.css('color');

                    if (found) {
                        text = found;
                        if (_data.$image.attr('src') === _data.imageStarted) _data.$image.attr('src', _data.imageDetected);
                        _data.$result.addClass('mic-keyword-found');
                        if (_data.keyWordColor) _data.$result.css({color: _data.keyWordColor});
                    }

                    _data.$result.html(text).show();

                    if (_data.finalTranscript) {
                        if (_data.timer) clearTimeout(_data.timer);

                        if (found) {
                            _data.$image.attr('src', _data.imageSent);
                            if (_data.textSentColor) _data.$result.css({color: _data.textSentColor});
                            _data.$result.addClass('mic-text-sent');
                            vis.setValue(_data.oid, _data.finalTranscript);
                        }

                        _data.finalTranscript = '';
                        _data.lastText = '';

                        setTimeout(function () {
                            _data.$image.attr('src', _data.imageActive);
                            _data.$result.css({color: _data.originalColor});
                            _data.$result.hide().removeClass('mic-keyword-found mic-text-sent');
                            _data.$text.html(_('info_speak_now')).show();
                        }, 1000);
                    } else {
                        _data.lastText = interimTranscript;

                        if (_data.timer) clearTimeout(_data.timer);
                        _data.timer = setTimeout(function () {
                            _data.timer = null;
                            _data.recognition.onend = null;
                            _data.recognition.stop();
                            _data.recognition = null;

                            var found = findKeyWord(_data.lastText);
                            if (found) {
                                _data.$image.attr('src', _data.imageSent);
                                if (_data.textSentColor) _data.$result.css({color: _data.textSentColor});
                                _data.$result.addClass('mic-text-sent');
                                vis.setValue(_data.oid, _data.finalTranscript);
                            }

                            _data.finalTranscript = '';
                            _data.lastText = '';

                            setTimeout(function () {
                                _data.$image.attr('src', _data.imageActive);
                                _data.$result.css({color: _data.originalColor});
                                _data.$result.hide().removeClass('mic-keyword-found mic-text-sent');
                                _data.$text.html(_('info_speak_now')).show();
                                startRecognition();
                            }, 1000);
                        }, 3000);
                    }
                };

                _data.recognition.lang     = _data.language;

                _data.recognition.start();
            }

            if (_data.speechMode === 'continuous') {
                if (!vis.editMode) {
                    startRecognition();
                } else {
                    $div.find('.mic-info-text').html(_('info_start'));
                }
            } else {
                $div.find('.mic-info-text').html(_('info_start'));
                if (!vis.editMode) {
                    $div.click(function () {
                        startRecognition();
                    });
                }
            }
        },
        getTimeInterval: function (oldTime, hoursToShow) {
            var result = '';

            var newTime = new Date ();

            if (!oldTime) return '';
            if (typeof oldTime === 'string') {
                oldTime = new Date(oldTime);
            } else {// 2000.01.01 00:00:00 = 946681200000
                if (typeof oldTime === 'number') oldTime = oldTime > 946681200000 ? new Date(oldTime) : new Date(oldTime * 1000);
            }

            var seconds = (newTime.getTime() - oldTime.getTime()) / 1000;

            if (hoursToShow && (seconds / 3600) > hoursToShow) return '';

            if (seconds < 60) {
                result = _('just&nbsp;now');
            } else
            if (seconds <= 3600)
                result = _('for&nbsp;%s&nbsp;min.', Math.floor (seconds / 60));
            else
            if (seconds <= 3600 * 24)
                result = _('for&nbsp;%s&nbsp;hr.&nbsp;and&nbsp;%s&nbsp;min.', Math.floor (seconds / 3600), (Math.floor (seconds / 60) % 60));
            else
            if (seconds > 3600 * 24 && seconds <= 3600 * 48)
                result = _('yesterday');
            else
            if (seconds > 3600*48) {
                result = _('for&nbsp;%s&nbsp;hours', Math.floor (seconds / 3600));
            }

            return result;
        },
        logout: function (el, data) {
            if (vis.editMode) return;
            var $el = $(el);
            $el.data('redirect', data.redirect_url);
            $el.data('app', data.in_app_close);

            $el.click(function () {
                if ($(this).data('app')) {
                    if (typeof logout === 'function') {
                        logout();
                    } else {
                        vis.showMessage(_('This option works only in APP'));
                    }
                } else if ($(this).data('redirect')) {
                    var redirect = $(this).data('redirect');
                    vis.conn.logout(function() {
                        window.location = redirect;
                    });
                } else {
                    vis.conn.logout(function(){
                        window.location.reload();
                    });
                }
            });
        },
        toggleFullScreen: function (wid, view, data, style) {
            var $div = $('#' + wid);

            var id = $div.attr('id');
            if (id && id.match(/_removed$/)) return;

            // if nothing found => wait
            if (!$div.length) {
                setTimeout(function () {
                    vis.binds.basic.toggleFullScreen(wid, view, data, style);
                }, 100);
                return;
            }

            var svgOn  = '<svg viewBox="0 0 24 24" style="display: inline-block; color: rgba(0, 0, 0, 0.87); fill: currentcolor; height: 24px; width: 24px; user-select: none; transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></svg>';
            var svgOff = '<svg viewBox="0 0 24 24" style="display: inline-block; color: rgba(0, 0, 0, 0.87); fill: currentcolor; height: 24px; width: 24px; user-select: none; transition: all 450ms cubic-bezier(0.23, 1, 0.32, 1) 0ms;"><path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"></path></svg>';

            if (!vis.editMode) {
                $div.unbind('click').click(function () {
                    if (vis.binds.basic.isFullScreen) {
                        vis.binds.basic.isFullScreen = false;
                        if (document.exitFullscreen) {
                            document.exitFullscreen();
                        } else if (document.mozCancelFullScreen) {
                            document.mozCancelFullScreen();
                        } else if (document.webkitExitFullscreen) {
                            document.webkitExitFullscreen();
                        }
                        $('#' + wid).find('.vis-fullscreen-icon').html(svgOn);
                    } else {
                        vis.binds.basic.isFullScreen = true;
                        var element = $('#vis_container')[0];
                        if (element.requestFullscreen) {
                            element.requestFullscreen();
                        } else if (element.mozRequestFullScreen) {
                            element.mozRequestFullScreen();
                        } else if (element.webkitRequestFullscreen) {
                            element.webkitRequestFullscreen();
                        } else if (element.msRequestFullscreen) {
                            element.msRequestFullscreen();
                        }
                        $('#' + wid).find('.vis-fullscreen-icon').html(svgOff);
                    }
                });
            }

            $div.find('.vis-fullscreen-icon').html(svgOn);
        }
    };

    $(document).mouseup(function () {
        if (vis.binds.basic.pressed) {
            clearInterval(vis.binds.basic.pressed);
            vis.binds.basic.pressed = null;
        }
    });

    if (vis.editMode) {
        vis.binds.basic.onOrientation = function (widgetID, view, newId, attr, isCss) {
            var data  = vis.views[view].widgets[widgetID].data;
            var style = vis.views[view].widgets[widgetID].style;
            var h = parseInt(style.height, 10);
            var w = parseInt(style.width, 10);

            if (data[attr] === 'vertical') {
                if (h < w) {
                    var t = style.height;
                    style.height = style.width;
                    style.width = t;
                    setTimeout(function () {
                        vis.showWidgetHelper(widgetID, true);
                    }, 0);
                    return ['width', 'height'];
                }
            } else {
                if (w < h) {
                    var t = style.height;
                    style.height = style.width;
                    style.width = t;
                    setTimeout(function () {
                        vis.showWidgetHelper(widgetID, true);
                    }, 0);
                    return ['width', 'height'];
                }
            }
        };
        vis.binds.basic.onAttrChanged = function (widgetID, view, newId, attr, isCss) {
            if (vis.binds.basic.groupTimer) clearTimeout(vis.binds.basic.groupTimer);
            vis.binds.basic.groupTimer = setTimeout(function () {
                vis.inspectWidgets(vis.activeViewDiv, vis.activeView, this.activeWidgets);
            }, 2000);
        };
    }
</script>

<!-- Basic Widgets -->


<script id="tplHtml"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="static"
        data-vis-prev='<img src="widgets/basic/img/Prev_HTML.png"></img>'
        data-vis-prev1='<div id="prev_tplFrame" style=" position: relative; text-align: initial;padding: 4px "><div class="vis-widget_prev vis-widget-lock" style="width: 80px; height: 80px; border: 3px solid rgb(73, 185, 255); border-radius: 20px;"><div style="top: 30px; color: rgb(73, 185, 255); font-size: 20px; text-align: center; padding-top: 32px;">HTML</div></div>'
        data-vis-name="HTML"
        data-vis-attrs="html/text;refreshInterval[0]/slider,0,180000,100">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 200px; height: 130px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body" <%= (el) -> vis.binds.basic.htmlRefresh(el, this.data.attr('html'), data.attr("refreshInterval")) %>>
            <%== this.data.attr('html') %>
        </div>
    </div>
</script>

<script id="tplShapes"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="static"
        data-vis-name="Svg shape"
        data-vis-prev='<div id="prev_tplShapes" style="position: relative; text-align: initial;padding: 4px "><div class="vis-widget_prev " style="width: 90px; height: 90px; left: 502px; top: 174px; position: absolute;"> <div class="vis-widget-prev-body"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="display: block;width: 100%;height: 100%;fill: rgb(255, 255, 255);stroke: rgb(60, 152, 211); stroke-width: 4px;"> <circle cx="50" cy="50" r="47"></circle></svg></div> </div></div>'
        data-vis-attrs="svgType[circle]/select,line,triangle,square,pentagone,hexagone,octagone,circle,star,arrow;strokeColor[#009cb3]/color;fill[#00b3ac]/color;strokeWidth[5]/slider,0,100,1;rotate/slider,0,360,1;scaleWidth[1]/slider,0,1,0.1;scaleHeight[1]/slider,0,1,0.1">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 100px; height: 100px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="-50 -50 100 100" style="display: block;width:100%; height:100%;fill:<%== this.data.attr('fill') %>;stroke:<%== this.data.attr('strokeColor')%>;stroke-width: <%== this.data.attr('strokeWidth') %>">
                <%
                var svg = '';
                var rotate      = parseFloat(this.data.attr('rotate')) || 0;
                var scaleWidth  = parseFloat(this.data.attr('scaleWidth')) || 1;
                var scaleHeight = parseFloat(this.data.attr('scaleHeight')) || 1;
                var strokeWidth = parseInt(this.data.attr('strokeWidth'), 10) || 0;

                if (this.data.svgType === 'triangle') {
                    svg = '<polygon transform="rotate(' + rotate + ')  scale(' + scaleWidth + ', ' + scaleHeight + ') " ' +
                        'points="' + vis.binds.basic.circlePoints(50 - strokeWidth, 3) + '"/>';
                } else if (this.data.svgType === 'line') {
                    svg = '<line  vector-effect="non-scaling-stroke"  transform="rotate(' + rotate + ')" x1="-50" y1="0" x2="50" y2="0"/>';
                } else if (this.data.svgType === 'circle') {
                    svg = '<circle transform="scale(' + scaleWidth + ', ' + scaleHeight + ') rotate(' + rotate + ')" cx="0" cy="0" r="' + (50 - parseInt(strokeWidth, 10) / 2) + '" />';
                } else if (this.data.svgType === 'pentagone') {
                    svg = '<polygon transform="rotate(' + rotate + ')  scale(' + scaleWidth + ', ' + scaleHeight + ') " ' +
                        'points="' + vis.binds.basic.circlePoints(50 - strokeWidth, 5) + '"/>';
                } else if (this.data.svgType === 'square') {
                    svg = '<polygon transform="rotate(' + rotate + ')  scale(' + scaleWidth + ', ' + scaleHeight + ') " ' +
                        'points="' + vis.binds.basic.circlePoints(50 - strokeWidth, 4) + '"/>';
                } else if (this.data.svgType === 'hexagone') {
                    svg = '<polygon transform="rotate(' + rotate + ')  scale(' + scaleWidth + ', ' + scaleHeight + ') " ' +
                        'points="' + vis.binds.basic.circlePoints(50 - strokeWidth, 6) + '"/>';
                } else if (this.data.svgType === 'octagone') {
                    svg = '<polygon transform="rotate(' + rotate + ')  scale(' + scaleWidth + ', ' + scaleHeight + ') " ' +
                        'points="' + vis.binds.basic.circlePoints(50 - strokeWidth, 8) + '"/>';
                } else if (this.data.svgType === 'star') {
                    svg = '<polygon transform="rotate(' + rotate + ')  scale(' + scaleWidth + ', ' + scaleHeight + ') " ' +
                        'points="' + vis.binds.basic.circlePoints(50 - strokeWidth, 5, 144) + '"/>';
                } else if (this.data.svgType === 'arrow') {
                    var points = vis.binds.basic.circlePoints(50 - strokeWidth * 4, 3, true);
                    var text = '';
                    for (var p = 0; p < points.length; p++) {
                        text += points.x + ',' + points.y;
                        if (points.length === p - 2) {
                            text += '0,0';
                        }
                    }
                    svg = '<polygon transform="rotate(' + rotate + ') translate(0,10)  scale(' + scaleWidth + ', ' + scaleHeight + ') " ' +
                        'points="0, -50 -43.3, 25 0,0 43.3, 25"/>';
                }
                %>
                <%== svg %>
                </g>
            </svg>
        </div>
    </div>
</script>

<script id="tplIFrame"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="static"
        data-vis-prev='<img src="widgets/basic/img/Prev_iFrame.png"></img>'
        data-vis-name="iFrame"
        data-vis-attrs="src;refreshInterval[0]/slider,0,180000,100;noSandbox/checkbox;refreshOnWakeUp/checkbox;refreshOnViewChange/checkbox;refreshWithNoQuery/checkbox;scrollX/checkbox;scrollY/checkbox;seamless[true]/checkbox">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top: 0px; left: 0px; width: 600px; height: 320px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <% if (vis.editMode) { %>
            <div class="editmode-helper" />
            <% } %>
            <iframe src="<%= this.data.attr('src') %>" <%= this.data.attr('noSandbox') ? '' : 'sandbox="allow-modals allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts"' %> style="position: absolute; border: 0; padding: 0; margin: 0; width: 100%; height: 100%;<%= this.data.attr('scrollX') == true ? 'overflow-x: scroll;' : 'overflow-x: hidden;' %><%= this.data.attr('scrollY') == true ? 'overflow-y: scroll;' : 'overflow-y: hidden;' %>" <%= this.data.attr('seamless') == true ? 'seamless' : '' %>></iframe>
            <div <%= (el) -> vis.binds.basic.iframeRefresh(el, data, this.view) %>></div>
        </div>
    </div>
</script>

<script id="tplImage"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="static"
        data-vis-prev='<img src="widgets/basic/img/Prev_Image.png"></img>'
        data-vis-name="Image"
        data-vis-attrs="src/image;stretch/checkbox;refreshInterval[0]/slider,0,180000,100;"
        data-vis-attrs0="refreshOnWakeUp/checkbox;refreshOnViewChange/checkbox;refreshWithNoQuery/checkbox;allowUserInteractions/checkbox;">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 200px; height: 130px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <% if (vis.editMode) { %>
                <div class="editmode-helper" />
            <% } %>
            <img class="<%= this.data.attr('stretch') ? 'vis-image' : '' %> <%= this.data.attr('allowUserInteractions') ? '' : 'vis-no-user-select vis-no-pointer-events' %>" style="top:0; left: 0; position: absolute; width: 100%; <%= this.data.attr('stretch') ? 'height: 100%;' : '' %>" <%= this.data.attr('src') ? 'src="' + this.data.attr('src') + '"' : '' %> />
            <div <%= (el) -> vis.binds.basic.imgRefresh(el, data, this.view) %> />
        </div>
    </div>
</script>

<script id="tplLink"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_tplLink.png"></img>'
        data-vis-set="basic"
        data-vis-type="static"
        data-vis-name="link"
        data-vis-attrs="html;href;target/auto,,_blank,_self,_parent,_top;alt">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 200px; height: 130px; " id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <a href="<%== this.data.attr('href') %>" target="<%== this.data.attr("target") %>" alt="<%== this.data.attr("alt") %>" style="text-decoration:none;width:100%;height:100%"><div style="width:100%;height:100%"><%== this.data.attr("html") %></div></a>
        </div>
    </div>
</script>

<script id="tplFrame"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<div id="prev_tplFrame" style=" position: relative; text-align: initial;padding: 4px "><div class="vis-widget_prev vis-widget-lock" style="width: 80px; height: 80px; border: 3px dashed rgb(60, 152, 211); border-radius: 20px;"><div style="top: 30px; color: rgb(60, 152, 211); font-size: 16px; text-align: center; padding-top: 31px;">BORDER</div></div>'
        data-vis-set="basic"
        data-vis-type="static"
        data-vis-name="Border"
        data-vis-attrs="title['Title'];title_font;title_color[black]/color;title_back/color;title_top[-10]/slider,-20,20,1;title_left[15]/slider,-20,30,1;header_height[0]/slider,0,100,1;header_color[black]/color">
    <div class="vis-widget <%== this.data.attr('class') %>" style="overflow:visible;width:50px;height:50px;border:1px solid #888" id="<%= this.data.attr('wid') %>" >
        <% if (this.data.attr('header_height')) { %>
	    <div style="width:100%;height:<%= this.data.attr('header_height') %>px;background-color:<%= this.data.attr('header_color') %>">
		<% } %>
        <div style="position: absolute;top:<%= this.data.attr('title_top') %>px;left:<%= this.data.attr('title_left') %>px;color:<%== this.data.attr('title_color') %>;background:<%== this.data.attr('title_back') %>;font:<%== this.data.attr('title_font') %>"><%== this.data.attr('title') %></div>
        <% if (this.data.attr('header_height')) { %>
        </div>
		<% } %>
    </div>
</script>

<script id="tplStatefulIFrame8"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_StatefulIFrame8.png"></img>'
        data-vis-type="stateful"
        data-vis-name="iFrame 8"
        data-vis-attrs="oid;refreshInterval[0]/slider,0,180000,100;count[1]/number;group.frames;src_(0-count);noSandbox/checkbox">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px; left: 0px; width: 600px; height: 320px;" id="<%= this.data.attr('wid') %>">
        <% if (vis.editMode) { %>
            <div class="editmode-helper"/>
        <% } %>
        <div class="vis-widget-body">
            <% if (vis.editMode) { %>
                <div class="editmode-helper"/>
            <% } %>
            <%
                var srcArr = [];
                var i = 0;
                while(data.attr('src_' + i) !== undefined) {
                    srcArr.push(data.attr('src_' + i));
                    i++;
                }
            %>
            <iframe class="vis-widget-element" <%= this.data.attr('noSandbox') ? '' : 'sandbox="allow-modals allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts"' %> data-oid="<%= this.data.attr('oid') %>" src="<%== vis.binds.stateful.value(srcArr, data.attr('oid')) %>" style="position: absolute; border: 0; padding: 0; margin: 0; width: 100%; height: 100%;"></iframe>
            <div <%= (el) -> vis.binds.stateful.iframe(el, srcArr, data.attr('refreshInterval')) %> />
        </div>
    </div>
</script>

<!-- basic Container -->
<script id="tplContainerView"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ContainerView.png"></img>'
        data-vis-type="container"
        data-vis-name="view in widget"
        data-vis-attrs="contains_view/views">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:400px; height: 270px;" id="<%= this.data.attr('wid') %>">
        <% if (vis.editMode) { %>
            <div class="editmode-helper"></div>
        <% } %>
        <div data-vis-contains="<%= this.data.attr('contains_view') %>" class="vis-widget-body vis-view-container">
        </div>
    </div>
</script>

<!-- Stateful Widgets -->
<script id="tplStatefulContainerView8"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_StatefulContainerView8.png"></img>'
        data-vis-type="stateful,container"
        data-vis-name="view in widget 8"
        data-vis-attrs="oid;persistent/checkbox;notIfInvisible/checkbox;count[1]/number;group.views;contains_view_(0-count)/views">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:400px; height: 270px;" id="<%= this.data.attr('wid') %>">
        <% if (vis.editMode) { %>
            <div class="editmode-helper" />
        <% } %>
        <%
            var viewArr = [];
            var i = 0;
            while (data.attr('contains_view_' + i) !== undefined) {
                viewArr.push(data.attr('contains_view_' + i));
                i++;
            }
        %>
        <div class="vis-widget-body">
            <div class="vis-view-container" data-oid="<%= data.attr('oid') %>" data-vis-contains="<%= vis.binds.stateful.value(viewArr, data.attr('oid')) %>" <%= (el) -> vis.binds.stateful.view(el, viewArr, data.attr('persistent'), data.attr('notIfInvisible')) %> />
        </div>
    </div>
</script>

<!-- TODO
<script type="text/ejs" id="tplStatefulIFrame8Persistent" class="vis-tpl" data-vis-set="basic" data-vis-name="stateful - iFrame 8 (persistent)" data-vis-attrs="oid;refreshInterval;src_(0-1)">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px; left: 0px; width: 600px; height: 320px;" id="<%= this.data.attr('wid') %>">
            <% if (vis.editMode) { %>
                <div class="editmode-helper" />
            <% } %>
          <div class="vis-widget-body">
            <% if (vis.editMode) { %>
                <div class="editmode-helper" />
            <% } %>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_0') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_1') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_2') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_3') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_4') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_5') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_6') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <iframe class="vis-widget-element" src="<%= this.data.attr('src_7') %>" style="position: absolute; border:0; padding:0; margin:0; width: 100%; height:100%;"></iframe>
            <div <%= (el) -> vis.binds.stateful.iframe(el, [data.attr("src_0"), data.attr("src_1"), data.attr("src_2"), data.attr("src_3"), data.attr("src_4"), data.attr("src_5"), data.attr("src_6"), data.attr("src_7"]), data.attr("refreshInterval")) %> />
        </div>
    </div>
</script>
-->

<script id="tplStatefulImage8"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_StatefulImage.png"></img>'
        data-vis-type="stateful"
        data-vis-name="Image 8"
        data-vis-attrs="oid;refreshInterval[0]/slider,0,180000,100;count[1]/number;group.images;src_(0-count)/image">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 200px; height: 130px;" id="<%= this.data.attr('wid') %>">
        <% if (vis.editMode) { %>
            <div class="editmode-helper" />
        <% } %>
        <div class="vis-widget-body">
            <% if (vis.editMode) { %>
                <div class="editmode-helper" />
            <% } %>
            <%
                var srcArr = [];
                var i = 0;
                while(data.attr("src_" + i) !== undefined) {
                    srcArr.push(this.data.attr("src_" + i));
                    i++;
                }
            %>
            <img class="vis-widget-element" data-oid="<%= this.data.attr('oid') %>" style="position:absolute; width:100%;" src="<%== vis.binds.stateful.value(srcArr, this.data.attr('oid')) %>" />
            <div <%= (el) -> vis.binds.stateful.image(el, srcArr, data.attr('refreshInterval')) %> />
        </div>
    </div>
</script>

<script id="tplHtmlNav"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="static,navigation"
        data-vis-prev='<img src="widgets/basic/img/Prev_HTMLnavigation.png"></img>'
        data-vis-name="HTML navigation"
        data-vis-attrs="html;nav_view;sync/checkbox;body-background/color;group.effects;hide_effect/effect;hide_duration/slider,0,10000,100;hide_options/effect-options;show_effect/effect;show_duration/slider,0,10000,100;show_options/effect-options">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 200px; height: 130px; " id="<%= this.data.attr('wid') %>" <%= (el) -> vis.binds.basic.navigation(el, {nav_view: data.attr('nav_view'), hideOptions: {effect: data.attr('hide_effect'), options: (data.attr('hide_options') ? data.attr('hide_options') : {}),duration:data.attr('hide_duration')}, showOptions: {effect:data.attr('show_effect'), options: (data.attr('show_options') ? data.attr('show_options') : {}), duration: data.attr('show_duration')}, sync: data.attr('sync'), background: data.attr('body-background')}) %>>
        <div class="vis-widget-body">
            <%== this.data.attr('html') %>
        </div>
    </div>
</script>

<script id="tplFilterDropdown"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_FilterDropdown.png"></img>'
        data-vis-set="basic"
        data-vis-type="filter"
        data-vis-name="filter - dropdown"
        data-vis-attrs="filters;group.effects;hide_effect/effect;hide_duration/slider,0,10000,100;show_effect/effect;show_duration/slider,0,10000,100">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px; left:0px; width: 200px; height: 40px;" id="<%= this.data.attr('wid') %>" <%= (el) -> vis.binds.basic.filterDropdown(el, data.attr('filters'), data.attr('hide_effect'), data.attr('hide_duration'), data.attr('show_effect'), data.attr('show_duration')) %>>
        <div class="vis-widget-body">
            <select id="" name="">
                <option value=""><%= _('all') %></option>
            </select>
        </div>
    </div>
</script>

<script id="tplValueFloat"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueFloat.png"></img>'
        data-vis-name="Number"
        data-vis-attrs="oid;html_prepend;html_append_singular;html_append_plural;group.extended;digits;is_comma[true]/checkbox;is_tdp/checkbox;factor[1];oid-quality;class_true;class_false;test_html">
    <div class="vis-widget <%== (vis.states.attr(this.data['oid-quality'] + '.val') === 'true' ||  vis.states.attr(this.data['oid-quality'] + '.val') === true) ? this.data.attr('class_true') : this.data.attr('class_false') %> <%== this.data.attr('class') %>" style="top: 0; left: 0; width: 60px; height: 18px" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') %>">
                <%== this.data.attr('html_prepend') %><%= vis.binds.basic.formatFloat(this.data) %><%== (parseFloat(vis.binds.basic.formatFloat(this.data)) === 1 ? this.data.attr('html_append_singular') : this.data.attr('html_append_plural')) %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueString"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val"
        data-vis-name="String"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueString.png"></img>'
        data-vis-attrs="oid;html_prepend;html_append;test_html">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px; left: 0px; width: 50px; height: 20px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') ? ((this.data.attr('oid').indexOf('"') !== -1) ? '' : this.data.attr('oid')) : this.data.attr('oid') %>">
                <%== this.data.attr("html_prepend") %><%= (vis.editMode && this.data.attr('test_html')) ? this.data.attr('test_html') : this.data.attr('oid') ? ((this.data.attr('oid').indexOf('"') !== -1) ? this.data.oid.substring(1, this.data.oid.length - 1) : (vis.states.attr(this.data.oid + '.val'))) : (vis.states.attr(this.data.oid + '.val')) %><%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueStringRaw"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueStringRaw.png"></img>'
        data-vis-name="String (unescaped)"
        data-vis-attrs="oid;html_prepend;html_append;test_html">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px; left: 0px; width: 50px; height: 20px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') %>">
                <%== this.data.attr('html_prepend') %><%== (vis.editMode && this.data.attr('test_html')) ? this.data.attr('test_html') : (typeof app !== 'undefined' ? app.replaceFilePathSrc(vis.states.attr(this.data.oid + '.val')) : vis.states.attr(this.data.oid + '.val')) %><%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueStringImg"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueStringImg.png"></img>'
        data-vis-type="val"
        data-vis-name="String img src"
        data-vis-attrs="oid;html_prepend;html_append;refreshInterval[0]/slider,0,180000,100">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px; left:0px; width:60px; height: 40px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') %>">
                <%== this.data.attr('html_prepend') %>
                <img src="<%= (typeof app !== 'undefined' ? app.replaceFilePathImg(vis.states.attr(this.data.oid + '.val')) : vis.states.attr(this.data.oid + '.val')) || '' %>" width="100%" />
                 <div <%= (el) -> vis.binds.basic.imgRefresh(el, vis.states.attr(data.oid + '.val' ), data, this.view) %> />
                <%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueTimestamp"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val,timestamp"
        data-vis-name="Timestamp"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueTimestamp.png"></img>'
        data-vis-attrs="oid;show_interval/checkbox;format_date/auto,YYYY.MM.DD hh:mm:ss,DD.MM.YYYY hh:mm:ss,YYYY.MM.DD,DD.MM.YYYY,YYYY/MM/DD hh:mm:ss,YYYY/MM/DD,hh:mm:ss;html_prepend;html_append;test_html">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top: 0px; left: 0px; width: 50px; height: 20px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') %>">
                <%== this.data.attr('html_prepend') %><%== (vis.editMode && this.data.attr('test_html')) ? this.data.attr('test_html') : vis.binds.basic.formatDate(vis.states.attr(this.data.oid + '.ts'), this.data.attr('format_date'), this.data.attr('show_interval')) %><%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueLastchange"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val,timestamp"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueLastchange.png"></img>'
        data-vis-name="Last change Timestamp"
        data-vis-attrs="oid;show_interval/checkbox;format_date/auto,YYYY.MM.DD hh:mm:ss,DD.MM.YYYY hh:mm:ss,YYYY.MM.DD,DD.MM.YYYY,YYYY/MM/DD hh:mm:ss,YYYY/MM/DD,hh:mm:ss;html_prepend;html_append;test_html">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px; left: 0px; width: 50px; height: 20px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') %>">
                <%== this.data.attr('html_prepend') %><%== (vis.editMode && this.data.attr('test_html')) ? this.data.attr('test_html') : vis.binds.basic.formatDate(vis.states.attr(this.data.oid + '.lc'), this.data.attr('format_date'), this.data.attr('show_interval')) %><%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueList"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueList.png"></img>'
        data-vis-type="val"
        data-vis-name="ValueList Text"
        data-vis-attrs="oid;html_prepend;html_append;valuelist/text;test_list/nselect,,0,1,2,3,4,5,6,7,8,9,10,11,12">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px;left:0px;width:60px;height:20px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') %>">
                <%== this.data.attr('html_prepend') %><%= (function (that){var list = (that.data.valuelist ? that.data.valuelist.split(';') : []); var val = list[(vis.editMode && (that.data.attr('test_list') || that.data.attr('test_list') == '0')) ? parseInt(that.data.attr('test_list')) : parseInt(vis.states.attr(that.data.oid + '.val'), 10)]; if (val) val = val.replace('§§', ';'); return val;})(this) %><%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueListHtml"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueListHtml.png"></img>'
        data-vis-type="val"
        data-vis-name="ValueList HTML"
        data-vis-attrs="oid;html_prepend;html_append;valuelist/text;test_list/nselect,,0,1,2,3,4,5,6,7,8,9,10,11,12">
    <div class="vis-widget <%== this.data.attr('class') %>" style="top:0px;left:0px;width:60px;height:20px;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <div data-oid="<%= this.data.attr('oid') %>">
                <%== this.data.attr('html_prepend') %><%== (function (that){var list = (that.data.valuelist ? that.data.valuelist.split(';') : []); var val = list[(vis.editMode && (that.data.attr('test_list') || that.data.attr('test_list') == '0')) ? parseInt(that.data.attr('test_list')) : parseInt(vis.states.attr(that.data.oid + '.val'), 10)]; if (val) val = val.replace('§§', ';'); return val;})(this) %><%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueListHtml8"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueListHtml8.png"></img>'
        data-vis-type="val"
        data-vis-name="ValueList HTML Style"
        data-vis-attrs="oid;html_prepend;html_append;count[2]/number,0,10,1;value(0-count);style(0-count);test_list/nselect,,0,1,2,3,4,5,6,7,8,9,10,11,12">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 100px; height: 30px;" id="<%= this.data.attr('wid') %>">
        <%
            var slist = [];
            var i = 0;
            while (data['style' + i] !== undefined) {
                slist[i] = data['style' + i]; i++;
            }
        %>
        <div class="vis-widget-body" style="<%== slist[(vis.editMode && (this.data.attr('test_list') || this.data.attr('test_list') == '0')) ? parseInt(this.data.attr('test_list')) : (parseInt((vis.states.attr(this.data.oid + '.val') == true ? 1 : (vis.states.attr(this.data.oid + '.val') == false ? 0 : vis.states.attr(this.data.oid + '.val'))), 10))] %>">
            <div data-oid="<%= this.data.attr('oid') %>">
               <%== this.data.attr('html_prepend') %><%
                   var list = [];
                   var j = 0;
                   while (data['value' + j] !== undefined) {
                        list[j] = data['value' + j];
                        if (list[j]) list[j] = list[j].replace('§§', ';');
                        j++;
                   }
                   %><%== list[(vis.editMode && (this.data.attr('test_list') || this.data.attr('test_list') == '0')) ? parseInt(this.data.attr('test_list')) : (parseInt((vis.states.attr(this.data.oid + '.val') == true ? 1 : (vis.states.attr(this.data.oid + '.val') == false ? 0 : vis.states.attr(this.data.oid + '.val'))), 10))] %><%== this.data.attr('html_append') %>
            </div>
        </div>
    </div>
</script>

<script id="tplValueBool"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueBool.png"></img>'
        data-vis-type="val"
        data-vis-name="Bool HTML"
        data-vis-attrs="oid;html_prepend;html_append;html_false;html_true">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:76px; height:76px;" id="<%= this.data.attr('wid') %>"  data-oid="<%= this.data.attr('oid') %>" >
        <div class="vis-widget-body">
            <%== this.data.attr('html_prepend') %>
            <% if (vis.binds.basic.isFalse(vis.states.attr(this.data.oid + '.val'), this.data.attr('min'), this.data.attr('max'))) { %>
                <%== this.data.attr("html_false") %>
            <% } else { %>
                <%== this.data.attr('html_true') %>
            <% } %>
            <%== this.data.attr('html_append') %>
        </div>
    </div>
</script>

<script id="tplAckBool"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_AckBool.png"></img>'
        data-vis-type="val"
        data-vis-name="AckFlag HTML"
        data-vis-attrs="oid;html_prepend;html_append;html_false;html_true">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:76px; height:76px;" id="<%= this.data.attr('wid') %>"  data-oid="<%= this.data.attr('oid') %>" >
        <div class="vis-widget-body">
            <%== this.data.attr('html_prepend') %>
            <%
            var str = vis.states.attr(this.data.oid + ".ack");
            var val = parseFloat(str);
            var state;
            if (str === false || str === "false" || val == 0) {
            %>
            <%== this.data.attr('html_false') %>
            <% } else { %>
            <%== this.data.attr('html_true') %>
            <% } %>
            <%== this.data.attr('html_append') %>
        </div>
    </div>
</script>

<script id="tplValueBoolCheckbox"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueBoolCheckbox.png"></img>'
        data-vis-set="basic"
        data-vis-type="ctrl"
        data-vis-name="Bool Checkbox"
        data-vis-attrs="oid;html_prepend;html_append">
    <div class="vis-widget <%== this.data.attr('class') %>" style="" id="<%= this.data.attr('wid') %>" >
        <div class="vis-widget-body">
			<%== this.data.attr('html_prepend') %>
			<input type="checkbox" name="<%= this.data.attr('wid') %>_checkbox" id="<%= this.data.attr('wid') %>_checkbox" data-oid="<%= this.data.attr('oid') %>" <%= (el) -> vis.binds.basic.checkbox(el) %>/>
			<%== this.data.attr('html_append') %>
        </div>
    </div>
</script>

<script id="tplValueInput"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueInput.png"></img>'
        data-vis-type="ctrl"
        data-vis-update-style="true"
        data-vis-name="Input val"
        data-vis-attrs="oid;html_prepend;html_append;numeric/checkbox;min;max;autoSet/checkbox;readOnly/checkbox">
    <div class="vis-widget <%== this.data.attr('class') %>" style="background: white; color: black; border: 2px inset" id="<%= this.data.attr('wid') %>" >
        <div class="vis-widget-body">
			<%== this.data.attr('html_prepend') %>
			<input type="text" <%= (this.data.attr('readOnly') === true || this.data.attr('readOnly') === 'true') ? 'readonly' : '' %> data-oid="<%= this.data.attr('oid') %>" <%= (el) -> vis.binds.basic.input(el, this.data) %> style="width: calc(100% - 5px);"/>
			<%== this.data.attr('html_append') %>
        </div>
    </div>
</script>

<script id="tplValueBoolSelect"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueBoolSelect.png"></img>'
        data-vis-type="ctrl"
        data-vis-name="Bool Select"
        data-vis-attrs="oid;html_prepend;html_append;text_true;text_false">
    <div class="vis-widget <%== this.data.attr('class') %>" style="overflow:false" id="<%= this.data.attr('wid') %>" >
        <div class="vis-widget-body"  style="overflow:false">
			<%== this.data.attr('html_prepend') %>
			<select id="<%= this.data.attr('wid') %>_select" data-oid="<%= this.data.attr('oid') %>">
				<option value="0" selected='selected'><%= this.data.attr('text_false') %></option>
				<option value="1"><%= this.data.attr('text_true') %></option>
			</select>
			<div <%= (el) -> vis.binds.basic.select(el) %>></div>
			<%== this.data.attr('html_append') %>
        </div>
    </div>
</script>

<script id="tplValueBoolCtrl"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueBoolCtrl.png"></img>'
        data-vis-type="ctrl"
        data-vis-name="Bool HTML"
        data-vis-attrs="oid;min;max;html_prepend;html_append;html_false;html_true;"
        data-vis-attrs1="group.ccontrol;urlTrue;urlFalse;oidTrue/id;oidFalse/id;">
    <div
        class="vis-widget <%== this.data.attr('class') %>"
        style="width:76px; height:76px;"
        id="<%= this.data.attr('wid') %>"
        data-oid="<%= this.data.attr('oid') %>"
        data-min="<%= this.data.attr('min') %>"
        data-max="<%= this.data.attr('max') %>"
        data-as-button="<%= this.data.attr('asButton') %>"
        data-url-true="<%=  this.data.attr('urlTrue') %>"
        data-url-false="<%= this.data.attr('urlFalse') %>"
        data-oid-true="<%=  this.data.attr('oidTrue') %>"
        data-oid-false="<%= this.data.attr('oidFalse') %>"
        <%= (el) -> vis.binds.basic.toggle(el) %>>
        <div class="vis-widget-body">
			<%== this.data.attr('html_prepend') %>
			<% if (vis.binds.basic.isFalse(vis.states.attr(this.data.oid + '.val'), this.data.attr('min'), this.data.attr('max'))) { %>
			    <%== this.data.attr('html_false') %>
			<% } else { %>
			    <%== this.data.attr('html_true') %>
			<% } %>
			<%== this.data.attr('html_append') %>
        </div>
    </div>
</script>

<script id="tplValueBoolCtrlSvg"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueBoolCtrlSvg.png"></img>'
        data-vis-type="ctrl,state"
        data-vis-name="Bool SVG"
        data-vis-attrs="oid;no_control/checkbox;"
        data-vis-attrs0="svg_false[<polygon points='100,10 40,198 190,78 10,78 160,198' style='fill:lime§ stroke:purple§ stroke-width:5§ fill-rule:nonzero' transform='scale(0.4)'/>]/text;"
        data-vis-attrs1="svg_true[<polygon points='100,10 40,198 190,78 10,78 160,198' style='fill:yellow§ stroke:red§ stroke-width:5§ fill-rule:nonzero' transform='scale(0.4)'/>]/text;"
        data-vis-attrs2="svg_opacity/slider,0,1,0.05">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:76px; height:76px;" id="<%= this.data.attr('wid') %>" data-oid="<%= this.data.attr('oid') %>">
        <div class="vis-widget-body">
            <% vis.binds.basic.showSvg(this.data.attr('class'), this.view, this.data.attr('wid'), this.data.attr('oid'), this.data.attr('svg_opacity'), this.data.attr('svg_false'), this.data.attr('svg_true'), null, this.data.attr('no_control')) %>
        </div>
    </div>
</script>

<script id="tplBasicState"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_BasicState.png"></img>'
        data-vis-set="basic"
        data-vis-type="ctrl"
        data-vis-name="HTML State"
        data-vis-attrs="oid;html;value;urlValue">
    <div
        class="vis-widget <%== this.data.attr('class') %>"
        style="width:76px; height:76px;"
        id="<%= this.data.attr('wid') %>"
        data-oid="<%= this.data.attr('oid') %>"
        data-url-value="<%= this.data.attr('urlValue') %>"
        data-val="<%= this.data.attr('value') %>"
        <%= (el) -> vis.binds.basic.state(el) %>
        >
        <div class="vis-widget-body">
			<%== this.data.attr("html") %>
        </div>
    </div>
</script>

<script id="tplRedNumber"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val"
        data-vis-name="Red Number"
        data-vis-prev='<img src="widgets/basic/img/Prev_RedNumber.png"></img>'
        data-vis-attrs="oid;type[circle]/select,circle,pin;html_prepend;html_append_singular;html_append_plural">
    <% if (this.data.attr('type') === 'pin') { %>
        <div class="vis-widget <%== this.data.attr('class') %>" style="width: 33px; height: 61px; padding-left: 4px" id="<%= this.data.attr('wid') %>" data-oid="<%= this.data.attr('oid') %>" <%= (el) -> vis.binds.basic.hideOnFalse(el) %>>
            <div class="vis-widget-body" >
                <img src="widgets/basic/img/pin_red5.svg" style="width: 100%; height: 100%">
                <div style="position:absolute; top: 22%; width: 95%; text-align: center">
                    <%== this.data.attr('html_prepend') %><%= parseInt(vis.states.attr(this.data.oid + '.val'), 10) %><%== (parseInt(vis.states.attr(this.data.oid + '.val'), 10) === 1 ? this.data.attr("html_append_singular") : this.data.attr("html_append_plural")) %>
                </div>
            </div>
        </div>
    <% } else { %>
        <div class="vis-widget <%== this.data.attr('class') %>" style="padding: 3px; width: auto; min-width: 21px; height: 21px; border-radius:16px; border: 3px solid white; background-color: rgb(214, 69, 69); color:white; font:normal normal normal 20px/normal Helvetica; text-align: center;" id="<%= this.data.attr('wid') %>" data-oid="<%= this.data.attr('oid') %>" <%= (el) -> vis.binds.basic.hideOnFalse(el) %>>
            <div class="vis-widget-body" >
                <%== this.data.attr('html_prepend') %><%= parseInt(vis.states.attr(this.data.oid + '.val'), 10) %><%== (parseInt(vis.states.attr(this.data.oid + '.val'), 10) === 1 ? this.data.attr("html_append_singular") : this.data.attr("html_append_plural")) %>
            </div>
        </div>
    <% } %>
</script>

<script id="tplBulbOnOffCtrl"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_BulbOnOffCtrl.png"></img>'
        data-vis-set="basic"
        data-vis-type="ctrl"
        data-vis-name="Bulb on/off"
        data-vis-attrs="oid;min;max;icon_off[img~bulb_off.png]/image;icon_on[img~bulb_on.png]/image;readOnly/checkbox;"
        data-vis-attrs0="group.ccontrol;urlTrue;urlFalse;oidTrue/id;oidFalse/id;oidTrueValue;oidFalseValue;"
        >
    <div
        data-oid="<%= this.data.attr('oid') %>"
        class="vis-widget <%== this.data.attr('class') %>"
        id="<%= this.data.attr('wid') %>"
        style="width: 44px; height: 59px"
        data-read-only="<%=  this.data.attr('readOnly') %>"
        data-min="<%= this.data.attr('min') %>"
        data-max="<%= this.data.attr('max') %>"
        data-url-true="<%=  this.data.attr('urlTrue') %>"
        data-url-false="<%= this.data.attr('urlFalse') %>"
        data-oid-true="<%=  this.data.attr('oidTrue') %>"
        data-oid-false="<%= this.data.attr('oidFalse') %>"
        data-oid-true-value="<%=  this.data.attr('oidTrueValue') %>"
        data-oid-false-value="<%= this.data.attr('oidFalseValue') %>"
        <%= (el) -> vis.binds.basic.toggle(el) %>
        >
        <div class="vis-widget-body">
            <% if (vis.binds.basic.isFalse(vis.states.attr(this.data.oid + '.val'), this.data.attr('min'), this.data.attr('max'))) { %>
                <img src="<%== this.data.attr('icon_off') ? this.data.attr('icon_off') : 'img/bulb_off.png' %>" width="100%"/>
            <% } else { %>
                <img src="<%== this.data.attr('icon_on') ? this.data.attr('icon_on') : 'img/icon_on.png' %>" width="100%"/>
            <% } %>
        </div>
    </div>
</script>

<script id="tplValueFloatBar"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val,bar"
        data-vis-name="Bar"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueFloatBar.png"></img>'
        data-vis-attrs="oid;min[0];max[100];orientation[horizontal]/select,horizontal,vertical/onOrientation;color[blue]/color;border;shadow;reverse/checkbox">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 240px; height: 20px; border: 1px solid #888" id="<%= this.data.attr('wid') %>">
        <div data-oid="<%= this.data.attr('oid') %>" class="vis-widget-body"
        style="<%= (this.data.attr('orientation') === 'vertical') ? ('height: ' + vis.binds.basic.getCalc(this.data) + ';' + ((this.data.border) ? ' width:  calc(100% - ' + vis.binds.basic.extractWidth(this.data.border, 2) + ');' : '') + (this.data.reverse === 'true' || this.data.reverse === true ? 'left: 0px; position: absolute; bottom: 0%;' : '')) : (((this.data.border) ? " height: calc(100% - " + vis.binds.basic.extractWidth(this.data.border, 2) + ');' : '') + 'width: ' + vis.binds.basic.getCalc(this.data) + ';' + (this.data.reverse === 'true' || this.data.reverse === true ? 'float: right; ' : '')) %>background-color:<%= this.data.color %>; border: <%= this.data.border %>; box-shadow: <%= this.data.shadow %>"></div>
    </div>
</script>

<script id="tplNote"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val"
        data-vis-name="Note"
        data-vis-prev='<img src="widgets/basic/img/Prev_Note.png"></img>'
        data-vis-attrs="oid;max_width[300];html_prepend;html_append;test_text">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:50px; height:50px; border:1px solid #888; background: rgba(255,255,105,0.8)" id="<%= this.data.attr('wid') %>" onclick="vis.binds.basic.editNote('<%= this.data.attr('wid') %>', '<%= this.data.attr('max_width') %>', '<%= this.data.attr('min_width') %>', '<%= this.data.attr('min_height') %>', '<%= this.data.attr('oid') %>')">
		<div data-oid="<%= this.data.attr('oid') %>" id="div_<%= this.data.attr('wid') %>" style="padding: 10px">
			<%== this.data.attr('html_prepend') %><%= (this.data.test_text && vis.editMode) ? this.data.test_text : (vis.states.attr(this.data.oid + '.val') == null ? "" : vis.states.attr(this.data.oid + '.val')) %><%== this.data.attr('html_append') %>
		</div>
    </div>
</script>

<script id="tplTableBody"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="json,table"
        data-vis-name="Table"
        data-vis-prev='<img src="widgets/basic/img/Prev_TableBody.png"></img>'
        data-vis-attrs="table_oid/id;"
        data-vis-attrs0="static_value[[{^Title^: ^first^, ^Value^: 1, ^_Description^: ^Value1^}, {^Title^: ^second^, ^Value^: 2, ^_Description^: ^Value2^}]]/text;"
        data-vis-attrs1="event_oid/id;new_on_top/checkbox;ack_oid/id;hide_header/checkbox;show_scroll/checkbox;detailed_wid/widget;max_rows/number;"
        data-vis-attrs2="colCount/number;group.header/byindex;colName(1-colCount);colWidth(1-colCount);colAttr(1-colCount);"
        data-vis-attrs-not-used="btn_print;view_for_print/views"
        >
    <div class="vis-widget <%== this.data.attr('class') %>" id="<%= this.data.attr('wid') %>" style="width: 300px; height: 150px; background: #d3d3d3">
       <% vis.binds.table.showTable(this.view, this.data.attr('wid'), this.data); %>
    </div>
</script>

<script id="tplHtmlLogout"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="tools"
        data-vis-prev='<img src="widgets/basic/img/Prev_HtmlLogout.png"></img>'
        data-vis-name="HTML logout"
        data-vis-attrs="html[<button style=^cursor: pointer^>Logout</button>]/text;redirect_url;in_app_close/checkbox">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width: 70px; height: 30px; cursor: pointer" id="<%= this.data.attr('wid') %>" <%= (el) -> vis.binds.basic.logout(el, this.data) %> >
        <div class="vis-widget-body">
            <%== this.data.attr('html') %>
        </div>
    </div>
</script>

<!--script id="tplDialog"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="table"
        data-vis-name="Dialog"
        data-vis-attrs="show/checkbox;trigger_id/id;button(1-3);title;text;image/image;width[400]/slider,50,1000,10;height[200]/slider,50,1000,10;modal/checkbox;_no_style[true]/hidden;_no_move[true]/hidden;_no_resize[true]/hidden;margin_left[0]/slider,0,200,1;margin_top[0]/slider,0,200,1"
        >
    <%
        var options =  {
            trigger_id:  this.data.attr('trigger_id'),
            buttons:     [this.data.attr('button1'), this.data.attr('button2'), this.data.attr('button3')],
            image:       this.data.attr('image'),
            title:       this.data.attr('title'),
            text:        this.data.attr('text'),
            width:       this.data.attr('width'),
            height:      this.data.attr('height'),
            show:        this.data.attr('show'),
            modal:       this.data.attr('modal'),
            margin_left: this.data.attr('margin_left'),
            margin_top:  this.data.attr('margin_top')
        };
        vis.binds.table.showDialog(this.view, this.data.attr('wid'), options);
    %>
</script-->

<script id="tplValueGesture"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val,tools"
        data-vis-prev='<img src="widgets/basic/img/Prev_ValueGesture.png"></img>'
        data-vis-name="Gesture indicator"
        data-vis-no-gestures="true"
        data-vis-attrs="html_prepend;html_append_singular;html_append_plural;group.extended;digits[0];is_comma[true]/checkbox;is_tdp/checkbox;factor[1];test_html">
    <div class="vis-widget <%== this.data.attr('class') %>" style="height: 21px; border: 1px solid #c7c7c7; border-radius: 5px; text-align: center; padding-top: 6px; box-shadow: 2px 2px 5px 1px gray; padding-left: 2px; padding-right: 2px; background: lightgray;" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <% vis.binds.basic.createValueGesture(this.data.wid, this.view, this.data, this.style); %>
        </div>
    </div>
</script>

<script id="tplSpeech2Text"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-type="val"
        data-vis-prev='<img src="widgets/basic/img/Prev_Speech2Text.png"></img>'
        data-vis-name="Speech to text"
        data-vis-no-gestures="true"
        data-vis-attrs="oid;speechMode[single]/select,single,startstop,continuous;language/select,,en-US,de,ru-RU;keywords;"
        data-vis-attrs0="group.image;noImage/checkbox;imageInactive[widgets~basic~img~micInactive.svg]/image;imageActive[widgets~basic~img~micActive.svg]/image;imageStarted[widgets~basic~img~micStarted.svg]/image;imageDetected[widgets~basic~img~micDetected.svg]/image;imageSent[widgets~basic~img~micSent.svg]/image;imageHeightPx[70]/slider,0,200,1;imageWidthPx[70]/slider,0,200,1;"
        data-vis-attrs1="group.text;noText/checkbox;noResults/checkbox;keyWordColor[#FFB051]/color;textSentColor[#7E88D3]/color;">
    <div class="vis-widget <%== this.data.attr('class') %>" style="height: 77px; width: 500px" id="<%= this.data.attr('wid') %>">
        <div class="vis-widget-body">
            <table style="height: 100%; width: 100%"><tr>
                <td style="<%= this.data.attr('noImage') ? 'display: none' : '' %>"><img class="mic-image" style="height: <%= this.data.attr('imageHeightPx') %>px; width: <%= this.data.attr('imageWidthPx') %>px" src="<%= this.data.attr('imageInactive') %>" /></td>
                <td class="mic-text" style="width: 100%">
                    <div class="mic-info-text" style="<%= this.data.attr('noText')    ? 'display: none' : '' %>"></div>
                    <div class="mic-results"   style="<%= this.data.attr('noResults') ? 'display: none' : '' %>"></div>
                </td>
            </tr></table>
        </div>
    </div>
    <% vis.binds.basic.speech2text(this.data.wid, this.view, this.data, this.style); %>
</script>

<script id="tplFullScreen"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_FullScreen.png"></img>'
        data-vis-set="basic"
        data-vis-type="tools"
        data-vis-name="Full Screen"
        data-vis-attrs="">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:43px; height:43px; background: #AAAAAA; cursor: pointer; opacity: 0.9" id="<%= this.data.attr('wid') %>">
		<div class='vis-fullscreen-icon' style="padding: 10px"></div>
		<%= vis.binds.basic.toggleFullScreen(this.data.wid, this.view, this.data, this.style); %>
    </div>
</script>

<script id="tplScreenResolution"
        type="text/ejs"
        class="vis-tpl"
        data-vis-prev='<img src="widgets/basic/img/Prev_ScreenResolution.png"></img>'
        data-vis-set="basic"
        data-vis-type="tools"
        data-vis-name="Screen Resolution"
        data-vis-attrs="">
    <div class="vis-widget <%== this.data.attr('class') %>" style="width:170px; height:75px; border: 1px solid #888; font-size: 12px; opacity: 0.8" id="<%= this.data.attr('wid') %>">
		<div id="div_<%= this.data.attr('wid') %>" style="padding: 10px">
			Default view: <span class='vis-resolution-default-view'></span><br>
			Width: <span class='vis-resolution-width'></span><br>
			Height: <span class='vis-resolution-height'></span><br>
			Instance: <span><%== vis.instance ? vis.instance : vis.binds.basic.createScreenText() %></span>
		</div>
		<%= vis.binds.basic.detectScreen(this.data.attr('wid')) %>
    </div>
</script>


<script id="_tplGroup"
        type="text/ejs"
        class="vis-tpl"
        data-vis-set="basic"
        data-vis-attrs="group.objects;attrCount[1]/slider,0,20,1;attrName(1-attrCount)//onAttrChanged;attrType(1-attrCount)/select,,id,checkbox,image,color,views,html,widget,history/onAttrChanged;"
>
    <div class="vis-widget <%== this.data.attr('class') %>" style="overflow: visible" id="<%= this.data.attr('wid') %>"></div>
</script>