;(function(factory) {
    "use strict";

    var _cmd_ = {};

    if (typeof exports === 'object') {
        if (typeof require === 'function'){
            var ecmd = require('./ecmd').ECMD;

            _cmd_ = factory;

            Object.keys(ecmd).forEach(function (cmd) {
                    _cmd_[cmd] = ecmd[cmd];
                });

            exports.CMD = _cmd_;
        } else {
            exports.CMD = factory;
        }
    } else {
        _cmd_ = factory;

        if (window && window.mcConst && window.mcConst._CMD_){
            Object.keys(_cmd_).forEach(function (cmd) {
                window.mcConst._CMD_[cmd] = _cmd_[cmd];
            });
        }

        window.getCMD = function getCMD(){
            if (window.hasOwnProperty('_ECMD_')){
                Object.keys(window._ECMD_).forEach(function (cmd) {
                    _cmd_[cmd] = window._ECMD_[cmd];
                });
            }

            return _cmd_;
        }
    }
})({
        Login        : 'login',
        Register     : 'register',
        Reminde      : 'reminde',
        OK           : 'OK',
        Ping         : 'ping',
        History      : 'history',
        NewFoto      : 'newfoto',
        Logs         : 'logs',
        StopLogs     : 'stopLogs',
        Blocked      : 'blocked',
        cLog         : 'cLog',
        AdsFiles     : 'adsFiles',
        checkSSL     : 'checkSSL',
        generateCert : 'generateCert',
        checkPush    : 'checkPush',
        getUrl       : 'getUrl',
        
        getUrlProcess: 'getUrlProcess',
        getUrlAbort  : 'getUrlAbort',
        getUrlError  : 'getUrlError',

        encode_qrcode: 'encode_qrcode',

        // === FTP == browser -> node ================

        bn_ftp_get_list : "bn0001", //
        bn_ftp_login    : "bn0002", //

        // === FTP == node -> browser ================

        nb_ftp_get_list : "nb0001", //
        nb_ftp_login    : "nb0002", //
        nb_ftp_error    : "nb0003", //

        // ===========================================

        sc_drop_connect: '9999',

        // = Client CMD ==============================
        cs_hello                                : '0001', // команда-приветствие, отправляется от клиента при подключении к серверу. С этой команды начинается любое подключение к серверу.
        cs_login                                : '0003', // подключение к серверу под заданной учётной записью. Логин может происходить по одному из вариантов: UIN, ник или адрес электронной почты.
        cs_register_new_user                    : '0004', // зарегистрировать на сервере нового пользователя.
        cs_domain_login                         : '0005', // подключение к серверу с доменной авторизацией в Active Directory.
        cs_restore_account                      : '0006', // восстановление своей учётной записи
        cs_work_time_upload_old_data            : '0007', // отправка на сервер данных о рабочем времени клиента, пока тот был в офлайн (нужна доработка)
        cs_restore_connect_to_channels          : '0008', // восстановить вход в открытые каналы после отключения от сервера (нужна доработка)
        cs_get_bbs                              : "0009", // получить полный текст доски объявлений
        cs_get_adv_new_data                     : "000A", // запрос новых данных на рекламу
        cs_special_ping                         : "000B", // пинг сервера, проверка связи
        cs_ping                                 : "000B", // пинг от клиента, проверка, есть ли соединение. Если длительное время от клиентов не было пинга или любого другого запроса - соединение считается "мёртвым" и автоматически удаляется с сервера.

        cs_ping2                                : "000C",

        cs_get_channels_list                    : "000D", // получить с сервера список созданных каналов
        cs_get_actions_list                     : "000E", // получить список ACTIONs, если они есть и к ним есть доступ
        cs_work_time_control_active_caption     : "000F", // отправка на сервер данных о рабочем времени, нужна доработка
        // deprecated cs_get_small_user_info                  : "0010", // получить краткую информацию о пользователе
        cs_private_request                      : "0011", // запрос на открытие привата с указанным пользователем
        cs_get_hello_msg                        : "0012", // запрос содержимого приветствия канала
        cs_pong                                 : "0013", // ответ на серверную команду sc_ping
        cs_get_contacts_list                    : "0014", // получить список личных персональных контактов.
        cs_get_common_contacts_list             : "0015", // получить список общих контактов (древовидный список контактов, общий для всех пользователей сервера).
        cs_put_msg2txt_channel                  : "0016", // отправить сообщение в текстовый канал
        cs_private_msg                          : "0017", // отправить приватное сообшение другому пользователю
        cs_join_txt_channel                     : "0018", // подключиться к существующему текстовому каналу
        cs_leave_txt_channel                    : "0019", // выйти из текстового канала
        cs_add_new_bbs                          : "001A", // отправить новое сообщение на доску объявлений

        cs_create_txt_channel                   : "001D", // создать новый текстовый канал.
        cs_get_uin_info                         : "001E", // получить полную информацию об указанном пользователе
        cs_get_uin_foto                         : "001F", // получить фотографию пользователя
        cs_get_remote_uin_current_time          : "0020", // получить текущее системное время удалённого пользователя
        cs_send_my_current_time                 : "0021", // отправить свою текущую дату и время указанному пользователю
        cs_get_user_computer_info               : "0022", // получить IP/MAC адрес и название компьютера удалённого клиента
        cs_get_active_window_caption            : "0023", // получить заголовок активного окна пользователя
        cs_active_window_caption                : "0024", // отправка заголовка активного окна
        cs_get_ignores_list                     : "0025", // получить список игноров для указанного пользователя
        cs_update_ignores_list                  : "0026", // обновить персональный список игноров (доработать разбор списка)
        cs_get_favorite_channels                : "0027", // получить список "любимых" каналов
        cs_add_favorite_channel                 : "0028", // добавить канал с указаненым идентификатором в список "любимых"
        cs_delete_favorite_channel              : "0029", // удалить текстовый канал из списка "любимых"
        cs_get_msgtemplates                     : "002A", // получить список персональных "быстрых" сообщений
        cs_update_msgtemplates                  : "002B", // сохранить на сервере в своём аккаунте список "быстрых" сообщений
        cs_set_account_password                 : "002C", // установить новый пароль для своей учётной записи

        cs_add_personal_contact_group           : "001B", // добавить новую группу в персональную панель контактов
        cs_delete_id_from_personal_contacts     : "001C", // удалить группу контактов из личного списка контактов
        cs_add_new_contact                      : "002D", // добавить пользователя в личный список контактов
        cs_rename_contacts_group                : "002F", // переименовать личную группу контактов
        cs_move_personal_contact                : "0030", // перенести персональный контакт из одной группы в другую

        cs_open_remote_computer_shares          : "0031", // окрыть удалённый компьютер по сети Проводником (показать открытые ресурсы (shares))
        cs_forcibly_join_to_text_channel        : "0032", // принудительно включить выбранного пользователя в указанный текстовый канал
        cs_change_txtch_topic                   : "0033", // изменить тему текстового канала
        cs_get_public_ftp_info                  : "0034", // получить информацию с сервера о публичном доступе к общему FTP серверу
        cs_get_channel_history_messages         : "0035", // получить историю сообщений в указанном текстовом канале
        cs_rename_text_channel                  : "0036", // переименовать существующий текстовый канал
        cs_ignore_get                           : "0037", // добавить в игнор пользователя и / или получить информацию об его игнорировании
        cs_add_ignore                           : "0038", // добавить юзера в игнор-список (либо обновить данные)
        cs_clear_text_channel                   : "0039", // очистить выбранный текстовый канал от всех сообщений у всех находящихся в нём пользователей
        cs_personal_message2txtch               : "003A", // персональное/важное сообщение лично другому пользователю в текстовый канал
        cs_block_mac_by_uin                     : "003B", // заблокировать MAC адрес пользователя по его UIN
        cs_block_ip_by_uin                      : "003C", // заблокировать IP адрес пользователя по его UIN
        cs_kill_user                            : "003D", // отключить пользователя от сервера
        cs_kick_from_txt_channel                : "003E", // выгнать пользователя из текстового канала
        cs_private_beep                         : "003F", // отправить пользователю звуковой сигнал
        cs_get_server_uptime                    : "0040", // получить аптайм сервера MyChat
        cs_get_server_version                   : "0041", // получить версию сервера
        cs_halt_user                            : "0042", // отключить пользователя от сервера и завершить его приложение
        cs_set_state                            : "0043", // установить свой сетевой статус (свободен, занят и т.п.)
        cs_typing_notify                        : "0044", // отправить уведомление пользователю о том, что мы ему что-то пишем в привате
        cs_get_user_state                       : "0045", // получить статус другого пользователя
        cs_set_uin_foto                         : "0046", // установить фотографию для своего профиля
        cs_quit                                 : "0047", // пользователь отключается от сервера и посылает ему уведомление об этом
        cs_files_offline_ok                     : "0048", // пользователь согласился принять отложенные для него на сервере файлы
        cs_files_offline_late                   : "0049", // мы не хотим принимать отложенные для нас файлы прямо сейчас, примем их позже
        cs_files_offline_delete                 : "004A", // удалить все файлы, которые были отправлены офлайн указанным пользователем
        cs_get_user_quick_info                  : "004B", // получить краткую информацию об указанном пользователе
        cs_raw_data                             : "004C", // отправка произвольного пакета данных для онлайн-клиента
        cs_raw_data_txt_channel                 : "004D", // отправка произвольного пакета данных в текстовый канал
        cs_action                               : "004E", // выполнение MyChat Action
        cs_stat                                 : '0058', // отправить на сервер статистику использования сервисов чата
        cs_fatal_error_info                     : '0054', // отправить на сервер данные о произошедшей фатальной ошибке, приведшей к краху клиентского приложения

        // === file transfer ===

        cs_files_request_transfer               : '004F', // отправить запрос на отправку файлов и/или папок другому пользователю
        cs_files_transfer_deny                  : '0050', // отказаться принимать файлы от другого пользователя
        cs_files_transfer_accept                : '0051', // согласиться принимать файлы от другого пользователя
        cs_files_transfer_abort                 : '0052', // прервать передачу файлов
        cs_files_internal_send_idx              : '0053', // уведомление о начале передачи очередного файла из списка файлов для отправки
        cs_files_transfer_request_abort         : '0055', // отправить пользователю отказ от принятия файлов
        cs_files_internal_sended_ok_idx         : '0056', // успешно передан файл с указанным индексом из общего списка передаваемых файлов в сеансе связи
        cs_files_transfer_progress              : '0061', // отправить информацию другому пользователю о прогрессе передаваемых файлов. Отправляется не чаще раза в секунду
        cs_files_success_recieved               : '0062', // уведомление отправителю файлов, что все файлы успешно приняты
        cs_files_request_timeout                : '0057', // команда, которая отправляется автоматически, по истечении периода времени, когда получатель ничего не ответил на
                                                          // запрос приёма файлов(например, его не было за компьютером). Передача файлов в этом случае должна быть отменена автоматически
        // ==========================

        cs_send_broadcast                       : '005A', // отправить оповещение
        cs_get_broadcast_presets_names          : '005B', // получить список персональных пресетов для рассылки оповещений
        cs_delete_broadcast_preset              : '005C', // удалить шаблон списка пользователей для оповещения
        cs_add_broadcast_preset                 : '005D', // добавить новый пресет для оповещений
        cs_broadcast_readed_notify              : '005E', // уведомить отправителя оповещения персональным сообщением, что его сообщение только что было прочитано получателем, набор объектов
        cs_broadcast_just_readed                : '005F', // отправить на сервер уведомление об обязательном прочтении полученных оповещений (или одного оповещения), набор объектов

        // ==========================

        cs_get_users_list                       : '0059', // получить с сервера список пользователей (ФИО, пол, аватар и т.п.) согласно запросу
        cs_set_uin_info                         : '0068', // обновить информацию о профиле пользователя
        cs_find_users                           : '0060', // поиск пользователей на сервере согласно заданным критериям. Есть два варианта объекта
        cs_ban_user                             : '0066', // наложить наказание на пользователя (бан). По истении строка наказания оно автоматически снимается сервером.
                                                          // Наказание может наложить только оператор канала
        cs_set_user_online_notify               : '0067', // установить статус онлайн-уведомления о присутствии другого пользователя в сети
        cs_get_private_info                     : '0078', // получить краткую информацию о пользователе, с которым открывается приватный разговор
        cs_send_messages_buffer                 : "0079", // отправка буфера сообщений на сервер перед разрывом соединения

        cs_media_call                           : '007A',
        cs_media_call_accept                    : '007B',
        cs_media_call_reject                    : '007C',
        cs_media_call_close                     : '0080',
        cs_media_call_error                     : '0081', //произошла ошибка при сеансе аудио или видео связи
        cs_media_call_busy                      : '008E',

        cs_web_get_user_foto_file               : '007D',
        cs_web_support_i_am_busy                : '0094', // если пользователю WEB-поддержки с сайта приходит сообщение не от оператора, с кем он в данный момент говорит, он отвечает этой командой

        cs_adm_list_users                       : "0086", // получить список пользователей с сервера по заданным критериям. Нужны административные права
        cs_adm_get_server_info                  : '0090',
        cs_adm_get_user_profile                 : "0091", // получение полной информации о профиле любого пользователя, административная команда
        cs_adm_list_roles                       : '008B', // получить список групп прав пользователей (роли), нужны административные права
        cs_adm_set_user_password                : '0097', // изменить пароль пользователя
        cs_adm_create_user                      : '0096', // создать нового пользователя, административная команда
        cs_adm_remove_user                      : '0095', // удалить пользователя, административная команда
        cs_adm_modify_user_profile              : '0098', // модификация профиля юзера
        cs_adm_clear_user_foto                  : '0099', // удаление фотографии указанного пользователя, админкоманда
        cs_adm_get_server_options               : '009A', // получить все настройки сервера, админкоманда
        cs_adm_get_server_net_interfaces        : '009C', // получить список реальных IP всех сетевых интерфейсов сервера MyChat, админкоманда
        cs_adm_get_user_info_by_preset          : '009D', // получить список любых полей из профиля пользователя, админкоманда
        cs_adm_set_server_options               : '009B', // установить настройки сервера, админкоманда
        cs_adm_remove_all_logs                  : '009E', // удалить все протоколы на сервере, админкоманда
        cs_adm_make_backup_server_db            : '009F', // создать резервную копию базы данных сервера, админкоманда

        cs_adm_set_user_foto                    : "00A0", // назначить фото для пользователя

        cs_adm_get_job_positions_list           : '0093', // получить список должностей компании, административная команда
        cs_adm_job_positions_del                : '00A4', // удалить должность по индексу
        cs_adm_job_positions_add                : '00A3', // добавить новую должность
        cs_adm_job_positions_set_sequence       : '00A2', // установить последовательность должностей компании, массив, админкоманда (последовательсть ID должностей, те, что первые - "старше" тех, кто дальше)
        cs_adm_job_positions_modify             : '00A5', // изменить должность

        cs_adm_role_add                         : '00A6', // добавить новую группу прав
        cs_adm_role_delete                      : '00A7', // удалить группу прав
        cs_adm_role_modify                      : '00A8', // изменить группу прав
        cs_adm_role_set_rights                  : '00A9', // установить новые правила для группы прав
        cs_adm_role_users_list                  : '00AA', // получить список пользователей, входящих в заданную группу прав
        cs_adm_role_apply_to_users              : '00AB', // назначить роль указанному списку пользователей

        cs_send_invite                          : '00AC', // todo: отправить приглашение для любого пользователя присоединиться к MyChat

        cs_adm_check_smtp                       : '00AD', // проверить работоспособность системы отправки почты

        cs_adm_enter_mychat_reg_data            : '00AE', // ввести регистрационные данные для MyChat Server
        cs_adm_enter_mychat_guest_reg_data      : '00AF', // ввести серийный номер для MyChat Guest

        cs_adm_get_websupport_groups            : '00B0', // получить список групп для веб-поддержки
        cs_adm_add_user_to_websupport_group     : '00B1', // перенести пользователя в заданную группу веб-поддержки
        cs_adm_delete_user_from_websupport      : '00B2', // удаление пользователя с группы веб-поддержки
        cs_adm_add_websupport_group             : '00B3', // добавить новую группу WEB-поддержки
        cs_adm_delete_websupport_group          : '00B4', // удалить группу веб-поддержки
        cs_adm_rename_websupport_group          : '00B5', // переименовать группу веб-поддержки
        cs_adm_get_websupport_group_users       : '00B6', // получить список пользователей указанной группы WEB-поддержки

        cs_adm_get_custom_options               : '00B7', // запросить кастомные настройки

        cs_adm_get_total_contacts_list          : '00B8', // запросить общий список контактов
        cs_adm_tcl_add_group                    : '00B9', // добавить новую группу в общий список контактов
        cs_adm_tcl_del_ids_list                 : '00BA', // удалить список групп и/или пользователей из общего списка контактов
        cs_adm_tcl_add_users_list_to_group      : '00E3', // добавить список пользователей в указанную группу
        cs_adm_tcl_move_users_and_groups        : '00E4', // переместить пользователей и/или группы в пределах общего списка контактов
        cs_adm_tcl_rename_group                 : '00E5', // переименовать группу в общем списке контактов

        cs_adm_import_users                     : '00BB', //

        cs_adm_return_server_to_zero_state      : '00BD', // вернуть базу данных MyChat Server в первоначальное состояние, все данные будут удалены. Админкоманда

        cs_adm_set_custom_options               : '00BC', // установить заданные настройки, количество полей может быть переменным
        cs_adm_get_licenses                     : '00BE', // получить информацию по лицензиям MyChat Server

        cs_adm_get_antiflood_filter_data        : '00BF', // получить информацию по антифлуд-фильтрам. Админкоманда
        cs_adm_set_antiflood_filter_data        : '00C0', // установить настройки серверных антифлуд-фильтров. Админкоманда
        cs_adm_modify_flood_except_users        : '00C1', // изменить список пользователей, которых не касаются настройки антифлуд-фильтров
        cs_adm_get_flood_except_users_list      : '00C2', // получить список пользователей, которых не касаются настройки антифлуд-фильтров

        cs_adm_get_allow_ip_list                : '00C3', // получить список IP адресов ("белый" список), которым разрешено подключаться к MyChat Server
        cs_adm_add_new_ip_to_allow_list         : '00C4', // добавить новый IP адрес, маску или диапазон в список разрешённых адресов
        cs_adm_delete_allow_ip                  : '00C5', // удалить IP адрес из списка разрешённых адресов для подключения
        cs_adm_clear_allow_ip_list              : '00C6', // полностью очистить список разрешённых IP адресов

        cs_adm_get_blocked_ip_list              : '00C7', // получить список заблокированных IP адресов (масок и диапазонов). Админкоманда
        cs_adm_add_ip_to_block_list             : '00C8', // добавить IP адрес в список заблокированных
        cs_adm_delete_blocked_ip                : '00C9', // удалить из списка заблокированных IP адрес/маску/диапазон
        cs_adm_clear_blocked_ip_list            : '00CA', // очистить список заблокированных IP адресов/масок/диапазонов

        cs_adm_get_blocked_mac_list             : '00CB', // получить список заблокированных MAC адресов
        cs_adm_delete_blocked_mac               : '00CC', // удалить заблокированный MAC адрес из общего списка
        cs_adm_add_mac_to_block_list            : '00CD', // добавить MAC адрес в список заблокированных
        cs_adm_clear_blocked_mac_list           : '00CE', // очистить список заблокированных MAC адресов

        cs_adm_get_deny_nicks_list              : '00CF', // получить список заблокированных ников в JSON-формате
        cs_adm_add_deny_nick                    : '00D0', // добавить новый ник в заблокированные
        cs_adm_delete_deny_nick                 : '00D1', // удалить ник из списка блокировок
        cs_adm_clear_deny_nicks_list            : '00D2', // полностью очистить список заблокированных ников

        cs_adm_get_deny_conf_list               : '00D3', // получить список заблокированных конференций в JSON-формате
        cs_adm_add_deny_conf                    : '00D4', // добавить новую конференцию в список заблокированных
        cs_adm_delete_deny_conf                 : '00D5', // удалить конференцию из блек-листа
        cs_adm_clear_deny_conf_list             : '00D6', // полностью очистить список заблокированных конференций

        cs_adm_get_bad_words_filters_data       : '00D7', // получить информацию по фильтрам плохих слов в чате
        cs_adm_set_bad_words_filter_data        : '00D8', // сохранить данные по фильтрам "плохих" слов
        cs_adm_get_bad_words_list               : '00D9', // получить полный список "плохих" слов. Админкоманда
        cs_adm_add_bad_word_to_filters          : '00DA', // добавить новое "плохое" слово в список фильтрации, админкоманда
        cs_adm_del_bad_word_from_filters        : '00DB', // удалить "плохое" слово и общего списка
        cs_adm_clear_bad_words_list             : '00DC', // полностью очистить список "плохих" слов, админкоманда
        cs_adm_load_badwords_except_confs       : '00DD', // получить список конференций, в которых отключен фильтр мата
        cs_adm_add_badwords_except_conf         : '00DE', // добавить новую конференцию в список исключений антимат-фильтра
        cs_adm_del_badwords_except_conf         : '00DF', // удалить конференцию из списка исключений антимат-фильтра
        cs_adm_clear_badwords_except_confs      : '00E0', // очистить список исключений конференций антимат-фильтров

        cs_adm_export_users_to_csv              : '00E1', // экспорт списка пользователей в CSV файл
        cs_adm_multiply_modify_users            : '00E2', // множественное изменение данных пользователей
        cs_get_online_users_states              : '00E6', // получить список UIN-ов и статусов всех пользователей, которые в данный момент есть онлайн
        cs_get_depts_list                       : '00E7', // получить список подразделений компании

        cs_adm_get_all_text_confs               : '00E8', // получить список всех текстовых конференций

        cs_adm_force_update_global_contacts     : '00E9', // принудительно обновить кеш общего списка контактов и разослать его всем онлайн-пользователям

        cs_adm_get_bans_list                    : '00EA', // получить список всех банов, которые в данный момент актуальны на сервере. Админкоманда
        cs_adm_del_bans                         : '00EB', // снять указанные баны по индексам, админкоманда
        cs_adm_get_moderators                   : '00EC', // получить список модераторов, админкоманда
        cs_adm_get_conf_names_by_uid_list       : '00ED', // получить список названий конференций по их UID
        cs_adm_delete_moderators                : '00EE', // удалить список модераторов
        cs_adm_add_moderator                    : '00EF', // добавить модератора конференции
        cs_adm_del_moderator_confs              : '00F0', //

        cs_get_broadcasts_history               : '00F1', //

        cs_get_random_uin                       : '00F3', // получить случайный UIN из списка людей онлайн
        cs_set_custom_ignore                    : '00F4', // добавить игнор для указанного пользователя
        cs_del_custom_ignore                    : '00F5', //  игнор для указанного пользователя

        cs_adm_get_auto_conf_list               : '00F6', // получить список автосоздаваемых конференций на сервере
        cs_adm_del_auto_conf                    : '00F7', // удаление автосоздаваемой конференции по идентификатору
        cs_adm_add_auto_conf                    : '00F8', // создать новый автосоздаваемый канал
        cs_adm_update_auto_conf                 : '00F9', // обновить данные об австосоздаваемой конференции
        cs_adm_add_group_to_auto_conf           : '00FA', // добавить группу для включения в автосоздаваемую конференцию
        cs_adm_del_group_from_auto_conf         : '00FB', // удалить группу пользователей из автосоздаваемой конференции

        cs_adm_get_bbs_msg_list                 : '00FC', // получить список актуальных сообщений на доске объявлений
        cs_adm_bbs_clear_actual                 : '00FD', // удалить все актуальные сообщения на доске объявлений
        cs_adm_bbs_get_msg                      : '00FE', // получить данные сообщение на доске объявлений по его идентификатору
        cs_adm_bbs_modify_msg                   : '00FF', // изменить сообщение на доске объявлений, админкоманда
        cs_adm_bbs_del_messages                 : '0100', // удалить актуальные сообщения на доске объявлений по их индексу
        cs_adm_add_bbs_message                  : '0101', // добавить новое сообщение на доску объявлений

        cs_adm_save_ad_options                  : '0102', // сохранить данные по настройке Active Directory интеграции
        cs_adm_get_ad_options                   : '0103', // получить настройки по Active Directory интеграции

        cs_adm_import_ad_users                  : '0104', // импортировать выбранных пользователей active directory

        cs_adm_get_update_packet_data           : '0105', // получить данные update-пакета для клиентов MyChat
        cs_adm_upload_update_packet             : '0106', // загрузить пакет обновления на сервер. Административная команда

        cs_adm_get_online_users_list            : '0107', // получить список онлайн-пользователей
        cs_adm_kill_users                       : '0108', // отключить от сервера указанный список пользователей (разорвать соединение). В ответ приходит sc_adm_command_complete с командой cs_adm_kill_users
        cs_adm_halt_users                       : '0109', // отправить списку пользователей команду завершения работы приложения с последующим отключением от сервера.
                                                          // В ответ приходит sc_adm_command_complete с командой cs_adm_halt_users
        cs_adm_get_ad_users_list                : '010A', // получить с сервера Active Directory список пользователей
        cs_sync_private_history_last            : '010B', // получить последние N сообщений из приватного разговора с указанным пользователей. Можно запросить максимум 100 сообщений
        cs_sync_private_history                 : '010C', // получить логи разговоров в привате (синхронизация)

        cs_adm_get_script                       : '010D', // получить скрипт по его ID
        cs_adm_get_script_event_states          : '010E', // получить список статусов доступных скриптов. Нужны админправа
        cs_adm_script_check_syntax              : '010F', // проверить синтаксис написанного серверного скрипта
        cs_adm_script_onoff                     : '0110', // включение выключение скрипта
        cs_adm_script_run                       : '0111', // запуск скрипта
        cs_adm_script_delete                    : '0112', // удалить скрипт
        cs_adm_script_save                      : '0113', // сохранить скрипт
        cs_adm_script_create                    : '0114', // создать скрипт

        cs_adm_restart_server_services          : '0115', // принудительный перезапуск встроенного WEB-сервера, админкоманда

        cs_adm_get_active_conf_list             : '011B', // получить список работающих конференций, админкоманда
        cs_adm_kill_txt_conf                    : '011C', // удалить текстовую конференцию с сервера (не автосоздаваемую). Админкоманда. В ответ приходит complete: cs_adm_kill_txt_conf либо ошибка
        cs_adm_get_users_in_conf                : '011D', // получить список пользователей в конференции
        cs_adm_kick_users_from_conf             : '011E', //выгнать из конференции указанных пользователей

        cs_info                                 : '077C', //

        cs_adm_remove_conversations             : '0183', // удалить любые протоколы разговоров на сервере и у клиентов за всё время
        cs_live_reconnect                       : '01AF', // лайв переподключение андроида

        // ==== KANBAN =========================================================

        cs_kanban_get_projects_list             : '0117', // получить список проектов kanban
        cs_kanban_get_stages_list               : '0118', // получить список этапов проекта
        cs_kanban_get_tasks_list                : '0119', // получить список задач kanban-доски
        cs_kanban_get_tags_list                 : '011A', // получить список тегов kanban-доски
        cs_kanban_add_project                   : '0120', // добавить новый проект на kanban-доску
        cs_kanban_add_stage                     : '0121', // добавить новый stage на kanban доску
        cs_kanban_delete_stage                  : '0122', // удалить этап указанного проекта с kanban-доски
        cs_kanban_modify_stage                  : '0123', // изменить этап проекта kanban-доски
        cs_kanban_add_task                      : '013B', // добавить новую задачу на kanban-доску
        cs_kanban_task_move                     : '013C', // перенос задачи в новый stage
        cs_kanban_task_remove                   : '013D', // удаление задачи
        cs_kanban_task_edit                     : '013E', // редактирование задачи
        cs_kanban_add_comment                   : '013F', // добавление нового комментария к таску на kanban-доске
        cs_kanban_get_comments                  : '0140', // получить список комментариев к задаче на kanban-доске
        cs_kanban_delete_comment                : '0141', // удалить комментарий к задаче с доски kanban
        cs_kanban_close_project                 : '0142', // закрыть проект kanban
        cs_kanban_reopen_project                : '0143', // открыть заново уже закрытый проект kanban
        cs_kanban_delete_project                : '0144', // удалить kanban проект
        cs_kanban_edit_project                  : '0145', // изменить kanban-проект
        cs_kanban_get_personal_options          : '0149', // получить персональный набор опций клиента по его UIN
        cs_kanban_save_personal_options         : '014A', // сохранить персональный набор настроек. JSON объект, любые поля

        cs_kanban_get_project_info              : '014C', // получить краткую информацию о проекте
        cs_kanban_get_task_info                 : '014D', // получить краткую информацию о задаче

        cs_kanban_get_last_performers           : '0153', // получить последних исполнителей задач для указанного проекта
        cs_kanban_get_project_tags_list         : '0168', // получить список тегов для конкретного проекта
        cs_kanban_get_dashboard                 : '0169', // получить краткую сводную информацию о проектах Kanban

        // ==============================================================

        cs_get_personal_options                 : '0149', // получить персональный набор опций клиента по его UIN
        cs_save_personal_options                : '014A', // сохранить персональный набор настроек. JSON объект, любые поля

        cs_browser_info                         : '0124', // информация о браузере пользователя, если это web-клиент

        cs_media_offer                          : '0125', // создание медиа-запроса к клиенту
        cs_media_answer                         : '0126', // создание медиа-ответа на запрос media offer
        cs_media_ice_candidate                  : '0127', // ответ STUN/TURN сервера для собеседника
        cs_media_change_settings                : '0128', // изменение настроек медиа-данных пользователя (аудио/видео)
        cs_media_ready                          : '0129', // NodeWebKit клиента успешно стартовал и работает
        cs_media_exit_from_mid                  : '012A', // пользователь вышел из media-канала

        cs_import_personal_contacts             : '012B', // импорт персональных контактов

        cs_adm_get_client_options_presets       : '012C', // получить список шаблонов настроек клиентов, админкоманда
        cs_adm_del_client_options_preset        : '012D', // удалить шаблон настроек клиента по его идентификатору, админкоманда
        cs_adm_create_client_options_preset     : '012E', // создать новый шаблон настроек для клиентов, админкоманда
        cs_adm_update_client_options_preset     : '012F', // изменить шаблон настроек, админкоманда
        cs_adm_apply_roles_to_options_presets   : '0131', // назначить роли групп прав пользователей для наборов настроек, массив

        cs_adm_add_new_user_group               : '0132', // создать новую группу пользователей
        cs_adm_get_user_groups                  : '0133', // получить список существующих групп пользователей
        cs_adm_get_group_users_list             : '0134', // получить список пользователей указанный группы
        cs_adm_add_users_to_group               : '0135', // добавить список пользователей в группу
        cs_adm_remove_users_from_group          : '0136', // удалить пользователей из группы
        cs_adm_rename_group_of_users            : '0137', // переименовать указанную группу пользователей
        cs_adm_delete_groups_list               : '0138', // удалить список групп пользователей

        cs_adm_set_integration_tool_options     : '0139', // установить настройки интеграции инструмента (phpbb... etc.)
        cs_adm_get_integration_tool_options     : '013A', // получить настройки интеграции инструмента (phpbb... etc.)

        cs_adm_get_check_domains_list           : '0146', // получить список доменов с адресами и портами, которые используются для проверки наличия пользователей в данных доменах
        cs_adm_add_check_domain                 : '0147', // добавить домен в список доменов для проверки возможности логинов доменных пользователей
        cs_adm_delete_check_domain              : '0148', // удалить домен из списка доменов для проверки подключающихся доменных пользователей

        cs_adm_get_allowed_and_blocked_plugins  : '014E', // получить списки разрешённых и запрещённых плагинов
        cs_adm_add_allowed_or_blocked_plugins   : '014F', // добавить названия плагинов в список запрещённых или разрешённых клиентских плагинов
        cs_adm_delete_allowed_or_blocked_plugin : '0150', // удалить плагин из списка разрешённых или запрещённых клиентских плагинов

        cs_adm_change_mychat_server             : '0151', // изменить параметры подключения клиентов к серверу MyChat
        cs_adm_get_script_info                  : '0152', // получить краткую информацию о скрипте, админкоманда

        // == FORUM ===========================================

        cs_forum_get_structure                  : '0156', // получить структуру форума (разделы и топики, в JSON)
        cs_forum_create_section                 : '0157', // добавить новый раздел в форум
        cs_forum_delete_section                 : '0158', // удаление раздела форума
        cs_forum_change_section                 : '0159', // перемещение/переименование раздела форума
        cs_forum_create_topic                   : '015A', // добавить новый топик в форум
        cs_forum_change_topic                   : '015B', // перемещение/переименование топика форума
        cs_forum_create_post                    : '015C', // добавить новый пост в форум

        cs_forum_delete_post                    : '015D', // удалить сообщение из форума
        cs_forum_delete_topic                   : '015E', // удалить тему из форума
        cs_forum_change_post                    : '015F', // перемещение/переименование сообщения форума
        cs_forum_get_topic_posts                : '0160', // получить список сообщений указанного топика форума
        cs_forum_get_section_info               : '0161', // получить информацию о секции (список топиков, краткая информация о них: LastChange, UIN, DisplayName, Sex, Avatar, DateTime, CountMessages)

        cs_get_book                             : '0164', // получить справочник с сервера
        cs_is_file_exists                       : '0165', // узнать, есть ли файл с таким хэш-кодом на сервере. Параметры Where и ID потом вернутся обратно пользователю в команде-ответке
        cs_get_image_thumbs                     : '0166', // получить уменьшенную копию изображения с сервера

        cs_create_token                         : '0154', // создать токен для быстрого доступа в какой-нибудь сервис чата
        cs_login_by_token                       : '0155', // логин в MyChat/kanban/forum/web по токену
        cs_get_removed_user_info                : '016F', // получить краткую информацию об удалённом пользователе

        cs_adm_get_integration_telegram_users   : '016B', // получить список пользователей для интеграции с Telegram
        cs_adm_integration_telegram_delete_user : '016C', // удалить Telegram пользователя из списка для интеграции
        cs_adm_integration_telegram_modify_user : '016D', // изменить параметры Telegram пользователя из списка для интеграции
        cs_adm_integration_telegram_clear_users_list: '016E', // очистить список пользователей для интеграции с Telegram

        cs_integration_icq_set_account          : '0170', // привязать ICQ аккаунт к своей учётной записи
        cs_integration_icq_send_message         : '0171', // отправить сообщение пользователю ICQ
        cs_adm_delete_conf_message              : '0172', // удалить сообщение из текстовой конференции

        cs_adm_get_history_info_private         : '0173', // админкоманда, получить информацию по сообщениям в привате за диапазон времени. В ответ приходит 8107 sc_adm_history_info_private
        cs_adm_get_history_private              : '0174', // админкоманда, получение истории приватов двух юзеров по диапазону индексов
        cs_adm_get_history_info_conf            : '0175', // админкоманда, получить информацию по сообщениям в конференции за диапазон времени. В ответ приходит 8109 sc_adm_history_info_conf
        cs_adm_get_history_conf                 : '0176', // админкоманда, получение истории в конференции по диапазону индексов
        cs_adm_get_history_private_user_pairs   : '0177', // админкоманда, получить все пары приватных разговоров за все время, ответ будет 810B sc_adm_history_private_user_pairs

        cs_adm_check_ports                      : '017A', // проверить, не заняты ли порты указанных сервисов, админкоманда. Если всё ок, будет complete, если нет - ошибка с первым "неудачным" портом

        cs_moder_delete_conf_message            : '017B', // удалить сообщение из текстовой конференции, нужны права для удаления сообщений в конференциях из раздела "Администрирование"

        cs_adm_reconnect_users2autoconf         : '017D', // добавить/выгнать пользователей автосоздаваемой конференции, которую только что меняли

        cs_adm_get_blocked_hwid_list            : '017E', // получить список заблокированных HardwareID, админкоманда
        cs_adm_delete_blocked_hwid              : '017F', // удалить заблокированный HardwareID адрес из общего списка
        cs_adm_clear_blocked_hwid_list          : '0180', // очистить список заблокированных HardwareID на сервере
        cs_adm_add_hwid_to_block_list           : '0181', // добавить HardwareID клиента в список блокировок
        cs_adm_get_system_logs                  : '0182', // получить системные логи за период времени, админкоманда

        cs_get_options_preset                   : '0130', // получить шаблон настроек по его идентификатору

        cs_adm_modify_check_domain              : '0185', // отредактировать настройки для указанного домена
        cs_adm_get_domains_list                 : '0186', // получить список доменов, с которыми может работать сервер MyChat
        
        cs_adm_forum_get_subs_groups            : '0187', // получить список групп пользователей, которые подписаны на конкретную тему либо секцию
        cs_adm_forum_add_subs_group             : '0188', // подписать группу пользователей на тему или секцию форума
        cs_adm_forum_delete_subs_group          : '0189', // удалить группу пользователей из подписки на секцию или тему форума
        cs_adm_forum_clear_subs                 : '018A', // удалить все подписки на тему или раздел форума (группы и пользователи)
        cs_adm_forum_add_subs_user              : '018B', // подписать пользователя на тему или секцию форума
        cs_adm_forum_delete_subs_user           : '018C', // удалить пользователей из подписки на секцию или тему форума
        cs_adm_forum_get_subs_users             : '018D', // получить список пользователей, которые подписаны на конкретную тему либо секцию

        cs_sync_conf_history                    : '0179', // получить логи разговоров в конференции (синхронизация). Пользователь должен находиться в указанной конференции
        cs_get_forum_subs                       : '018E', // получить список подписок на темы и разделы форума
        cs_forum_toggle_subs                    : '018F', // добавить или убрать подписку на тему либо раздел (секцию) форума
        cs_set_custom_options                   : '0190', // сохранить кастомные настройки клиента на сервере
        cs_get_custom_options                   : '0191', // получить кастомные настройки клиента на сервере

        cs_adm_integration_quiz_check_question  : '0193', // проверить существование вопроса в базе робота-викторины по тексту вопроса или по номеру
        cs_adm_integration_quiz_add_question    : '0194', // добавить новый вопрос в базу робота-викторины
        cs_adm_integration_quiz_del_question    : '0195', // удалить вопрос из базы робота-викторины по номеру
        cs_adm_integration_quiz_modify_question : '0196', // редактировать вопрос в базе робота-викторины по индексу
        cs_adm_integration_quiz_get_stat        : '0197', // получить статистику робота-викторины
        cs_adm_integration_quiz_clear_stat      : '0198', // очистить статистику робота-викторины
        cs_adm_enter_quiz_reg_data              : '0199', // ввести серийный номер для робота-викторины

        cs_users_live_search                    : '019A', // найти список пользователей на сервере
        cs_get_private_dialogs                  : '019B', // получить список своих приватных диалогов
        cs_del_private_dialog                   : '019C', // удалить диалог с указанным юзером из списка приватных диалогов
        cs_private_msg_read                     : '019D', // пользователь только что прочитал приватное сообщение из указанного диалога
        cs_private_msg_got                      : '019E', // пользователь только что получил приватное сообщение из указанного диалога
        cs_private_get_dialog_msg_states        : '019F', // получить информацию о полученных и прочитанных сообщениях в приватном диалоге с оппонентом

        cs_adm_delete_private_message           : '01A0', // удалить сообщение из приватного диалога

        cs_delete_private_message               : '01A1', // удалить сообщение из привата, нужны права для удаления произвольных сообщений в своих приватах
        cs_redirect_private_talk                : '01A2', // перенаправить приватный разговор от одного пользователя к другому

        cs_get_users_for_redirect_dialog        : '01A3', // получить список пользователей, на которых можно сделать перенаправление диалога
        cs_forward_messages                     : '01A4', // (7.4+) переслать сообщения из привата или конференции
        cs_private_multicast_msg                : '01A5', // (7.4+) отправить приватное сообщение нескольким пользователям
        cs_create_presenter                     : '01A6', // (7.4+) создать и сохранить presenter страницы для форума
        cs_adm_terminal_command                 : '01A7', // выполнить команду из консоли админки

        cs_create_media_conf                    : '01A8', // создать медиа-конференцию или вебинар

        cs_get_delayed_commands                 : '01A9', // получить список отложенных команд

        cs_adm_modify_allow_ip                  : '01AA', // изменить IP, маску или диапазон в фильтре разрешённых IP адресов
        cs_adm_modify_blocked_ip                : '01AB', // изменить IP, маску или диапазон в фильтре запрещённых IP адресов

        cs_kanban_task_take                     : '01AC', // взять задачу в работу

        cs_get_users_changeid_data              : '01AD', // получить краткую информацию о списке пользователей
        cs_get_user_avatars                     : '01AE', // получить аватары пользователей (прямоугольные картинки)

        cs_conf_got_message                     : '01B0', // юзер получил сообщение в конференции
        cs_conf_read_message                    : '01B1', // юзер прочитал сообщение в конференции

        cs_media_busy                           : '01B2', // передать сигнал "занято" для входящего звонка, сервер обрабатывает эту команду и генерирует приватное сообщение от имени звонящего с типом сообщения MSG_TYPE_MEDIA_CALL (12) и Type=mediastate_call_busy (10)

        cs_halt_cid                             : '01B4', // отключить CID пользователя от сервера и завершить его приложение
        cs_kill_cid                             : '01B5', // отключить CID пользователя от сервера

        cs_adm_asterisk_do_connect              : '01BB', // подключиться к серверу Asterisk
        cs_adm_asterisk_send_command            : '01BC', // выполнить команду Asterisk
        cs_adm_dismiss_an_employee              : '01BD', // уволить одного или несколько сотрудников, пользователь блокируется, удаляется из всех списков контактов и из групп пользователей

        cs_adm_integration_turbosms_check_balance: '01BF', // получить баланс состояния счёта в сервисе TurboSMS
        cs_adm_integration_turbosms_send_message : '01C0', // отправить SMS либо Viber-сообщение на указанный номер телефона

        cs_adm_modify_common_user_group         : '01C3', // изменить группу пользователей
        cs_adm_create_personal_user_group       : '01C4', // создать новую личную группу пользователей
        cs_adm_get_personal_user_groups         : '01C5', // получить список персональных групп указанного пользователя
        cs_adm_modify_personal_user_group       : '01CA', // изменить персональную группу пользователей
        cs_adm_add_users_to_private_group       : '01CB', // добавить пользователей в личную группу указанного пользователя
        cs_adm_remove_users_from_private_group  : '01CC', // удалить пользователей из личной группы пользователя
        cs_adm_get_personal_group_users_list    : '01CD', // получить список пользователей персональной группы

        cs_kanban_add_user_group_to_project     : '01C6', // дать доступ группе пользователей к канбан-проекту
        cs_kanban_add_access_user_groups_to_stage: '01C8', // дать доступ списку групп пользователей к этапу канбан-проекта, ответка -
        cs_create_personal_user_group           : '01CE', // создать новую личную группу пользователей
        cs_remove_personal_user_group           : '01CF', // удалить личные группы пользователя
        cs_add_users_to_personal_user_group     : '01D0', // добавить список пользователей в личную группу пользователя
        cs_get_personal_user_group_data         : '01D1', // получить данные персональной группы пользователей
        cs_remove_users_from_personal_user_group: '01D2', // удалить пользователей из личной группы пользователя
        cs_get_personal_user_groups             : '01D3', // получить список персональных групп пользователя
        cs_rename_personal_user_group           : '01D4', // переименовать персональную группу пользователей
        cs_get_public_user_groups               : '01D5', // получить список публичных групп пользователей
        cs_get_kanban_rights_group_list         : '01D6', // получить список групп прав с доступом к канбану
        cs_get_kanban_get_projects_groups       : '01D7', // получить список групп проекта для разграничения прав доступа
        cs_kanban_remove_user_groups_from_project: '01C7', // убрать доступ для групп пользователей в канбан-проекте
        cs_get_common_user_group_data           : '01D8', // получить данные общей группы пользователей

        cs_adm_get_all_user_group_membership_list: '01D9', // получить список общих и личных групп, куда входит указанный пользователь, ответ - sc_all_user_group_membership_list

        cs_geo_position                         : '01DA', // текущая геопозиция устройства пользователя ответ на запрос 815C sc_get_geo_position (8.12+)
        cs_get_user_gps_history                 : '01DB', // запрос истории перемещений пользователя за период времени
        cs_get_user_gps_position                : '01DC', // отправить запрос на текущие GPS координаты всем онлайн-приложениям указанного пользователя

        cs_adm_fire_users                       : '01DD', // уволить одного или нескольких сотрудников, учётные записи блокируются, пользователи удаляются из общего и личных списков контактов и из всех групп ответ на команду - ошибка или sc_users_fired

        cs_media_conf                           : '01DE', // работа с медиаконференциями, универсальная команда

        cs_adm_custom_menu_create               : '01DF', // создать custom-меню для клиентских приложений
        cs_adm_get_custom_menu_list             : '01E0', // получить список существующих custom-меню для клиентских приложений
        cs_adm_remove_custom_menu_list          : '01E1', // удалить список шаблонов кастомных меню по их индексам, если всё ок, то отправляется команда sc_adm_command_complete
                                                          // если есть ошибки - то 8001 sc_error с указанием номера, что не так
        cs_adm_modify_custom_menu               : '01E2', // изменить шаблон кастомного меню по индексу
        cs_adm_add_group_to_custom_menu         : '01E3', // добавить группу пользователей в custom-menu
        cs_remove_groups_from_custom_menu       : '01E4', // удалить группы пользователей из custom-menu, если всё ок, то ответка - sc_adm_command_complete
        cs_get_custom_menu                      : '01E5', // получить данные своего custom-menu, ответ, если меню есть - 8164 sc_custom_menu (8.14+)
                                                          // если меню нету, никакого ответа не будет, ошибки тоже не будет
        cs_remote_exec                          : '01E6', // удалённый запуск скрипта на сервере, скриптовое событие OnClientRemoteExec. Нужны права

        cs_media_conf_leave                     : '01E8', // пользователь выходит из медиаконференции
        cs_media_conf_join                      : '01E9', // пользователь подключается к уже созданной медиаконференции

        cs_adm_ad_get_user_photo_thumbs         : '01EB', //  получить миниатюры фотографий пользователей из домена
        cs_adm_ad_sync_now                      : '01ED', // административная команда для немедленного выполнения синхронизации с доменом

        cs_adm_check_user_pwd                   : '01EF', // проверка, правильный ли пароль у пользователя, ответ на запрос - sc_adm_check_user_pwd_state

        cs_media_conf_close                     : '01F0', // пользователь закрывает медиаконференцию, все автоматически выходят из неё
        cs_media_conf_broadcast                 : '01F2', // универсальная команда рассылки сообщения всем пользовтелям медиа конференции, кроме отправителя

        cs_get_fresh_users_data                 : '01F3', // получить свежую информацию по изменениям ChangeID пользователей сервера, всех, у кого этот показатель больше
                                                          // указанного числа
        cs_login_done                           : '01F4', // клиент сигнализирует, что он получил от сервера основную порцию данных для первичного подключения и готов принимать оставшиеся данные
        cs_get_conf_user_list                   : '01F5', // получить список пользователей указанной конференции. Пользователь должен в ней находиться
                                                          // команда отправляется, если на клиент-сайде нет списка юзеров конференции или не совпадает
                                                          // контрольная сумма "UserListCRC32" из команды sc_join_txt_channel. Ответка -
      
        cs_close_text_conf                      : '01F6', // закрыть текстовую конференцию. Для этого должны быть права на закрытие конференций либо юзер должен быть owner-ом указанной конфы.
                                                          // Нельзя закрыть автосоздаваемую конференцию, у которой owner Elisa (UIN 0). Если в данный момент в конфе происходит звонок - он будет прекращён.
                                                          // Необязательно находиться в конференции. Если конфа будет успешно закрыта, то она блокируется, убирается из онлайн-структур сервера,
                                                          // а все юзеры получают уведомление про выход из этой конференции

        cs_adm_change_text_conf_owner           : '01F7', // сменить владельца текстовой конференции. Если владелец uin=0, то функция вернёт ошибку.
        cs_adm_get_user_conf_list               : '01F8', // получить список конференций, куда входит указанный пользователь, ответ - sc_adm_user_conf_list

        cs_adm_upload_badword_list              : '01FA', // загрузить на сервер список "плохих" слов для фильтра, список дополнит сущетвующий и в ответ придёт команда sc_badword_list_uploaded
                                                          // с информацией, сколько слов добавлено, либо ошибка
        cs_try_to_change_private_message        : '01B8', // попытка отредактировать своё сообщение в привате.
                                                          // редактировать можно только свои последние сообщения в течение заданного периода времени
        cs_try_to_change_conf_message           : '01B9', // попытка отредактировать своё сообщение в конференции, отправленное только в течение указанного в настройках сервера периода времени


        // =========================================

        adm_ldap_get_user_list: 'ldap_get_user_list',
        adm_ldap_get_user_info: 'ldap_get_user_info',

        adm_ldap_user_list: 'ldap_user_list',
        adm_ldap_user_info: 'ldap_user_info',

        // Server CMD ==============================

        sc_hello                                : '8000', // ответ на соединение клиента (сигнатура версии которую присылает клиент, например "mc5.0")
        sc_error                                : "8001", // произошла какая-то ошибка
        sc_accept_connection                    : "8002", // сервер разрешает соединение
        sc_free_edition                         : "8003", // сообщение клиенту, что тот подключен к бесплатному серверу MyChat
        sc_get_all_rights                       : "8004", // список прав клиента на сервисы чата, а также список разрешённых и запрещённых плагинов на данном сервере
        sc_login                                : "8005", // fucking login...
        //sc_job_positions                        : "8006", // * список должностей компании. Нужна доработка
        sc_remote_set_options_file              : "8007", // удалённая отправка списка настроек клиенту (файл). Будет удалено, останется только команда 8022 sc_remote_set_options
        sc_get_channels_list                    : "8008", // список каналов, которые созданы на сервере
        sc_bbs_changed                          : "8009", // уведомление клиента о том, что была изменена доска объявлений
        sc_offline_private                      : "800A", // офлайн приватное сообщение для клиента
        sc_private                              : "800B", // обычное приватное сообщение для клиента
        // !!! deprecated sc_get_small_user_info                  : "800C", // получить краткую информацию о пользователе (доделать)
        sc_show_advert_block                    : "800D", // показать рекламный блок в клиенте
        sc_hide_advert_block                    : "800E", // спрятать рекламный блок
        sc_pong                                 : "800F", // отправка с сервера команды-реакции на cs_ping, проверка связи
        sc_actions_list                         : "8010", // пришёл список команд ACTIONs с сервера, нужна доработка
        sc_files_offline_exists                 : "8011", // есть отложенные файлы для клиента
        sc_grant_private_access                 : "8012", // разрешение общаться с пользователем в привате, краткая информация о собеседнике
        sc_join_txt_channel                     : "8013", // вход пользователя в текстовый канал
        sc_txt_channel_hello_msg                : "8014", // текст приветствия указанного текстового канала
        sc_txt_channel_give_grant               : "8015", // получение прав на текстовый канал
        sc_ulist_in_txt_ch                      : "8016", // список пользователей в текстовом канале
        // !!! deprecated sc_join_newbie_txt_channel              : "8017", // новый пользователь вошёл в текстовый канал
        // !!! deprecated sc_join_newbies_txt_channel             : "8073", // новые пользователи вошли в текстовый канал
        sc_online_notify                        : "8018", // уведомление о том, что пользователь, который нам интересен, появился в онлайн
        sc_broadcast                            : "8019", // текстовое оповещение
        sc_user_online                          : "801A", // указанный пользователь подключен к серверу
        sc_trial                                : "801B", // информация о том, что используемая версия сервера незарегистрирована, и сколько дней осталось до конца работы trial-версии
        sc_remote_set_options                   : "801C", // настроить клиент в соответствии с пришедшим набором настроек в JSON формате. Доделать описание
        sc_get_msgtemplates                     : "801D", // с сервера пришёл список шаблонов для "быстрых" сообщений. Нужна переделка
        sc_get_contacts_list                    : "801E", // список личных контактов клиента. Доделать
        sc_get_common_contacts_list             : "801F", // список общих контактов клиента. Доделать
        sc_ping                                 : "8020", // 8020 принудительный пинг с сервера, проверка связи при плохом соединении, нужно при получении ответить командой cs_pong
        sc_ignore                               : "8021", // отправленное сообщение было проигнорировано другим пользователем
        sc_user_state                           : "8022", // текущий статус пользователя
        sc_leave_txt_channel                    : "8023", // пользователь вышел из указанного канала, информационное уведомление
        sc_kill_txt_ch                          : "8024", // текстовый канал удалён с сервера
        sc_bbs_body                             : "8025", // содержимое доски объявлений, доработать
        sc_add_personal_contact_group           : "8026", // в персональную панель контактов была успешно добавлена новая группа
        sc_delete_personal_contact_group        : "8027", // удалить группу из личного списка контактов
        sc_txt_channel_created                  : "8028", // уведомление о том, что на сервере создан новый текстовый канал
        sc_get_uin_info                         : "8029", // получение полной информации о пользователе
        sc_get_remote_uin_current_time          : "802A", // получить текущее системное время удалённого пользователя (remote user)
        sc_user_current_time                    : "802B", // текущие системные дата и время указанного пользователя
        sc_user_foto                            : "802C", // информация о фотографии указанного пользователя
        sc_user_computer_info                   : "802D", // информация об IP/MAC адресе пользователя и сетевом имени его компьютера
        sc_get_active_window_caption            : "802E", // запрос сервера у клиента заголовока активного окна
        sc_user_active_window_caption           : "802F", // ответ сервера клиенту с заголовока активного окна
        sc_ignores_list                         : "8030", // список игноров для указанного пользователя // доработать разбор строки
        sc_favorite_channels_list               : "8031", // список "любимых" каналов пользователя
        sc_change_password                      : "8032", // для пользователя установлен новый пароль к его учётной записи. Команда приходит в ответ на попытку изменения собственного пароля, либо при изменении пароля пользователя принудительно, на сервере, администратором
        sc_add_new_contact                      : "8033", // добавить новый контакт в персональный список контактов
        sc_delete_contact                       : "8034", // удалён контакт из личного списка контактов
        sc_rename_contacts_group                : "8035", // переименована личная группа контактов
        sc_move_personal_contact                : "8036", // персональный контакт перенесён в новую группу
        sc_open_remote_computer_shares          : "8037", // открыть удалённый компьютер по сети Проводником (показать открытые ресурсы (shares))
        sc_txtch_topic_changed                  : "8038", // изменена тема текстового канала
        sc_public_ftp_info                      : "8039", // информация о публичном доступе к FTP серверу MyChat
        sc_channel_history_messages             : "803A", // получена история сообщений в текстовом канале за временной период
        sc_rename_text_channel                  : "803B", // текстовый канал переименован
        sc_user_ignore_info                     : "803C", // информация об игнорировании указанного пользователя
        sc_clear_text_channel                   : "803D", // очистить выбранный текстовый канал от всех сообщений
        sc_personal_message2txtch               : "803E", // персональное/важное сообщение лично другому пользователю в текстовый канал
        sc_kick_from_txt_channel                : "803F", // пользователя выгнали из текстового канала
        sc_private_beep                         : "8040", // отправить пользователю звуковой сигнал
        sc_server_uptime                        : "8041", // сколько времени работает сервер MyChat без перезагрузки
        sc_server_version                       : "8042", // информация о версии сервера
        sc_user_offline                         : "8043", // пользователь с указанным UIN о тключился от сервера
        sc_halt                                 : "8044", // немедленно отключиться от сервера и завершить работу приложения в принудительном порядке
        sc_typing_notify                        : "8045", // уведомление о том, что нам в привате в данный момент кто-то пишет ответ
        // !!! deprecated sc_update_user_data                     : "8046", // обновить информацию об указанном пользователей
        sc_change_server                        : "8047", // изменить параметры подключения к серверу MyChat
        sc_user_quick_info                      : "8048", // краткая информация о пользователе
        sc_raw_data                             : "8049", // отправка произвольного пакета данных для онлайн-клиента
        sc_raw_data_txt_channel                 : "804A", // отправка произвольного пакета данных в текстовый канал

        sc_files_offline_send_accept            : "804B", // подтверждение на отправку файлов в офлайн (на сервер) для указанного пользователя
        sc_files_request_transfer               : "804C", // запрос на приём файлов от указанного пользователя
        sc_files_transfer_deny                  : "804D", // пользователь отказался принимать файлы
        sc_files_transfer_accept                : "804E", // пользователь согласился принимать файлы
        sc_files_transfer_abort                 : "804F", // пользователь прервал передачу файлов
        sc_file_internal_send_idx               : "8050", // идёт передача очередного файла
        sc_files_transfer_request_abort         : "8051", // пользователь ответил отказом на запрос приёма файлов
        sc_file_internal_sended_ok_idx          : "8052", // очередной файл успешно передан
        sc_files_request_timeout                : "8053", // отказ от приёма файлов по тайм-ауту
        sc_files_transfer_progress              : '8059', // информация о прогрессе передаваемых файлов между двумя пользователями
        sc_files_success_recieved               : '805B', //

        // !!! deprecated sc_update_self_nick_avatar_sex          : '805A', // уведомление пользователю о том, что ему следует обновить свои ник, аватар и пол в интерфейсе программы
        
        sc_registered                           : "805E", // уведомление пользователя о том, что он успешно зарегистрирован на сервере
        sc_find_users_list                      : "8058", // список пользователей, в ответ на клиентский запрос поиска пользователей (cs_find_users). Набор объектов
        sc_users_list                           : "8055", // список пользователей, отправляемый на клиент. Набор объектов
        sc_serv_stat                            : '8054', // общая статистика сервера
        sc_private_info                         : '806F', // краткая информация о пользователе, полученная по шаблону

        sc_media_call                           : '8070',
        sc_media_call_accept                    : '8071',
        sc_media_call_reject                    : '8072',
        sc_media_call_close                     : '8075',
        sc_media_call_error                     : '8076',
        sc_media_call_busy                      : '8081',
        sc_media_incoming_call_missed           : '80D7', // пропущен входящий медиазвонок от указанного пользователя, вы в данный момент общались с другим человеком
        sc_media_offer                          : '80D2', // медиа-запрос к клиенту
        sc_media_answer                         : '80D3', // ответ на запрос media offer
        sc_media_ice_candidate                  : '80D4', // ответ на запрос ответ cs_media_ice_candidate
        sc_media_change_settings                : '80D5', // изменение настроек медиа-данных пользователя (аудио/видео)
        sc_media_ready                          : '80D6', // NodeWebKit клиента успешно стартовал и работает

        sc_web_user_foto_file                   : '8074',
        sc_web_support_i_am_busy                : '8087', // если пользователю WEB-поддержки с сайта приходит сообщение не от оператора, с кем он в данный момент говорит, он отвечает этой командой

        sc_adm_set_topic                        : "8079", // результат работы административной команды по установке темы конференции
        sc_adm_list_channels                    : "807A",
        sc_adm_list_users                       : "807B",
        sc_adm_get_server_info                  : "8083", // результат работы административной команды по получению полного списка созданных текстовых конференций. Набор объектов, UID канала
        sc_adm_get_user_profile                 : "8084", // получение полной информации о профиле любого пользователя, административная команда
        sc_adm_list_roles                       : '807F', // список ролей (групп права) пользователей с сервера, административная команда, массив
        sc_adm_user_created                     : '8088', // пользователь только что был создан
        sc_adm_get_job_positions_list           : '8086', // список должностей компании, массив объектов
        sc_adm_server_options                   : '8089', // настройки сервера, ответ на административную команду cs_adm_get_server_options
        sc_adm_server_net_interfaces            : '808A', // список реальных IP адресов сетевых интерфейсов сервера MyChat (IPv4 и IPv6)
        sc_adm_user_info_by_preset              : '808B', // список информационных полей указанного пользователя согласно запрошенному набору
        sc_adm_command_complete                 : '808C', // административная команда успешно выполнена

        sc_adm_job_positions_added              : '808E', // добавлена новая должность
        sc_adm_job_positions_modified           : '808F', // должность была изменена успешно

        sc_adm_role_added                       : '8090', // успешно создана новая группа прав
        sc_adm_role_modified                    : '8091', // группа прав была успешно изменена
        sc_adm_role_users_list                  : '8092', // список пользователей указанной группы прав

        sc_adm_smtp_checked                     : '8093', // SMTP проверка
        sc_invite_to_webchat_sended_ok          : '8094', // уведомление о том, что отправка приглашения для другого человека в MyChat прошла успешно
        sc_adm_websupport_groups                : '8095', // список групп для сотрудников WEB-поддержки сайта, массив
        sc_adm_websupport_group_added           : '8096', // добавлена новая группа WEB-поддержки
        sc_adm_websupport_group_users           : '8097', // список пользователей WEB-support группы
        sc_adm_websupport_group_renamed         : '8098', // группа веб-поддержки успешно переименована
        sc_adm_custom_options                   : '8099', // кастомные настройки, запрошенные с помощью команды cs_adm_get_custom_options
                                                          // Количество полей может быть переменным
        sc_adm_total_contacts_list              : '809A', // общий список контактов, массив объектов

        sc_adm_tcl_group_added                  : '809B', // группа общего списка контактов успешно создана
        sc_adm_tcl_users_added                  : '80A9', // список пользователей успешно занесён в группу общих контактов

        sc_adm_users_imported                   : '809C', // пользователи импортированы в сервер
        sc_adm_server_licenses                  : '809D', // информация о лицензиях MyChat Server

        sc_adm_antiflood_filter_data            : '809E', // информация по антифлуд-фильтрам. Админкоманда
        sc_adm_flood_except_users_list          : '809F', // список пользователей, которых не касаются серверные антифлуд-фильтры, массив. Если массив пустой - значит, таких пользователей на сервере нет

        sc_adm_allow_ip_list                    : '80A0', // список разрешённых IP адресов
        sc_adm_blocked_ip_list                  : '80A1', // список заблокированных IP адресов (масок и диапазонов), массив объектов
        sc_adm_blocked_mac_list                 : '80A2', // список заблокированных MAC адресов
        sc_adm_blocked_nicks_list               : '80A3', // список заблокированных ников, админкоманда. Массив текстовых строк
        sc_adm_blocked_confs_list               : '80A4', // список заблокированных названий конференций. Массив текстовых строк

        sc_adm_bad_words_filter_data            : '80A5', // данные по фильтрам "плохих" слов
        sc_adm_bad_words_list                   : '80A6', // полный список "плохих" слов, админкоманда. Массив текстовых строк
        sc_adm_bad_words_except_confs           : '80A7', // список конференций, в кот орых отключен антимат-фильтр. Массив текстовых строк
        sc_adm_export_users_to_csv_file         : '80A8', // список пользователей с указанными данными успешно экспортирован в CSV файл

        sc_online_users_states                  : '80AA', // список UIN-ов и статусов всех пользователей, которые в данный момент есть онлайн
        sc_dept_list                            : '80AB', // список подразделений компании, массив объектов
        sc_caches                               : '80AC', // контрольные суммы (CRC32) кешей различных данных, которые, возможно, будут нужны клиенту
        sc_adm_all_text_confs                   : '80AD', // список всех текстовых конференций, которые когда-либо создавались на сервере
        sc_just_connect_disconnect_users        : '80AE', // список пользователей, которые отключились или подключились за последнее время (раз в три секунды обычно)
        sc_adm_bans_list                        : '80AF', // список банов пользователей, массив объектов
        sc_adm_moderators_list                  : '80B0', // список модераторов чата, админкоманда, массив объектов
        sc_adm_conf_names_list_by_uid           : '80B1', // список текстовых конференций, которые когда-либо создавались на сервере.

        sc_broadcasts_list_history              : '80B2', // список оповещений, которые были отправлены пользователем, за период. Массив объектов
        sc_put_msg2txt_channel                  : '80B4', // получить сообщение в текстовый канал

        sc_adm_auto_conf_list                   : '80B5', // получить список автосоздаваемых каналов
        sc_adm_auto_conf_created                : '80B6', // успешно добавлена автосоздаваемая конференция. Админкоманда
        sc_txtch_update_modes                   : '80B7', // обновить режимы текстовой конференции
        sc_adm_bbs_msg_list                     : '80B9', // список сообщений на доске объявлений, админкоманда, массив объектов
        sc_adm_bbs_msg_data                     : '80BA', // подробные данные по сообщению на доске объявлений

        sc_adm_ad_users_imported                : '80BB', // список пользователей, которых импортировали из Active Directory
        sc_adm_ad_options                       : '80BC', // настройки по Active Directory интеграции

        sc_adm_update_packet_data               : '80BD', // данные по пакетам обновления для MyChat Client
        sc_adm_online_users_list                : '80BE', // список онлайн-пользователей, которые в данный момент подключены к MyChat Server. Массив объектов
        sc_adm_ad_users_list                    : '80BF', // список пользователей домена для импорта, массив объектов. Количество полей может быть переменным, в зависимости от того, указаны они для данного пользователя
                                      //                                      в домене, или нет. Заблокированные доменные пользователи специально не "вытаскиваются".

        sc_sync_private_history                 : '80C0', // данные для синхронизации истории сообщений в привате. Массив объектов
        sc_adm_script_data                      : '80C1', // запрошенный серверный скрипт со всеми данными
        sc_adm_all_script_states                : '80C2', // список скриптов со статусами, массив объектов
        sc_adm_script_checked                   : '80C3', // проверен синтаксис скрипта
        sc_adm_script_executed                  : '80C4', // скрипт выполнен по запросу, админкоманда
        sc_adm_script_created                   : '80C5', // новый серверный скрипт создан, админкоманда, ответ на 0114 cs_adm_script_create
        sc_adm_script_deleted                   : '80C6', // скрипт только что удалён успешно, пришёл список новых идентификаторов позиций для скриптов (если они есть, если нет - список пустой)
        sc_adm_script_saved                     : '80C7', // скрипт успешно сохранён, админкоманда
        sc_adm_script_log                       : '80C8', // добавить текстовую строчку в лог редактора скриптов

        sc_adm_active_conf_list                 : '80CC', // список работающих конференций, админкоманда, ответ на запрос 011B cs_adm_get_active_conf_list. Массив объектов
        sc_adm_conf_users_list                  : '80CD', // полный список пользователей конференции, админкоманда, ответ на запрос 011D cs_adm_get_users_in_conf. Массив объектов

        // ==== BROADCASTS ==========================================

        sc_broadcast_read_notify                : '8057', // уведомление о прочтении оповещения для пользователя
        sc_broadcast_sent_ok                    : '8100', // оповещение успешно отправлено

        // ==== KANBAN ================================================

        sc_kanban_projects_list                 : '80C9', // список проектов kanban доски, массив объектов, ответ на 0117 cs_kanban_get_projects_list
        sc_kanban_stages_list                   : '80CA', // список этапов kanban-доски, массив объектов
        sc_kanban_tags_list                     : '80CB', // список тегов kanban-доски, ответ на 011A cs_kanban_get_tags_list
        sc_kanban_tasks_list                    : '80CE', // список задач kanban доски. Массив объектов
        sc_kanban_project_created               : '80D0', // новый проект kanban-доски успешно создан
        sc_kanban_stage_created                 : '80D1', // новый этап kanban-доски успешно создан
        sc_kanban_task_created                  : '80E1', // новый проект kanban-доски успешно создан
        sc_kanban_task_comment_added            : '80E2', // новый комментарий к задаче успешно добавлен
        sc_kanban_task_comments_list            : '80E3', // список комментариев к задаче на kanban доске, массив объектов
        sc_kanban_personal_options_list         : '80E5', // список персональных настроек клиента, JSON объект
        sc_kanban_event                         : '80E6', // kanban events
        sc_kanban_project_info                  : '80E7', // информация о kanban-проекте, ответ на запрос 014C cs_kanban_get_project_info
        sc_kanban_task_info                     : '80E8', // информация о задаче на kanban-доске, ответ на запрос 014D cs_kanban_get_task_info (5.21+)
        sc_kanban_last_performers_list          : '80EB', // список последних исполнителей задач на kanban-доске, ответ на запрос 0153 cs_kanban_get_last_performers, массив объектов
        sc_kanban_project_tags_list             : '80FE', // список тегов конкретного проекта
        sc_kanban_dashboard                     : '80FF', // краткая сводная информация по текущим задачам и проектам, массив объектов

        // ====================================================

        sc_personal_options_list                : '80E5', // список персональных настроек клиента, JSON объект

        sc_apply_client_settings                : '80DB', // применить клиентские настройки

        sc_adm_client_options_presets_list      : '80D8', // список шаблонов клиентских настроек, админкоманда, ответ на запрос 122C cs_adm_get_client_options_presets. Массив объектов
        sc_adm_client_options_preset_created    : '80D9', // набор настроек клиента успешно создан, ответ на команду 122E cs_adm_create_client_options_preset
        sc_adm_client_options_preset_updated    : '80DA', // набор настроек успешно отредактирован

        sc_adm_new_user_group_created           : '80DD', // уведомление о том, что новая группа пользователей успешно создана
        sc_adm_users_groups_list                : '80DE', // список групп пользователей, масив объектов
        sc_adm_group_users_list                 : '80DF', // список пользователей в группе, массив объектов

        sc_adm_integration_tool_options         : '80E0', // настройки интеграции инструмента (phpbb... etc.)
        sc_adm_get_check_domains_list           : '80E4', // список доменов с адресами, пользователи которых могут подключаться к серверу, массив объектов

        sc_adm_allowed_and_blocked_plugins      : '80E9', // список разрешённых и запрещённых клиентских плагинов
        sc_adm_script_info                      : '80EA', // краткая информация о скрипте, ответ на 0152 cs_adm_get_script_info

        // ==== FORUM ================================================

        sc_forum_structure                        : '80EF', // структура форума MyChat, ответ на запрос 0156 cs_forum_get_structure
        sc_forum_section_or_topic_created         : '80F0', // раздел форума или тема успешно создан
        sc_forum_post_created                     : '80F2', // сообщение в форуме успешно создано
        sc_forum_section_or_topic_changed         : '80F3', // раздел или тема форума успешно изменены
        sc_forum_section_or_topic_or_post_deleted : '80F4', // раздел, тема форума или сообщение успешно удалены
        sc_forum_post_changed                     : '80F5', // пост форума изменён
        sc_forum_topic_posts                      : '80F6', // список сообщений темы форума. Массив объектов
        sc_forum_section_info                     : '80F7', // информация о секции (список топиков, краткая информация о них: LastChange, UIN, DisplayName, Sex, Avatar, CountMessages). Массив объектов

        // ==========================================================

        sc_command_complete                     : '80F1', // команда успешно выполнена
        sc_book_data                            : '80FB', // возвращает содержимое справочника в ответ на команду cs_get_book

        sc_file_exists                          : '80FC', // есть или нет файл с таким хэш-кодом на сервере
        sc_image_thumbs                         : '80FD', // уменьшенная копия изображения с сервера

        sc_token_created                        : '80ED', // создан токен для доступа к сервису чата

        sc_adm_backup_server_db_ok              : '8101', // резервная копия баз данных сервера успешно создана
        sc_hide_text_conf                       : '8102', // скрыть конференцию из списка доступных
        sc_adm_integration_telegram_users_list  : '8103', // список пользователей для интеграции с Telegram. Массив объектов
        sc_adm_integration_telegram_user_added  : '8104', // уведомление, только что добавлен новый мобильный юзер в таблицу Telegram-пользователей
        sc_removed_user_info                    : '8105', // краткая информация об удалённом пользователе
        sc_login_finish                         : '8106', // клиентское приложение успешно авторизовано на сервере и ему передана вся необходимая информация (права, join-ы в конференции и т.п.)

        sc_adm_history_info_private             : '8107', // админкоманда, информация по сообщениям в привате за диапазон времени, ответ на 0173 cs_adm_get_history_info_private
        sc_adm_history_private                  : '8108', // лог приватных сообщений двух пользователей по указанному диапазону индексов, админкоманда, ответ на 0174 cs_adm_get_history_private
        sc_adm_history_info_conf                : '8109', // админкоманда, информация по сообщениям в конференции за диапазон времени, ответ на 0175 cs_adm_get_history_info_conf
        sc_adm_history_conf                     : '810A', // лог приватных сообщений двух пользователей по указанному диапазону индексов, админкоманда, ответ на 0176 cs_adm_get_history_conf
        sc_adm_history_private_user_pairs       : '810B', // админкоманда, все пары приватных разговоров за все время, ответ на 0177 cs_adm_get_history_private_user_pairs

        sc_sync_conf_history                    : '810D', // данные для синхронизации истории сообщений в конференции
        sc_info                                 : '810E', //

        sc_adm_clear_console                    : '810F', // очистить консоль вывода данных в редакторе скриптов
        sc_adm_blocked_hwid_list                : '8110', // список заблокированных HardwareID адресов
        sc_adm_system_logs                      : '8111', // системные логи за период времени, ответ на 0182 cs_adm_get_system_logs

        sc_web_services_info                    : '8114', // информация о WEB-сервисах MyChat Server. Присылается, только если они перенастроены либо изменяются в данный момент
        sc_server_ports                         : '8115', // список сетевых портов MyChat сервер, отправляется клиенту, если меняются сетевые настройки MyChat Server

        sc_adm_domains_list                     : '8116', // список доменов, с которыми может работать сервер MyChat
        sc_adm_forum_subs_groups_list           : '8117', // список групп пользователей, которые подписаны на конкретную тему либо секцию
        sc_adm_forum_subs_users_list            : '8118', // список идентификаторов пользователей, которые подписаны на конкретную тему либо секцию

        sc_forum_subs                           : '8119', // список подписок на темы и разделы форума
        sc_custom_options                       : '811A', // кастомные настройки клиента, запрошенные с сервера командой cs_set_custom_options

        sc_adm_integration_quiz_check_question  : '811B', // проверка существования вопроса в базе робота-викторины
        sc_adm_integration_quiz_question_added  : '811C', // новый вопрос в базу робота-викторины добавлен успешно
        sc_adm_integration_quiz_stat            : '811D', // статистика робота-викторины

        sc_exec_func_result                     : '811E', // результат выполнения функции на сервере
        sc_users_live_search                    : '811F', // список пользователей на сервере по заданному шаблону, результат поиска команды 019A cs_users_live_search

        sc_private_dialogs                      : '8120', // список приватных диалогов пользователя, массив объектов, свежие - сначала
        sc_del_private_dialog                   : '8121', // удалить диалог с указанным юзером из списка приватных диалогов, уведомление об успешном удалении на сервере, рассылается всем пользователям-владельцам

        sc_private_read                         : '8122', // уведомление самому себе и всем инстансам себя (multilogin) о том, что указанное приватное сообщение прочитано
        sc_private_read_notify                  : '8123', // уведомление оппоненту, что его собеседник только что прочитал приватное сообщение с указанным индексом (и все приватные сообщения до него)
        sc_private_got                          : '8124', // уведомление самому себе и всем инстансам себя (multilogin) о том, что указанное приватное сообщение получено
        sc_private_got_notify                   : '8125', // уведомление оппоненту, что его собеседник только что получил приватное сообщение с указанным индексом (и все приватные сообщения до него)
        sc_private_dialog_msg_states            : '8126', // информация о полученных и прочитанных сообщениях в приватном диалоге с оппонентом

        sc_private_redirect_complete            : '8127', // диалог успешно передан, приват можно закрыть
        sc_users_list_for_redirect_dialog       : '8128', // список пользователей для редиректа
        sc_my_multicast_msg                     : '8129', // (7.4+) моё многоадресное сообщение, ответ от сервера

        sc_create_presenter                     : '812A', // ответ на создание презентера
        sc_adm_terminal_command_result          : '812B', // ответ на терминальную команду админки


        sc_remove_conversations                 : '8112', // полностью удалить указанные протоколы разговоров за всё время из локальной базы данных
        sc_tech_kick                            : '812C', // принудительно выйти из текстовой конференции, на сервер ничего не отправлять
        sc_common_options                       : '812D', // команда для обновления общих для всех пользователей сервера параметров,
                                                          // все переменные - необязатльные, применять настройку, только если поле реально есть внутри JSON

        sc_adm_allow_ip_added                   : '812E', // добавлен IP, маска или диапазон в фильтре разрешённых IP адресов
        sc_adm_blocked_ip_added                 : '812F', // добавлен IP, маска или диапазон в фильтре запрещённых IP адресов
        sc_adm_script_log_clear                 : '8130', // очистить лог редактора скриптов в админке

        sc_kanban_task_taken                    : '8131', // задача успешно взята в работу

        sc_users_changeid_data                  : '8132', // информация о списке пользователей, UIN, ChangeID + данные
        sc_users_avatars                        : '8133', // аватары пользователей (прямоугольные картинки), массив объектов

        sc_cids_killed                          : '8137', // только что отключен от сервера список CID-ов пользователей
        sc_cids_halted                          : '8138', // только что отключен от сервера + завершены приложения списка CID-ов пользователей

        sc_conf_read                            : '8139', // пользователь только что прочитал сообщение в конференции, команда рассылается  всем инстансам UIN при мультилогине
        sc_media_incoming_call_accepted_by_another_cid: '813A', // медиа-звонок принят мной на другом устройстве
        sc_close_broadcast_window               : '813B', // закрыть окно входящего оповещения, оповещения были прочитаны на другом устройстве

        sc_adm_asterisk_log                     : '8142', // свежий кусок лога работы с Asterisk
        sc_integrations                         : '8143', // список включенных интеграций, массив объектов

        sc_adm_integration_turbosms_balance     : '8147', // баланс состояния счёта в сервисе TurboSMS
        sc_adm_integration_turbosms_ping        : '8148', // ответ PING от сервиса TurboSMS
        sc_adm_integration_turbosms_send_message: '8149', // ответ на отправку тестового сообщения

        sc_media_call_start_ok                  : '814A', // начат медиа звонок с указанными параметрами

        sc_tech_message                         : '80EE', //

        sc_personal_users_groups_list           : '814C', // список личных групп пользователей, со списком юзеров внутри, массив объектов
        sc_adm_new_personal_user_group_created  : '814D', // уведомление о том, что новая персональная группа пользователей успешно создана
        sc_adm_personal_group_users_list        : '814E', // список пользователей в персональной группе юзера, массив объектов
        sc_new_personal_user_group_created      : '814F', //  уведомление о том, что новая персональная группа пользователей успешно создана
        sc_personal_user_group_data             : '8151', // личная группа пользователя, ID, название и список пользователей
        sc_users_from_personal_user_group_removed: '8152', // список пользователей из персональной группы успешно удалён
        sc_personal_users_groups_names_list     : '8153', // список личных групп пользователей, массив объектов
        sc_public_users_groups_list             : '8155', // список публичных групп пользователей, массив объектов
        sc_kanban_rights_group_list             : '8156', // список групп прав с доступом к канбану, массив объектов
        sc_kanban_user_group_added_to_project   : '8157', // группа успешно добавлена в проект
        sc_kanban_project_group_list            : '8158', // список групп доступа к канбан-проекту
        sc_kanban_removed_user_groups_from_project: '8159', // из канбан-проекта удалены указанные группы пользователей
        sc_common_user_group_data               : '815A', // общая группа пользователя, ID, название и список пользователей
        sc_all_user_group_membership_list       : '815B', // список общих и личных групп, куда входит указанный пользователь, ответ на запрос cs_adm_get_all_user_group_membership_list

        sc_get_geo_position                     : '815C', // получить географическую позицию устройства пользователя ответ - 01DA cs_geo_position (8.12+)
        sc_user_gps_history                     : '815D', // история перемещений пользователя за период, ответ на запрос 01DB cs_get_user_gps_history

        sc_users_fired                          : '815E', // пользователи успешно уволены, ответ на cs_adm_fire_users
        sc_remove_history                       : '815F', // удаление сообщений/файлов/логов/записей звонков и т.п. любого контента в MyChat Client за период или полностью
                                                          // команда может приходить по запросу cs_get_delayed_commands либо, если клиент онлайн, то в момент выполнения на сервере
        sc_adm_custom_menu_created              : '8162', // custom-меню для клиентских приложений создано успешно, ответка на 01DF cs_adm_custom_menu_create
        sc_adm_custom_menu_list                 : '8163', // полный список custom-меню для клиентских приложений, массив объектов, ответка на 01E0 cs_adm_get_custom_menu_list
        sc_custom_menu                          : '8164', // custom-menu пользователя ответ на 01E5 cs_get_custom_menu
        sc_set_remote_client_current_place_id   : '8145', // открыть в интерфейсе удалённого клиента приват с определённым человеком либо конференцию

        sc_media_conf                           : '8160', // работа с медиаконференциями, основные команды с большой буквы, дополнительные - с маленькой
        sc_media_conf_join                      : '8166', // подключиться к медиаконференции
        sc_media_conf_leave                     : '8167', // отключиться от медиаконференции

        sc_adm_ad_users_photos                  : '8168', // отмашка в админку, что с запросами фоток мы закончили, можно начинать спрашивать, либо информация о наличии фоток (контрольные суммы, логины)
                                                          // массив объектов
        sc_adm_ad_user_photo_thumb              : '8169', // ответ от сервера, миниатюра фотографии пользователя
        sc_remove_my_acc                        : '816B', //

        sc_conf_status_change                   : '816C', // изменён статус конференции

        sc_adm_check_user_pwd_state             : '816D', // ответ на запрос корректности пароля пользователя (cs_adm_check_user_pwd)
        sc_media_conf_user_list                 : '816E', // ответ на запрос списка пользователей медиа-конференции (cs_get_media_conf_user_list)
        sc_media_conf_user_joined               : '816F', // пользователь подключился к медиаконференции, команда отправляется всем онлайн-пользователям указанной конференции
        sc_media_conf_broadcast                 : '8170', // универсальная команда рассылки сообщения всем пользователям медиа конференции, кроме отправителя

        sc_conf_user_list                       : '8171', // список пользователей указанной конференции, ответ на cs_get_conf_user_list
        sc_remove_users                         : '8172', // с сервера удалены указанные пользователи
        sc_join_newbie_to_txt_channel           : '8173', // замена sc_join_newbies_txt_channel

        sc_all_users_changed                    : '80F8', // информирование всех подключенных клиентов о том, что все юзеры изменились. Как правило, поменялся DisplayName. Следует спросить у сервера
                                                          // новую информацию обо всех пользователях, которые интересны клиентам (открытые конференции и приваты).
        sc_important_notifiers                  : '8174', // важное уведомление с сервера, нужно сгенерировать локально
        sc_adm_user_conf_list                   : '8175', // список конференций, в которые входит пользователь, ответ на запрос cs_adm_get_user_conf_list, массив объектов

        sc_conf_removed                         : '8176', // текстовая конференция удалена, нужно удалить кеши и всю локальную историю
        sc_badword_list_uploaded                : '8177', // список "плохих" слов для фильтра успешно добавлен


        // ==== Server -> Node =================================================

        sn_config                               : '1',
        sn_start                                : '2',
        sn_stop                                 : '3',
        sn_quit                                 : '4',
        sn_invite                               : '5',
        sn_iApi                                 : '6',
        sn_ip_filter                            : '7',
        sn_iApi_key                             : '8',
        sn_https_error                          : '9', 
        sn_rest_request                         : '10',
        sn_icq_connect                          : '11',
        sn_icq_send_message                     : '12',
        // sn_get_backup_path                      : '13', // sn_path_info
        sn_info                                 : '14',
        sn_path_info                            : '15',
        sn_operators                            : '16',
        sn_support_options                      : '17',
        sn_update_options                       : '18',
        sn_check_token                          : '19',
        sn_run_command                          : '20',
        sn_check_group_invite                   : '21',
        
        sn_media_conf_create                    : '22',
        sn_media_conf                           : '23',
        sn_media_conf_join                      : '24',
        sn_media_conf_leave                     : '25',
        sn_user_conf_info                       : '26',
        sn_media_conf_close                     : '27', // принудительное удаление медиа-конференции

        sn_check_ssl_info                       : '28', // перевірка сертифіката

        // ==== Node -> Server =================================================

        ns_started                              : '1001',
        ns_stopped                              : '1002',
        ns_bye                                  : '1003',
        ns_check_invite                         : '1004',
        ns_invite_sent                          : '1005',
        ns_integrationAPI                       : '1006',
        ns_ip_filter                            : '1007',
        ns_iApi_key                             : '1008',
        ns_https_error                          : '1009',
        ns_rest_request                         : '1010',
        ns_icq_connected                        : '1011',
        ns_icq_contact_list                     : '1012',
        ns_icq_send_message                     : '1013',
        ns_get_by_groups                        : '1015',
        ns_get_by_uins                          : '1016',
        ns_support_options                      : '1017',
        ns_check_token                          : '1018',
        ns_remove_tokens                        : '1019',
        ns_private_message                      : '1020',
        ns_check_group_invite                   : '1021',

        ns_media_conf                           : '1022',
        ns_media_conf_created                   : '1023',
        ns_media_conf_error                     : '1024',
        
        ns_get_user_conf_info                   : '1025',
        ns_media_conf_closed                    : '1026',
        ns_media_conf_leave                     : '1027',

        ns_check_ssl_info                       : '1028',

        // == HELP PATH ==========================================================

        accordance : {
                "navServerInfo/ServerInfo"     : "/serverhelp/#{lang}/index.html?serverinfo.htm",
                "navServerInfo/OnlineUsers"    : "/serverhelp/#{lang}/index.html?infoonlineusers.htm",
                "navServerInfo/NssService"     : "/serverhelp/#{lang}/index.html?infoadditionalservices.htm",
                "navServerInfo/Forum"          : "/serverhelp/#{lang}/index.html?infomychattechforum.htm",
                "navServerInfo/UserProfile"    : "/serverhelp/#{lang}/index.html?userprofile.htm",
                "navServerInfo/Terminal"       : "/serverhelp/#{lang}/index.html?infomychatterminal.htm",
                "navUsers/UserManager"         : "/serverhelp/#{lang}/index.html?usermanagement.htm",
                "navUsers/UserProfile"         : "/serverhelp/#{lang}/index.html?userprofile.htm",
                "navUsers/WorkPositions"       : "/serverhelp/#{lang}/index.html?userdepartments.htm",
                "navUsers/Contacts"            : "/serverhelp/#{lang}/index.html?usercommoncontacslist.htm",
                "navUsers/UsersImports"        : "/serverhelp/#{lang}/index.html?userimportfromfile.htm",
                "navUsers/Operators"           : "/serverhelp/#{lang}/index.html?usermoderators.htm",
                "navUsers/Bans"                : "/serverhelp/#{lang}/index.html?userbanlist.htm",
                "navUsers/ActiveDirectory"     : "/serverhelp/#{lang}/index.html?userimportactivedirectory.htm",
                "navUsers/UserGroups"          : "/serverhelp/#{lang}/index.html?usersgroups.htm",
                "navUsers/AdDomains"           : "/serverhelp/#{lang}/index.html?", // нет, синхронизация
                "navConference/AutoChannels"   : "/serverhelp/#{lang}/index.html?conferenceauto.htm",
                "navConference/ActiveChannels" : "/serverhelp/#{lang}/index.html?conferencesonlinelist.htm",
                "navRights/GroupRights"        : "/serverhelp/#{lang}/index.html?grouprights.htm",
                "navRights/GroupUsers"         : "/serverhelp/#{lang}/index.html?grouprightsusers.htm",
                "navRights/PluginAccess"       : "/serverhelp/#{lang}/index.html?", // нет
                "navTools/WebSupport"          : "/serverhelp/#{lang}/index.html?websupport.htm",
                "navTools/MyChatGuest"         : "/serverhelp/#{lang}/index.html?mychatguest.htm",
                "navTools/History"             : "/serverhelp/#{lang}/index.html?logsviewer.htm",
                "navTools/BBS"                 : "/serverhelp/#{lang}/index.html?", // нет
                "navTools/Updates"             : "/serverhelp/#{lang}/index.html?mychatupdatesystem.htm", // +
                "navTools/MCScripts"           : "/serverhelp/#{lang}/index.html?scripts.htm",
                "navTools/Reboot"              : "/serverhelp/#{lang}/index.html?", // нет
                "navTools/PresetManager"       : "/serverhelp/#{lang}/index.html?optionspresetscreate.htm", // +
                "navTools/RemoteSettings"      : "/serverhelp/#{lang}/index.html?optionspresetsassign.htm", // +
                "navTools/Integrations"        : "/serverhelp/#{lang}/index.html?toolsintegrations.htm", // +
                "navTools/Relocation"          : "/serverhelp/#{lang}/index.html?", // нет
                "navTools/Bots"                : "/serverhelp/#{lang}/index.html?", // нет
                "navTools/TotalClear"          : "/serverhelp/#{lang}/index.html?", // нет
                "navTools/Testport"            : "/serverhelp/#{lang}/index.html?MyChatServerTestPortErrors.htm",
                "navFilters/FilterAntiflood"   : "/serverhelp/#{lang}/index.html?filtersantiflood.htm",
                "navFilters/FilterBadWords"    : "/serverhelp/#{lang}/index.html?filtersbadwords.htm",
                "navFilters/FilterIP"          : "/serverhelp/#{lang}/index.html?filtersip.htm",
                "navFilters/FilterMAC"         : "/serverhelp/#{lang}/index.html?filtersmac.htm",
                "navFilters/FilterNames"       : "/serverhelp/#{lang}/index.html?filtersnames.htm",
                "navFilters/FilterHardware"    : "/serverhelp/#{lang}/index.html?filtershardwareid.htm",
                "navSettings/SettingsNetwork"  : "/serverhelp/#{lang}/index.html?networkoptions.htm",
                "navSettings/SettingsInfo"     : "/serverhelp/#{lang}/index.html?serverinfooptions.htm",
                "navSettings/SettingsLogs"     : "/serverhelp/#{lang}/index.html?logoptions.htm",
                "navSettings/SettingsFTP"      : "/serverhelp/#{lang}/index.html?ftpoptions.htm",
                "navSettings/SettingsWEB"      : "/serverhelp/#{lang}/index.html?webservicesoptions.htm",
                "navSettings/SettingsBackup"   : "/serverhelp/#{lang}/index.html?backupoptions.htm",
                "navSettings/SettingsService"  : "/serverhelp/#{lang}/index.html?maintenanceoptions.htm",
                "navSettings/SettingsAPI"      : "/serverhelp/#{lang}/index.html?integrationapioptions.htm",
                "navSettings/SettingsSMTP"     : "/serverhelp/#{lang}/index.html?smtpoptions.htm",
                "navSettings/SettingsFolders"  : "/serverhelp/#{lang}/index.html?mychatserverfolders.htm",
                "navSettings/Others"           : "/serverhelp/#{lang}/index.html?additionaloptions.htm",
                "navLicense/LicenseMyChat"     : "/serverhelp/#{lang}/index.html?mychatserverlicenses.htm",
                "navLicense/LicenseGuest"      : "/serverhelp/#{lang}/index.html?mychatguestlicenses.htm",
                "navLicense/LicenseClear"      : "/serverhelp/#{lang}/index.html?mychatclearlicenses.htm", // +
                "navLicense/LicenseQuiz"       : "/serverhelp/#{lang}/index.html?mychatquizlicenses.htm",  // +
                "mychat_versions"              : "/serverhelp/#{lang}/index.html?versionshistory.htm",

        },

        // ==== Client Type ====================================================

        ClientType: {
            WIN32           : 'win32',
            FTP             : 'ftp',
            WEB_ADMIN       : 'admin',
            WEB_KANBAN      : 'kanban',
            WEB_CHAT        : 'web',
            WEB_SUPPORT     : 'websupport',
            COMMON          : 'common',
            INTEGRATION_API : 'integrationapi',
            WEB_FORUM       : 'forum',
            WIN32_NEXT      : 'win32next',
            MACOS           : 'macos',
            ANDROID         : 'android',
            LINUX           : 'linux',
            GUEST           : 'mcguest',
            IOS             : 'ios',
            UPDATES         : 'updates',

            ALL             : 'any',
            UNKNOWN         : 'unknown'
        },

        callType : {
            VOICE  : 0,
            VIDEO  : 1,
            SHARING: 2
        },

        PrivateTask: {
            DEFAULT                  : 0,
            SEND_FILES               : 1,
            SEND_FILES_FROM_EXPLORER : 2,
            VOICE_CALL               : 3,
            VIDEO_CALL               : 4,
            MY_SCREEN_SHARING        : 5
        },

        serverLogLevel: {
            NOTHING         : 0, // ничего не логгировать
            SERVER_ERRORS   : 10, // серверные ошибки
            NETWORK_ERRORS  : 20, // сетевые ошибки
            SERVER_INFO     : 30, // информационные сообщения о работе сервера

            CONNECTIONS     : 800, // подключения и отключения пользователей
            NETWORK         : 900, // входящий трафик
            VERBOSE         : 1000 // полный трафик от сервера к клиентам и обратно
        },

        serverLogEvents: {
            MYCHAT_TRAFFIC_IN  : 1,
            MYCHAT_TRAFFIC_OUT : 2,
            ALL_INPUT_TRAFFIC  : 3
        },

        userStates: {
            offline    : -1,
            online     : 0,
            away       : 1,
            dnd        : 2,
            webOnline  : 3
        },

        // ==== User Rights ====================================================

        RS: {
            QLogin: 1,                                            //"811":"Подключаться к MyChat серверу",
       /*+*/QBBSPost: 2,                                          //"786":"Создание новых сообщений на доске",
       /*+*/QBBSView: 3,                                          //"785":"Просмотр доски объявлений",
       /*+*/QTxtChCreate: 4,                                      //"797":"Создание текстовых каналов",
       /*+*/QTxtChSay: 5,                                         //"844":"Отправка сообщений в текстовые каналы",
       /*+*/QTxtChJoin: 6,                                        //"796":"Вход в существующие текстовые каналы",
       /*+*/QPrivateOpen: 7,                                      //"831":"Открытие новых приватов",
       /*+*/QPrivatesGetMessages: 8,                              //"832":"Получение приватных сообщений от других пользователей",
       /*+*/QUserDetailsChange: 9,                                //"837":"Изменение персонального профиля",
       /*+*/QFilesSend: 10,                                       //"841":"Разрешить отправлять файлы другим пользователям",
       /*+*/QFilesReceive: 11,                                    //"842":"Разрешить принимать файлы от других пользователей",

            QOperatorBan: 12,                                     //"821":"Право наказывать пользователей (ban)",
            QOperatorTurnOutFromChannel: 13,                      //"820":"Право изгнания пользователей из текстовых каналов (kick)",
            QKill: 14,                                            //
            QBlockIP: 15,                                         //
            QBlockMAC: 16,                                        //
            QOperatorTxtChTopicSet: 17,                           //"818":"Изменение темы текстовых каналов",

       /*+*/QFTPPublic: 18,                                       //"840":"Доступ к общей папке на файловом сервере",
       /*+*/QFTPPersonal: 19,                                     //"839":"Доступ к личной папке на файловом сервере",

            QRemoteAdm: 20,                                       //"783":"Удаленное администрирование сервера через консоль MyChat Client",
            QOperatorClearChannelText: 21,                        //"819":"Очистка текстовых каналов у всех пользователей",

       /*+*/QContactsListChange: 22,                              //"799":"Изменение персональной панели контактов",
       /*+*/QBroadcasts: 23,                                      //"823":"Отправка оповещения другим пользователям",

       /*-*/QAllowPersonalMsg: 24, //trash                               //"794":"Отправка персональных сообщений в каналах",
       /*-*/QAllowAlertMsg: 25,    //trash                               //"795":"Отправка важных персональных сообщений в каналах",
            QAllowSysInfoView: 26,                                //"815":"Просмотр сетевого имени компьютера и IP-адреса пользователя",

       /*+*/QSendImages: 27,                                      //"792":"Вставка изображений",

            QAllowIgnores: 28,                                    //"805":"Игнорирование других пользователей",

            QAllowInvites: 29,                                    //"810":"Отправка приглашений в каналы другим пользователям",

       /*+*/QImagesPrivates: 30,                                  //"830":"Вставка изображений",
       /*+*/QShowCommonContactsList: 31,                          //"800":"Показывать общий список контактов",
       /*+*/QHalt: 32,

            QTxtChRename: 33,
            QTxtChDelete: 34,
         // QForciblyInvites: 35,                                 // deprecated
            QBlockUIN: 36,
            QAllowPlugins: 37,                                    //"827":"Использование плагинов",

       /*+*/QAllowOptionsChange: 38,                              //"806":"Изменение настроек клиентского приложения",

       /*-*/QAllowMyFavoriteChannels: 39, //trash                        //"793":"Доступ к ''Моим любимым каналам''",

       /*+*/QAllowCloseProgram: 40,
       /*+*/QAllowContactsListsTotal: 41,                         // разрешить или запретить полностью доступ к панели контактов
       /*+*/QAllowAccountsManager: 42,                            // разрешить пользоваться менеджером учётных записей
            QWEBAllowViewLogsSelfPrivates: 43,                    // просмотр своих разговоров в приватах
            QWEBAllowViewLogsAllChannels: 44,                     // просмотр всех разговоров в каналах
            QWEBAllowViewLogsAllPrivates: 45,                     // просмотр всех разговоров в приватах
       /*+*/QAllowFindUsersTool: 46,                              // разрешить поиск пользователей

       /*-*/QAllowActions: 47,    //trash                                // разрешить вставку в текст Action-ов
            QAllowClientLogPrivates: 48,                          // разрешить или запретить клиенту писать логи приватов локально, у себя на компьютере
       /*-*/QMessengerStyle: 49,                                  // Messenger-style отображения майчат клиента

            QAllowOpenComputer: 50,                               // показывать или нет в меню опцию "Открыть компьютер" по щелчку на имени юзера
            QExceptionAllowReceivePrivates: 51,                   // Приём приватных сообщений от пользователей, которым запрещена отправка приватных сообщений
            QAllowViewRemoteUserMACAddress: 52,                   // разрешить смотреть MAC адрес удалённого юзера
       /*+*/QAllowViewRemoteUserActiveProcess: 53,                // разрешить смотреть активный процесс удалённого юзера
                
       /*-*/QWEBAllowViewFTPLog: 54,                              // Просмотр FTP протоколов

       /*+*/QWEBAllowViewSystemLog: 55,                           // Просмотр системных протоколов

       /*-*/QEnableTaskWorkersJobTimeControlSystem: 56,           // контроль рабочего времени
            QWEBSupportAllowAccess: 57,                           // доступ к WEB-интерфейсу веб-суппорта

       /*+*/QWEBAllowAdmin: 58,                                   // администрирование сервере через WEB

            QAllowProgramBlockTool: 59,                           // Блокирование работающей программы паролем
            QAllowNetworkStatusChange: 60,                        // Изменение сетевого статуса
            QEnableAllowedClientsPluginsList: 61,                 // Активировать список разрешённых клиентских плагинов
            QEnableBlockedClientsPluginsList: 62,                 // Активировать список запрещённых клиенских плагинов
            QEnablePluginsManagement: 63,                         // Разрешить управление плагинами на клиенте

            QAllowImagesInBroadcasts: 64,                         // вставка картинок в оповещениях

        /*-*/QEnableFontLayoutsInMessages: 65,                     // использование шрифтовой разметки в отправляемых сообщениях
            QAllowCreateHiddenChannels: 66,                       // - (это ещё не внесено в базу данных) разрешить создавать скрытые каналы
        /*-*/QEnableTransferFilesOnlyViaServer: 67,                // передавать файлы только через сервер
            QEnableImmunityFromBans: 68,                          // иммунитет от банов

       /*- ?? */QEnableAdvertBlock: 69,                               // показывать или нет рекламный блок
       /*+*/QBlockPrivatesExceptPersonalContacts: 70,             // Запретить приваты со всеми, кроме входящих в личный список контактов
       /*+*/QBlockPrivatesExceptCommonContacts: 71,               // Запретить приваты со всеми, кроме входящих в общий список контактов
       /*+*/QEnableImmunityFromIgnores: 72,                       // Иммунитет от игноров

            QIntegrationAPIEnableSendMsgFromAnyUser: 73,          // Разрешить отправку сообщений от имени этих пользователей

       /*+*/QEnableVoiceCalls: 74,                                // Голосовые звонки
       /*+*/QEnableVideoCalls: 75,                                // Видеозвонки
       /*+*/QAllowGetVoiceCalls: 76,                              // Разрешить получать голосовые звонки
       /*+*/QAllowGetVideoCalls: 77,                              // Разрешить получать видеозвонки
                
            QAllowAddNewPlugins: 78,                              // Добавление новых плагинов
            QAllowDeletePlugins: 79,                              // Удаление плагинов

       /*+*/QAllowChangeAccountPassword: 80,                      // Изменение пароля своей учётной записи
            QAllowAccessForeignersToPersonalFiles: 81,            // Разрешить доступ к личным файлам для других пользователей ("только чтение")
            QAllowPublishLinkToPersonalFiles: 82,                 // Разрешить публиковать ссылку на "Мои файлы на сервере"

            QFTPPublicWrite: 83,                                  // разрешить писать в общую папку
            QFTPPersonalWrite: 84,                                // разрешить писать в личную папку
            QAllowSendInvites: 85,                                // разрешить отправлять приглашения в MyChat другим людям
            QWEBAllowViewNodeJSLogs: 86,                          // разрешить просмотр логов NodeJS сервера
            QWEBAllowViewAuditLogs: 87,                           // разрешить просмотр логов аудита

       /*-*/QCommonAllowMainMenu: 144,                            // главное меню программы
       /*-*/QCommonAllowDialogs: 145,                             // панель диалогов

            QForumAccess: 146,                                    // доступ ко встроенному форуму
            QForumCreateSections: 147,                            // форум, "Можно создавать новые разделы"
            QForumChangeSections: 148,                            // форум, "Изменение разделов (удаление, переименование, перенос)"
            QForumCreateTopics: 149,                              // форум, "Можно создавать новые темы"
            QForumChangeTopics: 150,                              // форум, "Изменение тем (удаление, переименование, перенос)"
            QForumCreatePosts: 151,                               // форум, "Можно создавать новые сообщения"
            QForumChangePosts: 152,                               // форум, "Изменение сообщений (удаление, модификация, перенос)"
            QForumChangeSelfPosts: 153,                           // форум, "Изменение собственных сообщений (удаление, модификация, перенос)"
            QForumDeleteSections: 154,                            // форум, "Удаление секций"
            QForumDeleteTopics: 155,                              // форум, "Удаление тем"
            QForumDeletePosts: 156,                               // форум, "Удаление сообщений"
            QForumDeleteSelfPosts: 157,                           // форум, "Удаление собственных сообщений"

            QBroadcastsOnlyInMyGroups: 158,                       // оповещения, "Отправка оповещений только в пределах своих групп пользователей"
            QTxtChViewHidden : 159,                               // Конференции, "Просмотр скрытых конференций"
            QICQAccess: 160,                                      // "Интеграция с ICQ", "Доступ к ICQ"

         /*+*/QTxtConfSendFiles: 161,                               // "Конференции", "Вставка файлов"
         /*+*/QPrivSendMessages: 162,                               // "Приваты", "Отправка сообщений"
         /*+*/QPrivInsertFiles: 163,                                // "Приваты", "Вставка файлов"
                
            QAllowRemoveConfMessages: 164,                        // "Администрирование", "Удаление любых сообщений в конференциях"
            QAdmAccessToRemoveConfMessages: 165,                  // "админка", "Инструменты", "Просмотр протоколов", Удаление сообщений из протоколов конференций
            QAllowViewHistoryTool: 166,                           // Просмотр истории сообщений

       /*+*/QAllowViewRemoteUserProfile: 174,                     //  "Профиль", "Просмотр профилей других пользователей"
            QAllowFilterHardware: 175,
            QAllowSettingsFolders: 176,
            
            QAdmAccessLicensesWipe: 177,                          // админка, "Доступ к функциям управления сервером", "Лицензии", "Очистка данных"
            QAdmToolWipe: 178,                                    // админка, доступ к инструменту "Очистка данных"
            QEnableScreenSharing: 179,                            // "Приваты", Трансляция экрана
            QAllowGetScreenSharing: 180,                          // "Приваты", Разрешить получать трансляции экрана
            
            QForumChangeTopicsColor : 181,                        // "Форум", "Изменение цвета для тем"
            QForumSubsNotify        : 182,                        // "Форум", "Подписка/отписка на уведомления в секциях и темах"
            QForumInsertImages      : 183,                        // "Форум", "Вставка изображений в сообщениях"
            QForumInsertFiles       : 184,                        // "Форум", "Вставка файлов в сообщениях"
            QAdmAccessForumSubs     : 185,                        // "Форум", "Управление подписками"

            QAdmAccessLicensesQuiz  : 187,                        // админка, "Доступ к функциям управления сервером", "Лицензии", "MyChat викторина"
            QAdmAccessToRemovePrivMessages  : 188,                // "админка", "Инструменты", "Просмотр протоколов", Удаление приватных сообщений из протоколов"
            QCommonAllowScreenshotTool      : 189,                // Отправка снимка экрана в чат

       /*+*/QAllowRemovePrivateMessages     : 190,                // Удаление любых сообщений в приватах
       /*+*/QCommonAllowQuickMessages       : 191,                // "Быстрые" сообщения
       /*+*/QAllowRedirectDialogs           : 192,                // Перенаправление диалогов
                
            QMulticast : 193,                                     // "Приваты", "Многоадресные приватные сообщения"
            QAdmTerminal: 194,                                    // "MyChat Server", "Terminal"
            QForumPresenter : 195,                                // "Форум", "Создание ссылок для просмотра тем и сообщений"
            QKanbanFullAccess: 196,                               // полный доступ к Kanban доске
            QEnableWakeUpBeep: 197,                               // Разрешить "будить" пользователя
            QAllowRemoveLocalDBConfMessages: 198,                 // "Конференции", "Удаление любых сообщений в конференциях в своей локальной базе данных"
            QAllowRemoveLocalDBPrivateMessages: 199,              // "Приваты", "Удаление любых сообщений в приватах в своей локальной базе данных"
            QAllowClientLogConferences: 200,                      // "Протоколирование", "Хранить историю сообщений конференций в локальной базе данных"
            QAndroidSecurityMode: 201,                            // "Android", "Запрет скриншов экрана в диалогах и blur окна приложения при переключении между последними приложениями"
            QAndroidShowCallsOnMainScreen: 202,                   // "Отображать вкладку \"Звонки\" на главном экране",
            QPrivMakeAsteriskCalls: 203,                          // "Приваты", "Звонки через интеграцию с Asterisk"
            QPrivGetAsteriskCalls: 204,                           // "Приваты", "Разрешить получать звонки через интеграцию с Asterisk"
            QAllowViewConfMsgReadGotStatus: 205,                  // "Конференции", "Разрешить смотреть статусы доставки/прочтения сообщений"
            QPrivAllowHangUpCalls: 206,                           // "Приваты", "Разрешить завершать звонки"
            QPrivAutoAnswerIncomingCalls: 207,                    // "Приваты", "Автоматически отвечать на входящие звонки"
            QPrivAllowMuteSoundDuringCalls: 208,                  // "Приваты", "Разрешить выключать микрофон во время звонка"
            QPrivAllowDisableCameraDuringCalls: 209,              // "Приваты", "Разрешить выключать камеру во время звонка"
            QPrivAllowRecordMediaCalls: 210,                      // "Приваты", "Разрешить запись звонков"
            QAllowExitTextConfs: 211,                             // "Конференции", "Разрешить покидать текстовые конференции"
            QViewTextConfMembersList: 212,                        // "Конференции", "Показывать список членов конференции"
            QAllowMyChatGuest2Conf: 213,                          // "MyChat Guest", "Отправка приглашений MyChat Guest для входа в конференцию"
            QAllowBrowseTextConfList: 214,                        // "Конференции", "Разрешить просматривать список доступных конференций"

       /*+*/QKanbanAccess: 134,                                   // доступ к Kanban
            QKanbanAddTask: 186,                                  // "Kanban", "Добавление заданий"
            QKanbanProjectAdd: 215,                               // "Kanban", "Проекты", "Создание новых проектов"
            QKanbanProjectEdit: 216,                              // "Kanban", "Проекты", "Редактирование проектов"
            QKanbanProjectClose: 217,                             // "Kanban", "Проекты", "Закрытие проектов"
            QKanbanStageAdd: 218,                                 // "Kanban", "Этапы", "Создание новых этапов"
            QKanbanStageRemove: 219,                              // "Kanban", "Этапы", "Удаление этапов"
            QKanbanStageEdit: 220,                                // "Kanban", "Этапы", "Редактирование этапов"
            QKanbanTaskRemove: 221,                               // "Kanban", "Задачи", "Удаление задач"
            QKanbanTaskEdit: 222,                                 // "Kanban", "Задачи", "Редактирование задач"
            QKanbanTaskMoveBetweenStages: 223,                    // "Kanban", "Задачи", "Перенос задач между этапами"
            QKanbanTaskAccessOnlyPersonal: 224,                   // "Kanban", "Задачи", "Доступ только к своим заданиям"
            QKanbanCommentAdd: 225,                               // "Kanban", "Комментарии", "Добавление комментариев"
            QKanbanCommentRemove: 226,                            // "Kanban", "Комментарии", "Удаление комментариев"

            QUserGroupsCommonView: 227,                           // "Группы пользователей", "Общие группы",  "Доступ к общим группам"
            QUserGroupsPersonalView: 228,                         // "Группы пользователей", "Личные группы", "Доступ к личным группам"
            QUserGroupsPersonalCreate: 229,                       // "Группы пользователей", "Личные группы", "Создание личных групп"
            QUserGroupsPersonalRemove: 230,                       // "Группы пользователей", "Личные группы", "Удаление личных групп"
            QUserGroupsPersonalEdit: 231,                         // "Группы пользователей", "Личные группы", "Редактирование личных групп"
            QTxtConfInsertSourceCode: 232,                        // "Конференции", "Вставка форматированонго исходного кода"
            QPrivInsertSourceCode: 233,                           // "Приваты", "Вставка форматированонго исходного кода"
            QKanbanRemoveSelfComments: 234,                       // "Канбан", "Комментарий", "Удаление своих комментариев"
            QKanbanViewTaskHistory:235,                           // "Канбан", "Комментарий", "Просмотр истории изменения задачи"
            QAdmAccessPersonalGroups: 236,                        // админка, "Пользователи", "Личные группы пользователей"
            QAdmAccessSettingsPlugins: 237,                       // админка, "Настройки", "Плагины"
            QEnableGPSTracking: 238,                              // "Общие", "Отправка текущей геопозиции на сервер"
            QAllowViewUserGeoPosition: 239,                       // "Профиль", "Просмотр информации", "Геопозиция (GPS)"
            QAdmAccessOptionsGPS: 240,                            //
            QFireUsers: 241,                                      // "Администрирование", "Увольнение пользователей"
            QAllowPrintChatText: 242,                             // "Общие", "Печать истории чатов на принтере"
            QAllowSaveChatText: 243,                              // "Общие", "Сохранение истории чатов в файл"
            QAllowRemoteExecScripts: 244,                         // "Integration API", "Разрешить удалённое выполнение скриптов"
            QAllowCustomMenu: 245,                                // "Общие", "Пользовательское меню"
            QAdmAccessToCustomMenu: 246,                          // админка, "Доступ к функциям управления сервером", "Инструменты", "Пользовательские меню"
            QAdmAccessPortTestTool: 247,                          // админка, "Доступ к функциям управления сервером", "Инструменты", "Тест портов"
            QProfileAllowToRemove: 248,                           // "Профиль", "Разрешить удаление своей учётной записи"
            QAllowConnectWindows: 249,                            //
            QAllowConnectLinux: 250,                              //
            QAllowConnectmacOS: 251,                              //
            QAllowConnectWEB: 252,                                //
            QAllowConnectAndroid: 253,                            //
            QAllowConnectiOS: 254,                                //
            QAllowCreateVoiceConf: 255,                           // "Конференции", "Звонки", "Создание голосовых конференций"
            QAllowCreateVideoConf: 256,                           // "Конференции", "Звонки", "Создание видеоконференций"
            QAllowCreateWebinar: 257,                             // "Конференции", "Звонки", "Создание вебинаров"
            QAllowCloseMediaConf: 258,                            // "Конференции", "Звонки", "Закрытие медиа конференций"
            QAllowEnterMediaConf: 259,                            // "Конференции", "Звонки", "Вход в медиа конференции"
            QAllowLeaveMediaConf: 260,                            // "Конференции", "Звонки", "Выход из медиа конференций"
            QAllowRemoveConf: 261,                                // "Конференции", "Удаление конференций"
            QAllowCloseConf: 262,                                 // "Конференции", "Закрытие конференций"
            QAllowRemoveSelfConf: 263,                            // "Конференции", "Удаление своих конференций"
            QAllowCloseSelfConf: 264,                             // "Конференции", "Закрытие своих конференций"
            QAllowEditSelfPrivateMessages: 265,                   // "Приваты", "Редактирование своих сообщений"
            QAllowEditSelfConfMessages: 266,                      // "Конференции", "Редактирование своих сообщений"
        },

        // =====================================================================

        msgType: {
             OLD_SHIT            : 0,
             TEXT                : 1,
            IMAGE               : 2,
            BEEP                : 3,
            OLD_FILE            : 4,  // deprecated
            MARKDOWN            : 5,
            ACTION              : 6,
            LAN_LINK            : 7,
            ANY_LINK            : 8,
            PREVIEW_CUSTOM_LINK : 9,
            INTEGRATION_API     : 10,
            SOURCE_CODE         : 11,
            MEDIA_CALL          : 12,
            IGNORE              : 13,
            SERVICE             : 14,
            CONF_PERSONAL       : 15,
            CONF_ALERT          : 16,
            CONF_CHANGE_TOPIC   : 17,
            CONF_BAN            : 18,
            CONF_TURN_OUT       : 19,
            BROADCAST_NOTIFY    : 20,
            COMMENT             : 21, // simple text, not shown in WEB support (for homemedhelp)
             KANBAN_NOTIFY      : 22, // уведомления с канбан-доски
            FILE                : 23,
             LOCATION           : 24, // географическая позиция
             CONTACT            : 25, // vCard
            AUDIO               : 26, // аудиозапись
            VIDEO               : 27, // видеозапись
            ADM_DELETE_MESSAGE  : 28, // удаление любого сообщения по его индексу
             FORUM_NOTIFY       : 29, // уведомления с форума
            SHOW_RECEIVED_FILES : 'srf', //
            SHOW_UPLOADED_FILES : 'suf', //
            PRIVATE_REDIRECT    : 30, // перенаправление приватного сообщения от одного пользователя - другому

            FORWARD             : 31, // message forward, оригинальное сообщение внутри "Msg", как контейнер
            CLIPBOARD_EXCEL     : 32, // (7.5+), содержимое буфера обмена в текстовом виде таблицы MS Excel
            BARCODE             : 33, // qr или штрих-код
            FTP_PUBLIC          : 34, // 8.0+ общий FTP
            FTP_PERSONAL        : 35, // 8.0+ личный FTP
            CONF_LINK           : 36, // Ссылка на текстовую конференцию, JSON в теле сообщения (поле "Msg")

            CONF_JUST_CREATED   : 38, // Информация о созданной конференции.
            CONF_INVITED        : 40, // Одного или нескольких пользователей пригласили в конференцию.
            YOUTUBE_LINK        : 41, // 8.6+ YouTube-ссылка
            REPLY               : 42, // 8.6+ ответ на сообщение
            REPLY_QUOTE         : 43,
            IMAGE_NEW           : 44, // Изображение
            FILE_NEW            : 45, // файлы
            EXCEL_NEW           : 46, // (8.6+), содержимое буфера обмена в текстовом виде таблицы MS Excel
            FORMATTED_TEXT      : 47, // (8.6+) форматированный текст
            MYCHAT_GUEST        : 48, // (8.8+) приглашение MyChat Guest успешно отправлено
            TEXT_WITH_TAGS      : 50, // (8.10+) текст с тегами [MENTION]123[/MENTION]
            TEXT_MODIFY         : 51, // Редактирование любого текстового сообщения (MSG_TYPE_TEXT) по его индексу.
                                      // "Idx" : 1745, // идентификатор сообщения, которое нужно изменить
                                      // "MsgNew" : "Bla-bla-bla", // текст нового сообщения
                                      // "Modifier": 17 // UIN юзера, который изменил сообщение, необязательный параметр, если месадж редактировал отправитель

            MEDIA_CONF_START    : 52,
            MEDIA_CONF_CLOSE    : 53
        },
        
        msgClientType: {
            WIN32   : 0,
            WEB     : 1,
            MACOS   : 2,
            LINUX   : 3,
            ANDROID : 4
        },

        loginStyle: {
            STANDARD       : '0',
            AD             : '1',
            NO_PASS        : '2',
            AD_TRANSPARENT : '3'
        },

        msgMods: {
            NONE     : 0,
            MODIFIED : 1,
            DELETED  : 2
        },

        confType: {
            STANDARD : 1, // обычная конференция
            PASSWORD : 2, // закрытая паролем
            HIDDEN   : 3  // скрытая
        },

        Errors: {
            WrongPassword       : 14,
            UserNotExist        : 17,
            WrongServerVersion  : 81,
            ConnectionLimit     : 209,
            NetworkError        : 224,
            Disconnected        : 223,
            WebServerStopped    : 321,
            ServerBusy          : 312,

            '---' : '---'
        },
        
        nsInternalErrors: {
            TELEGRAM_SCRIPT_NOT_FOUND      : 1,
            TELEGRAM_SCRIPT_DISABLED       : 2,
            INVALID_SCRIPT_RESULT          : 3,
            SCRIPT_TIMED_OUT               : 4,
            SCRIPT_SYNTAX                  : 5,
            SCRIPT_RUNTIME                 : 6,
            SCRIPT_NO_ONREQUESTBYREST      : 7,
            SCRIPT_INVALID_ONREQUESTBYREST : 8
        },

        whereType: {
            PRIVATE    : 1,
            CONFERENCE : 2,
            FORUM      : 3,
            KANBAN     : 4,
            BBS        : 5,
            BROADCAST  : 6,
        },

        ntfType: {
            ANDROID_SETUP             : 100, // просьба установить Android-приложение
            COMMON                    : 101, // встроенное уведомление, генерируется локально
            LINUXMACWEB               : 102, // встроенное уведомление, linux/mac/web
            UTP                       : 107, // встроенное уведомление, платные услуги
            GAME                      : 108, // встроенное уведомление, робот-викторина и т.п. развлекательные штуки
            IOS_SETUP                 : 109, // просьба установить iOS-приложение
            NEED_SUBSCRIPTION_2MONTHS : 110, // осталось два месяца до конца действия подписки
            NEED_SUBSCRIPTION_1MONTH  : 111, // остался месяц до конца действия подписки
            NEED_SUBSCRIPTION_2WEEKS  : 112, // осталось две недели до конца действия подписки
            SUBSCRIPTION_EXPIRED      : 113, // подписка просрочена
            FREE_VER_EXPIRED          : 114, // срок использования бесплатной версии закончился
        },

        updateConsoleCMD : "--updateClient",
        normalStart      : "--start",

        _last_: '_last_' // просто, шоб було
        // ==========================================
});


CodeMirror.defineMode("pascal", function() {
	function words(str) {
		var obj = {}, words = str.split(" ");
		for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
		return obj;
	}
	var keywords = words("and array begin case const div do downto else end file for forward integer " +
		"boolean char function goto if in label mod nil not of or packed procedure " +
		"program record repeat set string then to type until var while with try except finally TStringList");
	var atoms = {"null": true};

	var isOperatorChar = /[+\-*&%=<>!?|\/]/;

	function tokenBase(stream, state) {
		var ch = stream.next();
		if (ch == "#" && state.startOfLine) {
			stream.skipToEnd();
			return "meta";
		}
		if (ch == '"' || ch == "'") {
			state.tokenize = tokenString(ch);
			return state.tokenize(stream, state);
		}
		if (ch == "(" && stream.eat("*")) {
			state.tokenize = tokenComment;
			return tokenComment(stream, state);
		}
		if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
			return null;
		}
		if (/\d/.test(ch)) {
			stream.eatWhile(/[\w\.]/);
			return "number";
		}
		if (ch == "/") {
			if (stream.eat("/")) {
				stream.skipToEnd();
				return "comment";
			}
		}
		if (isOperatorChar.test(ch)) {
			stream.eatWhile(isOperatorChar);
			return "operator";
		}
		stream.eatWhile(/[\w\$_]/);
		var cur = stream.current();
		if (keywords.propertyIsEnumerable(cur)) return "keyword";
		if (atoms.propertyIsEnumerable(cur)) return "atom";
		return "variable";
	}

	function tokenString(quote) {
		return function(stream, state) {
			var escaped = false, next, end = false;
			while ((next = stream.next()) != null) {
				if (next == quote && !escaped) {end = true; break;}
				escaped = !escaped && next == "\\";
			}
			if (end || !escaped) state.tokenize = null;
			return "string";
		};
	}

	function tokenComment(stream, state) {
		var maybeEnd = false, ch;
		while (ch = stream.next()) {
			if (ch == ")" && maybeEnd) {
				state.tokenize = null;
				break;
			}
			maybeEnd = (ch == "*");
		}
		return "comment";
	}

	// Interface

	return {
		startState: function() {
			return {tokenize: null};
		},

		token: function(stream, state) {
			if (stream.eatSpace()) return null;
			var style = (state.tokenize || tokenBase)(stream, state);
			if (style == "comment" || style == "meta") return style;
			return style;
		},

		electricChars: "{}"
	};
});

CodeMirror.defineMIME("text/x-pascal2", "pascal2");

webix.protoUI({
	name:"codemirror-editor",
	defaults:{
		mode:"text/x-pascal",
		lineNumbers:true,
		matchBrackets:true,
		theme:"neat"
	},
	$init:function(config){
		this.$view.innerHTML = "<textarea style='width:100%;height:100%;'></textarea>";
		this.$ready.push(this._render_when_ready);
	},

	// _render_cm_editor:function(){ // загрузку сделаю сам
	//
	// 	webix.require("pascalHints.js", this._render_when_ready, this);
	// },

	_render_when_ready:function(){
		webix.require.disabled = true;

		var extraPascalHints = window.extraPascalHints || {};

		this.editor = CodeMirror.fromTextArea(this.$view.firstChild, {
			mode         : this.config.mode,
			lineNumbers  : this.config.lineNumbers,
			matchBrackets: this.config.matchBrackets,
			theme        : this.config.theme,
			hintOptions  : {
				completeSingle: false
			}
		});


		var server = new CodeMirror.TernServer({
			defs: [extraPascalHints],
			queryOptions: {
				completions: {
					caseInsensitive: true
				}
			},
			hintDelay: 15000
		});

		this.editor.setOption("extraKeys", {
			"Ctrl-Space": function(cm) { server.complete(cm); },
			"Ctrl-U"    : function(cm) { server.showType(cm); },
			"Ctrl-O"    : function(cm) { server.showDocs(cm); },
			"Alt-."     : function(cm) { server.jumpToDef(cm); },
			"Alt-,"     : function(cm) { server.jumpBack(cm); },
			"Ctrl-Q"    : function(cm) { server.rename(cm); },
			"Ctrl-."    : function(cm) { server.selectName(cm); },
			"Tab"       : function(cm) { cm.replaceSelection(Array(cm.getOption("indentUnit") + 1).join(" ")); }
		});

		// this.editor.on("cursorActivity", function(cm) {
		// 	server.updateArgHints(cm);
		// });

		this.setValue(this.config.value);

		if (this._focus_await)
			this.focus();

		this.callEvent("onReady", []);


	},

	_set_inner_size:function(){
		if (!this.editor || !this.$width) return;

		this._updateScrollSize();
		this.editor.scrollTo(0,0); //force repaint, mandatory for IE
	},
	_updateScrollSize:function(){
		var box = this.editor.getWrapperElement();
		var height = (this.$height || 0) + "px";

		box.style.height = height;
		box.style.width = (this.$width || 0) + "px";

		var scroll = this.editor.getScrollerElement();
		if (scroll.style.height != height){
			scroll.style.height = height;
			this.editor.refresh();
		}
	},
	$setSize:function(x,y){
		if (webix.ui.view.prototype.$setSize.call(this, x, y)){
			this._set_inner_size();
		}
	},

	setValue:function(value){
		if(!value && value !== 0)
			value = "";

		this.config.value = value;
		if(this.editor){
			this.editor.setValue(value);
			//by default - clear editor's undo history when setting new value
			if(!this.config.preserveUndoHistory)
				this.editor.clearHistory();
			this._updateScrollSize();
		}
	},

	getValue:function(){
		return this.editor?this.editor.getValue():this.config.value;
	},

	focus:function(){
		this._focus_await = true;
		if (this.editor)
			this.editor.focus();
	},

	getEditor:function(){
		return this.editor;
	},


	//undo, redo, etc
	undo:function(){
		this.editor.undo();
	},
	redo:function(){
		this.editor.redo();
	},
	undoLength:function(){
		return this.editor.historySize().undo;
	}
}, webix.ui.view, webix.EventSystem);
/*!
 * History API JavaScript Library v4.2.0
 *
 * Support: IE8+, FF3+, Opera 9+, Safari, Chrome and other
 *
 * Copyright 2011-2014, Dmitrii Pakhtinov ( spb.piksel@gmail.com )
 *
 * http://spb-piksel.ru/
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Update: 2014-11-06 21:35
 */
(function(L){"function"===typeof define&&define.amd?define("object"!==typeof document||"loading"!==document.readyState?[]:"html5-history-api",L):L()})(function(){var h=!0,i=null,o=!1;function M(a,b){var c=e.history!==r;c&&(e.history=r);a.apply(r,b);c&&(e.history=j)}function F(){}function l(a,b,c){if(a!=i&&""!==a&&!b){var b=l(),d=g.getElementsByTagName("base")[0];!c&&d&&d.getAttribute("href")&&(d.href=d.href,b=l(d.href,i,h));c=b.d;d=b.h;a=""+a;a=/^(?:\w+\:)?\/\//.test(a)?0===a.indexOf("/")?d+a:a:d+"//"+b.g+(0===a.indexOf("/")?a:0===a.indexOf("?")?c+a:0===a.indexOf("#")?c+b.e+a:c.replace(/[^\/]+$/g,"")+a)}else if(a=b?a:f.href,!q||c)a=a.replace(/^[^#]*/,"")||"#",a=f.protocol.replace(/:.*$|$/,
":")+"//"+f.host+k.basepath+a.replace(RegExp("^#[/]?(?:"+k.type+")?"),"");N.href=a;var a=/(?:(\w+\:))?(?:\/\/(?:[^@]*@)?([^\/:\?#]+)(?::([0-9]+))?)?([^\?#]*)(?:(\?[^#]+)|\?)?(?:(#.*))?/.exec(N.href),b=a[2]+(a[3]?":"+a[3]:""),c=a[4]||"/",d=a[5]||"",e="#"===a[6]?"":a[6]||"",j=c+d+e,n=c.replace(RegExp("^"+k.basepath,"i"),k.type)+d;return{b:a[1]+"//"+b+j,h:a[1],g:b,i:a[2],k:a[3]||"",d:c,e:d,a:e,c:j,j:n,f:n+e}}function Z(){var a;try{a=e.sessionStorage,a.setItem(y+"t","1"),a.removeItem(y+"t")}catch(b){a=
{getItem:function(a){a=g.cookie.split(a+"=");return 1<a.length&&a.pop().split(";").shift()||"null"},setItem:function(a){var b={};if(b[f.href]=j.state)g.cookie=a+"="+z.stringify(b)}}}try{m=z.parse(a.getItem(y))||{}}catch(c){m={}}s(p+"unload",function(){a.setItem(y,z.stringify(m))},o)}function A(a,b,c,d){var f=0;c||(c={set:F},f=1);var g=!c.set,j=!c.get,k={configurable:h,set:function(){g=1},get:function(){j=1}};try{w(a,b,k),a[b]=a[b],w(a,b,c)}catch(l){}if(!g||!j)if(a.__defineGetter__&&(a.__defineGetter__(b,
k.get),a.__defineSetter__(b,k.set),a[b]=a[b],c.get&&a.__defineGetter__(b,c.get),c.set&&a.__defineSetter__(b,c.set)),!g||!j){if(f)return o;if(a===e){try{var n=a[b];a[b]=i}catch(q){}if("execScript"in e)e.execScript("Public "+b,"VBScript"),e.execScript("var "+b+";","JavaScript");else try{w(a,b,{value:F})}catch(r){"onpopstate"===b&&(s("popstate",c=function(){G("popstate",c,o);var b=a.onpopstate;a.onpopstate=i;setTimeout(function(){a.onpopstate=b},1)},o),O=0)}a[b]=n}else try{try{var m=H.create(a);w(H.getPrototypeOf(m)===
a?m:a,b,c);for(var p in a)"function"===typeof a[p]&&(m[p]=a[p].bind(a));try{d.call(m,m,a)}catch(t){}a=m}catch(u){w(a.constructor.prototype,b,c)}}catch(v){return o}}return a}function $(a,b,c){c=c||{};a=a===P?f:a;c.set=c.set||function(c){a[b]=c};c.get=c.get||function(){return a[b]};return c}function B(a,b){var c=(""+("string"===typeof a?a:a.type)).replace(/^on/,""),d=t[c];if(d){b="string"===typeof a?b:a;if(b.target==i)for(var f=["target","currentTarget","srcElement","type"];a=f.pop();)b=A(b,a,{get:"type"===
a?function(){return c}:function(){return e}});O&&(("popstate"===c?e.onpopstate:e.onhashchange)||F).call(e,b);for(var f=0,g=d.length;f<g;f++)d[f].call(e,b);return h}return aa(a,b)}function Q(){var a=g.createEvent?g.createEvent("Event"):g.createEventObject();a.initEvent?a.initEvent("popstate",o,o):a.type="popstate";a.state=j.state;B(a)}function v(a,b,c,d){q?x=f.href:(0===n&&(n=2),b=l(b,2===n&&-1!==(""+b).indexOf("#")),b.c!==l().c&&(x=d,c?f.replace("#"+b.f):f.hash=b.f));!C&&a&&(m[f.href]=a);D=o}function R(a){var b=
x;x=f.href;if(b){S!==f.href&&Q();var a=a||e.event,b=l(b,h),c=l();a.oldURL||(a.oldURL=b.b,a.newURL=c.b);b.a!==c.a&&B(a)}}function T(a){setTimeout(function(){s("popstate",function(a){S=f.href;C||(a=A(a,"state",{get:function(){return j.state}}));B(a)},o)},0);!q&&a!==h&&"location"in j&&(U(E.hash),D&&(D=o,Q()))}function ba(a){var a=a||e.event,b;a:{for(b=a.target||a.srcElement;b;){if("A"===b.nodeName)break a;b=b.parentNode}b=void 0}var c="defaultPrevented"in a?a.defaultPrevented:a.returnValue===o;b&&"A"===
b.nodeName&&!c&&(c=l(),b=l(b.getAttribute("href",2)),c.b.split("#").shift()===b.b.split("#").shift()&&b.a&&(c.a!==b.a&&(E.hash=b.a),U(b.a),a.preventDefault?a.preventDefault():a.returnValue=o))}function U(a){var b=g.getElementById(a=(a||"").replace(/^#/,""));b&&b.id===a&&"A"===b.nodeName&&(a=b.getBoundingClientRect(),e.scrollTo(I.scrollLeft||0,a.top+(I.scrollTop||0)-(I.clientTop||0)))}var e=("object"===typeof window?window:this)||{};if(!e.history||"emulate"in e.history)return e.history;var g=e.document,
I=g.documentElement,H=e.Object,z=e.JSON,f=e.location,r=e.history,j=r,J=r.pushState,V=r.replaceState,q=!!J,C="state"in r,w=H.defineProperty,E=A({},"t")?{}:g.createElement("a"),p="",K=e.addEventListener?"addEventListener":(p="on")&&"attachEvent",W=e.removeEventListener?"removeEventListener":"detachEvent",X=e.dispatchEvent?"dispatchEvent":"fireEvent",s=e[K],G=e[W],aa=e[X],k={basepath:"/",redirect:0,type:"/",init:0},y="__historyAPI__",N=g.createElement("a"),x=f.href,S="",O=1,D=o,n=0,m={},t={},u=g.title,
ca={onhashchange:i,onpopstate:i},Y={setup:function(a,b,c){k.basepath=(""+(a==i?k.basepath:a)).replace(/(?:^|\/)[^\/]*$/,"/");k.type=b==i?k.type:b;k.redirect=c==i?k.redirect:!!c},redirect:function(a,b){j.setup(b,a);b=k.basepath;if(e.top==e.self){var c=l(i,o,h).c,d=f.pathname+f.search;q?(d=d.replace(/([^\/])$/,"$1/"),c!=b&&RegExp("^"+b+"$","i").test(d)&&f.replace(c)):d!=b&&(d=d.replace(/([^\/])\?/,"$1/?"),RegExp("^"+b,"i").test(d)&&f.replace(b+"#"+d.replace(RegExp("^"+b,"i"),k.type)+f.hash))}},pushState:function(a,
b,c){var d=g.title;u!=i&&(g.title=u);J&&M(J,arguments);v(a,c);g.title=d;u=b},replaceState:function(a,b,c){var d=g.title;u!=i&&(g.title=u);delete m[f.href];V&&M(V,arguments);v(a,c,h);g.title=d;u=b},location:{set:function(a){0===n&&(n=1);e.location=a},get:function(){0===n&&(n=1);return q?f:E}},state:{get:function(){return m[f.href]||i}}},P={assign:function(a){0===(""+a).indexOf("#")?v(i,a):f.assign(a)},reload:function(){f.reload()},replace:function(a){0===(""+a).indexOf("#")?v(i,a,h):f.replace(a)},
toString:function(){return this.href},href:{get:function(){return l().b}},protocol:i,host:i,hostname:i,port:i,pathname:{get:function(){return l().d}},search:{get:function(){return l().e}},hash:{set:function(a){v(i,(""+a).replace(/^(#|)/,"#"),o,x)},get:function(){return l().a}}};if(function(){var a=g.getElementsByTagName("script"),a=(a[a.length-1]||{}).src||"";(-1!==a.indexOf("?")?a.split("?").pop():"").replace(/(\w+)(?:=([^&]*))?/g,function(a,b,c){k[b]=(c||"").replace(/^(0|false)$/,"")});s(p+"hashchange",
R,o);var b=[P,E,ca,e,Y,j];C&&delete Y.state;for(var c=0;c<b.length;c+=2)for(var d in b[c])if(b[c].hasOwnProperty(d))if("function"===typeof b[c][d])b[c+1][d]=b[c][d];else{a=$(b[c],d,b[c][d]);if(!A(b[c+1],d,a,function(a,d){if(d===j)e.history=j=b[c+1]=a}))return G(p+"hashchange",R,o),o;b[c+1]===e&&(t[d]=t[d.substr(2)]=[])}j.setup();k.redirect&&j.redirect();k.init&&(n=1);!C&&z&&Z();if(!q)g[K](p+"click",ba,o);"complete"===g.readyState?T(h):(!q&&l().c!==k.basepath&&(D=h),s(p+"load",T,o));return h}())return j.emulate=
!q,e[K]=function(a,b,c){a in t?t[a].push(b):3<arguments.length?s(a,b,c,arguments[3]):s(a,b,c)},e[W]=function(a,b,c){var d=t[a];if(d)for(a=d.length;a--;){if(d[a]===b){d.splice(a,1);break}}else G(a,b,c)},e[X]=B,j});
/*
 * MIT License
 *  You may use this code as long as you retain this notice.  Use at your own risk! :)
 *  https://github.com/danschumann/limby-resize
 *  0.0.4
 */
var canvasResize = function (original, canvas, cb) {
    var
        w1 = original.width,
        h1 = original.height,
        w2 = canvas.width,
        h2 = canvas.height,
        img = original.getContext("2d").getImageData(0, 0, w1, h1),
        img2 = canvas.getContext("2d").getImageData(0, 0, w2, h2);

    if (w2 > w1 || h2 > h1) {
        canvas.getContext('2d').drawImage(original, 0, 0, w2, h2);

        if (cb) {
            cb();
        }
    } else {
        var data = img.data;
        // we don't use this much, as working with doubles isn't great
        var _data2 = img2.data;

        // We enforce float type for every entity in the array
        // this prevents weird faded lines when things get rounded off
        var data2 = Array(_data2.length);

        for (var i = 0; i < _data2.length; i++) {
            data2[i] = 0.0;
        }

        // We track alphas, since we need to use alphas to correct colors later on
        var alphas = Array(_data2.length >> 2);
        for (var i = 0; i < _data2.length >> 2; i++) {
            alphas[i] = 1;
        }

        // when resizing down, this will be decimal
        var xScale = w2 / w1;
        var yScale = h2 / h1;

        // For every pixel in the original, we tally it up in the new one
        var nextY = function (y1) {
            for (var x1 = 0; x1 < w1; x1++) {
                var

                    // the original pixel is split between two pixels in the output, we do an extra step
                    extraX = false,
                    extraY = false,

                    // the output pixel
                    targetX = Math.floor(x1 * xScale),
                    targetY = Math.floor(y1 * yScale),

                    // The percentage of this pixel going to the output pixel
                    xFactor = xScale,
                    yFactor = yScale,

                    // The percentage of this pixel going to the right neighbor or bottom neighbor
                    bottomFactor = 0,
                    rightFactor = 0,

                    // positions of pixels in the array
                    offset = (y1 * w1 + x1) * 4,
                    targetOffset = (targetY * w2 + targetX) * 4;

                // Right side goes into another pixel
                if (targetX < Math.floor((x1 + 1) * xScale)) {

                    rightFactor = (((x1 + 1) * xScale) % 1);
                    xFactor -= rightFactor;

                    extraX = true;

                }

                // Bottom side goes into another pixel
                if (targetY < Math.floor((y1 + 1) * yScale)) {

                    bottomFactor = (((y1 + 1) * yScale) % 1);
                    yFactor -= bottomFactor;

                    extraY = true;

                }

                var a;

                a = (data[offset + 3] / 255);

                var alphaOffset = targetOffset / 4;

                if (extraX) {

                    // Since we're not adding the color of invisible pixels,  we multiply by a
                    data2[targetOffset + 4] += data[offset] * rightFactor * yFactor * a;
                    data2[targetOffset + 5] += data[offset + 1] * rightFactor * yFactor * a;
                    data2[targetOffset + 6] += data[offset + 2] * rightFactor * yFactor * a;

                    data2[targetOffset + 7] += data[offset + 3] * rightFactor * yFactor;

                    // if we left out the color of invisible pixels(fully or partly)
                    // the entire average we end up with will no longer be out of 255
                    // so we subtract the percentage from the alpha ( originally 1 )
                    // so that we can reverse this effect by dividing by the amount.
                    // ( if one pixel is black and invisible, and the other is white and visible,
                    // the white pixel will weight itself at 50% because it does not know the other pixel is invisible
                    // so the total(color) for the new pixel would be 128(gray), but it should be all white.
                    // the alpha will be the correct 128, combinging alphas, but we need to preserve the color
                    // of the visible pixels )
                    alphas[alphaOffset + 1] -= (1 - a) * rightFactor * yFactor;
                }

                if (extraY) {
                    data2[targetOffset + w2 * 4] += data[offset] * xFactor * bottomFactor * a;
                    data2[targetOffset + w2 * 4 + 1] += data[offset + 1] * xFactor * bottomFactor * a;
                    data2[targetOffset + w2 * 4 + 2] += data[offset + 2] * xFactor * bottomFactor * a;

                    data2[targetOffset + w2 * 4 + 3] += data[offset + 3] * xFactor * bottomFactor;

                    alphas[alphaOffset + w2] -= (1 - a) * xFactor * bottomFactor;
                }

                if (extraX && extraY) {
                    data2[targetOffset + w2 * 4 + 4] += data[offset] * rightFactor * bottomFactor * a;
                    data2[targetOffset + w2 * 4 + 5] += data[offset + 1] * rightFactor * bottomFactor * a;
                    data2[targetOffset + w2 * 4 + 6] += data[offset + 2] * rightFactor * bottomFactor * a;

                    data2[targetOffset + w2 * 4 + 7] += data[offset + 3] * rightFactor * bottomFactor;

                    alphas[alphaOffset + w2 + 1] -= (1 - a) * rightFactor * bottomFactor;
                }

                data2[targetOffset] += data[offset] * xFactor * yFactor * a;
                data2[targetOffset + 1] += data[offset + 1] * xFactor * yFactor * a;
                data2[targetOffset + 2] += data[offset + 2] * xFactor * yFactor * a;

                data2[targetOffset + 3] += data[offset + 3] * xFactor * yFactor;

                alphas[alphaOffset] -= (1 - a) * xFactor * yFactor;
            }

            if (y1++ < h1)
                setTimeout(nextY.bind(this, y1), 0); // this allows other processes to tick
            else
                done();

        };

        nextY(0);

        var done = function () {

            // fully distribute the color of pixels that are partially full because their neighbor is transparent
            for (var i = 0; i < (_data2.length >> 2); i++) {
                if (alphas[i] && alphas[i] < 1) {
                    data2[(i << 2)] /= alphas[i];     // r
                    data2[(i << 2) + 1] /= alphas[i]; // g
                    data2[(i << 2) + 2] /= alphas[i]; // b
                }
            }

            // re populate the actual imgData
            for (var i = 0; i < data2.length; i++) {
                _data2[i] = Math.round(data2[i]);
            }

            var context = canvas.getContext("2d");

            context.putImageData(img2, 0, 0);
            //deferred.resolve();

            if (cb) {
                cb();
            }
        };
    }
};

// Allow for use with browser or node.js
if ('undefined' !== typeof window) {
    window.canvasResize = canvasResize;
} else {
    module.exports = canvasResize;
}

function mcConnect () {
    "use strict";

    var CLIENT_TO_SERVER = 'client-to-server-cmd';
    var SERVER_TO_CLIENT = 'server-to-client-cmd';

    var CallBackFunctionPull = {};
    var sendStack = [];
    var self      = this;
    var _config   = {
        idError              : 0,
        AjaxInProgress       : false,
        _Timeout             : 20000,
        CRLF                 : "\r\n",
        CR                   : "\r",
        LF                   : "\n"
    };

    self.NoCMD          = false;
    self.CallBackNoCMD  = null;
    self.LeaveCallBacks = false;

    function check(idx, CMD) {
        CallBackFunctionPull[CMD].splice(idx, 1);

        if (CallBackFunctionPull[CMD].length === 0) {
            delete CallBackFunctionPull[CMD];
        }

        return CallBackFunctionPull.hasOwnProperty(CMD) ? CallBackFunctionPull[CMD].length > 0 : false;
    }
    
    function isObject(obj) {
        return Object.prototype.toString.call( obj ) === '[object Object]';
    }

    function requestError(XMLHttpRequest) {
        CallBackFunctionPull = {};
        sendStack = [];

        if (XMLHttpRequest >= 1 || XMLHttpRequest === undefined){
            if (self.OnError) {
                //self.OnError((XMLHttpRequest == '' || !XMLHttpRequest)? "error" : XMLHttpRequest);
                self.OnError("error");
            }

            if (mcConst.socketIO){
                mcConst.socketIO.disconnect();

                // throw new Error("Network error");
            }
        }
    }

    function __SendData(_data){
        mcConst.socketIO.emit(CLIENT_TO_SERVER, _data);
    }

    function RequestSuccess(msg){
        var CR_IDX = msg.length ? msg.indexOf(_config.CR) : -1;

        // console.log(msg);

        if (CR_IDX !== -1) {
            var cmd  = msg.slice(0, CR_IDX);
            var data = msg.slice(CR_IDX + 1, msg.length + 1);

            if (self.NoCMD) {
                self.CallBackNoCMD.apply(msg);
            } else {
                self.RunCallBackFunctionByCMD(cmd, data);
            }
        } else {
            var cmd  = "ping";

            if (self.NoCMD) {
                self.CallBackNoCMD.apply(msg);
            } else {
                self.RunCallBackFunctionByCMD(cmd, msg);
            }
        }
    }

    /**
     * @return {number}
     */
    self.SendDataToServer = function(_data){
        var sendingData = '';
        var prepareData = {};

        if ((!_data) || (_data.length === 0)) {
            if (console && console.warn) {
                console.warn('SendDataToServer: _data is empty or undefined');
            }

            return 1;
        } else {
            switch (typeof _data){
                case "string":
                    sendingData = _data;
                break;

                case "object":
                     prepareData = mcService.Marge({
                        CMD        : '',
                        Data       : '',
                        OnReceive  : null
                    }, _data || {});

                    if (prepareData.Data === ''){
                        console.error('SendDataToServer: "Data" is undefined');

                        return 2;
                    }

                    if (isObject(prepareData.Data)){
                        prepareData.Data = JSON.stringify(prepareData.Data);
                    }

                    sendingData = prepareData.CMD + _config.CR + prepareData.Data;

                    if (prepareData.CMD !== '' && prepareData.OnReceive){
                        self.SetCallBackFunctionByCMD(prepareData.CMD, prepareData.OnReceive);
                    }
                break;
            }

            __SendData(sendingData, prepareData.immediately);
        }
    };

    //=====================================================================
    self.OnError        = undefined;

    //=====================================================================
    self.SetCallBackFunctionByCMD = function(CMD, callback){
        if (callback){
            if (!CallBackFunctionPull.hasOwnProperty(CMD)) {
                CallBackFunctionPull[CMD] = [];
            }

            CallBackFunctionPull[CMD].push(callback);
        }
    };

    //=====================================================================
    self.ClearAllCallBackFunctionByCMD = function(){
        for (var i in CallBackFunctionPull){
            if (CallBackFunctionPull.hasOwnProperty(i)) {
                delete CallBackFunctionPull[i];
            }
        }
    };

    //=====================================================================
    self.RunCallBackFunctionByCMD = function(CMD, MSG){
        var next = CallBackFunctionPull.hasOwnProperty(CMD) ? CallBackFunctionPull[CMD].length > 0 : false;
        var idx  = 0;

        if (!next && CMD != 'OK') {
            console.warn("CMD: \"" + CMD + "\" not have request func");

            requestError();
        }

        while (next){
            if (CallBackFunctionPull[CMD] && CallBackFunctionPull[CMD][idx]){
                if (isObject(CallBackFunctionPull[CMD][idx])) {
                    CallBackFunctionPull[CMD][idx].cb.apply(MSG);

                    if (CallBackFunctionPull[CMD][idx].one){
                        next = check(idx, CMD);

                        continue;
                    }
                } else {
                    CallBackFunctionPull[CMD][idx].apply(MSG);
                }

                if (self.LeaveCallBacks){
                    idx++;
                } else {
                    next = check(idx, CMD);
                }
            } else {
                next = false;
            }
        }
    };

    mcConst.initWS = function (socketIO) {
        socketIO.on(SERVER_TO_CLIENT, RequestSuccess);
        socketIO.on('error',          requestError);
        socketIO.on('connect_failed', requestError);
        socketIO.on('disconnected',   requestError);
        socketIO.on('reconnecting',   requestError);
    }
}

function mcCmdLoop (mcConnect, $rootScope){
    "use strict";

    window.idMcPingTimer = null;

    function RunCMD(CMD_Block, debug) {
        if (debug) {
            console.log("CMD_Block:\n" + CMD_Block);
        }

        if (CMD_Block && CMD_Block.length > 0){
            CMD_Block = mcService.StringToObj(CMD_Block);

            for (var CMD_Numb in CMD_Block){
                $rootScope.ProcessCMD([CMD_Numb, CMD_Block[CMD_Numb]]);
            }
        }
    }

    function cmdPing (sID){
        $rootScope.SendCMDToServer([mcConst._CMD_.Ping, sID]);
    }



    return function StartPingTimer(_time, sID, opt){ // this.StartPingTimer =
        var self = {};
        var options =  opt || {
            onError : null,
            onStop  : null,
            onWarn  : null
        };

        mcConnect.ClearAllCallBackFunctionByCMD();
        mcConnect.LeaveCallBacks = true;

        mcConnect.SetCallBackFunctionByCMD(mcConst._CMD_.Ping, function(){
            var data = this;

            if ((data !== "{}") && (data.length > 0)) {
                RunCMD(data);
            }
        });

        if (mcConst.SessionID)
            window.idMcPingTimer = setInterval(function(){
                if (mcConst.SessionID) {
                    cmdPing(mcConst.SessionID);
                } else {
                    console.error("mcConst.SessionID is not defined. StopPingTimer()");

                    self.StopPingTimer();
                }
            }, _time);

        self.StopPingTimer = function(){
            if (window.idMcPingTimer !== null){
                clearInterval(window.idMcPingTimer);

                window.idMcPingTimer = null;

                mcConnect.ClearAllCallBackFunctionByCMD();

                if (options.onStop) {
                    options.onStop();
                }
            }
        };

        mcConnect.OnError = function(err){
            if (console) {
                console.warn('An error occurred: Ping-Timer has been Stopped');
            }

            self.StopPingTimer();

            if (options.onError){
                options.onError(err);
            }
        };

        return self;
    }
}

/*
 * Purl (A JavaScript URL parser) v2.3.1
 * Developed and maintanined by Mark Perkins, mark@allmarkedup.com
 * Source repository: https://github.com/allmarkedup/jQuery-URL-Parser
 * Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details.
 */

;(function(factory) {
    if (typeof exports === 'object') {
        exports.purl = factory();
        return;
    }

    if (typeof define === 'function' && define.amd) {
        define(factory);
    } else {
        window.purl = factory();
    }
})(function() {

    var tag2attr = {
            a       : 'href',
            img     : 'src',
            form    : 'action',
            base    : 'href',
            script  : 'src',
            iframe  : 'src',
            link    : 'href',
            embed   : 'src',
            object  : 'data'
        },

        key = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'], // keys available to query

        aliases = { 'anchor' : 'fragment' }, // aliases for backwards compatability

        parser = {
            strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,  //less intuitive, more accurate to the specs
            loose :  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
        },

        isint = /^[0-9]+$/;

    function parseUri( url, strictMode ) {
        var str = decodeURI( url ),
        res   = parser[ strictMode || false ? 'strict' : 'loose' ].exec( str ),
        uri = { attr : {}, param : {}, seg : {} },
        i   = 14;

        while ( i-- ) {
            uri.attr[ key[i] ] = res[i] || '';
        }

        // build query and fragment parameters
        uri.param['query'] = parseString(uri.attr['query']);
        uri.param['fragment'] = parseString(uri.attr['fragment']);

        // split path and fragement into segments
        uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');
        uri.seg['fragment'] = uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/');

        // compile a 'base' domain attribute
        uri.attr['base'] = uri.attr.host ? (uri.attr.protocol ?  uri.attr.protocol+'://'+uri.attr.host : uri.attr.host) + (uri.attr.port ? ':'+uri.attr.port : '') : '';

        return uri;
    }

    function getAttrName( elm ) {
        var tn = elm.tagName;
        if ( typeof tn !== 'undefined' ) return tag2attr[tn.toLowerCase()];
        return tn;
    }

    function promote(parent, key) {
        if (parent[key].length === 0) return parent[key] = {};
        var t = {};
        for (var i in parent[key]) t[i] = parent[key][i];
        parent[key] = t;
        return t;
    }

    function parse(parts, parent, key, val) {
        var part = parts.shift();
        if (!part) {
            if (isArray(parent[key])) {
                parent[key].push(val);
            } else if ('object' == typeof parent[key]) {
                parent[key] = val;
            } else if ('undefined' == typeof parent[key]) {
                parent[key] = val;
            } else {
                parent[key] = [parent[key], val];
            }
        } else {
            var obj = parent[key] = parent[key] || [];
            if (']' == part) {
                if (isArray(obj)) {
                    if ('' !== val) obj.push(val);
                } else if ('object' == typeof obj) {
                    obj[keys(obj).length] = val;
                } else {
                    obj = parent[key] = [parent[key], val];
                }
            } else if (~part.indexOf(']')) {
                part = part.substr(0, part.length - 1);
                if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
                parse(parts, obj, part, val);
                // key
            } else {
                if (!isint.test(part) && isArray(obj)) obj = promote(parent, key);
                parse(parts, obj, part, val);
            }
        }
    }

    function merge(parent, key, val) {
        if (~key.indexOf(']')) {
            var parts = key.split('[');
            parse(parts, parent, 'base', val);
        } else {
            if (!isint.test(key) && isArray(parent.base)) {
                var t = {};
                for (var k in parent.base) t[k] = parent.base[k];
                parent.base = t;
            }
            if (key !== '') {
                set(parent.base, key, val);
            }
        }
        return parent;
    }

    function parseString(str) {
        return reduce(String(str).split(/&|;/), function(ret, pair) {
            try {
                pair = decodeURIComponent(pair.replace(/\+/g, ' '));
            } catch(e) {
                // ignore
            }
            var eql = pair.indexOf('='),
                brace = lastBraceInKey(pair),
                key = pair.substr(0, brace || eql),
                val = pair.substr(brace || eql, pair.length);

            val = val.substr(val.indexOf('=') + 1, val.length);

            if (key === '') {
                key = pair;
                val = '';
            }

            return merge(ret, key, val);
        }, { base: {} }).base;
    }

    function set(obj, key, val) {
        var v = obj[key];
        if (typeof v === 'undefined') {
            obj[key] = val;
        } else if (isArray(v)) {
            v.push(val);
        } else {
            obj[key] = [v, val];
        }
    }

    function lastBraceInKey(str) {
        var len = str.length,
            brace,
            c;
        for (var i = 0; i < len; ++i) {
            c = str[i];
            if (']' == c) brace = false;
            if ('[' == c) brace = true;
            if ('=' == c && !brace) return i;
        }
    }

    function reduce(obj, accumulator){
        var i = 0,
            l = obj.length >> 0,
            curr = arguments[2];
        while (i < l) {
            if (i in obj) curr = accumulator.call(undefined, curr, obj[i], i, obj);
            ++i;
        }
        return curr;
    }

    function isArray(vArg) {
        return Object.prototype.toString.call(vArg) === "[object Array]";
    }

    function keys(obj) {
        var key_array = [];
        for ( var prop in obj ) {
            if ( obj.hasOwnProperty(prop) ) key_array.push(prop);
        }
        return key_array;
    }

    function purl( url, strictMode ) {
        if ( arguments.length === 1 && url === true ) {
            strictMode = true;
            url = undefined;
        }
        strictMode = strictMode || false;
        url = url || window.location.toString();

        return {

            data : parseUri(url, strictMode),

            // get various attributes from the URI
            attr : function( attr ) {
                attr = aliases[attr] || attr;
                return typeof attr !== 'undefined' ? this.data.attr[attr] : this.data.attr;
            },

            // return query string parameters
            param : function( param ) {
                return typeof param !== 'undefined' ? this.data.param.query[param] : this.data.param.query;
            },

            // return fragment parameters
            fparam : function( param ) {
                return typeof param !== 'undefined' ? this.data.param.fragment[param] : this.data.param.fragment;
            },

            // return path segments
            segment : function( seg ) {
                if ( typeof seg === 'undefined' ) {
                    return this.data.seg.path;
                } else {
                    seg = seg < 0 ? this.data.seg.path.length + seg : seg - 1; // negative segments count from the end
                    return this.data.seg.path[seg];
                }
            },

            // return fragment segments
            fsegment : function( seg ) {
                if ( typeof seg === 'undefined' ) {
                    return this.data.seg.fragment;
                } else {
                    seg = seg < 0 ? this.data.seg.fragment.length + seg : seg - 1; // negative segments count from the end
                    return this.data.seg.fragment[seg];
                }
            }

        };

    }
    
    purl.jQuery = function($){
        if ($ != null) {
            $.fn.url = function( strictMode ) {
                var url = '';
                if ( this.length ) {
                    url = $(this).attr( getAttrName(this[0]) ) || '';
                }
                return purl( url, strictMode );
            };

            $.url = purl;
        }
    };

    //purl.jQuery(window.jQuery);

    return purl;

});


 /**
 * Created by Gifer on 20.02.2017.
 */

 (function (root) {

     // Store setTimeout reference so promise-polyfill will be unaffected by
     // other code modifying setTimeout (like sinon.useFakeTimers())
     var setTimeoutFunc = setTimeout;

     function noop() {}

     // Polyfill for Function.prototype.bind
     function bind(fn, thisArg) {
         return function () {
             fn.apply(thisArg, arguments);
         };
     }

     function Promise(fn) {
         if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
         if (typeof fn !== 'function') throw new TypeError('not a function');
         this._state = 0;
         this._handled = false;
         this._value = undefined;
         this._deferreds = [];

         doResolve(fn, this);
     }

     function handle(self, deferred) {
         while (self._state === 3) {
             self = self._value;
         }
         if (self._state === 0) {
             self._deferreds.push(deferred);
             return;
         }
         self._handled = true;
         Promise._immediateFn(function () {
             var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
             if (cb === null) {
                 (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
                 return;
             }
             var ret;
             try {
                 ret = cb(self._value);
             } catch (e) {
                 reject(deferred.promise, e);
                 return;
             }
             resolve(deferred.promise, ret);
         });
     }

     function resolve(self, newValue) {
         try {
             // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
             if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.');
             if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
                 var then = newValue.then;
                 if (newValue instanceof Promise) {
                     self._state = 3;
                     self._value = newValue;
                     finale(self);
                     return;
                 } else if (typeof then === 'function') {
                     doResolve(bind(then, newValue), self);
                     return;
                 }
             }
             self._state = 1;
             self._value = newValue;
             finale(self);
         } catch (e) {
             reject(self, e);
         }
     }

     function reject(self, newValue) {
         self._state = 2;
         self._value = newValue;
         finale(self);
     }

     function finale(self) {
         if (self._state === 2 && self._deferreds.length === 0) {
             Promise._immediateFn(function() {
                 if (!self._handled) {
                     Promise._unhandledRejectionFn(self._value);
                 }
             });
         }

         for (var i = 0, len = self._deferreds.length; i < len; i++) {
             handle(self, self._deferreds[i]);
         }
         self._deferreds = null;
     }

     function Handler(onFulfilled, onRejected, promise) {
         this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
         this.onRejected = typeof onRejected === 'function' ? onRejected : null;
         this.promise = promise;
     }

     /**
      * Take a potentially misbehaving resolver function and make sure
      * onFulfilled and onRejected are only called once.
      *
      * Makes no guarantees about asynchrony.
      */
     function doResolve(fn, self) {
         var done = false;
         try {
             fn(function (value) {
                 if (done) return;
                 done = true;
                 resolve(self, value);
             }, function (reason) {
                 if (done) return;
                 done = true;
                 reject(self, reason);
             });
         } catch (ex) {
             if (done) return;
             done = true;
             reject(self, ex);
         }
     }

     Promise.prototype['catch'] = function (onRejected) {
         return this.then(null, onRejected);
     };

     Promise.prototype.then = function (onFulfilled, onRejected) {
         var prom = new (this.constructor)(noop);

         handle(this, new Handler(onFulfilled, onRejected, prom));
         return prom;
     };

     Promise.all = function (arr) {
         var args = Array.prototype.slice.call(arr);

         return new Promise(function (resolve, reject) {
             if (args.length === 0) return resolve([]);
             var remaining = args.length;

             function res(i, val) {
                 try {
                     if (val && (typeof val === 'object' || typeof val === 'function')) {
                         var then = val.then;
                         if (typeof then === 'function') {
                             then.call(val, function (val) {
                                 res(i, val);
                             }, reject);
                             return;
                         }
                     }
                     args[i] = val;
                     if (--remaining === 0) {
                         resolve(args);
                     }
                 } catch (ex) {
                     reject(ex);
                 }
             }

             for (var i = 0; i < args.length; i++) {
                 res(i, args[i]);
             }
         });
     };

     Promise.resolve = function (value) {
         if (value && typeof value === 'object' && value.constructor === Promise) {
             return value;
         }

         return new Promise(function (resolve) {
             resolve(value);
         });
     };

     Promise.reject = function (value) {
         return new Promise(function (resolve, reject) {
             reject(value);
         });
     };

     Promise.race = function (values) {
         return new Promise(function (resolve, reject) {
             for (var i = 0, len = values.length; i < len; i++) {
                 values[i].then(resolve, reject);
             }
         });
     };

     // Use polyfill for setImmediate for performance gains
     Promise._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) ||
         function (fn) {
             setTimeoutFunc(fn, 0);
         };

     Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
         if (typeof console !== 'undefined' && console) {
             console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
         }
     };

     /**
      * Set the immediate function to execute callbacks
      * @param fn {function} Function to execute
      * @deprecated
      */
     Promise._setImmediateFn = function _setImmediateFn(fn) {
         Promise._immediateFn = fn;
     };

     /**
      * Change the function to execute on unhandled rejection
      * @param {function} fn Function to execute on unhandled rejection
      * @deprecated
      */
     Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
         Promise._unhandledRejectionFn = fn;
     };

     if (typeof module !== 'undefined' && module.exports) {
         module.exports = Promise;
     } else if (!root.Promise) {
         root.Promise = Promise;
     }

 })(this);

 (function () {
     function _on(event, cb) {
         if (Object.prototype.toString.call( event ) !== "[object String]"){
             console.error("[events.on] Event name must be string");
         } else
         if (eventList.hasOwnProperty(event)){
             //console.error("[events.on] Event %s already exist", event);

             eventList[event].push(cb);
         } else {
             eventList[event] = [cb];
         }
     }

     function _off(event) {
         if (eventList.hasOwnProperty(event)){
             delete eventList[event];
         } else {
             console.warn("[events.off] Unknown event: " + event);
         }
     }

     function _broadcast(event, args, nolog) {
         var res = null;

         // if (Object.prototype.toString.call( event ) !== "[object String]"){
         //     console.warn("[events.broadcast] Event name must be string");
         // } else
         if (!eventList.hasOwnProperty(event)){
             if (!nolog) {
                 console.warn("[events.broadcast] Unknown event: " + event);
             }
         } else {
             eventList[event].forEach(function (cb) {
                 res = cb.apply(null, [null, args || []]);
             });

             if (res !== void(0)) {
                 return res;
             }
         }
     }

     function _http(url, callback, post, data) {
         var res;

         try{
             res = new Promise(function (resolve, reject) {
                 var _request = new XMLHttpRequest();

                 _request.open(post ? "POST" : "GET", url, post);

                 _request.onreadystatechange = function(){
                     if (_request.readyState === 4) {
                         if (_request.status === 200) {
                             if (callback) {
                                 callback(_request.responseText);
                             }

                             resolve(_request.responseText);
                         } else {
                             reject(_request.statusText);
                         }
                     }
                 };

                 _request.send(post ? data : null);
             });

             res.success = res.then;
         } catch (e){
             console.error(e.message);
         }

         return res;
     }

     function changeLocation() { // info
         if ($location){
             $location.data = purl().data;

             $rootScope.$broadcast("onChangeHrefPath", [$location], true);
         }
     }

     var units      = [];
     var moduleList = {}; // Loaded Modules
     var eventList  = {}; // Event Emitter
     var $rootScope = {   // Global Scope
         $on         : _on,
         $off        : _off,
         $emit       : _broadcast,
         $broadcast  : _broadcast,
         isWebClient : location.protocol !== "file:"
     };
     var $location  = null;

     try {
         $location = purl();
     } catch (e){
         console.error(e.message);
     }

     window.mcComponents = {
         start: function () {
             units.forEach(function (unit) {
                 var selectScope = moduleList;

                 selectScope.$rootScope = $rootScope;
                 selectScope.$http      = _http;
                 selectScope.$location  = $location;
                 selectScope.$scope     = { // Local Scope
                     $on       : _on,
                     $off      : _off,
                     $emit     : _broadcast,
                     $broadcast: _broadcast
                 };

                 try {
                     moduleList[unit.module] = new (Function.prototype.bind.apply(window[unit.module], [null].concat(unit.args.map(function (item) {
                         return selectScope[item];
                     }))));
                 } catch (e){
                     console.error(e);
                 }

                 selectScope = null;
             });

             return this;
         },
         units: function (items) {
             units = Object.prototype.toString.call( items ) === "[object Array]" ? items : [];

             return this;
         },
         _broadcast: _broadcast
     };

     (function(eventInfo){
         window[eventInfo[0]](eventInfo[1] + "popstate", changeLocation, false);
     })(window.addEventListener ? ["addEventListener", ''] : ["attachEvent", "on"]);
 })();

 var _messages_ = {};


// Created by Gifer on 21.07.2017.

var ___native_console = window.console;

function cLog(CMD, sendCMD, needSessionID) {
    var isObject = function (obj) {
        return Object.prototype.toString.call( obj ) === '[object Object]';
    };

    if (CMD && sendCMD){
        window.console = {
            log : function log(){
                try{
                    ___native_console.log.apply(null, arguments);
                } catch (e){
                    Function.prototype.bind.apply(___native_console.log, [null].concat(arguments));
                }

                var data = isObject(arguments[0]) ? JSON.stringify(arguments[0]) : arguments[0];

                sendCMD( [CMD]. concat(needSessionID ? [mcConst.SessionID] : []). concat(['log ', data]), !needSessionID);
            },

            error: function error(){
                try {
                    ___native_console.error.apply(null, arguments);
                } catch (e){
                    Function.prototype.bind.apply(___native_console.error, [null].concat(arguments));
                }

                var data = isObject(arguments[0]) ? JSON.stringify(arguments[0]) : arguments[0];
                var _err = {};

                try{
                    Error.captureStackTrace(_err);
                } catch (e){}

                sendCMD([CMD].concat(needSessionID ? [mcConst.SessionID] : []).concat(['err ', data + "\n" + _err.stack]), !needSessionID);
            },

            err: function err(){
                try {
                    ___native_console.error.apply(null, arguments);
                } catch (e){
                    Function.prototype.bind.apply(___native_console.error, [null].concat(arguments));
                }

                var data = isObject(arguments[0]) ? JSON.stringify(arguments[0]) : arguments[0];
                var _err = {};

                try{
                    Error.captureStackTrace(_err);
                } catch (e){}

                sendCMD([CMD].concat(needSessionID ? [mcConst.SessionID] : []).concat(['err ', data + "\n" + _err.stack]), !needSessionID);
            },

            warn: function warn(){
                try {
                    ___native_console.warn.apply(null, arguments);
                } catch (e) {
                    Function.prototype.bind.apply(___native_console.warn, [null].concat(arguments));
                }

                var data = isObject(arguments[0]) ? JSON.stringify(arguments[0]) : arguments[0];

                sendCMD([CMD].concat(needSessionID ? [mcConst.SessionID] : []).concat(['warn', data]), !needSessionID);
            }
        };
    }
}

function servicesController(_api) {
    'use strict';

    var hexCodes = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
    var imgIndex = 1;

    var serviceList = {
        ModalTimer : null,
        noNotify   : false,
        notify     : null,
        idNotify   : 0,

        /**
         * @return {string}
         */
        insertIco : function(ico, css, attr){
            if (serviceList.isObject(attr)){
                var tt = [];

                Object.keys(attr).forEach(function (item) {
                    tt.push(item + "='" + attr[item] + "'")
                });

                attr = tt.join(' ');
            }

            return "<span class='webix_icon " + ico + " " + (css || "fa-lg") + "' " + (attr || "") + "></span>"
        },

        /**
         * @return {boolean}
         */
        checkRights: function(id, rightsList){
            var res = false;

            id = parseInt(id);

            if (!isNaN(id)){
                res = rightsList ? rightsList[id - 1] == "1" : mcConst.MyRightsSet[id - 1];
            }

            return res;
        },

        /**
         * @return {boolean}
         */
        isPlainObject : function(obj) {
            var res = false;

            if (!obj || !serviceList.isObject(obj) || obj.nodeType || obj.setInterval){
                res = false;
            } else
            if (obj.constructor && !obj['constructor'] && !obj.constructor['isPrototypeOf']){
                res = false;
            } else {
                var key;
                
                for ( key in obj ) {}

                res = key === undefined || !!obj[key];
            }

            return res;
        },

        /**
         * @return {object}
         */
        oldMarge : function () {
            var options, name, src, copy, copyIsArray, clone,
                target = arguments[0] || {},
                i = 1,
                length = arguments.length,
                deep = false;

            // Handle a deep copy situation
            if ( typeof target === "boolean" ) {
                deep = target;
                target = arguments[1] || {};
                // skip the boolean and the target
                i = 2;
            }

            // Handle case when target is a string or something (possible in deep copy)
            if ( typeof target !== "object" && typeof target !== "function") {
                target = {};
            }

            // extend jQuery itself if only one argument is passed
            // if ( length === i ) {
            //     target = this;
            //     --i;
            // }

            for ( ; i < length; i++ ) {
                // Only deal with non-null/undefined values
                if ( (options = arguments[ i ]) !== null ) {
                    // Extend the base object
                    for ( name in options ) {
                        src  = target [ name ];
                        copy = options[ name ];

                        // Prevent never-ending loop
                        if ( target === copy ) {
                            continue;
                        }

                        // Recurse if we're merging plain objects or arrays
                        if ( deep && copy && ( serviceList.isPlainObject(copy) || (copyIsArray = serviceList.isArray(copy)) ) ) {
                            if ( copyIsArray ) {
                                copyIsArray = false;
                                clone = src && serviceList.isArray(src) ? src : [];
                            } else {
                                clone = src && serviceList.isPlainObject(src) ? src : {};
                            }

                            // Never move original objects, clone them
                            target[ name ] = serviceList.oldMarge( deep, clone, copy );

                            // Don't bring in undefined values
                        } else if ( copy !== undefined ) {
                            target[ name ] = copy;
                        }
                    }
                }
            }

            // Return the modified object
            return target;
        },

        /**
         * @return {object}
         */
        Marge : function Marge() {
            if (serviceList.isIE()){
                return serviceList.oldMarge.apply(null, arguments);
            } else {
                if (!Object.assign) {
                    Object.defineProperty(Object, 'assign', {
                        enumerable  : false,
                        configurable: true,
                        writable    : true,
                        value       : function(target, firstSource) {
                            'use strict';

                            if (target === undefined || target === null) {
                                throw new TypeError('Cannot convert first argument to object');
                            }

                            var to = Object(target);

                            for (var i = 1; i < arguments.length; i++) {
                                var nextSource = arguments[i];

                                if (nextSource === undefined || nextSource === null) {
                                    continue;
                                }

                                var keysArray = Object.keys(Object(nextSource));

                                for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
                                    var nextKey = keysArray[nextIndex];
                                    var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);

                                    if (desc !== undefined && desc.enumerable) {
                                        to[nextKey] = nextSource[nextKey];
                                    }
                                }
                            }

                            return to;
                        }
                    });
                }

                return Object.assign.apply(null, arguments);
            }
        },

        /**
         * @return {object}
         */
        deepExtend : function(out) {
            out = out || {};

            for (var i = 1; i < arguments.length; i++) {
                var obj = arguments[i];

                if (!obj)
                    continue;

                for (var key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        if (typeof obj[key] === 'object')
                            out[key] = serviceList.deepExtend(out[key], obj[key]);
                        else
                            out[key] = obj[key];
                    }
                }
            }

            return out;
        },

        /**
         * @return {boolean}
         */
        RGBToHex : function (color) {
            var res = false;

            if (color) {
                if (color.substr(0, 1) === '#') {
                    res = color;
                } else {
                    var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color);

                    var red = parseInt(digits[2]);
                    var green = parseInt(digits[3]);
                    var blue = parseInt(digits[4]);

                    var rgb = blue | (green << 8) | (red << 16);

                    res = digits[1] + '#' + rgb.toString(16);
                }
            }

            return res;
        },

        /**
         * @return {boolean}
         */
        IntToBool : function (Int){
            return serviceList.isBoolean(val) ? val : val == '1';
        },

        /**
         * @return {number}
         */
        BoolToIntEx : function (b){
            return (b === true) ? 0 : -1;
        },

        /**
         * @return {boolean}
         */
        isIE : function (){
            //return '\v'=='v';

            var tmp = document.documentMode, _isIE;

            // Try to force this property to be a string.
            try {
                document.documentMode = "";
            } catch(e){ }

            // If document.documentMode is a number, then it is a read-only property, and so
            // we have IE 8+.
            // Otherwise, if conditional compilation works, then we have IE < 11.
            // Otherwise, we have a non-IE browser.
            _isIE = typeof document.documentMode === "number" || eval("/*@cc_on!@*/!1");

            // Switch back the value to be unobtrusive for non-IE browsers.
            try{document.documentMode = tmp;}
            catch(e){ }

            return _isIE;
        },

        /**
         * @return {boolean}
         */
        isIE6 : function (){
            var gg = navigator['appVersion'];
            var ggg = gg.indexOf("MSIE");
            var gggg = gg.slice(ggg + 5, ggg + 6);

            return gggg === "6";
        },

        /**
         * @return {boolean}
         */
        isFuckingFirefox : function() {
            return typeof InstallTrigger !== 'undefined';
        },

        /**
         * @return {object}
         */
        LessOfTwo : function (itm1, itm2, inString){
            var u1, u2;

            if (parseInt(itm1) < parseInt(itm2)) {
                u1 = itm1;
                u2 = itm2;
            } else {
                u1 = itm2;
                u2 = itm1;
            }

            return inString ? u1 + "_" + u2 : {min:u1, more:u2};
        },

        /**
         * @return {string}
         */
        formatDate : function (formatDate, formatString){
            if (!formatDate) return formatDate;

            var mcDate = serviceList.isString(formatDate);

            if (mcDate) formatDate = formatDate.split('.');

            var nowYY = (new Date()).getFullYear();
            var yyyy = mcDate ? parseInt(formatDate[2]) : formatDate.getFullYear();
            var yy = yyyy.toString().substring(2);
            var m = mcDate ? parseInt(formatDate[1]) : formatDate.getMonth() + 1;
            var mm = m < 10 ? "0" + m : m;
            var d = mcDate ? parseInt(formatDate[0]) : formatDate.getDate();
            var dd = d < 10 ? "0" + d : d;

            var  h = mcDate ? parseInt(formatDate[3]) : formatDate.getHours();
            var  hh = h < 10 ? "0" + h : h;
            var  n = mcDate ? parseInt(formatDate[4]) : formatDate.getMinutes();
            var  nn = n < 10 ? "0" + n : n;
            var  s = mcDate ? parseInt(formatDate[5]) : formatDate.getSeconds();
            var  ss = s < 10 ? "0" + s : s;
            var  zzz = mcDate ? parseInt(formatDate[6] || "0") : formatDate.getMilliseconds();
            
            if (zzz < 10) {
                zzz = "00" + zzz;
            } else
            if (zzz >= 10 && zzz < 100){
                zzz = "0" + zzz;
            }

            var lang = "en";

            if (typeof mcConst === 'object'){
                lang = mcConst.Lang;
            }

            if (typeof require === 'function'){
                window.moment = require('moment');
            }

            var MMM = moment().locale(lang).month(parseInt(m) - 1).format('MMMM');
            var MM  = moment().locale(lang).month(parseInt(m) - 1).format('MMM');

            formatString = formatString.replace(/\?yyyy/, yyyy == nowYY ? "" : yyyy);
            formatString = formatString.replace(/yyyy/, yyyy);
            formatString = formatString.replace(/yy/, yy);
            formatString = formatString.replace(/mm/, mm);
            formatString = formatString.replace(/m/, m);
            formatString = formatString.replace(/dd/, dd);
            formatString = formatString.replace(/d/, d);
            formatString = formatString.replace(/hh/, hh);
            formatString = formatString.replace(/h/, h);
            formatString = formatString.replace(/nn/, nn);
            formatString = formatString.replace(/n/, n);
            formatString = formatString.replace(/ss/, ss);
            formatString = formatString.replace(/s/, s);
            formatString = formatString.replace(/zzz/, zzz);
            formatString = formatString.replace(/MMM/, MMM);
            formatString = formatString.replace(/MM/, MM);

            return formatString;
        },

        /**
         * @return {string}
         */
        DIV : function (x1, x2){
            var y1 = (x1 / x2).toString();
            var idx = y1.indexOf(".");

            return y1.slice(0, (idx !== -1) ? idx : y1.length);
        },

        CopyArray : function (arr){
            return [].concat(arr);
        },

        StringToArray : function (_msg, separator){
            var res =[];
            var idx = -1;

            if (_msg){
                if (serviceList.isIE() === false) {
                    res = _msg.split(separator) || [];
                } else {
                    do {
                        idx = _msg.indexOf(separator);
                        if (idx >= 0) {
                            res.push(_msg.slice(0, idx));
                            _msg = _msg.slice(idx + 1, _msg.length + 1);
                        }
                    } while (idx !== -1);
                }

                if (res.length && res[res.length - 1].length === 0) {
                    res.pop();
                }
            }

            return res;
        },

        GetSubstring : function (str, term){
            var idx = str.indexOf(term);
            return (idx !== -1)? str.slice(0, idx) : str.slice(0, str.length + 1);
        },

        GetSubstringFrom : function (str, term){
            var idx = str.indexOf(term);
            return (idx !== -1)? str.slice(idx + 1, str.length + 1) : str.slice(0, str.length + 1);
        },

        DelSubstring : function (str, term){
            var idx = str.indexOf(term);
            return (idx !== -1)? str.slice(idx + 1, str.length + 1) : "";
        },

        delArrayItem : function(arr, pos, len){
            if ( pos >= 0 ) {
                arr.splice(pos,(len || 1));
            }
        },

        doGetCaretPosition : function (ctrl) {
            var CaretPos = 0;	// IE Support

            if (document.selection) {
                var Sel = document.selection.createRange();

                ctrl.focus ();
                Sel.moveStart ('character', -ctrl.value.length);

                CaretPos = Sel.text.length;
            } else { // Firefox support
                if (ctrl.selectionStart || ctrl.selectionStart == '0'){
                    CaretPos = ctrl.selectionStart;
                }
            }

            return CaretPos;
        },

        inArray: function( elem, arr, i ) {
            var len;

            if ( arr ) {
                len = arr.length;
                i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;

                for ( ; i < len; i++ ) {
                    if ( i in arr && arr[ i ] === elem ) {
                        return i;
                    }
                }
            }

            return -1;
        },

        inArrayB: function (){
            return serviceList.inArray.apply(null, arguments) !== -1;
        },

        inArrayLowerCase: function( elem, arr, i ) {
            var len;

            if ( arr ) {
                len = arr.length;
                i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;

                for ( ; i < len; i++ ) {
                    if ( i in arr && arr[ i ].toLowerCase() === elem.toLowerCase() ) {
                        return i;
                    }
                }
            }

            return -1;
        },

        inArrayNoStrict: function( elem, arr, i ) {
            var len;

            if ( arr ) {
                len = arr.length;
                i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;

                for ( ; i < len; i++ ) {
                    if ( i in arr && arr[ i ] == elem ) {
                        return i;
                    }
                }
            }

            return -1;
        },

        isArray : function (obj) {
            return Object.prototype.toString.call( obj ) === '[object Array]';
        },

        isString : function (obj) {
            return Object.prototype.toString.call( obj ) === '[object String]';
        },

        isDate : function (obj) {
            return Object.prototype.toString.call( obj ) === "[object Date]";
        },

        isHtmlElement : function (obj) {
            return Object.prototype.toString.call( obj ).indexOf('[object HTML') === 0;
        },

        isNumber : function (obj) {
            return Object.prototype.toString.call( obj ) === '[object Number]';
        },

        isObject : function (obj) {
            return Object.prototype.toString.call( obj ) === '[object Object]';
        },

        isFunction : function (obj) {
            return Object.prototype.toString.call( obj ) === '[object Function]';
        },

        isBoolean : function (obj) {
            return Object.prototype.toString.call( obj ) === '[object Boolean]';
        },

        RandomHash : function (len, isPwd) {
            var letters =  isPwd
                ? 'JjKAEeaMpsTt9QqRxBcDdF2fGgHh3ibC-kL7mNnPV85yr6SUuZ1WwXY4._vz!@#%$&*'
                : 'JjKAEeaMpsTt9QqRxBcDdF2fGgHhI3ibC-kL7mNnOPV85yr6SUuZo1WwXlY40._vz';
            var res = '';

            for (var i=0; i <  len; i++) {
                res += letters[Math.floor(Math.random() * letters.length)];
            }

            return res;
        },

        getRandomInt : function (min, max){
            return Math.floor(Math.random() * (max - min + 1)) + min;
        },

        GetType : function (obj){
            return Object.prototype.toString.call( obj );
        },

        isFormatedLikeIP : function(ip){
            var reg = /((((\d){1,3}\.){3})((\d){1,3}))/; // |(((^|:)([0-9a-fA-F]{0,4})){1,8})

            return reg.test(ip);
        },

        isValidFIO : function (fio){
            var pattern = new RegExp(/^([\x27а-яА-Яa-zA-ZїЇіІєЄ]{2,}|[\x27а-яА-Яa-zA-ZїЇіІєЄ]{2,}\-[\x27а-яА-Яa-zA-ZїЇіІєЄ]{2,})\040[\x27а-яА-Яa-zA-ZїЇіІєЄ]{2,}|[\x27а-яА-Яa-zA-ZїЇіІєЄ]{2,}\040[\x27а-яА-Яa-zA-ZїЇіІєЄ]{2,}$/);
            return pattern.test(fio);
        },

        isValidEmailAddress : function (emailAddress) {
            var pattern = new RegExp(/^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i);
            return pattern.test(emailAddress);
        },   

        isValidIpAddress : function (ip) {
            var reg = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/; // |(((^|:)([0-9a-fA-F]{0,4})){1,8})

            return reg.test(ip);
        },

        isValidIpAddressV6 : function (ip) {
            var reg = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
            // var reg = /^(:([0-9a-fA-F]{0,4})){1,8}$/;

            return reg.test(ip);
        },

        isValidHostName : function (ip) {
            // var reg = /^[0-9a-zA-Z\-.]*$/;
            // var reg = new RegExp("^[\\p{L}0-9a-zA-Z\\-.]*$", "u");
            var reg = /^[0-9a-zA-Zа-яА-Я\-.]*$/;

            return reg.test(ip) || serviceList.isValidIpAddressV6(ip);
        },

        isValidIpRange : function(ip){
            var reg = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(-)((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;

            return reg.test(ip);
        },

        isValidIpMask : function(ip){
            var reg = /^(((25([0-5]|\?)|2([0-4]|\?)(\d|\?)|([01]|\?)?(\d|\?)(\d|\?)?)|\*)\.){3}((25([0-5]|\?)|2([0-4]|\?)(\d|\?)|([01]|\?)?(\d|\?)(\d|\?)?)|\*)$/;

            return reg.test(ip);
        },

        isValidMACAddress : function(mac){
            var reg = /^([0-9a-fA-F]{2}([:-]|$)){6}$|([0-9a-fA-F]{4}([.]|$)){3}$/;

            return reg.test(mac);
        },

        isValidPhoneNumber: function (tel){
            var reg = /^(\s*)?(\+)?([- _():=+]?\d[- _():=+]?){10,14}(\s*)?$/;

            return reg.test(tel);
        },

        isHasNoRussianSymbol : function (sText) {
            var pattern = new RegExp(/[a-zA-Z0-9]/i);

            return pattern.test(sText);//(pattern.test(sText) || (sText.search(" ") == -1));
        },

        isSymbolicNumbers : function (sText) {
            var pattern = new RegExp(/[a-zA-Z0-9а-яА-ЯїЇіІєЄ\s]/i);

            return pattern.test(sText);
        },

        isURL : function (_url){
            var u = /(((http|https|ftp|ftps)(:\/\/)?|(:\/\/)(www\.)?|(www\.))[a-zа-я0-9-]+\.[a-zа-я0-9-]{2,6})/gi;

            return u.test(_url);
        },

        trim : function ( str ){
            return str.toString().replace(/^\s+|\s+$/g,'');
        },

        /**
         * @return {string}
         */
        GetUserOS : function (){
            var os = "";
            var appV = navigator.appVersion;
            var oscpu = navigator.oscpu;

            if (serviceList.isIE()){
                os = appV.split(";")[2];
            } else {
                if (oscpu !== null || oscpu !== undefined) {
                    os = oscpu;
                } else os = appV.slice(appV.indexOf("(") + 1, ((appV.indexOf(";") != -1) ? appV.indexOf(";") : appV.indexOf(")")) );
            }

            return navigator.platform + " " + os;
        },

        /**
         * @return {string}
         */
        GetUserLanguage : function (){
            return  (navigator.language       ? navigator.language       : "") +
                    (navigator.systemLanguage ? navigator.systemLanguage : "");
        },

        /**
         * @return {string}
         */
        GetUserRefLink : function (){
            return document.referrer;
        },

        /**
         * @return {string}
         */
        GetUserAgent : function (){
            return navigator.userAgent;
        },

        /**
         * @return {string}
         */
        GetUserBrowser : function (){
            var browser = "";

            if (this.isIE()){
                browser = "IE";
            } else
            if (navigator.appName === "Opera"){
                browser = "Opera";
            } else
            if (navigator.vendor === "Apple Computer, Inc."){
                browser = "Safari";
            } else
            if (navigator.vendor === "Google Inc."){
                browser = "Chrome";
            } else
            if (navigator.oscpu){
                browser = "FireFox";
            } else {
                browser = "Other Brouser";
            }

            return browser;
        },

        pos  : function (FindStr, Src){
            return Src.indexOf(FindStr);
        },

        copy : function (Src, From, Count){
            return (Src) ? Src.slice(From, From + (Count || (Src.length - From))) : "";
        },

        ReplaceURLs : function( txt, options ) {
            var
                SCHEME = "[a-z\\d.-]+://",
                IPV4 = "(?:(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.){3}(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])",
                HOSTNAME = "(?:(?:[^\\s!@#$%^&*()_=+[\\]{}\\\\|;:'\",.<>/?]+)\\.)+",
                TLD  =  "(?:ac|ad|aero|ae|af|ag|ai|al|am|an|ao|aq|arpa|ar|asia|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|biz|bi|bj|bm|" +
                        "bn|bo|br|bs|bt|bv|bw|by|bz|cat|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|coop|com|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|" +
                        "do|dz|ec|edu|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|" +
                        "gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|info|int|in|io|iq|ir|is|it|je|jm|jobs|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|" +
                        "kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mil|mk|ml|mm|mn|mobi|mo|mp|mq|mr|ms|mt|museum|mu|mv|" +
                        "mw|mx|my|mz|name|na|nc|net|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pro|pr|ps|pt|pw|" +
                        "py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|" +
                        "tl|tm|tn|to|tp|travel|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g|" +
                        "xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp|" +
                        "xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw|dev)",
                PORT = "(?::\\d{1,5})?",
                HOST_OR_IP = "(?:" + HOSTNAME + TLD + PORT + "|" + IPV4 + PORT + ")",
                PATH = "(?:[;/][^#?<>()\\s]*)?",
                QUERY_FRAG = "(?:\\?[^#<>\\s]*)?(?:#[^<>\\s]*)?",
                URI1 = "\\b" + SCHEME + "[^<>(\\s|\\)|\\(|\\[|\\])]+", //"[^<>\\s]+",
                URI2 = "\\b" + HOST_OR_IP + PATH + QUERY_FRAG + "(?!\\w)",

                MAILTO = "mailto:",
                EMAIL = "(?:" + MAILTO + ")?[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@" + HOST_OR_IP + QUERY_FRAG + "(?!\\w)",

                URI_RE = new RegExp( "(?:" + URI1 + "|" + URI2 + "|" + EMAIL + ")", "ig" ),
                SCHEME_RE = new RegExp( "^" + SCHEME, "i" );

            var quotes = {
                "'": "`",
                '>': '<',
                ')': '(',
                ']': '[',
                '}': '{',
                'В»': 'В«',
                'вЂє': 'вЂ№'
            };

            var default_options = {
                callback: function( text, href ) {
                    return href ? '<a href="' + href + '" title="' + href + '">' + text + '<\/a>' : text;
                },
                punct_regexp: /(?:[!?.,:;'"]|(?:&|&amp;)(?:lt|gt|quot|apos|raquo|laquo|rsaquo|lsaquo);)$/
            };

            options = options || {};

            // Temp variables.
            var arr,
                i,
                link,
                href,

                // Output HTML.
                html = '',

                // Store text / link parts, in order, for re-combination.
                parts = [],

                // Used for keeping track of indices in the text.
                idx_prev,
                idx_last,
                idx,
                link_last,

                // Used for trimming trailing punctuation and quotes from links.
                matches_begin,
                matches_end,
                quote_begin,
                quote_end;

            // Initialize options.
            for ( i in default_options ) {
                if ( options[ i ] === undefined ) {
                    options[ i ] = default_options[ i ];
                }
            }

            // Find links.
            while ( arr = URI_RE.exec( txt ) ) {

                link = arr[0];
                idx_last = URI_RE.lastIndex;
                idx = idx_last - link.length;

                // Not a link if preceded by certain characters.
                if ( /[\/:]/.test( txt.charAt( idx - 1 ) ) ) {
                    continue;
                }

                // Trim trailing punctuation.
                do {
                    // If no changes are made, we don't want to loop forever!
                    link_last = link;

                    quote_end = link.substr( -1 );
                    quote_begin = quotes[ quote_end ];

                    // Ending quote character?
                    if ( quote_begin ) {
                        matches_begin = link.match( new RegExp( '\\' + quote_begin + '(?!$)', 'g' ) );
                        matches_end = link.match( new RegExp( '\\' + quote_end, 'g' ) );

                        // If quotes are unbalanced, remove trailing quote character.
                        if ( ( matches_begin ? matches_begin.length : 0 ) < ( matches_end ? matches_end.length : 0 ) ) {
                            link = link.substr( 0, link.length - 1 );
                            idx_last--;
                        }
                    }

                    // Ending non-quote punctuation character?
                    if ( options.punct_regexp ) {
                        link = link.replace( options.punct_regexp, function(a){
                            idx_last -= a.length;
                            return '';
                        });
                    }
                } while ( link.length && link !== link_last );

                href = link;

                // Add appropriate protocol to naked links.
                if ( !SCHEME_RE.test( href ) ) {
                    href = ( href.indexOf( '@' ) !== -1 ? ( !href.indexOf( MAILTO ) ? '' : MAILTO )
                        : !href.indexOf( 'irc.' ) ? 'irc://'
                            : !href.indexOf( 'ftp.' ) ? 'ftp://'
                                : 'http://' )
                        + href;
                }

                // Push preceding non-link text onto the array.
                if ( idx_prev != idx ) {
                    parts.push([ txt.slice( idx_prev, idx ) ]);
                    idx_prev = idx_last;
                }

                // Push massaged link onto the array
                parts.push([ link, href ]);
            }

            // Push remaining non-link text onto the array.
            parts.push([ txt.substr( idx_prev ) ]);

            // Process the array items.
            for ( i = 0; i < parts.length; i++ ) {
                html += options.callback.apply( window, parts[i] );
            }

            // In case of catastrophic failure, return the original text;
            return html || txt;
        },

        isObjectEmpty : function (obj){
            var flag = true;

            if (obj && (this.isObject(obj))){
                for (var i in obj){
                    flag = false;
                }
            }

            return flag;
        },

        StringToObj : function (_data){
            var res = null;

            if (this.isString(_data)){
                try {
                    res = JSON.parse(_data);
                } catch(e){
                    // console.error('Error. Can\'t convert to JSON:\n' + _data);
                }
            }

            return res || _data;
        },

        isNewNotificationSupported: function () {
            if (!window.Notification || !Notification.requestPermission)
                return false;
            if (Notification.permission !== 'granted')
                // throw new Error('You must only call this *before* calling Notification.requestPermission(), otherwise this feature detect would bug the user with an actual notification!');
                return false;

            // try {
            //     new Notification('');
            // } catch (e) {
            //     if (e.name === 'TypeError')
            //     return false;
            // }
            return true;
        },

        CreateNotification : function (opt) {
            if (serviceList.notify !== null){
                clearTimeout(serviceList.idNotify);

                serviceList.notify.close();
                serviceList.idNotify = 0;
                serviceList.notify = null;
            }

            if (!serviceList.noNotify && serviceList.isNewNotificationSupported()){
                serviceList.notify = new window.Notification(opt.title || " ", {
                    icon   : mcConst.imagesPath.all + '75x75.png',
                    tag    : opt.tag || "mcNotify",
                    body   : opt.body || "Empty"
                });

                serviceList.idNotify = setTimeout(function(){
                    serviceList.notify.close();
                    serviceList.idNotify = 0;
                    serviceList.notify   = null;
                }, opt.timeOut);

                serviceList.notify.onerror = function(){
                    if (console) {
                        console.warn("permission state = default or denied");
                    }

                    clearTimeout(serviceList.idNotify);

                    serviceList.idNotify = 0;
                    serviceList.notify = null;
                    serviceList.noNotify = true;
                };

                if (opt.onShow){
                    serviceList.notify.onshow = function(){
                        opt.onShow();
                    };
                }

                if (opt.click){
                    serviceList.notify.onclick = function() {
                        clearTimeout(serviceList.idNotify);

                        if (serviceList.notify) {
                            serviceList.notify.close();
                            serviceList.notify = null;
                        }

                        serviceList.idNotify = 0;

                        window.focus();

                        opt.click();
                    };
                }

                if (serviceList.notify.show) {
                    serviceList.notify.show();
                }
            }
        },

        CheckNotification : function (rrr){
            var res = false;

            if (window.webkitNotifications || window.Notification) {
                if ((window.webkitNotifications && window.webkitNotifications.checkPermission() === 0) || Notification.permission === "granted") { // 0 is PERMISSION_ALLOWED
                    res = true;
                    serviceList.noNotify = false;
                } else {
                    if (window.Notification){
                        Notification.requestPermission(function (permission) { // Whatever the user answers, we make sure Chrome stores the information
                            if(!('permission' in Notification)) {
                                Notification.permission = permission;
                            }
                        });
                    } else {
                        window.webkitNotifications.requestPermission(function(ssss){
                            rrr = ssss === 'granted';
                            serviceList.noNotify = !rrr;
                        });
                    }
                }
            } else {
                console.warn("Notifications are not supported for this Browser/OS version yet.");
            }

            return res;
        },

        mobileDetection : {
            Android:function () {
                return navigator.userAgent.match(/Android/i);
            },
            BlackBerry:function () {
                return navigator.userAgent.match(/BlackBerry/i);
            },
            iOS:function () {
                return navigator.userAgent.match(/iPhone|iPad|iPod/i);
            },
            Opera:function () {
                return navigator.userAgent.match(/Opera Mini/i);
            },
            Windows:function () {
                return navigator.userAgent.match(/IEMobile/i);
            },
            any:function () {
                return (this.Android() || this.BlackBerry() || this.iOS() || this.Opera() || this.Windows()) || false;
            }
        },

        MyFormatTime : function (time, short){
            var res = "";

            var ss = parseInt(time % 60);
            var hh = parseInt(time / 3600);
            var nn = parseInt(time / 60) - (hh * 60);

            if (short){
                res = ((nn < 10) ? ("0" + nn) : nn) + ":" + ((ss < 10) ? ("0" + ss) : ss);
            } else {
                res = ((hh < 10) ? ("0" + hh) : hh) + ":" + ((nn < 10) ? ("0" + nn) : nn) + ":" + ((ss < 10) ? ("0" + ss) : ss);
            }

            return res;
        },

        startOfDay : function(day){
            var now = day.getTime();

            return  now - (day.getHours()*1000*60*60 + day.getMinutes()*1000*60 + day.getSeconds()*1000 + day.getMilliseconds());
        },

        storage: {
            get: function () {
                let res;

                try {
                    res = webix.storage.local.get.apply(null, arguments);
                } catch (e) {}
                
                return res;
            },
            put: function () {
                try {
                    webix.storage.local.put.apply(null, arguments);
                } catch (e) {}
            },
            remove: function () {
                try {
                    webix.storage.local.remove.apply(null, arguments);
                } catch (e) {}
            }
        },

        detectLang : function (init){
            init = init === "undefined" || !init ? null : init;
            
            var locale = init || ( (window.navigator.language || window.navigator.userLanguage).slice(0, 2).toLowerCase() );
            var lang = locale;

            if (locale !== 'en' && locale !== 'ru' && locale !== 'uk') {
                locale = MC_RESOURCE.TextSource.www[_api] + 'en';
                lang = 'en';
            } else {
                locale = MC_RESOURCE.TextSource.www[_api] + locale;
            }

            // webix.storage.local.put(mcConst.storageFields.lang, lang);
            serviceList.storage.put(mcConst.storageFields.lang, lang);

            return [locale, lang];
        },

        Lang : function(id, items, term){
            var opt = {};

            if (serviceList.isObject(id)){
                opt = id;
            } else {
                opt = {
                    id   : id,
                    items: items,
                    term : term,
                    html : false
                };
            }

            var res = mcConst[opt.from ? "LMSG_" + opt.from : "LMSG"][opt.id.toString()];

            if (opt.html){
                if (serviceList.isArray(opt.items)){
                    opt.items.forEach(function (t, i) {
                        if (t) {
                            opt.items[i] = t.replace(/</ig, "&lt;");
                        }
                    });
                } else
                if (opt.items) {
                    opt.items = opt.items.replace(/</ig, "&lt;");
                }
            }

            return opt.items ? serviceList.myReplace(res, opt.items, opt.term) : res;
        },

        getElementByClass : function(classList, _node){
            var res  = null;
            var node = _node || document;

            if(document.getElementsByClassName) {
                res = node.getElementsByClassName(classList)
            } else {
                var list = node.getElementsByTagName('*');
                var length = list.length;
                var classArray = classList.split(/\s+/);
                var classes = classArray.length;
                var result = [];

                for (var i = 0; i < length; i++) {
                    for (var j = 0; j < classes; j++)  {
                        if (list[i].className.search('\\b' + classArray[j] + '\\b') != -1) {
                            result.push(list[i]);

                            break
                        }
                    }
                }

                res = result;
            }

            return res;
        },

        myReplace : function(source, _items, term){
            var res = source;
            var items = [];

            if (_items !== void(0) && source){
                var _term = term || "%s";

                if (!serviceList.isArray(_items)) {
                    items.push(_items);
                } else {
                    items = _items;
                }

                if (items.length > 0){
                    res = source.toString().replace(_term, items.shift());
                    res = serviceList.myReplace(res, items, _term);
                }
            }

            return res;
        },

        initResize : function(source, Name){
            mcConst.scrResize = source;
            mcConst.isShowed  = Name;
        },

        showView : function(view){
            if (view && view.className.indexOf('hidden') !== -1) {
                view.className = view.className.replace(' hidden', "");
            }
        },

        hideView : function(view){
            if (view && view.className.indexOf('hidden') === -1) {
                view.className += ' hidden';
            }
        },

        showCurrentView : function(Name, $rootScope, view, options){
            options = options || {};

            if (mcConst.isShowed !== Name) {
                mcConst.isShowed && $rootScope.$broadcast('hide' + mcConst.isShowed);
                $rootScope.$broadcast('setLocation', ['/' + $rootScope.currentRootPath + '/' + Name + '/', options.callBack, options.title]);

                serviceList.showView(view);

                mcConst.isShowed = Name;
            }
        },

        getLangItemsFromList : function(from, to, correct){
            var res = [];

            correct = correct || 0;

            for (var i = from; i <= to; i++){ // 249 492
                res.push({
                    id    : (i - from + correct).toString(),
                    value : serviceList.Lang(i)
                })
            }

            return res;
        },

        getLanguagesItems : function(from, to, correct){
            var res = [];

            correct = correct || 0;

            for (var i = from; i <= to; i++){ // 249 492
                res.push({
                    id    : (i - from + correct).toString(),
                    value : mcConst.LanguagesList[i]
                })
            }

            return res;
        },

        GetFioFormatList : function(){
            return serviceList.getLangItemsFromList(975, 983);/*.sort(function(a, b){
            return serviceList.sortAB(a.value.toLowerCase(), b.value.toLowerCase());
        });*/
        },

        sortAB : function(a,b,invert){
            return (a > b) ? (invert ? -1 : 1) : ((a < b) ? (invert ? 1 : -1) : 0);
        },

        GetCountriesList : function(){
            var res = serviceList.getLanguagesItems(249, 492, 1).sort(function(a, b){
                return serviceList.sortAB(a.value.toLowerCase(), b.value.toLowerCase());
            });

            res.unshift({
                id   : '-1',
                value: serviceList.Lang({id: 140, from: "admin"}) // "140":"Ничего не выбрано",
            });

            return res;
        },

        GetMaritalStatusList : function(){
            return serviceList.getLangItemsFromList(151, 157, 1);
        },

        GetSpokenLangList : function(){
            var res = serviceList.getLanguagesItems(180, 248, 1).sort(function(a, b){
                return serviceList.sortAB(a.value.toLowerCase(), b.value.toLowerCase());
            });

            res.unshift({
                id: '-1',
                value: serviceList.Lang({id: 140, from: "admin"}) // "140":"Ничего не выбрано",
            });

            return res;
        },

        GetInterestsList : function(){
            var res = serviceList.getLangItemsFromList(494, 543, 1);

            res.unshift({
                id: '-1',
                value: serviceList.Lang(140) // "140":"Ничего не выбрано",
            });

            return res;
        },

        GetPastList : function(){
            var res = serviceList.getLangItemsFromList(546, 553, 1);

            res.unshift({
                id: '-1',
                value: serviceList.Lang(140) // "140":"Ничего не выбрано",
            });

            return res;
        },

        GetPastOrgList : function(){
            var res = serviceList.getLangItemsFromList(554, 573, 1);

            res.unshift({
                id: '-1',
                value: serviceList.Lang(140) // "140":"Ничего не выбрано",
            });

            return res;
        },

        GetWeekDays : function(){
            return serviceList.getLangItemsFromList(646, 652);
        },

        SaveSessionSettings : function(login, pwd, servPwd, rm, email){
            if (serviceList.isObject(login)){
                pwd     = login.pwd;
                servPwd = login.servPwd;
                rm      = login.rm;
                login   = login.login;
                // email   = login.Email;
            }

                serviceList.storage.put(mcConst.storageFields.Login, login);

                if (rm){
                    serviceList.storage.put(mcConst.storageFields.Pwd, pwd);
                    serviceList.storage.put(mcConst.storageFields.ServPwd, servPwd);
                    serviceList.storage.put(mcConst.storageFields.Rm, true);

                    // if (mcConst.storageFields.Email) webix.storage.local.put(mcConst.storageFields.Email, email); // for websupport
                } else {
                    serviceList.storage.remove(mcConst.storageFields.Pwd);
                    serviceList.storage.remove(mcConst.storageFields.ServPwd);
                    serviceList.storage.remove(mcConst.storageFields.Rm);

                    // if (mcConst.storageFields.Email) webix.storage.local.remove(mcConst.storageFields.Email); // for websupport
                }

        },

        LoadSessionSettings : function(){
            var res = {};

                res.login   = serviceList.storage.get(mcConst.storageFields.Login);
                res.pwd     = serviceList.storage.get(mcConst.storageFields.Pwd);
                res.servPwd = serviceList.storage.get(mcConst.storageFields.ServPwd);
                res.rm      = serviceList.storage.get(mcConst.storageFields.Rm);

            // if (mcConst.storageFields.Email) res.Email = webix.storage.local.get(mcConst.storageFields.Email);

            return res;
        },

        ClearSessionSettings: function(leaveUIN, noAutoconnectOnReload){
                if (!leaveUIN) {
                    serviceList.storage.remove(mcConst.storageFields.Login);
                }

                serviceList.storage.remove(mcConst.storageFields.Pwd);
                serviceList.storage.remove(mcConst.storageFields.ServPwd);
                serviceList.storage.remove(mcConst.storageFields.Rm);

                if (noAutoconnectOnReload){
                    serviceList.storage.put(mcConst.storageFields.AutoRld, true);
                } else {
                    serviceList.storage.remove(mcConst.storageFields.AutoRld);
                }
        },

        toNormalDate : function (value, needTime){
            if (serviceList.isString(value)) {
                value = value.split('.');
            }

            var date = value[0] + '.' + //day
                value[1] + '.' + //month
                value[2];        //year

            var time = value[3] + ':' + //hour
                value[4] + ':' + //minutes
                value[5];        //seconds

            return date + ((needTime)? " " + time : "");
        },

        sortableDate : function(date, noSec){
            var dd = date.split('.');

            return dd[2] + '.' + dd[1] + '.' + dd[0] + ' ' + dd[3] + ':' + dd[4] + (!noSec ? ':' + dd[5] : '');
        },

        secToTime : function(sec){
            var ss = sec % 60;
            var dd = parseInt(sec / 86400);
            sec = sec - 86400*dd;
            var hh = parseInt(sec / 3600);
            var nn = parseInt(sec / 60) - (hh * 60);

            return (dd) + ':' + ((hh < 10) ? ("0" + hh) : hh) + ":" + ((nn < 10) ? ("0" + nn) : nn) + ":" + ((ss < 10) ? ("0" + ss) : ss);
        },

        formatNumber : function(numb){
            var stNumb = numb.toString();
            var res = [];
            var id = 1;

            for (var i = stNumb.length - 1; i >= 0; i --){
                res.unshift(((id === 3) ? " " : "") + stNumb[i]);

                id = (id === 3) ? 1 : (id + 1);
            }

            return res.join('');
        },

        convertBool : function (val) {
            switch (val) {
                case true:  val = '1'; break;
                case false: val = '0'; break;
                default:    val = val + "";
            }

            return val;
        },

        convertIntToBool : function (val) {
            return serviceList.isBoolean(val) ? val : val == 1;
        },

        clearPlaneObj : function(obj){
            for (var i in obj){
                obj[i] = null;
            }
        },

        Queue : function(lookupTime, loop){
            var self      = this;
            var needRun   = [];
            var canNext   = loop || false;
            var paramList = [];
            var nowRunned = false;
            var time      = lookupTime || 100;

            var lookUp    = null;

            function start(){
                return setInterval(function(){
                    if (!nowRunned && needRun.length > 0){
                        nowRunned = true;

                        var arg = (serviceList.isArray(paramList[0])) ? paramList[0] : [paramList[0]];

                        needRun[0].apply(self, arg);
                    }
                }, time);
            }

            this.next = function(){
                if (needRun.length > 0){
                    needRun.shift();
                    paramList.shift();

                    nowRunned = false;
                } else
                if (!canNext){
                    clearInterval(lookUp);

                    self = null;
                }
            };

            this.addTask = function (qItem, params){
                if (needRun.length === 0 && !nowRunned) {
                    lookUp = start();
                }

                needRun.push(qItem);
                paramList.push(params);

                return needRun.length;
            };
        },

        TaskList : function(_scope){
            var self  = this;
            var list  = [];
            var scope = {};

            this.AddTask = function(task){
                list.push(task);
            };

            this.Next = function(){
                if (list[0]){
                    list.shift().apply(scope, arguments);
                } else {
                    self = null;
                }
            };

            this.Run = function(){
                self.Next();
            };

            scope = serviceList.Marge({
                next : self.Next,
                Next : self.Next
            }, _scope || {});
        },

        transformDataObject : function(source, dependency){
            var res = [];

            if (source && dependency){
                for ( var i = 0; i < source.length; i++){
                    var item = {};

                    for (var j = 0; j < dependency.length; j++){
                        item[dependency[j][1]] = source[i][dependency[j][0]].toString();
                    }

                    res.push(item);
                }
            } else {
                res = source;
            }

            return res;
        },

        networkInterfaces: function(IPVer, IPlist){
            var myType =(IPVer == 0) ? "IPv4" : "IPv6"; // $scope.data.IPVer
            var IPs    = [].concat(IPlist[myType]); // $scope.data.networkInterfaces[myType]

            for (var i = 0; i < IPs.length; i++){
                IPs[i] = {id : IPs[i], value: (( IPs[i] == '0.0.0.0') || (IPs[i] == '::')) ? serviceList.Lang(667) : IPs[i]};// "667": "слушать всё",
            }

            return IPs;
        },

        correctStringWithCRLF : function(val){
            return (serviceList.isString(val)) ? val.replace(/(?!\r)\n/g, '\r\n') : val;
        },

        removeCRFL: function(text){
            return text.toString().replace(/\n/g, '<br>').replace(/\r/g, '');
        },

        initChangesApplyForSettings: function($scope, $rootScope, CMD, applyText, storage, cancelSave){
            var backupItems = {};

            storage = storage || mcConst.dataModels.SettingsNetwork;

            function clearChangedData (){
                $scope.changedData.data.Items    = {};
                $scope.changedData.data.Desc     = "";
                $scope.changedData.data.ShowDesc = false;
            }

            $scope.changedData = {
                data : {
                    Desc   : "",
                    Items  : {},
                    ShowDesc : false,
                    Reopen : false
                },
                clearChangedData: clearChangedData,
                onApply : function() {
                    $scope.data = serviceList.Marge($scope.data, $scope.changedData.data.Items);
                    backupItems = serviceList.Marge({}, $scope.changedData.data.Items);

                    var data = {};

                    if ($scope.changedData.data.Items.hasOwnProperty("TURNPortTCP")){
                        data.turn = $scope.changedData.data.Items["TURNPortTCP"];
                    }
                    if ($scope.changedData.data.Items.hasOwnProperty("WEBTCPPort")){
                        data.web = $scope.changedData.data.Items["WEBTCPPort"];
                    }
                    if ($scope.changedData.data.Items.hasOwnProperty("TCPPort")){
                        data.core = $scope.changedData.data.Items["TCPPort"];
                    }
                    if ($scope.changedData.data.Items.hasOwnProperty("FTPPort")){
                        data.ftp = $scope.changedData.data.Items["FTPPort"];
                    }
                    if ($scope.changedData.data.Items.hasOwnProperty("FTPPortsPool")){
                        data.ftprange = $scope.changedData.data.Items["FTPPortsPool"];
                    }
                    if ($scope.changedData.data.Items.hasOwnProperty("TURNExternalConfig")){
                        data.turnconfig = $scope.changedData.data.Items["TURNExternalConfig"];
                    }

                    if (Object.keys(data).length){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.cs_adm_check_ports,
                            mcConst.SessionID,
                            JSON.stringify(data),
                            function () {
                                $scope.applyChange($scope.data);

                                clearChangedData();
                            }
                        ]);
                    } else {
                        $scope.applyChange($scope.data);

                        clearChangedData();
                    }
                },
                onClose : function(){
                    $scope.$emit("show" + $scope.Name, []);

                    clearChangedData();
                }
            };

            function changeApplyData (id, val){
                $scope.changedData.data.ShowDesc  = true;
                $scope.changedData.data.Items[id] = serviceList.correctStringWithCRLF(val);
                $scope.changedData.data.Desc      = serviceList.Lang(590); // "590": "Список измененных параметров:<br>",

                var item = "";

                for (var i in $scope.changedData.data.Items){
                    item = $scope.changedData.data.Items[i].toString().replace(/\\/g, '\\\\').replace(/</g, "&lt;");

                    $scope.changedData.data.Desc += "<br>" + i + ": <b>" + (
                        (
                            (i.indexOf('PWD') !== -1) ||
                            (i.toLowerCase().indexOf('pass') !== -1) ||
                            (i === "UseConnPass")
                        ) ? "*****" : item ) + "</b>"; // &#092;
                }

                $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
            }

            function checkLastSlash(data, where) {
                if (data[where] && ["\\", "/"].indexOf(data[where][data[where].length - 1]) === -1){
                    data[where] += '\\';
                }
                // if (data.BackupsDir && (data.BackupsDir[data.BackupsDir.length - 1] != '\\') && (data.BackupsDir[data.BackupsDir.length - 1] != '/')){
                //     data.BackupsDir += '\\';
                // }
            }

            $scope.change = function(newV, oldV){
                if ($scope.skipChangeNow) return;

                var id = serviceList.copy(this.config.id, 3);
                var valid = true;
                // var restoreValue = false;

                if (newV == undefined){
                    newV = this.getValue();
                }

                if (oldV === undefined){
                    oldV = $rootScope.mcStorage[storage][id];
                }

                if (this.config.pathAlias){
                    newV = serviceList.trim(newV.replace(/\W/ig, ""));

                    this.$setValue(newV);
                } else
                if (this.config.view === "checkbox"){
                    newV = serviceList.convertIntToBool(newV);
                    oldV = serviceList.convertIntToBool(oldV);
                } else
                if (this.config.mcType === "port"){
                    valid = !isNaN(parseInt(newV)) && newV && (newV > 0) && (newV < 65534); //^\d+$/.test(newV);
                } else
                // if (this.config.id === "stgRobotAvatarNum"){
                //     valid = (/^\d+$/.test(newV)) && (newV >= 0) && (newV <= 239);
                // } else
                // if (this.config.id === "stgMaxUploadFileSize"){
                //     newV = serviceList.convertIntToBool(newV);
                // } else
                if (this.config.id === "stgRobotName"){
                    valid = serviceList.trim(newV) !== "";
                } else
                if (this.config.id === "stgExternalIP" || this.config.id === "stwExternalIP"){
                    valid = serviceList.isValidIpAddress(newV) || serviceList.isValidHostName(newV) ? serviceList.trim(newV).indexOf(":") === -1 : false;

                    if (!valid){
                        newV = $rootScope.mcStorage[storage][id];
                    }

                    changeApplyData(id, newV);
                }

                if (valid && (mcConst.isShowed === $scope.Name) && (serviceList.correctStringWithCRLF(newV) !== oldV)){
                    if (this.config.pathAlias && !newV){
                        newV = oldV;
                    }

                    changeApplyData(id, newV);
                } else {
                    if (((this.config.view !== 'text') && (this.config.view !== 'textarea'))) {
                        this.$setValue(oldV);
                    }
                }
            };

            $scope.changeExc = function () {
                if (this.config && this.config.view === 'counter' || this.config.view === 'text') {
                    var newV = this.getValue();
                    var oldV = $scope.data[serviceList.copy(this.config.id, 3)];

                    if (!isNaN(newV)) {
                        $scope.change.apply(this, [newV, oldV]);
                    } else {
                        $scope.change.apply(this, [oldV, 1]);
                        this.$setValue(oldV);
                    }
                }
            };

            $scope.applyChange = function(data){
                // webix.message(applyText($scope.changedData.data.Items));

                if (cancelSave && cancelSave()){
                    return;
                }

                if ($scope._onApply){
                    $scope._onApply(data);
                }

                ["BackupsDir", "FTPPublicDir", "FTPPersonalDir", "FilesDir", "LogsDir"].forEach(function (t) {
                    checkLastSlash(data, t);
                });

                var res = JSON.stringify(data, function(key, value){
                    return value;
                });

                $rootScope.$broadcast('SendCMDToServer', [
                    CMD,
                    mcConst.SessionID,
                    res,
                    function () {
                        webix.message(applyText(backupItems));
                        
                        $rootScope.mcStorage[storage] = serviceList.Marge($rootScope.mcStorage[storage], backupItems || {});
                    }
                ]);

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst._CMD_.cs_adm_get_server_options,
                    mcConst.SessionID
                ]);
            };
        },

        openNewWindow : function(url, blank){
            var newWindow = window.open(url, blank ? '_blank' : '', blank ? '' : 'menubar=no,resizable=0,directories=no,location=no,toolbar=no,status=no,screenX=0,screenY=0,width=1000,height=600');

            if (newWindow) newWindow.focus();
        },

        onOffToBool : function(val){
            return serviceList.isBoolean(val) ? val : val == 'on';
        },

        InObject : function(item, obj){
            var res = false;

            for(var i in obj) {
                if (item == obj[i]) {
                    res = true;
                    break;
                }
            }

            return res;
        },

        getIdxByIdFromData : function(data, id){
            var res = null;

            for (var i = 0; i < data.length; i ++){
                if (data[i].id == id) {
                    res = i;
                    break;
                }
            }

            return res;
        },

        getIdxByNameFromData : function(data, key, val){
            var res = null;

            for (var i = 0; i < data.length; i ++){
                if ((data[i][key] !== undefined) && (data[i][key] == val)) {
                    res = i;
                    break;
                }
            }

            return res;
        },

        getValueByNameFromData : function(data, key, val){
            var res = "";

            for (var i = 0; i < data.length; i ++){
                if ((data[i][key] !== undefined) && (data[i][key] == val)) {
                    res = data[i][key];
                    break;
                }
            }

            return res;
        },

        oldLicenseKey : function(key){
            var res = false;
            var reg = /^([A-Z0-9]{4}\-){6}[A-Z0-9]{4}$/;

            res = reg.test(serviceList.trim(key));

            if (res) {
                res = serviceList.trim(key);
            }

            return res;
        },

        checkLicenseKey : function(key){
            var res = false;
            var reg = /^([A-F0-9]{4}\-){10}[A-F0-9]{4}$/;

            res = reg.test(serviceList.trim(key));

            if (res) {
                res = serviceList.trim(key);
            }

            return res;
        },

        checkGuestKey : function(key){
            var res = false;
            var reg = /^([A-F0-9]{4}\-){5}[A-F0-9]{4}$/;

            res = reg.test(serviceList.trim(key));

            if (res) {
                res = serviceList.trim(key);
            }

            return res;
        },

        checkQuizKey : function(key){
            var res = false;
            var reg = /^[A-F0-9]{6,8}\-([A-F0-9]{4}\-){3}[A-F0-9]{4}$/;

            res = reg.test(serviceList.trim(key));

            if (res) {
                res = serviceList.trim(key);
            }

            return res;
        },

        renameProperty : function (oldName, newName) {
            if (this.hasOwnProperty(oldName)) {
                this[newName] = serviceList.trim(this[oldName]);

                delete this[oldName];
            }
            return this;
        },

        ListButtonSet: function(opt){
            function add(){
                $$(_idBtn).hide();
                $$(_idBFld).show();

                if (options.actions.beforeAdd){
                    options.actions.beforeAdd();
                }

                if ( options.hideSearchField ) $$(options.hideSearchField).hide();

                if (items.fields[0]) {
                    if (types[options.type] !== types.combo) {
                        items.fields[0].setValue("");
                        if (items.fields[1]) {
                            items.fields[1].setValue("");
                        }
                    }

                    items.fields[0].focus();

                    if (options.actions.preview){
                        options.actions.preview(items.fields[0]);
                    }
                } else {
                    throw new Error('No fields found!');
                }

                if (options.actions.afterShow){
                    options.actions.afterShow(items.fields);
                }
            }

            function save (){
                if (options.actions.save && options.actions.save.apply(null, items.fields)){
                    back();
                }
            }

            function back (){
                if (items.fields[0] && items.fields[0].hasOwnProperty('getPopup')){
                    items.fields[0].getPopup().hide();
                }

                $$(_idBFld).hide();
                $$(_idBtn).show();

                if ( options.hideSearchField ) $$(options.hideSearchField).show();

                if (options.actions.afterClose){
                    options.actions.afterClose();
                }
            }

            function del(){
                var _list        = $$(options.list);
                var selectedItem = _list.getSelectedItem();

                if (selectedItem && options.actions.del){
                    var len     = selectedItem[options.selectedItem] ? selectedItem[options.selectedItem].length : 0;
                    var delText = serviceList.Lang(1078, len > 15 ? serviceList.copy(selectedItem[options.selectedItem], 0, 15) + "..." : selectedItem[options.selectedItem]); // "1078":"Удалить %s из списка?",

                    if (serviceList.isArray(selectedItem)){
                        delText = serviceList.Lang(1142); // "1142":"Удалить отмеченные элементы?",
                    }

                    options.regShowWindow(serviceList.RandomHash(4), webix.confirm({
                        type  : "confirm-warning",
                        text  : delText,
                        ok    : serviceList.Lang(581), // "581": "Удалить",
                        cancel: serviceList.Lang(103), // "103": "Отмена",
                        callback:function(yes){
                            if (yes){
                                options.actions.del(selectedItem, _list);

                                if (serviceList.isArray(selectedItem)){
                                    for (var i = 0; i < selectedItem.length; i ++){
                                        _list.remove(selectedItem[i].id);
                                    }

                                    webix.message(serviceList.Lang(1506)); // "1506":"Элементы удалены",
                                } else {
                                    webix.message(serviceList.Lang(1077, selectedItem[options.selectedItem])); // "1077":"%s удален",

                                    _list.remove(selectedItem.id);
                                }

                                if (options.actions.afterDel) options.actions.afterDel(_list);
                            }
                        }
                    }));
                }
            }

            function clear(){
                //if ($$(options.list).serialize().length){
                options.regShowWindow(serviceList.RandomHash(4), webix.confirm({
                    type  : "confirm-warning",
                    text  : serviceList.Lang(1072),// "1072":"Очистить список?",
                    ok    : serviceList.Lang(581), // "619": "Очистить",
                    cancel: serviceList.Lang(103), // "103": "Отмена",
                    callback:function(yes){
                        if (yes){
                            if (options.actions.clear()){
                                $$(options.list).clearAll();
                            }
                        }
                    }
                }));
                //}
            }

            function afterRender(){
                // items.fields[0] = this;

                webix.UIManager.addHotKey("Enter", function() {
                    save();

                    return false;
                }, this);

                webix.UIManager.addHotKey("Esc", function() {
                    back();

                    return false;
                }, this);
            }
            
            function edit() {
                var _list        = $$(options.list);
                var selectedItem = _list.getSelectedItem();

                if (selectedItem && options.actions.save) {
                    $$(_idBtn).hide();
                    $$(_idBFld).show();

                    if ( options.hideSearchField ) $$(options.hideSearchField).hide();

                    items.fields[0].setValue(selectedItem.IP);
                    items.fields[1].setValue(selectedItem.ClientType);
                    items.fields[2].setValue(selectedItem.Comment);
                    items.fields[3] = selectedItem.id;

                    items.fields[0].focus();

                    if (options.actions.preview){
                        options.actions.preview(items.fields[0]);
                    }

                    if (options.actions.afterShow){
                        options.actions.afterShow(items.fields);
                    }
                }
            }

            var types   = {
                'textComment'   : 1,
                '1'             : 1,
                'text'          : 2,
                '2'             : 2,
                'combo'         : 3,
                '3'             : 3,
                'textRichselectComment' : 4,
                '4'             : 4,
                'textRichselectCommentEdit' : 5,
                '5'             : 5
            };

            var options = serviceList.Marge({
                type   : types.textComment,
                idBtn  : serviceList.RandomHash(10),
                gravity: 1,
                actions: {
                    del    : null,
                    clear  : null,
                    save   : null,
                    preview: null,
                    enable : null,
                    disable: null,
                    beforeAdd: null,
                    afterClose: null
                },
                text : {
                    field1 : "", // "1075":"Введите IP, маску или диапазон",
                    field2 : "", // serviceList.Lang(1032) "1032":"Комментарий:",
                    field3 : ""  // serviceList.Lang(1032) "1032":"Комментарий:",
                },
                visibleBtns: {
                    add: true,
                    del: true,
                    cls: true
                },
                titleBtns: {
                    add: "",
                    del: "",
                    cls: "",
                    save: "",
                    cancel: "",
                },
                list : null,
                listData : [],
                regShowWindow: null,
                selectedItem: 'value'
            }, opt || {});

            var res     = null;

            if (serviceList.isFunction(options._back)){
                options._back(back);
            }

            if (!options.regShowWindow){
                var errtext = 'Needs \"regShowWindow\" for show popup windows in ' + options.list;

                console.error(errtext);

                webix.message({ type:"error", text: errtext, expire : mcConst.errMessageExpire * 2});
            } else {
                var _idBtn  = options.idBtn;
                var _idBFld = serviceList.RandomHash(10);
                var items   = {
                    fieldBlock: null,
                    fields    : [],
                    list      : null
                };

                res = { gravity: options.gravity, rows : [
                    { id: _idBtn, cols: [] // блок с кнопками: добавить удалить очистить
                        .concat([{ view: "button", value: options.titleBtns.add || serviceList.Lang(50), hidden: !options.visibleBtns.add, click: add, css: "applyButton"}]) // "50" : "Добавить",
                        .concat([{ view: "button", value: options.titleBtns.del || serviceList.Lang(52), hidden: !options.visibleBtns.del, click: del, type: "danger"}])     // "52" : "Удалить",
                        .concat(types[options.type] === types.textRichselectCommentEdit ? [{ view: "button", value: serviceList.Lang(51), hidden: !options.visibleBtns.del, click: edit}] : [])    // "51" : "Изменить",
                        .concat(options.visibleBtns.cls ? [{ view: "button", value: options.titleBtns.cls || serviceList.Lang(619), hidden: !options.visibleBtns.cls,click: clear}] : []) // "619": "Очистить",
                    },
                    { id: _idBFld, hidden: true, rows: [{}]} // появляющийся блок
                ], on: {
                    onShow: function (){
                        
                    }
                }};

                res.emit = {
                    add : add,
                    edit: edit,
                    del : del
                };

                switch (types[options.type]){
                    case types.textComment:
                        res.rows[1].rows = [
                            { view: "text", placeholder: options.text.field1, on: { onAfterRender: function() { items.fields[0] = this; afterRender.apply(this, arguments); } } },
                            { cols: [
                                { view: "text", placeholder: options.text.field2, // id: "ipfAcceptAddComment",
                                    on: { onAfterRender: function() { items.fields[1] = this; afterRender.apply(this, arguments); } }
                                },
                                { view: "button", value: options.titleBtns.save || serviceList.Lang(104), width: 100, click: save}, // "104": "Сохранить",
                                { view: "button", value: options.titleBtns.cancel || serviceList.Lang(103), width: 100, click: back, type: "danger"}  // "103": "Отмена",
                            ]}
                        ];
                    break;

                    case types.text:
                        res.rows[1].cols = [
                            { view: "text", placeholder: options.text.field1, on: { onAfterRender: function() { items.fields[0] = this; afterRender.apply(this, arguments); } } },// "1075":"Введите IP, маску или диапазон",
                            { view: "button", value: options.titleBtns.save || serviceList.Lang(104), width: 100, click: save}, // "104": "Сохранить",
                            { view: "button", value: options.titleBtns.cancel || serviceList.Lang(103), width: 100, click: back, type: "danger"} // "103": "Отмена",
                        ];
                    break;

                    case types.combo:
                        res.rows[1].cols = [
                            { view: "combo", options: options.listData, on: { onAfterRender: function() { items.fields[0] = this; afterRender.apply(this, arguments); } } },
                            { view: "button", value: options.titleBtns.save || serviceList.Lang(104), width: 100, click: save, css: "applyButton"}, // "104": "Сохранить",
                            { view: "button", value: options.titleBtns.cancel || serviceList.Lang(103), width: 100, click: back, type: "danger"} // "103": "Отмена",
                        ];
                    break;

                    case types.textRichselectComment:
                        res.rows[1].rows = [
                            { cols: [
                                { view: "text", placeholder: options.text.field1, on: { onAfterRender: function() { items.fields[0] = this; afterRender.apply(this, arguments); } } },
                                { view: "richselect", placeholder: options.text.field2, options: options.listData, on: { onAfterRender: function() { items.fields[1] = this } } }
                            ]},
                            { cols: [
                                { view: "text", placeholder: options.text.field3, // id: "ipfAcceptAddComment",
                                    on: { onAfterRender: function() { items.fields[2] = this; afterRender.apply(this, arguments); } }
                                },
                                { view: "button", value: options.titleBtns.save || serviceList.Lang(104), width: 100, click: save}, // "104": "Сохранить",
                                { view: "button", value: options.titleBtns.cancel || serviceList.Lang(103), width: 100, click: back, type: "danger"}  // "103": "Отмена",
                            ]}
                        ];
                    break;

                    case types.textRichselectCommentEdit:
                        res.rows[1].rows = [
                            { cols: [
                                { view: "text", placeholder: options.text.field1, on: {
                                    onAfterRender: function() {
                                        items.fields[0] = this;
                                        afterRender.apply(this, arguments);
                                    } } },
                                { view: "richselect", placeholder: options.text.field2, options: options.listData, on: {
                                    onAfterRender: function() {
                                        items.fields[1] = this
                                    } } }
                            ]},
                            { cols: [
                                { view: "text", placeholder: options.text.field3, // id: "ipfAcceptAddComment",
                                    on: { onAfterRender: function() { items.fields[2] = this; afterRender.apply(this, arguments); } }
                                },
                                { view: "button", value: options.titleBtns.save || serviceList.Lang(104), width: 100, click: function () {save(types[options.type])}}, // "104": "Сохранить",
                                { view: "button", value: options.titleBtns.cancel || serviceList.Lang(103), width: 100, click: back, type: "danger"}  // "103": "Отмена",
                            ]}
                        ];
                    break;
                }
            }

            return res;
        },

        findItemInArrayOfObj: function( arr, val, id, lowerCase ){
            for (var i = 0; i < arr.length; i++){
                if (!id){
                    for (var j in arr[i]){
                        if (lowerCase){
                            if (arr[i][j].toLowerCase() == val.toLowerCase()){
                                return i;
                            }
                        } else
                        if (arr[i][j] == val){
                            return i;
                        }
                    }
                } else
                if (lowerCase){
                    if (arr[i][id].toLowerCase() == val.toLowerCase()){
                        return i;
                    }
                } else
                if (arr[i][id] == val){
                    return i;
                }
            }

            return -1;
        },

        ContextMenu : function(_master, oldMenu, cb, onShow, removePrev, addItems, itemsCB){
            function clearSelection() {
                if (master.unselectAll){
                    master.unselectAll()
                } else {
                    master.clearSelection();
                }
            }

            function selectAll (){
                if (master.openAll){
                    master.openAll();
                }

                // clearSelection();

                if (master.selectAll){
                    master.selectAll();
                } else {
                    master.selectRange(master.getFirstId(), master.getLastId());
                }
            }

            var master = _master || {};

            if (oldMenu && removePrev) {
                oldMenu.destructor();
            }

            if (!master.contextTitle) {
                master.contextTitle = {};
            }

            var contextMenu = !oldMenu || (oldMenu && removePrev) ? {
                view  : "context",
                width : 220,
                master: master,
                body  : { rows: []},
                on: {
                    onShow: function() {
                        if (onShow) onShow.apply(this, []);
                    }
                }
            } : [];

            var items = [
                { view: "button", value: serviceList.Lang(master.contextTitle.all || 1105), click: function(){ // "1105":"Выделить все",
                    var context = this.getTopParentView();

                    if (cb) cb.call(context.getContext().obj, 'beforeSelectAll');

                    selectAll();

                    if (cb) cb.call(context.getContext().obj, 'selectAll');

                    context.hide();
                }},
                { view: "button", value: serviceList.Lang(master.contextTitle.clear || 1106), click: function(){ // "1106":"Снять выделение",
                    var context = this.getTopParentView();

                    if (cb) cb.call(context.getContext().obj, 'beforeClear');

                    clearSelection();

                    if (cb) cb.call(context.getContext().obj, 'clear');

                    context.hide();
                }},
                { view: "button", value: serviceList.Lang(master.contextTitle.invert || 1107), click: function(){ // "1107":"Инвертировать выделение",
                    var selectedItems = master.getSelectedItem();
                    var context = this.getTopParentView();

                    if (cb) cb.call(context.getContext().obj, 'beforeInvert');

                    if (serviceList.isObject(selectedItems)){
                        selectedItems = [selectedItems];
                    }

                    selectAll();

                    for (var i = 0; selectedItems && i < selectedItems.length; i ++){
                        master.unselect(selectedItems[i].id);
                    }

                    if (cb) cb.call(context.getContext().obj, 'invert');

                    context.hide();
                }}
            ].concat(addItems && addItems.length && itemsCB && itemsCB.length === addItems.length
                ? addItems.map(function (item, id){
                    item.click = function () {
                        var selectedItems = master.getSelectedItem(true);
                        
                        itemsCB[id](selectedItems);

                        this.getTopParentView().hide();
                    }

                    return item;
                })
                : []
            );

            if (oldMenu === true && !removePrev){
                contextMenu = items;
            } else {
                contextMenu.body.rows = contextMenu.body.rows.concat(items);
                
                contextMenu = webix.ui(contextMenu);
            }

            return contextMenu;
        },

        getAllUserForFillList: function(list, cb, $rootScope){
            var usersCash = $rootScope.mcStorage[mcConst.dataModels.UserManager];

            if (usersCash && usersCash.Params === "All" && !list.length){
                cb.apply(usersCash, [usersCash.Users]);
            } else
            if (!usersCash || usersCash.Params !== "All" || (list.length > 0 && usersCash.Users.length !== list.length)){
                $rootScope.$broadcast('getAllUserList', [false, function() {
                    usersCash = $rootScope.mcStorage[mcConst.dataModels.UserManager];

                    cb.apply(usersCash, [usersCash.Users]);
                }]);
            }
        },

        getAllUserWithParams: function(cb, $rootScope, params){
            var usersCash = $rootScope.mcStorage[mcConst.dataModels.UserManager];

            if (usersCash && usersCash.Params === "All" &&  params === "All"){
                cb.apply(usersCash, [usersCash.Users]);
            } else {
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_list_users,
                    mcConst.SessionID,
                    !params ? 'All' : params.Params || 'All',
                    !params ? mcConst.userFields : params.Filters || mcConst.userFields,
                    function (data) {
                        $rootScope.mcStorage.UserManager = data;

                        cb.apply(data, [data.Users]);
                    }
                ]);
            }
        },

        getMcSettings: function($rootScope, show, always){
            if (!$rootScope.mcStorage.SettingsNetwork || always){
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_server_options,
                    mcConst.SessionID,

                    function (data){
                        $rootScope.mcStorage.SettingsNetwork = data;

                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_get_server_info,
                            mcConst.SessionID,

                            function( data ){
                                $rootScope.mcStorage.ServerInfo = data;

                                if ( show ) show();
                            }
                        ]);
                    }
                ]);
            } else {
                if ( show ) show();
            }
        },

        getTitle: function(path){
            var res = "";

            switch (path){
                case "ServerInfo":      res = serviceList.Lang(10);   break; // "10" : "Информация о сервере",
                case "UserManager":     res = serviceList.Lang(49);   break; // "49" : "Список пользователей",
                case "UserProfile":     res = serviceList.Lang(1484); break; // "1484":"Профиль пользователя",
                case "GroupRights":     res = serviceList.Lang(57);   break; // "57" : "Группы прав"
                case "GroupUsers":      res = serviceList.Lang(916);  break; // "916":"Пользователи групп",
                case "Contacts":        res = serviceList.Lang(587);  break; // "587": "Общий список контактов",
                case "WorkPositions":   res = serviceList.Lang(588);  break; // "588": "Должности компании",
                case "WebSupport":      res = serviceList.Lang(938);  break; // "938":"Web-поддержка",
                case "MyChatGuest":     res = serviceList.Lang(945);  break; // "945":"MyChat Guest",
                case "LicenseMyChat":   res = serviceList.Lang(944);  break; // "944":"MyChat Server",
                case "LicenseGuest":    res = serviceList.Lang(945);  break; // "945":"MyChat Guest",
                case "UsersImports":    res = serviceList.Lang(960);  break; // "960":"Импорт пользователей",
                case "Operators":       res = serviceList.Lang(817);  break; // "817":"Модераторы",
                case "Bans":            res = serviceList.Lang(1029); break; // "1029":"Забаненные пользователи",
                case "AutoChannels":    res = serviceList.Lang(1039); break; // "1039":"Автосоздаваемые конференции",
                case "RemoteSettings":  res = serviceList.Lang(1329); break; // "1329":"Дистанционные настройки клиента",
                case "History":         res = serviceList.Lang(1134); break; // "1134":"Просмотр протоколов",
                case "FilterAntiflood": res = serviceList.Lang(1057); break; // "1057":"Антифлуд",
                case "FilterBadWords":  res = serviceList.Lang(1058); break; // "1058":"Плохие слова",
                case "FilterIP":        res = serviceList.Lang(1059); break; // "1059":"IP фильтры",
                case "FilterMAC":       res = serviceList.Lang(1060); break; // "1060":"MAC фильтры",
                case "FilterNames":     res = serviceList.Lang(1061); break; // "1061":"Блокировки названий",
                case "SettingsNetwork": res = serviceList.Lang(591);  break; // "591": "Сетевые настройки MyChat",
                case "SettingsInfo":    res = serviceList.Lang(596);  break; // "596": "Информация",
                case "SettingsLogs":    res = serviceList.Lang(598);  break; // "598": "Протоколирование",
                case "SettingsFTP":     res = serviceList.Lang(599);  break; // "599": "FTP файловый сервер",
                case "SettingsWEB":     res = serviceList.Lang(600);  break; // "600": "WEB-сервисы",
                case "SettingsBackup":  res = serviceList.Lang(601);  break; // "601": "Резервные копии",
                case "SettingsService": res = serviceList.Lang(602);  break; // "602": "Обслуживание",
                case "SettingsAPI":     res = serviceList.Lang(603);  break; // "603": "Integration API",
                case "SettingsSMTP":    res = serviceList.Lang(921);  break; // "921":"Настройка SMTP",
                case "Others":          res = serviceList.Lang(672);  break; // "672": "Дополнительно",
            }

            return res;
        },

        formatDeptList: function( data ){
            var separator = '';
            var levels = {};
            var i = 0;
            var res = [];
            var normalData = [];
            var idx;
            var deptList = [];

            while (data.length > 0 || i < data.length){
                if (data[i].ParentID == 0) {
                    normalData.push(data[i]);

                    data.splice(i, 1);
                } else {
                    idx = serviceList.findItemInArrayOfObj(normalData, data[i].ParentID, "GroupID");

                    if (idx == -1) {
                        i++;
                    } else {
                        normalData.push(data[i]);

                        data.splice(i, 1);
                    }
                }

                if (data.length > 0 && i == data.length){
                    i = 0;
                }
            }

            for (i = 0; i < normalData.length; i++){
                if (normalData[i].ParentID == 0) {
                    levels[normalData[i].GroupID] = 0;
                } else {
                    levels[normalData[i].GroupID] = levels[normalData[i].ParentID] + 1;
                }

                separator = new Array(levels[normalData[i].GroupID] + 1).join('&#151;');

                res.push({
                    id: normalData[i].GroupID,
                    value: separator + normalData[i].GroupName
                });
            }

            for (i = 0; i < normalData.length; i++){
                if (normalData[i].ParentID == 0){
                    deptList.push(res[i]);
                } else {
                    deptList.splice(serviceList.findItemInArrayOfObj(deptList, normalData[i].ParentID, "id") + 1, 0, res[i]);
                }
            }

            return deptList;
        },

        copyToBuffer: function(){
            setTimeout(function(){
                webix.message(serviceList.Lang(1483)); // "1483":"Лог скопирован в буфер обмена!",
            }, 10);

            return $$("logsContainer").$view.innerText.replace(/\n/g, '\r\n');
        },

        convertDomainToDn : function(dn){
            if (dn.indexOf('=') === -1){
                dn = dn.split('.');

                for (var i = 0; i < dn.length; i++){
                    dn[i] = 'DC=' + dn[i];
                }

                dn = dn.join(',').toUpperCase();
            } else {
                dn = dn.toUpperCase();
            }

            return dn;
        },

        convertDataToTree: function(data, withMe){
            function add(current, parent){
                var item = null;

                if (current.IsGroup){
                    item = {
                        DisplayName: current.GroupName || current.DisplayName,
                        id         : current.ID || current.id,
                        ParentID   : current.ParentID,
                        GroupID    : current.GroupID,
                        IsGroup    : true,
                        folder     : true,
                        data       : current.data || []
                    };
                } else {
                    if (!withMe && current.UIN == mcConst.UserInfo.UIN){
                        return false;
                    }

                    item = {
                        DisplayName: current.DisplayName,
                        id         : current.ID || current.id,
                        ParentID   : current.ParentID,
                        State      : current.State,
                        onlineState: current.onlineState,
                        UIN        : current.UIN,
                        TeamLead   : current.TeamLead
                    };
                }

                parent.push(item);

                return true;
            }

            var res = [];
            var structure = [];
            var _data = [].concat(data);
            var i = 0;
            var needAdd = null;

            while (_data.length > 0){
                if (_data[i].ParentID == -1){
                    _data.splice(i, 1);
                } else
                if (_data[i].ParentID == 0){
                    needAdd = add(_data[i], res);
                    if (needAdd) add(res[res.length - 1], structure);

                    _data.splice(i, 1);
                } else {
                    var idx = serviceList.findItemInArrayOfObj(structure, _data[i].ParentID, "GroupID");

                    if (idx >= 0){
                        needAdd = add(_data[i], structure);
                        if (needAdd) add(structure[structure.length - 1], structure[idx].data);

                        _data.splice(i, 1);
                    } else {
                        i++;
                    }
                }

                if (i == _data.length) {
                    i = 0;
                }
            }

            return res;
        },

        hideFrame: function(id){
            var view = document.getElementById(id);

            if (view){
                view.style.display = 'none';
            }
        },

        showFrame: function(id, inline){
            var view = document.getElementById(id);

            if (view){
                view.style.display = (inline ? 'inline-' : '') + 'block';
            }
        },

        getFrame: function(id, src){
            var res = src || document.getElementById(id);

            if (res && !res.showFrame && !res.hideFrame) {
                res.showFrame = function() {
                    serviceList.showFrame(id) };
                res.hideFrame = function() {
                    serviceList.hideFrame(id) };
            }

            return res;
        },

        convertObjToArray: function(obj, keyToField, copy){
            var res = [];

            for (var i in obj){
                if (serviceList.isObject(obj[i])){
                    if (keyToField) obj[i][keyToField] = i;

                    res.push(copy ? serviceList.Marge({}, obj[i]) : obj[i] );
                }
            }

            return res;
        },

        getStateStatuses: function(state){
            return {
                Online  : state.Online  ? serviceList.StringToArray(state.Online, ',') : serviceList.StringToArray(state.Users, ','),
                Offline : state.Offline ? serviceList.StringToArray(state.Offline, ',') : [],
                States  : state.States  ? serviceList.StringToArray(state.States, ',') : serviceList.StringToArray(state.Statuses, ',')
            };
        },

        addEvent : function(object, type, callback) {
            if (object == null || typeof(object) == 'undefined') return;
            if (object.addEventListener) {
                object.addEventListener(type, callback, false);
            } else if (object.attachEvent) {
                object.attachEvent("on" + type, callback);
            } else {
                object["on"+type] = callback;
            }
        },

        getWindowSize: function(){
            // var wndWidth = 0;
            // var wndHeight = 0;

            /*if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
                wndWidth = document.documentElement.clientWidth;
                wndHeight = document.documentElement.clientHeight;
            } else {
                if (typeof (window.innerWidth) == 'number') {
                    wndWidth = window.innerWidth;
                    wndHeight = window.innerHeight;
                } else
                if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
                    wndWidth = document.body.clientWidth;
                    wndHeight = document.body.clientHeight;
                }
            }*/

            // return {
            //     width  : wndWidth,
            //     height : wndHeight
            // };
            let {
                    width,
                    height,
                    widthOrig = null,
                    heightOrig = null,
                    scale,
                    offsetTop,
                    offsetLeft,
                    offsetTopOrig = null,
                    offsetLeftOrig = null,
                    pageLeft,
                    pageTop,
                    pageLeftOrig = null,
                    pageTopOrig = null,
                } = window.visualViewport;

            return Object.fromEntries(
                Object.entries({
                    width,
                    widthOrig,
                    height,
                    heightOrig,
                    scale,
                    offsetTop,
                    offsetTopOrig,
                    offsetLeft,
                    offsetLeftOrig,
                    pageLeft,
                    pageLeftOrig,
                    pageTop,
                    pageTopOrig,
                }).filter(([k, v]) => v !== null));
        },

        convertDnArrayToTreeTable: function(dnList, base){
            var res = [];
            var dnStructure = {};
            var dn = "distinguishedName";

            function createStructure(obj, structure, parent){
                function add (arr, item){
                    var link = {
                        value: item
                    };

                    if (structure.length === 0){
                        link = serviceList.Marge(link, obj);
                    } else {
                        // link['$row'] = "value";
                        // link['$parent'] = 0;
                        link['open'] = true;
                        link['data'] = [];
                    }

                    arr.push(link);

                    return link;
                }

                if (structure.length){
                    var item = structure.pop().replace('CN=', '');

                    parent = parent || res;

                    var idx = serviceList.findItemInArrayOfObj(parent, item, "value");

                    createStructure(obj, structure, idx === -1 ? add(parent, item).data : parent[idx].data);
                }
            }

            for (var i = 0; i < dnList.length; i++){
                dnList[i][dn] = dnList[i][dn].replace(',' + base, '');

                if (!dnStructure[dnList[i][dn]]){
                    dnStructure[dnList[i][dn]] = dnList[i][dn].split(',');

                    createStructure(dnList[i], [].concat(dnStructure[dnList[i][dn]]), null);
                }
            }

            return res;
        },

        makeIceServers: function (data, isWeb){
            /** @namespace data.IPList*/
            /** @namespace data.TURNPort*/
            /** @namespace data.Credential */
            var res = [];
            var ipList = data.IPList.split(',');

            if (ipList[0] === ""){
                ipList[0] = isWeb ? window.location.host : mcConst.ServerInfo.Host;
            }

            for (var i = 0; i < ipList.length; i++){
                var tcp  = 'turn:' + ipList[i] + ':' + data.TURNPort +'?transport=tcp';
                var udp  = 'turn:' + ipList[i] + ':' + data.TURNPort +'?transport=udp';
                var stun = 'stun:' + ipList[i] + ':' + data.TURNPort;

                res.push({
                    urls       : [stun, udp, tcp],
                        //.concat(isWeb ? tcp : [])
                        // .concat(isWeb || (mcConst.ClientSettings && mcConst.ClientSettings.MediaNetworkTransportTCP) ? stun : [])
                        // .concat(isWeb || (mcConst.ClientSettings && mcConst.ClientSettings.MediaNetworkTransportTCP) ? tcp  : [])
                        // .concat(isWeb || (mcConst.ClientSettings && mcConst.ClientSettings.MediaNetworkTransportUDP) ? udp  : []),
                        // .concat(['stun:stun.l.google.com'])

                    credential : data.Credential,
                    username   : data.UserName
                });
            }

            return res;
        },

        checkRightsCollection: function(_ids, equals){
            var res = false;
            var id = null;

            for (var i = 0; i < _ids.length; i ++){
                id = parseInt(_ids[i]) - 1;

                res = equals
                    ? res && (mcConst.MyRightsSet.RightsSet[id] == '1')
                    : res || (mcConst.MyRightsSet.RightsSet[id] == '1');
            }

            return res;
        },

        MyTimer: function (_target){
            var Now = 0;
            var id = null;
            var view = _target;

            this.setView = function (newView) {
                view = newView;
            };

            this.Start = function(){
                Now = 0;

                clearInterval(id);

                id = setInterval(function(){
                    Now++;

                    if (view) {
                        if (view.innerText !== void(0)) {
                            view.innerText = serviceList.MyFormatTime(Now, true);
                        } else {
                            view.text(serviceList.MyFormatTime(Now, true));
                        }
                    }
                }, 1000);
            };

            this.Pause = function(newTime){
                clearInterval(id);

                Now = newTime || Now;
            };

            this.Stop = function(){
                if (view) {
                    if (view.innerText !== void(0)) {
                        view.innerText = serviceList.MyFormatTime(0, true);
                    } else {
                        view.text(serviceList.MyFormatTime(0, true));
                    }
                }

                clearInterval(id);

                return serviceList.MyFormatTime(Now, true);
            };
        },
        
        openLink: function(link, param){
            var params = param || "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes";
            window.open(link, "", params);
        },

        showImportResult: function(data, $rootScope){
            var add = [];
            var upd = [];
            var err = [];
            var res = "";

            if (data && data.Results && data.Users){
                for (var i = 0; i < data.Results.length; i++){
                    switch (data.Results[i]){
                        case '0': case 0:
                        add.push(data.Users[i]);
                        break;

                        case '1': case 1:
                        upd.push(data.Users[i]);
                        break;

                        default:
                            err.push(data.Users[i]);
                    }
                }

                if (add.length){
                    res += "<span class='blue _grName'>" + mcLang(1552) + '</span><br>';// "1552":"Добавлены пользователи:",
                    res += add.join('<br>') + '<br><br>';
                }

                if (upd.length){
                    res += "<span class='green _grName'>" + mcLang(1553) + '</span><br>';// "1553":"Обновлены пользователи:",
                    res += upd.join('<br>') + '<br><br>';
                }

                if (err.length){
                    res += "<span class='red _grName'>" + mcLang(1554) + '</span><br>';// "1554":"Не добавленные пользователи:",
                    res += err.join('<br>');
                }

                var wnd = webix.ui({
                    view: "window",
                    position: "center",
                    modal: true,
                    width: 300,
                    height: 500,
                    head: mcLang(971), // "971":"Результат:",
                    body: { rows: [
                        { template: res, borderless: true, scroll: "y" },
                        { view: "button", value: mcLang(12), click: function(){
                            this.getTopParentView().hide();
                            this.getTopParentView().destructor();
                        }} //"12" : "Закрыть",
                    ]}
                });

                $rootScope.regShowWindow(serviceList.RandomHash(4), wnd);

                wnd.show();

                if (add.length || upd.length){
                    $rootScope.$broadcast('refreshUserManagerOnNextShow', []);
                }
            }
        },

        getUserStateText: function(_state, noColor){
            var state = "";

            switch (_state){
                case mcConst.states.offline:
                    state = serviceList.Lang(1641); break; // "1641":"Не в сети",

                case mcConst.states.online:
                    state = (!noColor ? '<span class="green">' : "") + serviceList.Lang(1642) + (!noColor ? '</span>' : ""); break; // "1642":"В сети",

                case mcConst.states.webOnline:
                    state = (!noColor ? '<span class="green">' : "") + serviceList.Lang(1642) + (!noColor ? '</span>' : ""); break; // "1642":"В сети",

                case mcConst.states.away:
                    state = (!noColor ? '<span class="blue">' : "") + serviceList.Lang(1643) + (!noColor ? '</span>' : ""); break; // "1643":"Нет на месте",

                case mcConst.states.dnd:
                    state = (!noColor ? '<span class="red">' : "") + serviceList.Lang(1644) + (!noColor ? '</span>' : ""); break; // "1644":"Не беспокоить",
            }

            return state;
        },

        getColorForStatus: function(status){
            var res = "#545454";

            status = parseInt(status);

            switch (status){
                case mcConst.states.offline: res = '#929292';  break; // "29" : "Не в сети",

                case mcConst.states.online: res = '#2bca2e'; break; // "30" : "В сети",

                case mcConst.states.webOnline: res = '#2bca2e'; break; // "30" : "В сети",

                case mcConst.states.away: res = 'blue'; break; // "31" : "Нет на месте",

                case mcConst.states.dnd: res = 'red'; break; // "32" : "Не беспокоить",
            }

            return res;
        },

        smartReplace: function (source, options) {
            for (var item in options){
                source = source.replace(new RegExp('{' + item + '}', 'g'), options[item]);
            }

            return source;
        },

        getIPs: function (callback){
            function handleCandidate(candidate){
                //match just the IP address
                var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
                var ip_addr = ip_regex.exec(candidate)[1];

                //remove duplicates
                if(ip_dups[ip_addr] === undefined)
                    callback(ip_addr);

                ip_dups[ip_addr] = true;
            }

            var ip_dups = {};

            //compatibility for firefox and chrome
            var RTCPeerConnection = window.RTCPeerConnection
                || window.mozRTCPeerConnection
                || window.webkitRTCPeerConnection;
            var useWebKit = !!window.webkitRTCPeerConnection;

            //bypass naive webrtc blocking using an iframe
            if(!RTCPeerConnection){
                //NOTE: you need to have an iframe in the page right above the script tag
                //
                //<iframe id="iframe" sandbox="allow-same-origin" style="display: none"></iframe>
                //<script>...getIPs called in here...
                //
                var win = iframe.contentWindow;
                RTCPeerConnection = win.RTCPeerConnection
                    || win.mozRTCPeerConnection
                    || win.webkitRTCPeerConnection;
                useWebKit = !!win.webkitRTCPeerConnection;
            }

            //minimal requirements for data connection
            var mediaConstraints = {
                optional: [{RtpDataChannels: true}]
            };

            var servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};

            //construct a new RTCPeerConnection
            var pc = new RTCPeerConnection(servers, mediaConstraints);

            //listen for candidate events
            pc.onicecandidate = function(ice){

                //skip non-candidate events
                if(ice.candidate)
                    handleCandidate(ice.candidate.candidate);
            };

            //create a bogus data channel
            pc.createDataChannel("");

            //create an offer sdp
            pc.createOffer(function(result){

                //trigger the stun server request
                pc.setLocalDescription(result, function(){}, function(){});

            }, function(){});

            //wait for a while to let everything done
            setTimeout(function(){
                //read candidate info from local description
                var lines = pc.localDescription.sdp.split('\n');

                lines.forEach(function(line){
                    if(line.indexOf('a=candidate:') === 0)
                        handleCandidate(line);
                });
            }, 1000);

            //Test: Print the IP addresses into the console
            //getIPs(function(ip){console.log(ip);});
        },

        treeWalker: function(treeArray, deepIn, cb){
            if (serviceList.inArray(treeArray)){
                for (var i = 0; i < treeArray.length; i++){
                    if (cb) cb(treeArray[i]);

                    if (treeArray[i].hasOwnProperty(deepIn)) serviceList.treeWalker(treeArray[i][deepIn], deepIn, cb);
                }
            }
        },

        updateStatuses: function (stList, dataList){
            function setState(_user) {
                if (_user.hasOwnProperty("UIN")){
                    if (stList.Statuses && stList.Users) {
                        _user.onlineState = stList.Statuses[stList.Users.indexOf(_user.UIN.toString())];
                    } else {
                        // _user.State = stList[_user.UIN.toString()] !== undefined ? stList[_user.UIN.toString()] : mcConst.states.offline;
                        _user.onlineState = stList[_user.UIN] !== undefined ? stList[_user.UIN] : mcConst.states.offline;
                    }

                    dataList.updateItem && dataList.updateItem(_user.id, _user);
                }
            }

            if (stList && dataList){
                if (serviceList.isArray(dataList)){
                    dataList.forEach(setState);
                } else {
                    dataList.each(setState);
                }
            }
        },

        getCaretPosition: function  (ctrl) {
            var CaretPos = 0;

            if (document.selection) {
                var Sel = document.selection.createRange();

                Sel.moveStart('character', - ctrl.value.length);

                CaretPos = Sel.text.length;
            } else

            // Fucking firefox support
            if (ctrl.selectionStart || ctrl.selectionStart == '0'){
                CaretPos = ctrl.selectionStart;
            }

            return CaretPos;

        },

        setCaretPosition: function (ctrl, pos, selectCount){
            pos = parseInt(pos);
            
            if(ctrl.setSelectionRange) {
                ctrl.setSelectionRange(pos, pos + (selectCount || 0));
            } else
            if (ctrl.createTextRange) {
                var range = ctrl.createTextRange();

                range.collapse(true);
                range.moveEnd('character', pos + (selectCount || 0));
                range.moveStart('character', pos);
                range.select();
            }
        },

        goToHelp : function (_path, go) {
            var path = (_path || window.location.hash).replace(/^#\/|^\/|\/$/g, "");
            var localPath =  serviceList.isIE()
                ? window.location.protocol + "//" + window.location.host
                : window.location.origin;

            if (_path && _path.toLowerCase().indexOf("http") === 0){
                window.open(_path, '', '');
            } else
            if (mcConst._CMD_.accordance.hasOwnProperty(path) && mcConst._CMD_.accordance[path] !== ""){
                window.open(localPath + serviceList.myReplaceFormated(mcConst._CMD_.accordance[path], {lang: mcConst.Lang === "uk" ? "ua" : mcConst.Lang}), '', '');
                // window.open(localPath + serviceList.myReplaceFormated(mcConst._CMD_.accordance[path], {lang: mcConst.Lang === "en" ? "_en" : ""}), '', '');
            } else
            if (go){
                window.open(localPath + "/" + path, '', '');
            }
        },

        getHelpLink : function (_path, text, _class, _id) {
            var path = (_path || window.location.hash).replace(/^#\/|^\/|\/$/g, "");
            var localPath =  serviceList.isIE()
                ? window.location.protocol + "//" + window.location.host
                : window.location.origin;
            var res = "";

            if (_path){
                res = serviceList.myReplaceFormated(
                    "<a href='#{link}' target='_blank' class='#{class}' id='#{id}'>#{text}</a>",
                    {
                        text : text || "Link",
                        link : (_path.toLowerCase().indexOf("http") === 0 ? _path : localPath + _path),
                        class: _class || "",
                        id   : _id || ""
                    }
                );
            } else
            if (mcConst._CMD_.accordance.hasOwnProperty(path) && mcConst._CMD_.accordance[path] !== ""){
                res = serviceList.myReplaceFormated(
                    "<a href='${link}' target='_blank' class='${class}' id='${id}'>${text}</a>",
                    {
                        text : text || "Link",
                        link : localPath + serviceList.myReplaceFormated(mcConst._CMD_.accordance[path], {lang: mcConst.Lang === "uk" ? "ua" : mcConst.Lang}),
                        class: _class || "",
                        id   : _id || ""
                    }
                );
            }

            return res;
        },

        HotkeyManager: function(debug){
            var keyList     = {};
            var presetList  = {};
            var maxKeyLevel = 0;
            var firedKeys   = {};
            var sourceMap   = {}; // key: [marker1, marker2, ...]
            var sourceMarker= "hotKeyMarker" + serviceList.RandomHash(5);
            var disableAll  = false;
            var removeList  = [];
            var removeTimer = null;

            function convertToKeyString(obj, code){
                return  code
                    ? (obj.ctrlKey ? "ctrl+" : "") +
                      (obj.shiftKey? "shift+": "") +
                      (obj.altKey  ? "alt+"  : "") +
                      code.toString()
                    : null;
            }

            function findByKeyCode(name, key) {
                var res = null;

                presetList[name].source.forEach(function (preset) {
                    if (convertToKeyString(preset, preset.key) === key.toString()){
                        res = preset;
                    }
                });

                return res;
            }

            function registerKeys(name, preset){
                var source = preset.source;

                for (var i = 0; i < source.length; i++){
                    var key = convertToKeyString(source[i], source[i].key);

                    if (!keyList.hasOwnProperty(key)){
                        keyList[key] = {};
                    }

                    // if (debug) {
                    //     console.log(
                    //       `+ Registered key: ${key}`+
                    //       `  Preset        : ${name}` +
                    //       `  maxKeyLevel   : ${maxKeyLevel}`);
                    // }

                    keyList[key][name] = source[i].func;

                    if (sourceMap[key]){
                        sourceMap[key].push(preset.marker);
                    } else {
                        sourceMap[key] = [preset.marker];
                    }
                }

                if (preset.target && !preset.ID){
                    preset.ID = webix.event(preset.target, "keydown", function(e){
                        if (disableAll) {
                            e.preventDefault();
                            
                            return false;
                        }

                        var keyCode     = convertToKeyString(e, e.keyCode);
                        var skipDefault = false;
                        var where       = this;

                        if (keyList.hasOwnProperty(keyCode) &&
                            where.hasOwnProperty(sourceMarker) &&
                            sourceMap.hasOwnProperty(keyCode) &&
                            sourceMap[keyCode].indexOf(where[sourceMarker]) !== -1
                        ) {
                            if (!firedKeys.hasOwnProperty(keyCode)) {
                                if (debug) {
                                    console.log('Fired key: '+ keyCode);
                                    // console.log(e);
                                }

                                firedKeys[keyCode] = 'fired';

                                for (var i in keyList[keyCode]){
                                    if (where[sourceMarker] === presetList[i].marker){
                                        if (presetList[i].level >= maxKeyLevel){
                                            var _preset = findByKeyCode(i, keyCode); // находим совпадающий индекс сочетания клавиш

                                            if (!_preset._locked){                            // если у пресета нет лока - выполняем
                                                if (debug) {
                                                    console.log('Run func: '+ _preset.func.name);
                                                }

                                                skipDefault = !keyList[keyCode][i](e, where); // запуск событие
                                            } else {
                                                if (debug) {
                                                    console.log('! Func  locked: '+ _preset.func.name);
                                                    console.log('! locked value: '+ _preset._locked);
                                                }
                                            }
                                        } else {
                                            var source = presetList[i].source;

                                            for (var j in source){
                                                if (convertToKeyString(source[j], source[j].key) === keyCode){
                                                    skipDefault = source[j].skipDefault;

                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }

                                (function (key) {
                                    setTimeout(function () {
                                        delete firedKeys[key];
                                    }, 10);
                                })(keyCode);
                            }

                            if (skipDefault){
                                e.preventDefault();

                                return false;
                            }
                        }
                    });
                }
            }

            function removeKeys(_name){
                function _doRemove(name) {
                    for (var keyCode in keyList){
                        if (keyList[keyCode].hasOwnProperty(name)){
                            if (presetList[name].level === maxKeyLevel && maxKeyLevel > 0){
                                var entries = 0;
                                var prevKeyLevel = 0;

                                Object.keys(presetList).forEach(function (preset) {
                                    var curLevel = presetList[preset].level;

                                    if (curLevel === maxKeyLevel){
                                        entries ++;
                                    }

                                    if (curLevel > prevKeyLevel && curLevel < maxKeyLevel){
                                        prevKeyLevel = curLevel;
                                    }
                                });

                                if (entries === 1){
                                    maxKeyLevel = prevKeyLevel;
                                }
                            }

                            if (debug) {
                                console.log('- Removing key: ' + keyCode);
                                console.log('- Preset: ' + name);
                                console.log('- maxKeyLevel: ' + maxKeyLevel);
                            }

                            removeLock(keyCode, presetList[name].key);

                            sourceMap[keyCode].splice(sourceMap[keyCode].indexOf(presetList[name].marker), 1);

                            if (sourceMap[keyCode].length === 0){
                                delete sourceMap[keyCode];
                            }

                            delete keyList[keyCode][name];
                        }
                    }

                    if (presetList[name]){
                        webix.eventRemove(presetList[name].ID);

                        delete presetList[name];
                    }

                    if (removeList.length){
                        return _doRemove(removeList.shift());
                    } else {
                        clearTimeout(removeTimer);
                        removeTimer = null;
                    }
                }
                
                if (_name) removeList.push(_name);

                if (!removeTimer){
                    removeTimer = setTimeout(function (){
                        _doRemove(removeList.shift());
                    }, 10);
                }
            }

            function lockAction(key, except) {
                for (var i in presetList){
                    presetList[i].source.forEach(function (preset) {
                        if (i !== except && key.toString() === convertToKeyString(preset, preset.key)){
                            if (preset._locked){
                                preset._locked ++;
                            } else {
                                preset._locked = 1;
                            }

                            if (debug) {
                                console.log('Add lock key: '+ key + ', value: ' + preset._locked);
                                console.log(presetList[i]);
                            }
                        } else {
                            preset._locked = 0;
                        }
                    });
                }
            }

            function removeLock(key) {
                for (var i in presetList){
                    presetList[i].source.forEach(function (preset) {
                        if (key.toString() === convertToKeyString(preset, preset.key) && preset.hasOwnProperty("_locked") && preset._locked > 0){
                            preset._locked --;

                            if (debug) {
                                console.log('remove lock key: '+ key + ', value: ' + preset._locked);
                                console.log(preset);
                            }
                        }
                    });
                }
            }

            this.disable = function (){
                disableAll = true;
            };

            this.enable = function (){
                disableAll = false;
            };

            this.debug = function (state){
                debug = !!state;

                console.log(`HotkeyManager debugger is ${!!state ? 'on': 'off'}`);
            };

            this.showPresetList = function () {
                console.log("showPresetList");
                
                Object.keys(presetList).forEach(function (name) {
                    console.log(presetList[name]);
                    // console.log(
                    //     `========================` +
                    //     `name  : ${name}` +
                    //     `preset: ${mcService.ObjToString(presetList[name].preset)}` +
                    //     `target: ${presetList[name].target.tagName || presetList[name].target.nodeName}` +
                    //     `ID    : ${presetList[name].ID}`
                    // );
                });
            };

            this.clearPresetLevel = function (level) {
                debug && console.log("clearPresetLevel: " + level);

                Object.keys(presetList).forEach(function (name) {
                    if (presetList[name].level >= level){
                        removeKeys(name);
                    }
                })
            }

            this.addPreset = function(name, preset, target, disablePrevious){
                if (!presetList.hasOwnProperty(name)){
                    var marker = serviceList.RandomHash(10);

                    if (target.hasOwnProperty(sourceMarker)){
                        marker = target[sourceMarker];
                    } else {
                        target[sourceMarker] = marker;
                    }

                    presetList[name] = {
                        name  : name,
                        source: preset,
                        target: target,
                        marker: marker,
                        ID    : null
                    };

                    if (disablePrevious) {
                        maxKeyLevel ++;
                    }

                    preset.forEach(function (item) {
                        if (item.lockPrev){
                            lockAction(convertToKeyString(item, item.key), name);
                        }
                    });

                    presetList[name].level = maxKeyLevel;

                    if (debug) {
                        console.log("addPreset:");
                        console.log(presetList[name]);
                        // console.log(
                        //     `+++++\n` +
                        //     `addPreset: ${name}\n` +
                        //     `preset   : ${mcService.ObjToString(preset)}\n` +
                        //     `target   : ${target.tagName || target.nodeName}\n` +
                        //     `level    : ${maxKeyLevel}\n` +
                        //     `disablePrevious: ${!!disablePrevious}\n`
                        // );
                    }

                    registerKeys(name, presetList[name]);
                } else {
                    // console.warn("Preset \"" + name + "\" is present");

                    return false;
                }
            };

            this.removePreset = function(name){
                if (presetList.hasOwnProperty(name)){
                    removeKeys(name);
                } else {
                    return false;
                }
            };
        },

        utcTime: function(msg, decode, format) {
            var dt = null;

            if (mcService.isDate(msg)){
                dt = msg;
            } else
            if (serviceList.isNumber(msg)) {
                dt = new Date(msg);
            } else {
                dt = msg.dtUTC || msg.dt || msg;
            }

            return dt
                ? serviceList.formatDate(new Date(
                    (new (Function.prototype.bind.apply(
                        Date,
                        [null].concat(serviceList.formatDate(dt, "yyyy.mm.dd.hh.nn.ss.zzz").split('.').map(function (val, idx) {
                            return idx === 1 ? val - 1 : val;
                        }))
                    ))).getTime() + (new Date()).getTimezoneOffset() * 1000 * 60 * (!decode ? -1 : 1)
                ), format || "dd.mm.yyyy.hh.nn.ss.zzz")
                : ""
            ;
        },

        reloadOrChangeProtocol: function () {
            if (mcConst.changeProtocol && mcConst.changeProtocol !== location.protocol) {
                location.protocol = mcConst.changeProtocol;

                window.open(location.href);
            } else {
                location.search = "";
                location.reload(true);
            }
        },

        myReplaceFormated : function(source, items){
            if (serviceList.isObject(items) && serviceList.isString(source)){
                for (var i in items) {
                    source = source.replace(new RegExp("#{" + i + "}", "g"), items[i]);
                }
            }

            return source;
        },

        myReplaceUni : function(source, items){
            if (serviceList.isObject(items) && serviceList.isString(source)){
                for (var i in items){
                    source = source.replace(new RegExp(i, "g"), items[i]);
                }
            }

            return source;
        },

        createKanbanLink: function (projectID, taskID, commentID) {
            return serviceList.getLocalHostPath(location.protocol !== 'file:') +
                "/" + mcConst.pathAliases.AliasKanban + "/#project=" + projectID + (taskID ? "&task=" + taskID + (commentID ? "&comment=" + commentID : "") : "");
        },

        createForumLink: function (path){
            return serviceList.getLocalHostPath(location.protocol !== 'file:') + "/" + mcConst.pathAliases.AliasForum + "/#/" + path;
        },

        getCommonFilesPath: function (isWebClient) {
            return this.myReplaceFormated("ftp://#{user}:#{pwd}@#{host}:#{port}/", {
                host : isWebClient ? window.location.host : mcConst.ServerInfo.Host,
                user : mcConst.FTP.CommonUser,
                pwd  : mcConst.FTP.CommonPWD,
                port : mcConst.UserInfo.PortFTP
            });
        },

        SHA1: function () {
            var sha1 = new Rusha();
            sha1.resetState();

            return sha1;
        },

        convertToEntities : function(tstr) {
            function dec2hex(i){
                var result = "0000";

                if      (i >= 0    && i <= 15)    { result = "000" + i.toString(16); }
                else if (i >= 16   && i <= 255)   { result = "00"  + i.toString(16); }
                else if (i >= 256  && i <= 4095)  { result = "0"   + i.toString(16); }
                else if (i >= 4096 && i <= 65535) { result =         i.toString(16); }

                return result
            }
            var bstr = "";

            if (tstr){
                for(var i = 0; i < tstr.length; ++i)
                {
                    if(tstr.charCodeAt(i) > 127)
                    {
                        bstr += "\\u" + dec2hex(tstr.charCodeAt(i));
                    } else {
                        bstr += tstr.charAt(i);
                    }
                }
            } else {
                throw new Error('convertToEntities: incoming data is empty or undefined: ' + tstr);
                //console.error('convertToEntities: incoming data is empty or undefined', true);
            }

            return bstr;
        },

        extractFileName : function(Path){
            var count = 0;

            if (Path){
                for (var i = Path.length - 1; i >= 0; i--){
                    count ++;

                    if ((Path[i] === '\\') || (Path[i] === '/')) {
                        return Path.slice(i + 1, i + count);
                    }
                }
            }

            return Path;
        },

        extractFileExtension : function(Path){
            var path = (Path || "").split('.');

            return path[path.length - 1];
        },

        extractFilePath : function(Path){
            for (var i = Path.length - 1; i >= 0; i--){
                if ((Path[i] === '\\') || (Path[i] === '/')) {
                    return Path.slice(0, i);
                }
            }

            return Path;
        },

        getLocalHostPath: function (isWebClient) {
            var res = "";

            if (isWebClient) {
                res = serviceList.isIE() ? window.location.protocol + "//" + window.location.host : window.location.origin
            } else {
                var host = mcConst.UserInfo.useAltAddr ? mcConst.ServerInfo.AltHost : mcConst.ServerInfo.Host;
                var port = mcConst.UserInfo.PortNode;

                res = (mcConst.UserInfo.HTTPS ? "https://" : "http://") + (mcConst.ServerInfo.IPv6 ? "[" + host + "]" : host) +
                      (mcConst.UserInfo.HTTPS ? (port != 443 ? ':' + port : '') : (port != 80  ? ':' + port : ''))
            }

            return res;
        },

        createHostPath: function (_host, _port, noProtocol) {
            var port  = _port ? _port : mcConst.UserInfo.PortNode;
            var host  = _host ? _host : mcConst.ServerInfo.Host;
            var https = window.location.protocol !== 'file:' ? window.location.protocol === "https:" : mcConst.UserInfo.HTTPS;
            
            return (
                noProtocol
                    ? ""
                    : (https ? "https://" : "http://")
                ) +
                (host.indexOf(":") === -1 // no port
                    ? host + (https
                            ? (port != 443 ? ':' + port : '')
                            : (port != 80  ? ':' + port : '')
                      )
                    : host
                );
        },

        formatFileSize: function(size, round){
            var index = 0;

            while (size > 1024){
                index ++;

                size = size / 1024;
            }

            return (round ? Math.round(Math.round(size * 100)/100) : Math.round(size * 100)/100) + " " + ["B","KB","MB","GB","TB","PB","EB"][index];
        },

        fileTimeStamp: function (dd) {
            // var currentTimeZoneOffsetInMS = (new Date()).getTimezoneOffset() * 60 * 1000;
            // var now  = new Date((new (Function.prototype.bind.apply(
            //     Date,
            //     [null].concat(serviceList.formatDate(dd ? new Date(dd) : new Date(), "yyyy.mm.dd.hh.nn.ss.zzz").split('.').map(function (val, idx) {
            //         return idx === 1 ? val - 1 : val;
            //     }))
            // ))).getTime() - currentTimeZoneOffsetInMS);
            // var then = new Date(
            //     now.getFullYear(),
            //     now.getMonth(),
            //     now.getDate(),
            //     0,0,0
            // );
            // var diff = ((now.getTime() - then.getTime()) || (24 * 60 * 60 * 1000));// + currentTimeZoneOffsetInMS;
            if (typeof require === 'function') {
                window.moment = require('moment');
            }

            var now   = serviceList.utcTime(dd ? new Date(dd) : new Date(), true).split('.');
            // 0  1  2    3  4  5  6
            // dd.mm.yyyy.hh.nn.ss.zzz
            var diff  = parseInt(now[6]) + parseInt(now[5])*1000 + parseInt(now[4])*1000*60 + parseInt(now[3])*1000*60*60;
            var diff2 = moment(new Date(now[2], parseInt(now[1]) - 1, now[0], now[3], now[4], now[5])).startOf('day').diff(moment({year:"1", month: "0", day: "1"}).startOf('day'), 'days') + 1;
                                                                                                                           
            return diff + "." + diff2;
        },

        getSelectedText: function (element){
            var res = {
                selectionStart : element.selectionStart,
                selectionEnd   : element.selectionEnd
            };

            // nothing is selected
            if (res.selectionStart !== res.selectionEnd) {
                var string = element.value;

                res.prefix  = string.substring(0, res.selectionStart);
                res.infix   = string.substring(res.selectionStart, res.selectionEnd);
                res.postfix = string.substring(res.selectionEnd);
            }

            // element.value = prefix + 'REPLACED TEXT' + postfix;

            return  res;
        },

        setSelectionText: function(inputBox, start, end){
            if (start > end) {
                start = end;
            }

            if ("selectionStart" in inputBox) { //gecko
                inputBox.setSelectionRange(start, end);
            } else {
                var r = inputBox.createTextRange();
                r.collapse(true);
                r.moveStart('character',start);
                r.moveEnd('character',end - start);
                r.select();
            }
        },
        
        convertArrayToObj: function (arr, item) {
            var res = {};

            if (item && serviceList.isString(item) && serviceList.isArray(arr)){
                arr.forEach(function (val) {
                    res[val[item]] = val;
                })
            } else {
                console.error('convertArrayToObj: is not Array or Item is not string!');
            }

            return res;
        },

        convertArrayObjToObj: function(arr, keyField){
            var res = {};

            for (var i = 0; i < arr.length; i++){
                if (arr[i].hasOwnProperty(keyField)){
                    res[arr[i][keyField]] = arr[i];
                }
            }

            return res;
        },

        getAvatar: function (sex) {
            var avatar = "";

            switch (sex){
                case 0: // alien
                    avatar = serviceList.insertIco("fa-user taskAvatar"); break;

                case 1: // male
                    avatar = serviceList.insertIco("fa-male taskAvatar"); break;

                case 2: // female
                    avatar = serviceList.insertIco("fa-female taskAvatar"); break;
            }

            return avatar;
        },

        getPriority: function (priority) {
            var res = "";

            switch (parseInt(priority)){
                case mcConst.priority.LOW      : res = mcLang(61); break;
                case mcConst.priority.MEDIUM   : res = mcLang(62); break;
                case mcConst.priority.HIGH     : res = mcLang(63); break;
                case mcConst.priority.IMPORTANT: res = mcLang(64); break;
                case mcConst.priority.URGENT   : res = mcLang(65); break;
                case mcConst.priority.CRITICAL : res = mcLang(66); break;
            }

            return res;
        },

        openKanbanLinkIfCan : function (e, $rootScope) {
            var res = false;

            if (e.target.nodeName === "A" && (
                    (e.target.origin + e.target.pathname == window.location.origin + window.location.pathname) ||
                    ((serviceList.isIE() && e.target.protocol + "//" + e.target.host + e.target.pathname) == (window.location.protocol + "//" + window.location.host + window.location.pathname))
                )){
                setTimeout(function () {
                    $rootScope.$broadcast('openKanbanURI', [e.target.href]);
                }, 10);

                e.preventDefault();

                res = true;
            }

            return res;
        },

        replaceKanbanLink: function (link, text) {
            var res = '<a href="' + link + '" title="' + link + '" ' + (link.indexOf('mailto') == -1 ? 'target="_blank"' : '') + ' class="internalLink">' + (text || link) + '</a>';

            if ((new RegExp(serviceList.isIE()
                    ? window.location.protocol + "//" + window.location.host + window.location.pathname
                    : window.location.origin + window.location.pathname
                )).test(link)){

                var parse = purl(link);

                var projectID = parse.fparam("project");
                var taskID    = parse.fparam("task");
                var commentID = parse.fparam("comment");

                res = '<a href="' + link + '" title="' + link + '" ' + (link.indexOf('mailto') == -1 ? 'target="_blank"' : '') + ' class="internalLink">';

                if (commentID){
                    res += "COMMENT #" + commentID;
                } else
                if (taskID){
                    res += "TASK #" + taskID;
                } else
                if (projectID){
                    res += "PROJECT #" + projectID;
                }

                res += '</a>';
            }

            return res;
        },

        getByCssClass: function(classList, _node){
            var res = null;
            var node = _node || document;

            if (document.getElementsByClassName) {
                res = node.getElementsByClassName(classList)
            } else {
                var list = node.getElementsByTagName('*');
                var length = list.length;
                var classArray = classList.split(/\s+/);
                var classes = classArray.length;
                var result = [];

                for (var i = 0; i < length; i++) {
                    for (var j = 0; j < classes; j++) {
                        if (list[i].className.search('\\b' + classArray[j] + '\\b') !== -1) {
                            result.push(list[i]);

                            break
                        }
                    }
                }

                res = result;
            }

            return res;
        },

        disableContextMenu : function(_view, exception){
            webix.event(_view.$view, "contextmenu", function(e){
                function skipItems(items, where) {
                    var flag = true;

                    if (items && items.length){
                        items.forEach(function (item) {
                            if (where.length && where.indexOf(item) !== -1){
                                flag = false;
                            }
                        });
                    }

                    return flag;
                }

                if ((
                        e.target.nodeName !== "INPUT" &&
                        e.target.nodeName !== "TEXTAREA" &&
                        e.target.parentNode && e.target.parentNode.parentNode &&
                        skipItems(exception, e.target.className.split(" ").concat(e.target.parentNode.className.split(" ")).concat(e.target.parentNode.parentNode.className.split(" ")))
                    ) ||
                    (e.target.type === "button")) {

                    e.preventDefault();
                }
            });
            // webix.event(_view.$view, "contextmenu", function(e){
            //     if ((e.target.nodeName != "INPUT") && (e.target.nodeName != "TEXTAREA") || (e.target.type == "button")) {
            //         e.preventDefault();
            //     }
            // });
        },

        setStatusForUser: function(_user, state){
            var users = serviceList.getElementByClass(mcConst.storageOpts.STATUSICO + _user);

            for (var i = 0; i < users.length; i++){
                users[i].style.color = serviceList.getColorForStatus(state);

                if (users[i].className.indexOf("fa-user smaller") === -1){
                    users[i].style.backgroundColor = serviceList.getColorForStatus(state);
                }
            }
        },

        Base64 : {
            // private property
            _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

            // public method for encoding
            encode : function (input) {
                var output = "";
                var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
                var i = 0;

                input = serviceList.Base64._utf8_encode(input);

                while (i < input.length) {
                    chr1 = input.charCodeAt(i++);
                    chr2 = input.charCodeAt(i++);
                    chr3 = input.charCodeAt(i++);

                    enc1 = chr1 >> 2;
                    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                    enc4 = chr3 & 63;

                    if (isNaN(chr2)) {
                        enc3 = enc4 = 64;
                    } else if (isNaN(chr3)) {
                        enc4 = 64;
                    }

                    output = output +
                        this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
                        this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

                }

                return output;
            },

            // public method for decoding
            decode : function (input) {
                var output = "";
                var chr1, chr2, chr3;
                var enc1, enc2, enc3, enc4;
                var i = 0;

                input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

                while (i < input.length) {

                    enc1 = serviceList.Base64._keyStr.indexOf(input.charAt(i++));
                    enc2 = serviceList.Base64._keyStr.indexOf(input.charAt(i++));
                    enc3 = serviceList.Base64._keyStr.indexOf(input.charAt(i++));
                    enc4 = serviceList.Base64._keyStr.indexOf(input.charAt(i++));

                    chr1 = (enc1 << 2) | (enc2 >> 4);
                    chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                    chr3 = ((enc3 & 3) << 6) | enc4;

                    output = output + String.fromCharCode(chr1);

                    if (enc3 !== 64) {
                        output = output + String.fromCharCode(chr2);
                    }

                    if (enc4 !== 64) {
                        output = output + String.fromCharCode(chr3);
                    }

                }

                output = serviceList.Base64._utf8_decode(output);

                return output;

            },

            // private method for UTF-8 encoding
            _utf8_encode : function (string) {
                string = string.replace(/\r\n/g,"\n");
                var utftext = "";

                for (var n = 0; n < string.length; n++) {

                    var c = string.charCodeAt(n);

                    if (c < 128) {
                        utftext += String.fromCharCode(c);
                    } else
                    if((c > 127) && (c < 2048)) {
                        utftext += String.fromCharCode((c >> 6) | 192);
                        utftext += String.fromCharCode((c & 63) | 128);
                    } else {
                        utftext += String.fromCharCode((c >> 12) | 224);
                        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                        utftext += String.fromCharCode((c & 63) | 128);
                    }

                }

                return utftext;
            },

            // private method for UTF-8 decoding
            _utf8_decode : function (utftext) {
                var string = "";
                var i  = 0;
                var c  = 0;
                var c1 = 0;
                var c2 = 0;
                var c3 = 0;

                while ( i < utftext.length ) {

                    c = utftext.charCodeAt(i);

                    if (c < 128) {
                        string += String.fromCharCode(c);
                        i++;
                    } else
                    if((c > 191) && (c < 224)) {
                        c2 = utftext.charCodeAt(i+1);
                        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                        i += 2;
                    } else {
                        c2 = utftext.charCodeAt(i+1);
                        c3 = utftext.charCodeAt(i+2);
                        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                        i += 3;
                    }

                }

                return string;
            }
        },

        isOdd : function (num) { return num % 2;},

        replaceMcComponents : function (text, isWeb, $rs, nick) {
            var items = text.split(mcConst.terminator2);
            var elem  = "";
            var smileFile = "";

            items.forEach(function (item, idx) {
                if (serviceList.isOdd(idx)){
                    elem = item.split(mcConst.terminator3);

                    switch (item[0]) {
                        case ")":
                            try {
                                elem[0] = elem[0].replace(")", "");

                                if (mcConst.SmileysSet[elem[0]]){
                                    smileFile = mcConst.SmileysSet[elem[0]][elem[1]];
                                }

                                if (smileFile && (isWeb || mcConst.ClientSettings.SysEventsDisableEmotions == '0')){
                                    items[idx] = serviceList.myReplaceFormated(
                                        "<img src='#{path}/#{smile}'>",
                                        {
                                            path : MC_RESOURCE.TextSource.smileys + mcConst.SmileysSet[elem[0]].name,
                                            smile: smileFile
                                        }
                                    );
                                } else {
                                    items[idx] = elem[1];
                                }
                            } catch (e) {
                                items[idx] = ":)";
                            }
                        break;

                        case "F":
                            var style = elem[0].split("#");
                            style = style[style.length - 1];

                            items[idx] = elem[1];

                            for (var i = 0; i < style.length; i++){
                                switch (style[i]) {
                                    case "B": items[idx] = "<b>" + items[idx] + "</b>"; break;
                                    case "I": items[idx] = "<i>" + items[idx] + "</i>"; break;
                                    case "U": items[idx] = "<u>" + items[idx] + "</u>"; break;
                                    case "S": items[idx] = "<strike>" + items[idx] + "</strike>"; break;
                                }
                            }
                        break;
                            
                        case ">":
                            var uin = elem[0].replace(">", "");

                            var name = elem[1];

                            if (name.indexOf('noname (') === 0) {
                                name = nick ? nick : $rs.$broadcast(window._messages_.usersSmallInfo.getUserSmallInfo, [uin]).DisplayName;
                            }

                            items[idx] = "<span uin='" + uin +"' class='brown bolder'>@" + name + "</span>";
                        break;

                        case "A":
                            var link = elem[0].replace("A", "");

                            if (link.indexOf("\\") === 0) {
                                link = link.replace("\\\\", "local://").replace(/\\/g, "/");
                            }

                            items[idx] = link + mcConst.myChatLinkTitle + elem[1];
                        break;

                        case "f": // public FTP
                            items[idx] = mcConst.ftpPublic;
                        break;

                        case "m": // personal FTP                 // uin
                            items[idx] = mcConst.ftpPersonal + elem[0].replace("m", "");
                        break;
                    }
                }
            });
            
            return items.join("");
        },

        numberList: function (length, forwardZero) {
            var strLength = length.toString().length;
            var res = (new Array(length || 1)).join('.').split('.');

            res = res.map(function (itm, idx) {
                var st = idx.toString();

                return forwardZero ? (new Array(strLength + 1 - st.length)).join('0') + st : st;
            });

            return res;
        },

        forvardZero: function (st, strLength, symbol) {
            st = st.toString();
            
            return (new Array(strLength + 1 - st.length)).join(symbol || '0') + st;
        },

        toHex: function (numb, hexLen){
            var str = "";

            numb = parseInt(numb, 10);

            while (numb > 0){
                str  = hexCodes[numb % 16] + str;
                numb = Math.floor(numb / 16);
            }

            while (str.length < hexLen){
                str = "0" + str;
            }

            return str;
        },

        hexToDec: function(hex){
            return parseInt(hex, 16);
        },

        FadeControl: function Fade(elem) {
            var el   = elem;
            var stop = null;

            this.in = function () {
                stop = "out";
    
                var last = new Date();
                var tick = function() {
                    if (stop === "in") {
                        stop = null;
                    } else {
                        el.style.opacity = + el.style.opacity + (new Date() - last) / 400;

                        last = new Date();

                        if (el.style.opacity <= 1) {
                            (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
                        } else {
                            stop = null;
                        }
                    }
                };

                tick();
            };

            this.out = function () {
                stop = "in";

                var last = new Date();
                var tick = function() {
                    if (stop === "out"){
                        stop = null;
                    } else {
                        el.style.opacity = + el.style.opacity - (new Date() - last) / 400;

                        last = new Date();

                        if (el.style.opacity > 0) {
                            (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
                        } else {
                            stop = null;
                        }
                    }
                };

                tick();
            };
        },

        Capitalize: function (str) {
            return str[0].toUpperCase() + str.substring(1).toLowerCase();
        },

        ObjToString : function(_obj){
            var res = "";

            if (serviceList.isString(_obj) || serviceList.isNumber(_obj)){
                res = _obj.toString() + "";
            } else {
                try {
                    res = JSON.stringify(_obj);
                } catch (e){
                    res = _obj.toString() + "";
                }
            }

            return res;
        },

        typeFlag: function (displayFlag, lookField) {
            var lng = $$(displayFlag);
            var lastChar = $$(lookField).getValue();
            lastChar = lastChar[lastChar.length - 1];

            if (lastChar){
                if (lastChar.match(/[a-zA-Z]/)) {
                    lng.define('template', 'EN');
                    lng.refresh();
                } else
                if (lastChar.match(/[а-яА-Я]/)){
                    lng.define('template', 'RU');
                    lng.refresh();
                } else
                if (lastChar.match(/[їЇіІєЄ]/)){
                    lng.define('template', 'UA');
                    lng.refresh();
                }
            }
        },

        buildForumStructure: function (struct, data, ids, structCash, exeptTopicks) {
            var newIds  = [];
            var newData = [];
            var idx     = 0;
            var item    = null;

            while (idx < data.length){
                item = data[idx];

                if (item){
                    if (item.Type === mcConst.msgTypes.topic && exeptTopicks){
                        data.splice(idx, 1);
                    } else

                    if (serviceList.inArrayNoStrict(item.ParentID, ids) !== -1){
                        item.id = item.Type + "_" + item.ID;

                        structCash[mcConst.msgTypes.section + "_" + item.ParentID].Item.data.push(item);

                        structCash[item.id] = {
                            Item: item
                        };

                        if (item.Type === mcConst.msgTypes.section) {
                            newIds.push(item.ID);

                            structCash[item.id].Item.data = [];
                            structCash[item.id].Data      = structCash[item.id].Item.data;
                        }

                        data.splice(idx, 1);
                    } else {
                        newData.push(item);

                        idx ++;
                    }
                } else {
                    i ++;
                }

                item = null;
            }

            return data.length > 0 ? serviceList.buildForumStructure(struct, newData, newIds, structCash, exeptTopicks) : struct;
        },

        insertAtCursor: function (textarea, val, isPara) {
            var res = 0;

            if (document.selection) {
                var sel = document.selection.createRange();

                textarea.focus();

                sel.text = val;

                res = sel.text.toString().length - 1;
            } else
            if (textarea.selectionStart || textarea.selectionStart == '0') {
                var startPos = textarea.selectionStart;
                var endPos   = textarea.selectionEnd;

                var prevText = textarea.value.substring(0, startPos);
                var nextText = textarea.value.substring(endPos, textarea.value.length);

                textarea.value =
                    (isPara && prevText.length && prevText[prevText.length - 1] !== "\n" ? prevText + "\n" : prevText) +
                     val +
                    (isPara && nextText.length && nextText[0] !== "\n" ? "\n" + nextText : nextText);

                textarea.selectionStart = startPos + val.length + (isPara ? 1 : 0);
                textarea.selectionEnd   = startPos + val.length + (isPara ? 1 : 0);

                res = textarea.selectionEnd;
            } else {
                textarea.value += (isPara && textarea.value.length && textarea.value[textarea.value.length - 1] !== "\n") ? "\n" + val : val;

                res = textarea.value.length - 1;
            }

            return res;
        },

        parseAttachment: function (text, files, pref, cb, duManager, generateLinks, isComment){
            var link  = "";
            var closeSymbol = "}";
            var isWeb = location.protocol !== 'file:';

            if (text.indexOf(pref) >=0 ){
                text = text.split(pref);

                for (var i = 0; i < text.length; i++){
                    if (!i && text[i].length){
                        if (cb) {
                            text[i] = cb(text[i], files);
                        }

                        continue;
                    }

                    var idx       = text[i].indexOf(closeSymbol);
                    var name      = serviceList.copy(text[i], 0, idx);
                    var endOfLine = serviceList.copy(text[i], idx + 1, text[i].length - 1);
                    var parsedEndLine = "";

                    if (files && files.hasOwnProperty(name)){
                        if (pref === mcConst.prefix.file){
                            link = serviceList.myReplaceFormated(
                                '<a href="#{link}" class="internalLink" title="#{link}" target="_blank">#{name}</a>',
                                {
                                    link: serviceList.getLocalHostPath(isWeb) + "/" + mcConst.pathAliases.AliasFiles + "/kanban/" + files[name].Hash + "/" + name,
                                    name: serviceList.insertIco("fa-file-o", "fs90") + name
                                }
                            );
                        } else

                        if (pref === mcConst.prefix.image){
                            imgIndex++;

                            if (generateLinks){
                                generateLinks(files[name], name);
                            }

                            var resolutionW = files[name].width  ? Math.round(parseInt(files[name].width))  : "auto";
                            var resolutionH = files[name].height ? Math.round(parseInt(files[name].height)) : "auto";

                            if (files[name].width){
                                if (resolutionH === resolutionW && resolutionW <= mcConst.imageSize.big.y){
                                    // nothing 
                                } else
                                if (resolutionH >= resolutionW) {
                                    if (resolutionH > mcConst.imageSize.big.y){
                                        resolutionH = mcConst.imageSize.big.y;
                                    }

                                    resolutionW = Math.round(files[name].width / (files[name].height / mcConst.imageSize.big.y));
                                } else {
                                    if (resolutionW > mcConst.imageSize.big.x){
                                        resolutionW = mcConst.imageSize.big.x;
                                    }

                                    resolutionH = Math.round(files[name].height / (files[name].width / mcConst.imageSize.big.x));
                                }
                            }

                            var now = serviceList.RandomHash(7);

                            link = serviceList.myReplaceFormated(
                                '<div><a href="#{hrefImg}" class="internalLink" target="_blank" style="#{widthPX} #{heightPX};">' + // background-image: url(#{tmp})
                                    '<img #{idClass}="img_temp_#{hash}" src="#{loadImage}" alt="" width="#{width}" height="#{height}" >' +  // style="background-image: url(#{tmp})"
                                '</a></div>',
                                {
                                    idClass  : isComment ? "id" : "class",
                                    tmp      : mcConst.imagesPath.noFile,
                                    width    : resolutionW || "",
                                    height   : resolutionH || "",
                                    widthPX  : "width:"  + (resolutionW && resolutionW !== "auto" ? resolutionW + "px": resolutionW) + ";",
                                    heightPX : "height:" + (resolutionH && resolutionH !== "auto" ? resolutionH + "px": resolutionH) + ";",
                                    hrefImg  : files[name].lnkHref ? files[name].lnkHref : "#",
                                    loadImage: isComment ? "" : (files[name].imgSrc  ? files[name].imgSrc  : ""),
                                    // loadImage: "", //mcConst.imagesPath.noImage,
                                    hash     : files[name].Hash + (isComment ? "_" + now : "")
                                }
                            );

                            duManager.loadThumbs([files[name].Hash, name, null, now]);
                        }

                        if (cb) {
                            parsedEndLine = cb(endOfLine, files);
                        }

                        text[i] = link + (parsedEndLine || endOfLine);
                    } else {
                        if (cb) {
                            parsedEndLine = cb(endOfLine, files);

                            text[i] = link + (parsedEndLine || endOfLine);
                        }
                    }
                }
                
                text = text.join('');
            } else
            if (cb) {
                text = cb(text, files);
            }

            return text;
        },

        checkNumbersCounter: function(code){
            if (this.config.view === "counter" && serviceList.inArray(code, mcConst.keyCodes.Digits.concat(mcConst.keyCodes.EditSymbols)) === -1){
                return false;
            }
        },

        isImage: function (file) {
            return serviceList.inArrayNoStrict(serviceList.extractFileExtension(file).toLowerCase(), ["png", "jpg", "jpeg", "gif", "bmp"]) !== -1;
        },

        getCurrentChantTypeForFiles: function (type) {
            // var currentChat = type;
            var res         = 1;

            switch (type){
                case "UIN"   : res = mcConst.whereFiles.private;break;
                case "UID"   : res = mcConst.whereFiles.conf;   break;
                case "Forum" : res = mcConst.whereFiles.forum;  break;
                case "Kanban": res = mcConst.whereFiles.kanban; break;
                case "BBS"   : res = mcConst.whereFiles.bbs;    break;
            }

            return res;
        },

        copyTextToClipboard: function (text, message) {
            function fallbackCopyTextToClipboard(text) {
                var textArea = document.createElement("textarea");

                textArea.value = text;
                textArea.className = "__terminal-clipcopy";

                document.body.appendChild(textArea);

                textArea.focus();
                textArea.select();

                try {
                    document.execCommand('copy');

                    webix.message('Text copied to clipboard');
                } catch (err) {
                    console.error('Fallback: could not copy text to clipboard: ', err);
                }

                document.body.removeChild(textArea);
            }

            if (!navigator.clipboard) {
                fallbackCopyTextToClipboard(text);

                return;
            }

            navigator.clipboard.writeText(text).then(function() {
                if (message !== false) {
                    webix.message(message || 'Text copied to clipboard');
                }
            }, function(err) {
                console.error('Could not copy text to clipboard: ', err);
            });
        },

        presenterTemp: function (){
            return "<!DOCTYPE html>" +
                "<html lang=\"en\">" +
                "<head>" +
                "    <meta charset=\"UTF-8\">" +
                "    <title>#{title}</title>" +
                "    <link rel=\"stylesheet\" type=\"text/css\" href=\"/mctools/simplemde/simplemde.min.css\">" +
                "    <link rel=\"stylesheet\" type=\"text/css\" href=\"/frameworks/webix/codebase/css/font-awesome.min.css\">" +
                "    <link rel=\"stylesheet\" type=\"text/css\" href=\"/frameworks/webix/codebase/css/github-markdown.css\">" +
                "</head>" +
                "<body class='markdown-body'>" +
                "    #{content}" +
                "    #{mc_sign}" +
                "</body>" +
                "</html>"
            ;
        },

        getSmileNumbByName : function (name) {
            return Object.keys(mcConst.SmileysSet).filter(function (item) {
                if (mcConst.SmileysSet[item].name === name) {
                    return true;
                }
            }).join("") || name;
        },

        getMyStatus: function () {
            switch (mcConst.UserInfo.onlineState) {
                case mcConst.states.online : return mcLang(30);   // "30" :"В сети",
                case mcConst.states.offline: return mcLang(29);   // "29" :"Не в сети",
                case mcConst.states.away   : return mcLang(31);   // "31" :"Нет на месте",
                case mcConst.states.dnd    : return mcLang(32);   // "32" :"Не беспокоить",
                case mcConst.states.webOnline: return mcLang(30); // "30" :"В сети",
            }
        },

        getTwoLettersName : function (name) {
            var rex = null;

            try {
                rex = (new RegExp("((\\p{L}|\\d).+[\\s\\-._()]+(\\p{L}|\\d))|(\\p{L}|\\d)", "iu")).exec(name);
            } catch (e) {
                rex = (new RegExp("((\\S|\\d).+[\\s\\-._()]+(\\S|\\d))|(\\S|\\d)", "i")).exec(name);
            }

            var res = "";

            if (!rex){
                res = (name || "U").toString()[0];
            } else
            if (rex[4]){
                res = rex[4];
            } else {
                res = rex[2] + rex[3];
            }

            return res.toUpperCase();
        },

        Error: function (id, params) {
            return serviceList.myReplace(mcConst.ErrorText[id], params);
        },

        /**
         * @return {boolean}
         */
        CheckLink: function (text) {
            var SCHEME   = "[a-z\\d.-]+://";
            var IPV4     = "(?:(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.){3}(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])";
            var HOSTNAME = "(?:(?:[^\\s!@#$%^&*()_=+[\\]{}\\\\|;:'\",.<>/?]+)\\.)+";
            var TLD      =  "(?:ac|ad|aero|ae|af|ag|ai|al|am|an|ao|aq|arpa|ar|asia|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|biz|bi|bj|bm|" +
                    "bn|bo|br|bs|bt|bv|bw|by|bz|cat|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|coop|com|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|" +
                    "do|dz|ec|edu|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|" +
                    "gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|info|int|in|io|iq|ir|is|it|je|jm|jobs|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|" +
                    "kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mil|mk|ml|mm|mn|mobi|mo|mp|mq|mr|ms|mt|museum|mu|mv|" +
                    "mw|mx|my|mz|name|na|nc|net|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pro|pr|ps|pt|pw|" +
                    "py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tel|tf|tg|th|tj|tk|" +
                    "tl|tm|tn|to|tp|travel|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g|" +
                    "xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp|" +
                    "xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw|dev)";
            var PORT = "(?::\\d{1,5})?";
            var HOST_OR_IP = "(?:" + HOSTNAME + TLD + PORT + "|" + IPV4 + PORT + ")";
            var PATH = "(?:[;/][^#?<>\\s]*)?";
            var QUERY_FRAG = "(?:\\?[^#<>\\s]*)?(?:#[^<>\\s]*)?";
            var URI1 = "\\b" + SCHEME + "[^<>(\\s|\\)|\\(|\\[|\\])]+"; //"[^<>\\s]+";
            var URI2 = "\\b" + HOST_OR_IP + PATH + QUERY_FRAG + "(?!\\w)";

            var MAILTO = "mailto:";
            var EMAIL  = "(?:" + MAILTO + ")?[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@" + HOST_OR_IP + QUERY_FRAG + "(?!\\w)";
            var URI_RE = new RegExp( "^(?:" + URI1 + "|" + URI2 + ")$", "i" ); // "|" + EMAIL +

            return URI_RE.test(text);
        },

        checkNoRestoreTool: function (restoreTool){
            return restoreTool === mcConst.dataModels.Settings         || restoreTool === mcConst.dataModels.UserProfile ||
                   restoreTool === mcConst.dataModels.HistoryBroadcast || restoreTool === mcConst.dataModels.ViewLogs ||
                   restoreTool === mcConst.dataModels.CreateConf;
        },

        tree_icon: function (obj){
            if (obj.$count || obj.needLoad){
                if (obj.open)
                    return "<div class='webix_tree_open'></div>";
                else
                    // return "<div class='_tree_close'></div>";
                    return "<div class='webix_tree_close'></div>";
            } else
                return "<div class='webix_tree_none'></div>";
        },

        IM: function (_uin){
            var uin = parseInt(_uin);
            var me  = parseInt(mcConst.UserInfo.UIN);
            
            return !isNaN(uin) && uin === me;
        },

        checkMediaTypesSupport : function (){
            var types = [
                "audio/webm;codecs=opus",
                "audio/webm",
                
                "video/webm",
                "video/ogg",
                "video/mp4",
                "video/mpeg",

                'video/webm;codecs="vp08.00.41.08,vorbis"',
                'video/webm;codecs="vp09.02.10.10.01.09.16.09.01,opus"',

                "video/webm;codecs=h264",
                "video/webm;codecs=vp8",
                "video/webm;codecs=vp9",
            ];

            for (var i in types) {
                console.log( (MediaRecorder.isTypeSupported(types[i]) ? "Yes" : "No ") + " - " + types[i]);
            }

            console.log("https://developer.mozilla.org/en-US/docs/Web/Media/Formats/codecs_parameter");
        },

        getSearchQuery: function (src, condition, simple) {
            var data = null;

            if (condition === "ref") {
                data = src.split('&ref=')[1];
            } else {
                src = serviceList.copy(src, 1).split('&');

                for (var i = 0; i < src.length; i++){
                    if ((condition && serviceList.isFunction(condition) && condition(src[i])) || !condition || src[i].indexOf(condition + "=") === 0){
                        if (simple) {
                            data = decodeURI(src[i].split('=')[1]);

                            break;
                        } else {
                            if (!data){
                                data = [];
                            }

                            data.push(src[i]);
                        }
                    }
                }
            }

            return data;
        },

        jsonp: function (url, callback, err, term) {
            var callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());

            window[callbackName] = function(data) {
                delete window[callbackName];

                document.body.removeChild(script);

                callback(data);
            };

            var script  = document.createElement('script');
            script.src  = url +  (term ? term : "&") + 'callback=' + callbackName;
            script.onerror = function (e){
                delete window[callbackName];

                document.body.removeChild(script);

                err && err(e);
            };

            try {
                document.body.appendChild(script);
            } catch (e){}
        },

        getVisualViewPortValues : function (clampOffsets, resizeDimensions) {
            const clamp = (val, min, max) => Math.min(Math.max(val, min), max);
            
            let {
                    width,
                    height,
                    widthOrig = null,
                    heightOrig = null,
                    scale,
                    offsetTop,
                    offsetLeft,
                    offsetTopOrig = null,
                    offsetLeftOrig = null,
                    pageLeft,
                    pageTop,
                    pageLeftOrig = null,
                    pageTopOrig = null,
                } = window.visualViewport;

            // Adjust values by clamping
            if (clampOffsets) {
                // Cache original values
                pageTopOrig = pageTop;
                pageLeftOrig = pageLeft;
                offsetTopOrig = offsetTop;
                offsetLeftOrig = offsetLeft;

                // Offsets measured against the page cannot go negative, nor exceed the max scroll offset
                // @note: Values below only used for absolute positioning
                pageTop = clamp(pageTop, 0, document.body.offsetHeight - height);
                pageLeft = clamp(pageLeft, 0, document.body.offsetWidth - width);

                // Offsets measured against the Layout Viewport cannot go negative, nor exceed the max offset within the Layout Viewport
                // @note: Values below only used for fixed positioning
                const layoutViewportHeight = (window.innerHeight * scale); // @TODO: This only is true when window.innerHeight resizes. Which is not always the case when pinch-zooming (or which happens too late as UA UI shows/hides)
                const layoutViewportWidth = (window.innerWidth * scale); // @TODO: This only is true when window.innerHeight resizes. Which is not always the case when pinch-zooming (or which happens too late as UA UI shows/hides)
                offsetTop = clamp(offsetTop, 0, layoutViewportHeight - height);
                offsetLeft = clamp(offsetLeft, 0, layoutViewportWidth - width);
            }

            // Adjust values by resizing height/width
            // Only needed for browsers that expose overscrolling through scrollX/scrollY
            if (resizeDimensions) {
                widthOrig = width;
                heightOrig = height;
                pageTopOrig = pageTop;
                pageLeftOrig = pageLeft;
                offsetTopOrig = offsetTop;
                offsetLeftOrig = offsetLeft;

                // Mobile Safari: Fixed Viewport does overscroll. Max value can overshoot 0 (inverse of overScrollY) and min value can exceed inverted max scroll distance
                // Desktop Safari: Fixed Viewport does not overscroll. Max value is 0, Min value is inverted max scroll distance.
                // We need a way to distinguish between both, because they need a different fix
                // @TODO: No longer rely on UA sniffing here, and find a way to detect wether the Fixed Viewport can overscroll or not …
                const isMobileSafari = (!!window.navigator.userAgent.match(/iPad/i) || !!window.navigator.userAgent.match(/iPhone/i));
                const isDesktopSafari = !isMobileSafari;

                // Overscrolling at the right edge
                if (width + pageLeft > document.body.offsetWidth) {
                    width = document.body.offsetWidth - pageLeft;

                    // @note: Value below only used for fixed positioning
                    if (isMobileSafari) {
                        if (scale == 1) offsetLeft -= (widthOrig - width);
                        if (offsetLeft < 0) offsetLeft = -offsetLeft;
                    }
                    else {
                        offsetLeft += (widthOrig - width); // Add overscroll value to the offset
                    }
                }

                // Overscrolling at the bottom edge
                if (height + pageTop > document.body.offsetHeight) {
                    height = document.body.offsetHeight - pageTop;

                    // @note: Value below only used for fixed positioning
                    if (isMobileSafari) {
                        if (scale == 1) offsetTop -= (heightOrig - height);
                        if (offsetTop < 0) offsetTop = -offsetTop;
                    }
                    else {
                        offsetTop += (heightOrig - height); // Add overscroll value to the offset
                    }
                }

                // Overscrolling at the left edge
                // @note: Might be tricky to achieve as you might trigger back navigation
                if (pageLeft < 0) {
                    width += pageLeft;

                    // @note: Value below only used for abs position
                    pageLeft = 0;

                    // @note: Value below only used for fixed positioning
                    offsetLeft = Math.abs(offsetLeft);
                }

                // Overscrolling at the top edge
                // @note: Might be tricky to achieve as you might trigger pull-to-refresh
                if (pageTop < 0) {
                    height += pageTop;

                    // @note: Value below only used for abs positioning
                    pageTop = 0;

                    // @note: Value below only used for fixed positioning
                    offsetTop = Math.abs(offsetTop);
                }

            }

            return Object.fromEntries(
                Object.entries({
                    width,
                    widthOrig,
                    height,
                    heightOrig,
                    scale,
                    offsetTop,
                    offsetTopOrig,
                    offsetLeft,
                    offsetLeftOrig,
                    pageLeft,
                    pageLeftOrig,
                    pageTop,
                    pageTopOrig,
                }).filter(([k, v]) => v !== null)
            );
        },

        _min: function (d0, d1, d2, bx, ay) {
            return d0 < d1 || d2 < d1
                ? d0 > d2
                    ? d2 + 1
                    : d0 + 1
                : bx === ay
                    ? d1
                    : d1 + 1;
        },

        levenshteinDistance : function(a, b){
            if (a === b) return 0;

            if (a.length > b.length) {
                let tmp = a;
                a = b;
                b = tmp;
            }

            let la = a.length;
            let lb = b.length;
            let x  = 0;
            let offset = 0;
            let vector = [];
            let y, d0, d1, d2, d3, dd, dy, ay, bx0, bx1, bx2, bx3;

            while (la > 0 && (a.charCodeAt(la - 1) === b.charCodeAt(lb - 1))) {
                la--;
                lb--;
            }

            while (offset < la && (a.charCodeAt(offset) === b.charCodeAt(offset))) {
                offset++;
            }

            la -= offset;
            lb -= offset;

            if (la === 0 || lb < 3) {
                return lb;
            }

            for (y = 0; y < la; y++) {
                vector.push(y + 1);
                vector.push(a.charCodeAt(offset + y));
            }

            let len = vector.length - 1;

            for (; x < lb - 3;) {
                bx0 = b.charCodeAt(offset + (d0 = x));
                bx1 = b.charCodeAt(offset + (d1 = x + 1));
                bx2 = b.charCodeAt(offset + (d2 = x + 2));
                bx3 = b.charCodeAt(offset + (d3 = x + 3));
                dd = (x += 4);
                for (y = 0; y < len; y += 2) {
                    dy = vector[y];
                    ay = vector[y + 1];
                    d0 = _min(dy, d0, d1, bx0, ay);
                    d1 = _min(d0, d1, d2, bx1, ay);
                    d2 = _min(d1, d2, d3, bx2, ay);
                    dd = _min(d2, d3, dd, bx3, ay);
                    vector[y] = dd;
                    d3 = d2;
                    d2 = d1;
                    d1 = d0;
                    d0 = dy;
                }
            }

            for (; x < lb;) {
                bx0 = b.charCodeAt(offset + (d0 = x));
                dd = ++x;
                for (y = 0; y < len; y += 2) {
                    dy = vector[y];
                    vector[y] = dd = _min(dy, d0, dd, bx0, vector[y + 1]);
                    d0 = dy;
                }
            }

            return dd;
        }
    };

    var multiple    = {
        kanban: {
            FilterFiled : function (options){
                function clearFilter(filter, noFocus){
                    if (clearShowed && !options.noCloseBtn) {
                        $$("clearBtn" + rnd).hide();

                        clearShowed = false;
                    }

                    options.thisFilter.setValue('');
                    options.thisFilter.$setValue('');

                    if (!filter) {
                        doFilter(noFocus);
                    } else {
                        options.List.filter("");
                    }

                    if (options.onClear) {
                        options.onClear();
                    }
                }

                function checkParams(text, obj, paramList, strict) {
                    var fp = [];
                    var show = true;

                    for (var i = 0; i < paramList.length; i++){
                        var param = paramList[i];

                        if (serviceList.isArray(obj[param])){
                            fp.push(obj[param].join('|').toLowerCase());
                        } else
                        if (param.indexOf(':') === -1){
                            if (obj[param] !== undefined) fp.push(obj[param].toString().toLowerCase());
                        } else {
                            var _param = param.split(':');

                            fp = fp.concat(obj[_param[0]].toString().toLowerCase().split(_param[1]));
                        }
                    }

                    if (serviceList.isString(text)){
                        if (strict){
                            show = fp.indexOf(text.toString().toLowerCase()) !== -1;
                        } else {
                            show = fp.join('|').indexOf(text) !== -1;
                        }
                    } else

                    if (serviceList.isBoolean(text)){
                        show = fp.indexOf(text.toString().toLowerCase()) !== -1;
                    } else

                    if (serviceList.isArray(text)){
                        for (var i = 0; i < text.length; i ++){
                            if (fp.indexOf(text[i].toString().toLowerCase()) === -1) {
                                show = false;

                                break;
                            }
                        }
                    }

                    return show;
                }

                function doFilter(noFocus) {
                    if (options.List && options.thisFilter) {
                        var text        = serviceList.trim(options.thisFilter.getValue().toString()).toLowerCase();
                        var listFilters = options.List._otherFilterOptions ? Object.keys(options.List._otherFilterOptions) : [];
                        var ofo         = options.List._otherFilterOptions;

                        if (text === "" && !listFilters.length){
                            clearFilter(true);

                            if (!noFocus) {
                                options.thisFilter.focus();
                            }
                        } else {
                            var res = [];
                            var pos = serviceList.getCaretPosition(options.thisFilter.getInputNode());

                            // console.log('=======================================');

                            options.List.filter(function(obj){
                                var filterResult = true;
                                var subFilter    = true;

                                // console.log(obj);
                                // console.log(obj.Tags);

                                if (!options.filterParams || options.filterParams.length === 0){
                                    options.filterParams = ['value'];
                                }

                                if (text !== ""){
                                    filterResult = checkParams(text, obj, options.filterParams);
                                }

                                if (filterResult && listFilters.length){
                                    for (var i = 0; i < listFilters.length; i ++){
                                        var searchText = ofo[listFilters[i]].items;

                                        if (serviceList.isString(searchText)){
                                            subFilter = subFilter && checkParams(searchText, obj, ofo[listFilters[i]].fields);
                                        } else

                                        if (serviceList.isArray(searchText)){
                                            subFilter = ofo[listFilters[i]].union === mcConst.methods.AND;

                                            for (var j = 0; j < searchText.length; j ++){
                                                subFilter = ofo[listFilters[i]].union === mcConst.methods.OR
                                                    ? subFilter || checkParams(searchText[j], obj, ofo[listFilters[i]].fields, true)
                                                    : subFilter && checkParams(searchText[j], obj, ofo[listFilters[i]].fields, true)
                                                ;

                                                if (ofo[listFilters[i]].union === mcConst.methods.AND){
                                                    break;
                                                }
                                            }
                                        }

                                        if (!subFilter) {
                                            break;
                                        }
                                    }
                                }

                                filterResult = filterResult && subFilter;

                                return filterResult ? !!res.push(obj) : false;
                            });

                            if (options.onAfterFilter){
                                options.onAfterFilter(res);

                                res = null;
                            }
                        }

                        if (!clearShowed && text !== "" && !options.noCloseBtn) {
                            clearShowed = true;

                            $$("clearBtn" + rnd).show();

                            if (!noFocus) setTimeout(function () {
                                options.thisFilter.focus();

                                serviceList.setCaretPosition(options.thisFilter.getInputNode(), pos);
                            }, 5);
                        }
                    }
                }

                var clearShowed = false;
                var rnd         = Math.random();
                var _filter     = { rows: [
                    { height: (options.topSpacer === undefined)? 0 : options.topSpacer },

                    { cols: [
                        { view: "search", padding: 0, css: 'noPaddingChild', placeholder: options.searchText || serviceList.Lang(10), keyPressTimeout: 400, on: { // "10" :"Введите текст для поиска",
                            onKeyPress: function (code, e) {
                                if (code === 27 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                                    var needFocus = this.getValue().length;

                                    clearFilter();

                                    if (needFocus) {
                                        this.focus();
                                    }
                                }
                            },
                            onTimedKeypress : function () {
                                doFilter();
                            },
                            onAfterRender : function closeFilter(){
                                options.thisFilter = this;
                                _filter.thisFilter = this;
                                
                                options.List = $$(options.listName);

                                setTimeout(function () {
                                    _filter.thisFilter.getInputNode().setAttribute("autocomplete", "off");
                                }, 100);
                            }
                        }},

                        { id: "clearBtn" + rnd, view: "button", type: "iconButton", icon: "times", width: 27, hidden: true, click: function () {
                            setTimeout(function () {
                                clearFilter();
                            }, 50);
                        }}
                    ]},

                    { height: options.bottomSpacer === undefined ? 4 : options.bottomSpacer }
                ]};

                if (options.id){
                    _filter.id = options.id;
                }

                if (options.rows){
                    _filter = serviceList.Marge(_filter, options.rows);
                }

                _filter.relocateList = function (newList, noFocus) {
                    var needClear = !!options.List;

                    options.listName = newList;
                    options.List = $$(newList);

                    if (options.List){
                        if (needClear) {
                            clearFilter(null, noFocus);
                        }
                    } else {
                        options.listName = "";
                        options.List = null;
                    }
                };

                _filter.doFilter = doFilter;
                _filter.clearFilter = clearFilter;

                return _filter;
            },
            createLink  : function (projectID, taskID, commentID) {
                return serviceList.isIE()
                    ? serviceList.myReplaceFormated("#{protocol}//#{host}#{path}#project=#{project}#{task}",
                        {
                            protocol: window.location.protocol,
                            host    : window.location.host,
                            path    : window.location.pathname,
                            project : projectID,
                            task    : taskID ? "&task=" + taskID + (commentID ? "&comment=" + commentID : "") : ""
                        })
                    : serviceList.myReplaceFormated("#{origin}#{path}#project=#{project}#{task}",
                        {
                            origin  : window.location.origin,
                            path    : window.location.pathname,
                            project : projectID,
                            task    : taskID ? "&task=" + taskID + (commentID ? "&comment=" + commentID : "") : ""
                        });
            },
            insertIco   : function (ico, size, attr){
                return "<span class='webix_icon byCenter " + ico + " " + ((size) ? size : "fa-lg") + "' " + (attr ? (serviceList.isString(attr) ? attr : attr.join(' ')) : "") + "></span>"
            }
        },

        admin: {
            FilterFiled : function (options){
                function clearFilter(){
                    if (clearShowed) {
                        $$("clearBtn" + rnd).hide();

                        clearShowed = false;
                    }

                    options.prevText = "";

                    options.thisFilter.$setValue('');
                    options.List.filter("");

                    if (options.onClear) {
                        options.onClear();
                    }
                }

                function doFilter(reFilter, noFocus) {
                    if (options.thisFilter){
                        var saveText = options.thisFilter.getValue().toString();
                        var text = serviceList.trim(saveText).toLowerCase();

                        if (text == ""){
                            clearFilter();

                            if (!options.escPressed && !noFocus) {
                                options.thisFilter.focus();
                            }
                        } else {
                            var res = [];

                            if (!options.prevText || options.prevText != text || reFilter){
                                options.prevText = text;

                                if (options.onBeforeFilter){
                                    options.onBeforeFilter(text);
                                }

                                options.List.filter(function(obj){
                                    var fp = [];

                                    if (!options.filterParams || options.filterParams.length == 0){
                                        options.filterParams = ['value'];
                                    }

                                    for (var i = 0; i < options.filterParams.length; i++){
                                        if (serviceList.isArray(obj[options.filterParams[i]])){
                                            fp.push(obj[options.filterParams[i]].join('|'));
                                        } else {
                                            fp.push(obj[options.filterParams[i]]);
                                        }
                                    }

                                    var filter = fp.join('|');

                                    filter = filter.toString().toLowerCase();

                                    if (filter.indexOf(text) != -1) {
                                        res.push(obj);
                                    }

                                    return (filter.indexOf(text) != -1);
                                });

                                if (options.onAfterFilter){
                                    options.onAfterFilter(res);

                                    res = null;
                                }

                                if (!clearShowed) {
                                    clearShowed = true;

                                    var pos = serviceList.getCaretPosition(options.thisFilter.getInputNode());

                                    $$("clearBtn" + rnd).show();

                                    options.thisFilter.$setValue(saveText);

                                    if (!noFocus) {
                                        options.thisFilter.focus();

                                        serviceList.setCaretPosition(options.thisFilter.getInputNode(), pos);
                                    }
                                }
                            }
                        }
                    }
                }

                var rnd = Math.random();
                var clearShowed = false;
                var _filter = { rows: [
                    { cols: [
                        { view: "text", padding: 0, css: 'noPaddingChild', tooltip: options.tooltip || "", placeholder: options.searchText || serviceList.Lang(71), keyPressTimeout: 300, on: { // "71" : "Введите текст для поиска"
                            onKeyPress: function (code, e) {
                                options.escPressed = false;

                                if (code === 27 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                                    options.escPressed = true;

                                    options.nowCleared = options.thisFilter.getValue().toString() != "";

                                    clearFilter();

                                    if (options.nowCleared) {
                                        this.focus();
                                    } else {
                                        this.blur();

                                        webix.UIManager.setFocus(document);
                                    }
                                }
                            },
                            onTimedKeypress : function () {
                                if (webix.UIManager.hasFocus(this)) {
                                    doFilter();
                                }
                            },
                            onAfterRender : function closeFilter(){
                                options.thisFilter = this;
                                _filter.thisFilter = this;
                                options.List       = $$(options.listName);

                                this.getInputNode().setAttribute("autocomplete", "off");
                            }
                        }},

                        { id: "clearBtn" + rnd, view: "button", type: "iconButton", icon: "times", height: 28, width: 27, hidden: true, click: clearFilter } // , css: "noBorder webixBlue"
                    ]},

                    { height: (options.bottomSpacer == undefined)? 4 : options.bottomSpacer }
                ]};

                if (options.id){
                    _filter.id = options.id;
                }

                _filter.doFilter = doFilter;
                _filter.clearFilter = clearFilter;

                return _filter;
            },
            checkRights : function (_id){
                var id = parseInt(_id) - 1;

                return mcConst.MyRightsSet.RightsSet[id] === '1' && (!_gLock.navAccess || (_gLock.navAccess && !_gLock.navAccess[_id]));
            }
        },

        chat: {
            FilterFiled : function (options){
                function clearFilter(){
                    if (clearShowed) {
                        $$(CLEAR).hide();

                        clearShowed = false;
                    }

                    options.thisFilter.$setValue('');
                    options.List.filter("");

                    if (options.onClear) {
                        options.onClear();
                    }
                }

                var rnd         = serviceList.RandomHash(6);
                var EDITOR      = (options.id || rnd) + "Editor";
                var CLEAR       = "clearBtn" + (options.clearID || rnd);
                var clearShowed = false;

                var _filter     = { id: options.id || (rnd + 'FilterBlock'), rows: [
                    { cols: [
                        { id: EDITOR, view: "text", padding: 0, css: 'noPaddingChild', placeholder: options.placeholder || "Search", keyPressTimeout: 500, on: { // "71" : "Введите текст для поиска"
                            onKeyPress: function(code, e){
                                if (options.keyEvents && options.keyEvents.hasOwnProperty(code)){
                                    if (options.keyEvents[code](options.List.getSelectedItem())) {
                                        e.preventDefault();
                                    }
                                }
                            },

                            onTimedKeypress : function(){
                                var origin = serviceList.trim(this.getValue().toString());
                                var text   = origin.toLowerCase();

                                if (text === ""){
                                    clearFilter();

                                    this.focus();
                                } else {
                                    var pos = serviceList.getCaretPosition(this.getInputNode());
                                    
                                    options.List.filter(function(obj){
                                        var fp = [];

                                        if (!options.filterParams || options.filterParams.length === 0){
                                            options.filterParams = ['value'];
                                        }

                                        for (var i = 0; i < options.filterParams.length; i++){
                                            if (serviceList.isArray(obj[options.filterParams[i]])){
                                                fp.push(obj[options.filterParams[i]].join('|'));
                                            } else {
                                                fp.push(obj[options.filterParams[i]]);
                                            }
                                        }

                                        var filter = fp.join('|');

                                        filter = filter.toString().toLowerCase();

                                        return (filter.indexOf(text) !== -1);
                                    });

                                    if (!clearShowed) {
                                        clearShowed = true;

                                        if (!options.noClearBtn) {
                                            $$(CLEAR).show();
                                        }

                                        // var pos = serviceList.getCaretPosition(this.getInputNode());

                                        this.$setValue(origin);
                                        this.focus();

                                        serviceList.setCaretPosition(options.thisFilter.getInputNode(), pos);
                                    }
                                }

                                if (options.OnEnterText){
                                    options.OnEnterText(origin);
                                }
                            },
                            onAfterRender : function(){
                                options.thisFilter = this;
                                options.List       = $$(options.listName);
                                options.hotkeyID   = serviceList.RandomHash(10);

                                $$(options.id || (rnd + 'FilterBlock')).onClear = function (cb) {
                                    options.onClear = cb;
                                };

                                if (serviceList._hotkeys){
                                    serviceList._hotkeys.addPreset(options.hotkeyID, [{
                                        key : mcConst.keyCodes.esc,
                                        // lockPrev: true,
                                        func: function closeFilter() {
                                            if (options.thisFilter.getValue().toString() !== "") {
                                                options.nowCleared = true;
                                            }

                                            clearFilter();

                                            options.thisFilter.focus();
                                        }
                                    }], options.thisFilter.getNode());
                                }
                            },
                            onDestruct: function () {
                                serviceList._hotkeys.removePreset(options.hotkeyID);
                            }
                        }},

                        { id: CLEAR, view: "button", type: "iconButton", icon: "times", width: 27, hidden: true, on: {onItemClick: clearFilter}, css: "icoButton button_primary byCenter iconNoPadding" } //
                    ]},

                    { height: (options.bottomSpacer == undefined)? 4 : options.bottomSpacer }
                ]};

                _filter.EDITOR = EDITOR;
                _filter.CLEAR  = CLEAR ;
                _filter.clearFilter = clearFilter;

                return _filter;
            }
        },

        forum: {
            FilterFiled : function (options){
                function clearFilter(){
                    if (clearShowed) {
                        $$("clearBtn" + rnd).hide();

                        clearShowed = false;
                    }

                    options.thisFilter.$setValue('');
                    options.List.filter("");

                    if (options.onClear) {
                        options.onClear();
                    }
                }

                var rnd = Math.random();
                var clearShowed = false;
                var res = { rows: [
                    { height: (options.topSpacer === undefined)? 0 : options.topSpacer },

                    { cols: [
                        { view: "search", padding: 0, css: 'noPaddingChild', placeholder: serviceList.Lang(options.placeHolder || 10), keyPressTimeout: 600, on: { // "10" :"Введите текст для поиска",
                            onKeyPress: function (code, e) {
                                if (code === 27 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                                    clearFilter();

                                    this.focus();
                                }
                            },
                            onTimedKeypress : function(){
                                var text = serviceList.trim(this.getValue().toString()).toLowerCase();

                                if (!options.List) {
                                    options.List = $$(options.listName);
                                }

                                if (text == ""){
                                    clearFilter();

                                    this.focus();
                                } else {
                                    options.List.filter(function(obj){
                                        var fp = [];

                                        if (!options.filterParams || options.filterParams.length == 0){
                                            options.filterParams = ['value'];
                                        }

                                        for (var i = 0; i < options.filterParams.length; i++){
                                            fp.push(obj[options.filterParams[i]]);
                                        }

                                        var filter = fp.join('|');

                                        filter = filter.toString().toLowerCase();

                                        return (filter.indexOf(text) != -1);
                                    });

                                    if (!clearShowed) {
                                        clearShowed = true;

                                        var pos = serviceList.getCaretPosition(this.getInputNode());

                                        $$("clearBtn" + rnd).show();

                                        this.$setValue(text);
                                        this.focus();

                                        serviceList.setCaretPosition(this.getInputNode(), pos);
                                    }
                                }
                            },
                            onAfterRender : function(){
                                options.thisFilter = this;
                                options.List = $$(options.listName);
                            }
                        }},

                        { id: "clearBtn" + rnd, view: "button", type: "iconButton", icon: "times", width: 27, hidden: true, click: clearFilter } // , css: "noBorder webixBlue"
                    ]},

                    { height: (options.bottomSpacer == undefined)? 4 : options.bottomSpacer }
                ]};

                if (options.id){
                    res.id = options.id;
                }

                if (options.rows){
                    res = serviceList.Marge(res, options.rows);
                }

                res.relocateList = function (newList) {
                    options.List = $$(newList);

                    clearFilter();
                };

                return res;
            },
            createLink  : function (path) {
                return serviceList.isIE()
                    ? window.location.protocol + "//" + window.location.host + window.location.pathname + "#" + path
                    : window.location.origin + window.location.pathname + "#" + path;
            },
            disableContextMenu : function (_view, exception){
                webix.event(_view.$view, "contextmenu", function(e){
                    function emersion(target, count) {
                        var res = [];
                        var parent = target.parentElement;

                        if (parent){
                            res = res.concat(parent.className.split(" "));

                            if (count){
                                count --;
                            }

                            if (parent.nodeName !== "#document" && count > 0){
                                res = res.concat(emersion(parent, count));
                            }
                        }

                        return res;
                    }

                    function skipItems(items, where, target) {
                        var flag = true;

                        if (items && items.length){
                            items.forEach(function (item) {
                                if ((where.length && where.indexOf(item) !== -1) || emersion(target, 4).indexOf(item) !== -1){
                                    flag = false;
                                }
                            });
                        }

                        return flag;
                    }

                    if (((e.target.nodeName !== "INPUT") && (e.target.nodeName !== "TEXTAREA") && skipItems(exception, e.target.className.split(" "), e.target))
                        || (e.target.type === "button")) {
                        e.preventDefault();
                    }
                });
            }
        }
    };

    if (_api && multiple[_api]){
        Object.keys(multiple[_api]).forEach(function (keyName) {
            serviceList[keyName] = multiple[_api][keyName];
        });
    }

    return serviceList;
}


if (typeof exports === 'object') {
    exports.srv = servicesController();
}
var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c<a.length&&0==a[c];)c++;this.num=new Array(a.length-c+b);for(var d=0;d<a.length-c;d++)this.num[d]=a[d+c]}function j(a,b){this.totalCount=a,this.dataCount=b}function k(){this.buffer=[],this.length=0}function m(){return"undefined"!=typeof CanvasRenderingContext2D}function n(){var a=!1,b=navigator.userAgent;return/android/i.test(b)&&(a=!0,aMat=b.toString().match(/android ([0-9]\.[0-9])/i),aMat&&aMat[1]&&(a=parseFloat(aMat[1]))),a}function r(a,b){for(var c=1,e=s(a),f=0,g=l.length;g>=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d<this.moduleCount;d++){this.modules[d]=new Array(this.moduleCount);for(var e=0;e<this.moduleCount;e++)this.modules[d][e]=null}this.setupPositionProbePattern(0,0),this.setupPositionProbePattern(this.moduleCount-7,0),this.setupPositionProbePattern(0,this.moduleCount-7),this.setupPositionAdjustPattern(),this.setupTimingPattern(),this.setupTypeInfo(a,c),this.typeNumber>=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f<this.modules.length;f++)for(var g=f*e,h=0;h<this.modules[f].length;h++){var i=h*e,j=this.modules[f][h];j&&(d.beginFill(0,100),d.moveTo(i,g),d.lineTo(i+e,g),d.lineTo(i+e,g+e),d.lineTo(i,g+e),d.endFill())}return d},setupTimingPattern:function(){for(var a=8;a<this.moduleCount-8;a++)null==this.modules[a][6]&&(this.modules[a][6]=0==a%2);for(var b=8;b<this.moduleCount-8;b++)null==this.modules[6][b]&&(this.modules[6][b]=0==b%2)},setupPositionAdjustPattern:function(){for(var a=f.getPatternPosition(this.typeNumber),b=0;b<a.length;b++)for(var c=0;c<a.length;c++){var d=a[b],e=a[c];if(null==this.modules[d][e])for(var g=-2;2>=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g<a.length&&(j=1==(1&a[g]>>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h<d.length;h++){var i=d[h];g.put(i.mode,4),g.put(i.getLength(),f.getLengthInBits(i.mode,a)),i.write(g)}for(var l=0,h=0;h<e.length;h++)l+=e[h].dataCount;if(g.getLengthInBits()>8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j<b.length;j++){var k=b[j].dataCount,l=b[j].totalCount-k;d=Math.max(d,k),e=Math.max(e,l),g[j]=new Array(k);for(var m=0;m<g[j].length;m++)g[j][m]=255&a.buffer[m+c];c+=k;var n=f.getErrorCorrectPolynomial(l),o=new i(g[j],n.getLength()-1),p=o.mod(n);h[j]=new Array(n.getLength()-1);for(var m=0;m<h[j].length;m++){var q=m+p.getLength()-h[j].length;h[j][m]=q>=0?p.get(q):0}}for(var r=0,m=0;m<b.length;m++)r+=b[m].totalCount;for(var s=new Array(r),t=0,m=0;d>m;m++)for(var j=0;j<b.length;j++)m<g[j].length&&(s[t++]=g[j][m]);for(var m=0;e>m;m++)for(var j=0;j<b.length;j++)m<h[j].length&&(s[t++]=h[j][m]);return s};for(var c={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},d={L:1,M:0,Q:3,H:2},e={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},f={PATTERN_POSITION_TABLE:[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],G15:1335,G18:7973,G15_MASK:21522,getBCHTypeInfo:function(a){for(var b=a<<10;f.getBCHDigit(b)-f.getBCHDigit(f.G15)>=0;)b^=f.G15<<f.getBCHDigit(b)-f.getBCHDigit(f.G15);return(a<<10|b)^f.G15_MASK},getBCHTypeNumber:function(a){for(var b=a<<12;f.getBCHDigit(b)-f.getBCHDigit(f.G18)>=0;)b^=f.G18<<f.getBCHDigit(b)-f.getBCHDigit(f.G18);return a<<12|b},getBCHDigit:function(a){for(var b=0;0!=a;)b++,a>>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<<h;for(var h=8;256>h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;c<this.getLength();c++)for(var d=0;d<a.getLength();d++)b[c+d]^=g.gexp(g.glog(this.get(c))+g.glog(a.get(d)));return new i(b,0)},mod:function(a){if(this.getLength()-a.getLength()<0)return this;for(var b=g.glog(this.get(0))-g.glog(a.get(0)),c=new Array(this.getLength()),d=0;d<this.getLength();d++)c[d]=this.get(d);for(var d=0;d<a.getLength();d++)c[d]^=g.gexp(g.glog(a.get(d))+b);return new i(c,0).mod(a)}},j.RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],j.getRSBlocks=function(a,b){var c=j.getRsBlockTable(a,b);if(void 0==c)throw new Error("bad rs block @ typeNumber:"+a+"/errorCorrectLevel:"+b);for(var d=c.length/3,e=[],f=0;d>f;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=['<table style="border:0;border-collapse:collapse;">'],h=0;d>h;h++){g.push("<tr>");for(var i=0;d>i;i++)g.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:'+e+"px;height:"+f+"px;background-color:"+(a.isDark(h,i)?b.colorDark:b.colorLight)+';"></td>');g.push("</tr>")}g.push("</table>"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}();
/**
 * Created by Gifer on 12.07.2016.
 */

"use strict";

(function () {
    if (window.mcWidgets){
        window.mcWidgets.UsersOfGroups = function UsersOfGroups($rootScope, _groups, w, h) {
            var view       = null;
            var presetName = mcService.RandomHash(15);
            var userList   = {};
            var groups     = [];
            var uins       = "";
            var textSource = {
                title : "",
                cancel: mcLang(12)  // "12" : "Закрыть",
            };
            var userListID = mcService.RandomHash(10);
            var filterField= null;
            var filterOptions = {
                listName     : userListID,
                filterParams : [
                    "DisplayName",
                    "groupNames",
                    "UIN"
                ]
            };

            function close() {
                if (view){
                    view.hide();
                }

                $rootScope.hotKeyDispatcher.removePreset(presetName);
            }

            function concatUsersList(list, group) {
                list.forEach(function (user) {
                    var uin = user.UIN;

                    if (!userList[uin]){
                        userList[uin] = user;
                    }

                    if (!userList[uin].groupNames){
                        userList[uin].groupNames = [];
                    }

                    if (group.Name && userList[uin].groupNames.indexOf(group.Name) == -1){
                        userList[uin].groupNames.push(group.Name);
                    }
                });
            }

            // =======================================================

            this.init = function (_groups, _uins) {
                if (!mcService.isArray(_groups)){
                    groups = [_groups];
                } else {
                    groups = _groups;
                }

                uins = _uins || "";
            };

            this.initTextSource = function (source) {
                textSource = mcService.Marge(textSource, source);
            };

            this.close = close;

            this.show = function () {
                if (view){
                    view.destructor();
                }

                userList = {};

                var task = new mcService.TaskList();

                task.AddTask(function () {
                    $rootScope.hotKeyDispatcher.addPreset(presetName, [{
                        key    : mcConst.keyCodes.esc,
                        func   : function () {
                            if (!filterOptions.nowCleared){
                                close();
                            }

                            filterOptions.nowCleared = false;
                        }
                    }], document, true);

                    task.Next();
                });

                task.AddTask(function () {
                    if (uins) {
                        $rootScope.$broadcast('SendCMDToServer' , [
                            mcConst._CMD_.cs_get_users_changeid_data,
                            mcConst.SessionID,

                            uins,

                            function (data) {
                                if (data && data.length) {
                                    data.forEach(function(item){
                                        item.id = item.UIN;
                                    });

                                    concatUsersList(data, {});
                                }

                                task.Next();
                            }
                        ]);
                    } else {
                        task.Next();
                    }
                });

                groups.forEach(function (group) {
                    task.AddTask(function () {
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_get_group_users_list,
                            mcConst.SessionID,
                            group.ID,
                            
                            function( data ){
                                data.forEach(function(item){
                                    item.id = item.UIN;
                                });

                                concatUsersList(data, group);

                                task.Next();
                            }
                        ]);
                    });
                });

                task.AddTask(function () {
                    filterField = new mcService.FilterFiled(filterOptions);

                    view = webix.ui({
                        view    : "window",
                        position: "center",
                        modal   : true,
                        head    : textSource.title || false,
                        width   : w || 400,
                        height  : h || 500,
                        css     : "autoheightTitle",
                        body    : { rows: [
                            { padding: 4, rows: [
                                filterField
                            ]},

                            {
                                // view      : "list",
                                id: userListID,
                                view        : "datatable",
                                resizeColumn: true,
                                drag        : true,
                                select      : "row",
                                multiselect : true,
                                headerRowHeight: 25,
                                minColumnWidth : 70,
                                navigation  : false,
                                columns     : [
                                    { id:"UIN",         header:"UIN", width: 55,     sort:"int"},
                                    { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                                ],
                                // type    : { height:"auto" },
                                data    : mcService.convertObjToArray(userList)
                                // template: function (obj) {
                                //     return "<b>" + obj.DisplayName + "</b><span class='toRight'>(UIN: <b>" + obj.UIN + "</b>)</span><br><div class='byRight'>" + obj.groupNames.join(' | ') + "</div>";
                                // }
                            },

                            { height: 4},
                            { height: 30, cols: [
                                {},
                                { view: "button", width: 120, value: textSource.cancel, click: close },
                                {}
                            ]},
                            { height: 4}
                        ]}
                    });

                    view.show();

                    $rootScope.$broadcast('addShowedWindow', [presetName, view]);
                });

                task.Run();
            };

            this.init(_groups);
        }
    } else {
        console.error('window.mcWidgets is not defined!');
    }
})();



 (function () {
     "use strict";
     if (window.mcWidgets){
         window.mcWidgets.ListEditButtons = function ListEditButtons($rootScope){
             var textSource = {
                 add  : mcLang(50),
                 edit : mcLang(51),
                 del  : mcLang(52),
                 clone: mcLang(579)
             };

             function show(params, fillparams){
                 var wndId = mcService.RandomHash(7);

                 $rootScope.hotKeyDispatcher.addPreset(wndId, [{
                     key : mcConst.keyCodes.enter,
                     func: function(){
                         var form = params.dialog.getChildViews()[1];

                         if (params.confirm.apply(form, [].concat(form.getChildViews())) !== true) { // если возвращает true, то зыкрывать диалоговое окно не нужно, в поле для ввода текста есть ошибка и т.д.
                             params.dialog.close();
                         }
                     }
                 }, {
                     key : mcConst.keyCodes.esc,
                     func: function(){
                         params.dialog.close();
                     }
                 }], document, true);

                 params.dialog = webix.ui(mcService.Marge(params.options, {
                     view     : "window",
                     position : "center",
                     id       : wndId,
                     body     : {
                         view : 'form',
                         rules:{
                             "Name"    : webix.rules.isNotEmpty
                         },
                         elements : [{
                             view       : "text",
                             label      : params.editTitle, // mcService.Lang(904), // "904":"Название должности",
                             name       : 'Name',
                             labelPosition : 'top',
                             required   : "true"
                         }]
                         .concat(params.additionalItems ? params.additionalItems : [])
                         .concat({
                             cols : [{
                                 view  : "button",
                                 value : mcService.Lang(104), // "104": "Сохранить",
                                 click : function() {
                                     var form = this.getFormView();

                                     if (params.confirm.apply(form, [].concat(form.getChildViews())) !== true) { // если возвращает true, то зыкрывать диалоговое окно не нужно, в поле для ввода текста есть ошибка и т.д.
                                         params.dialog.close();
                                     }
                                 }
                             }, {
                                 view  : "button",
                                 type  : "danger",
                                 value : mcService.Lang(103), // "103": "Отмена",
                                 click : function(){
                                     params.dialog.close();
                                 }
                             }]
                         })
                     },
                     on : {
                         onShow : function(){
                             if (mcService.isString(params.list)) {
                                 params.list = $$(params.list);
                             }

                             if (fillparams) {
                                 this.getChildViews()[1].getChildViews().forEach(function(item, id){
                                     if (params.fillItems[id] != undefined) item.setValue(params.list.getSelectedItem()[params.fillItems[id]]);
                                 });
                             }

                             this.getChildViews()[1].getChildViews()[0].focus();

                             $rootScope.$broadcast('addShowedWindow', [wndId, this]); // сообщаем менеджеру переходов между экранами, что появилось новое окно и его нужно закрыть при изменении экрана
                         },
                         onDestruct : function(){
                             $rootScope.hotKeyDispatcher.removePreset(wndId);
                         }
                     }
                 }));

                 params.dialog.show();
             }

             function startDel(params) {
                 if (mcService.isString(params.list)) {
                     params.list = $$(params.list);
                 }

                 var item = params.list.getSelectedItem();

                 if (item){
                     $rootScope.$broadcast('addShowedWindow', [mcService.RandomHash(4), webix.confirm({
                         type  : "confirm-warning",
                         text  : mcService.myReplace(params.actionTitles.del, params.delName ? item[params.delName] : null), // "902":"Удалить должность \"%s\"?",
                         ok    : mcService.Lang(581), // "581": "Удалить",
                         cancel: mcService.Lang(103), // "103": "Отмена",
                         callback:function(yes){
                             if (yes){
                                 params.actions.del(item);
                             }
                         }
                     })]);
                 }
             }

             this.initTextSource = function (source) {
                 textSource = mcService.Marge(textSource, source);
             };

             this.editButtons = function(_params){
                 var res    = {};
                 var params = null;

                 var _actions = {
                     add: function(){
                         params.confirm = params.actions.add;
                         params.options.head = params.actionTitles.add;

                         show(params);
                     },
                     del: function(){
                         startDel(params);
                     },
                     edit: function(){
                         params.confirm = params.actions.edit;
                         params.options.head = params.actionTitles.edit;

                         show(params, true);
                     },
                     clone: function(){
                         params.confirm = params.actions.clone;
                         params.options.head = params.actionTitles.clone;

                         show(params, true);
                     }
                 };

                 params = mcService.Marge({
                     additionalItems: [],
                     list      : null,
                     fillItems : [],
                     confirm   : null,
                     actions   : {},
                     editTitle : "",
                     delDesc   : "",
                     delName   : "",
                     vertical  : false,
                     onShow    : null,
                     dialog    : null,
                     hotkeyPreset: mcService.RandomHash(10),

                     options : {
                         modal : true,
                         head  : "",
                         width : 300
                     },
                     actionTitles: {
                         add: "",
                         del: "",
                         edit: "",
                         clone: ""
                     },
                     hotKeys : {},
                     showed   : {
                         add  : true,
                         del  : true,
                         edit : true,
                         clone: true
                     }
                 }, _params);

                 params.hotKeys.add   = mcService.Marge({
                     keyTitle: "",
                     key     : null,
                     altKey  : false,
                     shiftKey: false,
                     ctrlKey : false,
                     func    : _actions.add
                 }, params.hotKeys.add  );
                 params.hotKeys.del   = mcService.Marge({
                     keyTitle: "",
                     key     : null,
                     altKey  : false,
                     shiftKey: false,
                     ctrlKey : false,
                     func    : _actions.del
                 }, params.hotKeys.del  );
                 params.hotKeys.edit  = mcService.Marge({
                     keyTitle: "",
                     key     : null,
                     altKey  : false,
                     shiftKey: false,
                     ctrlKey : false,
                     func    : _actions.edit
                 }, params.hotKeys.edit );
                 params.hotKeys.clone = mcService.Marge({
                     keyTitle: "",
                     key     : null,
                     altKey  : false,
                     shiftKey: false,
                     ctrlKey : false,
                     func    : _actions.clone
                 }, params.hotKeys.clone);

                 params.rawBTN = {};
                 params.rawBTN.bAdd   = { id: "wdlb" + mcService.RandomHash(5), view: "button", value: textSource.add,   tooltip: params.hotKeys.add  ? params.hotKeys.add.keyTitle : "", click: _actions.add };  // "50" : "Добавить",
                 params.rawBTN.bEdit  = { id: "wdlb" + mcService.RandomHash(5), view: "button", value: textSource.edit,  tooltip: params.hotKeys.edit ? params.hotKeys.edit.keyTitle : "", click: _actions.edit};  // "51" : "Изменить",
                 params.rawBTN.bDel   = { id: "wdlb" + mcService.RandomHash(5), view: "button", value: textSource.del,   tooltip: params.hotKeys.del  ? params.hotKeys.del.keyTitle : "", click: _actions.del, type: "danger"}; // "52" : "Удалить",
                 params.rawBTN.bClone = { id: "wdlb" + mcService.RandomHash(5), view: "button", value: textSource.clone, tooltip: params.hotKeys.clone ? params.hotKeys.clone.keyTitle : "", click: _actions.clone}; // "579": "Клонировать",

                 res[params.vertical ? "rows" : "cols"] = []
                     .concat(params.actions.add   && params.showed.add   ? mcService.Marge({}, params.rawBTN.bAdd  ) : [])
                     .concat(params.actions.edit  && params.showed.edit  ? mcService.Marge({}, params.rawBTN.bEdit ) : [])
                     .concat(params.actions.del   && params.showed.del   ? mcService.Marge({}, params.rawBTN.bDel  ) : [])
                     .concat(params.actions.clone && params.showed.clone ? mcService.Marge({}, params.rawBTN.bClone) : [])
                 ;

                 return {
                     btnList  : res,

                     startEdit: function(edit){
                         if (edit === false) {
                             _actions.add();
                         } else {
                             _actions.edit();
                         }
                     },

                     startDel : _actions.del,

                     disable: function (){
                         var bAdd   = $$(params.rawBTN.bAdd.id);
                         var bEdit  = $$(params.rawBTN.bEdit.id);
                         var bDel   = $$(params.rawBTN.bDel.id);
                         var bClone = $$(params.rawBTN.bClone.id);

                         bAdd   && bAdd  .disable();
                         bEdit  && bEdit .disable();
                         bDel   && bDel  .disable();
                         bClone && bClone.disable();
                     },

                     enable: function (){
                         var bAdd   = $$(params.rawBTN.bAdd.id);
                         var bEdit  = $$(params.rawBTN.bEdit.id);
                         var bDel   = $$(params.rawBTN.bDel.id);
                         var bClone = $$(params.rawBTN.bClone.id);

                         bAdd   && bAdd  .enable();
                         bEdit  && bEdit .enable();
                         bDel   && bDel  .enable();
                         bClone && bClone.enable();
                     },

                     enableHotKeys : function () {
                         var _keys = [];

                         Object.keys(params.hotKeys).forEach(function (_key) {
                             if (params.hotKeys[_key].key) {
                                 _keys.push(params.hotKeys[_key]);
                             }
                         });

                         if (_keys.length){
                             $rootScope.hotKeyDispatcher.addPreset(params.hotkeyPreset, _keys, document, true);
                         }
                     },

                     disableHotKeys: function () {
                         $rootScope.hotKeyDispatcher.removePreset(params.hotkeyPreset);
                     }
                 };
             };
         }
     }
 })();

"use strict";

var mcConst = {
    Title : "MyChat Server Control Panel",
    LMSG  : [],
    SYSLOG: [],
    _CMD_ : window.hasOwnProperty('getCMD') ? getCMD() : {},
    LanguagesList: {},
    changeProtocol : location.protocol,

    neverDate: '01.01.1900.00.00.00',

    emptyIndexS: "_NoInDeX_",
    emptyIndexI: -1,

    socketIO: null,

    io_transport: ["polling", "websocket"], //

    nodePathes: {
        images: "sendimages",
        files : "files"
    },

    pathAliases: {
        AliasAdmin    : "admin", // папка-псевдоним, путь к админке
        AliasAPI      : "API", // папка-псевдоним, путь к Integration API
        AliasChat     : "chat", // папка-псевдоним, путь к WEB-чату
        AliasFiles    : "files", // папка-псевдоним, путь к файлам, залитым на сервер
        AliasForum    : "forum", // папка-псевдоним, путь ко встроенному форуму
        AliasKanban   : "kanban", // папка-псевдоним, путь к канбан-доске

        LobbyEnable   : true, // включен доступ к списку сервисов MyChat
        ForumEnable   : true, // включить доступ ко встроенному форуму
        KanbanEnable  : true, // включить доступ к канбан-доске
        ChatEnable    : true, // включить доступ к WEB-чату
        AdminEnable   : true // включить доступ к WEB-админке
    },

    whereFiles: {
        private: 1,
        conf   : 2,
        forum  : 3,
        kanban : 4,
        bbs    : 5,
        broadc : 6
    },

    Lang : "en",

    imageSize: {
        small : {
            x: 120,
            y: 120,
            xy: '120x120'
        },
        medium: {
            x: 150,
            y: 150,
            xy: '150x150'
        },
        big   : {
            x: 200,
            y: 200,
            xy: '200x200'
        }
    },

    restartOptions: ['','',''],

    restartItems: {
        MyChat: 'm',
        FTP   : 'f',
        WEB   : 'w'
    },

    lockInterface : 'lockInterface',

    storageFields: {
        lang    : "admLang",
        Login   : "admLogin",
        Pwd     : "admPwd",
        ServPwd : "admServPwd",
        Rm      : "admRm"
    },

    Books: {
        SMTP: "smtp",
        Names: "names"
    },

    userFields : 'LASTACCESS,LASTSPEAKTIME,STATE,TAG,DOMAIN,' +
                 'REPUTATION,NICK,DISPLAYNAME,EMAIL,GROUPRIGHTS,' +
                 'UIN,ACTIVE,REGISTERED,WORKDEPT,TEAMLEAD,AUTHTYPE,SEX', 

    states: {
        offline    : -1,
        online     : 0,
        away       : 1,
        dnd        : 2,
        webOnline  : 3
    },

    currentState: 0,

    dataModels : {
        ServerInfo      : 'ServerInfo',
        UserManager     : 'UserManager',
        Login           : 'Login',
        NavPanel        : 'NavPanel',
        UserProfile     : 'UserProfile',
        GroupRights     : 'GroupRights',
        GroupUsers      : 'GroupUsers',
        ApplyPanel      : "ApplyPanel",
        RightsManager   : "RightsManager",
        Contacts        : "Contacts",
        WorkPositions   : "WorkPositions",
        WebSupport      : "WebSupport",
        MyChatGuest     : "MyChatGuest",

        LicenseMyChat   : "LicenseMyChat",
        LicenseGuest    : "LicenseGuest",
        LicenseClear    : "LicenseClear",
        LicenseQuiz     : "LicenseQuiz",

        UsersImports    : "UsersImports",
        Operators       : "Operators",
        Bans            : "Bans",
        AutoChannels    : "AutoChannels",
        RemoteSettings  : "RemoteSettings",
        History         : "History",
        BBS             : "BBS",
        WorkTime        : "WorkTime",
        ActiveDirectory : "ActiveDirectory",
        Updates         : "Updates",
        OnlineUsers     : "OnlineUsers",
        MCScripts       : "MCScripts",
        Reboot          : "Reboot",
        ActiveChannels  : "ActiveChannels",
        PresetManager   : "PresetManager",
        UserGroups      : "UserGroups",
        PersonalGroups  : "PersonalGroups",
        NssService      : "NssService",
        Forum           : "Forum",
        SupportForum    : "SupportForum",
        Integrations    : "Integrations",
        PluginAccess    : "PluginAccess",
        Relocation      : "Relocation",
        Bots            : "Bots",
        TotalClear      : "TotalClear",
        AdDomains       : "AdDomains",
        Terminal        : "Terminal",
        CustomMenu      : "CustomMenu",
        Testport        : "Testport",

        FilterAntiflood : "FilterAntiflood",
        FilterBadWords  : "FilterBadWords",
        FilterIP        : "FilterIP",
        FilterMAC       : "FilterMAC",
        FilterNames     : "FilterNames",
        FilterHardware  : "FilterHardware",

        SettingsNetwork : "SettingsNetwork",
        SettingsInfo    : "SettingsInfo",
        SettingsInvite  : "SettingsInvite",
        SettingsLogs    : "SettingsLogs",
        SettingsFTP     : "SettingsFTP",
        SettingsWEB     : "SettingsWEB",
        SettingsBackup  : "SettingsBackup",
        SettingsService : "SettingsService",
        SettingsAPI     : "SettingsAPI",
        SettingsGPS     : "SettingsGPS",
        SettingsSMTP    : "SettingsSMTP",
        SettingsFolders : "SettingsFolders",
        SettingsWebCache: "SettingsWebCache",
        SettingsPlugins : "SettingsPlugins",
        Others          : "Others",

        userInfoByPreset  : 'userInfoByPreset',
        networkInterfaces : 'networkInterfaces',
        userFotoPath      : 'userFotoPath',
        settingsIpList    : 'settingsIpList',

        wizardSteps : 'wizardSteps',
        wizard_1    : 'wizard_1',
        wizard_2    : 'wizard_2',
        wizard_3    : 'wizard_3',
        wizard_4    : 'wizard_4',
        wizard_5    : 'wizard_5',
        wizard_6    : 'wizard_6',
        wizard_7    : 'wizard_7',
        wizard_8    : 'wizard_8',
        wizard_9    : 'wizard_9',
        wizard_10   : 'wizard_10',
        wizard_11   : 'wizard_11'
    },

    imagesPath : {
        noFilter   : "source/images/nofilter20.png",
        // langPath   : 'source/languages/',
        loadingImg : 'source/images/loading.gif',
        all        : 'source/images/',
        flags      : 'source/images/flags/',
        loadImage  : 'source/images/loadimg.gif',
        noImage    : 'source/images/noimage.png'
    },

    customServerOptions : {
        EnableWebSupport  : false,
        EnableMyChatGuest : false
    },

    serverOptionsNames : {
        EnableWebSupport    : 'EnableWebSupport',
        EnableMyChatGuest   : 'EnableMyChatGuest',
        ShowOperatorsList   : 'WebSupportShowOperatorsList',
        AskUserFields       : 'WebSupportAskUserFields',
        DisplayNickStyle    : 'WebSupportDisplayNickStyle',
        DisplayNickFormat   : 'WebSupportDisplayNickFormat',
        InFrame             : 'WebSupportInFrame',
        SupportOptions      : 'WebSupportOptions',
        DisconnectIdleTime  : 'WebSupportDisconnectIdleTime'
    },

    LicenseInfo : {
        "ServerRegisteredBy"      : "Network Software Solutions", // на кого зарегистрирован сервер
        "IsFree"                  : false,                        // (5.7+) если сервер бесплатный, то true, иначе - false
        "IsMyChatGuestRegistered" : false                          // зарегистрирован ли сервис MyChat Guest
    },

    customLogin : false,

    lockWindowHeight : 65,

    ApplyPanelShowed : false,

    errMessageExpire : 5000,

    guestGroupId : 7,

    userFoto : {
        w : 135,
        h : 157
    },

    CRLF : '\r\n',
    CR   : '\r',
    LF   : '\n',

    MyRightsSet : [
      /*
       *{1}   QLogin,
       *{2}   QBBSPost,
       *{3}   QBBSView,
       *{4}   QTxtChCreate,
       *{5}   QTxtChSay,
       *{6}   QTxtChJoin,
       *{7}   QPrivateOpen,
       *{8}   QPrivatesGetMessages,
       *{9}   QUserDetailsChange,
       *{10}  QFilesSend,
       *{11}  QFilesRecieve,
       *{12}  QOperatorBan,
       *{13}  QOperatorTurnOutFromChannel,
       *{14}  QKill,
       *{15}  QBlockIP,
       *{16}  QBlockMAC,
       *{17}  QOperatorTxtChTopicSet,
       *{18}  QFTPPublic,
       *{19}  QFTPPersonal,
       *{20}  QRemoteAdm,
       *{21}  QOperatorClearChannelText,
       *{22}  QContactsListChange,
       *{23}  QBroadcasts,
       *{24}  QAllowPersonalMsg,
       *{25}  QAllowAlertMsg,
       *{26}  QAllowSysinfoView,
       *{27}  QSendImages,
       *{28}  QAllowIgnores,
       *{29}  QAllowInvites,
       *{30}  QImagesPrivates,
       *{31}  QShowCommonContactsList,                 // Включить общий список контактов
       *{32}  QHalt,
       *{33}  QTxtChRename,
       *{34}  QTxtChDelete,
       *{35}  QForciblyInvites,                        // разрешить принудительно "загонять" других юзеров в любые каналы
       *{36}  QBlockUIN,
       *{37}  QAllowPlugins,
       *{38}  QAllowOptionsChange,
       *{39}  QAllowMyFavoriteChannels,
       *{40}  QAllowCloseProgram,                      // разрешить закрытие клиентской программы (Alt+X)
       *{41}  QShowPersonalContactsList,               // Включить личный список контактов
       *{42}  QAllowAccountsManager,                   // разрешить пользоваться менеджером учётных записей
       *{43}  QWEBAllowViewLogsSelfPrivates,           // просмотр своих разговоров в приватах
       *{44}  QWEBAllowViewLogsAllChannels,            // просмотр всех разговоров в каналах
       *{45}  QWEBAllowViewLogsAllPrivates,            // просмотр всех разговоров в приватах
       *{46}  QAllowFindUsersTool,                     // разрешить поиск пользователей
       *{47}  QAllowActions,                           // разрешить вставку в текст Action-ов
       *{48}  QAllowClientLogPrivatesAndChannels,      // разрешить или запретить клиенту писать логи локально, у себя на компьютере
       *{49}  QMessengerStyle,                         // Messenger-style отображения майчат клиента
       *{50}  QAllowOpenComputer,                      // показывать или нет в меню опцию "Открыть компьютер" по щелчку на имени юзера
       *{51}  QExceptionAllowRecievePrivates,          // Приём приватных сообщений от пользователей, которым запрещена отправка приватных сообщений
       *{52}  QAllowViewRemoteUserMACAddress,          // разрешить смотреть MAC адрес удалённого юзера
       *{53}  QAllowViewRemoteUserActiveProcess,       // разрешить смотреть активный процесс удалённого юзера
       *{54}  QWEBAllowViewFTPLog,                     // Просмотр FTP протоколов
       *{55}  QWEBAllowViewSystemLog,                  // Просмотр системных протоколов
       *{56}  QEnableTaskWorkersJobTimeControlSystem,  // контроль рабочего времени
       *{57}  QWEBSupportAllowAccess,                  // доступ к WEB-интерфейсу веб-суппорта
       *{58}  QWEBAllowAdmin,                          // управление сервером (WEB-админка)
       *{59}  QAllowProgramBlockTool,                  // Блокирование работающей программы паролем
       *{60}  QAllowNetworkStatusChange,               // Изменение сетевого статуса
       *{61}  QEnableAllowedClientsPluginsList,        // Активировать список разрешённых клиентских плагинов
       *{62}  QEnableBlockedCLientsPluginsList,        // Активировать список запрещённых клиенских плагинов
       *{63}  QEnablePluginsManagement,                // Разрешить управление плагинами на клиенте
       *{64}  QAllowImagesInBroadcasts,                // вставка картинок в оповещениях
       *{65}  QEnableFontLayoutsInMessages,            // использование шрифтовой разметки в отправляемых сообщениях

       {66 это ещё не внесено в базу данных}  QAllowCreateHiddenChannels,         // разрешить создавать скрытые каналы

       *{67}  QEnableTransferFilesOnlyViaServer,       // передавать файлы только через сервер
       *{68}  QEnableImmunityFromBans,                 // иммунитет от банов
       *{69}  QEnableAdvertBlock,                      // показывать или нет рекламный блок
       *{70}  QBlockPrivatesExceptPersonalContacts,    // Запретить приваты со всеми, кроме входящих в личный список контактов
       *{71}  QBlockPrivatesExceptCommonContacts,      // Запретить приваты со всеми, кроме входящих в общий список контактов
       *{72}  QEnableImmunityFromIgnores,              // Иммунитет от игноров
       *{73}  QIntegrationAPIEnableSendMsgFromAnyUser, // Разрешить отправку сообщений от имени этих пользователей
       *{74}  QEnableVoiceCalls,                       // Голосовые звонки
       *{75}  QEnableVideoCalls,                       // Видеозвонки
       *{76}  QAllowGetVoiceCalls,                     // Разрешить получать голосовые звонки
       *{77}  QAllowGetVideoCalls,                     // Разрешить получать видеозвонки
       *{78}  QAllowAddNewPlugins,                     // Добавление новых плагинов
       *{79}  QAllowDeletePlugins,                     // Удаление плагинов
       *{80}  QAllowChangeAccountPassword,             // Изменение пароля своей учётной записи
       *{81}  QAllowAccessForeignersToPersonalFiles,   // Разрешить доступ к личным файлам для других пользователей ("только чтение")
       *{82}  QAllowPublishLinkToPersonalFiles,        // Разрешить публиковать ссылку на "Мои файлы на сервере"
       *{83}  QFTPPublicWrite,                         // разрешить писать в общую папку
       *{84}  QFTPPersonalWrite,                       // разрешить писать в личную папку
       *{85}  QAllowSendInvites,                       // разрешить отправлять приглашения в MyChat другим людям
       *{86}  QWEBAllowViewNodeJSLogs,                 // разрешить просмотр логов NodeJS сервера
       *{87}  QWEBAllowViewAuditLogs,                  // разрешить просмотр логов аудита
       *{88}  QAdmAccessServerInfo,                    // админка, "Доступ к функциям управления сервером", "MyChat Server", "Информация о сервере"
       *{89}  QAdmAccessOnlineUsers,                   // админка, "Доступ к функциям управления сервером", "MyChat Server", "Онлайн пользователи"
       *{90}  QAdmAccessUsersList,                     // админка, "Доступ к функциям управления сервером", "Пользователи", "Список пользователей"
       *{91}  QAdmAccessPublicContactsList,            // админка, "Доступ к функциям управления сервером", "Пользователи", "Общий список контактов"
       *{92}  QAdmAccessCompanyPositions,              // админка, "Доступ к функциям управления сервером", "Пользователи", "Должности компании"
       *{93}  QAdmAccessImportUsersFromFile,           // админка, "Доступ к функциям управления сервером", "Пользователи", "Импорт пользователей из файла"
       *{94}  QAdmAccessModerators,                    // админка, "Доступ к функциям управления сервером", "Пользователи", "Модераторы"
       *{95}  QAdmAccessBannedUsers,                   // админка, "Доступ к функциям управления сервером", "Пользователи", "Забаненные пользователи"
       *{96}  QAdmAccessActiveDirectory,               // админка, "Доступ к функциям управления сервером", "Пользователи", "Active Directory"
       *{97}  QAdmAccessAutocreatedConfs,              // админка, "Доступ к функциям управления сервером", "Конференции", "Автосоздаваемые конференции"
       *{98}  QAdmAccessGroupsRights,                  // админка, "Доступ к функциям управления сервером", "Управление правами", "Группы прав"
       *{99}  QAdmAccessGroupsRightsUsers,             // админка, "Доступ к функциям управления сервером", "Управление правами", "Пользователи групп"
       *{100} QAdmAccessMyChatGuest,                   // админка, "Доступ к функциям управления сервером", "Инструменты", "MyChat Guest"
       *{101} QAdmAccessWebSupportOnSite,              // админка, "Доступ к функциям управления сервером", "Инструменты", "Web-поддержка на сайт"
       *{102} QAdmAccessBBS,                           // админка, "Доступ к функциям управления сервером", "Инструменты", "Доска объявлений"
       *{103} QAdmAccessUpdates,                       // админка, "Доступ к функциям управления сервером", "Инструменты", "Обновления"
       *{104} QAdmAccessAntiflood,                     // админка, "Доступ к функциям управления сервером", "Фильтры", "Антифлуд"
       *{105} QAdmAccessIPFilters,                     // админка, "Доступ к функциям управления сервером", "Фильтры", "IP фильтры"
       *{106} QAdmAccessMACFilters,                    // админка, "Доступ к функциям управления сервером", "Фильтры", "MAC фильтры"
       *{107} QAdmAccessBadwords,                      // админка, "Доступ к функциям управления сервером", "Фильтры", "Плохие слова"
       *{108} QAdmAccessNamesBlock,                    // админка, "Доступ к функциям управления сервером", "Фильтры", "Блокировки названий"
       *{109} QAdmAccessOptionsNetwork,                // админка, "Доступ к функциям управления сервером", "Настройки", "Сетевые настройки"
       *{110} QAdmAccessOptionsServerInfo,             // админка, "Доступ к функциям управления сервером", "Настройки", "Информация о сервере"
       *{111} QAdmAccessOptionsLogging,                // админка, "Доступ к функциям управления сервером", "Настройки", "Протоколирование"
       *{112} QAdmAccessOptionsFTP,                    // админка, "Доступ к функциям управления сервером", "Настройки", "FTP файловый сервер"
       *{113} QAdmAccessOptionsWebServices,            // админка, "Доступ к функциям управления сервером", "Настройки", "WEB-сервисы"
       *{114} QAdmAccessOptionsBackups,                // админка, "Доступ к функциям управления сервером", "Настройки", "Резервные копии"
       *{115} QAdmAccessOptionsMaintenance,            // админка, "Доступ к функциям управления сервером", "Настройки", "Обслуживание"
       *{116} QAdmAccessOptionsIntegrationsAPI,        // админка, "Доступ к функциям управления сервером", "Настройки", "Integration API"
       *{117} QAdmAccessOptionsSMTP,                   // админка, "Доступ к функциям управления сервером", "Настройки", "Настройка SMTP"
       *{118} QAdmAccessOptionsAdditional,             // админка, "Доступ к функциям управления сервером", "Настройки", "Дополнительно"
       *{119} QAdmAccessLicensesMyChatServer,          // админка, "Доступ к функциям управления сервером", "Лицензии", "MyChat Server"
       *{120} QAdmAccessLicensesMyChatGuest,           // админка, "Доступ к функциям управления сервером", "Лицензии", "MyChat Guest"
       *{121} QWEBAllowViewWorkTimeLogs,               // разрешить просмотр логов рабочего времени
       *{122} QAdmAccessMSLScripts,                    // админка, "Доступ к функциям управления сервером", "Инструменты", "Скрипты"
       *{123} QAdmProfileAllowChangeRightsGroup,       // админка, профиль пользователя, разрешить изменение группы прав
       *{124} QAdmProfileAllowChangeAutorization,      // админка, профиль пользователя, разрешить изменение типа авторизации
       *{125} QAdmProfileAllowChangePassword,          // админка, профиль пользователя, разрешить изменение пароля пользователя
       *{126} QAdmUsersListAllowAdd,                   // админка, список пользователей, разрешить добавлять новых юзеров
       *{127} QAdmUsersListAllowChange,                // админка, список пользователей, разрешить изменять профили пользователей
       *{128} QAdmUsersListAllowDelete,                // админка, список пользователей, разрешить удалять пользователей
       *{129} QAdmUsersListAllowExport,                // админка, список пользователей, разрешить экспорт пользователей
       *{130} QAdmUsersListAllowMassChange             // админка, список пользователей, разрешить массовое изменение пользователей
       *{131} QAdmUsersRemoteOptionsControl            // админка, пользователи, "Удалённая настройка клиентов"
       *{132} QAdmAccessViewScriptLogs                 // админка, просмотр логов выполнения скриптов
       *{133} QAdmAccessToRestartServices
       *{134} QKanbanAccess,                           // доступ к Kanban доске
       *{135} QAdmActiveConfsAccess                    // доступ к списку активных конференций
       *{136} QAdmPresetsManagerAcess,                 // админка, доступ к менеджеру шаблонов клиентских настроек
       *{137} QAdmNSSForumAccess,                      // админка, доступ к форуму NSS
       *{138} QAdmNSSServiceAccess,                    // админка, доступ к доп.сервисам NSS
       *{139} QAdmUserGroupsAccess,                    // админка, доступ к управлению группами пользователей
       *{140} QAdmIntegrationToolsAccess               // админка, доступ к инструментам интеграции
      */
    ],

    LoginInfo : {
        login   : "",
        pwd     : "",
        servPwd : "",
        rm      : ""
    },

    Auth      : '',
    PWD       : '',
    servPass  : '',

    BrowserID : '',
    SessionID : '',

    LoggedIn  : false,
    nowLogin  : false,

    terminator       : '\u2022',
    terminator2      : '\u0002',
    terminator3      : '\u0003',
    newLine          : '\u000b',

    PingTimer        : null,
    PingInterval     : 10000,

    mcPara           : "L$",

    UserInfo   : {                       // информация о залогиненом юзере
        MaxUploadFileSize : 0,
        "UIN"             : 0,           // UIN пользователя, который залогинен в системе
        "Nick"            : "Anonymous", // ник пользователя, который сообщил ему сервер
        "Sex"             : 1,           // пол пользователя
        "Avatar"          : 0,           // номер аватара пользователя
        "LoginStyle"      : "login",     // тип логина: "login" - обычный логин, "domain" - доменная авторизация
        "AutoAwayTime"    : 15,          // время в минутах, после которого будет считаться, что пользователь неактивен
                                         // за компьютером, если он не нажимал ничего на клавиатуре и не шевелил мышкой
        "ServerSignature" : "",          // специальная сигнатура сервера MyChat, нужна для системы статистики
        "HWID"            : "",          // серийник сервера
        "Domain"          : "domain"     // если доменная авторизация, "LoginStyle" = "domain", то в этом параметре
                                         // передаётся ещё и имя домена, с которого проходит аторизация.
                                         // Если доменной авторизации нет - этот параметр не передаётся
    },

    ErrorText  : {},
    SrvErrorText: {},

    CanDisplayNotificator : false,
    NotificatorObject     : null,

    ExtendedMode           : true,
    CanChangToExtendedMode : true,
    WidthForExtendedMode   : 800,

    oneDay : 1000*60*60*24,
    oneHour: 1000*60*60,

    navWidth : 280,

    isShowed : null,
    nextShow : '',

    scrResize : null,
    navResize : null,

    adAttributesList: [
        "accountExpires",
        "adminDescription",
        "adminDisplayName",
        "ADsPath",
        "altRecipient",
        "altRecipientBL",
        "authOrig",
        "authOrigBL",
        "autoReplyMessage",
        "badPasswordTime",
        "badPwdCount",
        "c",
        "canonicalName",
        "Class",
        "co",
        "comment",
        "company",
        "Control-Computed",
        "countryCode",
        "createTimeStamp",
        "deletedItemFlags",
        "delivContLength",
        "deliverAndRedirect",
        "department",
        "departmentNumber",
        "description",
        "directReports",
        "displayName",
        "displayNamePrintable",
        "distinguishedName",
        "division",
        "dLMemRejectPerms",
        "dLMemRejectPermsBL",
        "dLMemSubmitPerms",
        "dLMemSubmitPermsBL",
        "employeeID",
        "employeeNumber",
        "employeeType",
        "extensionData",
        "extensionAttribute1",
        "facsimileTelephoneNumber",
        "garbageCollPeriod",
        "givenName",
        "homeDirectory",
        "homeDrive",
        "homeMDB",
        "homeMTA",
        "homePhone",
        "info",
        "initials",
        "ipPhone",
        "isDeleted",
        "isRecycled",
        "l",
        "lastKnownParent",
        "lastLogoff",
        "lastLogon",
        "lastLogonTimestamp",
        "legacyExchangeDN",
        "lockoutTime",
        "logonCount",
        "logonHours",
        "mail",
        "mailNickname",
        "manager",
        "mDBOverHardQuotaLimit",
        "mDBOverQuotaLimit",
        "mDBStorageQuota",
        "mDBUseDefaults",
        "memberOf",
        "mobile",
        "modifyTimeStamp",
        "msCOM-UserPartitionSetLink",
        "msDS-User-Account-",
        "msExchUserAccountControl",
        "msNPAllowDialin",
        "msNPCallingStationID",
        "msNPSavedCallingStationID",
        "msRADIUSCallbackNumber",
        "msRADIUSFramedIPAddress",
        "msRADIUSFramedRoute",
        "msRADIUSServiceType",
        "msRASSavedCallbackNumber",
        "msRASSavedFramedIPAddress",
        "msRASSavedFramedRoute",
        "msSFU30GidNumber",
        "msSFU30HomeDirectory",
        "msSFU30LoginShell",
        "msSFU30Name",
        "msSFU30NisDomain",
        "msSFU30Password",
        "msSFU30UidNumber",
        "name",
        "nTSecurityDescriptor",
        "objectCategory",
        "objectClass",
        "objectGUID",
        "objectSid",
        "otherFacsimileTelephoneNumber",
        "otherHomePhone",
        "otherIpPhone",
        "otherMobile",
        "otherPager",
        "otherTelephone",
        "pager",
        "Parent",
        "physicalDeliveryOfficeName",
        "postalCode",
        "postOfficeBox",
        "primaryGroupID",
        "profilePath",
        "protocolSettings",
        "proxyAddresses",
        "publicDelegates",
        "publicDelegatesBL",
        "pwdLastSet",
        "sAMAccountName",
        "scriptPath",
        "seeAlso",
        "securityProtocol",
        "sIDHistory",
        "sn",
        "st",
        "streetAddress",
        "submissionContLength",
        "telephoneNumber",
        "textEncodedORAddress",
        "title",
        "unauthOrig",
        "unauthOrigBL",
        "url",
        "userAccountControl",
        "userCertificate",
        "userParameters",
        "userPrincipalName",
        "userWorkstations",
        "uSNChanged",
        "uSNCreated",
        "whenChanged",
        "whenCreated",
        "wWWHomePage"
    ],

    keyCodes : {
        // Alphabet
        a:65, b:66, c:67, d:68, e:69,
        f:70, g:71, h:72, i:73, j:74,
        k:75, l:76, m:77, n:78, o:79,
        p:80, q:81, r:82, s:83, t:84,
        u:85, v:86, w:87, x:88, y:89,
        z:90,

        // Numbers
        n0:48, n1:49, n2:50, n3:51, n4:52,
        n5:53, n6:54, n7:55, n8:56, n9:57,

        // Controls
        tab:  9, enter :13,  shift :16, backspace:8,
        ctrl:17, alt   :18,  esc   :27, space    :32,
        menu:93, pause :19,  cmd   :91, insert   :45,
        home:36, pageup:33,'delete':46, end      :35,
        pagedown:34,

        // F*
        f1:112, f2:113, f3:114, f4 :115, f5 :116, f6 :117,
        f7:118, f8:119, f9:120, f10:121, f11:122, f12:123,

        // numpad
        np0: 96, np1: 97, np2: 98, np3: 99, np4:100,
        np5:101, np6:102, np7:103, np8:104, np9:105,

        npslash:11,npstar:106,nphyphen:109,npplus:107,npdot:110,

        // Lock
        capslock:20, numlock:144, scrolllock:145,

        // Symbols
        equals: 61, hyphen   :109, coma  :188, dot:190,
        gravis:192, backslash:220, sbopen:219, sbclose:221,
        slash :191, semicolon: 59, apostrophe : 222,

        // Arrows
        aleft:37, aup:  38, aright:39, adown:40,

        PrintSymbols :
            [32, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65,
             66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
             77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
             88, 89, 90, 96, 97, 98, 99, 100,101,102,103,
             105,106,107,109,110,111,186,187,188,189,190,
             104,191,192,219,220,221,222],

        EditSymbols  : [8,  32, 46],

        Digits :
            [48, 49, 50, 51,  52, 53, 54, 55, 56, 57,
             96, 97, 98, 99, 100,101,102,103,104,105],

        ControlFunc	 :
            [ 33, 34, 35, 36, 37, 38, 39, 40,112,113,
             114,115,116,117,118,119,120,121,122,123],

        ControlsKeys : [36, 33, 35, 34, 37, 38, 39, 40],

        PrintAndEdit : function(){
            return mcConst.keyCodes.PrintSymbols.concat(mcConst.keyCodes.EditSymbols);
        }
    },

    ServerInfo: {
        Host: window.location.host,
        Port: 2004,
        ID  : null
    },

    msgTypes: {
        section : 1,
        topic   : 2,
        post    : 3
    },

    KanbanEvents: {
        TASK_ADDED             : 1,
        TASK_PERFORMER_CHANGED : 2,
        COMMENT_ADDED          : 3,
        TASK_MOVED             : 4,
        TASK_CHANGED           : 5,
        TASK_DELETED           : 6,
        PROJECT_CLOSED         : 7
    },

    ForumNotify: {
        POST_CREATED : 1,
        POST_CHANGED : 2
    },


};
function mcCmdParser (mcConnect, $rootScope){
    "use strict";

    var SendCMDToServer = {};
    var ProcessCMD      = {};
    var pCmd = {};

    this.ProcessCMD = ProcessCMD;
    this.SendCMDToServer = SendCMDToServer;

    $rootScope.ErrorActions     = {};

    var _CMD_     = mcConst._CMD_;

    // ====================================================================================

    function customCallBack (cmd, data){
        if ($rootScope.customCallBack[cmd] && $rootScope.customCallBack[cmd].length > 0){
            var cb = $rootScope.customCallBack[cmd].shift();

            if ($rootScope.customCallBack[cmd].length == 0){
                delete $rootScope.customCallBack[cmd];
            }

            setTimeout(function () {
                cb(data);
            },1);

            return true;
        }
    }

    /**
     * @return {boolean}
     */
    this.MultiSender = function(){
        var cmd  = arguments[0];
        var sID  = arguments[1];
        var next = true;

        if (!SendCMDToServer[cmd] && mcService.InObject(cmd, _CMD_)){
            var data = "";

            for (var i = 1; i < arguments.length; i++){
                data += arguments[i] + ((i !== arguments.length)?  mcConst.CR : "");
            }

            //console.log('Sending CMD: ' + cmd);

            mcConnect.SendDataToServer({
                CMD  : cmd,
                Data : data
            });

            sendPing(sID);

            next = false;
        }

        return next;
    };

    /**
     * @return {boolean}
     */
    this.MultiParser = function (cmd, data) {
        if (!pCmd.hasOwnProperty(cmd)){
            return true;
        }

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        customCallBack(pCmd[cmd], mcService.StringToObj(data));
    };

    function criticalError (err){
        return ((mcService.inArray(err, [3, 4, 14, 15, 17, 23, 24, 44, 60, 71, 79, 80, 81, 82, 92, 177]) != -1) && mcConst.LoggedIn) || !mcConst.LoggedIn;
    }

    function runError(numb, params){
        if ($rootScope.ErrorActions[numb]){
            $rootScope.ErrorActions[numb](params);
        } else {
            return false;
        }
    }

    function closeSocketIO() {
        if (mcConst.socketIO){
            mcConst.socketIO.disconnect();
            mcConst.socketIO = null;
        }
    }

    function initSocketIo() {
        if (window.hasOwnProperty("io") && mcService.isFunction(window.io) && !mcConst.socketIO){
            mcConst.socketIO = io({
                transports: mcConst.io_transport,
                'reconnection': true,
                'reconnectionAttempts': 5,
                'timeout' : 20000
            });

            mcConst.initWS(mcConst.socketIO);
        }
    }

    pCmd[_CMD_.sc_adm_user_created]                    = _CMD_.cs_adm_create_user;
    pCmd[_CMD_.sc_adm_user_info_by_preset]             = _CMD_.cs_adm_get_user_info_by_preset;
    pCmd[_CMD_.sc_adm_get_user_profile]                = _CMD_.cs_adm_get_user_profile;
    pCmd[_CMD_.sc_adm_websupport_groups]               = _CMD_.cs_adm_get_websupport_groups;
    pCmd[_CMD_.sc_adm_job_positions_added]             = _CMD_.cs_adm_job_positions_add;
    pCmd[_CMD_.sc_adm_job_positions_modified]          = _CMD_.cs_adm_job_positions_modify;
    pCmd[_CMD_.sc_adm_role_users_list]                 = _CMD_.cs_adm_role_users_list;
    pCmd[_CMD_.sc_adm_smtp_checked]                    = _CMD_.cs_adm_check_smtp;
    pCmd[_CMD_.sc_adm_custom_options]                  = _CMD_.cs_adm_get_custom_options;
    pCmd[_CMD_.sc_adm_server_licenses]                 = _CMD_.cs_adm_get_licenses;
    pCmd[_CMD_.sc_adm_antiflood_filter_data]           = _CMD_.cs_adm_get_antiflood_filter_data;
    pCmd[_CMD_.sc_adm_flood_except_users_list]         = _CMD_.cs_adm_get_flood_except_users_list;
    pCmd[_CMD_.sc_adm_allow_ip_list]                   = _CMD_.cs_adm_get_allow_ip_list;
    pCmd[_CMD_.sc_adm_blocked_ip_list]                 = _CMD_.cs_adm_get_blocked_ip_list;
    pCmd[_CMD_.sc_adm_blocked_mac_list]                = _CMD_.cs_adm_get_blocked_mac_list;
    pCmd[_CMD_.sc_adm_blocked_nicks_list]              = _CMD_.cs_adm_get_deny_nicks_list;
    pCmd[_CMD_.sc_adm_blocked_confs_list]              = _CMD_.cs_adm_get_deny_conf_list;
    pCmd[_CMD_.sc_adm_bad_words_filter_data]           = _CMD_.cs_adm_get_bad_words_filters_data;
    pCmd[_CMD_.sc_adm_bad_words_list]                  = _CMD_.cs_adm_get_bad_words_list;
    pCmd[_CMD_.sc_adm_bad_words_except_confs]          = _CMD_.cs_adm_load_badwords_except_confs;
    pCmd[_CMD_.sc_adm_export_users_to_csv_file]        = _CMD_.cs_adm_export_users_to_csv;
    pCmd[_CMD_.sc_adm_get_job_positions_list]          = _CMD_.cs_adm_get_job_positions_list;
    pCmd[_CMD_.sc_adm_tcl_users_added]                 = _CMD_.cs_adm_tcl_add_users_list_to_group;
    pCmd[_CMD_.sc_dept_list]                           = _CMD_.cs_get_depts_list;
    pCmd[_CMD_.sc_adm_all_text_confs]                  = _CMD_.cs_adm_get_all_text_confs;
    pCmd[_CMD_.sc_adm_total_contacts_list]             = _CMD_.cs_adm_get_total_contacts_list;
    pCmd[_CMD_.sc_adm_server_options]                  = _CMD_.cs_adm_get_server_options;
    pCmd[_CMD_.sc_adm_get_server_info]                 = _CMD_.cs_adm_get_server_info;
    pCmd[_CMD_.sc_adm_server_net_interfaces]           = _CMD_.cs_adm_get_server_net_interfaces;
    pCmd[_CMD_.sc_adm_list_users]                      = _CMD_.cs_adm_list_users;
    pCmd[_CMD_.sc_web_user_foto_file]                  = _CMD_.cs_web_get_user_foto_file;
    pCmd[_CMD_.sc_adm_bans_list]                       = _CMD_.cs_adm_get_bans_list;
    pCmd[_CMD_.sc_adm_moderators_list]                 = _CMD_.cs_adm_get_moderators;
    pCmd[_CMD_.sc_adm_conf_names_list_by_uid]          = _CMD_.cs_adm_get_conf_names_by_uid_list;
    pCmd[_CMD_.sc_adm_list_roles]                      = _CMD_.cs_adm_list_roles;
    pCmd[_CMD_.sc_adm_auto_conf_created]               = _CMD_.cs_adm_add_auto_conf;
    pCmd[_CMD_.sc_adm_bbs_msg_list]                    = _CMD_.cs_adm_get_bbs_msg_list;
    pCmd[_CMD_.sc_adm_ad_options]                      = _CMD_.cs_adm_get_ad_options;
    pCmd[_CMD_.sc_adm_ad_users_imported]               = _CMD_.cs_adm_import_ad_users;
    // pCmd[_CMD_.sc_adm_update_packet_data]              = _CMD_.cs_adm_get_update_packet_data;
    pCmd[_CMD_.sc_adm_online_users_list]               = _CMD_.cs_adm_get_online_users_list;
    pCmd[_CMD_.sc_adm_script_data]                     = _CMD_.cs_adm_get_script;
    pCmd[_CMD_.sc_adm_all_script_states]               = _CMD_.cs_adm_get_script_event_states;
    pCmd[_CMD_.sc_adm_script_checked]                  = _CMD_.cs_adm_script_check_syntax;
    pCmd[_CMD_.sc_adm_script_executed]                 = _CMD_.cs_adm_script_run;
    pCmd[_CMD_.sc_adm_script_created]                  = _CMD_.cs_adm_script_create;
    pCmd[_CMD_.sc_adm_script_saved]                    = _CMD_.cs_adm_script_save;
    pCmd[_CMD_.sc_adm_script_deleted]                  = _CMD_.cs_adm_script_delete;
    pCmd[_CMD_.sc_adm_active_conf_list]                = _CMD_.cs_adm_get_active_conf_list;
    pCmd[_CMD_.sc_adm_conf_users_list]                 = _CMD_.cs_adm_get_users_in_conf;
    pCmd[_CMD_.sc_adm_client_options_presets_list]     = _CMD_.cs_adm_get_client_options_presets;
    pCmd[_CMD_.sc_adm_client_options_preset_created]   = _CMD_.cs_adm_create_client_options_preset;
    pCmd[_CMD_.sc_adm_client_options_preset_updated]   = _CMD_.cs_adm_update_client_options_preset;
    pCmd[_CMD_.sc_adm_users_groups_list]               = _CMD_.cs_adm_get_user_groups;
    pCmd[_CMD_.sc_adm_group_users_list]                = _CMD_.cs_adm_get_group_users_list;
    pCmd[_CMD_.sc_adm_new_user_group_created]          = _CMD_.cs_adm_add_new_user_group;
    pCmd[_CMD_.sc_adm_integration_tool_options]        = _CMD_.cs_adm_get_integration_tool_options;
    pCmd[_CMD_.sc_adm_get_check_domains_list]          = _CMD_.cs_adm_get_check_domains_list;
    pCmd[_CMD_.sc_adm_allowed_and_blocked_plugins]     = _CMD_.cs_adm_get_allowed_and_blocked_plugins;
    pCmd[_CMD_.sc_adm_script_info]                     = _CMD_.cs_adm_get_script_info;
    pCmd[_CMD_.sc_personal_options_list]               = _CMD_.cs_kanban_get_personal_options;
    pCmd[_CMD_.sc_book_data]                           = _CMD_.cs_get_book;
    pCmd[_CMD_.sc_adm_backup_server_db_ok]             = _CMD_.cs_adm_make_backup_server_db;
    pCmd[_CMD_.sc_adm_integration_telegram_users_list] = _CMD_.cs_adm_get_integration_telegram_users;
    pCmd[_CMD_.sc_adm_history_info_private]            = _CMD_.cs_adm_get_history_info_private;
    pCmd[_CMD_.sc_adm_history_private]                 = _CMD_.cs_adm_get_history_private;
    pCmd[_CMD_.sc_adm_history_info_conf]               = _CMD_.cs_adm_get_history_info_conf;
    pCmd[_CMD_.sc_adm_history_conf]                    = _CMD_.cs_adm_get_history_conf;
    pCmd[_CMD_.sc_adm_history_private_user_pairs]      = _CMD_.cs_adm_get_history_private_user_pairs;
    pCmd[_CMD_.sc_file_exists]                         = _CMD_.cs_is_file_exists;
    pCmd[_CMD_.sc_image_thumbs]                        = _CMD_.cs_get_image_thumbs;
    pCmd[_CMD_.sc_adm_blocked_hwid_list]               = _CMD_.cs_adm_get_blocked_hwid_list;
    pCmd[_CMD_.sc_adm_system_logs]                     = _CMD_.cs_adm_get_system_logs;
    pCmd[_CMD_.sc_adm_domains_list]                    = _CMD_.cs_adm_get_domains_list;
    pCmd[_CMD_.sc_forum_structure]                     = _CMD_.cs_forum_get_structure;
    pCmd[_CMD_.sc_adm_forum_subs_groups_list]          = _CMD_.cs_adm_forum_get_subs_groups;
    pCmd[_CMD_.sc_adm_forum_subs_users_list]           = _CMD_.cs_adm_forum_get_subs_users;
    pCmd[_CMD_.sc_adm_integration_quiz_check_question] = _CMD_.cs_adm_integration_quiz_check_question;
    pCmd[_CMD_.sc_adm_integration_quiz_stat]           = _CMD_.cs_adm_integration_quiz_get_stat;
    pCmd[_CMD_.sc_adm_terminal_command_result]         = _CMD_.cs_adm_terminal_command;
    pCmd[_CMD_.sc_cids_killed]                         = _CMD_.cs_kill_cid;
    pCmd[_CMD_.sc_cids_halted]                         = _CMD_.cs_halt_cid;
    pCmd[_CMD_.AdsFiles]                               = _CMD_.AdsFiles;
    pCmd[_CMD_.checkSSL]                               = _CMD_.checkSSL;
    pCmd[_CMD_.generateCert]                           = _CMD_.generateCert;
    pCmd[_CMD_.checkPush]                              = _CMD_.checkPush;

    pCmd[_CMD_.getUrl]                                 = _CMD_.getUrl;

    pCmd[_CMD_.sc_adm_integration_turbosms_balance]    = _CMD_.cs_adm_integration_turbosms_check_balance;
    pCmd[_CMD_.sc_adm_integration_turbosms_send_message] = _CMD_.cs_adm_integration_turbosms_send_message;
    pCmd[_CMD_.sc_personal_users_groups_list]          = _CMD_.cs_adm_get_personal_user_groups;
    pCmd[_CMD_.sc_adm_new_personal_user_group_created] = _CMD_.cs_adm_create_personal_user_group;
    pCmd[_CMD_.sc_adm_personal_group_users_list]       = _CMD_.cs_adm_get_personal_group_users_list;
    pCmd[_CMD_.sc_all_user_group_membership_list]      = _CMD_.cs_adm_get_all_user_group_membership_list;
    pCmd[_CMD_.sc_users_fired]                         = _CMD_.cs_adm_fire_users;
    pCmd[_CMD_.sc_adm_custom_menu_list]                = _CMD_.cs_adm_get_custom_menu_list;
    pCmd[_CMD_.sc_adm_custom_menu_created]             = _CMD_.cs_adm_custom_menu_create;
    pCmd[_CMD_.sc_adm_check_user_pwd_state]            = _CMD_.cs_adm_check_user_pwd;

    pCmd[_CMD_.sc_users_changeid_data     ]            = _CMD_.cs_get_users_changeid_data;
    pCmd[_CMD_.sc_adm_user_conf_list     ]             = _CMD_.cs_adm_get_user_conf_list;
    pCmd[_CMD_.sc_badword_list_uploaded  ]             = _CMD_.cs_adm_upload_badword_list;

    // ====================================================================================

    ProcessCMD[_CMD_.sc_login] = function sc_login(_data) {
        mcService.Marge(mcConst.UserInfo, _data || {
            "UIN"             : 17,        // UIN пользователя, который залогинен в системе
            "Nick"            : "Chapay",  // ник пользователя, который сообщил ему сервер
            "Sex"             : 1,         // пол пользователя
            "Avatar"          : 54,        // номер аватара пользователя
            "LoginStyle"      : "login",   // тип логина: "login" - обычный логин, "domain" - доменная авторизация
            "AutoAwayTime"    : 15,        // время в минутах, после которого будет считаться, что пользователь неактивен за компьютером, если он не нажимал ничего на клавиатуре и не шевелил мышкой
            "ServerSignature" : "MyChat4/16....", // специальная сигнатура сервера MyChat, нужна для системы статистики

            "Domain"          : "" // если доменная авторизация, "LoginStyle" = "domain", то в этом параметре передаётся ещё и имя домена, с которого проходит аторизация.
                                             // Если доменной авторизации нет - этот параметр не передаётся
        });

        mcConst.UserInfo.MaxUploadFileSize = mcConst.UserInfo.MaxUploadFileSize * 1024 * 1024;

        mcConst.LoggedIn = true;

        if (!mcConst.LoginInfo.login) {
            mcConst.LoginInfo.login = _data.InternalNick;
        }

        mcService.SaveSessionSettings(mcConst.LoginInfo);

        if (!mcConst.customLogin) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_server_net_interfaces,
                mcConst.SessionID,
                function (data) {
                    $rootScope.mcStorage.networkInterfaces = data;
                }
            ]);

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_server_info,
                mcConst.SessionID,
                function( data ){
                    $rootScope.mcStorage.ServerInfo = data;
                }
            ]);

            console.log('Logged in!');
        } else {
            $rootScope.mcStorage[mcConst.dataModels.Login] = mcConst.LoginInfo;
        }
    };

    ProcessCMD[_CMD_.sc_error] = function sc_error(_data){
        var err = mcService.StringToObj(_data) || {
            "ErrNum" : 21,        // номер ошибки
            "Params" : [          // параметры ошибки, если есть, параметров может быть любое количество, все - текстовые строки
                "bla-bla-bla",
                "test-test-test"
            ]
        };

        console.error(err);

        if (criticalError(err.ErrNum)){
            $rootScope.$broadcast('StopPingTimer', []);

            closeSocketIO();
        }

        if (!mcConst.LoggedIn && $rootScope.loginFormNotShowed) {
            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

            runError(err.ErrNum, err.Params);
        } else {
            $rootScope.$broadcast('ErrorMsg', [err.ErrNum, mcConst.ErrorText[err.ErrNum], err.Params, function(){
                if (!mcConst.LoggedIn){
                    $rootScope.$broadcast('enable' + mcConst.dataModels.Login, []);
                } else
                if (criticalError(err.ErrNum)){
                    mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", "");

                    mcService.reloadOrChangeProtocol();
                }

                $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

                runError(err.ErrNum, err.Params);
            }]);
        }
    };

    ProcessCMD[_CMD_.sc_halt] = function(){
        if (mcConst.LoggedIn || mcConst.PingTimer) {
            $rootScope.$broadcast('StopPingTimer' ,[]);

            closeSocketIO();

            $rootScope.$broadcast('ErrorMsg', ['223', mcConst.ErrorText['223'], '', function(){
                mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", "");

                mcService.reloadOrChangeProtocol();
            }]);
        }
    };

    ProcessCMD[_CMD_.sc_login_finish] = function(){
        // console.log('Login finish');
    };

    ProcessCMD[_CMD_.encode_qrcode] = function(info){
        customCallBack(_CMD_.encode_qrcode, info);
    };

    ProcessCMD[_CMD_.sc_get_all_rights] = function sc_get_all_rights(_data){
        mcConst.MyRightsSet = _data;

        if (mcService.checkRights(mcConst._CMD_.RS.QWEBAllowAdmin)){
            $rootScope.$broadcast('hideLogin', []);
            $rootScope.$broadcast('show' + mcConst.dataModels.NavPanel, []);
            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

            $rootScope.$broadcast('changeLocation', []);

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_get_licenses,
                mcConst.SessionID,

                function (data){
                    if (_gLock.License) data.ServerLicenseKey = "";

                    var delta = moment(new Date(mcService.formatDate(data.ServerUpdatesEndDate, "yyyy mm dd"))).startOf('day').diff(moment(new Date()).startOf('day'), 'days');

                    if (!data.IsFree && delta <= 30){
                        $rootScope.$broadcast('licenseExpired', [data]);
                        mcConst.ServerLicenseKey = data.ServerLicenseKey;
                    }

                    if (!data.IsFree && delta <= 0){
                        webix.ui({
                            view    : "window",
                            position: "center",
                            modal   : true,
                            width   : 400,
                            height  : 135,
                            head    : mcLang(1004), // "1004":"Внимание!",
                            padding : 10,
                            body    : { rows: [
                                { template: mcLang(2080), borderless: true, css: "expiredMessage"},             // "2080":"Закончился срок обновлений и поддержки. Пожалуйста, приобретите подписку на обновления",
                                { id: "countDownModal", view: "button", value: mcLang(12) + " 10", disabled: true, click: function(){  // "12" : "Закрыть",
                                    this.getTopParentView().hide();
                                    this.getTopParentView().destructor();
                                }}
                            ]},
                            on: {
                                onShow: function () {
                                    var i = 10;
                                    var countDownModal = $$("countDownModal");

                                    var intervalTimer = setInterval(function () {
                                        countDownModal.setValue(mcLang(12) + " " + --i);
                                        countDownModal.refresh();

                                        if (i === 0) {
                                            clearInterval(intervalTimer);

                                            countDownModal.setValue(mcLang(12));
                                            countDownModal.refresh();
                                            countDownModal.enable();
                                        }
                                    }, 1000);
                                }
                            }
                        }).show();
                    }
                }
            ]);
        }
    };

    ProcessCMD[_CMD_.sc_drop_connect] = function sc_drop_connect(){
        closeSocketIO();

        if (!mcConst.LoggedIn && mcConst.PingTimer){
            mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", false);

            $rootScope.$broadcast('StopPingTimer' ,[]);

            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

            mcConst.LoginInfo.pwd     = "";
            mcConst.LoginInfo.servPwd = "";
            mcConst.LoginInfo.rm      = false;

            $rootScope.$broadcast('show' + mcConst.dataModels.Login, [mcConst.Lang]);
        } else
        if (mcConst.LoggedIn || mcConst.PingTimer) {
            $rootScope.$broadcast('StopPingTimer' ,[]);

            $rootScope.$broadcast('ErrorMsg', ['223', mcConst.ErrorText['223'], '', function(){
                mcService.reloadOrChangeProtocol();
            }]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_command_complete ] = function sc_adm_command_complete(data){
        var info = mcService.StringToObj(data);

        switch (info.Cmd){
            case _CMD_.cs_adm_set_user_foto:
                $rootScope.$broadcast('profileFotoRefresh');
            break;

//          cs_adm_remove_all_logs:
//          cs_adm_job_positions_del:
//          cs_adm_job_positions_set_sequence:
//          cs_adm_role_delete:
//          cs_adm_delete_websupport_group:
//          cs_adm_remove_user:
//          cs_adm_del_bans:
//          cs_adm_delete_moderators:
//          cs_adm_add_moderator:
//          cs_adm_del_moderator_confs
//          cs_adm_kill_users
//          cs_adm_halt_users
//          cs_adm_script_onoff
//          cs_adm_kill_txt_conf
//          cs_adm_del_client_options_preset
//          cs_adm_apply_roles_to_options_presets
//          cs_adm_remove_users_from_group
//          cs_adm_rename_group_of_users
//          cs_adm_delete_groups_list
//          cs_adm_del_auto_conf
//          cs_adm_set_integration_tool_options
//          cs_adm_add_check_domain
//          cs_adm_delete_check_domain
//          cs_adm_add_allowed_or_blocked_plugins
//          cs_adm_delete_allowed_or_blocked_plugin
//          cs_adm_change_mychat_server

            default:
                customCallBack(info.Cmd);

                $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
        }
    };

    ProcessCMD[_CMD_.sc_adm_role_added] = function(data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        $rootScope.$broadcast('refresh' + mcConst.dataModels.GroupRights, ['add', info]);
    };

    ProcessCMD[_CMD_.sc_adm_role_modified] = function(data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
        $rootScope.$broadcast('refresh' + mcConst.dataModels.GroupRights, ['modify', info]);
    };

    ProcessCMD[_CMD_.sc_adm_websupport_group_users] = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
        $rootScope.$broadcast('refresh' + mcConst.dataModels.WebSupport, ['refreshList', info.Users]);
    };

    ProcessCMD[_CMD_.sc_adm_websupport_group_added] = function(data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
        $rootScope.$broadcast('refresh' + mcConst.dataModels.WebSupport, ['add', info]);
    };

    ProcessCMD[_CMD_.sc_adm_websupport_group_renamed] = function(data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
        $rootScope.$broadcast('refresh' + mcConst.dataModels.WebSupport, ['modify', info]);
    };

    ProcessCMD[_CMD_.sc_adm_tcl_group_added] = function(data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        $rootScope.$broadcast('refresh' + mcConst.dataModels.Contacts, ['addGroup', info]);
    };

    ProcessCMD[_CMD_.sc_adm_users_imported] = function(data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        $rootScope.$broadcast('refresh' + mcConst.dataModels.UsersImports, ['CSVcomplete', info]);
    };

    ProcessCMD[_CMD_.Logs] = function(data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        $rootScope.$broadcast('LogsChunk', [info]); // unlock
    };

    ProcessCMD[_CMD_.sc_adm_auto_conf_list]    = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        if (!customCallBack(_CMD_.cs_adm_get_auto_conf_list, info)) {
            $rootScope.$broadcast('listAutoCreateChannels', [info]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_bbs_msg_data]    = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        if (!customCallBack(_CMD_.cs_adm_bbs_get_msg, info)) {
            $rootScope.$broadcast('bbsInfoDetail', [info]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_ad_users_list]    = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        if (!customCallBack(_CMD_.cs_adm_get_ad_users_list, info)) {
            //$rootScope.$broadcast('bbsInfoDetail', [info]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_update_packet_data]    = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        if (!customCallBack(_CMD_.cs_adm_get_update_packet_data, info)) {
            $rootScope.$broadcast('on_sc_adm_update_packet_data', [info]);
        }
    };

    ProcessCMD[_CMD_.adm_ldap_user_info]    = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        if (!customCallBack(_CMD_.adm_ldap_get_user_info, info)) {
            //$rootScope.$broadcast('bbsInfoDetail', [info]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_script_log]    = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('scriptConsoleLog', [info]); // unlock
    };

    ProcessCMD[_CMD_.sc_adm_script_log_clear]    = function (){
        $rootScope.$broadcast('scriptConsoleLog', ['clear']);
    };

    ProcessCMD[_CMD_.sc_adm_clear_console]    = function (){
        $rootScope.$broadcast('scriptClearConsoleLog');
    };

    ProcessCMD[_CMD_.sc_adm_integration_telegram_user_added]    = function (data){
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('telegram_user_added', [info]);
    };

    ProcessCMD[_CMD_.sc_adm_integration_quiz_question_added]    = function (){
        $rootScope.$broadcast('quiz_question_added');
    };

    ProcessCMD[_CMD_.sc_web_services_info]  = function (data) {
        // "AliasAdmin" : "admin", // папка-псевдоним, путь к админке
        // "AliasAPI" : "API", // папка-псевдоним, путь к Integration API
        // "AliasChat" : "chat", // папка-псевдоним, путь к WEB-чату
        // "AliasFiles" : "files", // папка-псевдоним, путь к файлам, залитым на сервер
        // "AliasForum" : "forum", // папка-псевдоним, путь ко встроенному форуму
        // "AliasKanban" : "kanban", // папка-псевдоним, путь к канбан-доске
        //
        // "LobbyEnable" : true, // включен доступ к списку сервисов MyChat
        // "ForumEnable" : true, // включить доступ ко встроенному форуму
        // "KanbanEnable" : true, // включить доступ к канбан-доске
        // "ChatEnable" : true // включить доступ к WEB-чату
        // "AdminEnable" : true // включить доступ к WEB-админке

        mcConst.pathAliases = mcService.StringToObj(data);
    };

    ProcessCMD[_CMD_.sc_adm_allow_ip_added]  = function (data) {
        var info = mcService.StringToObj(data);

        if (!customCallBack(_CMD_.cs_adm_add_new_ip_to_allow_list, info)) {
        }
    };

    ProcessCMD[_CMD_.sc_adm_blocked_ip_added]  = function (data) {
        var info = mcService.StringToObj(data);

        if (!customCallBack(_CMD_.cs_adm_add_ip_to_block_list, info)) {
        }
    };

    ProcessCMD[_CMD_.sc_adm_asterisk_log]  = function (data) {
        var info = mcService.StringToObj(data);

        if (!customCallBack(_CMD_.cs_adm_asterisk_send_command, info)) {
            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
            $rootScope.$broadcast('asterisk_commands_log', [info]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_integration_turbosms_ping]  = function (data) {
        var info = mcService.StringToObj(data);

        if (!customCallBack(_CMD_.cs_adm_asterisk_send_command, info)) {
            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
            $rootScope.$broadcast('turbosms_commands_log', [info]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_integration_turbosms_balance]  = function (data) {
        var info = mcService.StringToObj(data);

        if (!customCallBack(_CMD_.cs_adm_asterisk_send_command, info)) {
            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
            $rootScope.$broadcast('turbosms_commands_log', [info]);
        }
    };

    ProcessCMD[_CMD_.sc_adm_ad_users_photos]  = function (data) {
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('ad_users_photos_ready', [info]);
    };

    ProcessCMD[_CMD_.sc_adm_ad_user_photo_thumb]  = function (data) {
        var info = mcService.StringToObj(data);

        $rootScope.$broadcast('ad_user_thumb', [info]);
    };

    // ProcessCMD[_CMD_.sc_adm_total_contacts_list]  = function (data) {
    //     var info = mcService.StringToObj(data);
    //
    //     if (!customCallBack(_CMD_.cs_adm_get_total_contacts_list, info)) {
    //     }
    // };

    // ==================================================================================

    SendCMDToServer[_CMD_.Login] = function CS_CMD_Login(_Auth, _PWD, _servPWD, _RM) {
        mcConst.LoginInfo.login = _Auth.replace('\\', "/");

        // mcConst.socketIO = io({
        //     'reconnection': true,
        //     'reconnectionAttempts': 2,
        //     'timeout' : 2000
        // });

        //mcConst.initWS(mcConst.socketIO);

        initSocketIo();

        mcConnect.SetCallBackFunctionByCMD(_CMD_.OK, function () {
            var data = this.split(mcConst.CR);

            mcConst.SessionID = data[0];

            //console.log('SessionID: ' + mcConst.SessionID);

            if (data.length > 1) {
                mcConst.LoginInfo.pwd     = data[1];
                mcConst.LoginInfo.servPwd = data[2];
            }

            $rootScope.$broadcast('StartPingTimer', []);
        });

        mcConnect.SetCallBackFunctionByCMD(_CMD_.Blocked, function () {
            var errCode = this;

            mcService.SaveSessionSettings("", "", "", false);

            $rootScope.$broadcast('enable' + mcConst.dataModels.Login, []);
            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

            $rootScope.$broadcast('ErrorMsg', [errCode, mcConst.ErrorText[errCode]]);
        });

        mcConnect.SendDataToServer({
            CMD: _CMD_.Login,
            Data: {
                UIN       : mcConst.LoginInfo.login,
                Pass      : _PWD,
                ServPass  : _servPWD,
                RM        : _RM,
                ClientType: 'admin',
                PingDelay : 1,
                UserAgent : navigator.userAgent || " ",
                Referral  : document.referrer || " ",
                Style     : mcConst.LoginInfo.login.indexOf('/') == -1 ? 0 : 1,
                State     : mcConst.currentState,
                UTC       : (new Date()).getTimezoneOffset() / -60
            }
        });
    };

    SendCMDToServer[_CMD_.cs_login_by_token] = function cs_login_by_token(token) {
        // mcConst.socketIO = io({
        //     'reconnection': true,
        //     'reconnectionAttempts': 2,
        //     'timeout' : 2000
        // });
        //
        // mcConst.initWS(mcConst.socketIO);

        initSocketIo();

        mcConnect.SetCallBackFunctionByCMD(_CMD_.OK, function () {
            var data = this.split(mcConst.CR);

            mcConst.SessionID = data[0];

            $rootScope.$broadcast('StartPingTimer', []);
        });

        mcConnect.SetCallBackFunctionByCMD(_CMD_.Blocked, function () {
            var errCode = this;

            mcService.SaveSessionSettings("", "", "", false);

            $rootScope.$broadcast('enable' + mcConst.dataModels.Login, []);
            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

            $rootScope.$broadcast('ErrorMsg', [errCode, mcConst.ErrorText[errCode]]);
        });

        mcConnect.SendDataToServer({
            CMD : _CMD_.cs_login_by_token,
            Data: {
                Token     : token,
                ClientType: 'admin',
                PingDelay : 1,
                UserAgent : navigator.userAgent || " ",
                Referral  : document.referrer || " ",
                State     : mcConst.currentState,
                UTC       : (new Date()).getTimezoneOffset() / -60
            }
        });
    };

    SendCMDToServer[_CMD_.cs_quit] = function cs_quit(sID){
        mcConnect.SendDataToServer({
            CMD  : _CMD_.cs_quit,
            Data : sID,
            immediately: true
        })
    };

    SendCMDToServer[_CMD_.Ping] = function CS_CMD_Ping(sID){
        mcConnect.SendDataToServer({
            CMD  : _CMD_.Ping,
            Data : sID
        })
    };

    // =====================================================================================

    var sendPing = SendCMDToServer[_CMD_.Ping];
}

"use strict";

function initLogin($scope){
    var labelWidth = 140;

    if ($$('loginForm')) $$('loginForm').destructor();

    var srvPwdPopup = webix.ui({
        view  : "popup",
        width : 330,
        height: 110,
        body  : {
            template   : mcService.insertIco("fa-info-circle") + mcService.Lang(1070), // "1070":"Общий пароль, которые проверяется перед авторизацией пользователя (раздел \"Настройки\" -&gt; \"Сетевые настройки\")",
            borderless : true
        }
    });

    var loginPopup = webix.ui({
        view  : "popup",
        width : 330,
        height: 95,
        body  : {
            template   : mcService.insertIco("fa-info-circle") + mcService.Lang(175), // "175":"Используйте для входа
            borderless : true
        }
    });

    webix.ready(function(){
        var _view = webix.ui({
            container: 'loginForm',
            id       : "loginForm",
            view     : "window",
            width    : 320,
            position : "center",
            head     : "MyChat Server Control Panel",
            body     : {
                view : 'form',
                rules:{
                    "loginField"    : webix.rules.isNotEmpty,
                    "passwordField" : webix.rules.isNotEmpty
                },
                elements:[{
                    cols : [{
                        view       : "text",
                        label      : mcService.Lang(1), // "1" : "Логин"
                        labelWidth : labelWidth,
                        id         : 'loginField',
                        name       : 'loginField',
                        value      : $scope.login,
                        required   : "true",
                        on         : {
                            onKeyPress : $scope.keyLogin
                        }
                    }, {
                        view     : "button",
                        template : '<div style="text-align: center; line-height: 30px; color: #777; font-size: 13pt; cursor: pointer"><b>?</b></div>', // mcService.insertIco('fa-info')
                        width    : 18,
                        borderless : true,
                        click    : function(){
                            loginPopup.show(this.getNode());
                        }
                    }, { width: 5 }]
                }, {
                    cols : [{
                        view       : "text",
                        label      : mcService.Lang(2), // "2" : "Пароль"
                        labelWidth : labelWidth,
                        type       : 'password',
                        value      : $scope.pwd,
                        id         : 'passwordField',
                        name       : 'passwordField',
                        required   : "true",
                        keyPressTimeout: 100,
                        on         : {
                            onKeyPress : $scope.keyLogin,
                            onTimedKeyPress : function(){
                                var lng = $$('loginDispLang');
                                var lastChar = $$('passwordField').getValue();
                                lastChar = lastChar[lastChar.length - 1];

                                if (lastChar){
                                    if (lastChar.match(/[a-zA-Z]/)) {
                                        lng.define('template', 'EN');
                                        lng.refresh();
                                    } else
                                    if (lastChar.match(/[а-яА-Я]/)){
                                        lng.define('template', 'RU');
                                        lng.refresh();
                                    } else
                                    if (lastChar.match(/[їЇіІєЄ]/)){
                                        lng.define('template', 'UA');
                                        lng.refresh();
                                    }
                                }
                            }
                        }
                    }, {
                        id       : 'loginDispLang',
                        template : 'EN',
                        width    : 23,
                        borderless : true
                    }]
                }, { cols: [
                    {
                        view       : "text",
                        label      : mcService.Lang(3), // "3" : "Пароль к серверу"
                        labelWidth : labelWidth,
                        type       : 'password',
                        id         : 'servPassField',
                        on         : {
                            onKeyPress : $scope.keyLogin
                        }
                    }, {
                        view     : "button",
                        template : '<div style="text-align: center; line-height: 30px; color: #777; font-size: 13pt; cursor: pointer"><b>?</b></div>', // mcService.insertIco('fa-info')
                        width    : 18,
                        borderless : true,
                        css      : "finger",
                        click    : function(){
                            srvPwdPopup.show(this.getNode());
                        }
                    }, { width: 5}
                ]},{ cols: [
                    {
                        view       : "richselect",
                        id         : "loginLang",
                        labelWidth : labelWidth,
                        label      : mcService.Lang(6), // "6" : "Язык интерфейса"
                        value      : $scope.lang,
                        options    : {
                            template : "#value#",
                            data     : [
                                { id : 'ru', value : "Русский"},
                                { id : 'uk', value : "Українська"},
                                { id : 'en', value : "English"}
                            ]
                        },
                        on : {
                            onChange : $scope.changeLang
                        }
                    },{
                        id         : "flagImg",
                        template   : "&nbsp;",
                        width      : 23,
                        borderless : true,
                        css        : "lh25"
                    }
                ]}, {
                    view       : "checkbox",
                    labelRight : mcService.Lang(1141), // "1141":"Запомнить меня на этом компьютере",
                    labelWidth : 0,
                    css        : "finger",
                    value      : $scope.remember,
                    on         : { onChange: function(newV){
                        $scope.remember = mcService.convertIntToBool(newV);
                    }}
                }, {
                    view       : "button",
                    value      : mcService.Lang(5), // "5" : "Войти"
                    id         : "loginBtn",
                    click      : $scope.loginBtnClick
                }]
            }
        });

        _view.show();

        $scope.flagImg = $$("flagImg");

        $scope.changeFlag($scope.lang);

        $$('loginField').focus();

        $$('loginField').getInputNode().setAttribute("autocomplete", "off");
        $$('passwordField').getInputNode().setAttribute("autocomplete", "off");
        $$('servPassField').getInputNode().setAttribute("autocomplete", "off");
        // $$('passwordField').getInputNode().setAttribute("autocomplete", "new-password");
        // $$('servPassField').getInputNode().setAttribute("autocomplete", "new-password");

        mcService.disableContextMenu(_view);
    });
}

"use strict";

function loginController ($scope, $rootScope, $location){
    $scope.Name = mcConst.dataModels.Login;
    $scope.remember = false;

    function disableForm (){
        $$("loginForm").disable();
    }

    // ======= Error Actions ==========

    $rootScope.ErrorActions[mcConst._CMD_.Errors.WrongPassword] = function(){ // "14"  : "Неверный пароль пользователя",
        mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", false);

        mcConst.LoginInfo.pwd     = "";
        mcConst.LoginInfo.servPwd = "";
        mcConst.LoginInfo.rm      = false;

        initLogin($scope);

        $rootScope.loginFormNotShowed = false;

        webix.ready(function(){
            setTimeout(function(){
                $$('passwordField').focus();
            }, 100);
        });
    };

    $rootScope.ErrorActions[4]   =
    $rootScope.ErrorActions[mcConst._CMD_.Errors.UserNotExist]  =
    $rootScope.ErrorActions[80]  =
    $rootScope.ErrorActions[92]  =
    $rootScope.ErrorActions[83]  = $rootScope.ErrorActions[mcConst._CMD_.Errors.WrongPassword]; // остался мусор в локал сторажде от предыдущего логина

    $rootScope.ErrorActions[177]  = function () {
        if (mcConst.isShowed){
            mcService.hideView(document.getElementById(mcConst.isShowed));
            mcService.hideView(document.getElementById(mcConst.dataModels.NavPanel));
            mcService.hideView(document.getElementById(mcConst.dataModels.ApplyPanel));
        }

        $rootScope.ErrorActions[mcConst._CMD_.Errors.WrongPassword]();
    };

    $rootScope.ErrorActions[mcConst._CMD_.Errors.ConnectionLimit]  = function (Params) {
        $rootScope.$broadcast('ErrorMsg', [mcConst._CMD_.Errors.ConnectionLimit, mcConst.ErrorText[mcConst._CMD_.Errors.ConnectionLimit], Params, function(){
            mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", "");

            location.reload();
        }]);
    };

    $rootScope.ErrorActions[215] =
        $rootScope.ErrorActions[216] = function () {
            location.search = "";
        };

    // ===============================

    $scope.keyLogin = function(code , e){
        if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
            $scope.loginBtnClick.apply(this);

            return false;
        }
    };

    $scope.loginBtnClick = function (){
        var isValid = this.getFormView().validate();

        if (isValid) {
            //$rootScope.showSpecificView = true;

            $rootScope.$broadcast('SendCMDToServer' , [
                mcConst.lockInterface,
                mcConst._CMD_.Login,
                $$('loginField').   $getValue(), //mcConst.LoginInfo.login  ,
                $$('passwordField').$getValue(), //mcConst.LoginInfo.pwd    ,
                $$('servPassField').$getValue(), //mcConst.LoginInfo.servPwd,
                mcConst.LoginInfo.rm             //mcConst.LoginInfo.rm
            ]);

            mcConst.LoginInfo.login = $$('loginField').$getValue();
            mcConst.LoginInfo.rm    = $scope.remember;

            this.blur();

            disableForm();
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(7)]); // "1084":"Название не может быть пустым или совпадать с существующим",
        }
    };

    $scope.changeLang = function(lang){
        $scope.changeFlag(lang);

        $rootScope.$broadcast('ChangLanguage', mcService.detectLang(lang));
    };

    $scope.changeFlag = function(lang){
        $scope.flagImg.define('template', '<img src="' + mcConst.imagesPath.flags + lang + '.png">');
        $scope.flagImg.refresh();
    };

    $scope.$on('enable' + $scope.Name, function enableForm (){
        var lForm = $$("loginForm");

        if (lForm) lForm.enable();
    });

    $scope.$on('hide' + $scope.Name, function(){
        if ($$("loginForm")) {
            $$("loginForm").hide();
        }
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        var firstAutoLogin = $location.param('default');

        $scope.lang     = args[0] || mcConst.Lang;
        $scope.login    = mcConst.LoginInfo.login || (firstAutoLogin ? 'admin' : "");
        $scope.pwd      = firstAutoLogin ? 'admin' : "";
        $scope.remember = firstAutoLogin ? false : mcConst.LoginInfo.rm;

        var token = $location.param('token');

        webix.storage.local.put('admLang', $scope.lang);

        if (token){
            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_login_by_token,
                token
            ]);

            window.history.pushState(null, document.title, window.location.pathname + window.location.hash.replace("token=" + token, ""));
        } else

        if ($scope.remember) {
            $rootScope.loginFormNotShowed = true;

            $rootScope.$broadcast('SendCMDToServer' , [
                mcConst.lockInterface,
                mcConst._CMD_.Login,
                mcConst.LoginInfo.login  ,
                mcConst.LoginInfo.pwd    ,
                mcConst.LoginInfo.servPwd,
                mcConst.LoginInfo.rm
            ]);
        } else {
            initLogin($scope);

            $rootScope.loginFormNotShowed = false;
        }

        if (firstAutoLogin || $rootScope.firstLogin) {
            var df = webix.ui({
                view     : "window",
                width    : 400,
                position : "center",
                modal    : true,
                head     : "MyChat Server Control Panel",
                body     : { padding  : 7, rows: [
                    { template: mcLang(4), autoheight: true, borderless: true, css: "byCenter" },
                    { height: 10},
                    { cols: [
                        {},
                        { view: "button", value: mcLang(13), width: 90, click: function () { // "13" : "Ок",
                            this.getTopParentView().hide();

                            firstAutoLogin = false;
                            $rootScope.firstLogin = false;
                        }},
                        {}
                    ]}
                ]}
            });

            setTimeout(function () {
                df.show();
            }, 100);
        }
    });
}

function initNavigation($scope){
    "use strict";

    var itemHeight = 40;

    var accordItemsContent = {  // body
        navServerInfo : {
            padding : 4,
            rows    : [{
                view       : "unitlist",
                id         : "listServerInfo",
                borderless : true,
                template   : "#title#",
                css        : "scrollMenu subTitleNav",
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView},
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       : (function(){
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.ServerInfo]) ? [{
                            id    : mcConst.dataModels.ServerInfo,
                            height : itemHeight,
                            selected: true,
                            title : mcService.Lang(10) // // "10" : "Информация о сервере",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.OnlineUsers]) ? [{
                            id    : mcConst.dataModels.OnlineUsers,
                            height: itemHeight,
                            selected: true,
                            title : mcService.Lang(1564) // "1564":"Онлайн пользователи",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.NssService]) ? [{
                            id    : mcConst.dataModels.NssService,
                            height : itemHeight,
                            selected: true,
                            title : mcService.Lang(1725) // "1725":"Дополнительные услуги",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SupportForum]) ? [{
                            id    : mcConst.dataModels.SupportForum,
                            height : itemHeight,
                            selected: true,
                            title : mcService.Lang(1730) // "1730":"Форум поддержки",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Terminal]) ? [{
                            id     : mcConst.dataModels.Terminal,
                            height : itemHeight,
                            selected: true,
                            title : "Terminal"
                        }] : [])
                    ;
                })()
            }]// , mcService.Marge({}, helpButton)
        },
        // =====================
        navUsers : {
            type:"head",
            padding : 4,
            rows:[{
                view       : "unitlist",  // list
                id         : "listUsers", // + mcConst.dataModels.UserManager,
                borderless : true,
                template   : "#title#",
                css        : "scrollMenu subTitleNav",
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       :(function() {
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.UserManager]) ? [{
                            id    : mcConst.dataModels.UserManager,
                            height : itemHeight,
                            title : mcService.Lang(49) // "49" : "Список пользователей",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Contacts]) ? [{
                            id    : mcConst.dataModels.Contacts,
                            height : itemHeight,
                            title : mcService.Lang(587) // "587": "Общий список контактов",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.UserGroups]) ? [{
                            id     : mcConst.dataModels.UserGroups,
                            height : itemHeight,
                            title  : mcService.Lang(1722) // "1722":"Группы пользователей",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.PersonalGroups]) ? [{
                            id     : mcConst.dataModels.PersonalGroups,
                            height : itemHeight,
                            title  : mcService.Lang(2186) // "2186":"Личные группы пользователей",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.WorkPositions]) ? [{
                            id    : mcConst.dataModels.WorkPositions,
                            height : itemHeight,
                            title : mcService.Lang(588) // "588": "Должности компании",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Bans]) ? [{
                            id    : mcConst.dataModels.Bans,
                            height : itemHeight,
                            title : mcService.Lang(1029) // "1029":"Забаненные пользователи",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.UsersImports]) ? [{
                            id    : mcConst.dataModels.UsersImports,
                            height : itemHeight,
                            title : mcService.Lang(960) // "960":"Импорт пользователей",
                        }] : [])

                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.ActiveDirectory]) ? [{
                            id     : mcConst.dataModels.ActiveDirectory,
                            height : itemHeight,
                            head   : mcLang(68),  // "68" : "Active Directory",
                            title  : mcLang(1963) // "1963":"Импорт пользователей",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.AdDomains]) ? [{
                            id     : mcConst.dataModels.AdDomains,
                            height : itemHeight,
                            head   : mcService.Lang(68), // "68" : "Active Directory",
                            title  : mcService.Lang(1964) // "1964":"Синхронизация",
                        }] : [])

                })(),
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView}
            }] // , mcService.Marge({}, helpButton)
        },
        // =====================
        navConference : {
            type:"head",
            padding : 4,
            rows:[{
                view       : "unitlist",
                id         : "listConference",
                borderless : true,
                template   : "#title#",
                css        : "scrollMenu subTitleNav",
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       :(function() {
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.ActiveChannels]) ? [{
                            id     : mcConst.dataModels.ActiveChannels,
                            height : itemHeight,
                            title  : mcService.Lang(1623) // "1623":"Активные конференции",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.AutoChannels]) ? [{
                            id     : mcConst.dataModels.AutoChannels,
                            height : itemHeight,
                            title  : mcService.Lang(1039) // "1039":"Автосоздаваемые конференции",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Operators]) ? [{
                            id    : mcConst.dataModels.Operators,
                            height : itemHeight,
                            title : mcService.Lang(817) // "817":"Модераторы",
                        }] : [])
                })(),
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView}
            }]
        },
        // =====================
        navRights : {
            type:"head",
            padding : 4,
            rows:[{
                view       : "unitlist",
                id         : "listRights", // + mcConst.dataModels.RightsManager,
                borderless : true,
                css        : "scrollMenu subTitleNav",
                template   : "#title#",
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       :(function() {
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.GroupRights]) ? [{
                            id     : mcConst.dataModels.GroupRights,
                            height : itemHeight,
                            title  : mcService.Lang(57) // "57" : "Группы прав"
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.GroupUsers]) ? [{
                            id     : mcConst.dataModels.GroupUsers,
                            height : itemHeight,
                            title  : mcService.Lang(916) // "916":"Пользователи групп",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.PluginAccess]) ? [{
                            id     : mcConst.dataModels.PluginAccess,
                            height : itemHeight,
                            title  : mcService.Lang(1758) // "1758":"Доступ к плагинам",
                        }] : [])
                })(),
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView}
            }]//, mcService.Marge({}, helpButton)
        },
        // =====================
        navTools : {
            type:"head",
            padding : 4,
            rows:[{
                view       : "unitlist",
                id         : "listTools",
                borderless : true,
                template   : "#title#",
                css        : "scrollMenu subTitleNav",
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       :(function() {
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Testport]) ? [{
                            id     : mcConst.dataModels.Testport,
                            height : itemHeight,
                            title  : mcService.Lang(2225) // "2225":"Тест портов",
                        }] : [])

                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Integrations]) ? [{
                            id     : mcConst.dataModels.Integrations,
                            height : itemHeight,
                            title  : mcService.Lang(1740) // "1740":"Интеграция",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.MyChatGuest]) ? [{
                            id     : mcConst.dataModels.MyChatGuest,
                            height : itemHeight,
                            title  : mcService.Lang(945) // "945":"MyChat Guest",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.WebSupport]) ? [{
                            id     : mcConst.dataModels.WebSupport,
                            height : itemHeight,
                            title  : mcService.Lang(938) // "938":"Web-поддержка",
                        }] : [])
                        .concat(mcService.checkRightsCollection($scope.rightsIdForMenuAccess[mcConst.dataModels.History]) ? [{
                            id     : mcConst.dataModels.History,
                            height : itemHeight,
                            title  : mcService.Lang(1134) // "1134":"Просмотр протоколов",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.BBS]) ? [{
                            id     : mcConst.dataModels.BBS,
                            height : itemHeight,
                            title  : mcService.Lang(1515) // "1515":"Доска объявлений",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Updates]) ? [{
                            id     : mcConst.dataModels.Updates,
                            height : itemHeight,
                            title  : mcService.Lang(1555) // "1555":"Обновления",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Forum]) ? [{
                            id     : mcConst.dataModels.Forum,
                            height : itemHeight,
                            head   : mcService.Lang(1793), // "1793":"Форум",
                            title  : mcService.Lang(1983) // "1983":"Управление подписками",
                        }] : [])
                        /*.concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.WorkTime]) ? [{
                            id     : mcConst.dataModels.WorkTime,
                            height : itemHeight,
                            title  : mcService.Lang(1582) // "1582":"Контроль рабочего времени",
                        }] : [])*/
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.MCScripts]) ? [{
                            id     : mcConst.dataModels.MCScripts,
                            height : itemHeight,
                            title  : mcService.Lang(1589) // "1589":"Скрипты",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Reboot]) ? [{
                            id     : mcConst.dataModels.Reboot,
                            height : itemHeight,
                            title  : mcService.Lang(1618) // "1618":"Перезагрузка",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Relocation]) ? [{
                            id     : mcConst.dataModels.Relocation,
                            height : itemHeight,
                            title  : mcService.Lang(1765) // "1765":"Перенос сервера",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Bots]) ? [{
                            id     : mcConst.dataModels.Bots,
                            height : itemHeight,
                            title  : mcService.Lang(1888) // "1888":"Боты",
                        }] : [])

                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.CustomMenu]) ? [{
                            id     : mcConst.dataModels.CustomMenu,
                            height : itemHeight,
                            title  : mcService.Lang(2218) // "2218":"Пользовательское меню",
                        }] : [])

                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.RemoteSettings]) ? [{
                            id     : mcConst.dataModels.RemoteSettings,
                            height : itemHeight,
                            head   : mcLang(1739), // "1739":"Шаблоны настроек",
                            title  : mcService.Lang(1329) // "1329":"Удаленная настройка клиентов",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.PresetManager]) ? [{
                            id     : mcConst.dataModels.PresetManager,
                            height : itemHeight,
                            head   : mcLang(1739), // "1739":"Шаблоны настроек",
                            title  : mcService.Lang(1688) // "1688":"Наборы настроек клиентов",
                        }] : [])

                        /*.concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.TotalClear]) ? [{
                            id     : mcConst.dataModels.TotalClear,
                            height : itemHeight,
                            head   : "&nbsp;&nbsp;&nbsp;",
                            title  : mcService.Lang(1945) // "1945":"Очистка",
                        }] : [])*/
                })(),
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView}
            }]
        },
        // =====================
        navFilters : {
            type:"head",
            padding : 4,
            rows:[{
                view       : "unitlist",
                id         : "listFilters",
                borderless : true,
                template   : "#title#",
                css        : "scrollMenu subTitleNav",
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       :(function() {
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.FilterAntiflood]) ? [{
                            id    : mcConst.dataModels.FilterAntiflood,
                            height: itemHeight,
                            title : mcService.Lang(1057) // "1057":"Антифлуд",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.FilterIP]) ? [{
                            id    : mcConst.dataModels.FilterIP,
                            height: itemHeight,
                            title : mcService.Lang(1059) // "1059":"IP фильтры",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.FilterMAC]) ? [{
                            id    : mcConst.dataModels.FilterMAC,
                            height: itemHeight,
                            title : mcService.Lang(1060) // "1060":"MAC фильтры",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.FilterHardware]) ? [{
                            id    : mcConst.dataModels.FilterHardware,
                            height: itemHeight,
                            title : mcService.Lang(1914) // "1914":"Hardware фильтры",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.FilterBadWords]) ? [{
                            id    : mcConst.dataModels.FilterBadWords,
                            height: itemHeight,
                            title : mcService.Lang(1058) // "1058":"Плохие слова",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.FilterNames]) ? [{
                            id    : mcConst.dataModels.FilterNames,
                            height: itemHeight,
                            title : mcService.Lang(1061) // "1061":"Блокировки названий",
                        }] : [])
                })(),
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView}
            }]
        },
        // =====================
        navSettings : {
            type:"head",
            padding : 4,
            rows:[{
                view       : "unitlist",
                id         : "listSettings", // + mcConst.dataModels.SettingsNetwork,
                borderless : true,
                template   : "#title#",
                css        : "scrollMenu subTitleNav",
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       :(function() {
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsNetwork]) ? [{
                            id     : mcConst.dataModels.SettingsNetwork,
                            height : itemHeight,
                            title  : mcService.Lang(591) // "591": "Сетевые настройки MyChat",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsInfo]) ? [{
                            id     : mcConst.dataModels.SettingsInfo,
                            height : itemHeight,
                            title  : mcService.Lang(596) // "596": "Информация",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsLogs]) ? [{
                            id     : mcConst.dataModels.SettingsLogs,
                            height : itemHeight,
                            title  : mcService.Lang(598) // "598": "Протоколирование",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsFTP]) ? [{
                            id     : mcConst.dataModels.SettingsFTP,
                            height : itemHeight,
                            title  : mcService.Lang(599) // "599": "FTP файловый сервер",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsWEB]) ? [{
                            id     : mcConst.dataModels.SettingsWEB,
                            height : itemHeight,
                            title  : mcService.Lang(600) // "600": "WEB-сервисы",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsWebCache]) ? [{
                            id     : mcConst.dataModels.SettingsWebCache,
                            height : itemHeight,
                            title  : mcService.Lang(2126) // "2126":"Кеширование WEB-сервера",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsBackup]) ? [{
                            id     : mcConst.dataModels.SettingsBackup,
                            height : itemHeight,
                            title  : mcService.Lang(601) // "601": "Резервные копии",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsService]) ? [{
                            id     : mcConst.dataModels.SettingsService,
                            height : itemHeight,
                            title  : mcService.Lang(602) // "602": "Обслуживание",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsAPI]) ? [{
                            id     : mcConst.dataModels.SettingsAPI,
                            height : itemHeight,
                            title  : mcService.Lang(603) // "603": "Integration API",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsSMTP]) ? [{
                            id     : mcConst.dataModels.SettingsSMTP,
                            height : itemHeight,
                            title  : mcService.Lang(921) // "921":"Настройка SMTP",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsGPS]) ? [{
                            id     : mcConst.dataModels.SettingsGPS,
                            height : itemHeight,
                            title  : mcService.Lang(2203) // "2203":"GPS трекинг",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.Others]) ? [{
                            id     : mcConst.dataModels.Others,
                            height : itemHeight,
                            title  : mcService.Lang(672) // "672": "Дополнительно",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsFolders]) ? [{
                            id     : mcConst.dataModels.SettingsFolders,
                            height : itemHeight,
                            title  : mcService.Lang(1941) // "1941":"Каталоги",
                        }] : [])
                        // .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsPlugins]) ? [{
                        //     id     : mcConst.dataModels.SettingsPlugins,
                        //     height : itemHeight,
                        //     title  : mcService.Lang(824)  // "824":"Плагины (дополнения)",
                        // }] : [])
                })(),
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView}
            }]
        },
        // =====================
        navLicense : {
            type:"head",
            padding : 4,
            rows:[{
                view       : "unitlist",
                id         : "listLicense",
                borderless : true,
                template   : "#title#",
                css        : "scrollMenu subTitleNav",
                uniteBy    : function(obj){
                    return obj.head || "_for_hide_";
                },
                data       :(function() {
                    return []
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseMyChat]) ? [{
                            id    : mcConst.dataModels.LicenseMyChat,
                            height : itemHeight,
                            title : mcService.Lang(944) // "944":"MyChat Server",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseGuest]) ? [{
                            id    : mcConst.dataModels.LicenseGuest,
                            height : itemHeight,
                            title : mcService.Lang(945) // "945":"MyChat Guest",
                        }] : [])
                        .concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseQuiz]) ? [{
                            id    : mcConst.dataModels.LicenseQuiz,
                            height : itemHeight,
                            title : mcService.Lang(2033) // "2033":"MyChat викторина",
                        }] : [])
                        /*.concat(mcService.checkRights($scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseClear]) ? [{
                            id    : mcConst.dataModels.LicenseClear,
                            height : itemHeight,
                            title : mcService.Lang(1958) // "1958":"MyChat Clear",
                        }] : [])*/
                })(),
                select     : true,
                scroll     : false,
                on         : { onAfterSelect : $scope.showView}
            }]
        }
    };

    var accordItems = []
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.ServerInfo],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.NssService],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SupportForum],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Terminal],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.OnlineUsers]])
        ? [{
            header  : mcService.insertIco('fa-info-circle') + "MYCHAT SERVER",//mcService.Lang(10).toUpperCase(),  // "10" : "Информация о сервере",
            id      : 'navServerInfo'
        }]
        : [])
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.UserManager],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Contacts],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.WorkPositions],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.RemoteSettings],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Operators],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Bans],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.UserGroups],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.AdDomains],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.PersonalGroups],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.ActiveDirectory]])
        ? [{
            header  : mcService.insertIco('fa-users') + mcService.Lang(16).toUpperCase(), // "16" : "Управление пользователями"
            id      : 'navUsers'
        }]
        : [])
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.ActiveChannels],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.AutoChannels]])
        ? [{
            header  : mcService.insertIco('fa-users') + mcService.Lang(31).toUpperCase(), // "31" : "Конференции",
            id      : 'navConference'
        }]
        : [])
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.GroupRights],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.PluginAccess],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.GroupUsers]])
        ? [{
            header  : mcService.insertIco('fa-list-ul') + mcService.Lang(586).toUpperCase(), // "586": "Управление правами",
            id      : 'navRights'
        }]
        : [])
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.MyChatGuest],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.WebSupport],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.BBS],
            //$scope.rightsIdForMenuAccess[mcConst.dataModels.WorkTime],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.MCScripts],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Reboot],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Relocation],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Integrations],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.PresetManager],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.TotalClear],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Bots],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Forum],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.CustomMenu],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Testport],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Updates]].concat($scope.rightsIdForMenuAccess[mcConst.dataModels.History]))
        ? [{
            header  : mcService.insertIco('fa-wrench') + mcService.Lang(99).toUpperCase(), // "99" : "Инструменты",
            id      : 'navTools'
        }]
        : [])
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.FilterAntiflood],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.FilterIP],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.FilterMAC],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.FilterBadWords],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.FilterNames]])
        ? [{
            header  : mcService.insertIco('fa-filter') + mcService.Lang(1040).toUpperCase(), // "1040":"Фильтры",
            id      : 'navFilters'
        }]
        : [])
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsNetwork],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsInfo],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsLogs],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsFTP],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsWEB],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsBackup],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsService],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsAPI],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsSMTP],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsFolders],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsWebCache],
            // $scope.rightsIdForMenuAccess[mcConst.dataModels.SettingsPlugins],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.Others]])
        ? [{
            header  : mcService.insertIco('fa-cogs') + mcService.Lang(15).toUpperCase(), // "15" : "Настройка"
            id      : 'navSettings'
        }]
        : [])
        .concat(mcService.checkRightsCollection([
            $scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseMyChat],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseClear],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseQuiz],
            $scope.rightsIdForMenuAccess[mcConst.dataModels.LicenseGuest]])
        ? [{
            header  : mcService.insertIco('fa-key') + mcService.Lang(943).toUpperCase(), // "943":"Лицензии",
            id      : 'navLicense'
        }]
        : []);

    accordItems[0].collapsed = false;

    for (var i = 0; i < accordItems.length; i++){
        accordItems[i].body = accordItemsContent[accordItems[i].id];
        accordItems[i].on   = { onItemClick : $scope.showPart };
    }

    var _view = webix.ui({
        container : $scope.Name,
        id        : $scope.Name,
        borderless: true,
        rows      : [{
            id    : "navRestartButton",
            type  : "danger",
            view  : "button",
            height: 36,
            hidden: true,
            value : mcService.Lang(1619), // "1619":"Перезагрузить %s-сервер",
            click : $scope.restartServer
        }, {
            view      : "accordion",
            id        : "navMainMenu",
            multi     : false,
            collapsed : true,
            type      : "wide",
            css       : "lightShadow",
            padding   : 5,
            width     : mcConst.navWidth,
            rows      : accordItems
        }, {
            type  : "icon",
            view  : "button",
            label : mcService.Lang(1014), // "1014":"Завершить сеанс",
            icon  : "sign-out",
            css   : "closeSession",
            click : function(){
                $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                    type  : "confirm-warning",
                    text  : mcService.Lang(1015), // "1015":"Завершить работу?",
                    ok    : mcService.Lang(114),  // "114": "да",
                    cancel: mcService.Lang(113),  // "113": "нет",
                    callback:function(yes){
                        if (yes) {
                            $scope.logout();
                        }
                    }
                }));
            }
        }]
    });

    var hideList = mcService.getElementByClass("webix_unit_header webix_unit__header");

    for (var i = 0; i < hideList.length; i ++){
        if (hideList[i].attributes.getNamedItem("webix_unit_id").value === "_for_hide_"){
            hideList[i].style.display = "none";
        }
    }

    $scope.navMainMenu = $$("navMainMenu");
    $scope.navRestartButton = $$("navRestartButton");

    mcService.disableContextMenu(_view);

    return _view;
}
function navController($scope, $rootScope){
    "use strict";

    $scope.Name       = mcConst.dataModels.NavPanel;
    $scope.openAcItem = "";

    var NavPanel     = null;
    var angElement   = document.getElementById($scope.Name);
    var location     = window.history.location || window.location;
    var showedWindow = {};
    var callBackForNextChangeLocation = null;

    var rightsIdForMenuAccess = {};

        // настрока соответствий меню и доступнам правам пользователя
        rightsIdForMenuAccess[mcConst.dataModels.ServerInfo]      = "88";
        rightsIdForMenuAccess[mcConst.dataModels.OnlineUsers]     = "89";
        rightsIdForMenuAccess[mcConst.dataModels.UserManager]     = "90";
        rightsIdForMenuAccess[mcConst.dataModels.Contacts]        = "91";
        rightsIdForMenuAccess[mcConst.dataModels.WorkPositions]   = "92";
        rightsIdForMenuAccess[mcConst.dataModels.UsersImports]    = "93";
        rightsIdForMenuAccess[mcConst.dataModels.Operators]       = "94";
        rightsIdForMenuAccess[mcConst.dataModels.Bans]            = "95";
        rightsIdForMenuAccess[mcConst.dataModels.ActiveDirectory] = "96";
        rightsIdForMenuAccess[mcConst.dataModels.AutoChannels]    = "97";
        rightsIdForMenuAccess[mcConst.dataModels.GroupRights]     = "98";
        rightsIdForMenuAccess[mcConst.dataModels.GroupUsers]      = "99";
        rightsIdForMenuAccess[mcConst.dataModels.MyChatGuest]     = "100";
        rightsIdForMenuAccess[mcConst.dataModels.WebSupport]      = "101";
        rightsIdForMenuAccess[mcConst.dataModels.History]         = ["54","44","45","43","55","86","87","132"];
        rightsIdForMenuAccess[mcConst.dataModels.BBS]             = "102";
        rightsIdForMenuAccess[mcConst.dataModels.WorkTime]        = "121";
        rightsIdForMenuAccess[mcConst.dataModels.MCScripts]       = "122";
        rightsIdForMenuAccess[mcConst.dataModels.Updates]         = "103";
        rightsIdForMenuAccess[mcConst.dataModels.FilterAntiflood] = "104";
        rightsIdForMenuAccess[mcConst.dataModels.FilterIP]        = "105";
        rightsIdForMenuAccess[mcConst.dataModels.FilterMAC]       = "106";
        rightsIdForMenuAccess[mcConst.dataModels.FilterBadWords]  = "107";
        rightsIdForMenuAccess[mcConst.dataModels.FilterNames]     = "108";

        rightsIdForMenuAccess[mcConst.dataModels.SettingsNetwork] = "109";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsInfo]    = "110";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsLogs]    = "111";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsFTP]     = "112";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsWEB]     = "113";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsWebCache]= "113";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsBackup]  = "114";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsService] = "115";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsAPI]     = "116";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsSMTP]    = "117";
        rightsIdForMenuAccess[mcConst.dataModels.Others]          = "118";
        rightsIdForMenuAccess[mcConst.dataModels.SettingsFolders] = mcConst._CMD_.RS.QAllowSettingsFolders;
        rightsIdForMenuAccess[mcConst.dataModels.SettingsPlugins] = mcConst._CMD_.RS.QAdmAccessSettingsPlugins;
        rightsIdForMenuAccess[mcConst.dataModels.SettingsGPS]     = mcConst._CMD_.RS.QAdmAccessOptionsGPS;  

        rightsIdForMenuAccess[mcConst.dataModels.LicenseMyChat]   = "119";
        rightsIdForMenuAccess[mcConst.dataModels.LicenseGuest]    = "120";
        rightsIdForMenuAccess[mcConst.dataModels.RemoteSettings]  = "131";
        rightsIdForMenuAccess[mcConst.dataModels.Reboot]          = "133";
        rightsIdForMenuAccess[mcConst.dataModels.ActiveChannels]  = "135";

        rightsIdForMenuAccess[mcConst.dataModels.PresetManager]   = "136";
        rightsIdForMenuAccess[mcConst.dataModels.NssService]      = "138";
        rightsIdForMenuAccess[mcConst.dataModels.UserGroups]      = "139";
        rightsIdForMenuAccess[mcConst.dataModels.PersonalGroups]  = mcConst._CMD_.RS.QAdmAccessPersonalGroups;
        rightsIdForMenuAccess[mcConst.dataModels.Integrations]    = "140";
        rightsIdForMenuAccess[mcConst.dataModels.SupportForum]    = "137";

        rightsIdForMenuAccess[mcConst.dataModels.AdDomains]       = "141";
        rightsIdForMenuAccess[mcConst.dataModels.PluginAccess]    = "142";
        rightsIdForMenuAccess[mcConst.dataModels.Relocation]      = "143";

        rightsIdForMenuAccess[mcConst.dataModels.FilterHardware]  = mcConst._CMD_.RS.QAllowFilterHardware;
        rightsIdForMenuAccess[mcConst.dataModels.TotalClear]      = mcConst._CMD_.RS.QAdmToolWipe;
        rightsIdForMenuAccess[mcConst.dataModels.LicenseClear]    = mcConst._CMD_.RS.QAdmAccessLicensesWipe;
        rightsIdForMenuAccess[mcConst.dataModels.Forum]           = mcConst._CMD_.RS.QAdmAccessForumSubs;
        rightsIdForMenuAccess[mcConst.dataModels.LicenseQuiz]     = mcConst._CMD_.RS.QAdmAccessLicensesQuiz;
        rightsIdForMenuAccess[mcConst.dataModels.Terminal]        = mcConst._CMD_.RS.QAdmTerminal;
        rightsIdForMenuAccess[mcConst.dataModels.CustomMenu]      = mcConst._CMD_.RS.QAdmAccessToCustomMenu; 
        rightsIdForMenuAccess[mcConst.dataModels.Testport]        = mcConst._CMD_.RS.QAdmAccessPortTestTool;

        rightsIdForMenuAccess[mcConst.dataModels.Bots]            = "999";

    $scope.rightsIdForMenuAccess = rightsIdForMenuAccess;

    function whoRestart(opt){
        var who = opt.join('');
        var textWho = "";

        switch (who){
            case mcConst.restartItems.MyChat + mcConst.restartItems.WEB + mcConst.restartItems.FTP:
            case mcConst.restartItems.MyChat :
            case mcConst.restartItems.MyChat + mcConst.restartItems.WEB:
            case mcConst.restartItems.MyChat + mcConst.restartItems.FTP : textWho = "MyChat"; break;
            case mcConst.restartItems.WEB : textWho = "Web";    break;
            case mcConst.restartItems.FTP : textWho = "FTP";    break;
            case mcConst.restartItems.WEB + mcConst.restartItems.FTP : textWho = "Web+FTP";break;
        }

        return textWho;
    }

    function getOptions(cb) {
        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_get_personal_options,
            mcConst.SessionID,
            
            function( data ){
                $rootScope.adminOptions = mcService.Marge($rootScope.adminOptions, data.ADMINOPT);

                if (cb) {
                    cb($rootScope.adminOptions);
                }
            }
        ]);
    }

    function sendOptions(options, target) {
        var sendData = [
            mcConst._CMD_.cs_save_personal_options,
            mcConst.SessionID
        ];

        var data     = { ADMINOPT: {}};
        var pathWay  = [];
        var path     = $rootScope.adminOptions;
        var dataPath = data.ADMINOPT;

        if (mcService.isString(target)){
            pathWay = target.split('.');

            for (var i = 0; i < pathWay.length; i++){
                if (!path.hasOwnProperty(pathWay[i])){
                    if (i === pathWay.length - 1){
                        path[pathWay[i]] = "";
                    } else {
                        console.error("Admin hasn't options: " + target);

                        return;
                    }
                }

                if (mcService.isObject(path[pathWay[i]])){
                    path = path[pathWay[i]];

                    dataPath[pathWay[i]] = {};
                    dataPath = dataPath[pathWay[i]];
                } else
                if (i !== pathWay.length - 1){
                    console.error("Admin hasn't options: " + target);

                    return;
                }
            }

            i--;

            if (mcService.isObject(options)){
                path     = mcService.Marge(path, options);
                dataPath = mcService.Marge(dataPath, path);
            } else {
                path[pathWay[i]]     = options;
                dataPath[pathWay[i]] = options;
            }
        } else
        if (mcService.isObject(target)){
            target = mcService.Marge(target, options);

            data = { ADMINOPT: $rootScope.adminOptions };
        } else
        if (!target && mcService.isObject(options)) {
            $rootScope.adminOptions = mcService.Marge($rootScope.adminOptions, options);

            data = { ADMINOPT: $rootScope.adminOptions };
        } else {
            console.error("Options must be Object or set target for set options");

            return;
        }

        sendData.push(JSON.stringify(data));

        $rootScope.SendCMDToServer( sendData );
    }

    // =================================

    $scope.restartServer = function(){
        $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
            type  : "confirm-warning",
            text  : mcLang(1619, whoRestart(mcConst.restartOptions)) + "?", // "1619":"Перезагрузить %s-сервер",
            ok    : mcService.Lang(114), // "114": "да",
            cancel: mcService.Lang(113), // "113": "нет",
            callback:function(yes){
                if (yes) {
                    $rootScope.$broadcast('SendCMDToServer', [
                        mcConst.lockInterface,
                        mcConst._CMD_.cs_adm_restart_server_services,
                        mcConst.SessionID,
                        !!mcConst.restartOptions[0],
                        !!mcConst.restartOptions[1],
                        !!mcConst.restartOptions[2]
                    ]);

                    if (!!mcConst.restartOptions[0] || !!mcConst.restartOptions[1]){
                        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
                        $rootScope.$broadcast('StopPingTimer' ,[]);

                        $rootScope.$broadcast('ErrorMsg', ['223', mcConst.ErrorText['223'], '', function(){
                            mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", "");

                            mcService.reloadOrChangeProtocol();
                        }]);
                    }

                    $scope.navRestartButton.hide();
                }
            }
        }));
    };

    $scope.showPart = function(el){
        var self = null;
        var needExpand = true;

        if (this == null || (this && !this.$view)){
            self = $$(el);
        } else {
            self = this;
            needExpand = false;
        }

        if (self){
            var collapsed = self.config.collapsed;

            if (collapsed || needExpand){
                var list = self.getChildViews()[0].getChildViews()[0];

                $scope.openAcItem = el;
                $rootScope.currentRootPath = el;

                if ((collapsed || needExpand) && list){
                    var item = list.getSelectedItem() || []; // ListUserManager
                    var id = "";

                    if (mcService.isObject(item)){ // when any list item selected
                        id = item.id;

                        $scope.showView(id);
                    } else
                    if (mcService.isArray(item) && item.length === 0){ // no list item selected
                        id = list.getFirstId();

                        list.select(id);
                    }
                }
            }

            return collapsed;
        } else {
            return false;
        }
    };

    $scope.showView = function (id){
        if (mcConst.isShowed !== id){
            switch (id){
                case mcConst.dataModels.UserManager:
                    $rootScope.$broadcast('show' + id, ['open']);
                    break;

                case mcConst.dataModels.ServerInfo:
                    $rootScope.mcStorage.ServerInfo = null;

                    $rootScope.$broadcast('show' + id, []);
                    break;

                default:
                    $rootScope.$broadcast('show' + id, []);
            }
        }
    };

    $scope.logout = function (){
        mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", false);

        /*$rootScope.ErrorActions[115] = function(){
            location.reload();
        };*/

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_quit,
            mcConst.SessionID
        ]);

        window.history.pushState(null, document.title, window.location.pathname + window.location.hash);

        setTimeout(function(){
            location.reload(true);
        }, 200);
    };

    $scope.setNewLocation = function(path, cbOnChange, pageTitle){
        if (callBackForNextChangeLocation){
            callBackForNextChangeLocation(path);
        }

        callBackForNextChangeLocation = cbOnChange;

        $rootScope.$broadcast('show' + mcConst.dataModels.NavPanel, []);

        if (location.hash !== ('#' + path)){
            window.history.pushState(null, null, '#' + path);
        }

        document.title = mcConst.Title + " " + (pageTitle || mcService.getTitle(path.replace(/^\//, '').replace(/\/$/, '').split('/').pop()));
    };

    $scope.changeLocation = function(){
        if (mcConst.LoggedIn){ //  && !$rootScope.skipLocation
            var path = location.hash.replace(/^#\//, '').replace(/\/$/, '').split('/');

            if (path){
                var menu = $$(path[0]);

                if (menu && menu.config.view == 'accordionitem'){
                    $rootScope.currentRootPath = path[0] || $rootScope.currentRootPath;

                    var list = menu.getChildViews()[0].getChildViews()[0];
                    var flag = list.getItem && list.getItem(path[1]);

                    if (flag){
                        $scope.showView.call(null, path[1]);

                        list.select(path[1]);
                    }

                    if (!path[1] || flag) {
                        menu.expand();

                        document.title = mcConst.Title + " " + mcService.getTitle(path[path.length - 1]);

                        $scope.clearShowedWindows();

                        return;
                    }
                }
            }

            var id = $scope.navMainMenu.getChildViews()[0].config.id;

            $$(id).expand();
            $rootScope.$broadcast('show' + mcService.copy(id, 3), []);
            $scope.showPart.apply(null, [id]);
        }
    };

    $scope.addWindowToShowed = function(id, link){
        showedWindow[id] = link;
    };

    $scope.delWindowFromShowed = function(id){
        if (showedWindow.hasOwnProperty(id)) delete showedWindow[id];
    };

    $scope.clearShowedWindows = function(){
        for (var i in showedWindow){
            if (showedWindow.hasOwnProperty(i)){
                if (!showedWindow[i].$destructed){
                    if (showedWindow[i].hide) {
                        showedWindow[i].hide();

                        delete showedWindow[i];
                    } else
                    if (showedWindow[i].parentNode){
                        webix.modalbox.hide(showedWindow[i]);

                        delete showedWindow[i];
                    }
                } else {
                    delete showedWindow[i];
                }
            } else {
                console.error('Hide function not found, window id: ' + i);
            }
        }

        showedWindow = {};
    };

    (function(eventInfo){
        window[eventInfo[0]](eventInfo[1] + 'popstate', $scope.changeLocation, false);
    })(window.addEventListener ? ['addEventListener', ''] : ['attachEvent', 'on']);

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    // ====================================================

    $scope.$on('NeedRestartServer', function(){
        $scope.navRestartButton.define('value', mcLang(1619, whoRestart(mcConst.restartOptions))); // "1619":"Перезагрузить %s-сервер",
        $scope.navRestartButton.refresh();
        $scope.navRestartButton.show();
    });

    $scope.$on('saveAdminOptions', function(e, args){
        sendOptions.apply(null, args);
    });

    $scope.$on('addShowedWindow', function(e, args){
        $scope.addWindowToShowed.apply(null, args);
    });

    $scope.$on('changeLocation', $scope.changeLocation);

    $scope.$on('setLocation', function(e, args){
        $scope.setNewLocation.apply(null, args);
    });

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('clearList' + $scope.Name, function(){
        var list = $$("list" + mcService.copy($scope.openAcItem, 3));

        if (list) list.unselectAll();
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.hideView(document.getElementById(mcConst.dataModels.ApplyPanel));

        getOptions();

        if (!NavPanel) {
            NavPanel = initNavigation($scope);
        } else {
            mcService.showView(document.getElementById($scope.Name));
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_licenses,
            mcConst.SessionID,
            function (data){
                mcConst.LicenseInfo = data;
            }
        ]);

        NavPanel.adjust();

        mcConst.navResize = NavPanel;
    });
}
"use strict";

function initApplyPanel($scope){
    if ($$($scope.Name)){
        $$($scope.Name).destructor();
    }

    var sData = $scope.Set.data;
    var editInfo = [];

    if (sData.ShowDesc){
        editInfo = [{
            view    : "template",
            type    : "header",
            template: function(){
                var text = mcService.Lang(100); // "100": "Применить изменения?",

                if (sData.Header != undefined){
                    text = sData.Header;
                }

                return  text;
            }
        }, {
            view    : "scrollview",
            css     : (!sData.Desc) ? 'hidden' : "",
            padding : 5,
            body    : {
                view : "template",
                id   : $scope.Name + "Description",
                template : function(){
                    var text = "";

                    if (sData.Desc != undefined){
                        text = sData.Desc;
                    }

                    return  text;
                }
            }
        }, {
            view   : "button",
            value  : $scope.Set.ApplyTitle, //mcService.Lang(104), // "104": "Сохранить",
            height : 35,
            css    : "applyButton",
            click  : $scope.applyChange
        }];
    }

    editInfo.push({
        view   : "button",
        type   : "danger",
        value  : $scope.Set.CloseTitle, //mcService.Lang(103), // "103": "Отмена",
        hidden : $scope.Set.HideClose,
        height : 35,
        click  : $scope.close
    });
    editInfo.push({});

    var _view = webix.ui({
        type     : "space",
        css      : "paddingTop",
        padding  : 3,
        container: $scope.Name,
        id       : $scope.Name,
        rows: editInfo
    });

    mcService.disableContextMenu(_view);

    return _view;
}
"use strict";

function applyPanelController($scope){
    $scope.Name = mcConst.dataModels.ApplyPanel;

    var navPanel   = document.getElementById(mcConst.dataModels.NavPanel);
    var applyPanel = document.getElementById(mcConst.dataModels.ApplyPanel);

    var emptyData  = {
        data : {
            Header     : "",
            Desc       : "",
            ShowDesc   : true,
            Items      : {},
            Reopen     : false
        },
        HideClose: false,
        onClose : null,
        onApply : null
    };

    function clearData(){
        $scope.Set.data.Items = {};
        $scope.Set.data.Desc  = "";
        $scope.Set.data.Header= "";
    }

    $scope.Set = mcService.Marge({}, emptyData);

    $scope.show = function(data){
        $scope.Set.CloseTitle = mcService.Lang(103);
        $scope.Set.ApplyTitle = mcService.Lang(104);

        $scope.Set = mcService.Marge( $scope.Set, data || {});

        mcService.hideView(navPanel);
        mcService.showView(applyPanel);

        initApplyPanel($scope).adjust();

        if ($scope.Set.data.ShowDesc) {
            var desc = $$($scope.Name + 'Description');
            var text = $scope.Set.data.Desc;

            desc.define('template', text);
            desc.refresh();
        }
    };

    $scope.hide = function(){
        mcService.showView(navPanel);
        mcConst.navResize.adjust();
        mcService.hideView(applyPanel);

        $scope.Set = mcService.Marge({}, emptyData);
    };

    $scope.close = function(){
        if ($scope.Set.onClose){
            $scope.Set.onClose.apply($scope.Set);
        }

        if ($scope.Set.data.Reopen) {
            clearData();

            $scope.show(webix.copy($scope.Set));
        } else {
            $scope.hide();
        }
    };

    $scope.applyChange = function(){
        if ($scope.Set.onApply){
            if ($scope.Set.onApply($scope.Set) === false){
                return;
            }
        }

        if ($scope.Set.data.Reopen){
            clearData();

            $scope.show(webix.copy($scope.Set));
        } else {
            $scope.hide();
        }
    };

    $scope.$on('apply' + $scope.Name, $scope.applyChange);

    $scope.$on('close' + $scope.Name, $scope.close);

    $scope.$on('hide' + $scope.Name, $scope.hide);

    $scope.$on('show' + $scope.Name, function(e, args) {
        $scope.show.apply(null, args);
    });
}
"use strict";

function initServerInfo($scope){//name, info){
    var sectionHeight = 30;

    if ($$($scope.Name)) {
        $$($scope.Name).destructor();
    }

    var mcVer = "";
    var info  = $scope.data || {};

    function getItemID(val){
        return mcService.copy(val, 5, val.length - 1);
    }

    var defineServerInfoItems = [
        {
            name : mcService.Lang(10), // "10" : "Информация о сервере",
            items : [
                [mcService.Lang(17), '----', 'info_Ver'],         // "17" : "Версия", 'Version'
                [mcService.Lang(46), '----', 'info_VerDate'],     // "46" : "Дата сборки сервера",
                [mcService.Lang(18), '----', 'info_Free'],        // "18" : "Лицензия", (19: бесплатная или 48: коммерческая) 'License'
                [mcService.Lang(47), '----', 'info_RegBy'],       // "47" : "Зарегистрирован на",
                [mcService.Lang(20), '----', 'info_MaxConnects']  // "20" : "Количество подключений" 'Connections'
            ]
        }, {
            name : mcService.Lang(21), // "21" : "Общие", "Common"
            items : [
                [mcService.Lang(22), '----', 'info_Started'],     // "22" : "Сервер стартовал", 'Start server'
                [mcService.Lang(23), '----', 'info_Uptime'],      // "23" : "Работаем", 'Working time'
                [mcService.Lang(1844), '----', 'info_Connections'], // "1844": "Соединений используется",
                [mcService.Lang(24), '----', 'info_OnlineUsers'], // "24" : "Пользователей подключено",
                [mcService.Lang(25), '----', 'info_RegUsers'],    // "25" : "Пользователей зарегистрировано", 'Online users'
                [mcService.Lang(26), '----', 'info_ConfCount']   // "26" : "Каналов создано", 'Online users'
                //[mcService.Lang(27), '----', 'info_FTPServ'],     // "27" : "FTP сервер", 'Online users'
                //[mcService.Lang(28), '----', 'info_HTTPServ']     // "28" : "HTTP сервер", 'Online users'
            ]
        }, {
            name : mcService.Lang(29), // "29" : "Сообщения",
            items : [
                [mcService.Lang(30), '----', 'info_StatPrivMsgCount'],     // "30" : "Приватные",
                [mcService.Lang(31), '----', 'info_StatConfMsgCount'],     // "31" : "Конференции",
                [mcService.Lang(32), '----', 'info_StatBBSMsgCount'],      // "32" : "Доска объявлений",
                [mcService.Lang(33), '----', 'info_StatBroadcastMsgCount'],// "33" : "Оповещений",
                [mcService.Lang(97), '----', 'info_MyChatGuestInvites']    // "97" : "MyChat Guest приглашения",
            ]
        }, {
            name : mcService.Lang(34), // "34" : "Статистика",
            items : [
                [mcService.Lang(38), '----', 'info_MaxOnline'],           // "38" : "Макс. количество пользователей",
                [mcService.Lang(39), '----', 'info_FTPUsersFoldersSize'], // "39" : "Объем пользовательских папок (байт)",
                [mcService.Lang(40), '----', 'info_FTPPublicFolderSize']  // "40" : "Объем общей папки (байт)",
            ]
        }, {
            name : mcService.Lang(41), // "41" : "Трафик",
            items : [
                [mcService.Lang(42), '----', 'info_InTraffic'], // "42" : "Входящий (байт)",
                [mcService.Lang(43), '----', 'info_OutTraffic'] // "43" : "Исходящиц (байт)",
            ]
        }, {
            name : mcService.Lang(44), // "44" : "Ошибки",
            items : [
                [mcService.Lang(45), '----', 'info_ErrorsScripts']  // "45" : "Скрипты"
            ]
        }
    ];

    var serverInfoItems = [{ id: "updatesWillSoonExpired" + $scope.Name, hidden: !$scope.needShowExpiredDate, type: "layout", css: "killEyes darkShadow", cols: [
        { view: "button", type: "icon", icon: "close", width: 30, css: "white", click: function () {
            this.getParentView().hide();
        }},

        { id: "updatesWillSoonExpiredText" + $scope.Name, height: 35, template: $scope.expiredDateText, css: "white lh25 sizeBigger noBG", borderless: true, width: 450 },

        { view: "button", value: mcLang(1787), width: 150, css: "bgYellow darkGray", click: function () {// "1787":"Купить подписку",
            mcService.openLink(mcLang(1788) + "?path=u1.r2.b4&period=1&count=" + (info.MaxConnects / 10) + "&key=" + mcConst.ServerLicenseKey); // "1788":"https://nsoft-s.com/buymychat.html"
        }},

        { width: 10 },

        { view: "button", value: mcLang(1789), width: 200, css: "bgYellow darkGray", click: function () { // "1789":"А что в новых версиях?",
            mcService.openLink(mcLang(1790) + "?" + mcVer + "#" + mcConst.UserInfo.HWID); // "1790":"https://nsoft-s.com/mychatversions.html",
        }},

        { }
    ]}];

    for (var i = 0; i < defineServerInfoItems.length; i++){
        var _headTitle = { cols:[
            {   view     : "template",
                template : defineServerInfoItems[i].name,
                height   : sectionHeight,
                type     : "header"
            }
        ]};

        if (i === 0) {
            _headTitle.cols.push({ view: "toolbar", width: 120, height: 34, cols: [
                { view: "button", value: mcLang(53), padding: 0, height: 38, click: function(){ // "53" : "Обновить",
                    $scope.getData();
                }}
            ]});

            _headTitle.cols.push({ view: "toolbar", width: 36, cols: [
                {view: "button", type: "icon", icon: "question", click: function () {
                    mcService.goToHelp();
                }, width: 30}
            ]});
        }

        serverInfoItems.push(_headTitle);

        serverInfoItems.push({
            type : 'layout',
            padding: 7,
            rows : (function(items){
                var res = [];

                for (var i = 0; i < items.length; i++){
                    var _info = "";
                    var val   = getItemID(items[i][2]);

                    if (info[val] !== undefined){
                        switch (val){
                            case 'Ver'     : mcVer = info[val].split('.'); mcVer = mcVer[0] + "." + mcVer[1]; _info = info[val]; break;
                            case 'Free'    : _info = (info[val] === true) ? mcService.Lang(19) : mcService.Lang(48);           break; // "19" : "бесплатная", "48" : "коммерческая",
                            case 'Started' : _info = mcService.toNormalDate(info[val].split('.'), true);                       break;
                            case 'Uptime'  : _info = mcService.secToTime(info[val]);                                           break;
                            case 'Connections': _info = info['Connections'] + '/' + info['MaxConnects'];                       break;
                            case 'NetInterfacesList' : continue; break;
                            case 'ServicesList'      : continue; break;
                            default        : _info = (mcService.isNumber(info[val])) ? mcService.formatNumber(info[val]) : info[val];
                        }
                    }

                    res.push({
                        height: 25,
                        cols : [
                            { view:"label", label: items[i][0], width: 260},

                            ( val === "Ver"
                                ? { cols: [
                                    { view:"label", label: _info || items[i][1], id : items[i][2], width: 80},
                                    { view:"button", value: mcLang(1766), width: 150, css: "", click: function () { // "1766":"История версий",
                                        mcService.goToHelp("mychat_versions");
                                    }},
                                    {}
                                  ]}
                                : { view:"label", label: _info || items[i][1], id : items[i][2]}
                            )
                        ]
                    });
                }

                return res;
            })(defineServerInfoItems[i].items)
        });
    }

    serverInfoItems.splice(5, 0, { cols: [
        { cols:[
            { view: "template", height: sectionHeight, template: mcLang(1814), type: "header" } // "1814":"Сервисы",
        ]}
    ]});

    serverInfoItems.splice(6, 0, { padding: 7, type: "layout", height: 238, rows: [
        { cols: [
            { rows: [
                { view: "label", label: mcLang(1815), height: 36}, // "1815":"Интерфейсы",
                { view: "list", width: 260, data: info.NetInterfacesList, css: "selectable"} //NetInterfacesList ["192.168.10.1", "213.130.24.149"]
            ]},

            { width: 5},

            { view:"datatable", //scroll: false,
                columns:[
                    { header:"Enabled",   template: function (obj) {
                        return obj.value.split(',')[1];
                    }, css: "grid_area"},
                    { header:"Service",    template: function (obj) {
                        return obj.value.split(',')[0];
                    }, css: "grid_area"},
                    { header:"Protocol",   template: function (obj) {
                        return obj.value.split(',')[2];
                    }, css: "grid_area"},
                    { header:"Ports",      template: function (obj) {
                        return obj.value.split(',')[3];
                    }, css: "grid_area"},
                    { header:"IP / Hosts", template: function (obj) {
                        return obj.value.split(',').splice(4);
                    }, fillspace: true, css: "grid_area"}
                ],
                data: info.ServicesList
            } //ServicesList ["...", "..."]
        ]}
    ]});

    var res = webix.ui({
        container  : $scope.Name,
        id         : $scope.Name,
        type       : "space",
        css        : "noBorder",
        rows       : serverInfoItems
    });

    mcService.disableContextMenu(res, ["selectable"]);

    return res;
}



function serverInfoController ($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.ServerInfo;

    $scope.needShowExpiredDate = false;
    $scope.expiredDateText     = "&nbsp;";

    var angElement = document.getElementById($scope.Name);
    var icView = null;

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_server_info,
            mcConst.SessionID,

            function( data ){
                $rootScope.mcStorage.ServerInfo = data;

                $scope.show($rootScope.mcStorage.ServerInfo);
            }
        ]);
    };

    $scope.show = function(data){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        $scope.data = data;

        icView = initServerInfo($scope);

        mcService.initResize(icView, $scope.Name);
    };

    $scope.$on('licenseExpired', function(e, args){
        var data = args[0];

        setTimeout(function () {
            var warn  = $$("updatesWillSoonExpired" + $scope.Name);
            var warnT = $$("updatesWillSoonExpiredText" + $scope.Name);

            $scope.delta     = moment(new Date(mcService.formatDate(data.ServerUpdatesEndDate, "yyyy mm dd"))).startOf('day').diff(moment(new Date()).startOf('day'), 'days');
            $scope.register  = !data.IsFree;
            $scope.updateEnd =  data.ServerUpdatesEndDate;

            $scope.needShowExpiredDate = $scope.delta <= 30;

            // "1785":"Ваша подписка на обновления закончится через %s дней", "1786":"У вас нет подписки на обновления",
            $scope.expiredDateText = $scope.delta <=0 ? mcLang(1786) : mcLang(1785, $scope.delta);

            if (warnT && warn && $scope.register && $scope.needShowExpiredDate){
                warn.show();

                warnT.define('template', $scope.expiredDateText); // "1785":"Срок действия подписки на обновления закончится через %s дней", "1786":"У вас нет подписки на обновление. <a href='https://nsoft-s.com/buymychat.html' class='webixBlue' target='_blank'>Купить подписку</a>",
                warnT.refresh();
            }
        }, 100);
    });

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.getData();
    });
}

function initOnlineUsers($scope){
    "use strict";

    var view    = $$($scope.Name);
    var prefix  = "onlUsers";
    var popupLW = 15;

    if (!view){
        var filter = mcService.FilterFiled({
                listName     : prefix + $scope.Name,
                filterParams : [
                    "UIN",
                    "DisplayName",
                    "Domain",
                    "Nick",
                    "RemoteIP",
                    "ClientType"
                ],
                onClear: $scope.filterOnClear,
                onAfterFilter : $scope.filterOnClear
            });

        view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", id: prefix + "Count", type : "header", template : mcService.Lang(1564), width: 250 }, // "1564":"Онлайн пользователи",
                    { view: "toolbar", height: 36, cols: [
                        { view: "button", value: mcLang(1565), width: 100, click: $scope.disconnect},// "1565":"Отключить",
                        { view: "button", value: mcLang(1566), width: 150, click: $scope.halt},      // "1566":"Звершить работу",

                        filter,

                        { id: "refreshTimer", template: '10', borderless: true, width: 30, type: "header", css: "lh20, noBG white", hidden: false}, // Хобиту мешает счетчик
                        { view: "button", icon: "refresh", type: "icon", width: 30, click: $scope.refresh},      // "53" : "Обновить",
                        { view: "button", icon: "gear",    type: "icon", width: 30, label: mcService.Lang(56), // "56" : "Настроить"
                            css: "toolBtnCenter", popup: "gridConfigOnline"}
                    ]},
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},
                { id: prefix + $scope.Name, view: "datatable",
                    resizeColumn: true,
                    select      : "row",
                    multiselect : "tuch",
                    minColumnWidth : 80,
                    css         : "selectable",
                    leftSplit   : 2,
                    columns: [
                        {id:"UIN",         width: 70,  header: mcLang(135),  css:"left_area", sort: "int"}, //"135": "UIN",
                        {id:"CID",         width: 70,  header: "CID",        css:"left_area", sort: "int"},
                        {id:"IP",          width: 150, header: mcLang(141),  css:"grid_area", sort: "string"}, //"141":"IP адрес",
                        {id:"ClientType", adjust:"header", header: mcLang(1572) + " &nbsp;", css:"grid_area", sort: "string"},//"1572":"Тип приложения",
                        {id:"State",       width: 130, header: mcLang(1114) + " &nbsp;", css:"grid_area", sort: "string", template: function(obj){
                            var res = '';

                            switch (obj.State){
                                case 0: res = mcLang(1575); break; // "1575":"Свободен",
                                case 1: res = mcLang(1576); break; // "1576":"Нет на месте",
                                case 2: res = mcLang(1577); break; // "1577":"Не беспокоить",
                            }

                            return res;
                        }},//"1114":"Статус пользователя",
                        {id:"Nick",        width: 130, header: mcLang(58),   css:"left_area", sort: "string"},  //"58" : "Ник",
                        {id:"DisplayName", width: 200, header: mcLang(1895), css:"grid_area", sort: "string"}, //"1895":"Отображаемое имя",
                        {id:"Email",       width: 200, header: mcLang(70),   css:"grid_area", sort: "string"}, //"70" : "Email",
                        {id:"AuthType",    width: 200, header: mcLang(126),  css:"grid_area", sort: "string", template: function(obj){ //"126": "Тип авторизации",
                            var res = '';

                            switch (obj.AuthType){
                                case 0: res = mcLang(1574); break; // "1574":"UIN и пароль",
                                case 1: res = mcLang(68);   break; // "68" : "Active Directory",
                                case 2: res = mcLang(1573); break; // "1573":"Без пароля",
                                case 3: res = mcLang(68);   break; // "68" : "Active Directory",
                            }

                            return res;
                        }},
                        {id:"Domain",      width: 200, header: mcLang(123),  css:"grid_area", sort: "string"}, //"123": "Имя домена",
                        {id:"Secured",     width: 130, header: mcLang(1567), css:"grid_area", sort: "string", template: function(obj){
                            var res = mcLang(1570);

                            switch (obj.Secured){
                                case 1:
                                    res = "TLSv1.1";
                                break;

                                case 2:
                                    res = "TLSv1.2";
                                break;

                                case 3:
                                    res = "TLSv1.3";
                                break;
                            }

                            return res;// ?  : mcLang(1570); // "1570":"Без шифрования", "1571":"Шифрование TLSv1.2",
                        }},//"1567":"Шифрование",
                        {id:"HardwareID",  width: 200, header: "HardwareID", css:"grid_area", sort: "string"},
                        {id:"MAC",         width: 150, header: mcLang(142),  css:"grid_area", sort: "string"}, //"142":"MAC адрес",
                        {id:"NetName",     width: 150, header: mcLang(1893), css:"grid_area", sort: "string"}, //"1893":"Имя компьютера",
                        {id:"LastAccessUTC", width: 200, header: mcLang(1568), css:"grid_area", sort: "string", template: function(obj){
                            /** @namespace obj.LastAccessUTC */
                            return mcService.formatDate(mcService.utcTime(obj.LastAccessUTC), 'yyyy.mm.dd hh:nn:ss');
                        }},//"1568":"Дата и время подключения",
                        {id:"OnlineTime",  adjust:"header", header: mcLang(1569) + " &nbsp;", css:"grid_area", sort: "string"}, //"1569":"Время в сети",
                        {id:"Ver",         width:150, header: mcLang(1118),  css:"grid_area", sort: "string"}, // "1118":"Версия клиента",
                        {id:"OS",          width:150, header: mcLang(1894),  css:"grid_area", sort: "string"}, // "1894":"ОС",
                        {id:"UserAgent",   width:150, header: "UserAgent",   css:"grid_area", sort: "string"},
                        {id:"Reflink",     width:150, header: "Reflink",    css:"grid_area", sort: "string"},
                        {id:"Lang",        width:150, header: mcLang(6),     css:"grid_area", sort: "string"}  // "6"  : "Язык интерфейса",

                        // "Interfaces"    : "192.168.10.1,192.168.11.3",   // (6.5+) список локальных сетевых интерфейсов пользователя, может быть пустым

                    ],
                    on: {
                        onItemDblClick: $scope.openProfile,
                        onAfterSort   : $scope.sortState,
                        onBeforeContextMenu: $scope.onClickedItem
                    }
                }
            ]
        });

        $scope.gridConfigOnline = webix.ui({
            view  : "popup",
            id    : "gridConfigOnline",
            width : 250,
            body  : {
                rows :[
                    { id: "onlIP",           view: "checkbox", labelWidth: popupLW, labelRight: mcLang(141),  value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlClientType",   view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1572), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlState",        view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1114), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlNick",         view: "checkbox", labelWidth: popupLW, labelRight: mcLang(58),   value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlDisplayName",  view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1895), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlEmail",        view: "checkbox", labelWidth: popupLW, labelRight: mcLang(70),   value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlAuthType",     view: "checkbox", labelWidth: popupLW, labelRight: mcLang(126),  value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlDomain",       view: "checkbox", labelWidth: popupLW, labelRight: mcLang(123),  value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlSecured",      view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1567), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlHardwareID",   view: "checkbox", labelWidth: popupLW, labelRight: "HardwareID", value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlMAC",          view: "checkbox", labelWidth: popupLW, labelRight: mcLang(142),  value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlNetName",      view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1893), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlLastAccessUTC",view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1568), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlOnlineTime",   view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1569), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlVer",          view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1118), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlOS",           view: "checkbox", labelWidth: popupLW, labelRight: mcLang(1894), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlUserAgent",    view: "checkbox", labelWidth: popupLW, labelRight: "UserAgent",  value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlReflink",      view: "checkbox", labelWidth: popupLW, labelRight: "Reflink",    value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "onlLang",         view: "checkbox", labelWidth: popupLW, labelRight: mcLang(6),    value: 1, on: {onItemClick: $scope.ChangeUmColumns} }
                ]
            }
        });

        $scope.onlineUsers  = $$(prefix + $scope.Name);
        $scope.refreshTimer = $$("refreshTimer");
        $scope.counter      = $$(prefix + "Count");

        $scope.filterUserList = filter.doFilter;
        $scope.filterField    = filter.thisFilter;
        // $scope.filterOnClear  = filter.onClear;
        $scope.filterOnAfter  = filter.onAfterFilter;

        $scope.contextMenu = new mcService.ContextMenu($scope.onlineUsers, $scope.contextMenu, null, function(){
            $scope.regShowWindow(this.config.id, this);
        }, true,
            [{ view: "button", value: "QR Code" }],
            [ $scope.getQrCode ]
        );

        mcService.disableContextMenu(view);
    } else {

    }

    return view;
}
function onlineUsersController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.OnlineUsers;
    $scope.data = {};

    var angElement   = document.getElementById($scope.Name);
    var view         = null;
    var timerCounter = null;
    var refreshTime  = 10;
    var time         = 10;
    var state        = null;
    var scrollTo     = {x:0, y:0};

    function showTimerTime(time){
        $scope.refreshTimer.define('template', time.toString());
        $scope.refreshTimer.refresh();
    }

    function hk(haltOrKill){
        var cids = $scope.onlineUsers.getSelectedId() || null;

        if (mcService.isObject(cids)){
            cids = [cids];
        }

        if (cids && cids.length){
            for (var i = 0; i < cids.length; i ++){
                cids[i] = cids[i].id;
            }

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                haltOrKill ? mcConst._CMD_.cs_halt_cid : mcConst._CMD_.cs_kill_cid,
                mcConst.SessionID,

                cids.join(','),

                function (){
                    setTimeout($scope.refresh, 59);
                }
            ]);
        }
    }

    function setCount(cnt){
        $scope.counter.define('template', mcLang(1564) + " [" + cnt + "]");
        $scope.counter.refresh();
    }

    function sortAndSelect(){
        if (state /*&& state.select && state.select.length*/) {
            $scope.onlineUsers.setState(state);
        }

        // if ($scope.onlineUsers.sortSettings){
        //     $scope.onlineUsers.sort();
            // $scope.onlineUsers.sort(Object.keys($scope.onlineUsers.sortSettings).map(function(k){
            //     return $scope.onlineUsers.sortSettings[k]
            // }));
        // }

        // if (state && state.select && state.select.length) {
        //     $scope.onlineUsers.setState(state);
        // }
    }

    // =============================================

    $scope.disconnect = function (){
         if ($scope.onlineUsers.getSelectedId()){
             $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                 type  : "confirm-warning",
                 text  : mcService.Lang(1578), // "1578":"Отключить выбранных пользователей?",
                 ok    : mcService.Lang(114),  // "114": "да",
                 cancel: mcService.Lang(113),  // "113": "нет",
                 callback:function(yes){
                     if (yes) {
                         hk(false);

                         $scope.refresh();
                     }
                 }
             }));
         }
    };

    $scope.halt = function (){
        if ($scope.onlineUsers.getSelectedId()) {
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(1579), //"1579":"Завершить работу выбранных пользователей?",
                ok    : mcService.Lang(114),  // "114": "да",
                cancel: mcService.Lang(113),  // "113": "нет",
                callback: function (yes) {
                    if (yes) {
                        hk(true);

                        $scope.refresh();
                    }
                }
            }));
        }
    };

    $scope.refresh = function (){
        time  = refreshTime;

        showTimerTime(time);

        $scope.getData();
    };

    $scope.sortState = function(by, dir, _as){
        $scope.onlineUsers.sortSettings = {
            by : by,
            dir: dir,
            as : _as
        };
    };

    $scope.ChangeUmColumns = function(newV){
        // if (newV === 0) {
        if (this.getValue() === 0) {
            $scope.onlineUsers.hideColumn(mcService.copy(this.config.id, 3));
        } else {
            $scope.onlineUsers.showColumn(mcService.copy(this.config.id, 3));
        }

        var hiddenFields = $scope.onlineUsers.getState().hidden || [];

        $rootScope.$broadcast('saveAdminOptions', [hiddenFields.join('|'), "onlineUserSettingsState"]);
    };

    var uinForContextMenu = null;

    $scope.getQrCode = function () {
        uinForContextMenu && $rootScope.$broadcast('showQrCode', [uinForContextMenu]);
    };

    $scope.onClickedItem = function (id){
        var item = this.getItem(id);

        if (item)
            uinForContextMenu = item.UIN;
        else
            item = null;
    };

    // =============================================

    $scope.openProfile = function(id){
        var item = $scope.onlineUsers.getItem(id);

        if (item){
            $rootScope.$broadcast('show' + mcConst.dataModels.UserProfile, [item.UIN, $scope.Name]);
        }
    };

    $scope.getData = function(){
        // clearInterval(timerCounter);
        // timerCounter = null;

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_online_users_list,
            mcConst.SessionID,
            
            function( data ){
                state    = $scope.onlineUsers.getState();
                scrollTo = $scope.onlineUsers.getScrollState();

                $scope.data = data;

                for (var i = 0; i < $scope.data.length; i++){
                    // $scope.data[i].id = $scope.data[i].UIN;
                    $scope.data[i].id = $scope.data[i].CID;
                }

                $scope.onlineUsers.clearAll();
                $scope.onlineUsers.parse($scope.data);

                if ($scope.filterField) {
                    $scope.filterUserList(true, !$scope.filterField.getValue());
                }

                sortAndSelect();

                // $scope.filterOnClear = sortAndSelect;

                setCount($scope.data.length);

                setTimeout(function () {
                    $scope.onlineUsers.scrollTo(scrollTo.x, scrollTo.y);
                }, 5);
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        $scope.filterOnClear = sortAndSelect;

        view = initOnlineUsers($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();

        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_get_personal_options,
            mcConst.SessionID,

            function( data ){
                $rootScope.adminOptions = mcService.Marge($rootScope.adminOptions, data.ADMINOPT);

                var hidden = $rootScope.adminOptions.onlineUserSettingsState ? $rootScope.adminOptions.onlineUserSettingsState.split('|') : [];

                hidden.forEach(function (item) {
                    $scope.onlineUsers.hideColumn(item);

                    $$("onl" + item).setValue(false);
                });
            }
        ]);
        // $scope.gridConfigOnline
    };

    $scope.$on('hide' + $scope.Name, function() {
        state = $scope.onlineUsers.getState();

        mcService.hideView(angElement);

        clearInterval(timerCounter);
        timerCounter = null;
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.show();

        time = refreshTime;

        showTimerTime(time);

        timerCounter = setInterval(function(){
            time --;

            if (time === 0) {
                $scope.getData();

                time = refreshTime;
            }

            showTimerTime(time);
        }, 1000);

        $scope.getData();
    });

}
"use strict";

function initNssService ($scope){
    var _view = $$($scope.Name);

    if (_view){
        _view.destructor();
    }

    _view = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { type: "layout", width:800, rows: [
                    { view: "template", type: "header", template: mcService.Lang(1726) }, // "1726":"Генератор дистрибутивов",
                    { padding: 7, cols: [
                        { minWidth: 400, gravity: 4, rows: [
                            { template: mcService.insertIco("fa-info-circle") + mcLang(1727), autoheight: true, borderless: true, css: "_info selectable"},  // "1727":"Генератор дистрибутивов MyChat Distrib Maker
                            { height: 5},
                            { cols: [
                                { view: "button", value: mcLang(1728), click: $scope.gotoMDM}, // "1728":"Перейти в MyChat Distrib Maker",
                                { borderless: true, height: 30, width: 170, css: "byRight", template : mcService.insertIco('fa-shopping-cart') + '&nbsp;<a href="' + mcLang(1738) + '" target="_blank">' + mcService.Lang(1737) + '</a>'} // "1737":"Купить услугу", "1738":"https://mychat.shop.allsoft.ru/basket/add/2662588",
                            ]}
                        ]},

                        { template: '<img src="' + mcConst.imagesPath.all + 'mdm.png" alt="">', borderless: true, gravity: 1, css: "byCenter"}
                    ]}
                ]}
            ]},

            { height: 10},

            { cols: [
                { type: "layout", width: 800, rows: [
                    { view: "template", type: "header", template: mcService.Lang(1734) }, // "1734":"Удалённая установка и настройка",
                    { padding: 7, cols: [
                        { minWidth: 400, gravity: 4, rows: [
                            { template: mcService.insertIco("fa-info-circle") + mcLang(1736), autoheight: true, borderless: true, css: "_info selectable"},  // "1736":"Специалист из команды разработчиков подключается к вам через программу удалённого управления
                            { height: 5},
                            { cols: [
                                {},
                                { borderless: true, height: 30, css: "byRight", template : mcService.insertIco('fa-shopping-cart') + '&nbsp;<a href="' + mcLang(1735) + '" target="_blank">' + mcService.Lang(1737) + '</a>'} // "1737":"Купить услугу", "1735":"https://mychat.shop.allsoft.ru/basket/add/3810333",
                            ]}
                        ]},

                        { template: '<img src="' + mcConst.imagesPath.all + 'support.png" alt="">', borderless: true, gravity: 1, css: "byCenter"}
                    ]}
                ]}
            ]},
            {}
        ]
    });

    mcService.disableContextMenu(_view);

    return _view;
}
"use strict";

function nssServiceController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.NssService;

    var angElement = document.getElementById($scope.Name);

    // ==============================================

    $scope.gotoMDM = function(){
        window.open('http://mychat-server.com/custommc/', '', '');
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initNssService($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
    });
}

"use strict";

function initSupportForum ($scope){
    var _view = $$($scope.Name);

    if (!_view) {
        _view = webix.ui({
            type: "space",
            padding: 5,
            container: $scope.Name,
            id: $scope.Name,
            borderless: true,
            rows: [
                { type: "layout", padding: 4, rows: [
                    { id: "adblockfind", hidden: !window.adblock, template: mcService.insertIco("fa-info-circle") + mcLang(1732), autoheight: true, css: "_info selectable"}, // "1732":"Если форум не загрузился — пожалуйста, отключите ADBlock на этой странице",

                    { id: "frame" + $scope.Name, hidden: window.adblock, view: "iframe", src: mcLang(1733) } // "1733":"https://nsoft-s.com/forum/",
                ]}
            ]
        });

        mcService.disableContextMenu(_view);
    }

    return _view;
}
"use strict";

function supportForumController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.SupportForum;

    var angElement = document.getElementById($scope.Name);

    // ==============================================

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSupportForum($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
    });
}

function initTerminal ($scope){
    "use strict";

    var _view = $$($scope.Name);

    if (!_view){
        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { template: mcLang(2142), css: "killEyes darkShadow yellow", autoheight: true, hidden: !mcService.isIE()}, // "2142":"Функционал ограничен, воспользуйтесь более современным браузером",
                
                { type: "layout", cols: [
                    { view: "template", type: "header", template: "Terminal" }, // https://nsoft-s.com/mcserverhelp/index.html?infomychatterminal.htm
                    { view: "toolbar", width: 36, cols: [
                        { view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                // { height: 5},

                { type: "layout", rows: [
                    { id: "__terminalWrapper", css: "bgNormal terminal_scroll selectable", template: $scope.getTemplate()}
                ]}
            ]
        });

        $scope.terminalWrapper = $$("__terminalWrapper");

        $scope.terminalWrapper.getNode().addEventListener("click", $scope.focusToTerminal);

        mcService.disableContextMenu(_view);

        $scope.createTerminal();
    }

    return _view;
}
function terminalController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.Terminal;

    var angElement  = document.getElementById($scope.Name);
    var _terminal = {
        prefix: "mcserv: ",
        
        inputName: "__terminal-input",
        input    : null,

        mirrorName: "__terminal-input-mirror",
        mirror    : null,
        
        terminalName: "__terminal-output-wrapper",
        terminal    : null,

        wrapperName: "__terminal-input-wrapper",
        wrapper    : null,

        cursorName: "__terminal-cursor",
        cursor: null,

        curPosition: 0,
        curWidth: 0,

        value : "",

        cmdHistory: [],
        cmdHistoryNumb: -1,

        localCommands: {
            "help": function () {
                mcService.goToHelp("/serverhelp/" + (mcConst.Lang === "uk" ? "ua" : mcConst.Lang) + "/index.html?infomychatterminal.htm", true);
            },
            
            "clear": function () {
                var self = this;

                self.terminal.innerHTML = "";
            },

            "cls": function () {
                var self = this;

                self.terminal.innerHTML = "";
            }
        },

        remoteCommands: {
            "ping": function (data) {
                return [data.Result + " " + ((new Date()).getTime() - data.TimeStamp) + " ms"];
            }
        },

        keysHandle: function(code){
            var self = this;
            var hasSelection = null;

            if (mcService.inArrayNoStrict(code, ["Shift", "Control", "Alt"]) === -1) {
                self.curPosition = mcService.getCaretPosition(self.input);

                switch (code) {
                    case "Enter":
                        self.value       = mcService.trim(self.input.value);
                        self.input.value = "";

                        if (self.value) {
                            var div = document.createElement("pre");

                            div.innerHTML       = self.prefix + self.value;
                            div.style.marginTop = "1px";

                            self.terminal.appendChild(div);

                            var inHistory = mcService.inArrayNoStrict(self.value, self.cmdHistory);

                            if (inHistory !== -1) {
                                self.cmdHistory.splice(inHistory, 1);
                            }

                            self.cmdHistory.push(self.value);
                            self.cmdHistoryNumb = self.cmdHistory.length - 1;

                            $scope.terminalWrapper.getNode().scrollTo(0, self.wrapper.offsetTop);
                        }

                        self.mirror.innerHTML = self.prefix;

                        self.curPosition = 0;

                        var params = self.value.split(' ');
                        var _cmd   = params.shift().toLowerCase();

                        if (self.localCommands.hasOwnProperty(_cmd)){
                            self.localCommands[_cmd].apply(self, params);
                        } else
                        if (_cmd !== "") {
                            $rootScope.$broadcast('SendCMDToServer', [
                                mcConst.lockInterface,
                                mcConst._CMD_.cs_adm_terminal_command,
                                mcConst.SessionID,

                                (new Date()).getTime(),
                                _cmd,
                                params.join(' '),

                                function (data) {
                                    var res = "";

                                    if (self.remoteCommands.hasOwnProperty(data.Cmd)) {
                                        res = self.remoteCommands[data.Cmd](data);
                                    } else {
                                        res = data.Result.split(mcConst.CRLF);
                                    }

                                    res.forEach(function (line) {
                                        var div = document.createElement("pre");

                                        div.innerHTML        = line;
                                        div.style.marginTop  = "1px";
                                        div.style.marginLeft = "8px";

                                        self.terminal.appendChild(div);
                                    });

                                    $scope.terminalWrapper.getNode().scrollTo(0, self.wrapper.offsetTop);
                                }
                            ]);
                        }
                    break;

                    case "ArrowUp":
                        if (self.cmdHistoryNumb >=0 ){
                            self.value = self.input.value = self.cmdHistory[self.cmdHistoryNumb];

                            if (self.cmdHistoryNumb) self.cmdHistoryNumb--;

                            self.mirror.innerHTML = self.prefix + self.value;
                        }

                        self.curPosition = 0;
                    break;

                    case "ArrowDown":
                        if (self.cmdHistoryNumb < self.cmdHistory.length){
                            if (self.cmdHistoryNumb < (self.cmdHistory.length - 1)) {
                                self.cmdHistoryNumb++;

                                self.value = self.input.value = self.cmdHistory[self.cmdHistoryNumb];

                                self.mirror.innerHTML = self.prefix + self.value;
                            } else {
                                self.value = self.input.value = "";
                                
                                self.mirror.innerHTML = self.prefix;
                            }

                            self.curPosition = 0;
                        }
                    break;

                    default:
                        self.value = self.input.value;

                        self.mirror.innerHTML = self.prefix + self.value;

                        hasSelection = self.input.selectionEnd - self.input.selectionStart; // - self.input.selectionStart

                        self.cursor.style.backgroundColor = "green";
                }

                var pos = self.curPosition * self.curWidth - self.input.value.length * self.curWidth;

                self.cursor.style.marginLeft = pos + "px";

                if (hasSelection) {
                    self.cursor.innerHTML             = (new Array(Math.abs(hasSelection) + 1)).join("&nbsp;");
                    self.cursor.style.backgroundColor = "darkgreen";
                } else
                    
                if (self.cursor.innerText.length !== 1) {
                    self.cursor.innerHTML = "&nbsp;";
                }

                self.wrapper.scrollTo(self.curPosition * self.curWidth, 0);
            }
        },

        onfocusInput: function(){
            mcService.setCaretPosition(this.input, this.curPosition);
        },

        onblurInput: function(){
            this.curPosition = mcService.getCaretPosition(this.input);
        },

        blinkCursor: function () {
            var self = this;

            var selection = window.getSelection().toString();

            if (selection){
                mcService.copyTextToClipboard(selection);
            }

            if (self.cursor){
                setTimeout(function () {
                    mcService.hideView(self.cursor);

                    setTimeout(function () {
                        mcService.showView(self.cursor);

                        if (_terminal.input) {
                            _terminal.input.focus();
                        }
                    }, 350);
                }, 350);
            }
        }
    };

    // ==============================================

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.focusToTerminal = function(){
        _terminal.blinkCursor();
    };

    $scope.createTerminal = function(){
        _terminal.input     = document.getElementById(_terminal.inputName);
        _terminal.terminal  = document.getElementById(_terminal.terminalName);
        _terminal.mirror    = document.getElementById(_terminal.mirrorName);
        _terminal.wrapper   = document.getElementById(_terminal.wrapperName);
        _terminal.cursor    = document.getElementById(_terminal.cursorName);

        _terminal.curWidth  = _terminal.cursor.getBoundingClientRect().width;
        // _terminal.curWidth  = _terminal.cursor.offsetWidth;

        _terminal.input.onfocus = function (){
            _terminal.onblurInput();
        };

        _terminal.input.onblur  = function (){
            _terminal.onblurInput();
        };

        _terminal.input.onkeydown = function (e) {
            var code;

            if (e.key !== undefined) {
                code = e.key;
            } else
            if (e.keyIdentifier !== undefined) {
                code = e.keyIdentifier;
            } else
            if (e.keyCode !== undefined) {
                code = e.keyCode;
            }

            setTimeout(function () {
                _terminal.keysHandle(code);
            }, 10);
        };
    };

    $scope.getTemplate = function(){
        return mcService.myReplaceFormated(
            "<div id='#{out}'></div>" +
            "<div id='#{inpWrapper}'>" +
            "   <input id='#{inpName}' type='text' autofocus>" +
            "   <pre id='#{mirror}' class='inline_pre'>#{prefix}</pre><pre id='#{cursor}' class='_terminalCursor'>&nbsp;</pre>" +
            "</div>",{
                cursor    : _terminal.cursorName,
                prefix    : _terminal.prefix,
                inpName   : _terminal.inputName,
                out       : _terminal.terminalName,
                mirror    : _terminal.mirrorName,
                inpWrapper: _terminal.wrapperName
        });
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initTerminal($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();

        $scope.focusToTerminal();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
    });
}

function initUserManager($scope){
    "use strict";

    var size      = 24;
    var btnHeight = 38;
    var imgPath   = mcConst.imagesPath.all;
    var popupLW   = 15;
    var _view = $$($scope.Name);

    if (!_view){
        var toolBar = {
            view : "toolbar",
            id   : "userToolBar",
            padding : 0,
            cols : (function(){
                return []
                    .concat(mcService.checkRights(126) ? [{
                        view: "button",
                        type: "icon",
                        height: btnHeight,
                        icon: "plus",
                        label: mcService.Lang(50),
                        css: "toolBtnCenter fa2x",
                        tooltip: mcService.Lang(50) + " (Ins)",
                        on: { onItemClick: $scope.newUser.addNewUserForm }// "50" : "Добавить",
                    }] : [])
                    .concat(mcService.checkRights(127) ? [{
                        view: "button",
                        type: "icon",
                        height: btnHeight,
                        icon: "edit",
                        label: mcService.Lang(51),
                        css: "toolBtnCenter fa2x",
                        tooltip: mcService.Lang(51) + " (Enter)",
                        click: $scope.massOpenOrSingle// "51" : "Изменить",
                    }] : [])
                    .concat(mcService.checkRights(128) ? [{
                        view: "button",
                        type: "icon",
                        height: btnHeight,
                        icon: "minus",
                        label: mcService.Lang(52),
                        css: "toolBtnCenter fa2x",
                        tooltip: mcService.Lang(52) + " (Del)",
                        on :{ onItemClick: $scope.deleteUser }// "52" : "Удалить",
                    }] : [])
                    .concat([{
                        view: "button",
                        type: "icon",
                        height: btnHeight,
                        icon: "refresh",
                        label: mcService.Lang(53),
                        css: "toolBtnCenter fa2x",
                        on: {// "53" : "Обновить",
                            onItemClick: function() { $scope.requestUsersList(true) }
                        }
                    }])
                    .concat(mcService.checkRights(129) ? [{
                        view: "button",
                        type: "icon",
                        height: btnHeight,
                        icon: "close",
                        label: mcLang(2207), // "2207":"Уволить",
                        css: "toolBtnCenter fa2x",
                        click: function(){
                            var items = $scope.userData.getSelectedId();

                            if (items && (items.length > 0 || items.id)){
                                $scope.dismiss(items);
                            } else {
                                // webix.message(mcService.Lang(1480)); // "1480":"Выберите пользователей для экспорта!",
                            }
                        }
                    }] : [])
                    .concat(mcService.checkRights(129) ? [{
                        view: "button",
                        type: "icon",
                        height: btnHeight,
                        icon: "arrow-circle-o-down",
                        label: mcService.Lang(55),
                        css: "toolBtnCenter fa2x",
                        click: function(){ // "55" : "Экспорт",
                            var items = $scope.userData.getSelectedId();

                            if (items && (items.length > 0 || items.id)){
                                //$scope.exportUser.show();
                                userExportsList($scope);
                            } else {
                                webix.message(mcService.Lang(1480)); // "1480":"Выберите пользователей для экспорта!",
                            }
                        }
                    }] : [])
                    .concat([{view: "button", type: "icon", height: btnHeight, icon: "gear", label: mcService.Lang(56), css: "toolBtnCenter fa2x", popup: "gridConfig"} ]) // "56" : "Настроить"
                    .concat([{view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30} ])
            })()
        };

        var searchBar = mcService.FilterFiled({
            listName     : "userData",
            bottomSpacer : 1,
            tooltip      : mcLang(1845), // "1845":"Для поиска нажмите F3 или Crtl+F",
            filterParams : [
                "UIN",
                "DisplayName",
                "Email",
                "GroupRights",
                // "CompNetName",
                // "IP",
                // "MAC",
                // "Ver",
                "Registered",
                "Domain",
                "Nick"
            ]
        });

        $scope.__filter = searchBar;

        var userData = {
            view        : "datatable",
            resizeColumn: true,
            id          : "userData",
            select      : "row",
            multiselect : true,
            headerRowHeight:25,
            minColumnWidth : 70,
            navigation  : false,
            leftSplit   : 2,
            scheme      : {
                $init:function(item){
                    item.$css = "";

                    if (item.TeamLead){
                        item.$css += ' blue';
                    }

                    if (!item.Active) {
                        item.$css += ' red';
                    }
                },
                $update:function(item){
                    if (item.TeamLead && item.$css.indexOf('blue') === -1){
                        item.$css += ' blue';
                    } else
                    if (!item.TeamLead && item.$css.indexOf('blue') !== -1){
                        item.$css = item.$css.replace(' blue', '');
                    }

                    if (!item.Active) {
                        if (item.$css.indexOf('red') === -1){
                            item.$css += ' red';
                        }
                    } else {
                        item.$css = item.$css ? item.$css.replace(' red', '') : "";
                    }
                }
            },
            columns     : [
                { id:"Sex",           width: 40,  header:"", css: "left_area byCenter", sort: 'int', template: function (obj) {
                    return obj.Sex == 1 ? mcService.insertIco('fa-male') : (obj.Sex == 2 ? mcService.insertIco('fa-female') : mcService.insertIco('fa-question'));
                }},
                { id:"UIN",           width: 55,  header:"UIN",              sort:"int",    css: "left_area"},
                { id:"DisplayName",   width: 250, header:mcService.Lang(1895), sort:"string", css: "left_area"}, // "1895":"Отображаемое имя",
                { id:"Nick",          width: 200, header:mcService.Lang(98), sort:"string", css: "grid_area"}, // "98" : "Ник",
                { id:"Email",         width: 200, header:mcService.Lang(70), sort:"string", css: "grid_area"}, // "70" : "Email",
                { id:"GroupRights",   width: 150, header:mcService.Lang(61), sort:"string", css: "grid_area"}, // "61" : "Группа прав",
                // { id:"CompNetName",   width: 150, header:mcService.Lang(62), sort:"string", css: "grid_area"}, // "62" : "Компьютер",
                // { id:"IP",            width: 150, header:mcService.Lang(63), sort:"string", css: "grid_area"}, // "63" : "IP",
                // { id:"MAC",           width: 150, header:mcService.Lang(64), sort:"string", css: "grid_area"}, // "64" : "MAC",
                { id:"LastAccess",    width: 200, header:mcService.Lang(65), sort:"text",   css: "grid_area", template: function(obj){ // "65" : "Последнее подключение",
                    return (obj.LastAccess.indexOf('1900') >= 0) ? mcLang(1613) : mcService.sortableDate(obj.LastAccess); // "1613":"никогда",
                }},
                // { id:"Ver",           width: 70,  header:mcService.Lang(66), sort:"string", css: "grid_area"}, // "66" : "Версия",
                { id:"Registered",    width: 150, header:mcService.Lang(67), sort:"text",   css: "grid_area", template: function(obj){ // "67" : "Регистрация",
                    return mcService.sortableDate(obj.Registered);
                }},
                { id:"Domain",        width: 130, header:mcService.Lang(123), sort:"string", css: "grid_area"}, // "123": "Имя домена",
                // { id:"Active",        width: 80,  header:mcService.Lang(128), sort:"string",css: "grid_area", template: function(obj){ // "128": "Включен",
                //     return (!obj.Active) ? mcService.Lang(113) : mcService.Lang(114); // "114": "да", "113": "нет",
                // }}
                // { id:"Secured",       width: 130, header:mcService.Lang(1567), sort:"string", css: "grid_area", template: function(obj){
                //     return obj.Secured ? mcLang(1571) : mcLang(1570); // "1570":"Без шифрования", "1571":"Шифрование TLSv1.2",
                // }} // "1567":"Шифрование",
            ],
            data: [],
            on : {
                onItemDblClick : $scope.massOpenOrSingle,
                onItemClick    : $scope.inputUserToSelectedList,
                onAfterSelect  : $scope.selectUsers,
                onAfterDelete  : function(){ $scope.statusBar.setTotalCount($scope.userData.data.count()) },
                onAfterAdd     : function(){ $scope.statusBar.setTotalCount($scope.userData.data.count()) },
                onBeforeContextMenu: $scope.onClickedItem
            }
        };

        var statusBar = {
            id    : "statusBar" + $scope.Name,
            height: 22,
            borderless: true,
            padding: 0,
            css   : "statusBarStyle",
            cols  : [
                { view: "template", type: "header", template: mcService.Lang(1216) + ": 0", gravity: 2},// "1216":"Всего",
                { view: "template", type: "header", template: mcService.Lang(1217) + ": 0", gravity: 2},// "1217":"Выделено",
                { view: "template", type: "header", template: mcService.Lang(1218) + ": 0", gravity: 3},// "1218":"Заблокировано",
                { view: "template", type: "header", template: mcService.Lang(68)   + ": 0", gravity: 3},// "68" : "Active Directory",
                { view: "template", type: "header", template: mcService.Lang(1341) + ": 0", gravity: 3} // "1341":"Web-поддержка",
            ]
        };

        _view = webix.ui({
            container  : $scope.Name, //'userManager',
            id         : $scope.Name,
            type       : 'space',
            autoheight : true,
            padding    : 0,
            rows       : [
                toolBar,
                searchBar,
                userData,
                statusBar
            ]
        });

        $scope.statusBar.containers = $$("statusBar" + $scope.Name);

        var gridConfig = webix.ui({
            view  : "popup",
            id    : "gridConfig",
            width : 250,
            body  : {
                rows :[
                    { id: "chkDisplayName", view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(1895), value: 1, on: {onItemClick: $scope.ChangeUmColumns} }, // "1895":"Отображаемое имя",
                    { id: "chkNick",        view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(98), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "chkEmail",       view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(70), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "chkGroupRights", view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(61), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    // { id: "chkCompNetName", view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(62), value: 1, on: {onChange: $scope.ChangeUmColumns} },
                    // { id: "chkIP",          view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(63), value: 1, on: {onChange: $scope.ChangeUmColumns} },
                    // { id: "chkMAC",         view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(64), value: 1, on: {onChange: $scope.ChangeUmColumns} },
                    { id: "chkLastAccess",  view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(65), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    // { id: "chkVer",         view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(66), value: 1, on: {onChange: $scope.ChangeUmColumns} },
                    { id: "chkRegistered",  view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(67), value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    { id: "chkDomain",      view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(123),value: 1, on: {onItemClick: $scope.ChangeUmColumns} },
                    // { id: "chkActive",      view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(128),value: 1, on: {onItemClick: $scope.ChangeUmColumns} }
                    // { id: "chkSecured",     view: "checkbox", labelWidth: popupLW, labelRight: mcService.Lang(1567),value: 1, on: {onChange: $scope.ChangeUmColumns} } // "1567":"Шифрование",
                ]
            }
        });

        $scope.userCreateForm = webix.ui({
            view     : "window",
            position : "center",
            id       : "userCreateForm",
            modal    : true,
            head     : mcService.Lang(583), // "583": "Добавить нового пользователя",
            body     : {
                view : 'form',
                width    : 300,
                rules:{
                    "login"    : webix.rules.isNotEmpty,
                    "password" : function(val) {
                        return webix.rules.isNotEmpty(val) || $scope.userCreateForm.getChildViews()[1].elements['authType'].$getValue() === mcConst._CMD_.loginStyle.NO_PASS;
                    }
                },
                elements : [{
                    view       : "text",
                    placeholder: mcService.Lang(58) + " " + mcLang(1812), // "58" : "Ник", "1812":"или Email",
                    name       : 'login',
                    required   : "true",
                    on         : { onTimedKeyPress: $scope.newUser.onEnterNewUserName, onBlur: $scope.newUser.onEnterNewUserName}
                }, { cols: [
                    {
                        view       : "text",
                        placeholder: mcService.Lang(2), // "2"  : "Пароль",
                        type       : 'password',
                        name       : 'password',
                        required   : "true",
                        on         : { onTimedKeyPress: $scope.newUser.onEnterNewUserName, onBlur: $scope.newUser.onEnterNewUserName}
                    }, {
                        view       : "button",
                        name       : "genkey",
                        tooltip    : mcLang(1816), // "1816":"Сгенирировать пароль",
                        width      : 28,
                        type       : "icon",
                        icon       : "key",
                        click      : $scope.newUser.generateUserPwd
                    }
                ]}, {
                    view       : "checkbox",
                    labelWidth : 0,
                    name       : "showpwd",
                    labelRight : mcService.Lang(1817), // "1817":"Показать пароль",
                    css        : "finger",
                    on         : { onChange: $scope.newUser.showHidePwd }
                }, {
                    view       : "richselect",
                    name       : "authType",
                    value      : mcConst._CMD_.loginStyle.STANDARD,
                    options    : [
                        {id: mcConst._CMD_.loginStyle.STANDARD, value: mcService.Lang(111)},  // "111": "обычная авторизация",
                        // {id: mcConst._CMD_.loginStyle.AD,       value: mcService.Lang(112)},  // "112": "Active Directory авторизация",
                        {id: mcConst._CMD_.loginStyle.NO_PASS,  value: mcService.Lang(1512)}  // "1512":"Безпарольная авторизация",
                    ],
                    on         : { onChange: $scope.newUser.changeUserType }
                }, {
                    cols : [{
                        view  : "button",
                        value : mcService.Lang(104), // "104": "Сохранить",
                        name  : "save",
                        disabled: true,
                        click : $scope.newUser.addNewUser
                    }, {
                        view  : "button",
                        type  : "danger",
                        value : mcService.Lang(103), // "103": "Отмена",
                        click : function(){
                            var form    = this.getFormView();
                            var login   = form.elements['login'];
                            var pwd     = form.elements['password'];
                            var showPwd = form.elements['showpwd'];

                            form.getParentView().hide();

                            login  .$setValue('');
                            pwd    .$setValue('');
                            showPwd.setValue(0);
                        }
                    }]
                }]
            },
            on: { onShow: $scope.newUser.onShowNewUserRegForm, onHide: $scope.newUser.onHideNewRegForm }
        });

        $scope.userData = $$('userData');

        $scope.contextMenu = new mcService.ContextMenu($scope.userData, $scope.contextMenu, function(){
            var selected = $scope.userData.getSelectedItem();
            var count = selected ? selected.length : 0;

            $scope.statusBar.setSelectCount(count);
        }, function(){
            $scope.regShowWindow(this.config.id, this);
        }, true,
            [{ view: "button", value: "QR Code" }],
            [ $scope.getQrCode ]
        );

        mcService.disableContextMenu(_view);

    } else {
        _view.adjust();
    }

    webix.UIManager.setFocus(_view);

    return _view;
}
function createMassEdit($scope, jobList) {
    "use strict";

    if ($scope.massEdit){
        $scope.massEdit.destructor();
    }

    var _sex = [
        {id: '0', value: mcService.Lang(136)}, // "136":"не определен",
        {id: '1', value: mcService.Lang(137)}, // "137":"мужской",
        {id: '2', value: mcService.Lang(138)}  // "138":"женский",
    ];

    var _active = [
        {id: '1', value: mcService.Lang(110)}, // "110": "включен",
        {id: '0', value: mcService.Lang(1514)}  // "1514":"заблокирован",
    ];

    $scope.massEdit = webix.ui({
        view     : "window",
        position : "center",
        id       : "massEdit" + $scope.Name,
        modal    : true,
        width    : 400,
        head     : mcService.Lang(1110), // "1110":"Массовое изменение",
        body     : { padding: 10, rows: [
            { cols: [
                { rows: [
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(1513), css: "finger", on: { onChange: function(newV){// "1513":"Состояние",
                        $scope.massData.Active.checked = mcService.convertIntToBool(newV);
                    }}},
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(133), css: "finger", on: { onChange: function(newV){// "133":"Пол",
                        $scope.massData.Sex.checked = mcService.convertIntToBool(newV);
                    }}},
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(170), css: "finger", on: { onChange: function(newV){// "170":"Название компании",
                        $scope.massData.CompanyName.checked = mcService.convertIntToBool(newV);
                    }}},
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(1843), css: "finger", on: { onChange: function(newV){// "1843":"Название домена",
                        $scope.massData.Domain.checked = mcService.convertIntToBool(newV);
                    }}},
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(171), css: "finger", on: { onChange: function(newV){// "171":"Должность",
                        $scope.massData.Position.checked = mcService.convertIntToBool(newV);
                    }}},
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(172), css: "finger", on: { onChange: function(newV){// "172":"Подразделение",
                        $scope.massData.WorkDept.checked = mcService.convertIntToBool(newV);
                    }}}, // , disabled: true
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(173), css: "finger", on: { onChange: function(newV){// "173":"Офис",
                        $scope.massData.Office.checked = mcService.convertIntToBool(newV);
                    }}},
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(61),  css: "finger", on: { onChange: function(newV){// "61" : "Группа прав",
                        $scope.massData.GroupRights.checked = mcService.convertIntToBool(newV);
                    }}}
                ]},
                { rows: [
                    { view: "select", options: _active, value: '1', on: {onChange: function(newV){
                        $scope.massData.Active.value = mcService.convertIntToBool(newV);
                    }}},
                    { view: "select", options: _sex, value: 0, on: {onChange: function(newV){
                        $scope.massData.Sex.value = newV;
                    }}},
                    { view: "text",  on: {onChange: function(newV){
                        $scope.massData.CompanyName.value = newV;
                    }}},
                    { view: "text",  on: {onChange: function(newV){
                        $scope.massData.Domain.value = newV;
                    }}},
                    { view: "select", id: "massEditWorkPosition", options: [], on: {onChange: function(newV){
                        $scope.massData.Position.value = newV;
                    }}},
                    { view: "select", id: "massDeptList", options: [], on: {onChange: function(newV){
                        $scope.massData.WorkDept.value = newV;
                    }}},
                    { view: "text",  on: {onChange: function(newV){
                        $scope.massData.Office.value = newV;
                    }}},
                    { view: "select", id: "massGroupRights", options: [], on: {onChange: function(newV){
                        $scope.massData.GroupRights.value = newV;
                    }}}
                ]}
            ]}, {height: 5},

            // "169":"Место работы",
            { template: mcService.Lang(169), borderless: true, type: "header"},{height: 5},

            { cols: [
                { rows: [
                    // "163":"Дом, улица",
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(163), css: "finger", on: { onChange: function(newV){
                        $scope.massData.WorkAddress.checked = mcService.convertIntToBool(newV);
                    }}},
                    // "164":"Город",
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(164), css: "finger", on: { onChange: function(newV){
                        $scope.massData.WorkCity.checked = mcService.convertIntToBool(newV);
                    }}},
                    // "165":"Штат / Область / Край",,
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(165), css: "finger", on: { onChange: function(newV){
                        $scope.massData.WorkState.checked = mcService.convertIntToBool(newV);
                    }}},
                    // "166":"ZIP / Почтовый индекс",
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(166), css: "finger", on: { onChange: function(newV){
                        $scope.massData.WorkZIP.checked = mcService.convertIntToBool(newV);
                    }}},
                    // "167":"Страна",
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(167), css: "finger", on: { onChange: function(newV){
                        $scope.massData.WorkCountry.checked = mcService.convertIntToBool(newV);
                    }}},
                    // "178":"WWW страница",
                    { view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(178), css: "finger", on: { onChange: function(newV){
                        $scope.massData.WorkWWW.checked = mcService.convertIntToBool(newV);
                    }}}, {height: 5},
                    { view: "button", value: mcService.Lang(104), click: function(){ // "104": "Сохранить",
                        var checked = 0;

                        for (var i in $scope.massData){
                            checked = checked || $scope.massData[i].checked;
                        }

                        if (checked){
                            $scope.massSave($scope.userData.getSelectedItem());
                            $scope.massEdit.hide();
                        }
                    }}
                ]},
                { rows: [
                    { view: "text", on: {onChange: function(newV){
                        $scope.massData.WorkAddress.value = newV;
                    }}},
                    { view: "text", on: {onChange: function(newV){
                        $scope.massData.WorkCity.value = newV;
                    }}},
                    { view: "text", on: {onChange: function(newV){
                        $scope.massData.WorkState.value = newV;
                    }}},
                    { view: "text", on: {onChange: function(newV){
                        $scope.massData.WorkZIP.value = newV;
                    }}},
                    { view: "select",options: mcService.GetCountriesList(), on: {onChange: function(newV){
                        $scope.massData.WorkCountry.value = newV;
                    }}},
                    { view: "text", on: {onChange: function(newV){
                        $scope.massData.WorkWWW.value = newV;
                    }}}, {height: 5},
                    { view: "button", type: "danger", value: mcService.Lang(103), click : function(){ // "103": "Отмена",
                        $scope.massEdit.hide();
                    }}
                ]}
            ]}
        ]},
        on: {
            onShow: function () {
                $scope.regShowWindow(this.config.id, this);

                $scope.massEditHotKeys();
            },
            onHide: function () {
                $scope.removeMassEditHotKeys();

                $scope.registerHotKeys();
            }
        }
    });

    $$("massDeptList")   .define('options', $scope.workDepts);
    $$("massGroupRights").define('options', $scope.GroupList);
    
    $$("massEditWorkPosition").define('options', jobList);

    // webix.UIManager.addHotKey("Esc", function() {
    //     $scope.massEdit.hide();
    //
    //     return false;
    // }, $scope.massEdit);

    $scope.massEdit.show();
}

﻿function userExportsList($scope) {
    "use strict";

    if (!$scope.exportUser){
        $scope.exportUser = webix.ui({
            view     : "window",
            position : "center",
            modal    : true,
            width    : 550,
            height   : 500,
            head     : mcService.Lang(1111), // "1111":"Экспорт пользователей",
            body     : { padding: 10, rows: [
                { view: "list", id: "exportList", select: "multiselect", multiselect:"touch", drag:"order", data: [
                    {id:"AuthType",               value:mcService.Lang(126)  + "<span style='float:right'>AuthType</span>" },// "126": "Тип авторизации",
                    {id:"UIN",                    value:mcService.Lang(1112) + "<span style='float:right'>UIN</span>"},// - "1112":"Числовой идентификатор пользователя",",
                    // {id:"RemoteClientType",       value:mcService.Lang(1532) + "<span style='float:right'>RemoteClientType</span>"},// "1532":"Тип клиентского приложения",
                    // {id:"RemoteInterfacesList",   value:mcService.Lang(1113) + "<span style='float:right'>RemoteInterfacesList</span>"},// - "1113":"Список локальных сетевых интерфейсов",",
                    {id:"LastAccess",             value:mcService.Lang(65)   + "<span style='float:right'>LastAccess</span>"},// - "65" : "Последнее подключение",
                    {id:"LastSpeakTime",          value:mcService.Lang(143)  + "<span style='float:right'>LastSpeakTime</span>"},// - "143":"Последняя отправка сообщения",
                    {id:"State",                  value:mcService.Lang(1114) + "<span style='float:right'>State</span>"},// - "1114":"Статус пользователя",,
                    {id:"Tag",                    value:mcService.Lang(108)  + "<span style='float:right'>Tag</span>"},// - "108": "Тег (служебная информация)",
                    // {id:"HardwareID",             value:mcService.Lang(1115) + "<span style='float:right'>HardwareID</span>"},// - "1115":"Идентификатор компьютера клиента",,
                    {id:"Domain",                 value:mcService.Lang(123)  + "<span style='float:right'>Domain</span>"},// - "123": "Имя домена",
                    // {id:"DomainRegTime",          value:mcService.Lang(1116) + "<span style='float:right'>DomainRegTime</span>"},// - "1116":"Дата регистрации в домене",,
                    // {id:"DomainChangeTime",       value:mcService.Lang(1117) + "<span style='float:right'>DomainChangeTime</span>"},// - "1117":"Дата последнего изменения данных о пользователе в домене",
                    // {id:"Ver",                    value:mcService.Lang(1118) + "<span style='float:right'>Ver</span>"},// - "1118":"Версия клиента",
                    // {id:"UTC",                    value:mcService.Lang(1119) + "<span style='float:right'>UTC</span>"},// - "1119":"UTC смещение локального времени клиента",,
                    {id:"Reputation",             value:mcService.Lang(1120) + "<span style='float:right'>Reputation</span>"},// - "1120":"Репутация пользователя, целое число",",
                    {id:"Nick",                   value:mcService.Lang(58)   + "<span style='float:right'>Nick</span>"},// "58" : "Ник",
                    {id:"DisplayName",            value:mcService.Lang(1121) + "<span style='float:right'>DisplayName</span>"},// - "1121":"Имя пользователя в чате",
                    {id:"Email",                  value:mcService.Lang(134)  + "<span style='float:right'>Email</span>"},// - "134":"Основной E-mail",
                    {id:"GroupRights",            value:mcService.Lang(144)  + "<span style='float:right'>GroupRights</span>"},// - "144":"Группа прав",
                    // {id:"CompNetName",            value:mcService.Lang(62)   + "<span style='float:right'>CompNetName</span>"},// "62" : "Компьютер",
                    // {id:"IP",                     value:mcService.Lang(141)  + "<span style='float:right'>IP</span>"},// "141":"IP адрес",
                    // {id:"MAC",                    value:mcService.Lang(142)  + "<span style='float:right'>MAC</span>"},// "142":"MAC адрес",
                    {id:"Registered",             value:mcService.Lang(1133) + "<span style='float:right'>Registered</span>"},// "1133":"Дата регистрации",
                    {id:"Active",                 value:mcService.Lang(128)  + "/" + mcService.Lang(109) + "<span style='float:right'>Active</span>"},// - "128":"Включен", / "109": "выключен",
                    {id:"LastName",               value:mcService.Lang(131)  + "<span style='float:right'>LastName</span>"},// "131":"Фамилия",
                    {id:"FirstName",              value:mcService.Lang(129)  + "<span style='float:right'>FirstName</span>"},// "129":"Имя",
                    {id:"MiddleName",             value:mcService.Lang(130)  + "<span style='float:right'>MiddleName</span>"},// "130":"Отчество",
                    {id:"Sex",                    value:mcService.Lang(133)  + "<span style='float:right'>Sex</span>"},// "133":"Пол",
                    {id:"Birthday",               value:mcService.Lang(149)  + "<span style='float:right'>Birthday</span>"},// "149":"Дата рождения",
                    {id:"Marital",                value:mcService.Lang(150)  + "<span style='float:right'>Marital</span>"},// "150":"Семейное положение",
                    {id:"HomePhone",              value:mcService.Lang(1122) + "<span style='float:right'>HomePhone</span>"},// "1122":"Домашний телефон",,
                    {id:"HomeAddress",            value:mcService.Lang(1123) + "<span style='float:right'>HomeAddress</span>"},// "1123":"Домашний адрес: дом, улица",,
                    {id:"HomeFax",                value:mcService.Lang(1124) + "<span style='float:right'>HomeFax</span>"},// "1124":"Домашний факс",
                    {id:"HomeCellular",           value:mcService.Lang(161)  + "<span style='float:right'>HomeCellular</span>"},// "161":"Мобильный",
                    {id:"HomeCountry",            value:mcService.Lang(1126) + "<span style='float:right'>HomeCountry</span>"},// "1126":"Домашний адрес: страна",
                    {id:"HomeCity",               value:mcService.Lang(1127) + "<span style='float:right'>HomeCity</span>"},// "1127":"Домашний адрес: город",
                    {id:"HomeState",              value:mcService.Lang(1128) + "<span style='float:right'>HomeState</span>"},// "1128":"Домашний адрес: штат / провинция / область / край",
                    {id:"HomeZIP",                value:mcService.Lang(1129) + "<span style='float:right'>HomeZIP</span>"},// "1129":"Домашний адрес: ZIP / почтовый индекс",
                    {id:"HomeWWW",                value:mcService.Lang(1130) + "<span style='float:right'>HomeWWW</span>"},// "1130":"Домашняя WEB-страничка",
                    {id:"CompanyName",            value:mcService.Lang(170)  + "<span style='float:right'>CompanyName</span>"},// "170":"Название компании",
                    {id:"WorkPosition",           value:mcService.Lang(171)  + "<span style='float:right'>WorkPosition</span>"},// "171":"Должность",
                    {id:"WorkDept",               value:mcService.Lang(172)  + "<span style='float:right'>WorkDept</span>"},// "172":"Подразделение",
                    {id:"WorkOffice",             value:mcService.Lang(173)  + "<span style='float:right'>WorkOffice</span>"},// "173":"Офис",
                    {id:"WorkPhone",              value:mcService.Lang(174)  + "<span style='float:right'>WorkPhone</span>"},// "174":"Телефон",
                    {id:"WorkFax",                value:mcService.Lang(160)  + "<span style='float:right'>WorkFax</span>"},// "160":"Факс",
                    {id:"WorkPager",              value:mcService.Lang(176)  + "<span style='float:right'>WorkPager</span>"},// "176":"Пейджер",
                    {id:"WorkAddress",            value:mcService.Lang(177)  + "<span style='float:right'>WorkAddress</span>"},// "177":"Рабочий адрес",
                    {id:"WorkCity",               value:mcService.Lang(164)  + "<span style='float:right'>WorkCity</span>"},// "164":"Город",
                    {id:"WorkState",              value:mcService.Lang(165)  + "<span style='float:right'>WorkState</span>"},// "165":"Штат / Область / Край",
                    {id:"WorkZIP",                value:mcService.Lang(166)  + "<span style='float:right'>WorkZIP</span>"},// "166":"ZIP / Почтовый индекс",
                    {id:"WorkCountry",            value:mcService.Lang(167)  + "<span style='float:right'>WorkCountry</span>"},// "167":"Страна",
                    {id:"WorkWWW",                value:mcService.Lang(178)  + "<span style='float:right'>WorkWWW</span>"},// "178":"WWW страница",
                    {id:"Lang1",                  value:mcService.Lang(179)  + "<span style='float:right'>Lang1</span>"},// "179":"Владение языками",
                    {id:"Lang2",                  value:mcService.Lang(179)  + "<span style='float:right'>Lang2</span>"},// "179":"Владение языками",
                    {id:"Lang3",                  value:mcService.Lang(179)  + "<span style='float:right'>Lang3</span>"},// "179":"Владение языками",
                    {id:"PersonalInterests1",     value:mcService.Lang(493)  + "<span style='float:right'>PersonalInterests1</span>"},// - "493":"Личные интересы",
                    {id:"PersonalInterestsText1", value:mcService.Lang(1125) + "<span style='float:right'>PersonalInterestsText1</span>"},// "1125":"Личные интересы, ключевые слова",
                    {id:"PersonalInterests2",     value:mcService.Lang(493)  + "<span style='float:right'>PersonalInterests2</span>"},// - "493":"Личные интересы",
                    {id:"PersonalInterestsText2", value:mcService.Lang(1125) + "<span style='float:right'>PersonalInterestsText2</span>"},// "1125":"Личные интересы, ключевые слова",
                    {id:"PersonalInterests3",     value:mcService.Lang(493)  + "<span style='float:right'>PersonalInterests3</span>"},// - "493":"Личные интересы",
                    {id:"PersonalInterestsText3", value:mcService.Lang(1125) + "<span style='float:right'>PersonalInterestsText3</span>"},// "1125":"Личные интересы, ключевые слова",
                    {id:"PersonalInterests4",     value:mcService.Lang(493)  + "<span style='float:right'>PersonalInterests4</span>"},// - "493":"Личные интересы",
                    {id:"PersonalInterestsText4", value:mcService.Lang(1125) + "<span style='float:right'>PersonalInterestsText4</span>"},// "1125":"Личные интересы, ключевые слова",
                    {id:"Past1",                  value:mcService.Lang(544)  + "<span style='float:right'>Past1</span>"},// "544":"Прошлое",
                    {id:"PastText1",              value:mcService.Lang(1131) + "<span style='float:right'>PastText1</span>"},// "1131":"Прошлое, ключевые слова",
                    {id:"Past2",                  value:mcService.Lang(544)  + "<span style='float:right'>Past2</span>"},// "544":"Прошлое",
                    {id:"PastText2",              value:mcService.Lang(1131) + "<span style='float:right'>PastText2</span>"},// "1131":"Прошлое, ключевые слова",
                    {id:"Past3",                  value:mcService.Lang(544)  + "<span style='float:right'>Past3</span>"},// "544":"Прошлое",
                    {id:"PastText3",              value:mcService.Lang(1131) + "<span style='float:right'>PastText3</span>"},// "1131":"Прошлое, ключевые слова",
                    {id:"PastOrg1",               value:mcService.Lang(545)  + "<span style='float:right'>PastOrg1</span>"},// "545":"Типы организаций",
                    {id:"PastOrgText1",           value:mcService.Lang(1132) + "<span style='float:right'>PastOrgText1</span>"},// "1132":"Типы организаций, ключевые слова",
                    {id:"PastOrg2",               value:mcService.Lang(545)  + "<span style='float:right'>PastOrg2</span>"},// "545":"Типы организаций",
                    {id:"PastOrgText2",           value:mcService.Lang(1132) + "<span style='float:right'>PastOrgText2</span>"},// "1132":"Типы организаций, ключевые слова",
                    {id:"PastOrg3",               value:mcService.Lang(545)  + "<span style='float:right'>PastOrg3</span>"},// "545":"Типы организаций",
                    {id:"PastOrgText3",           value:mcService.Lang(1132) + "<span style='float:right'>PastOrgText3</span>"},// "1132":"Типы организаций, ключевые слова",
                    {id:"Comments",               value:mcService.Lang(574)  + "<span style='float:right'>Comments</span>"}// "574":"Дополнительно",
                ], onContext:{}},
                { height: 5 },
                { cols: [
                    { view: "button", value: mcService.Lang(104), click: function(){ // "104": "Сохранить",
                        var items = $$("exportList").getSelectedId();

                        if (items && (items.length > 0 || items.id)){
                            $scope.exportToCSV($$("exportList"));
                            $scope.exportUser.hide();
                        } else {
                            webix.message(mcService.Lang(140)); // "140": "Ничего не выбрано",
                        }
                    }},
                    { view: "button", type: "danger", value: mcService.Lang(103), click : function(){ // "103": "Отмена",
                        $scope.exportUser.hide();
                    }}
                ]}
            ]},
            on: { onShow: function(){ $scope.regShowWindow(this.config.id, this); } }
        });

        $scope.contextMenuExport = new mcService.ContextMenu($$("exportList"), $scope.contextMenuExport, null, function(){
            $scope.regShowWindow(this.config.id, this);
        }, true);

        $$("exportList").sort("value", "asc");

        webix.UIManager.addHotKey("Esc", function() {
            $scope.exportUser.hide();

            return false;
        }, $scope.exportUser);

        webix.UIManager.addHotKey("Esc", function() {
            $scope.exportUser.hide();

            return false;
        }, $$("exportList"));

        mcService.disableContextMenu($scope.exportUser);
    }

    $scope.exportUser.show();
}

function userManagerController($scope, $rootScope){
    "use strict";

    $scope.Name      = mcConst.dataModels.UserManager;
    $scope.data      = [];
    $scope.selectedUINs = [];
    $scope.userData  = null;
    $scope.workDepts = [];
    $scope.statusBar = {
        containers : null,
        blockedUsersCount : 0,
        ad : 0,
        web: 0
    };
    $scope.massData  = {};

    var defaultMassDataValues = {
        Active      : { checked: false, value: true },
        Sex         : { checked: false, value: '0'},
        CompanyName : { checked: false, value: '' },
        Domain      : { checked: false, value: '' },
        Position    : { checked: false, value: '0'},
        WorkDept    : { checked: false, value: '0'},
        Office      : { checked: false, value: '' },
        WorkAddress : { checked: false, value: '' },
        WorkCity    : { checked: false, value: '' },
        WorkState   : { checked: false, value: '' },
        WorkZIP     : { checked: false, value: '' },
        WorkCountry : { checked: false, value: '0'},
        WorkWWW     : { checked: false, value: '' },
        GroupRights : { checked: false, value: '' },
    };
    var angElement = document.getElementById($scope.Name);
    var mcView     = null;
    var needRefreshOnShow = false;
    var xPosition  = 0;

    $rootScope.ErrorActions[306] = $rootScope.ErrorActions[308] =
    $rootScope.ErrorActions[310] = function(){ // "310": "пользователь с UIN %s уже заблокирован, увольнение невозможно"
        // удаляем колбек на увольнение
        $rootScope.customCallBack[mcConst._CMD_.cs_adm_fire_users].shift();
    };

    // ===========================================================

    function getSelectedUser(){
        var user = null;

        if (mcService.isArray($scope.selectedUINs) && $scope.selectedUINs.length > 0){
            user = $scope.selectedUINs[$scope.selectedUINs.length - 1];
        } else if(mcService.isObject($scope.selectedUINs)) {
            user = $scope.selectedUINs
        } else {
            //throw new Error('Can\'t open user, no selected user');
            webix.message(mcService.Lang(962)); // "962":"Сначала выберите пользователя!",
        }

        return user;
    }

    function getSelectedUINsList (ignore){
        var selectedItems = $scope.userData.getSelectedItem(true);
        var user     = getSelectedUser();
        var UINs     = "";

        if (selectedItems){
            if (selectedItems.length && selectedItems.length > 1){

                UINs = [];

                for (var i = 0; i < selectedItems.length; i++){
                    if (selectedItems[i].UIN == mcConst.UserInfo.UIN && !ignore){
                        webix.alert(mcService.Lang(1109)); // "1109":"Вы не можете удалить себя",

                        return [];
                    }

                    UINs.push(selectedItems[i].UIN);
                }

                UINs = UINs.join(',');
            } else {
                if (user.UIN == mcConst.UserInfo.UIN && !ignore){
                    webix.alert(mcService.Lang(1109)); // "1109":"Вы не можете удалить себя",

                    return [];
                }

                UINs = user.UIN;
            }
        }

        return UINs.toString();
    }

    function getUserInfoByPreset(uin){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_user_info_by_preset,
            mcConst.SessionID,
            uin,
            mcConst.userFields,
            $scope.refreshUser
        ]);
    }

    // ===========================================================

    var uinForContextMenu = null;

    $scope.getQrCode = function () {
        uinForContextMenu && $rootScope.$broadcast('showQrCode', [uinForContextMenu]);
    };

    $scope.onClickedItem = function (id){
        var item = this.getItem(id);

        if (item)
            uinForContextMenu = item.UIN;
        else
            item = null;
    };

    $scope.registerHotKeys = function(){
        var upDownMove = null;

        function moveFirstLast(moveId) {
            var selectedItem = $scope.userData.getSelectedId();
            var lastID = moveId;

            if ( selectedItem && selectedItem.id != lastID){
                $scope.userData.showItem(lastID);
                $scope.userData.select(lastID);

                var node = $scope.userData.getItemNode(lastID);

                if(node){
                    node.focus();
                }
            }
        }

        function moveUpDown(newID, shift) {
            $scope.userData.select(newID, shift ? true : false);
            $scope.userData.showItem(newID);

            var node = $scope.userData.getItemNode(newID);

            if(node){
                node.focus();
            }
        }

        function adown(e) {
            var selectedItem = $scope.userData.getSelectedId();

            if (!selectedItem){
                $scope.userData.select($scope.userData.getFirstId());

                selectedItem = $scope.userData.getSelectedId()
            }

            if (selectedItem.length){
                selectedItem = selectedItem[selectedItem.length - 1];
            }

            if (selectedItem && selectedItem.id !== undefined){
                var idx   = $scope.userData.getIndexById(selectedItem.id) + 1;
                var newID = $scope.userData.getIdByIndex(Math.min($scope.userData.count()-1, idx));

                moveUpDown(newID, e.shiftKey);
            }

            $scope.statusBar.setSelectCount($scope.userData.getSelectedId().length || 1);
        }

        function aup (e) {
            var selectedItem = $scope.userData.getSelectedId();

            if (!selectedItem) {
                $scope.userData.select($scope.userData.getFirstId());

                selectedItem = $scope.userData.getSelectedId()
            }

            if (selectedItem.length) {
                selectedItem = selectedItem[selectedItem.length - 1];
            }

            if (selectedItem && selectedItem.id !== undefined) {
                var idx = $scope.userData.getIndexById(selectedItem.id) - 1;
                var newID = $scope.userData.getIdByIndex(Math.max(0, idx));

                moveUpDown(newID, e.shiftKey);
            }

            $scope.statusBar.setSelectCount($scope.userData.getSelectedId().length || 1);
        }

        $rootScope.hotKeyDispatcher.addPreset($scope.Name + "Preset", [{
            key:  mcConst.keyCodes.end,
            func: function () {
                if (webix.UIManager.hasFocus($scope.__filter.thisFilter)) {
                    return true;
                }

                moveFirstLast($scope.userData.getLastId());
            }
        }, {
            key:  mcConst.keyCodes.home,
            func: function () {
                if (webix.UIManager.hasFocus($scope.__filter.thisFilter)) {
                    return true;
                }

                moveFirstLast($scope.userData.getFirstId());
            }
        }, {
            key: mcConst.keyCodes.adown,
            func: adown
        }, {
            key: mcConst.keyCodes.adown,
            shiftKey: true,
            func: adown
        }, {
            key: mcConst.keyCodes.aup,
            func: aup
        }, {
            key: mcConst.keyCodes.aup,
            shiftKey: true,
            func: aup
        }, {
            key: mcConst.keyCodes.pagedown,
            func: function () {
                if (!upDownMove)
                upDownMove = setTimeout(function () {
                    var selectedItem = $scope.userData.getSelectedId();

                    if (selectedItem.length){
                        selectedItem = selectedItem[selectedItem.length - 1];
                    }

                    if (selectedItem && selectedItem.id !== undefined){
                        var idx   = $scope.userData.getIndexById(selectedItem.id) + 20;
                        var newID = $scope.userData.getIdByIndex(Math.min($scope.userData.count()-1, idx));

                        moveUpDown(newID);
                    }

                    upDownMove = null;
                }, 10);
            }
        }, {
            key: mcConst.keyCodes.pageup,
            func: function () {
                if (!upDownMove)
                upDownMove = setTimeout(function () {
                    var selectedItem = $scope.userData.getSelectedId();

                    if (selectedItem.length){
                        selectedItem = selectedItem[selectedItem.length - 1];
                    }

                    if (selectedItem && selectedItem.id !== undefined) {
                        var idx   = $scope.userData.getIndexById(selectedItem.id) - 20;
                        var newID = $scope.userData.getIdByIndex(Math.max(0, idx));

                        moveUpDown(newID);
                    }

                    upDownMove = null;
                }, 10);
            }
        }, {
            key: mcConst.keyCodes.aleft,
            func: function () {
                if (webix.UIManager.hasFocus($scope.__filter.thisFilter)) {
                    return true;
                }

                xPosition = $scope.userData.getScrollState().x;

                if (xPosition > 0) {
                    xPosition -= 50;

                    $scope.userData.scrollTo(xPosition, $scope.userData.getScrollState().y);
                }
            }
        }, {
            key: mcConst.keyCodes.aright,
            func: function () {
                if (webix.UIManager.hasFocus($scope.__filter.thisFilter)) {
                    return true;
                }

                var max = 0;

                $scope.userData.getState().size.forEach(function (val) {
                    max += val;
                });

                xPosition = $scope.userData.getScrollState().x;

                if (xPosition < (max - $scope.userData.$width)){
                    xPosition += 50;

                    $scope.userData.scrollTo(xPosition, $scope.userData.getScrollState().y);
                }
            }
        }, {
            key: mcConst.keyCodes.delete,
            func: function () {
                if (webix.UIManager.hasFocus($scope.__filter.thisFilter)) {
                    return true;
                }

                $scope.deleteUser();
            }
        }, {
            key: mcConst.keyCodes.insert,
            func: function () {
                if (webix.UIManager.hasFocus($scope.__filter.thisFilter)) {
                    return true;
                }

                $scope.newUser.addNewUserForm();
            }
        }, {
            key: mcConst.keyCodes.enter,
            func: function () {
                webix.UIManager.setFocus(document);

                $scope.massOpenOrSingle();
            }
        }, {
            key: mcConst.keyCodes.f3,
            func: function () {
                $scope.__filter.thisFilter.focus();
            }
        }, {
            key: mcConst.keyCodes.f,
            ctrlKey: true,
            func: function () {
                $scope.__filter.thisFilter.focus();
            }
        }], document, true);
    };

    $scope.massEditHotKeys = function () {
        $rootScope.hotKeyDispatcher.addPreset($scope.Name + "MassEdit", [{
            key:  mcConst.keyCodes.esc,
            func: function () {
                $scope.massEdit.hide();
            }
        }], document, true);
    };
    
    $scope.removeMassEditHotKeys = function () {
        $rootScope.hotKeyDispatcher.removePreset($scope.Name + "MassEdit");
    };

    $scope.removeHotKey = function(){
        $rootScope.hotKeyDispatcher.removePreset($scope.Name + "Preset");
    };

    $scope.addUserToList = function(uin){
        $scope.userData.add({
            "UIN"           : uin,
            "DisplayName"   : $scope.addedUserName,
            "Email"         : '',
            "GroupRights"   : 'Guests',
            "CompNetName"   : '',
            "IP"            : '',
            "MAC"           : '',
            "LastAccess"    : mcConst.neverDate,
            "Ver"           : '',
            "DomainRegTime" : mcConst.neverDate,
            "Registered"    : mcConst.neverDate,
            "Domain"        : '',
            "Active"        : true,
            "Secured"       : false,
            "Sex"           : 0
        });

        $scope.userData.select($scope.userData.getLastId());
        $scope.userData.scrollTo(0, 9999999);

        $scope.statusBar.setSelectCount(1);

        $scope.updateCounters();

        $scope.addedUserName = '';
    };

    $scope.refreshUser = function(updateInfo){
        if (mcView && $scope.userData) {
            var sel = $scope.userData.getSelectedId() || $scope.selectedUINs;
            var row = null;
            var id  = null;

            if (mcService.isArray(sel)){

                for (var i = 0; i < sel.length; i++){
                    id = sel[i].row || sel[i].id;

                    row = mcService.Marge($scope.userData.getItem(id), updateInfo);

                    $scope.userData.updateItem(id, row);
                }
            } else {
                id = sel.row || sel.id;

                row = mcService.Marge($scope.userData.getItem(id), updateInfo);

                $scope.userData.updateItem(id, row);
            }

            $scope.updateCounters();
        }
    };

    $scope.massSave = function(userList){
        var fieldsList = [];
        var resFields = {};
        var res = {};

        for (var i in $scope.massData){
            if ($scope.massData[i].checked){
                fieldsList.push(i);
                resFields[i] = $scope.massData[i].value;
            }
        }

        res = mcService.Marge({
            UsersList: (function(list){
                var res = [];
                for (var i in list){
                    res.push(list[i].UIN);
                }
                return res.join(',');
            }(userList)),
            Fields   : fieldsList.join(',')
        }, resFields);

        if ($scope.massData.Active.checked){
            $scope.refreshUser({
                Active: $scope.massData.Active.value
            });
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_multiply_modify_users,
            mcConst.SessionID,
            JSON.stringify(res)
        ]);

        if ($scope.massData.Domain.value) {
            $scope.refreshUser({Domain : $scope.massData.Domain.value});
        }

        if ($scope.massData.GroupRights.value) {
            $scope.refreshUser({GroupRights : $scope.GroupList[mcService.findItemInArrayOfObj($scope.GroupList, $scope.massData.GroupRights.value, "id")].value});
        }
    };

    $scope.massOpenOrSingle = function(){
        var items = $scope.userData.getSelectedId();

        if (mcService.isObject(items) && items.id){
            $scope.openUserProfile();
        } else
        if (mcService.isArray(items) && mcService.checkRights(130)){
            var task = new mcService.TaskList();

            task.AddTask(function () {
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_list_roles,
                    mcConst.SessionID,
                    function ( data ){
                        $rootScope.mcStorage[mcConst.dataModels.GroupRights] = data;

                        task.Next();
                    }
                ]);
            });

            task.AddTask(function () {
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_get_depts_list,
                    mcConst.SessionID,
                    function (data) {
                        var jobList = mcService.transformDataObject(webix.copy($rootScope.mcStorage[mcConst.dataModels.WorkPositions]), [['Name', 'value'], ['ID', 'id']]);
                        var grpList = mcService.transformDataObject(webix.copy($rootScope.mcStorage[mcConst.dataModels.GroupRights]), [['Name', 'value'], ['ID', 'id']]);

                        $scope.workDepts = [];

                        $scope.workDepts = mcService.formatDeptList(data);

                        $scope.GroupList = grpList;

                        //$scope.massEdit.selectedUsers = items;

                        $scope.workDepts.unshift({ id: '-1', value: "---" });
                        $scope.GroupList.unshift({ id: '-1', value: "---" });

                        jobList.unshift({ id: '-1', value: "---" });

                        //$scope.massEdit.show();

                        $scope.removeHotKey();

                        $scope.massData = JSON.parse(JSON.stringify(defaultMassDataValues));

                        createMassEdit($scope, jobList);

                        //$rootScope.mcStorage[mcConst.dataModels.WorkPositions] = data.Data;

                        // $scope.workPositions = data;
                        //
                        // if ($scope.workPositions.length > 0){
                        //     $scope.massData.Position.value = $scope.workPositions[0].ID;
                        // }

                    }
                ]);
            });

            task.Run();
        }
    };

    $scope.openUserProfile = function (){
        var user = getSelectedUser();

        if (user && user.UIN && mcService.checkRights(127)){
            $rootScope.$broadcast('show' + mcConst.dataModels.UserProfile, [user.UIN]);
        }
    };

    $scope.deleteUser = function (){
        if (mcService.checkRights(128)){
            var selectedItems = $scope.userData.getSelectedItem(true);

            var UINs     = getSelectedUINsList();

            if (UINs){
                var user     = getSelectedUser();
                var multiple = UINs.indexOf(',') !== -1;
                var message  = (multiple)
                    ? mcService.Lang(1108)                                           // "1108":"Вы действительно хотите удалить выделенных пользователей?",
                    : mcService.Lang(580, user.DisplayName + ' (' + user.UIN + ')'); // "580": "Вы действительно хотите удалить пользователя?\n\n%s",

                if (mcService.inArrayNoStrict(1, UINs.split(',')) >= 0 ){
                    webix.alert(mcLang(1723)); // "1723":"Нельзя удалить пользователя с UIN:1",
                } else
                if (UINs.length > 0){ // user && user.UIN
                    $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                        type  : "confirm-warning",
                        text  : message,
                        ok    : mcService.Lang(581), // "581": "Удалить",
                        cancel: mcService.Lang(103), // "103": "Отмена",
                        callback:function(yes){
                            if (yes){
                                $rootScope.$broadcast('SendCMDToServer', [
                                    mcConst.lockInterface,
                                    mcConst._CMD_.cs_adm_remove_user,
                                    mcConst.SessionID,
                                    UINs,
                                    function (){
                                        if (multiple){
                                            for (var i = 0; i < selectedItems.length; i++){
                                                $scope.userData.remove(selectedItems[i].id);
                                            }
                                        } else {
                                            $scope.userData.remove(user.id);
                                        }

                                        $scope.selectedUINs = [];

                                        $scope.statusBar.setSelectCount(0);

                                        $scope.updateCounters();

                                        webix.message(mcService.Lang(582)); // "582": "Пользователь удален",

                                        $rootScope.needRefreshCommonContacts = true;
                                    }
                                ]);
                            }
                        }
                    }));
                }
            }
        }
    };

    $scope.dismiss = function (){
        if (mcService.checkRights(mcConst._CMD_.RS.QFireUsers)){
            var selectedItems = $scope.userData.getSelectedItem(true);

            var UINs     = getSelectedUINsList();

            if (UINs){
                var user     = getSelectedUser();
                var multiple = UINs.indexOf(',') !== -1;
                var message  = (multiple)
                    ? mcService.Lang(2209)                                            // "2209":"Вы действительно хотите уволить выделенных пользователей?",
                    : mcService.Lang(2210, user.DisplayName + ' (' + user.UIN + ')'); // "2210":"Вы действительно хотите уволить пользователя?\\n\\n%s",

                if (mcService.inArrayNoStrict(1, UINs.split(',')) >= 0 ){
                    webix.alert(mcLang(2211)); // "2211":"Нельзя уволить пользователя с UIN:1",
                } else
                if (UINs.length > 0){ // user && user.UIN
                    $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                        type  : "confirm-warning",
                        text  : message,
                        ok    : mcService.Lang(2207), // "2207":"Уволить",
                        cancel: mcService.Lang(103), // "103": "Отмена",
                        callback:function(yes){
                            if (yes){
                                $rootScope.$broadcast('SendCMDToServer', [
                                    mcConst.lockInterface,
                                    mcConst._CMD_.cs_adm_fire_users,
                                    mcConst.SessionID,
                                    UINs,
                                    
                                    function (){
                                        if (multiple){
                                            for (var i = 0; i < selectedItems.length; i++){
                                                selectedItems[i].Active = false;

                                                $scope.userData.updateItem(selectedItems[i].id, selectedItems[i]);
                                            }
                                        } else {
                                            user.Active = false;

                                            $scope.userData.updateItem(user.id, user);
                                        }

                                        // $scope.selectedUINs = [];

                                        // $scope.statusBar.setSelectCount(0);

                                        // $scope.updateCounters();

                                        // webix.message(mcService.Lang(582)); // "582": "Пользователь удален",

                                        $rootScope.needRefreshCommonContacts = true;
                                    }
                                ]);
                            }
                        }
                    }));
                }
            }
        }
    };

    $scope.newUser = {
        onShowNewUserRegForm : function() {
            $scope.removeHotKey();

            var Self = $scope.userCreateForm;
            var form = Self.getChildViews()[1];

            var login   = form.elements['login'];
            var pwd     = form.elements['password'];
            var showPwd = form.elements['showpwd'];
            var saveBtn = form.elements['save'];
            var authType= form.elements['authType'];

            authType.setValue(mcConst._CMD_.loginStyle.STANDARD);
            login   .$setValue('');
            pwd     .$setValue('');
            showPwd .$setValue(false);
            saveBtn .disable();

            login.getInputNode().setAttribute("autocomplete", "new-password");
            pwd.getInputNode().setAttribute("autocomplete", "new-password");

            pwd.getInputNode().removeEventListener("paste", function (){
                pwd.$setValue(e.clipboardData.getData('text'));
                $scope.newUser.onEnterNewUserName();
            });
            pwd.getInputNode().addEventListener("paste", function (e){
                $scope.newUser.onEnterNewUserName();
            });

            $scope.regShowWindow(this.config.id, Self);

            $rootScope.hotKeyDispatcher.addPreset(Self.config.id, [{
                key:  mcConst.keyCodes.enter,
                func: function(){
                    $scope.newUser.addNewUser.apply(Self);
                }
            },{
                key:  mcConst.keyCodes.esc,
                func: function(){
                    Self.hide();
                }
            }], document);
        },

        onHideNewRegForm : function() {
            $rootScope.hotKeyDispatcher.removePreset(this.config.id);
            $scope.registerHotKeys();
        },

        showHidePwd : function (val) {
            var form = this.getFormView();
            var pwd  = form.elements['password'];

            if (!val){
                pwd.define('type', 'password');
            } else {
                pwd.define('type', 'text');
            }

            pwd.refresh();
            pwd.getInputNode().setAttribute("autocomplete", "new-password");
        },

        generateUserPwd : function () {
            var form    = this.getFormView();
            var showPwd = form.elements['showpwd'];
            var pwd     = form.elements['password'];

            showPwd.setValue(1);

            pwd.setValue(mcService.RandomHash(12, true));

            $scope.newUser.onEnterNewUserName();
        },

        addNewUserForm : function () {
            if (mcService.checkRights(126)){
                var createUser = $scope.userCreateForm;

                createUser.show();
                createUser.getChildViews()[1].elements['login'].focus();
            }
        },

        onEnterNewUserName : function () {
            var form    = $scope.userCreateForm.getChildViews()[1];
            var login   = mcService.trim(form.elements['login'].getValue().toString());
            var pwd     = mcService.trim(form.elements['password'].getValue().toString());
            var saveBtn = form.elements['save'];
            var authType= form.elements['authType'].getValue();

            if (login.indexOf('@') >= 0){
                if (mcService.isValidEmailAddress(login) && (pwd !== "" || authType === mcConst._CMD_.loginStyle.NO_PASS)){
                    saveBtn.enable();
                } else {
                    saveBtn.disable();
                }
            } else
            if (login === "" || (pwd === "" && authType === mcConst._CMD_.loginStyle.STANDARD)) {
                saveBtn.disable();
            } else {
                saveBtn.enable();
            }
        },

        addNewUser : function() {
            var self    = this.getFormView() || this.getChildViews()[1];
            var isValid = self.validate();

            if (isValid){
                var login   = mcService.trim(self.elements['login'].$getValue().toString()).replace("\\", "/");
                var pwd     = self.elements['password'].$getValue().toString();
                var authType= self.elements['authType'].getValue();

                var nick  = "";
                var email = "";

                if (login.indexOf('@') >= 0){
                    if (mcService.isValidEmailAddress(login)){
                        email = login;
                        nick  = login.split('@')[0];
                    } else {
                        $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(7) ]); // "7"  : "Ошибка входа: неправильно введены данные",

                        login = "";
                    }
                } else
                if (login.indexOf('/') >= 1) {

                } else
                if (login !== "") {
                    nick = login;
                }

                if (login){
                    $scope.addedUserName = login;

                    $rootScope.$broadcast('SendCMDToServer', [
                        mcConst._CMD_.cs_adm_create_user,
                        mcConst.SessionID,

                        nick,
                        email,
                        pwd,
                        authType,

                        function(info){
                            $scope.addUserToList(info.UIN);

                            getUserInfoByPreset(info.UIN);

                            self.elements['login']   .$setValue('');
                            self.elements['password'].$setValue('');
                            self.elements['showpwd'] .setValue(0);

                            self.getParentView().hide();
                        }
                    ]);

                    $rootScope.needRefreshCommonContacts = true;
                }
            } else {
                $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(7) ]); // "7"  : "Ошибка входа: неправильно введены данные",
            }
        },

        changeUserType : function () {
            var form    = $scope.userCreateForm.getChildViews()[1];
            var pwd     = form.elements['password'];
            var authType= form.elements['authType'];
            var genkey  = form.elements['genkey'];
            var showpwd = form.elements['showpwd'];

            switch (authType.getValue()) {
                case mcConst._CMD_.loginStyle.NO_PASS:
                    pwd.disable();
                    genkey.disable();
                    showpwd.disable();
                break;

                case mcConst._CMD_.loginStyle.STANDARD:
                    pwd.enable();
                    genkey.enable();
                    showpwd.enable();
                break;
            }

            $scope.newUser.onEnterNewUserName();
        }
    };

    $scope.exportToCSV = function(fieldsList){
        var UINs      = getSelectedUINsList(true);

        if (UINs.length > 0){
            var selected  = fieldsList.getSelectedId();
            var allFields = fieldsList.serialize();

            var exportFields = [];

            if (mcService.isArray(selected)) {
                for (var i = 0; i < allFields.length; i++){
                    var idx = mcService.inArray(allFields[i].id, selected);

                    if (idx !== -1){
                        exportFields.push(allFields[i].id);

                        selected.splice(idx, 1);

                        if (selected.length === 0) {
                            break;
                        }
                    }
                }

                exportFields = exportFields.join(",");
            } else
            if (mcService.isString(selected)){
                exportFields = selected;
            }

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_export_users_to_csv,
                mcConst.SessionID,
                UINs,
                exportFields,
                function(data){
                    webix.alert("<a href='/downloads/" + data.FileName + "' target='_blank'>Download CSV file</a>");
                }
            ]);
        }
    };

    $scope.inputUserToSelectedList = function(id, e){
        // if (!e.ctrlKey && !e.shiftKey){
            // $scope.selectedUINs = [$scope.selectedUINs.pop()];
        // }

        $scope.selectedUINs = $scope.userData.getSelectedItem(true);

        $scope.statusBar.setSelectCount($scope.selectedUINs.length);
    };

    $scope.selectUsers = function (item){
        // $scope.selectedUINs.push(this.getItem(item));
        $scope.selectedUINs = $scope.userData.getSelectedItem(true);

        $scope.statusBar.setSelectCount($scope.selectedUINs.length);
    };

    $scope.requestUsersList = function(show, cb, params){
        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_list_users,
            mcConst.SessionID,
            !params ? 'All' : params.Params || 'All',
            !params ? mcConst.userFields : params.Filters || mcConst.userFields,

            function (data){
                $rootScope.mcStorage.UserManager = data;

                if (show) {
                    $scope.selectedUINs = [];

                    $scope.data = data.Users;//webix.copy(data.Users) || [];
                    $rootScope.mcStorage[mcConst.dataModels.UserManager] = $scope.data;

                    $scope.data.forEach(function (t) {
                        t.LastAccess = mcService.utcTime(t.LastAccess);
                    });

                    if ($scope.statusBar.containers){
                        $scope.statusBar.setSelectCount(0);
                    }

                    $rootScope.SendCMDToServer([
                        mcConst.lockInterface,
                        mcConst._CMD_.cs_adm_get_job_positions_list,
                        mcConst.SessionID,
                        function (data){
                            $rootScope.mcStorage[mcConst.dataModels.WorkPositions] = data.Data;

                            $scope.data.sort(function (a, b) {
                                return mcService.sortAB(a.UIN, b.UIN);
                            }); // "#UIN#", "asc", "int"

                            $scope.userData.clearAll();
                            $scope.userData.parse($scope.data.slice(0, 60));

                            $scope.userData.select($scope.userData.getFirstId());

                            setTimeout(function () {
                                $scope.userData.parse($scope.data.slice(60));

                                if ($scope.data) {
                                    $scope.updateCounters();
                                }
                            }, 50);
                        }
                    ]);
                } else {
                    if (cb) cb(data);
                }
            }
        ]);
    };

    $scope.ChangeUmColumns = function(newV){
        // if (newV === 0) {
        if (this.getValue() === 0) {
            $scope.userData.hideColumn(mcService.copy(this.config.id, 3));
        } else {
            $scope.userData.showColumn(mcService.copy(this.config.id, 3));
        }

        var hiddenFields = $scope.userData.getState().hidden || [];

        $rootScope.$broadcast('saveAdminOptions', [hiddenFields.join('|'), "userManagerSettingsState"]);
    };

    $scope.statusBar.setTotalCount = function(count){
        $scope.statusBar.containers.getChildViews()[0].define('template', mcService.Lang(1216) + ": " + count); // "1216":"Всего пользователей",
        $scope.statusBar.containers.getChildViews()[0].refresh();
    };

    $scope.statusBar.setSelectCount = function(count){
        $scope.statusBar.containers.getChildViews()[1].define('template', mcService.Lang(1217) + ": " + count); // "1217":"Выделено пользователей",
        $scope.statusBar.containers.getChildViews()[1].refresh();
    };

    $scope.statusBar.setBlockedCount = function(){
        $scope.statusBar.blockedUsersCount = 0;

        $scope.userData.data.each(function(item){
            if (!item.Active){
                $scope.statusBar.blockedUsersCount ++;
            }
        });

        $scope.statusBar.containers.getChildViews()[2].define('template', mcService.Lang(1218) + ": " + $scope.statusBar.blockedUsersCount); // "1218":"Заблокировано",
        $scope.statusBar.containers.getChildViews()[2].refresh();
    };

    $scope.statusBar.setADCount = function(){
        $scope.statusBar.ad = 0;

        $scope.userData.data.each(function(item){
            if (item.Domain){
                $scope.statusBar.ad ++;
            }
        });

        $scope.statusBar.containers.getChildViews()[3].define('template', mcService.Lang(68) + ": " + $scope.statusBar.ad); // "68" : "Active Directory",
        $scope.statusBar.containers.getChildViews()[3].refresh();
    };

    $scope.statusBar.setWebCount = function(){
        $scope.statusBar.web = 0;

        $scope.userData.data.each(function(item){
            if (item.GroupRights == "WEB guests"){
                $scope.statusBar.web ++;
            }
        });

        $scope.statusBar.containers.getChildViews()[4].define('template', mcService.Lang(1341) + ": " + $scope.statusBar.web); // "1341":"Web-поддержка",
        $scope.statusBar.containers.getChildViews()[4].refresh();
    };

    $scope.updateCounters = function(){
        $scope.statusBar.setTotalCount($scope.data.length);
        $scope.statusBar.setBlockedCount();
        $scope.statusBar.setADCount();
        $scope.statusBar.setWebCount();
    };

    $scope.show = function(data){
        var redraw = true;

        if (data === 'refresh' || !mcView || needRefreshOnShow) {
            $scope.requestUsersList(true);
        } else
        if (data === 'open' && mcView) {
            redraw = false;

            $rootScope.$broadcast('setLocation', ['/navUsers/' + $scope.Name + '/']);
        }

        needRefreshOnShow = false;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        if (redraw) {
            mcView = initUserManager($scope);

            // $scope.userData.parse($scope.data.slice(0, 60));
            //
            // setTimeout(function () {
            //     $scope.userData.parse($scope.data.slice(60));
            // }, 100);
        }

        $scope.updateCounters();

        mcService.initResize(mcView, $scope.Name);

        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_get_personal_options,
            mcConst.SessionID,

            function( data ){
                $rootScope.adminOptions = mcService.Marge($rootScope.adminOptions, data.ADMINOPT);

                var hidden = $rootScope.adminOptions.userManagerSettingsState ? $rootScope.adminOptions.userManagerSettingsState.split('|') : [];

                hidden.forEach(function (item) {
                    $scope.userData.hideColumn(item);

                    $$("chk" + item).setValue(false);
                });
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    // ================================================

    $scope.$on('refreshUserManagerOnNextShow', function(){
        needRefreshOnShow = true;
    });

    $scope.$on('getUserProfileForManager', function(e, args) {
        getUserInfoByPreset.apply(null, args);
    });

    $scope.$on('getAllUserList', function(e, args){
        $scope.requestUsersList.apply(null, args);
    });

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);

        $scope.removeHotKey();

        // if ($scope.__filter && $scope.__filter.clearFilter) $scope.__filter.clearFilter();
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $scope.show.apply(null, args);

        $scope.registerHotKeys();
    });
}

function userQrCode($rootScope) {
    "use strict";

    var w   = 450;
    var w_9 = w * .9;
    var h   = 580;
    var h_9 = w * .9;
    var userData= null;
    var qrWnd   = null;
    var qrCode  = null;
    var wndPWD  = null;
    var ip_1    = "";
    var ip_2    = "";
    var userPWD = "";
    var userUIN = 0;

    function closeQR() {
        qrCode && qrCode.clear();
        qrCode = null;
        
        qrWnd.close();

        $rootScope.hotKeyDispatcher.removePreset("__qr_code_mobile__");
    }

    function closePWD() {
        wndPWD && wndPWD.close();
        wndPWD = null;
        
        $rootScope.hotKeyDispatcher.removePreset("__qr_code_pwd__");
    }

    function getData(uin) {
        var taskList = new mcService.TaskList;

        userUIN = uin;

        userData = null;

        taskList.AddTask(function() {
            mcService.getMcSettings($rootScope, taskList.Next);
        });

        taskList.AddTask(function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_user_profile,
                mcConst.SessionID,

                userUIN,

                function (data){
                    userData = data;

                    taskList.Next();
                }
            ]);
        });

        taskList.AddTask(function(){
            // showQrCode();
            enterPWD()
        });

        taskList.Run();
    }

    function enterPWD() {
        var pwdWndName = "getQrCodeWindow";

        if ($$(pwdWndName)) {
            $$(pwdWndName).destructor();
        }

        function changePwdText() {
            var elem = this.getFormView().elements;

            if (mcService.trim(elem['password'].getValue()) != "") {
                elem["save"].enable();
            } else {
                elem["save"].disable();
            }
        }

        wndPWD = webix.ui({
            view     : "window",
            position : "center",
            width    : 300,
            id       : pwdWndName,
            head     : {
                cols: [
                    { width: 42 },
                    { view: "label", label: '<div class="byCenter toUpper">' + userData.DisplayName + '</div>' },
                    { view: "button", type: 'icon', width: 28, icon: 'times', css: "button_transparent", click: closePWD }
                ]
            },
            modal    : true,
            body     : {
                view : 'form',
                rules:{
                    "password" : webix.rules.isNotEmpty
                },
                elements : [{
                    id         : "pwdFieldQRCode",
                    view       : "text",
                    placeholder: mcService.Lang(124), // "124": "Пароль пользователя",
                    type       : 'password',
                    name       : 'password',
                    required   : "true",
                    on         : {
                        onChange       : changePwdText,
                        onTimedKeyPress: changePwdText,
                    }
                }, {
                    cols : [{}, {
                        name  : "save",
                        view  : "button",
                        disabled : true,
                        value : mcService.Lang(13), // "13" : "Ок",
                        click : function(){
                            checkPwd(this.getFormView().elements['password'].getValue(), userData.UIN);
                        }
                    }]
                }]
            }
        });

        wndPWD.show();

        $$("pwdFieldQRCode").getInputNode().addEventListener("paste", function (e){
            setTimeout(function () {
                changePwdText.apply($$("pwdFieldQRCode"));
            }, 10);
        });

        $rootScope.hotKeyDispatcher.addPreset("__qr_code_pwd__", [{
            key: mcConst.keyCodes.esc,
            func: closePWD
        }, {
            key: mcConst.keyCodes.enter,
            func: function () {
                checkPwd($$("pwdFieldQRCode").getValue(), userData.UIN);
            }
        }], document, true);

        $$("pwdFieldQRCode").focus();
    }

    function getQR() {
        var clientOptions = {
            Addr     : ip_1,
            Port     : mcConst.ServerInfo.Port,    // optional, default 2004
            AddrAlt  : ip_2, // optional
            PortAlt  : mcConst.ServerInfo.AltPort || mcConst.ServerInfo.Port, // optional, default 2004

            NodePort : mcConst.UserInfo.PortNode,
            SSL      : mcConst.UserInfo.HTTPS,
            Domain   : mcConst.UserInfo.Domain,  // optional
            Login    : userUIN || mcConst.UserInfo.UIN,     // optional
            Pwd      : userPWD, // mcConst.LoginInfo.pwd,    // optional
            ServerPwd: mcConst.LoginInfo.servPwd,// optional
            rm       : true
        };

        userPWD && $rootScope.$broadcast("SendCMDToServer", [
            mcConst._CMD_.encode_qrcode,
            mcConst.SessionID,

            JSON.stringify(clientOptions),

            function (args) {
                var data   = mcService.StringToObj(args);
                var opt    = data[0];
                var servID = data[1];

                document.getElementById("__qr_code_mobile__").innerHTML = "";

                qrCode && qrCode.clear();
                qrCode = new QRCode(document.getElementById("__qr_code_mobile__"), {
                    text: "https://mychat-server.com:50000/?id=" + servID + "&o=" + opt,
                    width: w_9,
                    height: h_9,
                    colorDark: "#131313",
                    colorLight: "#ffffff",
                    correctLevel: QRCode.CorrectLevel.H
                });
            }
        ]);
    }

    function checkPwd(pwd, uin) {
        $rootScope.$broadcast("SendCMDToServer", [
            mcConst._CMD_.cs_adm_check_user_pwd,
            mcConst.SessionID,

            uin,
            pwd,

            function (data) {
                if (data.Result === 0) {
                    userPWD = pwd;

                    closePWD();
                    showQrCode();
                    getQR();
                } else {
                    switch (data.Result) {
                        case 92:
                            webix.message(mcConst.ErrorText[15].replace("%s", uin)); // "15" : "пользователь UIN %s заблокирован",
                        break;

                        case 7:
                            webix.message(mcConst.ErrorText[92]); // "92" : "не удалось авторизоваться под указанным пользователем домена (неверно указаны логин, пароль или домен)",
                        break;

                        case 6:
                            webix.message(mcLang(2251)); // "2251":"Неправильный пароль",
                        break;

                        default:
                            webix.message(mcLang(2280, data.Result)); // "2280":"Неизвестная ошибка №",
                    }
                }
            }
        ]);
    }

    function showQrCode(){
        var ips = [].concat(mcService.networkInterfaces($rootScope.mcStorage.SettingsNetwork.IPVer, $rootScope.mcStorage.networkInterfaces));

        ips.shift();

        if ($rootScope.mcStorage.SettingsNetwork.ExternalIP){
            ips.unshift({
                value: $rootScope.mcStorage.SettingsNetwork.ExternalIP,
                id   : $rootScope.mcStorage.SettingsNetwork.ExternalIP
            });
        }

        qrWnd = webix.ui({
            position: "center",
            view    : "window",
            modal   : true,
            width   : w * 1.1,
            height  : h,
            cancel  : mcService.Lang(33), // "33": "Отмена",
            head    : {
                cols: [
                    { width: 42 },
                    { view: "label", label: '<div class="byCenter toUpper">QR Code</div>' },
                    { view: "button", type: 'icon', width: 28, icon: 'times', css: "button_transparent", click: closeQR }
                ]
            },
            body: { 
                padding: 7,
                rows   : [
                    { view: "select", id: "qrMainIp", value: 0, labelWidth: 200, label: mcLang(2249), options: ips, on: {onChange: selectIP} }, // "2249":"Основной адрес",
                    { view: "select", id: "qrAltIp",  value: ips.length >= 2 ? ips[1].id : 0, labelWidth: 200, label: mcLang(2250), options: ips, on: {onChange: selectIP} }, // "2250":"Альтернативный адрес",
                    { height: 30 },
                    { template: "<div class='byCenterAll' style='height: 100%; text-align: center;'><div id='__qr_code_mobile__' style='width: " + w_9 + "px; margin: auto;'>" +
                        "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcwAAAHMAQMAAABiFQrFAAAAAXNSR0IArs"  +
                        "4c6QAAAARnQU1BAACxjwv8YQUAAAAGUExURQAAAP///6XZn90AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIUSURBVHja7" +
                        "dtLcsIwDAZgMV3AIjM+Qo/So8HROEqOkF1ZZFADsWM5DwimIGz/2jTT+oviJGj8KDQTez5ff35zF93hlrmmdZEp3aRG" +
                        "qaCsuMN53iY9+sUy6gvt4jSme9mqfYoaUFDQCIoP3Zto44tjbYvpdnrYuhoKCgoKWhzt4kAbX2JBS6AE+mJq0NfPvU3" +
                        "LWftwY8qHst6lOlkrlaygeb5NOhcM+iYqovbtb/zWF5gYakDXUFKhyfUVb1OetHrubZrE/Kx5VayjpqCsyV3wTuWCk6" +
                        "OkQnX6WsVTSo/yQpzsWZYjnjYqlFPLWhJtCno4bWq3qSw6Lo71qJiy33aezpojKalkLYmSCsXDAc2BhuuIbLdTXDEVm" +
                        "yzDzPz6J1BQUNDblBLvKwXtXV0VYf6FkkpWHVoV1FedV0KH4pOT621yBfJoz+JCFFOyw0u+5vgZSmo0beJpq5IV9NVU" +
                        "5236Ta2vXNDD0Sowrv3RLyMFOzGbYMJtbA4b76cmtQvW6asO3RXUV9A86cJe8zCmDJYg2RfTVg4vH6Y6WUFBQUHv0Zk" +
                        "Yt3cjTbEpcwlQUFDQ/KiYZbPfm+7jIE85rFXKbWpQUFDQT6Tjr+INZyH/5eTxFgwoKChoGfQ88/+IB7/g2BdgUFBQ0L" +
                        "JosLPCjvYHoKCgoFlSEYKynXBv/fDSxfJcHRQUFDRlOokZOrQPiykoKChoPpT5D2DoEOZo8+7BAAAAAElFTkSuQmCC'" +
                        " alt='QR-код' style='opacity: .1; height: 100%; width: 100%'></div></div>",
                    borderless: true },
                ]
            }
        });

        qrWnd.show();

        $rootScope.hotKeyDispatcher.addPreset("__qr_code_mobile__", [{
            key: mcConst.keyCodes.esc,
            func: closeQR
        }], document, true);

        ip_1 = $$("qrMainIp").getValue();
        ip_2 = $$("qrAltIp").getValue();
    }

    function selectIP() {
        ip_1 = $$("qrMainIp").getValue();
        ip_2 = $$("qrAltIp").getValue();

        getQR();
    }

    $rootScope.$on("showQrCode", function (e, args){
        getData.apply(null, args);
    });
}
function initUserProfileView($scope){
    "use strict";

    var nameWidth      = 200;
    var blockWidth     = 820;
    var fotoBlock      = 150;
    var textAreaHeight = 75;

    var _sex = [
        {id: '0', value: mcService.Lang(136)}, // "136":"не определен",
        {id: '1', value: mcService.Lang(137)}, // "137":"мужской",
        {id: '2', value: mcService.Lang(138)}  // "138":"женский",
    ];

    var _groups = mcService.transformDataObject($scope.groupeRights, [['Name', 'value'], ['ID', 'id']]);

    var _workPosition = mcService.transformDataObject($scope.workPosition, [['Name', 'value'], ['ID', 'id'], ['TeamLead', 'TeamLead']]);

    _workPosition.unshift({id: '-1', value: "---"});

    $scope.workDepts.unshift({id: '-1', value: "---"});

    var _active = [
        {id: '1', value: mcService.Lang(114)}, // "114": "включить",
        {id: '0', value: mcService.Lang(113)}  // "113": "заблокировать",
    ];

    var _ad = [
        {id: mcConst._CMD_.loginStyle.STANDARD,       value: mcService.Lang(111)},  // "111": "обычная авторизация",
        {id: mcConst._CMD_.loginStyle.AD,             value: mcService.Lang(112)},  // "112": "Active Directory авторизация",
        {id: mcConst._CMD_.loginStyle.NO_PASS,        value: mcService.Lang(1512)}, // "1512":"Безпарольная авторизация",
        {id: mcConst._CMD_.loginStyle.AD_TRANSPARENT, value: mcService.Lang(1891)}  // "1891":"Active Directory прозрачная авторизация",
    ];

    var _auto = [
        {id: '1', value: mcService.Lang(110)}, // "110": "включен",
        {id: '0', value: mcService.Lang(109)}  // "109": "выключен",
    ];

    var upTabMain = {
        id      : 'upTabMain',
        type    : "line",
        padding : 8,
        rows : [{
            cols : [{
                width : blockWidth - fotoBlock + 1,
                rows: [{
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upAboutUser',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(78), css: 'headerLineHeight'},                           // "78" : "Описание"
                        {                   id: 'upUIN',       value:'', label: mcService.Lang(135)},                  // "135":"UIN:",
                        {type:$scope.data.UIN === 1 ? "" : "fastselect", id: 'upActive',    value:'0',label: mcService.Lang(128), options:_active}, // "128":"Активен",
                        {type:"text",       id: 'upFirstName', value:'', label: mcService.Lang(129)},                  // "129":"Имя:",
                        {type:"text",       id: 'upMiddleName',value:'', label: mcService.Lang(130)},                  // "130":"Отчество:",
                        {type:"text",       id: 'upLastName',  value:'', label: mcService.Lang(131)},                  // "131":"Фамилия:",
                        {type:"text",       id: 'upNick',      value:'', label: mcService.Lang(132)},                  // "132":"Ник:",
                        {type:"fastselect", id: 'upSex',       value:'1',label: mcService.Lang(133), options:_sex},    // "133":"Пол:",
                        {type:"text",       id: 'upEmail',     value:'', label: mcService.Lang(134)},                  // "134":"Основной E-mail:",
                        {type: mcService.checkRights(123) ? "fastselect" : "", id: 'upRole', value:'1',label: mcService.Lang(144), options:_groups} // "144":"Группа прав:",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onAfterEditStart: $scope.noExitByEsc, onTimedKeyPress: $scope.showApplyForm }
                }]
            }, {
                width : fotoBlock,
                rows:[
                    { view:"template", template:mcService.Lang(79), type:"header", height: 23, css: 'headerLineHeight'}, // "79" : "Фотография"
                    { id: 'upFoto',    template:'<img id="upFotoCanvas" src="" border="0">', height: 167, css: "byCenter"},

                    { view:"uploader",label: mcService.Lang(139), height:26, css: 'fotoBtn', id: 'upLoadFoto',  autosend: false, upload: "", multiple: false,
                        accept: ".jpg,.png,.jpeg", on : {onBeforeFileAdd : $scope.uploadFoto} },// "139":"Загрузить фото",
                    { view:"button",  label: mcService.Lang(147), height:26, css: 'fotoBtn', id: 'upClearFoto', click: $scope.clearFoto}  // "147":"Очистить фото",
                ]
            },{}]
        }, {
            height : 10
        }, {
            cols : [{
                width : blockWidth - fotoBlock + 1,
                rows: [{
                    view       : "property",
                    autoheight : true,
                    nameWidth  : nameWidth,
                    id         : 'upConfigAuth',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label",  css:'headerLineHeight', label: mcService.Lang(127)},                         // "127": "Настрока авторизации",
                        {type: mcService.checkRights(124) && $scope.data.UIN != 1 ? "fastselect" : "", id: 'upAuthType',   label: mcService.Lang(126), value: '', options: _ad}, // "126": "Active Directory авторизация",
                        {type: mcService.checkRights(124) && $scope.data.UIN != 1 ? "fastselect" : "", id: 'upDomainName', label: mcService.Lang(123), value: '', options: $scope.domainsList}               // "123": "Имя домена",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.id === "upDomainName"){
                            if (state.value !== $scope.data.DomainName || $scope.changedData.data.ShowDesc) {
                                $scope.showApplyForm.apply(this, arguments);
                            }
                        } else

                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, {
                    height : 25,
                    hidden : !mcService.checkRights(125),
                    cols   : [{
                        template: '<span style="padding-left: 5px; margin-top: -2px; position: absolute">' + mcService.Lang(124) + '</span>',
                        width   : nameWidth - 1
                    }, {
                        template: "<div id='upUserPWD' class='pwdProfile'></div>"
                    }]
                }]
            }, {
                width : fotoBlock,
                template: "<div class='finger getQrFromProfile' style='height: 100%; text-align: center; margin-top: 5px'>" +
                    "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAcwAAAHMAQMAAABiFQrFAAAAAXNSR0IArs"  +
                    "4c6QAAAARnQU1BAACxjwv8YQUAAAAGUExURQAAAP///6XZn90AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIUSURBVHja7" +
                    "dtLcsIwDAZgMV3AIjM+Qo/So8HROEqOkF1ZZFADsWM5DwimIGz/2jTT+oviJGj8KDQTez5ff35zF93hlrmmdZEp3aRG" +
                    "qaCsuMN53iY9+sUy6gvt4jSme9mqfYoaUFDQCIoP3Zto44tjbYvpdnrYuhoKCgoKWhzt4kAbX2JBS6AE+mJq0NfPvU3" +
                    "LWftwY8qHst6lOlkrlaygeb5NOhcM+iYqovbtb/zWF5gYakDXUFKhyfUVb1OetHrubZrE/Kx5VayjpqCsyV3wTuWCk6" +
                    "OkQnX6WsVTSo/yQpzsWZYjnjYqlFPLWhJtCno4bWq3qSw6Lo71qJiy33aezpojKalkLYmSCsXDAc2BhuuIbLdTXDEVm" +
                    "yzDzPz6J1BQUNDblBLvKwXtXV0VYf6FkkpWHVoV1FedV0KH4pOT621yBfJoz+JCFFOyw0u+5vgZSmo0beJpq5IV9NVU" +
                    "5236Ta2vXNDD0Sowrv3RLyMFOzGbYMJtbA4b76cmtQvW6asO3RXUV9A86cJe8zCmDJYg2RfTVg4vH6Y6WUFBQUHv0Zk" +
                    "Yt3cjTbEpcwlQUFDQ/KiYZbPfm+7jIE85rFXKbWpQUFDQT6Tjr+INZyH/5eTxFgwoKChoGfQ88/+IB7/g2BdgUFBQ0L" +
                    "JosLPCjvYHoKCgoFlSEYKynXBv/fDSxfJcHRQUFDRlOokZOrQPiykoKChoPpT5D2DoEOZo8+7BAAAAAElFTkSuQmCC'" +
                    " alt='QR-код' style='opacity: .3; height: 60px; '><br>QR Code</div>",
                onClick: {"getQrFromProfile" : $scope.getQrFromProfile}
            }, {}]
        },{
            height : 10
        },/*{
            cols: [
                { id: "pwdForQrCode", view : "text", type: "password", placeholder: mcLang(124) + " " + $scope.data.DisplayName, width: blockWidth - 210 }, // "124": "Пароль пользователя",
                { width: 10 },
                { view : "button", value: mcLang(2246), width: 200, click: $scope.showQrCode}, // "2246":"Сгенерировать QRCode",
                {}
            ]
        },*/{
            height : 10
        },{
            hidden: true,
            rows : [{
                width : blockWidth,
                // rows: [{
                    view       : "property",
                    autoheight : true,
                    nameWidth  : nameWidth,
                    id         : 'upSystemInfo',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label",   css:'headerLineHeight',      label: mcService.Lang(122)}, // "122": "Системная информация",

                        {view:"text", id: 'upCompNetName', value: '', label: mcService.Lang(62),  css: "selectable"}, // "62" : "Компьютер",
                        {view:"text", id: 'upIP',          value: '', label: mcService.Lang(141), css: "selectable"}, // "141":"IP адрес",
                        {view:"text", id: 'upMAC',         value: '', label: mcService.Lang(142), css: "selectable"}, // "142":"MAC адрес",
                        {view:"text", id: 'upLastAccess',  value: '', label: mcService.Lang(65),  css: "selectable"}, // "65" : "Последнее подключение",
                        {view:"text", id: 'upHardwareID',  value: '', label: "HardwareID",        css: "selectable"}  // "65" : "Последнее подключение",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                // }]
            }]
        }, { id: "upOtherSysInfo", rows: []}]
    };

    var upTabWork = {
        type : "line",
        id: 'upTabWork',
        padding : 8,
        rows : [{
            cols : [{
                width : blockWidth,
                rows: [{
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upCompanyInfo',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(121), css: 'headerLineHeight'},                                  // "121": "Информация о компании (организации)",
                        {type:"text",   id: 'upWorkCompanyName', value:'',  label: mcService.Lang(170)},                     // "170":"Название компании / организации:",
                        {type:"fastselect", id: 'upWorkPositionIdx', value:'0', label: mcService.Lang(171), options: _workPosition},    // "171":"Должность:",
                        {type:"fastselect", id: 'upWorkDeptIdx',     value:'0', label: mcService.Lang(172), options: $scope.workDepts}, // "172":"Подразделение:", type:"text", options: _workDept
                        {type:"text",   id: 'upWorkOffice',      value:'',  label: mcService.Lang(173)},                     // "173":"Офис:",
                        {type:"text",   id: 'upWorkPhone',       value:'',  label: mcService.Lang(174)},                     // "174":"Телефон:",
                        {type:"text",   id: 'upWorkFax',         value:'',  label: mcService.Lang(160)},                     // "160":"Факс",
                        {type:"text",   id: 'upWorkPager',       value:'',  label: mcService.Lang(176)}                      // "176":"Пейджер:",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upCompanyAddress',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(177), css: 'headerLineHeight'},                  // "177":"Рабочий адрес",

                        {type:"text",    id: 'upWorkStreetAddress', value: '',  label: mcService.Lang(163)}, // "163":"Дом, улица",
                        {type:"text",    id: 'upWorkCity',          value: '',  label: mcService.Lang(164)}, // "164":"Город",
                        {type:"text",    id: 'upWorkState',         value: '',  label: mcService.Lang(165)}, // "165":"Штат/Область/Край",
                        {type:"text",    id: 'upWorkZIP',           value: '',  label: mcService.Lang(166)}, // "166":"ZIP/Почтовый индекс",
                        {type:"fastselect", id: 'upWorkCountry',    value: '1', label: mcService.Lang(167), options: mcService.GetCountriesList()} // "167":"Страна",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upCompanyMore',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(574), css: 'headerLineHeight'},       // "574":"Дополнительно",
                        {type:"text",    id: 'upWorkWWW', value: '',  label: mcService.Lang(178)} // "178":"WWW страница",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, {cols: [
                    { view: "button", value: mcLang(2141), width: 250, click: $scope.dismiss, disabled: $scope.data.UIN == 1 || $scope.data.UIN == 0, hidden: true}, // "2141":"Уволить",
                    {}
                ]}]
            }, {}]
        },
        { cols: [
            { id: "dismissBTN" + $scope.Name, view: 'button', value: mcLang(2207), click: $scope.dismissUser, width:200, hidden: !mcService.checkRights(mcConst._CMD_.RS.QFireUsers) || !$scope.data.Active},  // "2207":"Уволить",
            {}
        ]}, {}
    ]};

    var upTabPersonal = {
        id         : 'upTabPersonal',
        type       : 'line',
        padding    : 8,
        rows : [{
            cols : [{
                width : blockWidth,
                rows: [{
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upPersonalInfo',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(148), css: 'headerLineHeight'},                                                         // "148":"Личная информация",
                        {type:"date",    id: 'upBirthday',        value:'0',  label: mcService.Lang(149) + ":", // "149":"Дата рождения:",
                            suggest: {
                                type:"calendar",
                                body: {
                                    minDate: new Date("1900.01.01"),
                                    maxDate: new Date("3000.01.01")
                                }
                            }
                        },
                        {type:"fastselect",  id: 'upMaritalStatus',   value:'6',  label: mcService.Lang(150) + ":", options: mcService.GetMaritalStatusList()} // "150":"Семейное положение",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm}
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upPersonalPhone',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(158), css: 'headerLineHeight'},            // "158":"Номера телефонов",

                        {type:"text",    id: 'upHomePhone',   value:'',  label: mcService.Lang(159)}, // "159":"Телефон",
                        {type:"text",    id: 'upHomeFax',     value:'',  label: mcService.Lang(160)}, // "160":"Факс",
                        {type:"text",    id: 'upHomeCellular',value:'',  label: mcService.Lang(161)}  // "161":"Мобильный",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upPersonalAddress',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(162), css: 'headerLineHeight'},                  // "162":"Домашний адрес",

                        {type:"text",    id: 'upHomeStreetAddress', value: '',  label: mcService.Lang(163)}, // "163":"Дом, улица",
                        {type:"text",    id: 'upHomeCity',          value: '',  label: mcService.Lang(164)}, // "164":"Город",
                        {type:"text",    id: 'upHomeState',         value: '',  label: mcService.Lang(165)}, // "165":"Штат/Область/Край",
                        {type:"text",    id: 'upHomeZIP',           value: '',  label: mcService.Lang(166)}, // "166":"ZIP/Почтовый индекс",
                        {type:"fastselect",  id: 'upHomeCountry',       value:'1',  label: mcService.Lang(167), options: mcService.GetCountriesList()} // "167":"Страна",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upPersonalMore',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(574), css: 'headerLineHeight'},        // "574":"Дополнительно",
                        {type:"text",    id: 'upHomeWWW', value: '',  label: mcService.Lang(168)}  // "168":"Личная WWW страница",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }]
            }, {}]
        }, {}
    ]};

    var upTabInterest = {
        id      : 'upTabInterest',
        type    : "line",
        padding : 8,
        rows : [{
            cols : [{
                width : blockWidth,
                rows: [{
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upSpokenLang',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(179), css: 'headerLineHeight'},                                                      // "179":"Владение языками",
                        {type:"fastselect",  id: 'upSpokenLang1',   value: 43,  label: mcService.Lang(120), options: mcService.GetSpokenLangList()}, // "120": "Основной язык",
                        {type:"fastselect",  id: 'upSpokenLang2',   value: 43,  label: mcService.Lang(119), options: mcService.GetSpokenLangList()}, // "119": "Второй язык",
                        {type:"fastselect",  id: 'upSpokenLang3',   value: 43,  label: mcService.Lang(118), options: mcService.GetSpokenLangList()}  // "118": "Третий язык",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upInterests',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(493), css: 'headerLineHeight'},                                                       // "493":"Личные интересы",
                        {type:"fastselect",  id: 'upInterests1',      value:'6',  label: mcService.Lang(117), options: mcService.GetInterestsList()}, // "117": "Категория"
                        {type:"text",    id: 'upInterestsWords1', value: '',  label: mcService.Lang(116)},                                        // "116": "Интересы",
                        {type:"fastselect",  id: 'upInterests2',      value:'6',  label: mcService.Lang(117), options: mcService.GetInterestsList()}, // "117": "Категория"
                        {type:"text",    id: 'upInterestsWords2', value: '',  label: mcService.Lang(116)},                                        // "116": "Интересы",
                        {type:"fastselect",  id: 'upInterests3',      value:'6',  label: mcService.Lang(117), options: mcService.GetInterestsList()}, // "117": "Категория"
                        {type:"text",    id: 'upInterestsWords3', value: '',  label: mcService.Lang(116)},                                        // "116": "Интересы",
                        {type:"fastselect",  id: 'upInterests4',      value:'6',  label: mcService.Lang(117), options: mcService.GetInterestsList()}, // "117": "Категория"
                        {type:"text",    id: 'upInterestsWords4', value: '',  label: mcService.Lang(116)}                                         // "116": "Интересы",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upPast',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(544), css: 'headerLineHeight'},                                             // "544":"Прошлое:",
                        {type:"fastselect",  id: 'upPast1',      value:'6',  label: mcService.Lang(117), options: mcService.GetPastList()}, // "117": "Категория"
                        {type:"text",    id: 'upPastWords1', value: '',  label: mcService.Lang(115)},                                   // "116": "Интересы",
                        {type:"fastselect",  id: 'upPast2',      value:'6',  label: mcService.Lang(117), options: mcService.GetPastList()}, // "117": "Категория"
                        {type:"text",    id: 'upPastWords2', value: '',  label: mcService.Lang(115)},                                   // "116": "Интересы",
                        {type:"fastselect",  id: 'upPast3',      value:'6',  label: mcService.Lang(117), options: mcService.GetPastList()}, // "117": "Категория"
                        {type:"text",    id: 'upPastWords3', value: '',  label: mcService.Lang(115)}                                    // "116": "Интересы",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }, { height : 10 }, {
                    view       : "property",
                    nameWidth  : nameWidth,
                    autoheight : true,
                    id         : 'upPastOrg',
                    keyPressTimeout: 200,
                    elements   : [
                        {type:"label", label:mcService.Lang(545), css: 'headerLineHeight'},                                                   // "545":"Типы организвций:",
                        {type:"fastselect",  id: 'upPastOrg1',      value:'6',  label: mcService.Lang(545), options: mcService.GetPastOrgList()}, // "545":"Типы организвций:",
                        {type:"text",    id: 'upPastOrgWords1', value: '',  label: mcService.Lang(115)},                                      // "116": "Интересы",
                        {type:"fastselect",  id: 'upPastOrg2',      value:'6',  label: mcService.Lang(545), options: mcService.GetPastOrgList()}, // "545":"Типы организвций:",
                        {type:"text",    id: 'upPastOrgWords2', value: '',  label: mcService.Lang(115)},                                      // "116": "Интересы",
                        {type:"fastselect",  id: 'upPastOrg3',      value:'6',  label: mcService.Lang(545), options: mcService.GetPastOrgList()}, // "545":"Типы организвций:",
                        {type:"text",    id: 'upPastOrgWords3', value: '',  label: mcService.Lang(115)}                                       // "116": "Интересы",
                    ],
                    on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                }]
            }, {}]
        }, {}]
    };

    var upTabSettings = {
        id      : 'upTabSettings',
        type    : 'line',
        padding : 8,
        rows : [{
            cols : [{
                width: blockWidth,
                rows: [
                    { view: "template", type: "header", template: mcService.Lang(574), height: 23, css: 'headerLineHeight'}, // "574":"Дополнительно",
                    { view: "textarea", id:"upAbout", height: textAreaHeight, value: "", css:'textArea', on: {onChange: $scope.changeTextArea, onTimedKeyPress: $scope.changeTextArea} },
                    { height : 10 },

                    { view: "template", type: "header", template: mcService.Lang(575), height: 23, css: 'headerLineHeight'}, // "575":"Приветствие в привате",
                    { view: "textarea", id:"upHelloMessage", height: textAreaHeight, value: "", css:'textArea', on: {onChange: $scope.changeTextArea, onTimedKeyPress: $scope.changeTextArea} },
                    { height : 10 },

                    {
                        view       : "property",
                        autoheight : true,
                        nameWidth  : nameWidth,
                        width      : blockWidth,
                        id         : 'upSettingsAR',
                        keyPressTimeout: 200,
                        elements   : [
                            {type:"label",   css:'headerLineHeight',  label: mcService.Lang(577)},                    // "577":"Автоответчик"
                            {type:"fastselect", id: 'upAutoreplay', value: '0', label: mcService.Lang(576), options: _auto} // "576":"Состояние автоответчика",
                        ],
                        on : { onAfterEditStop : function (state, editor) {
                            if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                                $scope.showApplyForm.apply(this, arguments);
                            }
                        }, onTimedKeyPress: $scope.showApplyForm }
                    },
                    { view: "textarea", id: "upAutoreplayMessage", height: textAreaHeight, value: "", css:'textArea', on: {onChange: $scope.changeTextArea, onTimedKeyPress: $scope.changeTextArea} },
                    { height : 10 },

                    { view: "template", type: "header", template: mcService.Lang(108), height: 23, css: 'headerLineHeight'}, // "108": "Тег (служебная информация)",
                    { view: "textarea", id: "upTag", height: textAreaHeight, value: "", css:'textArea', on: {onChange: $scope.changeTextArea, onTimedKeyPress: $scope.changeTextArea} },

                    { height : 10 },
                    {
                        view       : "property",
                        autoheight : true,
                        // nameWidth  : nameWidth,
                        width      : blockWidth,
                        id         : 'upSettingsCustom',
                        keyPressTimeout: 200,
                        nameWidth  : 30,
                        elements   : [
                            {type:"label", css:'headerLineHeight',    label: mcService.Lang(1884)}, // "1884":"Пользовательские поля",
                            {type:"text",   id:'upCustom1', value:'', label: '1'},
                            {type:"text",   id:'upCustom2', value:'', label: '2'},
                            {type:"text",   id:'upCustom3', value:'', label: '3'}
                        ],
                        on : { onAfterEditStop : function (state, editor) {
                        if (editor.config.type !== "text" || $scope.data[editor.config.id.replace('up', '')] !== editor.config.value){
                            $scope.showApplyForm.apply(this, arguments);
                        }
                    }, onTimedKeyPress: $scope.showApplyForm }
                    }
                ]
            }, {}]
        }, {}]
    };

    var upGroupList   = {
        id      : 'upGroupList',
        type    : 'line',
        padding : 8,
        cols    : [
            { width: blockWidth, rows: [
                { view: "label", label: mcLang(2186)}, // "2186":"Личные группы пользователей",
                    
                { id: "upPersonalGroup" + $scope.Name, view: "datatable", // select: "row",
                    columns: [
                        { id: "UINOwner",    header: "UIN",  width: 70},
                        { id: "DisplayName", header: mcLang(1545), fillspace: true}, // "1545":"Имя пользователя",
                        { id: "Name",        header: mcLang(2193), fillspace: true}, // "2193":"Группа",
                    ],
                    data : [],
                    on   : {
                        // onAfterEditStart : $scope.editStage,
                        // onAfterEditStop  : $scope.endEditStage,
                    }
                },

                { height: 10},

                { view: "label", label: mcLang(2194)}, // "2194":"Общие группы пользователей",

                { id: "upCommonGroup" + $scope.Name, view: "datatable", width: blockWidth, // select: "row",
                    columns: [
                        { id: "ID",   header: "ID",  width: 70},
                        { id: "Name", header: mcLang(1764), fillspace: true}, // "1764":"Название",
                    ],
                    data : [],
                    on   : {
                        // onAfterEditStart : $scope.editStage,
                        // onAfterEditStop  : $scope.endEditStage,
                    }
                },
            ]},
            {}
        ]
    };

    var upConfs    = {
        id      : 'upConfs',
        type    : 'line',
        padding : 8,
        cols    : [{ width: blockWidth, rows: [
            { view: "label", label: mcLang(2263)}, // "2263":"Конференції в які входить користувач",

            { id: "upConfList" + $scope.Name, view: "datatable", // select: "row",
                columns: [
                    { width: 40,  header: "", sort: "string", template: function (obj) {
                        return "<span class='byCenter'>" +
                            (obj.ConfType === mcConst._CMD_.confType.HIDDEN
                                ? mcService.insertIco("fa-eye", "", "title='" + mcLang(1847) + "'")                          // "1847":"Скрытая конференция",
                                : (obj.ConfType === mcConst._CMD_.confType.PASSWORD ? mcService.insertIco("fa-lock", "", "title='" + mcLang(2092) + "'") : "")) + // "2092":"Защищенная паролем",
                            "</span>";
                    }},
                    { id: "UID",      header: "UID",        width: 70},
                    { id: "ConfName", header: mcLang(1042), fillspace: true}, // "1042":"Название конференции",
                    { id: "DisplayName",  header: mcLang(2264), width: 120}, // "2264":"Власник",
                    // { id: "CanKick",   header: mcLang(2193), width: 70}, // "2193":"Группа",
                ],
                data : [],
                on   : {
                    // onShow: $scope.endEditStage,
                }
            }
        ]}, {}]
    };

    if ($$($scope.Name)) {
        $$($scope.Name).destructor();
    }

    var tabview = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows:[{
            type : "clean",
            rows : [
                { cols: [{
                    height     : 34,
                    view       : "tabbar",
                    id         : $scope.Name + 'tabbar',
                    multiview  : true,
                    animate    : false,
                    width      : 830,
                    options    : [
                        {value: mcService.Lang(73), id: 'upTabMain'},     // "73" : "Основное",
                        {value: mcService.Lang(74), id: 'upTabWork'},     // "74" : "Работа",
                        {value: mcService.Lang(2192), id: 'upGroupList'}, // "2192":"Группы",
                        {value: mcService.Lang(75), id: 'upTabPersonal'}, // "75" : "Личное",
                        {value: mcService.Lang(76), id: 'upTabInterest'}, // "76" : "Интересы",
                        {value: mcService.Lang(77), id: 'upTabSettings'}, // "77" : "Дополнительно",
                        {value: mcService.Lang(31), id: 'upConfs'}, // "31" : "Конференции",
                    ],
                    on : {
                        onChange : function(newValue, oldValue, config){
                            if (newValue === "upGroupList"){
                                $scope.getUserGroupsList();
                            } else
                            if (newValue === "upConfs") {
                                $scope.getFavoriteConfs();
                            }
                            
                            tabview.adjust();
                        }
                    }
                }, {}, { view: "button", type: "icon", icon: "question", css: "white", click: function () {
                    mcService.goToHelp();
                }, width: 30} ]},

                {
                    view : "scrollview",
                    body : {
                        view: "multiview",
                        animate: false,
                        cells: [upTabMain, upTabWork, upGroupList, upTabPersonal, upTabInterest, upTabSettings, upConfs]
                    }
                }
            ]
        }]
    });

    $scope.fillUserData();

    // ===============================

    if ($$('upChangePwdButton')) {
        $$('upChangePwdButton').destructor();
    }

    if (mcService.checkRights(125)){
        webix.ui({
            container : "upUserPWD",
            view      : "button",
            css       : "fotoBtn",
            id        : "upChangePwdButton",
            height    : 23,
            width     : 150,
            value     : mcService.Lang(106),
            disabled  : $scope.data.AuthType == mcConst._CMD_.loginStyle.NO_PASS || $scope.data.AuthType == mcConst._CMD_.loginStyle.AD || $scope.data.AuthType == mcConst._CMD_.loginStyle.AD_TRANSPARENT,
            click     : function() {
                $scope.pwdDialog = $scope.createChangePwdWindow(300, mcService.Lang(125));

                $scope.pwdDialog.show();
            }
        });
    }

    // -------------------------------------

    $scope.dismissBTN     = $$("dismissBTN" + $scope.Name);
    $scope.upOtherSysInfo = $$("upOtherSysInfo");

    $scope.upOtherSysInfo.getChildViews().forEach(function (t) {
        $scope.upOtherSysInfo.removeView(t);
    });

    if ($scope.userConnectionsInfo.length) {
        $scope.upOtherSysInfo.addView({
            cols: [{
                width: blockWidth,
                rows: [{
                    view: "property",
                    autoheight: true,
                    elements: [].concat([{ type: "label", css: 'headerLineHeight', label: mcLang(2072) }]) // "2072":"История подключений",
                }]
            }, {}   ]
        });

        $scope.userConnectionsInfo.forEach(function (elem, idx) {
            var tt = $scope.upOtherSysInfo.addView({
                cols: [{
                    width: blockWidth,
                    rows: [{
                        view: "property",
                        nameWidth: 200,
                        autoheight: true,
                        elements: [].concat([{ type: "label", css: 'headerLineHeightLight', label: elem.ClientType }]).concat(mcService.trim(elem.Ver) === "" ? [] : { view: "text", value: elem.Ver, label: "Ver", css: "selectable" }).concat(mcService.trim(elem.LastAccess) === "" ? [] : { view: "text", value: mcService.sortableDate(mcService.utcTime(elem.LastAccess)), label: "LastAccess", css: "selectable" }).concat(mcService.trim(elem.IP) === "" ? [] : { view: "text", value: elem.IP, label: "IP", css: "selectable" }).concat(mcService.trim(elem.MAC) === "" ? [] : { view: "text", value: elem.MAC, label: "MAC", css: "selectable" }).concat(mcService.trim(elem.CompName) === "" ? [] : { view: "text", value: elem.CompName, label: "CompName", css: "selectable" }).concat(mcService.trim(elem.OS) === "" ? [] : { view: "text", value: elem.OS, label: "OS", css: "selectable" }).concat(mcService.trim(elem.Secured) === "" ? [] : { view: "text", value: elem.Secured ? "enabled" : "disabled", label: "Secured", css: "selectable" }).concat(mcService.trim(elem.HardwareID) === "" ? [] : { type: "text", value: elem.HardwareID, label: "HardwareID", css: "selectable" }).concat(mcService.trim(elem.IPList) === "" ? [] : { type: "text", value: elem.IPList, label: "IPList", css: "selectable" }).concat(mcService.trim(elem.Reflink) === "" ? [] : { type: "text", value: elem.Reflink, label: "Reflink", css: "selectable" }).concat(mcService.trim(elem.BrowserInfo) === "" ? [] : { type: "text", value: elem.BrowserInfo, label: "BrowserInfo", css: "selectable" })
                    }]
                }, {}]
            });

            $$(tt).getChildViews()[0].getChildViews()[0].refresh();
        });
    }

    // ===============================

    mcService.disableContextMenu(tabview, ["selectable"]);

    return tabview;
}
function userProfileController($scope, $rootScope){
    "use strict";

    $scope.Name   = mcConst.dataModels.UserProfile;
    $scope.upView = null;
    $scope.workDepts = [];

    var angElement   = document.getElementById($scope.Name);
    var sName        = $scope.Name;
    var canChange    = false;
    var needChangePWD= false;
    var needRefreshCommonContacts = false;
    var backManager  = mcConst.dataModels.UserManager;
    var USER_PROFILE = 'USER_PROFILE';
    var canExit      = true;
    var initAuthType = mcConst._CMD_.loginStyle.STANDARD;
    var propList     = ['upAboutUser', 'upConfigAuth', 'upSystemInfo', 'upCompanyInfo', 'upCompanyAddress',
        'upCompanyMore', 'upPersonalInfo', 'upPersonalPhone', 'upPersonalAddress', 'upPersonalMore', 'upSpokenLang',
        'upInterests', 'upPast', 'upPastOrg', 'upSettingsAR', 'upSettingsCustom'];
    var conformity   = {
        'upUIN'        : 'upAboutUser',
        'upActive'     : 'upAboutUser',
        'upFirstName'  : 'upAboutUser',
        'upMiddleName' : 'upAboutUser',
        'upLastName'   : 'upAboutUser',
        'upNick'       : 'upAboutUser',
        'upSex'        : 'upAboutUser',
        'upEmail'      : 'upAboutUser',
        'upRole'       : 'upAboutUser',

        'upAuthType'        : 'upConfigAuth',
        'upDomainName'      : 'upConfigAuth',
        'upFtpPass'         : 'upConfigAuth',
        'upLoginPass'       : 'upConfigAuth',

        'upCompNetName' : 'upSystemInfo',
        'upIP'          : 'upSystemInfo',
        'upMAC'         : 'upSystemInfo',
        'upLastAccess'  : 'upSystemInfo',
        'upHardwareID'  : 'upSystemInfo',

        'upWorkCompanyName' : 'upCompanyInfo',
        'upWorkPositionIdx' : 'upCompanyInfo',
        'upWorkDeptIdx'     : 'upCompanyInfo',
        'upWorkOffice'      : 'upCompanyInfo',
        'upWorkPhone'       : 'upCompanyInfo',
        'upWorkFax'         : 'upCompanyInfo',
        'upWorkPager'       : 'upCompanyInfo',

        'upWorkStreetAddress' : 'upCompanyAddress',
        'upWorkCity'          : 'upCompanyAddress',
        'upWorkState'         : 'upCompanyAddress',
        'upWorkZIP'           : 'upCompanyAddress',
        'upWorkCountry'       : 'upCompanyAddress',

        'upWorkWWW' : 'upCompanyMore',

        'upBirthday'      : 'upPersonalInfo',
        'upMaritalStatus' : 'upPersonalInfo',

        'upHomeCellular' : 'upPersonalPhone',
        'upHomePhone'    : 'upPersonalPhone',
        'upHomeFax'      : 'upPersonalPhone',

        'upHomeStreetAddress' : 'upPersonalAddress',
        'upHomeCity'          : 'upPersonalAddress',
        'upHomeState'         : 'upPersonalAddress',
        'upHomeZIP'           : 'upPersonalAddress',
        'upHomeCountry'       : 'upPersonalAddress',

        'upHomeWWW' : 'upPersonalMore',

        'upSpokenLang1' : 'upSpokenLang',
        'upSpokenLang2' : 'upSpokenLang',
        'upSpokenLang3' : 'upSpokenLang',

        'upInterests1'      : 'upInterests',
        'upInterestsWords1' : 'upInterests',
        'upInterests2'      : 'upInterests',
        'upInterestsWords2' : 'upInterests',
        'upInterests3'      : 'upInterests',
        'upInterestsWords3' : 'upInterests',
        'upInterests4'      : 'upInterests',
        'upInterestsWords4' : 'upInterests',

        'upPast1'      : 'upPast',
        'upPastWords1' : 'upPast',
        'upPast2'      : 'upPast',
        'upPastWords2' : 'upPast',
        'upPast3'      : 'upPast',
        'upPastWords3' : 'upPast',

        'upPastOrg1'      : 'upPastOrg',
        'upPastOrgWords1' : 'upPastOrg',
        'upPastOrg2'      : 'upPastOrg',
        'upPastOrgWords2' : 'upPastOrg',
        'upPastOrg3'      : 'upPastOrg',
        'upPastOrgWords3' : 'upPastOrg',

        'upAutoreplay' : 'upSettingsAR',

        'upCustom1' : 'upSettingsCustom',
        'upCustom2' : 'upSettingsCustom',
        'upCustom3' : 'upSettingsCustom'
    };
    var profileUIN   = 0;
    var profileIsShowed = false;

    $rootScope.ErrorActions[70]  =  // "70" : "нельзя сменить ник, такое имя уже используется",
    $rootScope.ErrorActions[66]  =  // "66" : "недопустимый ник (или ФИО). Название заблокировано фильтром нецензурных выражений",
    $rootScope.ErrorActions[264] = function(){ // "264": "нельзя сменить email \"%s\" потому, что он уже используется в другой учётной записи",
        if (profileIsShowed) {
            canChange = false;
            
            loadProfile(profileUIN);
        }
    };

    function changeApplyData (id, val){
        $scope.changedData.data.ShowDesc  = true;
        $scope.changedData.data.Items[id] = mcService.correctStringWithCRLF(val);
        $scope.changedData.data.Desc      = mcService.Lang(590); // "590": "Список измененных параметров:<br>",
        $scope.changedData.data.Header    = mcService.Lang(589); // "589": "Сохранить изменения профиля?",

        for (var i in $scope.changedData.data.Items){
            $scope.changedData.data.Desc += "<br>" + i + ": <b>" + $scope.changedData.data.Items[i] + "</b>";
        }

        //applyFormIsShowed = true;
        $scope.changedData.CloseTitle = mcService.Lang(103) + " (ESC)";
        $scope.changedData.ApplyTitle = mcService.Lang(104) + " (CTRL+ENTER)";

        $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
    }

    function removeFromApplyData(id){
        delete $scope.changedData.data.Items[id];

        var flag = false;

        if (!Object.keys($scope.changedData.data.Items).length){
            $scope.changedData.data.Desc   = mcService.Lang(590); // "590": "Список измененных параметров:<br>",
            $scope.changedData.data.Header = mcService.Lang(589); // "589": "Сохранить изменения профиля?",
            $scope.changedData.CloseTitle  = mcService.Lang(1013) + " (ESC)";// "1013":"К списку пользователей",

            for (var i in $scope.changedData.data.Items){
                $scope.changedData.data.Desc += "<br>" + i + ": <b>" + $scope.changedData.data.Items[i] + "</b>";

                flag = true;
            }
        }

        if (!flag){
            clearChangedData();
        }

        $scope.changedData.data.ShowDesc  = flag;

        $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
    }

    function clearChangedData (){
        $scope.changedData.data.Items    = {};
        $scope.changedData.data.Desc     = "";
        $scope.changedData.data.ShowDesc = false;
        $scope.changedData.CloseTitle    = mcService.Lang(1013);// "1013":"К списку пользователей",
    }

    function loadProfile(uin){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_user_profile,
            mcConst.SessionID,
            uin,
            $scope.getData
        ]);
    }

    // ==== Change Password Form ==========================================

    $scope.createChangePwdWindow = function (width, head) {
        if ($$('upChangePwd')) {
            $$('upChangePwd').destructor();
        }

        function changePwdText() {
            var elem = this.getFormView().elements;

            if (mcService.trim(elem['password'].getValue()) != "") {
                elem["save"].enable();
            } else {
                elem["save"].disable();
            }
        }

        return webix.ui({
            view     : "window",
            position : "center",
            width    : width,
            id       : "upChangePwd",
            head     : head, // mcService.Lang(125),
            modal    : true,
            body     : {
                view : 'form',
                rules:{
                    "password" : webix.rules.isNotEmpty
                },
                elements : [{ cols: [
                        {
                            view       : "text",
                            placeholder: mcService.Lang(2), // "2"  : "Пароль",
                            type       : 'password',
                            name       : 'password',
                            required   : "true",
                            on         : {
                                onChange       : changePwdText,
                                onTimedKeyPress: changePwdText
                            }
                        }, {
                            view       : "button",
                            tooltip    : mcLang(1816), // "1816":"Сгенирировать пароль",
                            width      : 28,
                            type       : "icon",
                            icon       : "key",
                            click      : $scope.generateUserPwd
                        }
                    ]}, {
                    view       : "checkbox",
                    labelWidth : 0,
                    labelRight : mcService.Lang(1817), // "1817":"Показать пароль",
                    name       : "showpwd",
                    css        : "finger",
                    on         : { onChange: $scope.showHidePwd }
                }, {
                    cols : [{
                        view  : "button",
                        value : mcService.Lang(104), // "104": "Сохранить",
                        name  : "save",
                        disabled: true,
                        click : $scope.changePwd
                    }, {
                        view  : "button",
                        type  : "danger",
                        value : mcService.Lang(103), // "103": "Отмена",
                        click : $scope.cancelPwdChange
                    }]
                }]
            },
            on: { onShow: $scope.onShowNewUserRegForm, onHide: $scope.onHideNewRegForm }
        })
    };

    $scope.generateUserPwd = function () {
        this.getFormView().elements['showpwd'].setValue(1);
        this.getFormView().elements['password'].setValue(mcService.RandomHash(12, true));
    };

    $scope.onShowNewUserRegForm = function(){
        var Self = $scope.pwdDialog;
        var pwd  = Self.getBody().elements['password'];

        pwd.$setValue('');
        pwd.getInputNode().setAttribute("autocomplete", "new-password");
        pwd.focus();

        $scope.removeHotKey();
        $scope.regShowWindow(this.config.id, Self);

        $rootScope.hotKeyDispatcher.addPreset(Self.config.id, [{
            key:  mcConst.keyCodes.enter,
            func: function(){
                $scope.changePwd.apply(Self);
            }
        },{
            key:  mcConst.keyCodes.esc,
            func: function(){
                Self.hide();
            }
        }], document);
    };

    $scope.onHideNewRegForm = function(){
        $rootScope.hotKeyDispatcher.removePreset(this.config.id);
        $scope.registerHotKeys();
    };

    $scope.showHidePwd = function (val) {
        var pwd  = this.getFormView().elements['password'];

        if (!val){
            pwd.define('type', 'password');
        } else {
            pwd.define('type', 'text');
        }

        pwd.refresh();
        pwd.getInputNode().setAttribute("autocomplete", "new-password");
    };

    $scope.changePwd = function(){
        var form     = $scope.pwdDialog.getBody();
        var isValid  = form.validate();
        var pwd1     = form.elements['password'];
        var pwd1Val  = pwd1.getValue();

        if (isValid && pwd1Val) {
            if (needChangePWD){
                needChangePWD = false;

                $scope.applyChange($scope.data);
            }

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_set_user_password,
                mcConst.SessionID,
                $scope.data.UIN,
                pwd1Val
            ]);

            $$("upChangePwdButton").enable();

            webix.message({ type:"default", text: mcService.Lang(101) , expire: mcConst.errMessageExpire}); // "101": "Пароль успешно изменен!",

            setTimeout(function () {
                form.getTopParentView().hide();

                pwd1.setValue('');
            }, 10);
        }
    };

    $scope.cancelPwdChange = function(){
        this.getFormView().elements['password'].setValue('');
        this.getFormView().elements['showpwd'].setValue('');

        $$("upConfigAuth").config.elements[1].value = initAuthType;
        $$("upConfigAuth").refresh();

        this.getTopParentView().hide();
    };

    // ==============================================

    $scope.getFavoriteConfs = function () {
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_user_conf_list,
            mcConst.SessionID,

            $scope.data.UIN,

            function (data) {
                // "UID"         : 17, // идентификатор конференции
                // "ConfName"    : "Главная конференция",   // название конференции
                // "ConfTopic"   : "Общение на любые темы", // тема конференции
                // "ConfType"    : 1,                       // тип конференции, 1 - обычная, 2 - закрытая паролем, 3 - невидимая
                // "Owner"       : 17,                      // владелец конференции, её создатель. Если это UIN=0, то это автосоздаваемая конференция
                // "DisplayName" : "Monica Bellucci", // отображаемое имя владельца конференции
                // "CanKick"     : false              // true, если пользователя можно выгнать из конфы - он входит туда самостоятельно
                //                                    // если false - это значит, что он попадает в конфу согласно включаемых групп
                //                                    // или в конфу входит группа с индексом 0 (режим "Включать всех")

                var list = $$("upConfList" + $scope.Name);

                list.clearAll();
                list.parse(data);
                list.sort(function (a, b) {
                    return mcService.sortAB(a.UID, b.UID);
                });
            }
        ]);
    };

    $scope.getQrFromProfile = function () {
        $rootScope.$broadcast('showQrCode', [profileUIN]);
    };

    $scope.dismissUser = function (){
        if (mcService.checkRights(mcConst._CMD_.RS.QFireUsers)){
            var UIN     = $scope.data.UIN;

            if (UIN){
                if (UIN == 1 ){
                    webix.alert(mcLang(2211)); // "2211":"Нельзя уволить пользователя с UIN:1",
                } else { 
                    $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                        type  : "confirm-warning",
                        text  : mcLang(2210, [""]), // "2210":"Вы действительно хотите уволить пользователя?\\n\\n%s",
                        ok    : mcService.Lang(2207), // "2207":"Уволить",
                        cancel: mcService.Lang(103), // "103": "Отмена",
                        callback:function(yes){
                            if (yes){
                                $rootScope.$broadcast('SendCMDToServer', [
                                    mcConst.lockInterface,
                                    mcConst._CMD_.cs_adm_fire_users,
                                    mcConst.SessionID,
                                    UIN,

                                    function (){
                                        $scope.dismissBTN.hide();

                                        $$("upAboutUser").setValues({upActive: "0"}, true);

                                        $rootScope.needRefreshCommonContacts = true;
                                        $rootScope.$broadcast("getUserProfileForManager", [UIN]);
                                    }
                                ]);
                            }
                        }
                    }));
                }
            }
        }
    };

    $scope.getUserGroupsList = function (){
        $rootScope.$broadcast('SendCMDToServer', [
            // mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_all_user_group_membership_list,
            mcConst.SessionID,

            $scope.data.UIN,

            function (data) {
            // "UIN" : 17, // идентификатор пользователя
            // "Personal" : [
            //     {
            //         "Name"        : "Bla-bla-bla",
            //         "ID"          : 78,
            //         "UINOwner"    : 6,
            //         "DisplayName" : "John Smith"
            //     },
            // ],
            // "Common" : [
            //     {
            //         "Name"        : "Common Group",
            //         "ID"          : 12
            //     },
            //     ...
            // ]

                var personalList = $$("upPersonalGroup" + $scope.Name);
                var commonList   = $$("upCommonGroup" + $scope.Name);

                personalList.clearAll();
                personalList.parse(data.Personal);
                
                commonList.clearAll();
                commonList.parse(data.Common);

                console.log(data);
            }
        ]);
    }

    $scope.changedData = {
        CloseTitle : mcService.Lang(103) + " (ESC)",
        data    : {
            Header : "",
            Desc   : "",
            Items  : {},
            ShowDesc : false,
            Reopen : true
        },
        onApply : function(){
            var calcType = $scope.changedData.data.Items.AuthType || $scope.data.AuthType;
            var calcName = $scope.changedData.data.Items.DomainName !== undefined ? $scope.changedData.data.Items.DomainName : $scope.data.DomainName;

            initAuthType = $scope.data.AuthType;
            
            if ((calcType == mcConst._CMD_.loginStyle.AD || calcType == mcConst._CMD_.loginStyle.AD_TRANSPARENT) && !calcName ) {
                $$($scope.Name + 'tabbar').setValue('upTabMain');

                $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1362)]); // "1362":"Укажите имя домена",

                return false;
            } else {
                $scope.data = mcService.Marge($scope.data, $scope.changedData.data.Items); // _data;

                if ($scope.changedData.data.Items.AuthType == "0"){
                    if ($$("ChangePwdOnStandardAuth")){
                        $$("ChangePwdOnStandardAuth").destructor();
                    }

                    needChangePWD = true;

                    $scope.pwdDialog = $scope.createChangePwdWindow(500, mcService.Lang(1478)); // "1478":"Для обычной авторизации необходимо установить пароль",
                    $scope.pwdDialog.show();
                } else {
                    $scope.applyChange($scope.data);
                }

                $scope.changedData.data.Reopen = true;

                this.CloseTitle = mcService.Lang(1013) + " (ESC)";// "1013":"К списку пользователей",

                if ($scope.changedData.data.Items.Active) {
                    $scope.dismissBTN.show();
                } else
                if ($scope.changedData.data.Items.hasOwnProperty("Active") && !$scope.changedData.data.Items.Active) {
                    $scope.dismissBTN.hide();
                }

                clearChangedData();
            }
        },
        onClose : function(){
            if ($scope.changedData.data.Desc == "") {
                $rootScope.$broadcast('show' + backManager, ['open']);

                $rootScope.mcStorage.userFotoPath = {};

                clearChangedData();

                this.data.Reopen = false;
            } else {
                propList.forEach(function (list) {
                    $$(list).editStop();
                });

                $scope.fillUserData();

                $scope.changedData.data.ShowDesc = false;
                $scope.changedData.data.Reopen   = true;
            }

            this.CloseTitle   = mcService.Lang(1013) + " (ESC)";// "1013":"К списку пользователей",
        }
    };

    $scope.registerHotKeys = function(){
        $rootScope.hotKeyDispatcher.addPreset(USER_PROFILE, [{
            key    :  mcConst.keyCodes.enter,
            ctrlKey: true,
            func   : function (e) {
                if ($scope.changedData.data.Items && !mcService.isObjectEmpty($scope.changedData.data.Items)){
                    try {
                        $$(e.target.parentElement.parentElement.getAttribute("view_id")).editStop();
                    } catch (e) {}

                    $rootScope.$broadcast("apply" + mcConst.dataModels.ApplyPanel, []);

                    $rootScope.$broadcast("getUserProfileForManager", [$scope.data.UIN]);
                }
            }
        }, {
            key    :  mcConst.keyCodes.esc,
            func   : function () {
                if (canExit){
                    $rootScope.$broadcast("close" + mcConst.dataModels.ApplyPanel, []);
                }
            }
        }], document);
    };

    $scope.removeHotKey = function(){
        $rootScope.hotKeyDispatcher.removePreset(USER_PROFILE);
    };

    $scope.noExitByEsc = function () {
        canExit = false;
    };

    $scope.showApplyForm = function(state, editor){
        var newV = null;
        var oldV = null;
        var id   = null;

        canExit = true;

        if (editor || (this.getEditor() != 0)){
            if (arguments.length === 0){
                editor = editor || this.getEditor();

                id = mcService.copy(editor.id, 2);

                newV = mcService.trim(editor.getValue());
                oldV = mcService.convertBool($scope.data[id]);
            } else {
                id = mcService.copy(editor.id, 2);

                newV = mcService.trim(state.value);
                oldV = mcService.convertBool($scope.data[id]);//state.old;
            }

            if (mcConst.isShowed === $scope.Name && (editor)){
                var pwdBtn = $$("upChangePwdButton");

                switch (editor.id) {
                    case 'upWorkDeptIdx':
                        needRefreshCommonContacts = true;
                    break;

                    case 'upAuthType':
                        if (newV == 1|| newV == 3){
                            $$("upAboutUser").setValues({upNick: $scope.data.Nick}, true);

                            changeApplyData('Nick', $scope.data.Nick);
                        }
                    break;

                    case 'upAutoreplay':
                        newV = mcService.convertIntToBool(newV);
                    break;

                    case 'upActive':
                        newV = mcService.convertIntToBool(newV);

                        if (newV) {
                            // $scope.changedData.data.Items.Nick = $scope.data.Nick.toLowerCase(); // не понятно зачем делать ник в ловеркейме??

                            $$("upAboutUser").setValues({upNick: $scope.data.Nick}, true);
                        }
                    break;

                    case 'upNick':
                        newV = mcService.trim(newV.replace(/\u2022|\u0002|\u0003|\u000b|\r|\n/g, ""));

                        if (!newV){
                            return;
                        }
                    break;
                }

                changeApplyData(id, newV);

                if (pwdBtn &&
                    ($scope.changedData.data.Items.AuthType == mcConst._CMD_.loginStyle.AD ||
                     $scope.changedData.data.Items.AuthType == mcConst._CMD_.loginStyle.AD_TRANSPARENT ||
                     $scope.changedData.data.Items.AuthType == mcConst._CMD_.loginStyle.NO_PASS)
                ) {
                    pwdBtn.disable();
                } else
                if (pwdBtn && !$scope.changedData.data.Items.AuthType && $scope.data.AuthType == mcConst._CMD_.loginStyle.STANDARD){
                    pwdBtn.enable();
                }
            }
        }
    };

    $scope.changeTextArea = function(newV, oldV){
        var id = mcService.copy(this.config.id, 2);

        if (arguments.length === 0){
            newV = mcService.trim(this.getValue());
            oldV = $scope.data[id];
        } else {
            newV = mcService.trim(this.getValue());
        }

        if (mcConst.isShowed === $scope.Name && ((newV !== oldV) && canChange)){
            changeApplyData(mcService.copy(this.config.id, 2), newV);
        }
    };

    $scope.uploadFoto = function(item){
        var file = item.file;
        var type = item.type.toLowerCase();
        var res  = true;

        if(file && (type === "jpg" || type === "png" || type === "jpeg")){
            $rootScope.$broadcast(mcConst.lockInterface, []);

            var reader = new FileReader(); // We need to use a FileReader to actually read the file.

            reader.onload = function(event){
                $$('upFoto').define('template', '<canvas id="upFotoCanvas" height="' + mcConst.userFoto.h + '" width="' + mcConst.userFoto.w + '"></canvas>');
                $$('upFoto').refresh();

                var img = new Image();

                img.src = event.target.result;

                img.onload = function(){
                    var _canvas = document.createElement('canvas');
                    var resized = document.getElementById('upFotoCanvas');

                    _canvas.width  = img.width;
                    _canvas.height = img.height;

                    if ((_canvas.height <= mcConst.userFoto.h) && (_canvas.width <= mcConst.userFoto.w)){
                        resized.width  = _canvas.width;
                        resized.height = _canvas.height;
                    } else
                    if (_canvas.width >= _canvas.height) {
                        resized.width  = mcConst.userFoto.w;
                        resized.height = _canvas.height / (_canvas.width / mcConst.userFoto.w);
                    } else {
                        resized.width  = _canvas.width / (_canvas.height / mcConst.userFoto.h);
                        resized.height = mcConst.userFoto.h;
                    }

                    var ctx = _canvas.getContext('2d');

                    ctx.fillStyle = '#fff';
                    ctx.fillRect(0, 0, _canvas.width, _canvas.height);
                    ctx.drawImage(img, 0, 0, img.width, img.height);

                    canvasResize(_canvas, resized, function(){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.NewFoto,
                            mcConst.SessionID,
                            $scope.data.UIN,

                            resized.toDataURL('image/jpeg')
                        ]);

                        $rootScope.$broadcast('hide' + mcConst.lockInterface, []);
                    });
                };
            };

            reader.onerror = function(){
                $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(901) + file.name]); // "901":"Ошибка чтения файла: ",

                $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

                res = false;
            };

            reader.readAsDataURL(file);
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(901) + file.name]); // "901":"Ошибка чтения файла: ",

            $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

            res = false;
        }

        if (!res) {
            return res;
        }
    };

    $scope.fillUserData = function(){
        for (var i in $scope.data){
            var item = $$('up' + i);
            var value = $scope.data[i];

            switch (i){
                case 'LastAccess': value = mcService.toNormalDate(value.split('.'), true); break;
                case 'Birthday'  : value = mcService.toNormalDate(value.split('.'), false); break;
            }

            if (mcService.isObject(item)){
                item.setValue(mcService.convertBool(value));
            } else
            if (item === true) {
                item.setValue(mcService.convertBool(value));
            } else {
                var out = {};
                out['up' + i] = mcService.convertBool(value);

                item = $$(conformity['up' + i]);

                if (item) {
                    item.setValues(out, true);
                }
            }
        }
    };

    $scope.drawFoto = function(path){
        $rootScope.mcStorage.userFotoPath = path;

        if (path && path.FileName){
            $$('upFoto').define('template', '<img id="upFotoCanvas" src="' + path.FileName + '">');
            $$('upFoto').refresh();
        }

        canChange = true;
    };

    $scope.clearFoto = function(){
        $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
            type  : "confirm-warning",
            text  : mcService.Lang(665, $scope.data.Nick + ' (' + $scope.data.UIN + ')'), // "665": "Удалить фотографию пользователя %s?",
            ok    : mcService.Lang(581), // "581": "Удалить",
            cancel: mcService.Lang(103), // "103": "Отмена",
            callback:function(yes){
                if (yes){
                    $rootScope.$broadcast('SendCMDToServer', [
                        mcConst._CMD_.cs_adm_clear_user_foto,
                        mcConst.SessionID,
                        $scope.data.UIN
                    ]);

                    $$('upFoto').define('template', '<img id="upFotoCanvas" src="" border="0">');
                    $$('upFoto').refresh();

                    webix.message(mcService.Lang(664)); // "664": "Фото пользователя удалено",
                }
            }
        }));
    };

    $scope.show = function (data){
        $scope.data = data || [];
        $scope.workPosition = $rootScope.mcStorage.WorkPositions;
        $scope.groupeRights = $rootScope.mcStorage.GroupRights;

        $scope.changedData.CloseTitle  = mcService.Lang(1013) + " (ESC)";// "1013":"К списку пользователей",

        mcService.showCurrentView(sName, $rootScope, angElement, { callBack: clearChangedData });

        $scope.upView = initUserProfileView($scope);

        mcService.initResize($scope.upView, sName);

        $scope.registerHotKeys();

        $scope.upView.adjust();

        profileIsShowed = true;
    };

    $scope.applyChange = function(data){
        $rootScope.needRefreshCommonContacts = true;

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_modify_user_profile,
            mcConst.SessionID,
            JSON.stringify(data)
        ]);

        $rootScope.$broadcast("getUserProfileForManager", [data.UIN]);

        webix.message(mcService.Lang(666)); // "666": "Профиль изменен!",
    };

    $scope.profileFotoRefresh = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_web_get_user_foto_file,
            mcConst.SessionID,
            $scope.data.UIN,
            $scope.drawFoto
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.getData = function(data){
        var taskList = new mcService.TaskList;

        $rootScope.mcStorage[mcConst.dataModels.UserProfile] = data;
        $scope.userConnectionsInfo = data.Connections;

        // ==== Get Job Position ===
        taskList.AddTask(function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_job_positions_list,
                mcConst.SessionID,
                function (data) {
                    $rootScope.mcStorage[mcConst.dataModels.WorkPositions] = data.Data;

                    taskList.Next();
                }
            ]);
        });

        // === Get Roles List ===
        taskList.AddTask(function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_list_roles,
                mcConst.SessionID,
                function (data) {
                    $rootScope.mcStorage[mcConst.dataModels.GroupRights] = data;
                    taskList.Next();
                }
            ]);
        });

        // == Get Depts List ===
        taskList.AddTask(function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_get_depts_list,
                mcConst.SessionID,
                function( depts ) {
                    $scope.workDepts = mcService.formatDeptList(depts);

                    taskList.Next();
                }
            ]);
        });

        // Get Domain List
        taskList.AddTask(function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_domains_list,
                mcConst.SessionID,
                function( data ) {
                    $scope.domainsList = data.List.split(',');

                    if (data.List !== "") {
                        $scope.domainsList.unshift("");
                    }

                    taskList.Next();
                }
            ]);
        });

        // === Show ===
        taskList.AddTask(function(){
            $scope.show(data);

            taskList.Next();
        });

        taskList.AddTask(function(){
            $scope.profileFotoRefresh();

            $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
        });

        taskList.Run();
    };

    $scope.$on('profileFotoRefresh', $scope.profileFotoRefresh);

    $scope.$on('hide' + sName, function() {
        profileIsShowed = false;

        $scope.removeHotKey();

        mcService.hideView(angElement);
    });

    $scope.$on('show' + sName, function(e, args) {
        canChange   = false;
        backManager = args[1] || mcConst.dataModels.UserManager;
        profileUIN  = args[0];

        if (args[0] === 'reshow'){
            $scope.fillUserData();
            $scope.drawFoto($rootScope.mcStorage.userFotoPath);
        } else {
            loadProfile(profileUIN);
        }
    });
}



"use strict";

function initWorkPositions($scope){
    var WorkPositions = $$($scope.Name);

    if (!WorkPositions){
        $scope.mcLEB.initTextSource({
            add  : mcLang(50),
            edit : mcLang(51),
            del  : mcLang(52),
            clone: mcLang(579)
        });

        var editButtons = $scope.mcLEB.editButtons({
            actions: {
                add  : $scope.add,
                edit : $scope.edit,
                del  : $scope.del,
                clone: $scope.clone
            },
            actionTitles: {
                add  : mcLang(906), // "906":"Добавление должности",
                edit : mcLang(905), // "905":"Редактирование должности",
                del  : mcLang(902), // "902":"Удалить должность \"%s\"?",
                clone: mcLang(907)  // "907":"Клонирование должности",
            },
            additionalItems: [{
                view       : "checkbox",
                labelRight : mcService.Lang(903), // "903":"Руководитель подразделения",
                labelWidth : 0
            }],
            hotKeys  : {
                add  : {
                    keyTitle: mcLang(50) + " | Ins",
                    key     : mcConst.keyCodes.insert
                },
                del  : {
                    keyTitle: mcLang(52) + " | Del",
                    key     : mcConst.keyCodes.delete
                },
                edit : {
                    keyTitle: mcLang(51) + " | Enter",
                    key     : mcConst.keyCodes.enter
                }
            },
            delName  : "Name",
            fillItems: ["Name", "TeamLead"],
            editTitle: mcLang(904), // "904":"Название должности",
            list     : "wpList"
        });

        var _wpList = {
            view     : "list",
            select   : true,
            id       : "wpList",
            data     : $scope.data,
            navigation: true,
            template : function(obj){
                return mcService.myReplaceFormated("<div class='#{class}'>#{name}</div>", {
                    class: obj.TeamLead ? "dbClickWpList blue" : "dbClickWpList",
                    name : obj.Name
                });
            },
            drag     : true,
            on       : {
                onAfterSelect  : function(id){
                    $scope.selectedItem = this.getItem(id);
                },
                onBeforeDrag: function(){
                    return this.config.drag;
                },
                onItemDblClick : editButtons.startEdit,
                onAfterDrop    : $scope.newSequence
            }
        };

        var filter = new mcService.FilterFiled({
            listName     : 'wpList',
            filterParams : ['Name']
        });

        WorkPositions = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(588) }, // "588": "Должности компании",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: "layout", cols: [
                    { width: 600, padding: 4, rows: [
                        editButtons.btnList,
                        { height: 4},

                        filter,

                        _wpList,

                        { id: "workPositionSort" + $scope.Name, view: "checkbox", labelRight: mcService.Lang(1820), labelWidth: 0, value: $scope.sortPosition, css: "finger",
                            on: { onChange: $scope.sortList }
                        }  // "1820":"Автоматически сортировать должности по алфавиту",

                    ]}, {}
                ]},

                { id: "tip" + $scope.Name, template : mcService.Lang(909), hidden: $scope.sortPosition, height: 30, css: 'sizeBigger'}// "909":"Чтобы переместить должность в списке - перетащите ее мышкой на нужную позицию",
            ]
        });

        $scope.wpList = $$('wpList');
        $scope.wpList.select($scope.wpList.getFirstId());
        $scope.tipDD = $$("tip" + $scope.Name);

        $scope.workPositionSort = $$("workPositionSort" + $scope.Name);

        $scope.wpList.config.drag = !$scope.sortPosition;
        $scope.editButtons = editButtons;

        mcService.disableContextMenu(WorkPositions);

        $scope.registerMenuKeys = editButtons.enableHotKeys;
        $scope.removeHotKeys    = editButtons.disableHotKeys;
    } else {
        $scope.wpList.clearAll();
        $scope.wpList.define('data', $scope.data);
        $scope.wpList.refresh();
    }

    $scope.wpList.select($scope.wpList.getFirstId());

    webix.UIManager.setFocus($scope.wpList);

    return WorkPositions;
}


"use strict";

function workPositionsController($scope, $rootScope){
    $scope.Name         = mcConst.dataModels.WorkPositions;
    $scope.selectedItem = null;
    $scope.workDialogWindow = null;
    $scope.sequence     = '';
    $scope.wpList       = null;
    $scope.mcLEB        = new window.mcWidgets.ListEditButtons($rootScope);
    $scope.sortPosition = false;

    var sortStyle  = "asc";
    var angElement = document.getElementById($scope.Name);

    function sendCMD(cmd, cb, id){
        var form = this;
        var name = form.getChildViews()[0].getValue();
        var teamLeader = mcService.convertIntToBool(form.getChildViews()[1].getValue());

        if (checkName(name, id)){
            var params = [cmd, mcConst.SessionID];

            if (id) {
                params.push(id);
            }

            params.push(name);
            params.push(teamLeader);
            params.push(cb);

            $rootScope.$broadcast('SendCMDToServer', params);
        } else {
            return true;
        }
    }

    function checkDuplicate (name, id){
        var res = true;

        for (var i = 0; i < $scope.data.length; i++){
            if (id && (id == $scope.data[i].ID)){
                continue;
            }

            if ($scope.data[i].Name == name){
                res = false;

                break;
            }
        }

        return res;
    }

    function checkName(name, id){
        var _name = mcService.trim(name);
        var res   = false;

        if ((_name != '') && mcService.isSymbolicNumbers(_name) && checkDuplicate(_name, id)){
            res = true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(908)]); // "908":"Название должности не должно быть пустым и совпадать с уже существующим!",
        }

        return res;
    }

    function sort() {
        if ($scope.workPositionSort.getValue()){
            $scope.wpList.sort("#Name#", sortStyle, "string");

            $scope.newSequence();
        }
    }

    function add(data){
        var list = $scope.wpList;

        list.add(data);
        list.select(list.getLastId());
        list.scrollTo(0, 9999);

        $scope.data.push(data);

        sort();

        $rootScope.mcStorage[mcConst.dataModels.WorkPositions] = $scope.data;
    }

    // ============================================

    $scope.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_job_positions_del,
            mcConst.SessionID,
            item.ID,
            function(){
                var list = $scope.wpList;
                var r_id = mcService.getIdxByIdFromData($scope.data, $scope.selectedItem.id);

                list.remove($scope.selectedItem.id);
                list.select(list.getFirstId());

                if (r_id) {
                    $scope.data.splice(r_id, 1);
                }

                $rootScope.mcStorage[mcConst.dataModels.WorkPositions] = $scope.data;
            }
        ]);
    };

    $scope.add = function(){
        var res = sendCMD.apply(this, [mcConst._CMD_.cs_adm_job_positions_add, add]);

        $scope.selectedItem = null;

        return res;
    };

    $scope.edit = function(){
        return sendCMD.apply(this, [mcConst._CMD_.cs_adm_job_positions_modify, function(data){
            var list = $scope.wpList;
            var item = list.getItem($scope.selectedItem.id);
            var m_id = mcService.getIdxByIdFromData($scope.data, $scope.selectedItem.id);

            item.Name = data.Name;
            item.TeamLead = data.TeamLead;

            list.refresh();

            if (m_id) {
                $scope.data[m_id] = data;
            }

            $rootScope.mcStorage[mcConst.dataModels.WorkPositions] = $scope.data;
        }, $scope.selectedItem.ID]);
    };

    $scope.clone = function(){
        return sendCMD.apply(this, [mcConst._CMD_.cs_adm_job_positions_add, add]);
    };

    $scope.buildSequence = function(data){
        var sequence= [];

        for (var i = 0; i < data.length; i ++){
            sequence.push(data[i].ID);
        }

        return sequence.join(',');
    };

    $scope.newSequence = function(){
        $scope.data = [];

        $scope.wpList.data.each(function(obj){
            $scope.data.push(obj);
        });

        var sequence = $scope.buildSequence($scope.data);

        if (sequence != $scope.sequence){
            $scope.sequence = sequence;

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_job_positions_set_sequence,
                mcConst.SessionID,
                $scope.sortPosition,
                $scope.sequence
            ]);
        }
    };

    $scope.sortList = function (newVal) {
        sortStyle = newVal ? "asc" : "";

        $scope.sortPosition = mcService.convertIntToBool(newVal);

        sort();

        if (newVal){
            $scope.tipDD.hide();

            $scope.wpList.config.drag = false;
        } else {
            $scope.tipDD.show();

            $scope.wpList.config.drag = true;
        }
    };

    $scope.getData = function(){
        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_job_positions_list,
            mcConst.SessionID,
            function(data){
                $scope.sortPosition = data.SortPositions;

                $rootScope.mcStorage[mcConst.dataModels.WorkPositions] = data.Data;

                $scope.show(data.Data);

                $scope.registerMenuKeys();
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(data){
        $scope.data         = data;
        $scope.sequence     = $scope.buildSequence($scope.data);

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initWorkPositions($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();

        if ($scope.selectedItem){
            $scope.wpList.data.each(function(obj){
                if (obj.ID == $scope.selectedItem.ID) {
                    $scope.wpList.select(obj.id);
                }
            });
        }
    };

    $scope.$on('hide' + $scope.Name, function(){
        $scope.selectedItem = null;

        mcService.hideView(angElement);

        $scope.removeHotKeys();
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.getData();
    });
}

function initContacts($scope) {
    "use strict";

    function onItemSelect(id) {
        var item = this.getItem(id);

        if (item) {
            if (item.IsGroup) {
                $scope.groupID = this.getItem(id).GroupID;
                $scope.renameDept.enable();

                $$("renameDeptContext" + $scope.Name).enable();
            } else {
                $scope.groupID = this.getItem(id).ParentID;
                $scope.renameDept.disable();

                $$("renameDeptContext" + $scope.Name).disable();
            }

            $scope.selectedItem = id;

            $scope.addNewDept.enable();
            $scope.deleteDept.enable();
        }
    }

    function icon(obj){
        if (obj.$count || obj.needLoad){
            if (obj.open)
                return "<div class='webix_tree_open'></div>";
            else
                return "<div class='_tree_close'></div>";
        } else
            return "<div class='webix_tree_none'></div>";
    }

    var settings   = $$($scope.Name);
    $scope.groupID = 0;

    if (!settings) {
        var contactsTree = {
            view          : "treetable",
            resizeColumn  : true,
            id            : "contactsList" + $scope.Name,
            drag          : true,
            select        : "row",
            header        : false,
            multiselect   : true,
            navigation    : false,
            css           : "noBorderAll noWhiteSpace",
            fixedRowHeight:false,
            rowLineHeight :25,
            rowHeight     :25,
            columns       : [{
                id       : "DisplayName",
                fillspace: true,
                template : function (obj, common) {
                    var res  = "";
                    var name = "";

                    if (obj.IsGroup) {
                        var color = obj.$level > 1 ? "#00720d" : "black";

                        name = mcService.insertIco("fa-users", "smaller") + "<span class='treeBranchContacts webix_tree_item' style='color:" + color + ";'>" + obj.DisplayName + "</span>";
                    } else

                    if (obj.TeamLead) {
                        name = "<span class='teamlead'>" + mcService.insertIco("fa-user", "smaller") + obj.DisplayName + "</span>";
                    } else {
                        name = mcService.insertIco("fa-user", "smaller") + obj.DisplayName;
                    }

                    // res = icon(obj, common) + "<span style='cursor: pointer;'>" + name;
                    res = common.icon(obj, common) + "<span style='cursor: pointer;'>" + name;

                    if (!obj.IsGroup) {
                        res += " <span style='" + (mcService.isFuckingFirefox() ? "" : "float:right; ") + "color:#666; magrin-rigth: 19px; padding: 0; background: none; font-size: 85%'>(UIN: " + obj.UIN + ")</span>";
                    }

                    res += "</span>";

                    return common.space(obj) + res;
                }
            }],
            on: {
                onItemDblClick: function (info){
                    if (this.isBranchOpen(info.row)){
                        this.close(info.row);
                    } else {
                        this.open(info.row);
                    }
                },
                onAfterSelect: onItemSelect,
                onBeforeContextMenu: function (id) {
                    onItemSelect.apply(this, [id]);

                    if (!this.getSelectedItem() || !this.getSelectedItem().length) {
                        this.select(id, true);
                    }
                },
                onBeforeDrop: $scope.beforeDropToTree,
                onAfterDrop: function (context) {
                    $scope.treeToData();

                    if (context.from.config.view === "datatable") {
                        $scope.refreshFreeUsers($scope.viewUsersList.data.count());
                    }

                    $scope.sortTree();

                    // console.log('---- onAfterDrop ---');
                    // console.log(mcService.Marge({}, $scope.plainContactsList));

                    // $scope.viewCommonContacts.refresh();
                }
            }
        };

        var freeUserList = {
            view        : "datatable",
            resizeColumn: true,
            id          : "freeUserList" + $scope.Name,
            drag        : true,
            select      : "row",
            multiselect : true,
            headerRowHeight: 25,
            minColumnWidth : 70,
            navigation  : false,
            columns     : [
                { id:"UIN",         header:"UIN", width: 55,     sort:"int"},
                { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
            ],
            on: {
                onBeforeDrop: $scope.beforeDropToList,
                onAfterDrop: function () {
                    $scope.treeToData();
                    $scope.viewUsersList.sort("UIN", "asc", "int");
                    $scope.refreshFreeUsers($scope.viewUsersList.data.count());

                    // $scope.viewUsersList.show();
                }
            }, onContext: {}
        };

        settings = webix.ui({
            type      : "space",
            padding   : 5,
            container : $scope.Name,
            id        : $scope.Name,
            borderless: true,
            rows      : [
                {
                    cols: [
                        { view: "template", type: "header", template: mcService.Lang(587) }, // "587": "Общий список контактов",
                        { view: "toolbar", width: 36, cols: [
                            { view: "button", type: "icon", icon: "question", width: 30,
                                click: function () {
                                    mcService.goToHelp();
                                }
                            }
                        ]}
                    ]
                },


                {
                    cols: [
                        {
                            type: "header", gravity: 2, rows: [
                                { height: 3 },
                                new mcService.FilterFiled({
                                    listName: "contactsList" + $scope.Name,
                                    filterParams: ['DisplayName', 'UIN']
                                }),
                                contactsTree
                            ]
                        },
                        { view: "resizer" },
                        {
                            cols: [
                                { width: 5 },
                                {
                                    rows: [
                                        {
                                            rows: [
                                                { view: "button", id: "addNewDept" + $scope.Name, value: mcService.Lang(958) + " (INS)", disabled: true, click: $scope.btns.add }, // "958":"Добавить дочернее подразделение",
                                                { view: "button", value: mcService.Lang(957), click: $scope.btns.addRoot }, // "957":"Добавить подразделение в корень",
                                                { view: "button", id: "renameDept" + $scope.Name, value: mcService.Lang(859) + " (F2)", disabled: true, click: $scope.btns.rename }, // "859":"Переименовать",
                                                { view: "button", id: "deleteDept" + $scope.Name, value: mcService.Lang(52) + " (DEL)", disabled: true, click: $scope.btns.del, type: "danger" }, // "52" : "Удалить",
                                                { view: "button", value: mcService.Lang(53), click: $scope.btns.refresh } // "53" : "Обновить",
                                            ]
                                        },
                                        { height: 5 },

                                        { view: "template", type: "header", template: mcService.Lang(1143), id: "freeUserListCount" + $scope.Name }, // "1143":"Пользователи вне списка",

                                        { height: 5 },
                                        new mcService.FilterFiled({
                                            listName: "freeUserList" + $scope.Name,
                                            filterParams: ['DisplayName', 'UIN']
                                        }),

                                        freeUserList
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        });

        $scope.viewCommonContacts = $$("contactsList" + $scope.Name);
        $scope.viewUsersList      = $$("freeUserList" + $scope.Name);
        $scope.freeUsersCount     = $$("freeUserListCount" + $scope.Name);

        $scope.addNewDept = $$("addNewDept" + $scope.Name);
        $scope.deleteDept = $$("deleteDept" + $scope.Name);
        $scope.renameDept = $$("renameDept" + $scope.Name);

        $scope.addNewDept.disable();
        $scope.deleteDept.disable();
        $scope.renameDept.disable();

        $scope.context = webix.ui({
            view: "context",
            body: {
                rows: [
                    { view: "button", value: mcService.Lang(958), click: $scope.btns.add }, // "958":"Добавить дочернее подразделение",
                    { view: "button", value: mcService.Lang(957), click: $scope.btns.addRoot }, // "957":"Добавить подразделение в корень",
                    { view: "button", id: "renameDeptContext" + $scope.Name, value: mcService.Lang(859), disabled: true, click: $scope.btns.rename }, // "859":"Переименовать",
                    { view: "button", value: mcService.Lang(52), click: $scope.btns.del, type: "danger" }, // "52" : "Удалить",
                    { view: "button", value: mcService.Lang(53), click: $scope.btns.refresh }, // "53" : "Обновить",
                    { $template:"Separator", height: 7 },
                ].concat(mcService.ContextMenu($scope.viewCommonContacts, true))
            },
            on: {
                onShow: function () {
                    $scope.regShowWindow(this.config.id, this);
                }
            },
            id: "contactsListContextMenu" + $scope.Name,
            master: $scope.viewCommonContacts
        });

        mcService.ContextMenu($scope.viewUsersList, null, null, function () {
            $scope.regShowWindow(this.config.id, this);
        });

        mcService.disableContextMenu(settings);
    } else {
        if ($scope.dataCommonContacts) {
            var tree = $scope.viewCommonContacts;

            tree.clearAll();
            tree.parse(webix.copy($scope.dataCommonContacts));

            if ($scope.treeState) {
                tree.setState($scope.treeState);
            }
        }
    }

    $scope.sortTree();

    return settings;
}
/**
 * Created by Gifer on 15.12.2016.
 */

function contactsModifyDialog($scope, text, $rootScope) {
    if ($scope.dialogWindow){
        $scope.dialogWindow.destructor();
    }

    var rnd = mcService.RandomHash(20);

    $scope.dialogWindow = webix.ui({
        view     : "window",
        position : "center",
        modal    : true,
        width    : 300,
        head     : $scope.wndHead,
        body     : {
            view : 'form',
            rules:{
                "Name"   : webix.rules.isNotEmpty
            },
            elements : [{
                view     : "text",
                id       : 'dialog' + $scope.Name,
                label    : mcService.Lang(956), // "956":"Название подразделения",
                name     : 'Name',
                required : "true",
                value    : text || "",
                labelPosition : 'top'
            }, {
                cols : [{
                    view  : "button",
                    value : mcService.Lang(104), // "104": "Сохранить",
                    click : function() {
                        var name = this.getFormView().getChildViews()[0].getValue().replace(/\\/g, '');

                        $scope.confirm(name);

                        $rootScope.hotKeyDispatcher.removePreset(rnd);
                    }
                }, {
                    view  : "button",
                    type  : "danger",
                    value : mcService.Lang(103), // "103": "Отмена",
                    click : function(){
                        $scope.dialogWindow.hide();

                        $rootScope.hotKeyDispatcher.removePreset(rnd);
                    }
                }]
            }]
        },
        on : {
            onShow : function(){
                var self = this;

                setTimeout(function(){
                    self.getChildViews()[1].getChildViews()[0].focus();
                }, 10);

                $scope.regShowWindow(this.config.id, this);
            }
        }
    });

    $rootScope.hotKeyDispatcher.addPreset(rnd, [{
        key    : mcConst.keyCodes.enter,
        func   : function() {
            var view = $scope.dialogWindow.getChildViews()[1];
            var val  = view.getChildViews()[0].getValue();

            $scope.confirm.apply(view, [val]);

            $rootScope.hotKeyDispatcher.removePreset(rnd);
        }
    }, {
        key    : mcConst.keyCodes.esc,
        func   : function() {
            $scope.dialogWindow.hide();

            $rootScope.hotKeyDispatcher.removePreset(rnd);
        }
    }], document, true);

    $scope.dialogWindow.show();
}
function contactsController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.Contacts;

    $scope.showDialog   = null;
    $scope.dialogWindow = null;
    $scope.confirm      = null;

    $scope.wndHead = "";

    $scope.viewCommonContacts = null;
    $scope.dataCommonContacts = null;
    $scope.viewUsersList      = null;
    $scope.dataUsersList      = null;

    $scope.selectedItem      = null;
    $scope.plainContactsList = null;
    $scope.btns              = {};
    $scope.freeUsersCount    = null;

    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        HideClose: true,
        onApply : function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_force_update_global_contacts,
                mcConst.SessionID
            ]);
        }
    };

    var angElement = document.getElementById($scope.Name);
    var COMMON_CONTACTS = "COMMON_CONTACTS";

    function convertDataToTree(data){
        function add(current, parent){
            var item = null;

            if (current.IsGroup){
                item = {
                    DisplayName: current.GroupName || current.DisplayName,
                    id         : current.ID || current.id,
                    ParentID   : current.ParentID,
                    GroupID    : current.GroupID,
                    IsGroup    : true,
                    // folder     : true,
                    data       : current.data || []
                };
            } else {
                item = {
                    DisplayName: current.DisplayName,
                    id         : current.ID || current.id,
                    ParentID   : current.ParentID,
                    UIN        : current.UIN,
                    TeamLead   : current.TeamLead
                };
            }

            parent.push(item);
        }

        var res = [];
        var structure = [];
        var _data = [].concat(data);
        var i = 0;

        while (_data.length > 0){
            if (_data[i].ParentID == -1){
                _data.splice(i, 1);
            } else
            if (_data[i].ParentID == 0){
                add(_data[i], res);
                add(res[res.length - 1], structure);

                _data.splice(i, 1);
            } else {
                var idx = mcService.findItemInArrayOfObj(structure, _data[i].ParentID, "GroupID");

                if (idx === -1 && !_data[i].IsGroup){
                    // idx = 0;
                    _data.splice(i, 1); // если нет группы для юзера - валим его, а то получается вечный цикл, если что придется валить его в базе
                }

                if (idx >= 0){
                    add(_data[i], structure);
                    add(structure[structure.length - 1], structure[idx].data);

                    _data.splice(i, 1);
                } else {
                    i++;
                }
            }

            if (i == _data.length) {
                i = 0;
            }
        }

        return res;
    }

    function removeListFromData(list, ident){
        var tree = $scope.plainContactsList;

        // console.log('---- removeListFromData ---');
        // console.log('before');
        // console.log(mcService.Marge({}, $scope.plainContactsList));

        for (var i = tree.length - 1; i > 0; i--){
            if (list.length > 0) {
                var idx = mcService.inArrayNoStrict(tree[i][ident || "id"], list);

                if (idx != -1){
                    tree.splice(i, 1);
                    list.splice(idx, 1);
                }
            } else {
                break;
            }
        }

        $scope.dataCommonContacts = convertDataToTree(tree);

        // console.log('---- removeListFromData ---');
        // console.log('after');
        // console.log(mcService.Marge({}, $scope.plainContactsList));
    }

    $scope.registerHotKeys = function(){
        $rootScope.hotKeyDispatcher.addPreset(COMMON_CONTACTS, [{
            key    : mcConst.keyCodes.insert,
            func   : $scope.btns.add
        }, {
            key    : mcConst.keyCodes.insert,
            ctrlKey: true,
            func   : $scope.btns.addRoot
        }, {
            key    : mcConst.keyCodes.delete,
            func   : $scope.btns.del
        }, {
            key    : mcConst.keyCodes.f2,
            func   : $scope.btns.rename
        }], document);
    };

    $scope.removeHotKey = function(){
        $rootScope.hotKeyDispatcher.removePreset(COMMON_CONTACTS);
    };

    $scope.filterTree = function (val){
        var tree = $scope.viewCommonContacts;
        var stateName = "viewCommonContacts";

        if (val !== '') {
            if (!webix.storage.local.get(stateName)){
                webix.storage.local.put(stateName, tree.getState());
            }

            tree.filter("#DisplayName#", val);
        } else {
            var state = webix.storage.local.get(stateName);

            if (state){
                tree.filter("#DisplayName#", val);
                tree.setState(state);

                webix.storage.local.remove(stateName);
            }
        }
    };

    $scope.treeToData = function(){
        $scope.dataCommonContacts = convertDataToTree(webix.copy($scope.plainContactsList));
    };

    $scope.addGroup = function(parentID){
        $scope.confirm = function (groupName){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_tcl_add_group,
                mcConst.SessionID,
                groupName.toString().replace(/(\/|\|\\)/ig, ""),
                parentID
            ]);

            $scope.dialogWindow.hide();
            $scope.showApplyPanel();
        };

        $scope.wndHead = mcService.Lang(959); // "959":"Добавление подразделения",
    };

    $scope.addNewUsers = function(context){ // source, target
        var item   = this.getItem(context.target);
        var source = [].concat(context.source);
        var target = (item.IsGroup) ? item.GroupID : item.ParentID;

        // console.log('---- addNewUsers ---');
        // console.log('before');
        // console.log(mcService.Marge({}, $scope.plainContactsList));

        for (var i = 0; i < source.length; i ++){
            source[i] = $scope.viewUsersList.getItem(source[i]).UIN;
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_tcl_add_users_list_to_group,
            mcConst.SessionID,

            source.join(','),
            target,

            function (data){
                var user = null;
                var tree = $scope.viewCommonContacts;

                for (var i = 0; i < context.source.length; i ++){
                    user = tree.getItem(context.source[i]);

                    user.ID = data[user.UIN];
                    user.ParentID = target;

                    if (user.hasOwnProperty("$template")){
                        delete user.$template;
                    }

                    $scope.viewCommonContacts.data.changeId(user.id, data[user.UIN]);

                    $scope.plainContactsList.push(webix.copy(user));
                }

                $scope.treeToData();
                $scope.sortTree();

                $scope.treeState = tree.getState();

                // tree.clearAll();
                // tree.parse(webix.copy($scope.dataCommonContacts));
                // tree.setState($scope.treeState);

                $scope.showApplyPanel();

                // console.log('---- addNewUsers ---');
                // console.log('after');
                // console.log(mcService.Marge({}, $scope.plainContactsList));
            }
        ]);
    };

    $scope.editGroup = function(id){
        $scope.confirm = function (groupName){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_tcl_rename_group,
                mcConst.SessionID,
                id,
                groupName + ""
            ]);

            $scope.viewCommonContacts.getItem(id).DisplayName = groupName;
            $scope.viewCommonContacts.refresh(id);

            //$scope.plainContactsList[mcService.findItemInArrayOfObj($scope.plainContactsList, groupName, "DisplayName")].DisplayName = groupName;
            $scope.plainContactsList[mcService.findItemInArrayOfObj($scope.plainContactsList, id, "ID")].DisplayName = groupName;

            $scope.dialogWindow.hide();

            $scope.showApplyPanel();
        };

        $scope.wndHead = mcService.Lang(1144); // "1144":"Переименование подразделения",
    };

    $scope.btns.add = function(){
        if ($scope.selectedItem !== null){
            $scope.viewCommonContacts.unselectAll();
            $scope.viewCommonContacts.select($scope.selectedItem);

            $scope.context.hide();

            $scope.addGroup($scope.groupID);
            $scope.showDialog();
        }
    };

    $scope.btns.addRoot = function(){
        $scope.context.hide();

        $scope.addGroup(0);
        $scope.showDialog();
    };

    $scope.btns.rename = function(){
        var item = $scope.viewCommonContacts.getItem($scope.selectedItem);

        if ($scope.selectedItem !== null && item && item.IsGroup) {
            $scope.context.hide();

            $scope.editGroup($scope.selectedItem);
            $scope.showDialog(item.DisplayName);
        }
    };

    $scope.btns.del = function(){
        if ($scope.selectedItem !== null) {
            $scope.del();

            $scope.context.hide();
        }
    };

    $scope.btns.refresh = function(){
        $scope.refresh('refresh');

        $scope.context.hide();
    };

    $scope.moveUsersToUnallocated = function(list){
        // console.log('---- moveUsersToUnallocated ---');
        // console.log(mcService.Marge({}, $scope.plainContactsList));

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_tcl_del_ids_list,
            mcConst.SessionID,
            list.join(',')
        ]);

        removeListFromData(list, "ID");

        // $scope.viewUsersList.sort("UIN", "asc", "int");

        $scope.showApplyPanel();
    };

    $scope.del = function(){
        var selected = $scope.viewCommonContacts.getSelectedItem();

        if (!mcService.isArray(selected)){
            selected = [selected];
        }

        if (selected.length > 0){
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(1142), // "1142":"Удалить выделенные элементы?",
                ok    : mcService.Lang(581), // "581": "Удалить",
                cancel: mcService.Lang(103), // "103": "Отмена",
                callback:function(yes){
                    if (yes){
                        var res = [];

                        // console.log('---- del group ---');
                        // console.log('before');
                        // console.log(mcService.Marge({}, $scope.plainContactsList));

                        $scope.filterTree('');

                        setTimeout(function(){
                            $scope.viewCommonContacts.data.each( function(obj){ // получаем текущий список элементов
                                res.push(obj.id);
                            });

                            for (var i = 0; i < selected.length; i++){ // удаляем выделенные
                                if ($scope.viewCommonContacts.getItem(selected[i].id)){
                                    $scope.viewCommonContacts.remove(selected[i].id);

                                    $scope.viewCommonContacts.refresh();
                                }
                            }

                            $scope.viewCommonContacts.data.each( function(obj){ // сравниваем оставшиеся элементы с изначальным списком и нахлдим разницу
                                var idx = mcService.inArrayNoStrict(obj.id, res);

                                if (idx !== -1) {
                                    res.splice(idx, 1);
                                }
                            });

                            var removeGroup = [];

                            for (var i = 0; i < res.length; i++){ // добавляем удаленных пользователей в список нераспределенных пользователей
                                var idx = mcService.findItemInArrayOfObj($scope.plainContactsList, res[i], "ID");

                                if (idx !== -1){
                                    var user = $scope.plainContactsList[idx];

                                    if(!user.GroupID){
                                        $scope.viewUsersList.add(webix.copy(user));
                                    } else {
                                        removeGroup.push(idx);
                                    }
                                }
                            }

                            removeGroup.forEach(function (gID) {
                                $scope.plainContactsList.splice(gID, 1);
                            });

                            $scope.refreshFreeUsers($scope.viewUsersList.data.count());

                            $rootScope.$broadcast('SendCMDToServer', [
                                mcConst.lockInterface,
                                mcConst._CMD_.cs_adm_tcl_del_ids_list,
                                mcConst.SessionID,
                                res.join(',')
                            ]);

                            removeListFromData(res, "ID"); // чистим структуры

                            $scope.selectedItem = null;
                            $scope.viewUsersList.sort("UIN", "asc", "int");

                            $scope.showApplyPanel();

                            $scope.addNewDept.disable();
                            $scope.renameDept.disable();
                            $scope.deleteDept.disable();

                            $scope.treeToData();
                            $scope.sortTree();

                            // console.log('---- del group ---');
                            // console.log('after');
                            // console.log(mcService.Marge({}, $scope.plainContactsList));

                        }, 100);
                    }
                }
            }));
        }
    };

    $scope.doFilter = function (list){
        var value = this.getValue().toLowerCase();

        list.filter(function(obj){
            return (obj.DisplayName.toLowerCase().indexOf(value) >= 0) ||
                (obj.UIN.toString().indexOf(value) >= 0);
        })
    };

    $scope.refreshFreeUsers = function(count){
        $scope.freeUsersCount.define('template', mcService.Lang(1143) + " [" + count + "]");
        $scope.freeUsersCount.refresh();
    };

    $scope.getAllUsers = function(){
        $rootScope.$broadcast('getAllUserList', [false,
            function(){
                $scope.dataUsersList = webix.copy($rootScope.mcStorage[mcConst.dataModels.UserManager].Users);

                $scope.viewUsersList.clearAll();
                $scope.viewUsersList.parse($scope.dataUsersList);
                $scope.viewUsersList.sort("UIN", "asc", "int");

                $scope.refreshFreeUsers($scope.dataUsersList.length);
            }, {
                Params : 'notincommoncontacts',
                Filters: 'UIN,DISPLAYNAME,TEAMLEAD'
            }
        ]);
    };

    $scope.refresh = function(cmd, data){
        switch (cmd){
            case 'addGroup':
                data.IsGroup     = true;
                data.DisplayName = data.GroupName;
                data.id          = data.ID;
                data.data        = [];

                // console.log('---- addGroup ---');
                // console.log('before');
                // console.log(mcService.Marge({}, $scope.plainContactsList));

                var _idx = null;

                if (data.ParentID == 0) {
                    $scope.plainContactsList.unshift(webix.copy(data));

                    _idx = $scope.viewCommonContacts.add(data);
                } else {
                    var inData = $scope.plainContactsList;
                    var _id    = mcService.findItemInArrayOfObj(inData, data.ParentID, "GroupID");
                     _idx      = inData[_id].ID;

                    inData.splice(_id + 1, 0, webix.copy(data));

                    $scope.dataCommonContacts = convertDataToTree(inData);

                    _idx = $scope.viewCommonContacts.add(data, ($scope.viewCommonContacts.getItem[$scope.selectedItem] && $scope.viewCommonContacts.getItem[$scope.selectedItem].IsGroup) ? -1 : 0, _idx);
                }

                $scope.sortTree();

                var _item = $scope.viewCommonContacts.getItemNode(_idx);

                if (_item){
                    $scope.viewCommonContacts.scrollTo(0, _item.offsetHeight);
                    $scope.viewCommonContacts.open(_idx);
                    $scope.viewCommonContacts.select(_idx);

                    // console.log('---- addGroup ---');
                    // console.log('after');
                    // console.log(mcService.Marge({}, $scope.plainContactsList));
                } else {
                    console.warn(_item);
                    console.warn(_idx);
                    console.warn(inData[_id]);
                    console.warn($scope.plainContactsList);
                }
            break;

            case 'refresh':
                $scope.treeState = $scope.viewCommonContacts.getState();
                $scope.dataCommonContacts = null;
                $scope.selectedItem = null;
                $scope.getData();
            break;
        }
    };

    $scope.beforeDropToList = function(context){
        // $scope.viewUsersList.hide();

        var res = true;

        if (context.from.config.view === "datatable") {
            return false;
        } else

        if (mcService.isArray(context.source)){
            for (var i = 0; i < context.source.length; i++){
                if (context.from.getItem(context.source[i]).IsGroup){
                    context.source.splice(i, 1);

                    i--;
                }
            }

            if (context.source.length == 0){
                res = false;
            }
        } else {
            res = this.getItem(context.source).IsGroup;
        }

        if (res) {
            $scope.moveUsersToUnallocated([].concat(context.source));
        }

        return res;
    };

    $scope.beforeDropToTree = function(context){
        // $scope.viewCommonContacts.hide();
        // console.log('---- beforeDropToTree ---');
        // console.log('before');
        // console.log(mcService.Marge({}, $scope.plainContactsList));

        var targetItem = this.getItem(context.target);
        var res        = mcService.inArrayNoStrict(context.target, context.source) === -1;
        var idx        = -1;
        var _parent    = 0;

        if (targetItem) { // calculate webix parent id
            if (targetItem.IsGroup) {
                _parent = targetItem.id;

                idx = mcService.findItemInArrayOfObj($scope.plainContactsList, targetItem.GroupID, "GroupID");
            } else {
                idx = mcService.findItemInArrayOfObj($scope.plainContactsList, targetItem.ParentID, "GroupID");

                if (idx >= 0) {
                    _parent = $scope.plainContactsList[idx].ID;
                } else {
                    res = false;

                    console.error('Not found item in plainContactsList');
                }
            }
        } else {
            res = context.from.config.view === "treetable";

            // $scope.viewCommonContacts.show();
        }

        // datatable -> treetable
        if (res && context.from.config.view === "datatable" && targetItem){
            // $rootScope.$broadcast(mcConst.lockInterface, []);

            $scope.addNewUsers.call(this, context);

            context.parent = _parent;
            context.index  = -1; // set in last position

            return true;
        } else
       
        // treetable -> treetable
        if (res && context.from.config.view === "treetable"){
            if (context.source.length > 1){
                var itemsList = [];

                $scope.viewCommonContacts.data.each( function(obj){ // получаем текущий список элементов
                    itemsList.push(obj);
                });

                for (var i = context.source.length - 1; i >= 0; i --){
                    var parentIDX = this.getParentId(context.source[i]);

                    while (parentIDX > 0) {
                        var _id  = mcService.findItemInArrayOfObj(itemsList, parentIDX, "id");
                        var _idx = mcService.inArrayNoStrict(itemsList[_id].id, context.source);

                        if (_id >= 0 && _idx >=0){
                            context.source.splice(i, 1);

                            break;
                        }

                        if (mcService.inArrayNoStrict(parentIDX, context.source) !== -1){
                            return false;
                        }

                        parentIDX = this.getParentId(parentIDX);
                    }
                }

                for (var i = 0; i < context.source.length; i++){
                    if (!targetItem && !this.getItem(context.source[i]).IsGroup){
                        return false;
                    }

                    var parentItem = this.getItem(_parent);

                    var idxParent  = mcService.findItemInArrayOfObj($scope.plainContactsList, context.source[i], "ID");

                    $scope.plainContactsList[idxParent].ParentID = (parentItem && parentItem.IsGroup) ? parentItem.GroupID : ((parentItem) ? parentItem.ParentID : 0);

                    this.getItem(context.source[i]).ParentID = $scope.plainContactsList[idxParent].ParentID;
                }
            } else {
                if ((!targetItem && !this.getItem(context.source[0]).IsGroup) ||
                    (!targetItem && this.getItem(context.source[0]).IsGroup && this.getItem(context.source[0]).ParentID == 0)){
                    return false;
                }

                var idxSource = mcService.findItemInArrayOfObj($scope.plainContactsList, context.source[0], "ID");

                $scope.plainContactsList[idxSource].ParentID = _parent ? $scope.plainContactsList[idx].GroupID : 0;

                this.getItem(context.source[0]).ParentID = $scope.plainContactsList[idxSource].ParentID;
            }
        }

        if (res){
            context.parent = _parent;
            context.index  = -1; // set in last position
        }

        if (res && context.source.length > 0){
            var userID = [];
            var groupID = [];

            for (var i = 0; i < context.source.length; i ++){
                var item = this.getItem(context.source[i]);

                if (item.IsGroup){
                    groupID.push(item.id);
                } else {
                    userID.push(item.id);
                }
            }

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_tcl_move_users_and_groups,
                mcConst.SessionID,

                _parent == 0 ? -1 : _parent,
                groupID.join(','),
                userID.join(',')
            ]);

            $scope.showApplyPanel();
        }

        // console.log('---- beforeDropToTree ---');
        // console.log('after');
        // console.log(mcService.Marge({}, $scope.plainContactsList));

        return res;
    };

    $scope.showApplyPanel = function(){
        $scope.changedData.data.ShowDesc = true;
        $scope.changedData.data.Header   = mcService.Lang(1479); // "1479":"Обновить список контактов всем пользователям",
        $scope.changedData.ApplyTitle    = mcService.Lang(1780); // "1780":"Разослать клиентам",

        $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
    };

    $scope.sortTree = function(source){
        return (source || $scope.viewCommonContacts).sort(function sortMakesAsc(a,b){
            var sort = 0;

            if (!a.IsGroup && !b.IsGroup) {
                if (a.TeamLead && b.TeamLead) {
                    sort = mcService.sortAB(a.DisplayName.toLowerCase(), b.DisplayName.toLowerCase());
                } else
                if (a.TeamLead) { sort = -1; } else
                if (b.TeamLead) { sort = 1;  } else {
                    sort = mcService.sortAB(a.DisplayName.toLowerCase(), b.DisplayName.toLowerCase());
                }
            } else
            if ( a.IsGroup && !b.IsGroup){ sort = -1; } else
            if (!a.IsGroup &&  b.IsGroup){ sort = 1;  } else
            if ( a.IsGroup &&  b.IsGroup){ sort = mcService.sortAB(a.DisplayName.toLowerCase(), b.DisplayName.toLowerCase()); }

            return sort;
        });
    };

    $scope.getData = function(noAllUsers){
        // if (!$scope.dataCommonContacts || $rootScope.needRefreshCommonContacts){
            $rootScope.$broadcast('SendCMDToServer', [
                // mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_total_contacts_list,
                mcConst.SessionID,

                function( data ){
                    $rootScope.needRefreshCommonContacts = false;

                    $rootScope.mcStorage[mcConst.dataModels.Contacts] = data;

                    $scope.plainContactsList = webix.copy($rootScope.mcStorage[mcConst.dataModels.Contacts]);

                    $scope.treeToData();
                    $scope.getAllUsers();
                    $scope.show();

                    // console.log('---- getData ---');
                    // console.log(mcService.Marge({}, $scope.plainContactsList));
                }
            ]);
        // }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){ // data
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initContacts($scope);

        mcService.initResize(settings, $scope.Name);

        if (!$scope.showDialog){
            $scope.showDialog = function (text){
                contactsModifyDialog($scope, text, $rootScope);
            }
        }

        settings.adjust();
    };

    $scope.$on('refresh' + $scope.Name, function(e, args){
        $scope.refresh.apply(null, args);
    });

    $scope.$on('hide' + $scope.Name, function(){
        $scope.removeHotKey();

        $scope.treeState = $scope.viewCommonContacts.getState();

        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.dataCommonContacts = null;

        $scope.show();

        $scope.registerHotKeys();

        $scope.getData();
    });
}


function initUsersImportsView($scope){
    "use strict";
    
    var _view = $$($scope.Name);

    if (!_view) {
        var _ad = [
            {id: '2', value: mcService.Lang(1512)}, // "1512":"Безпарольная авторизация",
            {id: '1', value: mcService.Lang(112)}, // "112": "Active Directory авторизация",
            {id: '0', value: mcService.Lang(111)}  // "111": "обычная авторизация",
        ];

        var _CSV = {
            id      : 'CSV' + $scope.Name,
            type    : "layout",
            cols : [{
                gravity: 4,
                rows : [{
                    cols: [{
                        type: "header", template : "<form accept-charset='windows-1251'><input id='fileUpload' name='files[]' type='file' accept='.csv,.txt,.ad'></form>" // "963":"Загрузить из файла:",
                    }, {
                        view   : "toolbar",
                        padding: 2,
                        width  : 180,
                        cols   : [{
                            view    : "toggle",
                            id      : "toggleSettings" + $scope.Name,
                            onLabel : mcService.Lang(964), // "964":"Скрыть настройки",
                            offLabel: mcService.Lang(970), // "970":"Показать настройки",
                            value   : true,
                            align   : "right",
                            click   : $scope.CSV.toggleSettings
                        }]
                    }]
                }, {
                    type: 'layout',
                    rows: [{
                        view   : "textarea",
                        id     : 'previewCSV' + $scope.Name,
                        css    : 'textArea',
                        borderless: true,
                        template: function inputTextareaTemplate(obj, common){
                            var name = obj.name || obj.id;
                            var id   = "x" + webix.uid();
                            var html = "<textarea " + // style='width:" + common._get_input_width(obj) + "px;'
                                       " placeholder=\"" + mcService.Lang(1000) + "\"" + // "1000":"Введите сюда форматированный текст для отбработки и импорта на сервер",
                                       " id='" + id + "' name='" + name + "' class='webix_inp_textarea' wrap='off'>" + (obj.value || "") + "</textarea>";

                            return common.$renderInput(obj, html, id);
                        }
                    }]
                }, { view:"resizer" }, {
                    rows: [{
                        cols : [{
                            type: "header", template : mcService.Lang(971) // "971":"Результат:",
                        }, {
                            view : "toolbar",
                            padding : 2,
                            cols: [{
                                view: "button",
                                value: mcService.Lang(968), // "968":"Обработать текст",
                                width: 200,
                                click: function(){
                                    var data = $scope.CSV.inputData.getValue();
                                    var spr = data.indexOf("\r\n") == -1 ? "\n" : "\r\n";

                                    data = data.replace(new RegExp(spr, "g"), $scope.rowSeparate($scope.CSV.options.rows));

                                    $scope.CSV.parseInputData(data);
                                }
                            }, {
                                view : "button",
                                value: mcService.Lang(969), // "969":"Загрузить на сервер",
                                id   : "importBTN" + $scope.Name,
                                width: 200,
                                css  : "applyButton",
                                click: $scope.CSV.sendDataToServer
                            }]
                        }]
                    }, {
                        view      : "datatable",
                        id        : "csvDataTable" + $scope.Name,
                        resizeColumn: false,
                        navigation: true,
                        editable  : true,
                        editaction:"click",
                        datatype  : "csv",
                        columns   : []
                    }]
                }]
            }, { view:"resizer", hidden: true, id: 'CSVsettingsResizer' + $scope.Name}, {
                id    : 'CSVsettings' + $scope.Name,
                //hidden: true,
                rows  : [{
                    view     : "property",
                    width    : 360,
                    nameWidth: 180,
                    elements : [
                        { type: "label", label: mcService.Lang(963), css: 'headerLineHeight'},                                // "963":"Параметры данных",

                        { id: "titles",      type: "checkbox", label: mcService.Lang(2051), value: $scope.CSV.options.titles },       // "2051":"Строка с заголовками",
                        { id: "cell",        type: "text", label: mcService.Lang(965), value: $scope.CSV.options.cell.replace('\n', '\\n').replace('\t', '\\t').replace('\r', '\\r') },       // "965":"Разделитель колонок",
                        { id: "rows",        type: "fastselect", label: mcService.Lang(966),  value: "2", options: [{id:"1", value: "LF (\\n)"}, {id:"2", value: "CRLF (\\r\\n)"}] },// "966":"Разделители строк", $scope.CSV.options.rows.replace('\n', '\\n').replace('\t', '\\t').replace('\r', '\\r')
                        //{ id: "colsCount",  type: "text", label: mcService.Lang(967), value: $scope.CSV.options.colsCount },  // "967":"Количество колонок",
                        { id: "dateFormat",  label: mcService.Lang(972), value: $scope.CSV.options.dateFormat }, // "972":"Формат даты",
                        { id: "textFormat" , type: "fastselect", label: mcService.Lang(1005), value: "1", options: [{id:"1", value: "CSV"}, {id:"2", value: "users.ad, exported dsget.exe"}, {id:"3", value: "Text"}] }, // "1005":"Формат данных",
                        { id: "textEncoding",type:"fastselect", label: mcService.Lang(1006), value: "1", options: [{id:"1", value: "Windows-1251"}, {id:"2", value: "UTF-8"}, {id:"3", value: "ASCII"}] },  // "1006":"Кодировка",

                        { type: "label", label: mcService.Lang(997), css: 'headerLineHeight'},                                // "997":"Настройка пользователя",

                        { id: "fioFormat",   type: "fastselect",label: mcService.Lang(973), value: $scope.CSV.options.fioFormat, options: mcService.GetFioFormatList() },  // "973":"Формат имени",
                        { id: "defaultPass", type: "text",      label: mcService.Lang(984), value: $scope.CSV.options.defaultPass },// "984":"Пароль по умолчанию",
                        { id: "generateNick",type: "checkbox",  label: mcService.Lang(995), value: $scope.CSV.options.generateNick },// "995":"Сгенерировать ник",
                        { id: "nickFormat",  type: "fastselect",label: mcService.Lang(996), value: $scope.CSV.options.nickFormat, options: mcService.getLangItemsFromList(986, 994) },  // "996":"Формат ника",

                        { type: "label", label: mcService.Lang(68), css: 'headerLineHeight'},                                  // "68" : "Active Directory",

                        { id: "useDomain",   type: "fastselect",label: mcService.Lang(126), value: $scope.CSV.options.useDomain || "0", options: _ad },// "126": "Тип авторизации",
                        { id: "domainName",  type: "text",    label: mcService.Lang(123), value: $scope.CSV.options.domainName} // "123": "Имя домена",
                    ],
                    on : {
                        onAfterEditStop: $scope.CSV.changeConfig
                    }
                }]
            }]
        };

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows:[
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(961) }, //"961":"Импорт из CSV",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                _CSV
            ]
        });

        $scope.CSV.ready();

        mcService.disableContextMenu(_view);
    } else {

    }

    return _view;
}


function usersImportsController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.UsersImports;
    $scope.wrapView = null;

    var selectedItems = [];
    var columnsLabels = [];
    var conformity    = {};

    var angElement = document.getElementById($scope.Name);

    // ================ CSV ===================

    var rowSeparate = function (id){
        return id == 1 ? "\n" : (id == 2 ? "\r\n" : id);
    };

    function handleDragOver(e) {
        e.stopPropagation();
        e.preventDefault();
        e.dataTransfer.dropEffect = 'copy';
    }

    function handleFileSelect(e) {
        e.stopPropagation();
        e.preventDefault();

        $scope.openFile(e.dataTransfer.files[0], $scope.CSV.parseInputData);
    }

    function parseUserAd(data){
        window.____cellsTerms = [];

        var res = '';
        var subStr = mcService.trim(mcService.GetSubstring(data, rowSeparate($scope.CSV.options.rows))).replace(/\x20+(?=\S)/g, function(sub, idx, str){
            window.____cellsTerms.push(idx + sub.length);

            return sub;
        });

        window.____lineLength = subStr.length;

        data = mcService.GetSubstringFrom(data, rowSeparate($scope.CSV.options.rows));

        var __data = data.split('\n');

        while (__data.length > 0){
            var str = mcService.trim(__data.shift());

            if (str != ''){
                for (var j = 0; j < window.____cellsTerms.length; j++){
                    if (window.____cellsTerms[j] >= str.length) {
                        str += (new Array(window.____cellsTerms.length - j + 1)).join($scope.CSV.options.cell);
                        break;
                    } else {
                        str = str.split('');
                        str[window.____cellsTerms[j] - 1] = $scope.CSV.options.cell;
                        str = str.join('');
                    }
                }

                res += str + rowSeparate($scope.CSV.options.rows);
            }
        }

        return res;
    }

    function changeHeader(params){
        var itemName = params.iName || params.target[params.target.selectedIndex].innerHTML;
        var idx      = params.Idx === void(0) ? params.target.attributes[0].value : params.Idx;

        if (mcService.inArray(itemName, selectedItems) === -1){
            var columns = webix.toArray($scope.CSV.outputTable.config.columns);

            selectedItems.push(itemName);

            conformity['data' + idx] = itemName;

            columns[idx].header = itemName;

            $scope.xPosition = $scope.CSV.outputTable.getScrollState().x;

            $scope.CSV.outputTable.refreshColumns();

            setTimeout(function () {
                $scope.CSV.outputTable.scrollTo($scope.xPosition, $scope.CSV.outputTable.getScrollState().y);
            }, 10);

            $scope.CSV.handingSelectEvents(selectedItems);

            if (
                (itemName === "DisplayName") ||
                (itemName === "FirstName")   ||
                (itemName === "LastName")    ||
                (itemName === "MiddleName")  ||
                (itemName === "Nick")
                // (itemName == "Firstname") ||
                // (itemName == "Lastname") ||
                // (itemName == "Surname") ||
                // (itemName == "Nick")
            )
                $scope.CSV.importBTN.enable();
        } else {
            var select = this;

            setTimeout(function(){
                select.selectedItem = 0;
                select.selectedIndex= 0;
                select[0] = select.firstChild;
            }, 50);

            return false;
        }
    }

    function tryFindTitles(firstLine){
        var titles    = firstLine.split($scope.CSV.options.cell);
        var findTitle = false;

        titles.forEach(function (item, position) {
            var idx = mcService.inArrayLowerCase(item, columnsLabels);

            if (idx !== -1){
                findTitle = true;
                
                changeHeader({
                    Idx  : position,
                    iName: columnsLabels[idx]
                });
            }
        });

        return findTitle;
    }
    
    // ========================================

    $scope.rowSeparate = rowSeparate;

    $scope.CSV = {
        options: {
            rows      : "2",
            cell      : ';',
            colsCount : 4,
            dateFormat: 'dd.mm.yyyy',
            fioFormat : '1',
            defaultPass: '123456',
            useDomain : 0,
            domainName: "",
            titles    : true,
            generateNick: false,
            nickFormat: '1',
            textFormat: '1',
            textEncoding: '1' // CP1251
        },

        colsItems:[],

        inputData   : null,
        outputTable : null,
        importBTN   : null,

        view : null
    };

    $scope.CSV.selectType = function(idx, numb){
        idx = idx || 0;

        var items = columnsLabels;
        var res   = "<select idx='" + numb + "'>";

        for (var i = 0; i < items.length; i++){
            res += "<option " + ((i == idx || items[i] == idx) ? "selected" : "") + ">" + items[i] + "</option>";
        }

        return res + "</select>";
    };

    $scope.CSV.setDelimiters = function(delimiters){
        webix.DataDriver.csv.cell = delimiters.cell;
        webix.DataDriver.csv.row  = delimiters.rows;
    };

    $scope.CSV.changeConfig = function(state, editor){
        var newV = null;
        var oldV = null;
        var id   = null;

        if (editor || (this.getEditor() != 0)){
            if (arguments.length == 0){
                editor = editor || this.getEditor();

                id   = editor.id;

                newV = editor.getValue();
            } else {
                id   = editor.id;

                newV = state.value;
            }

            oldV = mcService.convertBool($scope.CSV.options[id]);

            try { // Fucking firefox must DIE!!!
                if (event && event.keyCode == 27){
                    newV = state.old;
                }
            } catch(e){}

            if( newV != oldV ){
                if (id === 'rows') {
                    $scope.CSV.options[id] = (newV == 1) ? "\n" : "\r\n"; //newV.replace('\\n', '\n').replace('\\t', '\t').replace('\\r', '\r');
                } else {
                    $scope.CSV.options[id] = newV;
                }

                if (id === 'textFormat') {
                    var property = $$('CSVsettings' + $scope.Name).getChildViews()[0];

                    switch (newV){
                        case "1":
                            property.getItem('rows').value = '2';
                            property.getItem('textEncoding').value = '1';

                            $scope.CSV.options['rows'] = '2';
                            $scope.CSV.options['textEncoding'] = '2';
                        break;

                        case "2":
                            property.getItem('rows').value = '2';
                            property.getItem('textEncoding').value = '3';

                            $scope.CSV.options['rows'] = '2';
                            $scope.CSV.options['textEncoding'] = '3';
                        break;
                    }

                    property.refresh();
                }
            }
        }
    };

    $scope.CSV.configureTable = function(conf){
        var columns = webix.toArray($scope.CSV.outputTable.config.columns);

        columns.splice(0, columns.length);

        if (conf != 'clear'){
            $scope.CSV.setDelimiters(conf);

            for (var i = 0; i < conf.colsCount; i ++){
                columns.insertAt({
                    id: "data" + i, header: $scope.CSV.selectType(selectedItems[i], i), minWidth: 200, fillspace: true, editor:"text"
                }, i);
            }
        }

        $scope.xPosition = $scope.CSV.outputTable.getScrollState().x;

        $scope.CSV.outputTable.refreshColumns();

        setTimeout(function () {
            $scope.CSV.outputTable.scrollTo($scope.xPosition, $scope.CSV.outputTable.getScrollState().y);
        }, 10);
    };

    $scope.CSV.parseInputData = function(data){
        if (mcService.trim(data) != ""){
            data = data.replace(new RegExp(rowSeparate($scope.CSV.options.rows) + "$"), "");

            if ($scope.CSV.options.textFormat == 2 && (data.indexOf('   ;') == -1)){ // users.ad
                data = parseUserAd(data);
            }

            var firstLine = mcService.GetSubstring(data, rowSeparate($scope.CSV.options.rows));

            $scope.CSV.options.colsCount = firstLine.split($scope.CSV.options.cell).length;

            $scope.CSV.outputTable.clearAll();

            conformity    = {};
            selectedItems = [];

            $$("toggleSettings" + $scope.Name).callEvent('click', [true]);

            $scope.CSV.configureTable(mcService.Marge($scope.CSV.options, {rows:rowSeparate($scope.CSV.options.rows)}));

            $scope.CSV.inputData.setValue(data);

            $scope.CSV.outputTable.parse(data, 'csv');

            $scope.CSV.handingSelectEvents();

            if ($$('CSVsettings' + $scope.Name).getChildViews()[0].getItem('titles').value && tryFindTitles(firstLine)){
                $scope.CSV.outputTable.remove($scope.CSV.outputTable.getFirstId());
            }
        } else {
            $scope.CSV.outputTable.clearAll();
            $scope.CSV.configureTable('clear');

            $scope.CSV.importBTN.disable();
        }
    };

    $scope.CSV.toggleSettings = function(){
        if (!this.getValue()){
            $$('CSVsettings' + $scope.Name).show();
            $$('CSVsettingsResizer' + $scope.Name).show();
        } else {
            $$('CSVsettings' + $scope.Name).hide();
            $$('CSVsettingsResizer' + $scope.Name).hide()
        }
    };

    $scope.CSV.handingSelectEvents = function(initArr){
        $scope.CSV.colsItems = new Array($scope.CSV.options.colsCount);
        selectedItems = initArr || selectedItems;

        for (var i = 0; i< $scope.CSV.options.colsCount; i ++){
            $scope.CSV.colsItems[i] = $scope.CSV.outputTable.getHeaderNode('data' + i).firstChild;

            if ($scope.CSV.colsItems[i].nodeName === "SELECT"){
                $scope.CSV.colsItems[i].removeEventListener('change', changeHeader);
                $scope.CSV.colsItems[i].addEventListener   ('change', changeHeader);
            }
        }
    };

    $scope.CSV.sendDataToServer = function(){
        var out = {
            "Fields"            : selectedItems.join(','),        // список полей, которые будут импортированы из CSV файла
            "DisplayNamePreset" : $scope.CSV.options.fioFormat,   // как отображается ФИО
            "DTFormat"          : $scope.CSV.options.dateFormat,  // формат даты и времени
            "GenerateNick"      : $$('CSVsettings' + $scope.Name).getChildViews()[0].getItem('generateNick').value,// нужно ли генерировать ник
            // "GenerateNick"      : $scope.CSV.options.generateNick,// нужно ли генерировать ник
            "NickFormat"        : $scope.CSV.options.nickFormat,  // формат генерации ника
            "DefaultPass"       : $scope.CSV.options.defaultPass, // пароль по умолчанию (если нужен)
            "AuthType"          : $scope.CSV.options.useDomain,   // используется авторизация Active Directory
            "Domain"            : $scope.CSV.options.domainName,  // имя домена, если есть

            "Users"              : [/*{
                "id"           : 18974,                           // идентификатор записи
                "TreeDept"     : "Головной офис > Бухгалтерия",   // подразделение, в котором работает человек
                "WorkPosition" : "Ведуший экономист",             // должность
                "DisplayName"  : "Третьякова Инна Валерьевна",    // ФИО человека
                "Birthday"     : "17.10.1985"                     // дата рождения
            }*/]
        };

        out.Users = [].concat($scope.CSV.outputTable.serialize());

        for (var i = 0; i < out.Users.length; i++){
            var el = webix.copy(out.Users[i]);

            var row = "";

            for (var j in el){
                if (conformity.hasOwnProperty(j)){ // el[j] != "" &&
                    mcService.renameProperty.apply(el, [j, conformity[j]]);

                    row += el[conformity[j]];
                } else {
                    delete el[j];
                }
            }

            if (row == "") {
                mcService.delArrayItem(out.Users, i);
            }

            out.Users[i] = el;
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            $scope.CSV.options.textFormat == 2 ? mcConst._CMD_.cs_adm_import_ad_users : mcConst._CMD_.cs_adm_import_users,
            mcConst.SessionID,
            JSON.stringify(out),
            function( data ){  // only for cs_adm_import_ad_users
                mcService.showImportResult(data, $rootScope);
            }
        ]);
    };

    $scope.CSV.ready = function(){
        var _parse = function(e){
            e.stopPropagation();
            e.preventDefault();

            $scope.openFile(e.target.files[0], $scope.CSV.parseInputData);
        };

        var fileLoader = document.getElementById('fileUpload');

        $scope.CSV.inputData   = $$('previewCSV' + $scope.Name);
        $scope.CSV.outputTable = $$("csvDataTable" + $scope.Name);
        $scope.CSV.view        = $$('CSV' + $scope.Name);
        $scope.CSV.importBTN   = $$("importBTN" + $scope.Name);

        fileLoader.removeEventListener('click',  $scope.clearTextArea);
        fileLoader.removeEventListener('change', _parse);

        fileLoader.addEventListener('click',  $scope.clearTextArea, false);
        fileLoader.addEventListener('change', _parse, false);

        $scope.CSV.inputData.getNode().addEventListener('dragover', handleDragOver, false);
        $scope.CSV.inputData.getNode().addEventListener('drop', handleFileSelect, false);
    };

    //=======================================

    $scope.clearTextArea = function(){
        this.value = null;
    };

    $scope.openFile = function(files, callback){
        function getEncoding(){
            var enc = "";

            switch ($scope.CSV.options.textEncoding){
                case '1': enc = mcService.isIE() ? "windows-1251" : "CP1251"; break;
                case '2': enc = "UTF-8"; break;
                case '3': enc = "CP866"; break;
            }

            return enc;
        }

        var reader = new FileReader();

        reader.onload = (function (theFile) {
            $scope.CSV.options.colsCount = 0;

            if (callback){
                callback(theFile.target.result);
            }

            reader = null;
        });

        if (/(\.ad)$/i.test(files.name)){
            var property = $$('CSVsettings' + $scope.Name).getChildViews()[0];

            property.getItem('rows').value         = '2';
            property.getItem('textEncoding').value = '3';
            property.getItem('textFormat').value   = '2';
            property.getItem('generateNick').value = false;
            property.getItem('useDomain').value    = '1';

            $scope.CSV.options['rows']         = '2';
            $scope.CSV.options['textEncoding'] = '3';
            $scope.CSV.options['textFormat']   = '2';
            $scope.CSV.options['generateNick'] = false;
            $scope.CSV.options['useDomain']    = '1';

            var wnd = webix.ui({
                view    : "window",
                modal   : true,
                position: "center",
                width   : 250,
                heihgt  : 100,
                head    : mcLang(1362), // "1362":"Укажите имя домена",
                body    : { view: "form", rules: {'domainName': webix.rules.isNotEmpty}, elements:[
                    { view: "text", name: "domainName", id: "importWndDomainName" },
                    { view: "button", value: mcLang(13), click: function(){ //"13" : "Ок",
                        if (this.getFormView().validate()){
                            $scope.CSV.options['domainName'] = this.getFormView().getChildViews()[0].getValue();
                            property.getItem('domainName').value = $scope.CSV.options['domainName'];
                            property.refresh();

                            reader.readAsText(files, getEncoding()); // 'CP866' e.target.files[0]

                            this.getTopParentView().hide();
                            this.getTopParentView().destructor();
                        }
                    }}
                ]}
            });

            $scope.regShowWindow(mcService.RandomHash(5), wnd);

            wnd.show();

            setTimeout(function(){
                $$("importWndDomainName").focus();
            }, 50);
        } else {
            reader.readAsText(files, getEncoding());
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.refresh = function(cmd, data){
        switch (cmd){
            case 'CSVcomplete':
                webix.alert(mcService.Lang(999)); // "999":"Импорт данных завершен",

                for (var i in data){
                    $scope.CSV.outputTable.getItem(i);
                }

                $rootScope.needRefreshCommonContacts = true;

                $rootScope.$broadcast('refreshUserManagerOnNextShow', []);
            break;
        }
    };

    $scope.show = function (){
        columnsLabels = [
            mcService.Lang(998), // "998":"- Не импортировать -",
            "DisplayName",
            "TreeDept",
            "FirstName",//"Firstname",
            "LastName",//"Lastname",
            "MiddleName",//"Surname",
            "Birthday",
            "Email",
            "Nick",
            "Sex",
            "WorkPosition",
            "Password",
            "HomePhone",
            "HomeFax",
            "HomeCellular",
            "HomeStreetAddress",
            "HomeCity",
            "HomeState",
            "HomeZIP",
            "HomeWWW",
            "WorkCompanyName",
            "WorkOffice",
            "WorkPhone",
            "WorkFax",
            "WorkStreetAddress",
            "WorkCity",
            "WorkState",
            "WorkZIP",
            "WorkWWW",
            "WorkPager",//"Pager",
            "About",
            "Tag"
        ];

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        $scope.wrapView = initUsersImportsView($scope);

        mcService.initResize($scope.wrapView, $scope.Name);

        $scope.wrapView.adjust();
    };

    $scope.$on('refresh' + $scope.Name, function(e, args) {
        $scope.refresh.apply(null, args);
    });

    $scope.$on('hide' + $scope.Name, function() {
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.show();

        if (selectedItems.length == 0){
            $scope.CSV.importBTN.disable();
        }
    });
}


"use strict";

function initBans($scope){
    var _view = $$($scope.Name);
    var labelHeight = 30;

    if (!_view){
        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type: "header", template : mcService.Lang(1029) }, // "1029":"Забаненные пользователи",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},


                { type: 'layout', padding: 5, cols : [
                    { view: "list", id:"banList", data: $scope.data, select: true, multiselect: true, template: "#DisplayName# (Ban ID: #ID#)", on: {
                        onAfterSelect: function(id) {
                            $scope.selectBan(this.getItem(id));

                            $$("banDelButton").enable();
                        }
                    }},
                    { view:"resizer" },
                    { id: "banInfo", hidden: true, padding: 5, rows: [
                        { template: mcService.Lang(1030), type: "header" },  // "1030":"Информация о наказании",

                        { cols: [
                            { width: 180, rows: [
                                { template: mcService.Lang(1031), borderless: true, height: labelHeight, css: "byRight"}, // "1031":"Кто наложил наказание:",
                                { template: mcService.Lang(1032) + ":", borderless: true, height: labelHeight, css: "byRight"}, // "1032":"Комментарий:",
                                { template: mcService.Lang(1033) + ":", borderless: true, height: labelHeight, css: "byRight"}, // "1033":"Канал",
                                { template: mcService.Lang(1034), borderless: true, height: labelHeight, css: "byRight"}, // "1034":"Дата и время наказания:",
                                { template: mcService.Lang(1037), borderless: true, height: labelHeight, css: "byRight"}, // ""1037":"Дата и время окончания:",
                                { template: mcService.Lang(1035), borderless: true, height: labelHeight, css: "byRight"}, // "1035":"Продолжительность:",
                                { template: mcService.Lang(1036), borderless: true, height: labelHeight, css: "byRight"}  // "1036":"Тип наказания:",
                            ]},
                            { rows: [
                                { template: $scope.selectedItem.DisplayNameBanner + " ",borderless: true, id: "banDisplayNameBanner", height: labelHeight, css: "bolder" },
                                { template: $scope.selectedItem.Reason + " ",           borderless: true, id: "banReason", height: labelHeight , css: "bolder"},
                                { template: $scope.selectedItem.ConfName + " ",         borderless: true, id: "banConfName", height: labelHeight, css: "bolder" },
                                { template: $scope.selectedItem.dtBan + " ",            borderless: true, id: "bandtBan", height: labelHeight, css: "bolder" },
                                { template: $scope.selectedItem.dtBanOff + " ",         borderless: true, id: "bandtBanOff", height: labelHeight, css: "bolder" },
                                { template: " ", borderless: true, id: "banRange", height: labelHeight, css: "bolder" },
                                { template: " ", borderless: true, id: "banBanType", autoheight: true, css: "bolder" } // "1485":"Запрет на вход в конференцию", "1486":"Запрет на отправку сообщений",
                            ]}
                        ]},

                        { height: 10 },

                        { cols:[
                            { width: 180 },
                            { view: "button", id: "banDelButton", maxWidth: 250, minWidth: 200, value: mcService.Lang(1038), disabled: true, click: $scope.removeBan, css: "applyButton"}, //"1038":"Снять наказание",
                            {}
                        ]},
                        {}
                    ]}
                ]}
            ]
        });

        $scope.banList = $$("banList");
        $scope.banInfo = $$("banInfo");
    } else {
        $scope.banList.clearAll();
        $scope.banList.define('data', $scope.data);

        if ($scope.data && $scope.data.length){
            $scope.banInfo.show();
        } else {
            $scope.banInfo.hide();
        }
    }

    $scope.banList.select($scope.banList.getFirstId());

    return _view;
}
"use strict";

function bansController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.Bans;
    $scope.selectedItem = {};

    var angElement = document.getElementById($scope.Name);
    var emptyObject = {
        DisplayNameBanner: '',
        Reason: '',
        ConfName: '',
        dtBan: '',
        dtBanOff: '',
        BanType: ''
    };

    $scope.selectBan = function (_sItem){
        $scope.selectedItem = _sItem || mcService.Marge({}, emptyObject);

        for (var i in $scope.selectedItem){
            var item = $$('ban' + i);
            var uid = 0;

            if (item){
                if (i === 'BanType' && $scope.selectedItem[i] !== ''){
                    item.define('template', parseInt($scope.selectedItem[i]) ? mcService.Lang(1486) : mcService.Lang(1485));
                } else
                if ((i === 'dtBan' || i === 'dtBanOff') && $scope.selectedItem[i]) {
                    var dt = $scope.selectedItem[i].split('.');

                    item.define('template', dt[2] + "." + dt[1] + "." + dt[0] + " " + dt[3] + ":" + dt[4] + ":" + dt[5]);
                } else
                if (i === 'ConfName'){
                    item.define('template', $scope.selectedItem[i] + ", UID: " + $scope.selectedItem.ConfID);
                } else {
                    item.define('template', $scope.selectedItem[i] + " ");
                }

                item.refresh();
            }
        }

        if ($scope.selectedItem.dtBanOff !== ''){
            item = $$('banRange');
            item.define('template', moment(moment($scope.selectedItem.dtBanOff, 'DD.MM.YYYY.HH.mm.ss')).fromNow(true));
            item.refresh();
        } else {
            $$("banDelButton").disable();
        }
    };

    $scope.removeBan = function(){
        $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
            type  : "confirm-warning",
            text  : mcService.Lang(1487),// "1487":"Вы действительно хотите досрочно снять наказание?",
            ok    : mcService.Lang(114), // "114": "да",
            cancel: mcService.Lang(113), // "113": "нет",
            callback:function(yes){
                if (yes){
                    var selectList = [];
                    var banList = $$("banList").getSelectedItem();
                    var res = [];

                    if (banList){

                    }

                    if (mcService.isObject(banList)){
                        selectList.push(banList);
                    } else
                    if (mcService.isArray(banList)){
                        selectList = banList;
                    }

                    for (var i = 0; i < selectList.length; i++){
                        res.push(selectList[i].ID);
                    }

                    if (res.length > 0){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_del_bans,
                            mcConst.SessionID,
                            res.join(','),
                            function(){
                                $$("banList").remove($$("banList").getSelectedId());

                                var first = $scope.banList.getFirstId();

                                if (first){
                                    $scope.banList.select(first);
                                } else {
                                    $scope.banInfo.hide();
                                }
                            }
                        ]);
                    }
                }
            }
        }));
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(data){
        $scope.data = data || [];

        $scope.selectedItem = mcService.Marge({}, emptyObject);

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initBans($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_bans_list,
            mcConst.SessionID,
            function(data){
                $scope.show(data);
            }
        ]);
    };

    $scope.$on('show' + $scope.Name, function(){
        $scope.getData();
        $scope.show();
    });
}
"use strict";

function initActiveDirectory($scope){
    var _view = $$($scope.Name);
    var labelWidth = 205;
    var width      = 555;

    if (!_view){
        var filer = mcService.FilterFiled({
            listName     : "ldapTableView",
            noClearBtn   : true,
            placeholder  : mcLang(48), // "48" :"Поиск...",
            onAfterFilter: function (res) {
                $scope.ldapUserCount.setValue(res.length);
            },
            onClear: function () {
                $scope.ldapUserCount.setValue($scope.totalCount);
            },
            filterParams : [
                "value",
                "sAMAccountName",
                "givenName",
                "initials",
                "sn",
                "mail",
                "company",
                "title",
                "department",
                "physicalDeliveryOfficeName",
                "telephoneNumber",
                "facsimileTelephoneNumber",
                "pager",
                "streetAddress",
                "l",
                "st",
                "postalCode",
                "countryCode",
                "wWWHomePage",
                "mobile",
                "homePhone"
            ]
        });

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcLang(68) + ": " + mcLang(1963) }, //"68" : "Active Directory", "1963":"Импорт пользователей",
                    {
                        view   : "toolbar",
                        padding: 2,
                        width  : 216,
                        cols   : [{
                            view    : "toggle",
                            id      : "toggleSettings" + $scope.Name,
                            onLabel : mcService.Lang(970), // "970":"Показать настройки",
                            offLabel: mcService.Lang(964), // "964":"Скрыть настройки",
                            value   : false,
                            align   : "right",
                            click   : function(){
                                this.getValue() ? $scope.ldapConnectSettings.show() : $scope.ldapConnectSettings.hide()
                            }
                        }, {
                            view: "button", type: "icon", icon: "question", click: function () {
                                mcService.goToHelp();
                            }, width: 30
                        }]
                    }
                ]},

                {  id: "ldapConnectSettings", type : 'layout', padding : 5, rows: [
                    { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1962, [$scope.adHelpLink]), css: "_info selectable", autoheight: true}, // "1962":"Как настроить прозрачную авторизацию пользователей и развернуть MyChat Client через GPO",

                    { height: 3},

                    { cols: [
                        { view: "form", id: "ldapConnectForm", borderless: true, padding: 0, rules:{
                            ldapHost:    webix.rules.isNotEmpty,
                            ldapPort:    webix.rules.isNotEmpty,
                            ldapBase:    webix.rules.isNotEmpty,
                            ldapUser:    webix.rules.isNotEmpty,
                            ldapPassword:webix.rules.isNotEmpty
                        }, elements: [
                            { cols: [
                                { view: "text", id:"ldapHost",name: "ldapHost", label: mcLang(1540) + ":", labelWidth: labelWidth, width: width/1.4}, //"1540":"IP или Host сервера домена",
                                { width: 10},
                                { view: "text", id:"ldapPort",name: "ldapPort", label: mcLang(593) + ":", labelWidth: 80, width: 160, value: 389} //"593": "TCP порт",
                            ]},
                            { view: "text",     id:"ldapBase",  name:"ldapBase",  label: mcLang(1541), labelWidth: labelWidth, placeholder: mcLang(1542)}, // "1541":"Базовый запрос:", "1542":"Например: DC=NSS,DC=COM",
                            { view: "checkbox", id:"ldapSecure",name:"ldapSecure",labelRight: mcLang(924), labelWidth: 0, on:{ onChange: function(val){
                                        $scope.ldapPort.setValue(val ? 636 : 389);
                                    }}}, // "924":"Использовать зашифрованое подключение SSL",
                            { view: "text",     id:"ldapUser",  name:"ldapUser",  label: mcLang(1545) + ":", labelWidth: labelWidth, width: width/1.4}, // "1545":"Имя пользователя:",
                            { cols: [
                                { view: "text",  id: "ldapPassword",name: "ldapPassword", type: "password", label: mcLang(2) + ":", labelWidth: labelWidth, width: width/1.4,
                                    // on: {onTimedKeyPress : function(){
                                        // var lng = $$('ldapDispLang');
                                        // var lastChar = $$('ldapPassword').getValue();
                                        // lastChar = lastChar[lastChar.length - 1];

                                        // if (lastChar && lng){
                                        //     if (lastChar.match(/[a-zA-Z]/)) {
                                        //         lng.define('template', 'EN');
                                        //         lng.refresh();
                                        //     } else
                                        //     if (lastChar.match(/[а-яА-Я]/)){
                                        //         lng.define('template', 'RU');
                                        //         lng.refresh();
                                        //     } else
                                        //     if (lastChar.match(/[їЇіІєЄ]/)){
                                        //         lng.define('template', 'UA');
                                        //         lng.refresh();
                                        //     }
                                        // }
                                    // }}
                                }, // "2"  : "Пароль",
                                { view: "toggle", width: 30, offIcon: "eye", onIcon: "eye-slash",  type:"icon", css: "noBG", tooltip: mcLang(1100) + "/" + mcLang(1099).toLowerCase(), // "1100":"Скрыть", "1099":"Показать",
                                    on: { onChange: function (val) {
                                            var pwd = $$('ldapPassword');

                                            if (val) {
                                                pwd.define('type', 'text');
                                            } else {
                                                pwd.define('type', 'password');
                                            }

                                            pwd.refresh();
                                            pwd.getInputNode().setAttribute("autocomplete", "new-password");
                                        }}
                                },
                                // { id: 'ldapDispLang', template: 'EN', width: 28, borderless: true },
                                { view: "button", value: mcLang(1546), click: $scope.connect} // "1546":"Подключиться",
                            ]},

                            { id: "ldapGetPhoto",           view: "checkbox", labelRight: mcService.Lang(2107), labelWidth: 0, value: true, css: "finger"}, // "2107":"Запрашивать фотографии пользователей",
                            { id: "ldapCreateCommonTree",   view: "checkbox", labelRight: mcService.Lang(1818), labelWidth: 0, value: "", css: "finger"}, // "1818":"Сформировать общий список контактов на основе структуры домена (OU, Organization Unit)",
                            { id: "ldapCreateWorkPosition", view: "checkbox", labelRight: mcService.Lang(1819), labelWidth: 0, value: "", css: "finger"}, // "1819":"Сформировать должности на основе данных из домена",

                            { cols: [
                                { view: "label", label: mcLang(1836), width: 80}, // "1836":"Показывать",
                                { id: "ldapListType", view: "select", width: 200, options: [
                                    { id: "0", value: mcLang(1837)}, // "1837":"всех",
                                    { id: "1", value: mcLang(1838)}, // "1838":"не импортированных",
                                    { id: "2", value: mcLang(1839)}  // "1839":"уже импортированных",
                                ], on: { onChange: $scope.changeListType}},
                                { view: "label", label: mcLang(1628).toLowerCase(), autowidth: true}, // "1628":"Пользователей",
                                { },
                                { view: "toggle", id: "ldapFilter", width: 142,
                                    onLabel : mcService.Lang(2079), // "2079":"Скрыть фильтр",
                                    offLabel: mcService.Lang(2078), // "2078":"Показать фильтр",
                                    value   : false,
                                    click   : $scope.showFilter
                                }
                            ]}
                        ]},

                        { rows: [
                            { view: "textarea", id: "ldapLog", hidden: true, label: " LDAP error log:", labelPosition: 'top', css: "errorArea"}
                        ]}
                    ]},

                    { height: 3},

                    { id: "ldapFilterWrap", hidden: true, rows: [
                        // { id: "ldapHeaderLabel", template: mcService.insertIco("fa-info-circle"), css: "_info selectable", autoheight: true},
                        // { view: "label", label: mcLang(2071), css: "_info"},           // "2071":"Заголовок LDAP запроса: (",
                        { view: "text",     id:"ldapBaseDN",  name:"ldapBase",  label: mcLang(2075), labelWidth: labelWidth}, // "2075":"Base DN",

                        { cols: [
                            { id: "ldapRequest", view: "text", label: mcLang(2077) + ":", labelWidth: labelWidth},   // "2077":"LDAP фильтр", "2072":"Дополните ваш LDAP запрос здесь (необязательно)",
                            { view: "button", value: mcLang(2076), autowidth: true, click: $scope.showFilterText} // "2076":"Показать запрос",
                        ]}
                    ]}
                ]},

                filer,

                {
                    view        : "treetable",
                    id          : "ldapTableView",
                    disabled    : true,
                    resizeColumn: true,
                    select      : "row",
                    multiselect : "touch",
                    minColumnWidth : 80,
                    leftSplit   : 1,
                    columns: [
                        // {id:"value",      header: [mcLang(1547),{ content:"textFilter"}], template:"{common.treetable()} #value#", width: 200,css: "left_area"}, //"1547":"Структура",
                        {id:"value",         header: mcLang(1547), template:"{common.treetable()} #value#", width: 200,css: "left_area"}, //"1547":"Структура",
                        {id:"jpegPhoto",     adjust:"header",header: [{text:mcLang(146),rowspan:2}], css:"grid_area byCenter", targetField:"Photo", template: $scope.drawAdFoto}, //"146":"Фото",
                        {id:"sAMAccountName",adjust:"header",header: [{text:mcLang(58), rowspan:2}], css:"grid_area", targetField:"Nick"}, //"58" : "Ник",
                        {id:"givenName",     adjust:"header",header: [{text:mcLang(129),rowspan:2}], css:"grid_area", targetField:"FirstName"}, //
                        {id:"initials",      adjust:"header",header: [{text:mcLang(130),rowspan:2}], css:"grid_area", targetField:"MiddleName"}, //
                        {id:"sn",            adjust:"header",header: [{text:mcLang(131),rowspan:2}], css:"grid_area", targetField:"LastName"}, //
                        {id:"mail",          width :130,     header: [{text:mcLang(134),rowspan:2}], css:"grid_area", targetField:"Email"}, //
                        {id:"company",       adjust:"header",header: [{text:mcLang(121),colspan:13}, mcLang(170)], css:"grid_area", targetField:"WorkCompanyName"}, //
                        {id:"title",         adjust:"header",header: ["", mcLang(171)], css:"grid_area", targetField:"WorkPosition"}, //
                        {id:"department",    adjust:"header",header: ["", mcLang(172)], css:"grid_area", targetField:"WorkDept"}, //
                        {id:"physicalDeliveryOfficeName",adjust:"header",header: ["", mcLang(173)], css:"grid_area", targetField:"WorkOffice"}, //
                        {id:"telephoneNumber",adjust:"header",header:["", mcLang(174)], css:"grid_area", targetField:"WorkPhone"}, //
                        {id:"facsimileTelephoneNumber",adjust:"header",header: ["", mcLang(160)], css:"grid_area", targetField:"WorkFax"}, //
                        {id:"pager",         adjust:"header",header: ["", mcLang(176)], css:"grid_area", targetField:"WorkPager"}, //
                        {id:"streetAddress", adjust:"header",header: ["", mcLang(163)], css:"grid_area", targetField:"WorkStreetAddress"}, //
                        {id:"l",             adjust:"header",header: ["", mcLang(164)], css:"grid_area", targetField:"WorkCity"}, //
                        {id:"st",            adjust:"header",header: ["", mcLang(165)], css:"grid_area", targetField:"WorkState"}, //
                        {id:"postalCode",    adjust:"header",header: ["", mcLang(166)], css:"grid_area", targetField:"WorkZIP"}, //
                        {id:"countryCode",   adjust:"header",header: ["", mcLang(167)], css:"grid_area", targetField:"WorkCountry"}, //
                        {id:"wWWHomePage",   adjust:"header",header: ["", mcLang(178)], css:"grid_area", targetField:"WorkWWW"}, //
                        {id:"mobile",        adjust:"header",header: [{text:mcLang(148),colspan:2}, mcLang(161)], css:"grid_area", targetField:"HomeCellular"}, //
                        {id:"homePhone",     adjust:"header",header: ["", mcLang(159)], css:"grid_area", targetField:"HomePhone"} //
                    ],
                    on: { onSelectChange: $scope.usersSelect}
                },

                { height: 36, cols: [
                    { view: "button", id: "ldapBtnImport", value: mcLang(1549), width: 150, disabled: true, click: $scope.startImport},  //"1549":"Импортировать",
                    { width: 5},
                    { view: "label", label: mcLang(1840), width: 150, css: "white"}, // "1840":"Всего пользователей:",
                    { id: "ldapUserCount", view: "label", label: "0", css: "white", width: 50},
                    {},
                    { view: "button", id: "ldapBtnShowConfig", value: mcLang(1548), disabled: true, width: 270, click: $scope.showConfig}, //"1548":"Настроить соответствие полей",
                ]}
            ]
        });

        $scope.configTreetable = webix.ui({
            view     : "window",
            position : "center",
            modal    : true,
            width    : 500,
            head     : mcLang(1550), // "1550":"Поля для импорта",
            height   : $scope.wndSize.height - 120,
            body     : { rows: [{
                view    : "datatable",
                editable: true,
                id      : "ldapConfigTable",
                columns : [
                    { id:"adParam", fillspace: 2, header: "Active Directory", css:"grid_area", editor:"combo", options: $scope.adAttributesList},  //
                    { id:"mcParam", fillspace: 3, header: "MyChat", css:"grid_area"}
                ]
            },{ cols: [
                { view: "button", value: mcLang(1551), click: $scope.refreshData, css: "applyButton"}, // "1551":"Применить",
                { view: "button", value: mcLang(12), click: function(){ // "12" : "Закрыть",
                    $scope.configTreetable.hide();
                }}
            ]}
            ]}
        });

        // filer.thisFilter.attachEvent('onTimedKeypress', function () {
        //     $scope.ldapUserCount.setValue($scope.ldapTableView.serialize().length);
        // });

        $scope.ldapGetPhoto        = $$("ldapGetPhoto");
        $scope.ldapHost            = $$("ldapHost");
        $scope.ldapPort            = $$("ldapPort");
        $scope.ldapBase            = $$("ldapBase");
        $scope.ldapSecure          = $$("ldapSecure");
        $scope.ldapUser            = $$("ldapUser");
        $scope.ldapPassword        = $$("ldapPassword");
        $scope.ldapLog             = $$("ldapLog");
        $scope.ldapTableView       = $$("ldapTableView");
        $scope.ldapListType        = $$("ldapListType");
        $scope.ldapUserCount       = $$("ldapUserCount");
        $scope.ldapRequest         = $$("ldapRequest");
        $scope.ldapBaseDN          = $$("ldapBaseDN");
        $scope.ldapFilter          = $$("ldapFilter");
        $scope.ldapHeaderLabel     = $$("ldapHeaderLabel");
        $scope.ldapConnectForm     = $$("ldapConnectForm");
        $scope.ldapBtnShowConfig   = $$("ldapBtnShowConfig");
        $scope.ldapBtnImport       = $$("ldapBtnImport");
        $scope.ldapConfigTable     = $$("ldapConfigTable");
        $scope.ldapConnectSettings = $$("ldapConnectSettings");
        $scope.ldapFilterWrap      = $$("ldapFilterWrap");
        $scope.ldapCreateCommonTree   = $$("ldapCreateCommonTree");
        $scope.ldapCreateWorkPosition = $$("ldapCreateWorkPosition");

        webix.UIManager.addHotKey('enter', function(){
            $scope.connect();
        }, $scope.ldapPassword);

        webix.UIManager.addHotKey('enter', function(){
            $scope.connect();
        }, $scope.ldapRequest);
        
        webix.UIManager.addHotKey('enter', function(){
            $scope.connect();
        }, $scope.ldapBaseDN);

        $scope.contextMenu = new mcService.ContextMenu($scope.ldapTableView, $scope.contextMenu, function(){
            var selected = $scope.ldapTableView.getSelectedItem();
            var count = selected ? selected.length : 0;

            $scope.usersSelect.apply($scope.ldapTableView);
        }, function(){
            $scope.regShowWindow(this.config.id, this);
        }, true);

        $scope.ldapUser.getInputNode().setAttribute("autocomplete", "off");
        $scope.ldapPassword.getInputNode().setAttribute("autocomplete", "off");

        mcService.disableContextMenu(_view);
    } else {

    }

    return _view;
}
function activeDirectoryController($scope, $rootScope){
    "use strict";

    $scope.Name         = mcConst.dataModels.ActiveDirectory;
    $scope.selectedItem = {};
    $scope.initData     = [];
    $scope.data         = [];

    var angElement      = document.getElementById($scope.Name);
    var defaultAdSet    = getDefaultSet();
    var successConnect  = false;
    var view            = null;
    var ldapParams      = {};
    var configSet       = [];
    var mcAttributesList= [];
    var usersToImport   = [];
    var ldapBaseDN      = "";
    var domainName      = "";
    var ldapHeader      = "";

    $scope.adAttributesList = mcConst.adAttributesList;

    // ======= Error Actions ==========

    $rootScope.ErrorActions[165] = function(data){ // "14"  : "Неверный пароль пользователя",
        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock

        showError(data);
    };

    // ============================================

    function getDefaultSet(){
        return [
            "sAMAccountName",
            "givenName",
            "initials",
            "sn",
            "mail",
            "company",
            "title",
            "department",
            "physicalDeliveryOfficeName",
            "telephoneNumber",
            "facsimileTelephoneNumber",
            "pager",
            "streetAddress",
            "l",
            "st",
            "postalCode",
            "countryCode",
            "wWWHomePage",
            "mobile",
            "homePhone",
            // "thumbnailPhoto",
            // "jpegPhoto",
            "displayName"
        ];
    }

    function dtMarge(ar1,ar2){
        var res = [];

        for (var i = 0; i < ar1.length; i++){
            if (ar2[i]){
                res.push({ adParam: ar1[i], mcParam: ar2[i].value, mcName: ar2[i].id });
            }
        }

        return res
    }

    function parseData(data){
        if (mcService.isArray(data)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_save_ad_options,
                mcConst.SessionID,
                $scope.ldapHost.getValue(),
                $scope.ldapPort.getValue(),
                ldapParams.domainName,
                mcService.convertIntToBool($scope.ldapSecure.getValue()),
                ldapParams.username,
                defaultAdSet
            ]);

            $rootScope.adminOptions.adImportUser   = ldapParams.username;
            $rootScope.adminOptions.adImportDomain = ldapParams.domainName;

            $rootScope.$broadcast('saveAdminOptions', [ldapParams.username, "adImportUser"]);
            $rootScope.$broadcast('saveAdminOptions', [ldapParams.domainName, "adImportDomain"]);

            successConnect = true;

            $scope.ldapTableView.enable();
            $scope.ldapBtnShowConfig.enable();

            $scope.initData = data;
            $scope.data = mcService.convertDnArrayToTreeTable(data, mcService.convertDomainToDn(ldapParams.domainName));

            $scope.totalCount = data.length;
            $scope.ldapUserCount.setValue($scope.totalCount);

            configSet = dtMarge(defaultAdSet, mcAttributesList);

            $scope.ldapTableView.clearAll();
            $scope.ldapTableView.parse($scope.data);

            var tt = [].concat(configSet);

            tt.shift();
            
            $scope.ldapConfigTable.clearAll();
            $scope.ldapConfigTable.define('data', tt);
            $scope.ldapConfigTable.refresh();
        } else {
            webix.err('LDAP: unknown error');
        }
    }

    function showError(data){
        if (data && data.length){
            var res = "";

            successConnect = false;

            res += "Code: " + data[0] + '\n';
            res += "Description: " + data[1] + '\n';
            res += "Message: " + data[2] + '\n';

            $scope.ldapLog.show();
            $scope.ldapLog.setValue(res);

            //$rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
        }
    }

    function getFullLdapFilterRequest(){
        return "(" + ldapHeader + mcService.trim($scope.ldapRequest.getValue()) + ")";
    }

    // ============================================

    $scope.showFilterText = function(){
        var wndFilter = webix.ui({
            view     : "window",
            position : "center",
            modal    : true,
            height   : 150,
            width    : 450,
            head     : mcService.Lang(2077), // "2077":"LDAP фильтр",
            body     : {
                padding : 5,
                rows    : [
                    { template: getFullLdapFilterRequest(), css: "selectable __ldapFilterQuery", borderless: true},
                    { height: 5 },

                    { cols: [
                        { view: "button", value: mcService.Lang(12), // "12" : "Закрыть",
                            click : function() {
                                wndFilter.hide();
                            }
                        },

                        { view: "button", value: mcService.Lang(2073), // "2073":"Скопировать запрос",
                            click : function() {
                                mcService.copyTextToClipboard(getFullLdapFilterRequest(), mcLang(2074)); // "2074":"Запрос скопирован в буфер обмена",
                            }
                        }
                    ]}
                ]
            },
            on: {
                onShow: function(){ $scope.regShowWindow(this.config.id, this); },
                onHide: function(){ wndFilter.destructor(); }
            }
        });

        wndFilter.show();
    };

    $scope.drawAdFoto = function (obj) {
        return obj.jpegPhoto ? "<img  style='height: 24px;' src='data:image/jpeg;base64," + obj.jpegPhoto + "'>" : "";
    };

    $scope.connect = function(){
        $scope.ldapLog.hide();

        $scope.ldapTableView    .disable();
        $scope.ldapBtnShowConfig.disable();
        $scope.ldapBtnImport    .disable();

        var ldapRequest = mcService.trim($scope.ldapRequest.getValue());
        var ldapFilter  = mcService.convertIntToBool($scope.ldapFilter.getValue());

        // var check = new RegExp("^((\\([\\s\\w<>=\\p{L}\\.*]+\\))+\s*)|(\\(\\s*(\(\s*[\\|!&]?\s*)(?=\\())(\\([\\s\\w<>=\\p{L}\\.\\*]+\\))+\\s*\\))+$", "igu");

        var check = null

        try {
            check = new RegExp("^((\\([\\s\\w<>=\\p{L}\\.*]+\\))+\s*)|(\\(\\s*(\(\s*[\\|!&]?\s*)(?=\\())(\\([\\s\\w<>=\\p{L}\\.\\*]+\\))+\\s*\\))+$", "igu");
        } catch (e) {
            check = new RegExp("^((\\([\\s\\w<>=\\S\\.*]+\\))+\s*)|(\\(\\s*(\(\s*[\\|!&]?\s*)(?=\\())(\\([\\s\\w<>=\\S\\.\\*]+\\))+\\s*\\))+$", "ig");
        }

        // var check = /^((\([\s\w<>=\p{L}\.*]+\))+\s*)|(\(\s*((\s*[\|!&]?\s*)(?=\())(\([\s\w<>=\p{L}\.\*]+\))+\s*\))+$/igu;

        ldapBaseDN = mcService.trim($scope.ldapBaseDN.getValue());

        // defaultAdSet = getDefaultSet();

        // var id2 = defaultAdSet.indexOf("jpegPhoto");

        // if ($scope.ldapGetPhoto.getValue()) {
        //     if (id2 === -1) {
        //         defaultAdSet.push("thumbnailPhoto");
        //         defaultAdSet.push("jpegPhoto");
        //     }
        // } else {
            var id1 = defaultAdSet.indexOf("thumbnailPhoto");
            var id2 = defaultAdSet.indexOf("jpegPhoto");

            if (id1 >=0 ){
                defaultAdSet.splice(id1, 1);
            }

            // id2 = defaultAdSet.indexOf("jpegPhoto");

            if (id2 >=0 ){
                defaultAdSet.splice(id2, 1);
            }
        // }

        if ($scope.ldapConnectForm.validate()){
            if ((!ldapFilter || (ldapFilter && (check.test(ldapRequest) || ldapRequest === "")))){
                ldapParams = {
                    domainName : $scope.ldapBase.getValue(),
                    username   : $scope.ldapUser.getValue()
                };

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_ad_users_list,
                    mcConst.SessionID,

                    $scope.ldapHost.getValue(),                               //Host     : Host,    //"192.168.10.1",  // адрес сервера, к которому происходит подключение по LDAP
                    $scope.ldapPort.getValue(),                               //Port     : Port,    //389,             // номер порта
                    $scope.ldapBase.getValue(),                               //Base     : Base,    //"dc=nss,dc=com",  // текст запроса или имя домена
                    mcService.convertIntToBool($scope.ldapSecure.getValue()), //UseSSL   : UseSSL,  //false,           // использовать шифрование или нет
                    $scope.ldapUser.getValue(),                               //UserName : UserName, //"admin"          // логин пользователя
                    $scope.ldapPassword.getValue(),                           //UserPassword : UserPassword,      // пароль пользователя
                    defaultAdSet,                                             //Attributes   : Attributes   // список атрибутов пользователей через запятую, которые мы хотим получить из домена. Регистр букв имеет значение
                    $scope.ldapListType.getValue(),
                    mcService.convertIntToBool($scope.ldapCreateCommonTree  .getValue()),
                    mcService.convertIntToBool($scope.ldapCreateWorkPosition.getValue()),
                    ldapRequest,
                    ldapBaseDN,
                    ldapFilter,

                    parseData
                ]);
            } else {
                console.log('LDAP check failed');

                showError([-1, "Parse", "Syntax error in LDAP query"]);
            }
        }
    };

    $scope.showConfig = function(){
        function closeConf(){
            $scope.configTreetable.hide();

            webix.UIManager.removeHotKey('Esc', closeConf);
        }

        $scope.configTreetable.show();

        webix.UIManager.addHotKey('Esc', closeConf);
    };

    $scope.changeListType = function () {
        if (successConnect){
            $scope.connect();
        }
    };

    $scope.refreshData = function(){
        $scope.configTreetable.hide();

        $scope.ldapConfigTable.add({adParam: "sAMAccountName", mcParam: "Ник", mcName: "Nick"}, 0);

        var data = $scope.ldapConfigTable.serialize();
        var columns = webix.toArray($scope.ldapTableView.config.columns);

        for (var i = 0; i < data.length; i++){
            data[i] = data[i].adParam;
        }

        for (var i = 2; i < columns.length; i++){
            columns[i].id = data[i-2];
        }

        defaultAdSet = data;

        if ($scope.ldapGetPhoto.getValue() && defaultAdSet.indexOf("jpegPhoto") === -1){
            defaultAdSet.push("thumbnailPhoto");
            defaultAdSet.push("jpegPhoto");
        } else
        if (!$scope.ldapGetPhoto.getValue()){
            var idx = defaultAdSet.indexOf("jpegPhoto");

            if (idx !== -1) defaultAdSet.splice(idx, 1);

            idx = defaultAdSet.indexOf("thumbnailPhoto");

            if (idx !== -1) defaultAdSet.splice(idx, 1);
        }

        defaultAdSet.push("displayName");

        $scope.ldapTableView.refreshColumns();

        $scope.connect();
    };

    $scope.startImport = function(){
        var domain = ldapParams.domainName;//.split(',');
        var res    = {
            Fields: "Nick,FirstName,MiddleName,LastName,Email,WorkCompanyName,WorkPosition,WorkDept,WorkOffice,WorkPhone," +
                    "WorkFax,WorkPager,WorkStreetAddress,WorkCity,WorkState,WorkZIP,WorkCountry,WorkWWW,HomeCellular," +
                    "HomePhone,uSNChanged,displayName" + ($scope.ldapGetPhoto.getValue() ? ",jpegPhoto" : ""),
            Domain: domain,
            Users : [],

            MakeCommonContactListByOU: mcService.convertIntToBool($scope.ldapCreateCommonTree  .getValue()),
            MakeWorkPositions        : mcService.convertIntToBool($scope.ldapCreateWorkPosition.getValue())
        };

        for (var i = 0; i < usersToImport.length; i++){
            var item = usersToImport[i];//configSet[i].adParam];
            var obj  = {};

            for (var j = 0; j < configSet.length; j++){
                obj[configSet[j].mcName] = item[configSet[j].adParam] || "";
            }

            // obj.jpegPhoto  = item.jpegPhoto;
            obj.Path       = item.distinguishedName;
            obj.uSNChanged = item.uSNChanged || 0;
            obj.displayName= item.displayName || "";
            obj.PhotoCRC32 = item.PhotoCRC32;

            res.Users.push(obj);
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_import_ad_users,
            mcConst.SessionID,
            JSON.stringify(res),
            
            function(data){
                mcService.showImportResult(data, $rootScope);

                $rootScope.$broadcast('refresh' + mcConst.dataModels.Contacts, []);
            }
        ]);

    };

    $scope.usersSelect = function(){
        var selected = this.getSelectedId();
        var item     = null;

        usersToImport = [];

        if (selected){
            selected = mcService.isObject(selected) ? [selected] : selected;

            for (var i = 0; i < selected.length; i++){
                item = $scope.ldapTableView.getItem(selected[i].id);

                // if (item && item.$row !== "value"){
                if (item && !item.hasOwnProperty("open")){
                    usersToImport.push(item);
                }
            }

            if (usersToImport.length) {
                $scope.ldapBtnImport.enable();
            } else {
                $scope.ldapBtnImport.disable();
            }
        } else {
            $scope.ldapBtnImport.disable();
        }
    };

    $scope.showFilter = function(){
        if ($scope.ldapFilter.getValue()) {
            $scope.ldapFilterWrap.hide();
        } else {
            $scope.ldapFilterWrap.show();
        }
    };

    // ============================================

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        if (!view) {
            defaultAdSet = getDefaultSet();
        }

        view = initActiveDirectory($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();
    };

    $scope.copyRequest = function(){
        mcService.copyTextToClipboard(getFullLdapFilterRequest(), mcLang(2074)); // "2074":"Запрос скопирован в буффер обмена",
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_ad_options,
            mcConst.SessionID,
            function (data){
                data.LdapConfig = data.LdapConfig.replace(/,jpegPhoto/g, "");
                data.LdapConfig = data.LdapConfig.replace(/,thumbnailPhoto/g, "");

                ldapHeader   = data.LDAPHead;
                domainName   = data.Base;
                defaultAdSet = data.LdapConfig ? data.LdapConfig.split(',') : defaultAdSet;
                ldapBaseDN   = data.LDAPBaseDN ? data.LDAPBaseDN : (domainName ? ((domainName.split('.')).map(function (dc) {
                    return "dc=" + dc;
                })).join(",") : "");

                $scope.ldapHost              .setValue(data.Host);
                $scope.ldapPort              .setValue(data.Port);
                $scope.ldapUser              .setValue($rootScope.adminOptions.adImportUser || data.UserName || mcConst.UserInfo.Nick);
                $scope.ldapSecure            .setValue(data.UseSSL);
                $scope.ldapCreateCommonTree  .setValue(data.MakeCommonContactListByOU);
                $scope.ldapCreateWorkPosition.setValue(data.MakeWorkPositions);
                $scope.ldapListType          .setValue(data.WhoShow);
                $scope.ldapRequest           .setValue(data.LDAPRequest || "");
                $scope.ldapFilter            .setValue(data.LDAPFilter);
                $scope.ldapBaseDN            .setValue(ldapBaseDN);

                if (data.LDAPFilter) {
                    $scope.ldapFilterWrap.show();
                }

                if (data.Base.indexOf('=') === -1 || $rootScope.adminOptions.adImportDomain) {
                    $scope.ldapBase.setValue($rootScope.adminOptions.adImportDomain || domainName || mcConst.UserInfo.Domain);
                }

                setTimeout(function(){
                    if (data.Host !== ''){
                        $scope.ldapPassword.focus()
                    } else {
                        $scope.ldapHost.focus();
                    }
                }, 320);
            }
        ]);
    };

    $scope.$on('ad_users_photos_ready', function(e, args){
        if (view){
            var users = args[0];

            if (users && users.length){
                users.forEach(function (user){
                    var adUser = $scope.ldapTableView.find({sAMAccountName : user.sAMAccountName}, true);

                    if (adUser) {
                        var id = mcService.findItemInArrayOfObj($scope.initData, user.sAMAccountName, "sAMAccountName");

                        adUser.PhotoCRC32 = user.PhotoCRC32;
                        (id !== -1) && ($scope.initData[id].PhotoCRC32 = user.PhotoCRC32);
                        
                        $scope.ldapTableView.updateItem(adUser.id, adUser);
                    }
                });
            }

            setTimeout(function (){
                var res = "";

                $scope.initData.forEach(function (item){
                    if (item.PhotoCRC32){
                        res += item.sAMAccountName + ',' + item.uSNChanged + ',';
                    }
                });

                $rootScope.$broadcast('SendCMDToServer', [
                    // mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_ad_get_user_photo_thumbs,
                    mcConst.SessionID,

                    $scope.ldapBase.getValue(),
                    res
                ]);
            }, 100);
        }
    });

    $scope.$on('ad_user_thumb', function(e, args){
        if (view){
            var user = args[0];

            if (user){
                var adUser = $scope.ldapTableView.find({sAMAccountName : user.sAMAccountName}, true);

                if (adUser) {
                    adUser.jpegPhoto = user.jpegPhoto;

                    $scope.ldapTableView.updateItem(adUser.id, adUser);
                }
            }
        }
    });

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.wndSize = $rootScope.wndSize;

        mcAttributesList = [
            {id:"Nick",             value:mcLang(58)},  // всегда должен быть первым
            {id:"FirstName",        value:mcLang(129)},
            {id:"MiddleName",       value:mcLang(130)},
            {id:"LastName",         value:mcLang(131)},
            {id:"Email",            value:mcLang(134)},
            {id:"WorkCompanyName",  value:mcLang(170)},
            {id:"WorkPosition",     value:mcLang(171)},
            {id:"WorkDept",         value:mcLang(172)},
            {id:"WorkOffice",       value:mcLang(173)},
            {id:"WorkPhone",        value:mcLang(174)},
            {id:"WorkFax",          value:mcLang(160)},
            {id:"WorkPager",        value:mcLang(176)},
            {id:"WorkStreetAddress",value:mcLang(163)},
            {id:"WorkCity",         value:mcLang(164)},
            {id:"WorkState",        value:mcLang(165)},
            {id:"WorkZIP",          value:mcLang(166)},
            {id:"WorkCountry",      value:mcLang(167)},
            {id:"WorkWWW",          value:mcLang(178)},
            {id:"HomeCellular",     value:mcLang(161) + " - " + mcLang(148)},
            {id:"HomePhone",        value:mcLang(159) + " - " + mcLang(148)}
        ];

        if (mcConst.Lang === "uk" || mcConst.Lang === "ru") {
            $scope.adHelpLink = mcService.getLocalHostPath(true) + "/serverhelp/index.html?howtoinstallactivedirectory.htm";
        } else {
            $scope.adHelpLink = "https://nsoft-s.com/en/mcserverhelp/index.html?howtoinstallactivedirectory.htm"
        }

        $scope.show();
        $scope.getData();
    });
}

/*
 var tt = {
 "Fields":"Nick,FirstName,MiddleName,LastName,Email,WorkCompanyName,WorkPosition,WorkDept,WorkOffice,WorkPhone,WorkFax,WorkPager,WorkStreetAddress,WorkCity,WorkState,WorkZIP,WorkCountry,WorkWWW,HomeCellular,HomePhone",
 "Domain":"NSS.COM",
 "Users": [{
 "Nick" : "",
 "FirstName" : "",
 "MiddleName" : "",
 "LastName" : "",
 "Email" : "",
 "WorkCompanyName" : "",
 "WorkPosition" : "",
 "WorkDept" : "",
 "WorkOffice" : "",
 "WorkPhone" : "",
 "WorkFax" : "",
 "WorkPager" : "",
 "WorkStreetAddress" : "",
 "WorkCity" : "",
 "WorkState" : "",
 "WorkZIP" : "",
 "WorkCountry" : "",
 "WorkWWW" : "",
 "HomeCellular" : "",
 "HomePhone" : ""
 }, ...]
 }
 */


"use strict";

function initAdDomains($scope){
    var settings = $$($scope.Name);

    if (!settings){
        settings = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcLang(68) + ": " + mcService.Lang(1964) }, // "1964":"Синхронизация",// "1755":"Домены",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type : 'layout', padding : 5, cols : [
                    { width: 400, rows : [
                        { id: "domainsList" + $scope.Name, view: "list", select: true,
                            template: function (obj) {
                                return "<b>" + obj.Domain + "</b>  [ " + obj.Host + ":" + obj.Port + (obj.Secured ? " - Secured": "") + " ]";
                            },
                            on: { onAfterSelect: $scope.selectDomain}
                        },

                        { height: 7},

                        { cols: [
                            /*
                                { view: "button", value: mcLang(50), width: 150, click: $scope.showAddDomain}, // "50" : "Добавить",
                                { width: 200},
                            */
                            { view: "button", value: mcLang(52), width: 150, click: $scope.delDomain, type: "danger"}, // "52" : "Удалить",
                            {}
                        ]}
                    ]},

                    { id: "domainsInfo", padding: 5, hidden: true, width:600, rows: [
                        { id: "domainsSync", view: "checkbox", val: "Sync",  labelRight: mcService.Lang(1965), labelWidth: 0, value: "", css: "finger", // "1965":"Синхронизация пользователей",
                            on: { onChange: $scope.onChangeItem }
                        },
                        { id: "domainsCreateCommonTree", val: "MakeCommonContacts",  view: "checkbox", labelRight: mcService.Lang(1818), labelWidth: 0, value: "", css: "finger", // "1818":"Сформировать общий список контактов на основе структуры домена (OU, Organization Unit)",
                            on: { onChange: $scope.onChangeItem }
                        },
                        { id: "domainsCreateWorkPosition", val: "MakePositions", view: "checkbox", labelRight: mcService.Lang(1819), labelWidth: 0, value: "", css: "finger", // "1819":"Сформировать должности на основе данных из домена",
                            on: { onChange: $scope.onChangeItem }
                        },

                        // Добавлять в чат новых юзеров из домена или нет
                        // SyncAddNewUsersFromDomain: boolean;
                        { id: "SyncAddNewUsersFromDomain", view: "checkbox", labelRight: mcService.Lang(2231), labelWidth: 0, css: "finger", // "2231":"Добавлять в чат новых пользователей домена",
                            on: { onChange: $scope.onChangeItem }
                        },

                        { id: "domainsUser", template: "&nbsp;", borderless: true, autoheight: true},

                        // Что делать с заблокированными в домене юзерами
                        // 0 - ничего не делать, 1 - увольнять, 2 - блокировать, 3 - удалять
                        // SyncLockDomainUsers: integer;
                        // { cols: [
                            { view: "richselect", value: "0", options: [
                                {id: "0", value: mcLang(683).toLowerCase()},  // "683": "Ничего не делать",
                                {id: "1", value: mcLang(2141).toLowerCase()}, // "2141":"Уволить сотрудника",
                                {id: "2", value: mcLang(684).toLowerCase()},  // "684": "Блокировать учетную запись",
                                {id: "3", value: mcLang(685).toLowerCase()}   // "685": "Удалять учетную запись",
                            ], label: mcLang(2226), labelWidth: 370 }, // "2226":"Что делать с заблокированными пользователями",
                            // {}
                        // ]},

                        // перезапись полей существующих пользователей
                        // 0 - перезаписывать только пустые поля
                        // 1 - перезаписывать все поля безусловно
                        // 2 - не перезаписывать поля, пропускать всё, что есть
                        // SyncOverwriteFieldsType: integer;
                        // { cols: [
                            { view: "richselect", value: "0", options: [
                                {id: "0", value: mcLang(2228)}, // "2228":"только пустые поля",
                                {id: "1", value: mcLang(2229)}, // "2229":"все поля безусловно",
                                {id: "2", value: mcLang(2230)}, // "2230":"не перезаписывать поля",
                            ], label: mcLang(2227), labelWidth: 370 }, // "2227":"Перезапись полей существующих пользователей",
                            // {}
                        // ]},

                        // как часто делать синхронизацию
                        // 0 - раз в неделю,
                        // 1 - каждый день,
                        // 2 - раз в 8 часов
                        // 3 - раз в 4 часа
                        // 4 - каждый час
                        // SyncFrequency: integer;
                        // { cols: [
                            { view: "richselect", value: "0", options: [
                                {id: "0", value: mcLang(2233)}, // "2233":"раз в неделю,",
                                {id: "1", value: mcLang(2234)}, // "2234":"каждый день",
                                {id: "2", value: mcLang(2235)}, // "2235":"раз в 8 часов",
                                {id: "3", value: mcLang(2236)}, // "2236":"раз в 4 часа",
                                {id: "4", value: mcLang(2237)}, // "2237":"каждый час",
                            ], label: mcLang(2232), labelWidth: 370 }, // "2232":"Период синхронизации",
                            // {}
                        // ]},

                        // SyncLDAPString: string; // кастомная строка для процесса синхронизации
                        // { cols: [
                            { rows: [
                                { cols: [
                                    { view: "label", label: mcLang(2077)}, // "2077":"LDAP фильтр",
                                    {},
                                    { view: "button", value: mcLang(2076), autowidth: true, click: $scope.showFilterText} // "2076":"Показать запрос",
                                ]},
                                { id: "ldapRequest" + $scope.Name, view: "textarea"},
                            ]},
                            // {}
                        // ]},

                        // LastSyncProtocolText: string;
                        // последний статус успех\неуспех, 0 - всё ок
                        // LastSyncState,
                        { id: "LastSyncState", view: "label", label: mcLang(2238)}, // "2238":"Статус синхронизации: ",

                        { view: "label", label: mcLang(2239)}, // "2239":"Лог подключения:",
                        // { cols: [
                            { id: "LastSyncProtocolText", view: "textarea", readonly: true},
                            // {}
                        // ]},

                        { cols: [
                            { view: "button", value: mcLang(2241), click: $scope.syncNow}, // "2241":"Синхронизировать сейчас",
                            {}
                        ]}
                    ]},
                        
                    {}
                ]}
            ]
        });

        $scope.wndAddDomain = webix.ui({
            view    : "window",
            position: "center",
            modal   : true,
            head    : false,
            width   : 400,
            height  : 400,
            body    : { view: "form", padding: 7, rules: {
                domain: webix.rules.isNotEmpty,
                host  : webix.rules.isNotEmpty,
                port  : webix.rules.isNumber
            }, elements: [
                { view: "text", label: mcLang(123),  labelWidth: 110, name: "domain"}, // "123": "Имя домена",
                { view: "text", label: mcLang(1756), labelWidth: 110, name: "host"}, // "1756":"Адрес домена",
                { view: "text", label: mcLang(593),  labelWidth: 110, name: "port"}, // "593": "TCP порт",
                { view: "checkbox", labelRight: mcLang(924), labelWidth: 0, css: "finger", on:{ //"924":"Использовать зашифрованное подключение SSL",
                    onChange: function (val) {
                        this.getFormView().getChildViews()[2].setValue(val ? '636' : '389');
                    }
                }},

                { cols: [
                    { view: "button", value: mcLang(13), click: $scope.addDomain }, // "13" : "Ок",
                    {},
                    { view: "button", value: mcLang(12), click: function () { // "12" : "Закрыть",
                        this.getTopParentView().hide();
                    }, type: "danger"}
                ]}
            ]},
            on: {
                onShow: function () {
                    var form = this.getChildViews()[0];

                    form.getChildViews()[0].setValue('');
                    form.getChildViews()[1].setValue('');
                    form.getChildViews()[2].setValue('389');
                    form.getChildViews()[3].setValue('');

                    form.getChildViews()[0].focus();
                }
            }
        });

        $scope.domainsList  = $$("domainsList" + $scope.Name);

        $scope.domainsInfo  = $$("domainsInfo");
        $scope.domainsSync  = $$("domainsSync");
        $scope.domainsUser  = $$("domainsUser");
        $scope.domainsCreateCommonTree   = $$("domainsCreateCommonTree");
        $scope.domainsCreateWorkPosition = $$("domainsCreateWorkPosition");

        mcService.disableContextMenu(settings);
    } else {
        $scope.domainsList.clearAll();
        $scope.domainsList.parse($scope.data);
    }

    return settings;
}

"use strict";

function adDomainsController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.AdDomains;
    $scope.data = [];

    var angElement = document.getElementById($scope.Name);
    var canChange  = true;
    var currentDomain = {};

    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        onApply : function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_modify_check_domain,
                mcConst.SessionID,

                currentDomain.Domain,
                
                mcService.convertIntToBool($scope.domainsSync.getValue()),
                mcService.convertIntToBool($scope.domainsCreateCommonTree.getValue()),
                mcService.convertIntToBool($scope.domainsCreateWorkPosition.getValue()),
                
                function () {
                    clearChangedData();
                }
            ]);
        },
        onClose : function(){
            clearChangedData();
        }
    };

    function clearChangedData (){
        $scope.changedData.data.Items    = {};
        $scope.changedData.data.Desc     = "";
        $scope.changedData.data.ShowDesc = false;

        $scope.domainsList.enable();

        currentDomain = {};
    }

    $scope.selectDomain = function (id) {
        currentDomain = $scope.domainsList.getItem(id);

        if (currentDomain){
            $scope.domainsSync.setValue(currentDomain.Sync);
            $scope.domainsCreateCommonTree.setValue(currentDomain.MakeCommonContacts);
            $scope.domainsCreateWorkPosition.setValue(currentDomain.MakePositions);

            $scope.domainsUser.define("template", mcLang(1966) + (currentDomain.UserLogin || mcLang(1045))); // "1966":"Пользователь: ", "1045":"нет",
            $scope.domainsUser.refresh();
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };
    
    $scope.delDomain = function () {
        var domain = $scope.domainsList.getSelectedItem();

        if (domain){
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(1078, domain.Domain), // "1078":"Удалить %s из списка?",
                ok    : mcService.Lang(114), // "114": "да",
                cancel: mcService.Lang(113), // "113": "нет",
                callback:function(yes){
                    if (yes) {
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_delete_check_domain,
                            mcConst.SessionID,
                            domain.Domain,
                            function () {
                                $scope.domainsList.remove($scope.domainsList.getSelectedId());

                                $scope.data.splice(mcService.findItemInArrayOfObj($scope.data, domain.Domain, 'Domain'), 1);
                            }
                        ]);
                    }
                }
            }));
        }
    };

    $scope.onChangeItem = function (val) {
        if (canChange) {
            $scope.domainsList.disable();

            $scope.changedData.data.ShowDesc = true;
            $scope.changedData.data.Items[this.config.val] = val;

            $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
        }
    };

    $scope.syncNow = function (){
        var domain = $scope.domainsList.getSelectedItem();

        if (domain) {
            $rootScope.$broadcast('SendCMDToServer', [
                // mcConst.lockInterface,
                mcConst._CMD_.cs_adm_ad_sync_now,
                mcConst.SessionID,
                
                domain.Domain
            ]);
        }
    };

    $scope.getData = function () {
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_check_domains_list,
            mcConst.SessionID,
            function (data) {
                // "Host"               : "192.168.10.1",   // имя хоста или IP адрес домена
                // "Domain"             : "mycompany.com",  // название домена
                // "Port"               : 389,              // номер порта для LDAP соединения
                // "Secured"            : false             // использовать шифрованное соединение или нет
                // "UserLogin"          : "admin",          // (7.1+) логин Windows-пользователя у которого есть доступ к домену для проведения синхронизации
                // "Sync"               : true,             // (7.1+) использовать автоматическую синхронизацию или нет
                // "MakeCommonContacts" : true,             // (7.1+) формировать общий список контактов на основе структуры домена (OU)
                // "MakePositions"      : true              // (7.1+) формировать должности на основе данных из домена

                /*
                // Что делать с заблокированными в домене юзерами
                // 0 - ничего не делать, 1 - увольнять, 2 - блокировать, 3 - удалять
                SyncLockDomainUsers: integer;

                SyncLDAPString: string; // кастомная строка для процесса синхронизации

                // перезапись полей существующих пользователей
                // 0 - перезаписывать только пустые поля
                // 1 - перезаписывать все поля безусловно
                // 2 - не перезаписывать поля, пропускать всё, что есть
                SyncOverwriteFieldsType: integer;

                // Добавлять в чат новых юзеров из домена или нет
                SyncAddNewUsersFromDomain: boolean;

                dtUTCLastSync: TDateTime;

                LastSyncProtocolText: string;
                // последний статус успех\неуспех, 0 - всё ок
                LastSyncState,

                // как часто делать синхронизацию
                // 0 - раз в неделю,
                // 1 - каждый день,
                // 2 - раз в 8 часов
                // 3 - раз в 4 часа
                // 4 - каждый час
                SyncFrequency: integer;*/

                canChange = false;

                $scope.data = data;

                $scope.show();

                $scope.domainsInfo.hide();

                var firstId = $scope.domainsList.getFirstId();

                if (firstId){
                    $scope.domainsList.select(firstId);
                    $scope.domainsInfo.show();
                }

                canChange = true;
            }
        ]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initAdDomains($scope);

        mcService.initResize(settings, $scope.Name);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();

        $scope.getData();
    });
}
function initUserGroups($scope){
    "use strict";

    // function usersTemplate(obj){
    //     return obj.DisplayName + " <span style='float:right'>(UIN: " + obj.UIN + ")</span>";
    // }
    var accessTypes = ["any", "chat", "kanban", "forum", "admin", "iapi", "msl"];
    var _view = $$($scope.Name);

    if (!_view) {
        $scope.mcLEB.initTextSource({
            add  : mcLang(50),
            edit : mcLang(51),
            del  : mcLang(52)
        });

        var editButtons = $scope.mcLEB.editButtons({
            actions: {
                add  : $scope.add,
                edit : $scope.edit,
                del  : $scope.del
            },
            actionTitles: {
                add  : mcLang(911), // "911":"Добавление новой группы",
                edit : mcLang(914), // "914":"Переименовать группу",
                del  : mcLang(913)  // "913":"Удалить группу \"%s\"?",
            },
            delName  : "Name",
            fillItems: ["Name"],
            editTitle: mcLang(910), // "910":"Название группы",
            list     : "guList" + $scope.Name
        });

        var _guList = {
            view        : "datatable",
            resizeColumn: true,
            id          : "guList" + $scope.Name,
            select      : "row",
            height      : 250,
            multiselect : false,
            headerRowHeight: 25,
            minColumnWidth : 70,
            navigation  : false,
            editable    : true,
            columns     : [
                { id:"AccessType", header:mcLang(2185),sort:"string", width: 150, editor:"multiselect", optionslist: true, options: accessTypes, fitMaster: true}, // "2185":"Тип доступа",
                { id:"Name",       header:mcLang(910), sort:"string", fillspace: true, template: function (obj){ // "910":"Название группы",
                    return "[" + obj.ID + "] " + obj.Name;
                }},
            ],
            on : {
                onAfterSelect: $scope.selectGroup,
                onAfterEditStop: $scope.changeAccessType
            }
        };

        _view = webix.ui({
            type      : "space",
            padding   : 5,
            container : $scope.Name,
            id        : $scope.Name,
            borderless: true,
            rows      : [
                { cols: [
                    { view: "template", type: "header", template: mcService.Lang(1722) }, // "1722":"Группы пользователей",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: "layout", cols: [
                    { rows: [
                        { height: 2},

                        editButtons.btnList,

                        { height: 4},

                        mcService.FilterFiled({
                            listName     : "guList" + $scope.Name,
                            filterParams : ["Name"]
                        }),

                        _guList,

                        { view : "resizer" },

                        { rows: [
                            { type: 'header', height: 30, id: 'currentListCN' + $scope.Name, template: mcService.Lang(919) }, // "919":"Пользователи выбранной группы",

                            // { height: 3},

                            // mcService.FilterFiled({
                            //     listName     : 'currentList' + $scope.Name,
                            //     filterParams : ["DisplayName"]
                            // }),

                            {
                                // id : 'currentList' + $scope.Name, view: "list", template: usersTemplate, navigation: true, drag: true, select: "multiselect", disabled: true,
                                view        : "datatable",
                                resizeColumn: false,
                                id          : 'currentList' + $scope.Name,
                                drag        : true,
                                select      : "row",
                                multiselect : true,
                                headerRowHeight: 25,
                                minColumnWidth : 70,
                                navigation  : false,
                                columns     : [
                                    { id:"UIN",         header:"UIN", width: 60,     sort:"int"},
                                    { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                                ],
                                on : {
                                    onBeforeDrop : $scope.moveUsers,
                                    onAfterSelect: function() {
                                        $scope.removeUser.enable();
                                    }
                                }
                            }
                        ]}
                    ]},

                    { view : "resizer" },

                    { rows: [
                        { type: 'header', height: 30, /*id: 'allUsersCN',*/ template: mcService.Lang(942) }, // "942":"Все пользователи",

                        { height: 3},

                        mcService.FilterFiled({
                            listName     : 'allUsers' + $scope.Name,
                            filterParams : ["DisplayName", "UIN"]
                        }),

                        {
                            // id : 'allUsers' + $scope.Name, view: "list", template: usersTemplate, navigation: true, drag: true, select: "multiselect",
                            view        : "datatable",
                            resizeColumn: false,
                            id          : 'allUsers' + $scope.Name,
                            drag        : true,
                            select      : "row",
                            multiselect : true,
                            headerRowHeight: 25,
                            minColumnWidth : 70,
                            navigation  : false,
                            columns     : [
                                { id:"UIN",         header:"UIN", width: 60,     sort:"int"},
                                { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                            ],
                            on : {
                                onBeforeDrop : $scope.moveUsers,
                                onAfterSelect: function() {
                                    $scope.addUser.enable();
                                }
                            }
                        }
                    ]}
                ]},

                { cols: [
                    { id: "removeUser" + $scope.Name, view: "button", label: mcService.Lang(918), type: 'danger', disabled: true, click: function(){ // "918":"Удалить пользователя из группы",
                        $scope.moveByButton('currentList', 'allUsers');
                    }},

                    { width: 10 },

                    { id: "addUser" + $scope.Name, view: "button", label: mcService.Lang(917), type: 'prev', disabled: true, click: function(){ // "917":"Переместить пользователя в группу",
                        $scope.moveByButton('allUsers', 'currentList');
                    }}
                ]}
            ]
        });

        $scope.addUser     = $$("addUser" + $scope.Name);
        $scope.removeUser  = $$("removeUser" + $scope.Name);
        $scope.allUsers    = $$('allUsers' + $scope.Name);
        $scope.currentList = $$('currentList' + $scope.Name);
        $scope.guList      = $$("guList" + $scope.Name);

        mcService.disableContextMenu(_view);
    }
    
    return _view;
}

function userGroupsController($scope, $rootScope){
    "use strict";

    $scope.Name   = mcConst.dataModels.UserGroups;
    $scope.grData = [];
    $scope.allUserData = [];
    $scope.guList = null;
    $scope.selectedGroup = null;
    $scope.mcLEB = new window.mcWidgets.ListEditButtons($rootScope);

    $scope.guestList   = null;
    $scope.currentList = null;

    var angElement = document.getElementById($scope.Name);
    var rcView     = null;

    function refreshTitle(_title, _lang, _count){
        var title = $$(_title);

        if (title){
            title.define('template', _lang + " [" + _count + "]");
            title.refresh();
        }
    }

    function checkDuplicate (name, id){
        var res = true;

        for (var i = 0; i < $scope.grData.length; i++){
            if (id && (id == $scope.grData[i].ID)){
                continue;
            }

            if ($scope.grData[i].Name.toLowerCase() == name.toLowerCase()){
                res = false;

                break;
            }
        }

        return res;
    }

    function checkName(name, id){
        var _name = mcService.trim(name);
        var res   = false;

        if ((_name != '') && mcService.isSymbolicNumbers(_name) && checkDuplicate(_name, id)){
            res = true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(912)]); // "912":"Название группы не должно быть пустым и совпадать с уже существующей!",
        }

        return res;
    }

    function fillAllUsers(){
        $scope.allUserData.sort(function (a, b) {
            return mcService.sortAB(a.UIN, b.UIN);
        });

        $scope.allUsers.clearAll();
        $scope.allUsers.parse($scope.allUserData);
        // $scope.allUsers.sort("UIN", "asc", "int");
    }

    // ===========================================================

    $scope.add  = function(){
        var form = this;
        var name = form.getChildViews()[0].getValue().replace(/\|/g, "");

        if (checkName(name)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_add_new_user_group,
                mcConst.SessionID,
                
                name,
                "admin",

                function(data){
                    var list = $scope.guList;
                    var item = {
                        Name: name,
                        ID  : data.ID,
                        AccessType: "admin"
                    };

                    list.add(item);
                    list.select(list.getLastId());
                    list.scrollTo(0, 9999);

                    $scope.grData.push(item);
                }
            ]);
        } else {
            return true;
        }
    };

    $scope.del  = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_delete_groups_list,
            mcConst.SessionID,
            $scope.guList.getSelectedItem().ID,
            function(){
                $scope.grData.splice(mcService.findItemInArrayOfObj($scope.grData, $scope.guList.getSelectedItem().ID, "ID"), 1);
                $scope.guList.remove($scope.guList.getSelectedId());

                if ($scope.guList.data.count() > 0){
                    $scope.guList.select($scope.guList.getFirstId());
                } else {
                    $scope.currentList.clearAll();
                    $scope.currentList.disable();
                    $scope.selectedGroup = null;
                }
            }
        ]);
    };

    $scope.edit = function(){
        var form = this;
        var name = form.getChildViews()[0].getValue().replace(/\|/g, "");

        if (checkName(name)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_rename_group_of_users,
                mcConst.SessionID,
                $scope.guList.getSelectedItem().ID,
                name,
                function(){
                    $scope.guList.getSelectedItem().Name = name;
                    $scope.guList.refresh();
                }
            ]);
        } else {
            return true;
        }
    };

    $scope.selectGroup = function(id){
        $scope.selectedGroup = this.getItem(id);
        $scope.getGroupUsers($scope.selectedGroup.ID);

        $scope.currentList.enable();
        $scope.removeUser.disable();
    };

    $scope.moveByButton = function(from, to){
        var selectedItems = $scope[from].getSelectedItem();

        if (mcService.isObject(selectedItems)){
            selectedItems = [selectedItems];
        }

        if (selectedItems){
            $scope.moveUsers.call(null, {
                fromList : from + $scope.Name,
                toList   : to + $scope.Name,
                uList    : selectedItems
            });
        }
    };

    $scope.moveUsers = function(context){
        var fromList = context.fromList || context.from.config.id;
        var toList   = context.toList   || context.to.config.id;
        var userList = context.uList    || context.source;
        var res      = [];
        var grID     = 0;

        if (fromList != toList && $scope.selectedGroup) {
            var uList = [];

            for (var i = 0; i < userList.length; i++){
                res.push($scope.allUsers.getItem(userList[i].id || userList[i]).UIN);

                uList.push($scope.allUsers.getItem(userList[i].id || userList[i]));
            }

            grID = $scope.selectedGroup.ID;

            if (res.length > 0){
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    toList == ('currentList' + $scope.Name) ? mcConst._CMD_.cs_adm_add_users_to_group : mcConst._CMD_.cs_adm_remove_users_from_group,
                    mcConst.SessionID,
                    res.join(','),
                    grID
                ]);
            }

            if (toList == ('currentList' + $scope.Name)){
                $$(toList).parse(uList);
                $$(toList).sort("UIN", "asc", "int");
            } else {
                uList.forEach(function(item){
                    $scope.currentList.remove(item.id);
                });
            }

            refreshTitle('currentListCN' + $scope.Name,  mcService.Lang(919), $scope.currentList.data.count());
            
            $scope.removeUser.disable();
            $scope.addUser.disable();
        }

        $$(fromList).unselectAll();

        return false;
    };

    $scope.getGroupUsers = function(id){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_group_users_list,
            mcConst.SessionID,
            id,
            function(data){
                data.forEach(function(item){
                    item.id = item.UIN;
                });

                var list = $scope.currentList;

                refreshTitle('currentListCN' + $scope.Name,  mcService.Lang(919), data.length);

                list.clearAll();

                if (data.length) {
                    list.parse(data);
                    list.sort("UIN", "asc", "int");
                }
            }
        ]);
    };

    $scope.selectFirstItemGroupList = function(){
        var grList       = $scope.guList;
        var selectedItem = grList.getSelectedItem() || [];

        if (mcService.isArray(selectedItem) && selectedItem.length !== 0){ // no list item selected
            grList.select(grList.getFirstId());
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.changeAccessType = function (state, editor){
        // console.log(state);
        // console.log(editor);
        var item = $scope.guList.getSelectedItem();

        if (state.old !== state.value && item){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_modify_common_user_group,
                mcConst.SessionID,

                item.ID,
                item.Name,
                item.AccessType
            ]);
        }
    };

    $scope.show = function (){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        rcView = initUserGroups($scope);

        $scope.selectFirstItemGroupList();

        mcService.initResize(rcView, $scope.Name);
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_user_groups,
            mcConst.SessionID,
            
            function(data){
                $scope.grData = data || [];

                $scope.show($scope);

                $scope.guList.clearAll();
                $scope.guList.define('data', $scope.grData);

                if ($scope.guList.data.count() > 0) {
                    $scope.guList.select($scope.guList.getFirstId());
                }

                mcService.getAllUserWithParams(function fill_uList (_data){
                    _data.forEach(function(item){
                        item.id = item.UIN;
                    });

                    $scope.allUserData = webix.copy(_data);

                    fillAllUsers();
                }, $rootScope, { Filters: "UIN,DISPLAYNAME" });
            }
        ]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.show($scope);
        $scope.getData();
    });
}
function initPersonalGroups($scope){
    "use strict";
    var _view = $$($scope.Name);

    if (!_view) {
        $scope.mcLEB.initTextSource({
            add  : mcLang(50),
            edit : mcLang(51),
            del  : mcLang(52)
        });

        _view = webix.ui({
            type      : "space",
            padding   : 5,
            container : $scope.Name,
            id        : $scope.Name,
            borderless: true,
            rows      : [
                { cols: [
                    { view: "template", type: "header", template: mcService.Lang(2186) }, // "2186":"Личные группы пользователей",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: "layout", cols: [
                    { rows: [
                        { type: 'header', height: 30, template: mcService.Lang(942) }, // "942":"Все пользователи",

                        { height: 3},

                        mcService.FilterFiled({
                            listName     : 'allUsers' + $scope.Name,
                            filterParams : ["DisplayName", "UIN"]
                        }),

                        { view: "checkbox", value: true, labelWidth: 0, css: "finger", labelRight: mcLang(2187), // "2187":"Пользователи с личными группами",
                            on: { onChange: $scope.getUsers }
                        },

                        {
                            view        : "datatable",
                            resizeColumn: false,
                            id          : 'allUsers' + $scope.Name,
                            drag        : true,
                            select      : "row",
                            multiselect : false,
                            headerRowHeight: 25,
                            minColumnWidth : 70,
                            navigation  : false,
                            columns     : [
                                { id:"UIN",         header:"UIN", width: 60,     sort:"int"},
                                { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                            ],
                            on : {
                                onAfterSelect: $scope.selectUser
                            }
                        }
                    ]},

                    { view: "resizer" },

                    { rows: [
                        { height: 2},

                        $scope.mcLEB.editButtons({
                            actions: $scope.groupsOfUser,
                            actionTitles: {
                                add  : mcLang(911), // "911":"Добавление новой группы",
                                edit : mcLang(914), // "914":"Переименовать группу",
                                del  : mcLang(913)  // "913":"Удалить группу \"%s\"?",
                            },
                            delName  : "Name",
                            fillItems: ["Name"],
                            editTitle: mcLang(910), // "910":"Название группы",
                            list     : "pguList" + $scope.Name
                        }).btnList,

                        { height: 4},

                        mcService.FilterFiled({
                            listName     : "pguList" + $scope.Name,
                            filterParams : ["Name"]
                        }),

                        {
                            view        : "datatable",
                            resizeColumn: false,
                            id          : "pguList" + $scope.Name,
                            select      : "row",
                            height      : 250,
                            multiselect : false,
                            headerRowHeight: 25,
                            minColumnWidth : 70,
                            navigation  : false,
                            editable    : true,
                            columns     : [
                                { id:"ID",   header:"ID",        sort:"number", width: 43}, // "2185":"Тип доступа",
                                { id:"Name", header:mcLang(910), sort:"string", fillspace: true}, // "910":"Название группы",
                            ],
                            on : {
                                onAfterSelect  : $scope.selectGroup
                            }
                        },

                        { view : "resizer" },

                        { rows: [
                            { type: 'header', height: 30, id: 'currentListCN'  + $scope.Name, template: mcService.Lang(919) }, // "919":"Пользователи выбранной группы",

                            // { height: 3},
                            // mcService.FilterFiled({
                            //     listName     : 'currentList' + $scope.Name,
                            //     filterParams : ["DisplayName"]
                            // }),

                            new mcService.ListButtonSet({
                                idBtn  : 'usersGroup' + $scope.Name,
                                type   : 'combo',
                                actions: $scope.usersOfGroup,
                                list   : 'currentList' + $scope.Name,
                                selectedItem : "DisplayName",
                                regShowWindow: $scope.regShowWindow,
                                visibleBtns: {
                                    add: true,
                                    del: true,
                                    cls: false
                                }
                            }),

                            {
                                view        : "datatable",
                                resizeColumn: false,
                                id          : 'currentList' + $scope.Name,
                                drag        : "target",
                                select      : "row",
                                multiselect : true,
                                headerRowHeight: 25,
                                minColumnWidth : 70,
                                navigation  : false,
                                columns     : [
                                    { id:"UIN",         header:"UIN", width: 60,     sort:"int"},
                                    { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                                ],
                                on : {
                                    onBeforeDrop : $scope.moveUsers
                                }
                            }
                        ]}
                    ]},

                ]},
            ]
        });

        $scope.allUsers    = $$('allUsers' + $scope.Name);
        $scope.currentList = $$('currentList' + $scope.Name);
        $scope.pguList     = $$("pguList" + $scope.Name);
        $scope.usersGroup  = $$('usersGroup' + $scope.Name);

        mcService.disableContextMenu(_view);
    }
    
    return _view;
}
"use strict";

function personalGroupsController($scope, $rootScope){
    $scope.Name   = mcConst.dataModels.PersonalGroups;
    $scope.grData = [];
    $scope.allUserData = [];
    $scope.pguList = null;
    $scope.selectedGroup = null;
    $scope.mcLEB  = new window.mcWidgets.ListEditButtons($rootScope);

    $scope.guestList   = null;
    $scope.currentList = null;
    $scope.usersOfGroup = {};
    $scope.groupsOfUser = {};
    $scope.userListData = [];

    var angElement = document.getElementById($scope.Name);
    var rcView     = null;

    function refreshTitle(_title, _lang, _count){
        var title = $$(_title);

        if (title){
            title.define('template', _lang + " [" + _count + "]");
            title.refresh();
        }
    }

    function checkDuplicate (name, id){
        var res = true;

        for (var i = 0; i < $scope.grData.length; i++){
            if (id && (id == $scope.grData[i].ID)){
                continue;
            }

            if ($scope.grData[i].Name.toLowerCase() == name.toLowerCase()){
                res = false;

                break;
            }
        }

        return res;
    }

    function checkName(name, id){
        var _name = mcService.trim(name);
        var res   = false;

        if ((_name != '') && mcService.isSymbolicNumbers(_name) && checkDuplicate(_name, id)){
            res = true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(912)]); // "912":"Название группы не должно быть пустым и совпадать с уже существующей!",
        }

        return res;
    }

    function fillAllUsers(){
        $scope.allUserData.sort(function (a, b) {
            return mcService.sortAB(a.UIN, b.UIN);
        });

        $scope.allUsers.clearAll();
        $scope.allUsers.parse($scope.allUserData);
    }

    // ===========================================================

    $scope.usersOfGroup.save = function(field){
        var uin = mcService.trim(field.getValue());
        var nik = mcService.trim(field.getText());

        if (nik === '') {
            return false;
        } else
        if (!$scope.currentList.getItem(uin)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_users_to_private_group,
                mcConst.SessionID,

                $scope.selectedGroup.ID,
                uin
            ]);

            $scope.currentList.add({
                id         : uin,
                UIN        : uin,
                ConfList   : '',
                DisplayName: nik
            });

            $scope.currentList.select(uin);

            return true;
        } else {
            webix.message(mcService.Lang(1511)); // "1511":"Такой пользователь уже есть",
        }
    };

    $scope.usersOfGroup.del = function(selectedItem){
        var uins = [];

        if (mcService.isArray(selectedItem)){
            for (var i = 0; i < selectedItem.length; i++){
                uins.push(selectedItem[i].UIN);
            }
        } else {
            uins = [selectedItem.UIN];
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_remove_users_from_private_group,
            mcConst.SessionID,

            $scope.selectedGroup.ID,
            uins.join(',')
        ]);

        $scope.selectedItem = [];
        $scope.currentList.select($scope.currentList.getFirstId());
    };

    $scope.usersOfGroup.preview = function(field){
        mcService.getAllUserForFillList($scope.userListData, function fill_uList (data){
            $scope.userListData = mcService.transformDataObject(webix.copy(data), [['DisplayName', 'value'], ['UIN', 'id']]);

            $scope.userListData.forEach(function (t, i) {
                t.value = t.value + "<span style='float:right'>(UIN: " + data[i].UIN + ")</span>"
            });

            field.define('options', $scope.userListData);
            field.refresh();
            field.focus();
        }, $rootScope);
    };

    // ===========================================================

    $scope.groupsOfUser.add  = function(){
        var form = this;
        var name = form.getChildViews()[0].getValue().replace(/\|/g, "");

        if (checkName(name) && $scope.selectedUser && $scope.selectedUser.UIN){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_create_personal_user_group,
                mcConst.SessionID,
                
                name,
                $scope.selectedUser.UIN,
                "",

                function(data){
                    var list = $scope.pguList;
                    var item = {
                        Name: name,
                        ID  : data.ID,
                    };

                    list.add(item);
                    list.select(list.getLastId());
                    list.scrollTo(0, 9999);

                    $scope.grData.push(item);
                }
            ]);
        } else {
            return true;
        }
    };

    $scope.groupsOfUser.del  = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_delete_groups_list,
            mcConst.SessionID,

            $scope.pguList.getSelectedItem().ID,
            
            function(){
                $scope.grData.splice(mcService.findItemInArrayOfObj($scope.grData, $scope.pguList.getSelectedItem().ID, "ID"), 1);
                $scope.pguList.remove($scope.pguList.getSelectedId());

                if ($scope.pguList.data.count() > 0){
                    $scope.pguList.select($scope.pguList.getFirstId());
                } else {
                    $scope.selectedGroup = null;

                    refreshTitle('currentListCN' + $scope.Name,  mcService.Lang(919), 0);

                    $scope.currentList.clearAll();
                    $scope.currentList.disable();
                    $scope.usersGroup.hide();


                }
            }
        ]);
    };

    $scope.groupsOfUser.edit = function(){
        var form = this;
        var name = form.getChildViews()[0].getValue().replace(/\|/g, "");

        if (checkName(name)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_modify_personal_user_group,
                mcConst.SessionID,

                $scope.pguList.getSelectedItem().ID,
                name,

                function(){
                    $scope.pguList.getSelectedItem().Name = name;
                    $scope.pguList.refresh();
                }
            ]);
        } else {
            return true;
        }
    };

    // ===========================================================

    $scope.selectUser = function (id){
        $scope.selectedUser = this.getItem(id);

        $scope.getUserGroups($scope.selectedUser.UIN);
    };

    $scope.selectGroup = function(id){
        $scope.selectedGroup = this.getItem(id);
        $scope.getGroupUsers($scope.selectedGroup.ID);

        $scope.currentList.enable();
    };

    $scope.moveByButton = function(from, to){
        var selectedItems = $scope[from].getSelectedItem();

        if (mcService.isObject(selectedItems)){
            selectedItems = [selectedItems];
        }

        if (selectedItems){
            $scope.moveUsers.call(null, {
                fromList : from + $scope.Name,
                toList   : to + $scope.Name,
                uList    : selectedItems
            });
        }
    };

    $scope.moveUsers = function(context){
        var fromList = context.fromList || context.from.config.id;
        var toList   = context.toList   || context.to.config.id;
        var userList = context.uList    || context.source;
        var res      = [];
        var grID     = 0;

        if (fromList != toList && $scope.selectedGroup) {
            var uList = [];
            var user  = null;

            for (var i = 0; i < userList.length; i++){
                user = $scope.allUsers.getItem(userList[i].id || userList[i]);

                if (user && user.UIN != mcConst.UserInfo.UIN){
                    res.push(user.UIN);

                    uList.push($scope.allUsers.getItem(userList[i].id || userList[i]));
                }
            }

            grID = $scope.selectedGroup.ID;

            if (res.length > 0){
                refreshTitle('currentListCN' + $scope.Name,  mcService.Lang(919), $scope.currentList.data.count());

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    // toList == ('currentList' + $scope.Name) ? mcConst._CMD_.cs_adm_add_users_to_group : mcConst._CMD_.cs_adm_remove_users_from_group,
                    mcConst._CMD_.cs_adm_add_users_to_private_group,
                    mcConst.SessionID,
                    grID,
                    res.join(',')
                ]);
            }

            if (toList == ('currentList' + $scope.Name)){
                $$(toList).parse(uList);
                $$(toList).sort("UIN", "asc", "int");
            } else {
                uList.forEach(function(item){
                    $scope.currentList.remove(item.id);
                });
            }
        }

        // $$(fromList).unselectAll();

        return false;
    };

    $scope.getUserGroups = function(uin){
        $scope.pguList.clearAll();

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_personal_user_groups,
            mcConst.SessionID,
            uin,
            function(data){
                $scope.grData = data || [];

                $scope.pguList.define('data', data);

                var id = $scope.pguList.getFirstId();

                if (id && $scope.grData.length) {
                    $scope.pguList.select(id);

                    $scope.usersGroup.show();
                    $scope.currentList.enable();
                } else {
                    refreshTitle('currentListCN' + $scope.Name,  mcService.Lang(919), 0);
                    
                    $scope.currentList.clearAll();
                    
                    $scope.usersGroup.hide();
                    $scope.currentList.disable();
                }
            }
        ]);
    };

    $scope.getGroupUsers = function(id){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_personal_group_users_list,
            mcConst.SessionID,

            id,
            $scope.selectedUser.UIN,

            function(data){
                // "UIN"   : 17, // идентификатор владельца группы
                // "ID"    : 21, // идентификатор личной группы пользователя-владельца
                // "Users" : [{}] // список пользователей в группе, массив объектов
                var users = data.Users;

                users.forEach(function(user){
                    user.id = user.UIN;
                });

                var list = $scope.currentList;

                refreshTitle('currentListCN' + $scope.Name,  mcService.Lang(919), users.length);

                $scope.usersGroup.show();
                $scope.currentList.enable();

                list.clearAll();

                if (users.length) {
                    list.parse(users);
                    list.sort("UIN", "asc", "int");
                }
            }
        ]);
    };

    $scope.getUsers = function (val){
        mcService.getAllUserWithParams(function fill_uList (_data){
            _data.forEach(function(item){
                item.id = item.UIN;
            });

            $scope.allUserData = webix.copy(_data);

            fillAllUsers();

            $scope.allUsers.select($scope.allUsers.getFirstId());
        }, $rootScope, { Filters: "UIN,DISPLAYNAME", Params: val ? "groupowner" : "all" });
    };

    $scope.selectFirstItemGroupList = function(){
        var grList       = $scope.pguList;
        var selectedItem = grList.getSelectedItem() || [];

        if (mcService.isArray(selectedItem) && selectedItem.length !== 0){ // no list item selected
            grList.select(grList.getFirstId());
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.changeAccessType = function (state, editor){
        // console.log(state);
        // console.log(editor);
        var item = $scope.pguList.getSelectedItem();

        if (state.old !== state.value && item){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_modify_common_user_group,
                mcConst.SessionID,

                item.ID,
                item.Name,
                item.AccessType
            ]);
        }
    };

    $scope.show = function (){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        rcView = initPersonalGroups($scope);

        $scope.selectFirstItemGroupList();

        mcService.initResize(rcView, $scope.Name);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.show($scope);
        $scope.getUsers(true);
    });
}
function initAutoChannels($scope){
    "use strict";

    var lWidth = 250;
    var _view  = $$($scope.Name);

    if (!_view){
        $scope.mcLEB.initTextSource({
            add  : mcLang(50),
            del  : mcLang(52)
        });

        $scope.editCnlsBtn = $scope.mcLEB.editButtons({
            actions: {
                add  : $scope.actions.save,
                del  : $scope.actions.del
            },
            actionTitles: {
                add  : mcLang(1731), // "1731":"Добавление новой конференции",
                del  : mcLang(1635)  // "1635":"Удалить конференцию?<br><b>\"%s\"</b>",
            },
            // delName  : "Name",
            delName  : "ConfName",
            // fillItems: ["Name"],
            fillItems: ["ConfName"],
            editTitle: mcLang(1042), // "1042":"Название конференции",
            list     : "autoChannelsList"
        });

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type: "header", template : mcService.Lang(1039) }, // "1039":"Автосоздаваемые каналы",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: 'layout', cols : [
                    { id: "autoChannelListWrapper", rows: [
                        $scope.editCnlsBtn.btnList,

                        new mcService.FilterFiled({
                            listName: "autoChannelsList",
                            filterParams: ['ConfName', 'UID']
                        }),

                        { view: "list", id: "autoChannelsList", select: true, template: "#ConfName# <i>(UID: #UID#)</i>", on: {
                            onAfterSelect: $scope.selectChannel
                        }}
                    ]},

                    { view : "resizer" },

                    { hidden: true, id: "autoChannelInfo", rows: [
                        // { id: "acnName", type: "header", template: "&nbsp;", borderless: true},
                        // { id: "acnName",     view: "text", label: mcService.Lang(1042) + ":", labelPosition: "top", readonly: true} // "1042":"Название канала",

                        { padding: 5, rows: [
                            { id: "acnConfName",  view: "text", labelPosition: "top", label: mcService.Lang(1042), labelWidth: lWidth, on: { onTimedKeyPress: $scope.changeEx, onChange: $scope.changeEx }}, // "1042":"Название канала",

                            { height: 5 },
                            { id: "acnConfTopic", view: "text", labelPosition: "top", label: mcService.Lang(1043), labelWidth: lWidth, on: { onTimedKeyPress: $scope.changeEx, onChange: $scope.changeEx }}, // "1043":"Тема канала:",

                            { height: 5 },
                            { id: "acnConfType",  view: "richselect", value: mcConst._CMD_.confType.STANDARD, readOnly: true, label: mcLang(2102), labelPosition: "top", // "2102":"Тип конференции",
                                on: { onChange: function (val) {
                                    if (val === mcConst._CMD_.confType.PASSWORD){
                                        $scope.acnPwdWrap.show();
                                    } else {
                                        $scope.acnPwdWrap.hide();
                                    }

                                    $scope.changeEx.apply(this, arguments);
                                }},
                                options: [
                                    { id: mcConst._CMD_.confType.STANDARD, value: mcLang(2099) }, // "2099":"Обычная конференция",
                                    { id: mcConst._CMD_.confType.PASSWORD, value: mcLang(2100) }, // "2100":"Конференция закрытая паролем",
                                    { id: mcConst._CMD_.confType.HIDDEN,   value: mcLang(2101) }  // "2101":"Невидимая конференция",
                                ]
                            },

                            { height: 5 },
                            { id: "acnPwdWrap", hidden: true, rows: [
                                { template: mcLang(1050), borderless: true, height: 22}, // "1050":"Пароль для входа в конференцию",
                                { cols: [
                                    { id: "acnPass",  view: "text", type: "password", on: { onTimedKeyPress: $scope.changeEx, onChange: $scope.changeEx }},
                                    { view: "toggle", width: 28, offIcon: "eye", onIcon: "eye-slash",  type:"icon", css: "iconNoPadding noBG", tooltip: mcLang(1099) + "/" + mcLang(1100).toLowerCase(), // "1099":"Показать", "1100":"Скрыть",
                                        on: { onChange: function (val) {
                                            var pwd = $scope.acnPassword;

                                            if (val) {
                                                pwd.define('type', 'text');
                                            } else {
                                                pwd.define('type', 'password');
                                            }

                                            pwd.refresh();
                                            pwd.getInputNode().setAttribute("autocomplete", "new-password");
                                        }}
                                    }
                                ]}
                            ]},

                            // { height: 5 },
                            // { id: "acnFlagLockExit",  view: "checkbox", value: 0, labelWidth: 0, labelRight: mcService.Lang(1048), css: "finger", on: { onChange: $scope.changeEx } }, // "1048":"Запретить выход из канала",

                            { height: 10 },
                            { id: "acnJoinGroups", view: "select", value: "0", css: "finger",
                                options: [
                                    { id: "1", value: mcService.Lang(1051)}, // "1051":"Подключать к каналу всех пользователей",
                                    { id: "0", value: mcService.Lang(1052)}  // "1052":"Подключать пользователей выбранных групп",
                                ],
                                on: {
                                    onChange: $scope.changeInviteFlag
                                }
                            },

                            { height: 5 },
                            { id: "selectGroup" + $scope.Name, hidden: true, gravity: 99, rows: [
                                new mcService.ListButtonSet({
                                    type   : 'combo',
                                    actions: $scope.groupsActions,
                                    list   : "groupList" + $scope.Name,
                                    selectedItem: "Name",
                                    visibleBtns: {
                                        add: true,
                                        del: true,
                                        cls: false
                                    },
                                    regShowWindow: $scope.regShowWindow,
                                    _back: $scope.groupContainerBack
                                }),

                                { rows: [
                                    // { view : "list", id: "groupList" + $scope.Name, select: true, template: "#Name#"},
                                    { view : "list", id: "groupList" + $scope.Name, select: true, template: "#Name#"},

                                    { height: 10},

                                    { cols: [
                                        // { view: "button", value: mcLang(1729), click: $scope.gotoGroups}, // "1729":"Управление группами",
                                        {},
                                        { view: "button", value: mcLang(16),   click: $scope.showUsers} // "16" : "Пользователи",
                                    ]}
                                ]}
                            ]}, {}
                        ]},

                        // { view: "toolbar", cols: [
                        //     { view: "label",  label: mcLang(1897)}, // "1897":"Подключить пользователей",
                        //     { view: "button", value: mcLang(1898), css: "applyButton", click: $scope.userSync} // "1898":"Синхронизация",
                        // ]}
                    ]}
                ]}
            ]
        });

        $scope.acnPassword      = $$("acnPass");
        $scope.acnPwdWrap       = $$("acnPwdWrap");
        $scope.acnConfType      = $$("acnConfType");
        $scope.autoChannelsList = $$("autoChannelsList");
        $scope.autoChannelInfo  = $$("autoChannelInfo");
        $scope.groupList        = $$("groupList" + $scope.Name);
        $scope.groupContainer   = $$("selectGroup" + $scope.Name);
        $scope.autoChannelListWrapper = $$("autoChannelListWrapper");
        // $scope.acnConfName      = $$("acnName");

        $$("acnConfName").$view.onpaste = function() {
            setTimeout(function(){
                $scope.changeEx.call($$("acnConfName"));
            }, 10);
        };

        $$("acnConfTopic").$view.onpaste = function() {
            setTimeout(function(){
                $scope.changeEx.call($$("acnConfTopic"));
            }, 10);
        };
    } else {
        $scope.autoChannelsList.clearAll();
        $scope.autoChannelListWrapper.enable();
    }

    return _view;
}
function autoChannelsController($scope, $rootScope){
    "use strict";

    $scope.Name      = mcConst.dataModels.AutoChannels;
    $scope.actions   = {};
    $scope.groupsActions = {};
    $scope.data      = null;
    $scope.groupData = [];
    $scope.mcLEB     = new window.mcWidgets.ListEditButtons($rootScope);

    $scope.wdgUsersOfGroups = new window.mcWidgets.UsersOfGroups($rootScope);

    // cs_adm_update_auto_conf
    // Когда мы создаем конфу - приходит параметр enable=false, я проверяю его и устанавливаю true, чтобы
    // показать окно сохранения параметров, если нажимают "отмена" - валю из списка.
    
    // Когда происходит изменение списка подключаемых групп юзеров или юзеров - добавляю параметр Sync = true
    // чтобы опять показать окно сохранения параметров.

    // Кнопка синхронизации больше не нужна

        mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_update_auto_conf, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    }, $scope.Name);

    var _view = document.getElementById($scope.Name);
    var groupList = [];

    function getGroupList(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_user_groups,
            mcConst.SessionID,

            function( data ){
                groupList = data;

                $scope.groupContainerBack();

                $scope.autoChannelsList.select($scope.autoChannelsList.getFirstId());
            }
        ]);
    }

    function fillGroupList(data){
        for (var i = 0; i < data.length; i++){
            data[i].id = data[i].UID;
            // data[i].InviteGroups = data[i].JoinGroups;
        }

        $rootScope.mcStorage[$scope.Name] = [].concat(data);

        $scope.autoChannelsList.clearAll();
        $scope.autoChannelsList.parse(data);
        // $scope.autoChannelsList.sort('#Name#', 'asc', 'string');
        $scope.autoChannelsList.sort('#ConfName#', 'asc', 'string');
    }

    //=====================================================

    $scope.changedData.onClose = function(){
        $scope.selectChannel($scope.autoChannelsList.getSelectedId());

        this.clearChangedData();

        $scope.autoChannelListWrapper.enable();
    };

    $scope.changedData.onApply = function(){
        $scope.data = mcService.Marge($scope.data, $scope.changedData.data.Items);

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_update_auto_conf,
            mcConst.SessionID,

            $scope.data.UID,
            $scope.data.ConfName,
            $scope.data.ConfType,
            $scope.data.ConfTopic,    // тема конференции
            $scope.data.Pass,         // пароль на вход в конференцию
            mcService.convertIntToBool($scope.data.InviteAll),    // присоединять абсолютно всех пользователей в эту конференцию или нет
            // false, //mcService.convertIntToBool($scope.data.FlagLockExit),  // запретить выход из конференции

            function (){
                $scope.autoChannelListWrapper.enable();
                $scope.autoChannelsList.refresh();
            }
        ]);

        this.clearChangedData();
    };

    //===================================================

    $scope.changeInviteFlag = function(val){
        if (!$scope.skipChangeNow){
            var item = $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId());

            // $scope.data.ConnectAllFlag = val;
            $scope.data.InviteAll = val;

            // if (item && item.ConnectAllFlag) {
            if (item && item.InviteAll) {
            //     item.ConnectAllFlag = val;
                item.InviteAll = val;
            }

            $scope.connectGroupType(val);

            if (item.InviteAll == 1){
                $scope.data.JoinGroups = "";
                $scope.groupList.clearAll();
            }

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_update_auto_conf,
                mcConst.SessionID,

                $scope.data.UID,
                $scope.data.ConfName,
                $scope.data.ConfType,
                $scope.data.ConfTopic,    // тема конференции
                $scope.data.Pass,         // пароль на вход в конференцию
                mcService.convertIntToBool($scope.data.InviteAll),    // присоединять абсолютно всех пользователей в эту конференцию или нет
                // false //mcService.convertIntToBool($scope.data.FlagLockExit)  // запретить выход из конференции
            ]);
        }
    };

    $scope.actions.save = function(val){
        var _val = mcService.trim(val.getValue());
        var list = $scope.autoChannelsList.serialize();

        // if (_val != "" && mcService.findItemInArrayOfObj(list, _val, 'Name', true) === -1) {
        if (_val != "" && mcService.findItemInArrayOfObj(list, _val, 'ConfName', true) === -1) {

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_add_auto_conf,
                mcConst.SessionID,

                _val,  // "Name"      : "Test room",   // название конференции
                // deprecated 8.0
                // "",    // "Topic"     : "Bla-bla-bla", // тема конференции
                // "",    // "Password"  : "",        // пароль на вход в конференцию
                // true,  // "JoinAll"   : false,         // присоединять абсолютно всех пользователей в эту конференцию или нет
                // false, // "BlockExit" : false,         // запретить выход из конференции
                // true,  // "SyncLogs"  : true           // синхронизация переписки
                // false,

                function(data){
                    var info = mcService.Marge({
                        id            : 0,
                        UID           : 0,
                        ConfName      : _val,         // название канала
                        ConfType      : mcConst._CMD_.confType.STANDARD,
                        ConfTopic     : "",           // тема канала
                        dtCreated     : "",           // дата и время создания канала
                        Owner         : 0,            // UIN создателя канала
                        Pass          : "",           // пароль на вход в конференцию. Если пароля нет - то пустое поле
                        // FlagLockExit  : false,
                        // InviteAll     : true,         // автоматически подключать в конференцию всех пользователей
                        JoinGroups    : ""            // ID групп пользователей, которых следует подключать в данную автосоздаваемую конференцию
                    }, data);
                        
                    // добавить глазик для пароля, чтобы посмотреть пароль - нужно на него нажать

                    info.id = data.UID;

                    $scope.autoChannelsList.add(info);
                    $scope.autoChannelsList.select($scope.autoChannelsList.getLastId());
                    $scope.autoChannelsList.scrollTo(0, 9999);

                    $scope.selectChannel(info.id);
                }
            ]);
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return true;
        }
    };

    $scope.actions.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_del_auto_conf,
            mcConst.SessionID,

            item.UID,

            function(){
                $scope.autoChannelsList.remove($scope.autoChannelsList.getSelectedId());

                var lastID = $scope.autoChannelsList.getLastId();

                if (lastID) {
                    $scope.autoChannelsList.select(lastID);
                    $scope.selectChannel(lastID);
                } else {
                    $scope.autoChannelInfo.hide();
                }
            }
        ]);
    };

    //===================================================

    var _back = null; // fucking shit hack

    $scope.groupContainerBack = function(cb){
        if (cb) {
            _back = cb;
        } else {
            if (_back) _back();
        }
    };

    $scope.groupsActions.preview = function(field){
        var list = mcService.transformDataObject(webix.copy(groupList), [['Name', 'value'], ['ID', 'id']]);
        // var list = mcService.transformDataObject(webix.copy(groupList), [['ConfName', 'value'], ['ID', 'id']]);

        field.define('options', list);
        field.refresh();
        list[0] && field.setValue(list[0].id);
    };

    $scope.groupsActions.save = function(val){
        var id = val.getValue();

        if (id != '' && !$scope.groupList.getItem(id)) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_group_to_auto_conf,
                mcConst.SessionID,
                $scope.autoChannelsList.getSelectedId(), // UID
                id,

                function(){
                    $scope.groupList.add({
                        ID  : id,
                        id  : id.toString(),
                        Name: val.getText()
                        // ConfName: val.getText()
                    });

                    var item = $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId());

                    if (mcService.isString(item.JoinGroups)) {
                        item = item.JoinGroups.split(',');

                        $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId()).JoinGroups = item;
                    }

                    item.JoinGroups.push(id);
                }
            ]);

            return true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return false;
        }
    };

    $scope.groupsActions.del = function(_item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_del_group_from_auto_conf,
            mcConst.SessionID,
            $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId()).UID,
            _item.ID
        ]);

        var item = $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId());

        if (mcService.isString(item.JoinGroups)) {
            item = item.JoinGroups.split(',');

            $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId()).JoinGroups = item;
        }

        var id = mcService.inArrayNoStrict(_item.ID, item.JoinGroups);

        if (id !== -1) {
            item.JoinGroups[id] = '';
        }
    };

    //===================================================

    $scope.userSync = function () {
        var item = $scope.autoChannelsList.getSelectedItem();

        if (item && item.UID){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_reconnect_users2autoconf,
                mcConst.SessionID,

                item.UID,

                function () {
                    webix.message(mcLang(1899)); // "1899":"Пользователи подключены!",
                }
            ]);
        }
    };

    $scope.showUsers = function () {
        var conf = $scope.autoChannelsList.getSelectedItem();

        $scope.wdgUsersOfGroups.init($scope.groupList.serialize(), conf.JoinUsers || "");
        $scope.wdgUsersOfGroups.initTextSource({
            cancel: mcLang(12), // "12" : "Закрыть",
            // title : mcLang(1757, $scope.data.Name) // "1757":"Пользователи конференции %s",
            title : mcLang(1757, $scope.data.ConfName) // "1757":"Пользователи конференции %s",
        });
        $scope.wdgUsersOfGroups.show();
    };

    $scope.gotoGroups = function(){
        $rootScope.$broadcast('setLocation', ['/navUsers/' + mcConst.dataModels.UserGroups + '/']);
        $rootScope.$broadcast('changeLocation', []);
    };

    $scope.selectChannel = function( id ){
        var item = $scope.autoChannelsList.getItem(id);

        $scope.groupList.clearAll();

        if (item){
            $scope.data = item;
            $scope.skipChangeNow = true;

            for (var i in item){
                var elem = $$("acn" + i);

                if (elem){
                    var val = mcService.isBoolean(item[i]) ? mcService.convertBool(item[i]) : item[i];

                    //elem.setValue(val);

                    switch (i){
                        // case "Name":
                        // case "ConfName":
                            // $scope.acnConfName.define("template", '"' + val + '"');
                            // $scope.acnConfName.refresh();
                            // $scope.acnConfName.setValue(val);
                        // break;

                        // case "ConnectAllFlag": $scope.connectGroupType(val);
                        case "JoinGroups":
                            $scope.connectGroupType(val.length && val[0] === "0");

                            elem.setValue(val.length && val[0] === "0" ? "1" : "0");
                        break;

                        default: elem.setValue(val);
                    }
                }
            }

            $scope.autoChannelInfo.show();

            if (mcService.isString(item.JoinGroups)){
                item.JoinGroups = item.JoinGroups.split(',');
            }

            var res = [];

            for (var i = 0; i < item.JoinGroups.length; i++)
                if (item.JoinGroups[i].length !== 0){
                    var newItem = groupList[mcService.findItemInArrayOfObj(groupList, item.JoinGroups[i], 'ID')];

                    if (newItem) {
                        newItem.id = item.JoinGroups[i];
                        res.push(newItem);
                    }
                }

            $scope.groupList.parse(res);

            $scope.skipChangeNow = false;

            $scope.groupContainerBack();
        }
    };

    $scope.connectGroupType = function(newV){
        if (newV == 1){ // all
            $scope.groupContainer.hide();
        } else {
            $scope.groupContainer.show();
        }
    };

    $scope.changeEx = function(){
        if (!$scope.skipChangeNow) {
            $scope.autoChannelListWrapper.disable();
        }

        $scope.change.apply(this, arguments);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_auto_conf_list,
            mcConst.SessionID,
            
            function( data ){
                $scope.groupData = data;
                $scope.InviteAll = data.JoinGroups === "0";

                fillGroupList($scope.groupData);
                getGroupList();
            }
        ]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, _view);

        var settings = initAutoChannels($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    //===================================================

    $scope.$on('hide' + $scope.Name, function(){
        $scope.autoChannelInfo.hide();

        mcService.hideView(_view);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.data = null;

        $scope.getData();

        $scope.show();
    });
}
function initActiveChannels($scope){
    "use strict";

    var view = $$($scope.Name);
    var prefix = "actChnls";

    if (!view){
        $scope.filterField = mcService.FilterFiled({
            listName     : prefix + $scope.Name,
            filterParams : [
                "UIN",
                "Name",
                "CreatorDisplayName",
                "Topic"
            ],
            onClear: $scope.restoreState,
            onAfterFilter: $scope.restoreState
        });

        view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", id: prefix + "Count", type : "header", template : mcService.Lang(1623), width: 250 }, // "1623":"Активные конференции",
                    { view: "toolbar", height: 36, cols: [
                        { view: "button", value: mcLang(1624), width: 200, click: $scope.dropChannel},   // "1624":"Удалить конференцию",

                        $scope.filterField,

                        { id: "refreshTimer" + $scope.Name, template: '10', borderless: true, width: 30, type: "header", css: "lh20, noBG white"},
                        { view: "button", icon: "refresh", type: "icon", width: 30, click: $scope.refreshChannels}      // "53" : "Обновить",
                    ]},
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { id: prefix + $scope.Name,
                    view        : "datatable",
                    resizeColumn: true,
                    select      : "row",
                    multiselect : true,
                    minColumnWidth : 80,
                    leftSplit   : 2,
                    columns: [
                        { width: 40,  header: "", css:"left_area", sort: "string", template: function (obj) {
                            return "<span class='byCenter'>" +
                                (obj.ConfType === mcConst._CMD_.confType.HIDDEN
                                    ? mcService.insertIco("fa-eye", "", "title='" + mcLang(1847) + "'")                          // "1847":"Скрытая конференция",
                                    : (obj.ConfType === mcConst._CMD_.confType.PASSWORD ? mcService.insertIco("fa-lock", "", "title='" + mcLang(2092) + "'") : "")) + // "2092":"Защищенная паролем",
                                "</span>";
                        }},
                        {id:"UID",           width: 70,  header: mcLang(1625), css:"left_area", sort: "int"},     //"1625":"UID",
                        {id:"Name",          width: 190, header: mcLang(1042), css:"left_area", sort: "string", template: function (obj) { //"1042":"Название конференции",
                            return  obj.Password === "" ? obj.Name : "<span class='red'>" + obj.Name + "</span>";
                        }},
                        {id:"Topic",         width: 200, header: mcLang(1043), css:"grid_area", sort: "string"},  //"1043":"Тема конференции",
                        //{id:"CreatorUIN",    width: 120, header: mcLang(1626), css:"grid_area", sort: "int"},   //"1626":"UIN создателя",
                        {id:"CreatorDisplayName", width: 200, header: mcLang(1627), css:"grid_area", sort: "string", template: function(obj){
                            return obj.CreatorDisplayName + " (UIN " + obj.CreatorUIN + ")";
                        }}, //"1627":"Имя создателя",
                        {id:"CountUsers",    width: 120, header: mcLang(1628),css:"grid_area", sort: "int"},      //"1628":"Кличество пользователей",
                        {id:"CountMessages", width: 110, header: mcLang(1629),css:"grid_area", sort: "int"},      //"1629":"Количество сообщений",
                        {id:"dtUTCCreated",  width: 140, header: mcLang(1599),css:"grid_area", sort: "string", template: function(obj){
                            return mcService.utcTime(obj.dtUTCCreated, false, 'yyyy.mm.dd hh:nn:ss');
                        }},//"1599":"Дата создания",
                        // {id:"ConnectAllFlag", adjust:"header", header: mcLang(1631), css:"grid_area", sort: "string", template: function(obj){
                        {id:"InviteAll", adjust:"header", header: mcLang(1631), css:"grid_area", sort: "string", template: function(obj){
                            return obj.CreatorUIN != '0' ? mcLang(1637) : obj.ConnectAllFlag ? mcLang(1632) : mcLang(1633); // "1632":"Всех пользователей", "1633":"По группам", "1637":"Свободный вход",
                        }}, //"1631":"Тип подключения",
                        // {id:"BlockCloseFlag", adjust:"header", header: mcLang(1634) + "  &nbsp;", css:"grid_area", sort: "string", template: function(obj){
                        //     return obj.CreatorUIN === 0 ? mcLang(113) : mcLang(114); // "114": "да", "113": "нет",
                        // }}, //"1634":"Можно выходить?",
                        // {id:"SyncLogsFlag",  adjust:"header", header: mcLang(1630), css:"grid_area", sort: "string", template: function(obj){ -- removed
                        //     return obj.SyncLogsFlag ? mcLang(114) : mcLang(113); // "114": "да", "113": "нет",
                        // }} //"1630":"Синхронизация сообщений",
                    ],
                    on: {
                        onItemClick: $scope.selectChannel
                    }
                },
                { id: "resizer" + $scope.Name, view: "resizer", hidden: true},
                { id: "userListWrp" + $scope.Name, hidden: true, cols: [
                    { type: "layout", rows: [
                        mcService.FilterFiled({
                            listName     : "userList" + $scope.Name,
                            filterParams : [
                                "UIN",
                                "DisplayName"
                            ]
                        }),
                        { id: "userList" + $scope.Name,
                            view        : "datatable",
                            resizeColumn: true,
                            select      : "row",
                            minColumnWidth : 80,
                            multiselect: true,
                            columns: [
                                {id:"UIN",         width: 70,  header: mcLang(135),  css:"grid_area", sort: "int"},    //"135": "UIN",
                                {id:"DisplayName", width: 190, header: mcLang(1545), css:"grid_area", sort: "string", fillspace:true, template: function (obj) {
                                    return !obj.CanKick ? mcService.insertIco("fa-lock", "gray", {title: mcLang(2262)}) + obj.DisplayName : obj.DisplayName // "2262":"Нельзя выгнать пользователя",
                                }},//"1545":"Имя пользователя",
                                {id:"State",       width: 120, header: mcLang(1513), css:"grid_area", sort: "string", template: function(obj){ // "1513":"Состояние",
                                    return mcService.getUserStateText(obj.State, true);
                                }}
                            ],
                            on: {
                                onItemClick: $scope.selectUser
                            }
                        }
                    ]},
                    { view: "resizer", borderless: true},
                    { type: "layout", padding: 4, rows: [
                        { id: prefix + "CreatorName", template: "&nbsp;", borderless: true, autoheight: true},

                        { cols: [
                            { width: 270, rows: [
                                { id: "btnChangeOwner" + $scope.Name,         view: "button", value: mcLang(2268), disabled: true, click: $scope.changeOwner}, // "2268":"Сменить владельца",
                                { id: "btnDisconnectUser" + $scope.Name,      view: "button", value: mcLang(1638), disabled: true, click: $scope.disconnect, type: "danger"}, // "1638":"Выгнать из конфреренции",
                                { id: "btnDisplayConfPassword" + $scope.Name, view: "button", value: mcLang(1639), click: $scope.viewPass} // "1639":"Посмотреть пароль",
                            ]},
                            {}
                        ]},
                        {}
                    ]}
                ]}
            ]
        });

        $scope.btnChangeOwner = $$("btnChangeOwner" + $scope.Name);
        $scope.CreatorName    = $$(prefix + "CreatorName");
        $scope.activeChannels = $$(prefix + $scope.Name);
        $scope.refreshTimer   = $$("refreshTimer" + $scope.Name);
        $scope.counter        = $$(prefix + "Count");

        $scope.resizer        = $$("resizer" + $scope.Name);
        $scope.userListWrp    = $$("userListWrp" + $scope.Name);
        $scope.userList       = $$("userList" + $scope.Name);
        
        $scope.btnDisplayConfPassword = $$("btnDisplayConfPassword" + $scope.Name);
        $scope.btnDisconnectUser      = $$("btnDisconnectUser" + $scope.Name);

        mcService.disableContextMenu(view);
    } else {

    }

    return view;
}
function activeChannelsController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.ActiveChannels;
    $scope.data = {};

    var angElement = document.getElementById($scope.Name);
    var view = null;
    var timerCounter = null;
    var refreshTime = 10;
    var time = refreshTime;
    var state = null;
    var filterState = null;
    var stateUsr = null;
    var wndChgQwn = null;

    function showTimerTime(time){
        $scope.refreshTimer.define('template', time.toString());
        $scope.refreshTimer.refresh();
    }

    function setCount(cnt){
        $scope.counter.define('template', mcLang(1623) + " [" + cnt + "]"); // "1623":"Активные конференции",
        $scope.counter.refresh();
    }

    // =============================================

    function closeWndOwn() {
        wndChgQwn && wndChgQwn.close();
        wndChgQwn = null;

        $rootScope.hotKeyDispatcher.removePreset("__change_owner__");
    }

    $scope.changeOwner = function () {
        var _wndName = "__changeOwner";

        if ($$(_wndName)) {
            $$(_wndName).destructor();
        }
                
        wndChgQwn = webix.ui({
            view     : "window",
            position : "center",
            width    : 400,
            id       : _wndName,
            head     : {
                cols: [
                    { width: 42 },
                    { view: "label", label: '<div class="byCenter toUpper">' + mcLang(2269) + '</div>' }, // "2269":"Выберите нового владельца",
                    { view: "button", type: 'icon', width: 28, icon: 'times', css: "button_transparent", click: closeWndOwn }
                ]
            },
            modal    : true,
            body     : { cols: [
                { view: "combo", id: "_listNewOwners", value: -1, options: [
                    { id: -1, value: mcLang(1658) } // "1658":"-- ничего не выбрано --"
                ]},
                { view: "button", width: 50, value: mcLang(13), click: function (){ // "13" : "Ок",
                    var uin = $$("_listNewOwners").getValue();
                    var uid = $scope.activeChannels.getSelectedItem().UID;

                    if (uin > 0) {
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.cs_adm_change_text_conf_owner,
                            mcConst.SessionID,

                            uid,
                            uin,

                            function(){
                                var user = $$("_listNewOwners").getList().getSelectedItem();

                                closeWndOwn();

                                $scope.CreatorName.define("template", mcLang(2261, user.value + " (UIN " + user.id + ")"));  //"2261":"Создатель конференции: %s",
                                $scope.CreatorName.refresh();
                            }
                        ]);
                    } else
                    if (uin === 0) {
                        webix.alert(mcLang(2270)); // "2270":"Нельзя заменить встроенного робота",
                    } else {
                        closeWndOwn();
                    }
                }}
            ]},
            on : {
                onShow: function (){
                    var _list = $$("_listNewOwners").getList();
                    _list.define("template", function (obj) {
                        return obj.value + " (UIN:" + obj.id + ")";
                    });

                    $rootScope.$broadcast('getAllUserList', [false,  function(data){
                        data.Users.forEach(function (item) {
                            item.value = item.DisplayName;
                            item.id    = item.UIN;
                        });

                        _list.clearAll();
                        _list.parse(data.Users || []);
                        _list.sort("id", "asc", "int");

                    }, {
                        Params : 'NOTWEBSUPPORT,ENABLED',
                        Filters: 'UIN,DISPLAYNAME'
                    }]);
                }
            }
        });

        wndChgQwn.show();

        $rootScope.hotKeyDispatcher.addPreset("__change_owner__", [{
            key: mcConst.keyCodes.esc,
            func: closeWndOwn
        }, {
            key: mcConst.keyCodes.enter,
            func: function () {

            }
        }], document, true);

        $$("_listNewOwners").focus();
    };

    $scope.showUserList = function(){
        $scope.resizer.show();
        $scope.userListWrp.show();

        var conf = $scope.activeChannels.getSelectedItem();

        $scope.CreatorName.define("template", mcLang(2261, conf.CreatorDisplayName + " (UIN " + conf.CreatorUIN + ")"));  //"2261":"Создатель конференции: %s",
        $scope.CreatorName.refresh();

        if (conf.Password == ""){
            $scope.btnDisplayConfPassword.hide();
        } else {
            $scope.btnDisplayConfPassword.show();
        }

        if (conf.CreatorUIN != 0){
            $scope.btnChangeOwner.enable();
        } else {
            $scope.btnChangeOwner.disable();
        }
    };

    $scope.hideUserList = function(){
        $scope.resizer.hide();
        $scope.userListWrp.hide();
    };

    $scope.dropChannel = function(){
        var item = $scope.activeChannels.getSelectedItem();

        if (item.length && item.length > 1){
            var cantDel = false;

            item.forEach(function (conf){
                if (conf.CreatorUIN == 0){
                    cantDel = true;
                }
            });

            if (cantDel){
                $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(2259), "nohelp"]); // "2259":"Нельзя удалить конференцию у которой создатель встроенный робот с UIN:0. Уберите виделение с таких конференций, чтобы удалить другие",
            } else {
                $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                    type  : "confirm-warning",
                    text  : mcService.Lang(2260), //"2260":"Ви хтите удалить виделенные конференции?",
                    ok    : mcService.Lang(114), // "114": "да",
                    cancel: mcService.Lang(113), // "113": "нет",
                    callback:function(yes){
                        if (yes) {
                            item.forEach(function (conf) {
                                $rootScope.$broadcast('SendCMDToServer', [
                                    mcConst.lockInterface,
                                    mcConst._CMD_.cs_adm_kill_txt_conf,
                                    mcConst.SessionID,
                                    conf.UID,
                                    
                                    function(){
                                        $scope.refreshChannels();
                                    }
                                ]);
                            });
                        }
                    }
                }));
            }
        } else
        if (item && item.CreatorUIN != 0){
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(1635, item.Name), //"1635":"Удалить конференцию?<br><b>\"%s\"</b>",
                ok    : mcService.Lang(114), // "114": "да",
                cancel: mcService.Lang(113), // "113": "нет",
                callback:function(yes){
                    if (yes) {
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_kill_txt_conf,
                            mcConst.SessionID,
                            item.UID,
                            function(){
                                $scope.hideUserList();

                                $scope.refreshChannels();
                            }
                        ]);
                    }
                }
            }));
        } else {
            $scope.regShowWindow(mcService.RandomHash(4), webix.alert(mcLang(1636))); // "1636":"Эту конференцию можно удалить только в разделе <a href='/admin/#/navConference/AutoChannels/'>Автосоздаваемые конференции</a>",
        }
    };

    $scope.refreshChannels = function(){
        stateUsr = $scope.userList.getState();

        time = refreshTime;

        showTimerTime(time);
        
        $scope.getData();
    };

    $scope.viewPass = function(){
        var pass = $scope.activeChannels.getSelectedItem().Password;

        $scope.regShowWindow(mcService.RandomHash(4), webix.alert(pass || mcLang(1640))); //"1640":"Нет пароля",
    };

    $scope.disconnect = function (){
        var users = $scope.userList.getSelectedItem();

         if (users){
             var list = [];

             if (!mcService.isArray(users)) {
                 users = [users];
             }

             for (var i = 0; i < users.length; i++){
                 if (users[i].UIN != 0) {
                     list.push(users[i].UIN);
                 }
             }

             if (list.length){
                 $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                     type  : "confirm-warning",
                     text  : mcService.Lang(1645, $scope.activeChannels.getSelectedItem().Name),// "1645":"Выгнать отмеченных пользователей из конференции?<br>%s",
                     ok    : mcService.Lang(114), // "114": "да",
                     cancel: mcService.Lang(113), // "113": "нет",
                     callback:function(yes){
                         if (yes) {
                             $rootScope.$broadcast('SendCMDToServer', [
                                 mcConst.lockInterface,
                                 mcConst._CMD_.cs_adm_kick_users_from_conf,
                                 mcConst.SessionID,
                                 $scope.activeChannels.getSelectedItem().UID,
                                 list.join(','),
                                 function(){
                                     $scope.btnDisconnectUser.disable();

                                     setTimeout($scope.refreshChannels, 500);

                                     $scope.resizer    .hide();
                                     $scope.userListWrp.hide();
                                 }
                             ]);
                         }
                     }
                 }));
             }
         }
    };

    $scope.selectChannel = function(uid){
        var isMulti = $scope.activeChannels.getSelectedItem().length;

        if (isMulti && isMulti > 1) {
            $scope.hideUserList();
        } else {
            $scope.showUserList()

            $scope.activeChannels.showItem(uid);

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_users_in_conf,
                mcConst.SessionID,
                uid,
                function(data){
                    $scope.btnDisconnectUser.disable();

                    for (var i = 0; i < data.length; i++){
                        data[i].id = data[i].UIN;
                    }

                    $scope.userList.clearAll();
                    $scope.userList.parse(data);

                    if (stateUsr && stateUsr.select && stateUsr.select.length) {
                        $scope.userList.setState(stateUsr);
                    }
                }
            ]);
        }
    };

    $scope.selectUser = function (uin) {
        var user = $scope.userList.getItem(uin);

        if (user.CanKick) {
            $scope.btnDisconnectUser.enable();
        } else {
            $scope.btnDisconnectUser.disable();
        }
    };

    // =============================================

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_active_conf_list,
            mcConst.SessionID,
            function( data ){
                $scope.data = data;

                for (var i = 0; i < $scope.data.length; i++){
                    $scope.data[i].id = $scope.data[i].UID;
                }

                state = $scope.activeChannels.getState();
                
                $scope.activeChannels.clearAll();
                $scope.activeChannels.parse($scope.data);
                $scope.activeChannels.sort(function (a, b) {
                    return mcService.sortAB(a.UID, b.UID);
                });

                $scope.filterField.doFilter(true, true);

                setCount($scope.data.length);
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.restoreState = function(){
        if (state){
            $scope.activeChannels.setState(state);
        }
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        view = initActiveChannels($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();
    };

    $scope.$on('hide' + $scope.Name, function() {
        mcService.hideView(angElement);

        clearInterval(timerCounter);
        timerCounter = null;
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.show();

        time = refreshTime;

        showTimerTime(time);

        timerCounter = setInterval(function(){
            time --;

            if (time === 0) {
                $scope.refreshChannels();

                time = refreshTime;
            }

            showTimerTime(time);
        }, 1000);

        $scope.getData();
    });

}
function initOperators($scope){
    "use strict";

    var _view = $$($scope.Name);

    if (!_view){
        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type: "header", template: mcService.Lang(817)},// "817":"Модераторы",
                    { cols: [
                        { view: "template", type: "header", template: mcService.Lang(31)},  // "31" : "Конференции",
                        { view: "toolbar", width: 36, cols: [
                            {view: "button", type: "icon", icon: "question", click: function () {
                                mcService.goToHelp();
                            }, width: 30}
                        ]}
                    ]}
                ]},
                { cols: [
                    { type: 'layout', rows: [
                        new mcService.ListButtonSet({
                            type   : 'combo',
                            actions: $scope.operatorsActions,
                            list   : "modUserList",
                            selectedItem : "DisplayName",
                            regShowWindow: $scope.regShowWindow
                        }),

                        new mcService.FilterFiled({
                            listName: "modUserList",
                            filterParams: ['DisplayName', 'UIN']
                        }),

                        { view: "list", id: "modUserList", select: "multiselect",
                            template: function (obj) {
                                return obj.DisplayName + (obj.UIN != -1 ? " <span style='float:right'>(UIN: " + obj.UIN + ")</span>" : "");
                            },
                            on: { onSelectChange: $scope.selectUsers }
                        }
                    ]},
                    { view:"resizer" },
                    { type: 'layout', rows: [
                        new mcService.ListButtonSet({
                            type   : 'combo',
                            actions: $scope.conferenceActions,
                            list   : "modConfsList",
                            selectedItem : "value",
                            regShowWindow: $scope.regShowWindow
                        }),
                        { view: "list", select: "multiselect", id: "modConfsList",
                            template: function (obj) {
                                return obj.id === -1
                                    ? "<span style='text-align: center; font-weight: bold; width: 100%; display: inline-block;'>" + obj.value + "</span>"
                                    : obj.value + " <span style='float:right'>(UID: " + obj.id + ")</span>"
                            },
                            disabled: true
                        }
                    ]}
                ]},

                { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1028), autoheight: true, borderless: true, css: "_info sizeBigger"} // "1028":"<b>Описание</b>: для того, чтобы модераторы могли выполнят
            ]
        });

        mcService.disableContextMenu(_view);

        $scope.modUserList  = $$("modUserList");
        $scope.modConfsList = $$("modConfsList");
    } else {
        $scope.modUserList.clearAll();
        $scope.modUserList.define('data', $scope.moderators);
        $scope.modUserList.sort("DisplayName", "asc");
        $scope.modUserList.refresh();
        $scope.modUserList.select($scope.modUserList.getFirstId());
    }

    return _view;
}


function operatorsController($scope, $rootScope){
    "use strict";

    $scope.Name         = mcConst.dataModels.Operators;
    $scope.selectedItem = [];
    $scope.showDialog   = null;
    $scope.modUserList  = null;
    $scope.modConfsList = null;
    $scope.operatorsActions  = {};
    $scope.conferenceActions = {};
    $scope.userListData = [];
    $scope.channelListData = [];
    $scope.moderators   = [];

    var angElement = document.getElementById($scope.Name);
    var currentOperatorChList = [];

    $scope.operatorsActions.save = function(field){
        var uin = mcService.trim(field.getValue());
        var nik = mcService.trim(field.getText());

        if (nik === '') {
            return false;
        } else
        if (!$scope.modUserList.getItem(uin)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_moderator,
                mcConst.SessionID,
                uin
            ]);

            $scope.modUserList.add({
                id: uin,
                UIN: uin,
                ConfList: '',
                DisplayName: nik
            });

            $scope.modUserList.select(uin);

            $scope.modUserList.sort("#DisplayName#", "asc");

            return true;
        } else {
            webix.message(mcService.Lang(1511)); // "1511":"Такой пользователь уже есть",
        }
    };

    $scope.operatorsActions.del = function(selectedItem){
        var uins = [];

        if (mcService.isArray(selectedItem)){
            for (var i = 0; i < selectedItem.length; i++){
                uins.push(selectedItem[i].UIN);
            }
        } else {
            uins = [selectedItem.UIN];
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_delete_moderators,
            mcConst.SessionID,
            uins.join(',')
        ]);

        $scope.selectedItem = [];
        $scope.modUserList.select($scope.modUserList.getFirstId());
    };

    $scope.operatorsActions.clear = function(){
        var uins = $scope.modUserList.serialize();

        for (var i = 0; i < uins.length; i++){
            uins[i] = uins[i].UIN;
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_delete_moderators,
            mcConst.SessionID,
            uins.join(',')
        ]);

        $scope.selectedItem = [];
        $scope.moderators = [];

        return true;
    };

    $scope.operatorsActions.preview = function(field){
        mcService.getAllUserForFillList($scope.userListData, function fill_uList (data){
            $scope.userListData = mcService.transformDataObject(webix.copy(data), [['DisplayName', 'value'], ['UIN', 'id']]);

            $scope.userListData.forEach(function (t, i) {
                t.value = t.value + "<span style='float:right'>(UIN: " + data[i].UIN + ")</span>"
            });

            field.define('options', $scope.userListData);
            field.refresh();
            field.focus();
        }, $rootScope);
    };

    $scope.conferenceActions.save = function(field){
        var uid = mcService.trim(field.getValue());
        var name= mcService.trim(field.getText());
        var user = $scope.modUserList.getSelectedItem();

        if (mcService.isArray(user)){
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1508)]); // "1508":"Нельзя добавить конференцию сразу нескольким пользователям",
        } else
        if (name === '') {
            return false;
        } else
        if (!$scope.modConfsList.getItem(uid)){
            // if ($scope.modConfsList.getItem(-1)) {
            //     $scope.modConfsList.remove(-1);
            //     $scope.modConfsList.enable();
            // }

            name = mcService.copy(name, 0, name.length - (name.length - name.indexOf('(UID:')));

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_add_moderator,
                mcConst.SessionID,
                user.UIN,
                uid
            ]);

            $scope.modConfsList.add({
                id   : uid,
                value: name
            });

            user.ConfList += ((user.ConfList == "") ? "" : ",") + uid;

            $scope.modConfsList.sort("#value#", "asc");

            return true;
        } else {
            webix.message(mcService.Lang(1510)); // "1510":"Такая конференция уже есть",
        }
    };

    $scope.conferenceActions.del = function(item){
        var selectedUsers = $scope.modUserList.getSelectedId();
        var uids = [];
        var UIN  = null;
        var newUIDS = "";
        var user = null;

        if (mcService.isString(selectedUsers) || mcService.isNumber(selectedUsers)) {
            user = $scope.modUserList.getItem(selectedUsers);

            UIN = user.UIN;
        }

        if (mcService.isArray(item)){
            for (var i = 0; i < item.length; i++){
                uids.push(item[i].id);
            }
        } else {
            uids = [item.id];
        }

        if (UIN){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_del_moderator_confs,
                mcConst.SessionID,

                UIN,
                uids.join(','),
                
                function(){
                    newUIDS = user.ConfList.split(',');

                    if (uids.length === user.ConfList.split(',').length){
                        $scope.modUserList.remove(user.id);
                        $scope.modUserList.select($scope.modUserList.getFirstId());
                    } else {
                        while (uids.length > 0){
                            mcService.delArrayItem(newUIDS, newUIDS.indexOf(uids.shift()), 1);
                        }

                        user.ConfList = newUIDS.join(',');
                    }
                }
            ]);
        }
    };

    $scope.conferenceActions.clear = function(){
        var selectedUsers = $scope.modUserList.getSelectedId();
        var UIN  = null;
        var user = null;

        if (mcService.isString(selectedUsers) || mcService.isNumber(selectedUsers)) {
            user = $scope.modUserList.getItem(selectedUsers);

            UIN = user.UIN;
        }

        if (currentOperatorChList.length > 0){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_del_moderator_confs,
                mcConst.SessionID,
                UIN,
                user.ConfList,
                function(){
                    $scope.modUserList.getItem(selectedUsers).ConfList = '';
                }
            ]);

            return true;
        } else {
            webix.message(mcService.Lang(1509)); // "1509":"Список пустой",

            return false;
        }
    };

    $scope.conferenceActions.preview = function(field){
        if (!field.getPopup().getBody().serialize().length){
            field.define('options', $scope.channelListData);
            field.refresh();
        }

        field.focus();
    };

    $scope.selectUsers = function (){
        var selectedItem = $scope.modUserList.getSelectedId();

        $scope.modConfsList.clearAll();
        // $scope.modConfsList.disable();

        if (mcService.isString(selectedItem) || mcService.isNumber(selectedItem)) {
            var item = $scope.modUserList.getItem(selectedItem);

            if (item && item.ConfList && item.ConfList != '') {
                currentOperatorChList = [];

                if (item.ConfList.indexOf('-1') >= 0){
                    currentOperatorChList.push({id: -1, value: mcService.Lang(1507)});
                }

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_conf_names_by_uid_list,
                    mcConst.SessionID,
                    item.ConfList,
                    
                    function ( data ){
                        for (var i in data){
                            currentOperatorChList.push({id: i, value: data[i]});
                        }

                        $scope.modConfsList.define('data', currentOperatorChList);
                        $scope.modConfsList.sort("value", "asc");
                        $scope.modConfsList.enable();
                    }
                ]);
            } else {
                $scope.modConfsList.define('data', [{id: -1, value: mcService.Lang(1507)}]); // "1507":"Все конференции",
            }

            $scope.modConfsList.refresh();
        }
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_all_text_confs,
            mcConst.SessionID,
            function(data){
                $scope.channelListData = [{id: -1, value: mcService.Lang(1507)}];

                for (var i in data){
                    $scope.channelListData.push({id: i, value: "<span style='word-break: break-all' title='" + data[i].Name + " UID:" + i + "'>" + data[i].Name + " <span style='float:right'>(UID: <b>" + i + "</b>)</span></span>"});
                }
            }
        ]);

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_moderators,
            mcConst.SessionID,
            function ( data ){
                $scope.moderators = data;

                for (var i = 0; i < $scope.moderators.length; i++){
                    $scope.moderators[i].id = $scope.moderators[i].UIN;
                }

                $scope.show();
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initOperators($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $scope.moderators = [];
        $scope.show.apply(null, args);
        $scope.getData();
    });
}

function initGroupRights($scope){
    "use strict";

    var thisView = $$($scope.Name);
    var lng      = mcLang;

    if (!thisView){
        var groupList = $scope.data || [{
            Name: "Web-guests", ID : '0', Rights :''
        }];

        var rightsList = [{
            value: lng(853), data : [          //"853":"Integration API",
                {id: "grID73",  value: lng(854)},//"854":"Разрешить отправку сообщений от имени этих пользователей",
                {id: "grID244", value: lng(2219)},//"2219":"Разрешить удалённое выполнение скриптов",
            ]}, {

            value: lng(775), data : [
                {id: "grID36", value: lng(776)},//"776":"Блокирование учетных записей пользователей",
                {id: "grID15", value: lng(777)},//"777":"Блокировка IP адреса пользователя",
                {id: "grID16", value: lng(778)},//"778":"Блокировка MAC адреса",
                {id: "grID32", value: lng(779)},//"779":"Завершение работы MyChat Client-а пользователя",
                {id: "grID14", value: lng(780)},//"780":"Отключение пользователя от сервера",
                {id: "grID33", value: lng(781)},//"781":"Переименование текстовых каналов",
                {id: "grID121",value: lng(1587)},//"1587":"Просмотр отчетов по контролю рабочего времени",
                {id: "grID34", value: lng(782)},//"782":"Удаление текстовых каналов",
                {id: "grID20", value: lng(783)},//"783":"Удаленное администрирование сервера через консоль MyChat Client",
                {id: "grID58", value: lng(774)}, //"774":"Управление сервером",
                {id: "grID241", value: lng(2208)}, //"2208":"Увольнение пользователей",
                // {id: "grID35", value: lng(843)} //"843":"Принудительное подключение пользователей в каналы",
            ]}, {

            value: lng(1581), data : [ //"1581":"Доступ к функциям управления сервером",
                { value: lng(944), data : [ //"944":"MyChat Server",
                    {id: "grID88", value: mcLang(10)},   // "10" : "Информация о сервере",
                    {id: "grID89", value: mcLang(1564)}, // "1564":"Онлайн пользователи",
                    {id: "grID138", value: mcLang(1725)},// "1725":"Дополнительные услуги",
                    {id: "grID137", value: mcLang(1730)} // "1730":"Форум поддержки",
                ]},
                { value: lng(16), data : [ //"16" : "Пользователи",
                    { value: lng(49), data : [ // "49" : "Список пользователей",
                        {id: "grID90", value: mcLang(1610)}, // "1610":"Доступ у списку пользователей",
                        {id: "grID126", value: mcLang(50)}, // "50" : "Добавить",
                        { value: lng(51), data : [ // "51" : "Изменить",
                            {id: "grID127", value: mcLang(1611)},// "1611":"Доступ к профилю пользователя",
                            {id: "grID123", value: mcLang(1612)},// "1612":"Изменение группы прав",
                            {id: "grID124", value: mcLang(126)}, // "126": "Тип авторизации",
                            {id: "grID125", value: mcLang(125)} // "125": "Изменение пароля пользователя",
                        ]},
                        {id: "grID128", value: mcLang(52)}, // "52" : "Удалить",
                        {id: "grID129", value: mcLang(55)}, // "55" : "Экспорт",
                        {id: "grID130", value: mcLang(1110)}// "1110":"Массовое изменение",
                    ]},

                    {id: "grID91", value: mcLang(587)}, // "587": "Общий список контактов",
                    {id: "grID92", value: mcLang(588)}, // "588": "Должности компании",
                    {id: "grID93", value: mcLang(960)}, // "960":"Импорт пользователей",
                    {id: "grID94", value: mcLang(817)}, // "817":"Модераторы",
                    {id: "grID95", value: mcLang(1029)},// "1029":"Забаненные пользователи",
                    {id: "grID139",value: mcLang(1722)}, // "1722":"Группы пользователей",

                    {id: "grID96", value: mcLang(1963)}, // "1963":"Импорт пользователей",
                    {id: "grID141",value: mcLang(1964)}  // "1964":"Синхронизация",
                ]},
                { value: lng(31), data : [ //"31" : "Конференции",
                    {id: "grID135", value: mcLang(1623)}, // "1623":"Активные конференции",
                    {id: "grID97",  value: mcLang(1039)}, // "1039":"Автосоздаваемые конференции",
                ]},
                { value: lng(586), data : [ //"586": "Управление правами",
                    {id: "grID98", value: mcLang(57)}, // "57" : "Группы прав"
                    {id: "grID99", value: mcLang(916)}, // "916":"Пользователи групп",
                    {id: "grID142", value: mcLang(1758)} // "1758":"Доступ к плагинам",
                ]},
                { value: lng(99), data : [ //"99" : "Инструменты",
                    {id: "grID100", value: mcLang(945)}, // "945":"MyChat Guest",
                    {id: "grID101", value: mcLang(938)}, // "938":"Web-поддержка",

                    { value: lng(1134), data : [ //"1134":"Просмотр протоколов",
                        {id: "grID54", value: lng(769)}, //"769":"Просмотр FTP-протоколов",
                        {id: "grID44", value: lng(770)}, //"770":"Просмотр всех разговоров в каналах",
                        {id: "grID45", value: lng(771)}, //"771":"Просмотр всех разговоров в приватах",
                        {id: "grID43", value: lng(772)}, //"772":"Просмотр своих разговоров в приватах",
                        {id: "grID55", value: lng(773)}, //"773":"Просмотр системных протоколов",
                        {id: "grID86", value: lng(1214)},//"1214":"Просмотр NodeJS-протоколов",
                        {id: "grID132",value: lng(1617)},//"1617":"Просмотр логов скриптов",
                        {id: "grID87", value: lng(1215)},//"1215":"Просмотр протоколов аудита",
                        {id: "grID165",value: lng(1887)},//"1887":"Удаление сообщений из протоколов конференций",
                        {id: "grID188",value: lng(2043)} //"2043":"Удаление приватных сообщений из протоколов",
                    ]},

                    {id: "grID102", value: mcLang(1515)}, // "1515":"Доска объявлений",
                    {id: "grID103", value: mcLang(1555)}, // "1555":"Обновления",
                    {id: "grID122", value: mcLang(1589)}, // "1589":"Скрипты",
                    {id: "grID133", value: mcLang(1618)}, // "1618":"Перезагрузка",
                    {id: "grID143", value: mcLang(1765)}, // "1765":"Перенос сервера",
                    {id: "grID140", value: mcLang(1740)}, // "1740":"Интеграция",
                    {id: "grID131", value: mcLang(1329)}, // "1329":"Назначение настроек клиентам",
                    {id: "grID136", value: mcLang(1688)}, // "1688":"Шаблоны настроек клиентов",
                    {id: "grID246", value: mcLang(2218)}, // "2218":"Пользовательские меню",
                    {id: "grID247", value: mcLang(2225)}, // "2225":"Тест портов",

                    { value: lng(1793), data : [ // "1793":"Форум",
                        {id: "grID185", value: mcLang(1983)} // "1983":"Управление подписками",
                    ]},

                    // {id: "grID178", value: mcLang(1945)}  // "1945":"Очистка"
                ]},
                { value: lng(1040), data : [ //"1040":"Фильтры",
                    {id: "grID104", value: mcLang(1057)}, // "1057":"Антифлуд",
                    {id: "grID105", value: mcLang(1059)}, // "1059":"IP фильтры",
                    {id: "grID106", value: mcLang(1060)}, // "1060":"MAC фильтры",
                    {id: "grID107", value: mcLang(1058)}, // "1058":"Плохие слова",
                    {id: "grID175", value: mcLang(1916)}, // "1916":"HardwareID",
                    {id: "grID108", value: mcLang(1061)} // "1061":"Блокировки названий",
                ]},
                { value: lng(15), data : [ //"15" : "Настройки",
                    {id: "grID109", value: mcLang(591)}, // "591": "Сетевые настройки MyChat",
                    {id: "grID110", value: mcLang(596)}, // "596": "Информация",
                    {id: "grID111", value: mcLang(598)}, // "598": "Протоколирование",
                    {id: "grID112", value: mcLang(599)}, // "599": "FTP файловый сервер",
                    {id: "grID113", value: mcLang(600)}, // "600": "WEB-сервисы",
                    {id: "grID114", value: mcLang(601)}, // "601": "Резервные копии",
                    {id: "grID115", value: mcLang(602)}, // "602": "Обслуживание",
                    {id: "grID116", value: mcLang(603)}, // "603": "Integration API",
                    {id: "grID117", value: mcLang(921)}, // "921":"Настройка SMTP",
                    {id: "grID118", value: mcLang(672)}, // "672": "Дополнительно",
                    {id: "grID176", value: mcLang(1941)}, // "1941":"Каталоги",
                    {id: "grID240", value: mcLang(2203)}, // "2203":"GPS трекинг",
                    // {id: "grID237", value: mcLang(824)}, // "824":"Плагины (дополнения)",
                ]},
                { value: lng(943), data : [ //"943":"Лицензии",
                    {id: "grID119", value: mcLang(944)},  // "944":"MyChat Server",
                    {id: "grID120", value: mcLang(945)},  // "945":"MyChat Guest",
                    {id: "grID187", value: mcLang(2033)}  // "2033":"MyChat викторина",
                    // {id: "grID177", value: mcLang(1958)}  // "1958":"MyChat Clear",
                ]}
            ]},{

            value: lng(784), data : [
                {id: "grID3",  value: lng(785)},//"785":"Просмотр доски объявлений",
                {id: "grID2",  value: lng(786)} //"786":"Создание новых сообщений на доске",
            ]}, {

            value: lng(787), data : [
                {id: "grID56", value: lng(788)}//"788":"Учет рабочего времени (экспериментально)",
            ]}, {

            value: lng(1722), data : [            // "1722":"Группы пользователей",
                {id: "grID227", value: lng(2162)},       // "2162":"Доступ к общим группам",
                { value: lng(2163), data : [      // "2163":"Личные группы",
                    {id: "grID228",  value: lng(2164)},  // "2164":"Доступ к личным группам",
                    {id: "grID229",  value: lng(2165)},  // "2165":"Создание личной группы",
                    {id: "grID230",  value: lng(2166)},  // "2166":"Удалите личной группы",
                    {id: "grID231",  value: lng(2167)},  // "2167":"Редактирование личной группы",
                    {id: "grID236",  value: lng(2186)},  // "2186":"Личные группы пользователей",
                ]},
            ]}, {

            value: lng(789), data : [
                {id: "grID51", value: lng(790)},//"790":"Прием приватных сообщений от пользователей, которым запрещена отправка приватных сообщений",
                {id: "grID68", value: lng(848)},//"848":"иммунитет от банов",
                {id: "grID72", value: lng(852)} //"852":"Иммунитет от игноров",
            ]}, {

            value: lng(1646), data : [              // "1646":"Kanban (управление проектами)",
                {id: "grID134",  value: lng(1647)}, // "1647":"Доступ к Kanban",
                {id: "grID196",  value: lng(2066)}, // "2066":"Полный доступ",

                { value: lng(2180), data : [      // "2180":"Проект",
                    {id: "grID215",  value: lng(2168)}, // "Создание новых проектов"
                    {id: "grID216",  value: lng(2169)}, // "Редактирование проектов"
                    {id: "grID217",  value: lng(2170)}, // "Закрытие проектов"
                ]},

                { value: lng(2181), data : [      // "2181":"Этап",
                    {id: "grID218",  value: lng(2171)}, // "Создание новых этапов"
                    {id: "grID219",  value: lng(2172)}, // "Удаление этапов"
                    {id: "grID220",  value: lng(2173)}, // "Редактирование этапов"
                ]},

                { value: lng(2182), data : [      // "2182":"Задание",
                    {id: "grID186",  value: lng(2035)}, // "2035":"Добавление заданий",
                    {id: "grID223",  value: lng(2176)}, // "Перенос задач между этапами"
                    {id: "grID224",  value: lng(2177)}, // "Доступ только к своим заданиям"
                    {id: "grID221",  value: lng(2174)}, // "Удаление задач"
                    {id: "grID222",  value: lng(2175)}, // "Редактирование задач"
                ]},

                { value: lng(2183), data : [      // "2183":"Комментарий",
                    {id: "grID225",  value: lng(2178)}, // "Добавление комментариев"
                    {id: "grID226",  value: lng(2179)}, // "Удаление комментариев"
                    {id: "grID234",  value: lng(2190)}, // "2190":"Удаление своих комментариев",
                    {id: "grID235",  value: lng(2191)}, // "2191":"Просмотр истории изменения задачи",
                ]},
            ]},{

            value: lng(945) + " & " + lng(938), data : [ //"945":"MyChat Guest",   "938":"Web-поддержка",
                {id: "grID57",  value: lng(768)},  //"768":"Доcтуп посетителей WEB-поддержки",
                {id: "grID85",  value: lng(937)},  //"937":"Отправка приглашений MyChat Guest для входа в приват",
                {id: "grID213", value: lng(2160)}, //"2160":"Отправка приглашений MyChat Guest для входа в конференцию",
            ]},{

            value: lng(31), data : [               //"31" : "Конференции",
                { value: lng(1851), data : [ //"1851":"Звонки",
                    {id: "grID255",  value: lng(2252)},  //"2252":"Создание голосовых конференций",
                    {id: "grID256",  value: lng(2253)},  //"2253":"Создание видеоконференций",
                    {id: "grID257",  value: lng(2254)},  //"2254":"Создание вебинаров",
                    {id: "grID258",  value: lng(2255)},  //"2255":"Закрытие медиа конференций",
                    {id: "grID259",  value: lng(2256)},  //"2256":"Вход в медиа конференции",
                    {id: "grID260",  value: lng(2257)},  //"2257":"Выход из медиа конференций",
                ]},
            
                {id: "grID211", value: lng(2158)}, // "2158":"Разрешить покидать текстовые конференции",
                {id: "grID212", value: lng(2159)}, // "2159":"Показывать список членов конференции",
                {id: "grID214", value: lng(2161)}, // "2161":"Разрешить просматривать список доступных конференций",
                // {id: "grID39", value: lng(793)},//"793":"Доступ к ''Моим любимым каналам''",
                // {id: "grID49", value: lng(803)},//"803":"Доступ к конференциям (Messenger-стиль)",
                // {id: "grID24", value: lng(794)},//"794":"Отправка персональных сообщений в каналах",
                {id: "grID5",  value: lng(1878)},  //"1878":"Отправка сообщений",
                {id: "grID27", value: lng(1986)},  // "1986":"Вставка изображений в сообщениях",
                {id: "grID232",value: lng(2189)},  // "2189":"Вставка форматированонго исходного кода",
                {id: "grID6",  value: lng(796)}, //"796":"Вход в существующие текстовые каналы",
                {id: "grID4",  value: lng(797)}, //"797":"Создание текстовых каналов",
                {id: "grID159",value: lng(1849)},//"1849":"Просмотр скрытых конференций",
                {id: "grID161",value: lng(1879)},// "1879":"Вставка файлов",
                {id: "grID164",value: lng(1886)},//"1886":"Удаление любых сообщений в конференциях",
                {id: "grID29", value: lng(2096)},//"2096":"Приглашение пользователей в свои конференции",
                {id: "grID198",value: lng(2082)},//"2082":"Удаление любых сообщений в конференциях в своей локальной базе данных",
                {id: "grID205",value: lng(2144)},//"2144":"Разрешить смотреть статусы доставки/прочтения сообщений",
                {id: "grID261",value: lng(2258)},//"2258":"Удаление конференций",
                {id: "grID262",value: lng(2265)},//"2265":"Закрытие конференций",
                {id: "grID263",value: lng(2266)},//"2266":"Удаление своих конференций",
                {id: "grID264",value: lng(2267)},//"2267":"Закрытие своих конференций",
                {id: "grID266",value: lng(2275)},//"2275":"Редактирование своих сообщений",
            ]}, {

            value: lng(798), data : [
                {id: "grID22", value: lng(799)},//"799":"Изменение личного списка контактов",
                {id: "grID31", value: lng(800)},//"800":"Показывать общий список контактов",
                {id: "grID41", value: lng(801)} //"801":"Показывать личный список контактов",
            ]}, {

            value: lng(802), data : [
                {id: "grID59", value: lng(804)},//"804":"Блокирование работающей программы паролем",
                {id: "grID144",value: lng(1791)},//"1791":"Главное меню",
                {id: "grID28", value: lng(805)},//"805":"Игнорирование других пользователей",
                {id: "grID38", value: lng(806)},//"806":"Изменение настроек клиентского приложения",
                {id: "grID80", value: lng(690)},//"690":"Изменение пароля своей учётной записи",
                {id: "grID60", value: lng(807)},//"807":"Изменение сетевого статуса",
                {id: "grID47", value: lng(808)},//"808":"Использование ACTIONs",
                {id: "grID65", value: lng(846)},//"846":"Использование шрифтовой разметки в отправляемых сообщениях",
                {id: "grID50", value: lng(809)},//"809":"Открытие общих ресурсов компьютера собеседника (''Открыть компьютер...'')",
                {id: "grID1",  value: lng(811)},//"811":"Подключаться к MyChat серверу",
                {id: "grID46", value: lng(812)},//"812":"Поиск пользователей",
                {id: "grID69", value: lng(849)},//"849":"показывать или нет рекламный блок",
                {id: "grID40", value: lng(816)},//"816":"Ручной выход из клиентского приложения (можно ли выключать чат пользователю)",
                {id: "grID145",value: lng(1792)},//"1792":"Список диалогов",
                {id: "grID166",value: lng(1892)},//"1892":"Просмотр истории сообщений",
                {id: "grID189",value: lng(2044)},//"2044":"Отправка снимка экрана в чат",
                {id: "grID191",value: lng(2047)},//"2047":"\"Быстрые\" сообщения",
                {id: "grID192",value: lng(2048)},//"2048":"Перенаправление диалогов",
                {id: "grID238",value: lng(2201)},//"2201":"Отправка текущей геопозиции на сервер",
                {id: "grID242",value: lng(2213)},//"2213":"Печать истории чатов на принтере",
                {id: "grID243",value: lng(2214)},//"2214":"Сохранение истории чатов в файл",
                {id: "grID245",value: lng(2218)},//"2218":"Пользовательские меню",
            ]}, {

            value: lng(817), data : [
                {id: "grID17", value: lng(818)},//"818":"Изменение темы текстовых каналов",
                {id: "grID21", value: lng(819)},//"819":"Очистка текстовых каналов у всех пользователей",
                {id: "grID13", value: lng(820)},//"820":"Право изгнания пользователей из текстовых каналов (kick)",
                {id: "grID12", value: lng(821)} //"821":"Право наказывать пользователей (ban)",
            ]}, {

            value: lng(822), data : [
                {id: "grID64", value: lng(845)},//"845":"Вставка файлов в оповещениях",
                {id: "grID23", value: lng(823)},//"823":"Отправка оповещения другим пользователям",
                {id: "grID158", value: lng(1846)} //"1846":"Отправка оповещений только в пределах своих групп пользователей",
            ]}, {

            value: lng(824), data : [
                {id: "grID62", value: lng(825), icon: "link", iconText: "", link: ""},//"825":"Активировать список запрещенных плагинов",
                {id: "grID61", value: lng(826), icon: "link", iconText: "", link: ""},//"826":"Активировать список разрешенных плагинов",
                {id: "grID78", value: lng(692)},//"692": "Добавление новых плагинов",
                {id: "grID37", value: lng(827)},//"827":"Использование плагинов",
                {id: "grID79", value: lng(691)},//"691": "Удаление плагинов",
                {id: "grID63", value: lng(828)} //"828":"Управление плагинами на клиенте",
            ]}, {

            value: lng(829), data : [// privates
                {id: "grID75", value: lng(695)},//"695": "Видеозвонки",
                {id: "grID30", value: lng(830)},//"830":"Вставка изображений",
                {id: "grID74", value: lng(855)},//"855":"Голосовые звонки",
                {id: "grID179",value: lng(1960)},//"1960":"Трансляция экрана",
                {id: "grID180",value: lng(1961)},//"1961":"Разрешить получать трансляции экрана",
                {id: "grID70", value: lng(850)},//"850":"Запретить приваты со всеми, кроме входящих в личный список контактов",
                {id: "grID71", value: lng(851)},//"851":"Запретить приваты со всеми, кроме входящих в общий список контактов",
                {id: "grID7",  value: lng(831)},//"831":"Открытие новых приватов",
                {id: "grID76", value: lng(694)},//"694": "Разрешить получать голосовые звонки",
                {id: "grID77", value: lng(693)},//"693": "Разрешить получать видеозвонки",
                {id: "grID8",  value: lng(832)}, //"832":"Получение приватных сообщений от других пользователей",
                {id: "grID162",value: lng(1878)},//"1878":"Отправка сообщений",
                {id: "grID163",value: lng(1879)},//"1879":"Вставка файлов",
                {id: "grID190",value: lng(2045)},//"2045":"Удаление любых сообщений в приватах",
                {id: "grID193",value: lng(2052)},//"2052":"Многоадресные приватные сообщения",
                {id: "grID197",value: lng(2081)},//"2081":"Разрешить \"будить\" пользователя",
                {id: "grID199",value: lng(2083)},//"2083":"Удаление любых сообщений в приватах в своей локальной базе данных",
                {id: "grID203",value: lng(2138)},//"2138":"Звонки через интеграцию с Asterisk",
                {id: "grID204",value: lng(2139)},//"2139":"Разрешить получать звонки через интеграцию с Asterisk",
                {id: "grID206",value: lng(2149)},//"2149":"Разрешить завершать звонки",
                {id: "grID207",value: lng(2150)},//"2150":"Автоматически отвечать на входящие звонки",
                {id: "grID208",value: lng(2151)},//"2151":"Разрешить выключать микрофон во время звонка",
                {id: "grID209",value: lng(2152)},//"2152":"Разрешить выключать камеру во время звонка",
                {id: "grID210",value: lng(2153)},//"2153":"Разрешить запись звонков",
                {id: "grID233",value: lng(2189)},//"2189":"Вставка форматированонго исходного кода",
                {id: "grID265",value: lng(2275)},//"2275":"Редактирование своих сообщений",
            ]}, {

            // value: lng(833), data : [
            //     {id: "grID48",  value: lng(834)},//"834":"Локальное протоколирование приватов на компьютере клиента",
            //     {id: "grID200", value: lng(2093)}//"2093":"Локальное протоколирование конференций на компьютере клиента",
            // ]}, {

            value: "Android", data : [
                {id: "grID201", value: lng(2094)},//"2094":"Запрет скриншов экрана в диалогах и скрытие окна приложения при переключении между приложениями",
                {id: "grID202", value: lng(2125)} //"2125":"Отображать вкладку \"Звонки\" на главном экране",
            ]}, {

            value: lng(835), data : [ //profile
                { value: lng(1900), data : [ // "1900":"Просмотр информации",
                    {id: "grID26",  value: lng(815)},  // "815":"IP-адреса пользователя",
                    {id: "grID52",  value: lng(813)},  // "813":"MAC-адрес сетевого интерфейса пользователя",
                    {id: "grID53",  value: lng(814)},  // "814":"Активный процесс пользователя",
                    {id: "grID167", value: lng(1901)}, // "1901":"Сетевое имя",
                    {id: "grID168", value: lng(1902)}, // "1902":"Тип клиента",
                    {id: "grID169", value: lng(1903)}, // "1903":"HardwareID",
                    {id: "grID170", value: lng(1904)}, // "1904":"UserAgent",
                    {id: "grID171", value: lng(1905)}, // "1905":"Reflink",
                    {id: "grID172", value: lng(1906)}, // "1906":"Название активного процесса",
                    {id: "grID173", value: lng(1907)},  // "1907":"Местоположение активного процесса",
                    {id: "grID239", value: lng(2202)}, // "2202":"Геопозиция (GPS)",
                ]},
                {id: "grID42", value: lng(836)},  // "836":"Доступ к менеджеру учетных записей",
                {id: "grID9",  value: lng(837)},  // "837":"Изменение персонального профиля",
                {id: "grID174",value: lng(1911)}, // "1911":"Просмотр профилей других пользователей",
                {id: "grID248",value: lng(2244)}, // "2244":"Разрешить удаление своей учётной записи",

            ]}, {

            value: lng(838), data : [
                {id: "grID19", value: lng(839)},//"839":"Доступ к личной папке на файловом сервере",
                {id: "grID18", value: lng(840)},//"840":"Доступ к общей папке на файловом сервере",
                {id: "grID81", value: lng(689)},//"689": "Разрешить доступ к личным файлам для других пользователей (\"только чтение\")",
                {id: "grID10", value: lng(841)},//"841":"Разрешить отправлять файлы другим пользователям",
                {id: "grID11", value: lng(842)},//"842":"Разрешить принимать файлы от других пользователей",
                {id: "grID82", value: lng(688)},//"688": "Разрешить публиковать ссылку на \"Мои файлы на сервере\"",
                {id: "grID84", value: lng(686)},//"686": "Разрешить писать в личную папку",
                {id: "grID83", value: lng(687)},//"687": "Разрешить писать в общую папку",
                {id: "grID67", value: lng(847)} //"847":"Передавать файлы только через сервер",
            ]}, {

            value: lng(1793), data : [ // "1793":"Форум",
                {id: "grID146", value: lng(1794)},//"1794":"Доступ к форуму",

                {id: "grID147", value: lng(1796)},//"1796":"Можно создавать новые разделы",
                {id: "grID149", value: lng(1797)},//"1797":"Можно создавать новые темы",
                {id: "grID151", value: lng(1799)},//"1799":"Можно создавать новые сообщения",

                {id: "grID148", value: lng(1795)},//"1795":"Изменение разделов (удаление, переименование, перенос)",
                {id: "grID150", value: lng(1798)},//"1798":"Изменение тем (удаление, переименование, перенос)",
                {id: "grID152", value: lng(1800)},//"1800":"Изменение сообщений (удаление, модификация, перенос)",
                {id: "grID153", value: lng(1801)}, //"1801":"Изменение собственных сообщений (удаление, модификация, перенос)",

                {id: "grID154", value: lng(1802)}, //"1802":"Удаление секций",
                {id: "grID155", value: lng(1803)}, //"1803":"Удаление тем",
                {id: "grID156", value: lng(1804)}, //"1804":"Удаление сообщений",

                {id: "grID181", value: lng(1984)}, //"1984":"Изменение цвета маркера для тем",
                {id: "grID182", value: lng(1985)}, //"1985":"Подписка/отписка на уведомления в разделах и темах",
                {id: "grID183", value: lng(1986)}, //"1986":"Вставка изображений в сообщениях",
                {id: "grID184", value: lng(1987)}, //"1987":"Вставка файлов в сообщениях",
                {id: "grID195", value: lng(2060)}, //"2060":"Создание презинтаций для сообщений",

                {id: "grID157", value: lng(1805)}  //"1805":"Удаление собственных сообщений",

            ]}, { // allow connection for OS

            value: lng(2248), data : [ // "2248":"Разрешённые для подключения ОС",
                {id: "grID249", value: "Windows"}, //
                {id: "grID250", value: "Linux"}, //
                {id: "grID251", value: "macOS"}, //
                {id: "grID252", value: "WEB"}, //
                {id: "grID253", value: "Android"}, //
                {id: "grID254", value: "iOS"}  //
            ]}
        ];

        function addGrId (list){
            list.forEach(function (item){
                if (item.data){
                    addGrId(item.data);
                } else
                if (item.id){
                    item.value += " [" + (item.id).replace("grID", "") + "]";
                }
            });
        }

        addGrId(rightsList);

        var _grList = {
            view     : "list",
            select   : true,
            id       : "grList",
            data     : groupList,
            navigation : true,
            template : "#Name#", //&nbsp;&nbsp;<span style='opacity: .85; font-size: 90%;'>#comments#</span>"
            height   : 196,
            on       : {
                onAfterSelect : function(id){
                    $scope.selectGrListItem(this.getSelectedItem().Rights);
                    $scope.selectedItem = this.getItem(id);

                    $scope.disableEditDel();
                },
                onItemDblClick : function(){
                    var item = this.getSelectedItem();

                    if (item.Name != "Guests" && item.Name != "WEB guests") {
                        $scope.edit();
                        $scope.showDialog();
                    }
                }
            }
        };

        var grControls = {
            width : 150,
            id    : 'grControls',
            rows  : [
                {view  : "button", value : mcLang(50), click : function(){// "50" : "Добавить",
                    $scope.add();
                    $scope.showDialog();
                }},

                { id: "editGroup" + $scope.Name, view  : "button", value : mcLang(859), click: function(){// "859":"Переименовать",
                    $scope.edit();
                    $scope.selectedItem = $scope.grList.getSelectedItem();
                    $scope.showDialog();
                }},

                { id: "delGroup" + $scope.Name, view  : "button", value : mcLang(52), click: function(){ // "52" : "Удалить",
                    $scope.selectedItem = $scope.grList.getSelectedItem();
                    $scope.del();
                }, type: "danger"},

                {view  : "button", value : mcLang(579), click: function(){// "579": "Клонировать",
                    $scope.add(true);
                    $scope.selectedItem = $scope.grList.getSelectedItem();
                    $scope.showDialog();
                }},

                {view  : "button", value : mcLang(53), click: function(){ // "53" : "Обновить",
                    $scope.refresh('refresh');
                }}
            ]
        };

        var grFilter = {
            view           : "text",
            height         : 34,
            placeholder    : mcLang(578), // "578": "Какое правило вы ищете? Напишите здесь",
            keyPressTimeout: 1000,
            on             : {
                onTimedKeyPress : function(){
                    $scope.doFilter(mcService.trim(this.getValue()));
                }
            }
        };

        var grClearFilter = {
            view  : "button",
            type  : "image",
            width : 32,
            image : mcConst.imagesPath.noFilter,
            click : function(){
                this.getParentView().getChildViews()[0].setValue('');

                $scope.doFilter("");
            }
        };

        var grTree = {
            view       : "tree",
            id         : "grTree",
            data       : rightsList,
            /*filterMode : {
                level : 2
            },*/
            activeTitle: true,
            navigation : false,
            css: "underlineItem",
            template   : function(obj, common){
                var res = '';

                if (mcService.isString(obj.id) && obj.id[0] == 'g') { // g
                    res = "<span style='width: 4px; height: 20px; position: relative; float: left;'></span>" + common.checkbox(obj,common) + "&nbsp;&nbsp;" + obj.value + "";
                } else {
                    res = common.icon(obj,common) + "<span style='color: blue'>" + obj.value + "</span>";
                }

                return res;
            },
            on : {
                onItemCheck : $scope.onCheckboxChange,
                onItemClick : function(id){
                    var item = this.getItem(id);

                    if (mcService.isString(item.id) && item.id[0] == 'g') { // g
                        if (item.checked) {
                            this.uncheckItem(item.id);
                        } else {
                            this.checkItem(item.id);
                        }
                    }
                }
            }
        };

        thisView = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows : [
                { cols: [
                    { view : "template", type : "header", template : mcLang(57) }, // "57" : "Группы прав",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { cols : [_grList,   grControls] },
                { view : "resizer" },
                { rows : [
                    //{ cols : [grFilter, grClearFilter] },
                    {height: 3}, mcService.FilterFiled({
                        listName     : "grTree",
                        filterParams : ["value"]
                    }),

                    { height: 5 },
                    { cols : [grTree] }
                ]}
            ]
        });

        $scope.grList = $$('grList');
        $scope.grTree = $$("grTree");

        $scope.grTree.sort(function (a, b) {
            // return a.value.indexOf("") && !b.data ? -1 : !a.data && b.data ? 1 : mcService.sortAB(a.value, b.value);
            return mcService.sortAB(a.value, b.value);
        });

        $scope.editGroup = $$("editGroup" + $scope.Name);
        $scope.delGroup  = $$("delGroup" + $scope.Name);

        mcService.disableContextMenu(thisView);
    } else {
        var grList = $scope.grList;

        grList.clearAll();
        grList.define('data', $scope.data);
        grList.sort("#Name#");
        grList.refresh();

        thisView.adjust();
    }

    if (!$scope.showDialog){
        $scope.showDialog = function (){
            if ($scope.dialogWindow){
                $scope.dialogWindow.destructor();
            }

            $scope.dialogWindow = webix.ui({
                view     : "window",
                position : "center",
                modal    : true,
                width    : 300,
                head     : $scope.wndHead,
                body     : {
                    view : 'form',
                    rules:{
                        "Name"    : webix.rules.isNotEmpty
                    },
                    elements : [{
                        view     : "text",
                        id       : 'dialog' + $scope.Name,
                        label    : mcLang(910), // "910":"Название группы прав",
                        name     : 'Name',
                        required : "true",
                        labelPosition : 'top'
                    }, {
                        cols : [{
                            view  : "button",
                            value : mcLang(104), // "104": "Сохранить",
                            click : function() {
                                $scope.confirm.apply(this.getFormView());
                            }
                        }, {
                            view  : "button",
                            type  : "danger",
                            value : mcLang(103), // "103": "Отмена",
                            click : function(){
                                $scope.dialogWindow.hide();
                            }
                        }]
                    }]
                },
                on : {
                    onShow : function(){
                        if ($scope.selectedItem) {
                            this.getChildViews()[1].getChildViews()[0].setValue($scope.selectedItem.Name);
                        }

                        this.getChildViews()[1].getChildViews()[0].focus();

                        $scope.regShowWindow(this.config.id, this);
                    }
                }
            });

            webix.UIManager.addHotKey("Enter", function() {
                $scope.confirm.apply($scope.dialogWindow.getChildViews()[1]);

                return false;
            }, $$('dialog' + $scope.Name));

            webix.UIManager.addHotKey("Esc", function() {
                $scope.dialogWindow.hide();

                return false;
            }, $$('dialog' + $scope.Name));

            $scope.dialogWindow.show();
        }
    }

    return thisView;
}


"use strict";

function groupRightsController($scope, $rootScope){
    $scope.Name         = mcConst.dataModels.GroupRights;
    $scope.dialogWindow = null;
    $scope.data         = [];
    $scope.wndHead      = '';
    $scope.showDialog   = null;
    $scope.selectedItem = null;
    $scope.confirm      = null;
    $scope.grList       = null;
    $scope.treeReady    = false;
    $scope.newRights    = '';

    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        onApply : function(){
            var m_id = mcService.getIdxByIdFromData($scope.data, $scope.selectedItem.id);
            if (m_id) {
                $scope.data[m_id].Rights = $scope.newRights;
            }

            $scope.selectedItem.Rights = $scope.newRights;

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_role_set_rights,
                mcConst.SessionID,
                $scope.newRights,
                $scope.selectedItem.ID
            ]);

            clearChangedData();

            webix.message(mcService.Lang(915)); // "915":"Права группы изменены!",
        },
        onClose : function(){
            $scope.grList.unselectAll();
            $scope.grList.select($scope.selectedItem.id);

            clearChangedData();
        }
    };

    function clearChangedData (){
        $scope.changedData.data.Items    = {};
        $scope.changedData.data.Desc     = "";
        $scope.changedData.data.ShowDesc = false;

        $scope.enableButtonsAndList();
        $scope.disableEditDel();

        $scope.newRights = '';
    }

    var angElement = document.getElementById($scope.Name);
    var rcView     = null;

    $scope.checkDuplicate = function(name, id){
        var res = true;

        for (var i = 0; i < $scope.data.length; i++){
            if (id && (id == $scope.data[i].ID)){
                continue;
            }

            if ($scope.data[i].Name == name){
                res = false;

                break;
            }
        }

        return res;
    };

    $scope.checkName = function(name, id){
        var _name = mcService.trim(name);
        var res   = false;

        if ((_name != '' && _name != 'Guests' && _name != 'WEB guests') && mcService.isSymbolicNumbers(_name) && $scope.checkDuplicate(_name, id)){
            res = true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(912)]); // "912":"Название группы не должно быть пустым и совпадать с уже существуюющей!",
        }

        return res;
    };

    $scope.add = function(clone){
        $scope.confirm = function (){
            var self = this;
            var name = self.getChildViews()[0].getValue();
            var _id  = (clone && $scope.selectedItem) ? $scope.selectedItem.ID : -1;

            if ($scope.checkName(name)){
                var params = [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_role_add,
                    mcConst.SessionID,
                    name,
                    _id
                ];

                self.getParentView().hide();

                $rootScope.$broadcast('SendCMDToServer', params);

            }
        };

        if (!clone) $scope.selectedItem = null;

        $scope.wndHead      = mcService.Lang(911); // "911":"Добавление новой группы прав",
    };

    $scope.del = function(){
        if ($scope.selectedItem){
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(913, $scope.selectedItem.Name), // "913":"Удалить группу прав \"%s\"?",
                ok    : mcService.Lang(581), // "581": "Удалить",
                cancel: mcService.Lang(103), // "103": "Отмена",
                callback:function(yes){
                    if (yes){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_role_delete,
                            mcConst.SessionID,
                            $scope.selectedItem.ID,
                            function(){
                                $scope.refresh('remove');
                                $rootScope.$broadcast('refreshUserManagerOnNextShow', []);
                            }
                        ]);
                    }
                }
            }));
        }
    };

    $scope.edit = function(){
        $scope.confirm = function (){
            if ($scope.selectedItem.ID) {
                var self = this;
                var name = self.getChildViews()[0].getValue();
                var _id  = $scope.selectedItem.ID;

                if ($scope.checkName(name, _id)){
                    var params = [
                        mcConst.lockInterface,
                        mcConst._CMD_.cs_adm_role_modify,
                        mcConst.SessionID,
                        name,
                        _id
                    ];

                    self.getParentView().hide();

                    $rootScope.$broadcast('SendCMDToServer', params);
                    $rootScope.$broadcast('refreshUserManagerOnNextShow', []);
                }
            }
        };

        $scope.wndHead = mcService.Lang(914); // "914":"Переименовать группу прав",
    };

    $scope.refresh = function(cmd, data){
        var res  = false;
        var list = $scope.grList;

        switch (cmd){
            case 'modify':
                var item = list.getItem($scope.selectedItem.id);
                var m_id = mcService.getIdxByIdFromData($scope.data, $scope.selectedItem.id);

                item.Name = data.Name;

                list.refresh();

                if (m_id) {
                    $scope.data[m_id].Name = data.Name;
                }
            break;

            case 'add':
                list.add(data);
                list.select(list.getLastId());
                list.scrollTo(0, 9999);

                $scope.data.push(data);
            break;

            case 'remove':
                var r_id = mcService.getIdxByIdFromData($scope.data, $scope.selectedItem.id);

                list.remove($scope.selectedItem.id);
                list.select(list.getFirstId());

                if (r_id) {
                    $scope.data.splice(r_id, 1);
                }

                $rootScope.$broadcast('refresh' + mcConst.dataModels.GroupUsers, [mcConst.guestGroupId]);
            break;

            case 'refresh':
                $scope.getData();
            break;

            default:
                res = true;
        }

        $rootScope.mcStorage[mcConst.dataModels.GroupRights] = $scope.data;

        return res;
    };

    $scope.doFilter = function (val){
        var tree = $$("grTree");
        var stateName = "grTreeState";

        if (val !== '') {
            if (!webix.storage.local.get(stateName)){
                webix.storage.local.put(stateName, tree.getState());
            }

            tree.filter("#value#", val);
        } else {
            var state = webix.storage.local.get(stateName);

            if (state){
                tree.filter("#value#", val);
                tree.setState(state);

                webix.storage.local.remove(stateName);
            }
        }
    };

    $scope.selectGrListItem = function (rights){
        var tree = $$('grTree');

        $scope.treeReady = false;

        for (var i = 0; i < rights.length; i ++){
            if (tree.getItem('grID' + (i + 1))){
                if (rights[i] ==  1) {
                    tree.checkItem('grID' + (i + 1));
                } else {
                    tree.uncheckItem('grID' + (i + 1));
                }
            }
        }

        $scope.treeReady = true;
    };

    $scope.disableEditDel = function () {
        if ($scope.selectedItem.Name == "Guests" || $scope.selectedItem.Name == "WEB guests") {
            $scope.editGroup.disable();
            $scope.delGroup.disable();
        } else {
            $scope.editGroup.enable();
            $scope.delGroup.enable();
        }
    };

    $scope.disableButtonsAndList = function(){
        if ($scope.grList.isEnabled()){
            var controls = $$('grControls').getChildViews();

            $scope.grList.disable();

            for (var i = 0; i < controls.length; i ++){
                controls[i].disable();
            }
        }
    };

    $scope.enableButtonsAndList = function(){
        if (!$scope.grList.isEnabled()){
            var controls = $$('grControls').getChildViews();

            $scope.grList.enable();

            for (var i = 0; i < controls.length; i ++){
                controls[i].enable();
            }
        }
    };

    $scope.selectFirstItemGroupList = function(){
        var grList       = $scope.grList;
        var selectedItem = grList.getSelectedItem() || [];

        if (mcService.isObject(selectedItem)){ // when any list item selected
            $scope.selectGrListItem(selectedItem.Rights);
        } else
        if (mcService.isArray(selectedItem) && selectedItem.length === 0){ // no list item selected
            grList.select(grList.getFirstId());
        }
    };

    $scope.onCheckboxChange = function(id, state){
        if ($scope.treeReady) {
            if ($scope.newRights == ''){
                $scope.newRights = $scope.selectedItem.Rights;
            }

            var idx = parseInt(mcService.copy(id, 4));

            $scope.newRights      = $scope.newRights.split('');
            $scope.newRights[idx - 1] = (state) ? '1' : '0';
            $scope.newRights      = $scope.newRights.join('');

            if ($scope.selectedItem.Rights == $scope.newRights){
                clearChangedData();

                $rootScope.$broadcast('hide' + mcConst.dataModels.ApplyPanel, []);
            } else {
                $scope.disableButtonsAndList();

                $scope.changedData.data.ShowDesc  = true;
                $scope.changedData.data.Items['Rights'] = $scope.newRights;

                $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
            }
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function (data){
        $scope.data = data;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        rcView = initGroupRights($scope);

        $scope.selectFirstItemGroupList();

        mcService.initResize(rcView, $scope.Name);
    };

    $scope.getData = function(data){
        if (!data){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_list_roles,
                mcConst.SessionID,
                function(data ){
                    $rootScope.mcStorage[mcConst.dataModels.GroupRights] = data;

                    $scope.show(data);
                }
            ]);
        } else {
            return true;
        }
    };

    $scope.$on('refresh' + $scope.Name, function(e, args){
        $scope.refresh.apply(null, args);
    });

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);

        $scope.treeReady = false;
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.getData();
    });
}
"use strict";

function initGroupUsers($scope){
    function usersTemplate(obj){
        return obj.DisplayName + " <span style='float:right'>(UIN: " + obj.UIN + ")</span>";
    }

    var thisView = $$($scope.Name);

    if (!thisView) {
        var _guList = {
            view     : "list",
            select   : true,
            id       : "guList" + $scope.Name,
            data     : $scope.grData,
            navigation : true,
            template : "#Name#", //&nbsp;&nbsp;<span style='opacity: .85; font-size: 90%;'>#comments#</span>"
            height   : 196,
            on       : {
                onAfterSelect : function(id){
                    $scope.selectedGroup = this.getItem(id);
                    $scope.getGroupUsers($scope.selectedGroup.ID);
                }
            }
        };

        thisView = webix.ui({
            type: "space",
            padding: 5,
            container: $scope.Name,
            id: $scope.Name,
            borderless: true,
            rows: [
                { cols: [
                    { view: "template", type: "header", template: mcService.Lang(916) }, // "916":"Пользователи групп",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: "layout", cols: [
                    { rows: [
                        _guList,

                        { view : "resizer" },

                        { rows: [
                            { type: 'header', height: 30, id: 'countCurrentGU', template: mcService.Lang(919) }, // "919":"Пользователи группы %s",

                            {height: 3}, mcService.FilterFiled({
                                listName     : 'currentList' + $scope.Name,
                                filterParams : ["DisplayName"]
                            }),

                            {
                                // view: "list", template: usersTemplate, navigation: true, drag: true, select: "multiselect",
                                id : 'currentList' + $scope.Name,
                                view        : "datatable",
                                resizeColumn: true,
                                drag        : true,
                                select      : "row",
                                multiselect : true,
                                headerRowHeight: 25,
                                minColumnWidth : 70,
                                navigation  : false,
                                columns     : [
                                    { id:"UIN",         header:"UIN", width: 55,     sort:"int"},
                                    { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                                ],
                                on : {
                                    onAfterDrop : $scope.moveUsers
                                }
                            }
                        ]}
                    ]},

                    { view : "resizer" },

                    { rows: [
                        { type: 'header', height: 30, id: 'countGuestsGU', template: mcService.Lang(920) }, // "920":"Нераспределенные пользователи (гости, группа Guests)",

                        {height: 3},
                        mcService.FilterFiled({
                            listName     : 'guestList' + $scope.Name,
                            filterParams : ["DisplayName"]
                        }),

                        {
                            // view: "list", template: usersTemplate, navigation: true, drag: true, select: "multiselect",
                            id : 'guestList' + $scope.Name,
                            view        : "datatable",
                            resizeColumn: true,
                            // id          : 'currentList' + $scope.Name,
                            drag        : true,
                            select      : "row",
                            multiselect : true,
                            headerRowHeight: 25,
                            minColumnWidth : 70,
                            navigation  : false,
                            columns     : [
                                { id:"UIN",         header:"UIN", width: 55,     sort:"int"},
                                { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                            ],
                            on : {
                                onAfterDrop : $scope.moveUsers
                            }
                        }
                    ]}
                ]},

                { cols: [
                    { view: "button", label: mcService.Lang(918), type: 'next', click: function(){ // "918":"Удалить пользователя из группы",
                        $scope.moveByButton('currentList', 'guestList');
                    }},

                    { width: 10 },

                    { view: "button", label: mcService.Lang(917), type: 'prev', click: function(){ // "917":"Переместить пользователя в группу",
                        $scope.moveByButton('guestList', 'currentList');
                    }}
                ]}
            ]
        });

        $scope.guestList   = $$('guestList' + $scope.Name);
        $scope.currentList = $$('currentList' + $scope.Name);
        $scope.guList      = $$("guList" + $scope.Name);

        mcService.disableContextMenu(thisView);
    } else {
        $scope.guList.clearAll();
        $scope.guList.define('data', $scope.grData);
        $scope.guList.refresh();
    }

    return thisView;
}
"use strict";

function groupUsersController($scope, $rootScope){
    $scope.Name   = mcConst.dataModels.GroupUsers;
    $scope.data   = [];
    $scope.grData = [];
    $scope.guList = null;
    $scope.selectedGroup = null;

    $scope.guestList   = null;
    $scope.currentList = null;

    var angElement = document.getElementById($scope.Name);
    var rcView     = null;

    function refreshTitle(_title, _lang, _count){
        var title = $$(_title);

        if (title){
            title.define('template', _lang + " [" + _count + "]");
            title.refresh();
        }
    }

    $scope.moveByButton = function(from, to){
        var selectedItems = $scope[from].getSelectedItem();

        if (mcService.isObject(selectedItems)){
            selectedItems = [selectedItems];
        }

        if (selectedItems){
            for (var i = 0; i < selectedItems.length; i ++){
                $scope[to].add(selectedItems[i]);
                $scope[from].remove(selectedItems[i].id);
            }

            $scope[to].sort("UIN", "asc", "int");

            $scope.moveUsers.call(null, {
                fromList : from + $scope.Name,
                toList   : to + $scope.Name,
                uList    : selectedItems
            });
        }
    };

    $scope.moveUsers = function(context){
        $rootScope.$broadcast('show' + mcConst.lockInterface, []); // unlock

        var fromList = context.fromList || context.from.config.id;
        var toList   = context.toList   || context.to.config.id;
        var userList = context.uList    || context.source;
        var res      = [];
        var grID     = 0;

        if (fromList !== toList) {
            if (this && this.sort) {
                this.sort("UIN", "asc", "int");
            }

            var item = $$(toList);

            for (var i = 0; i < userList.length; i++){
                res.push(item.getItem(userList[i].id || userList[i]).UIN);
            }

            if (res.length > 0){
                if (toList === ('guestList' + $scope.Name)){
                    grID = mcConst.guestGroupId;

                    refreshTitle('countGuestsGU',  mcService.Lang(920), $$(toList).data.count());
                    refreshTitle('countCurrentGU', mcService.Lang(919), $$(fromList).data.count());
                } else {
                    grID = $scope.selectedGroup.ID;

                    refreshTitle('countGuestsGU',  mcService.Lang(920), $$(fromList).data.count());
                    refreshTitle('countCurrentGU', mcService.Lang(919), $$(toList).data.count());
                }

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_role_apply_to_users,
                    mcConst.SessionID,
                    res.join(','),
                    grID
                ]);

                $rootScope.$broadcast('refreshUserManagerOnNextShow', []);
            }
        }

        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
    };

    $scope.doFilter = function (list){
        var value = this.getValue().toLowerCase();

        list.filter(function(obj){
            return (obj.DisplayName.toLowerCase().indexOf(value) >= 0) ||
                (obj.UIN.toString().indexOf(value) >= 0);
        })
    };

    $scope.getGroupUsers = function(id){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_role_users_list,
            mcConst.SessionID,
            id,
            $scope.refresh
        ]);
    };

    $scope.selectFirstItemGroupList = function(){
        var grList       = $scope.guList;
        var selectedItem = grList.getSelectedItem() || [];

        if (mcService.isObject(selectedItem)){ // when any list item selected
            //$scope.selectGrListItem(selectedItem.Rights);
        } else
        if (mcService.isArray(selectedItem) && selectedItem.length === 0){ // no list item selected
            grList.select(grList.getFirstId());
        }
    };

    $scope.refresh = function(data){
        var list  = null;

        if (data.ID == mcConst.guestGroupId){
            list = $scope.guestList;

            refreshTitle('countGuestsGU', mcService.Lang(920), data.Users.length);
        } else
        if ($scope.currentList){
            list = $scope.currentList;

            refreshTitle('countCurrentGU', mcService.Lang(919), data.Users.length);
        }

        if (list){
            data.Users.sort(function (a, b) {
                return mcService.sortAB(a.UIN, b.UIN);
            });

            list.clearAll();
            list.define('data', data.Users);
            // list.sort("UIN", "asc", "int");
        }
    };

    $scope.show = function (){
        if ($scope.grData.length > 0){
            var id  = mcService.getIdxByNameFromData($scope.grData, 'Name', 'Guests');

            mcConst.guestGroupId = $scope.grData[id].ID;

            $scope.grData.splice(id, 1);
        }

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        rcView = initGroupUsers($scope);

        $scope.selectFirstItemGroupList();

        mcService.initResize(rcView, $scope.Name);
    };

    $scope.getData = function(){
        if (!$rootScope.mcStorage[mcConst.dataModels.GroupRights]){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_list_roles,
                mcConst.SessionID,
                function(data){
                    $rootScope.mcStorage[mcConst.dataModels.GroupRights] = data;

                    $scope.show();
                }
            ]);
        }
    };

    $scope.$on('refresh' + $scope.Name, function(e, args){
        $scope.getGroupUsers(args[0]);
        //$scope.refresh.apply(null, args);
    });

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        if ($rootScope.mcStorage[mcConst.dataModels.GroupRights]){
            $scope.grData = [].concat($rootScope.mcStorage[mcConst.dataModels.GroupRights]);
            $scope.show();
        }

        if (!$scope.guestList || $scope.guestList.serialize().length == 0) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_list_roles,
                mcConst.SessionID,
                function(data){
                    $rootScope.mcStorage[mcConst.dataModels.GroupRights] = data;

                    $scope.grData = [].concat($rootScope.mcStorage[mcConst.dataModels.GroupRights]);
                    $scope.show();

                    $scope.getGroupUsers(mcConst.guestGroupId);
                }
            ]);

        }
    });
}
"use strict";

function initPluginAccess($scope){
    var view = $$($scope.Name);

    if (!view) {
        $scope.mcLEB_Allowed.initTextSource({
            add  : mcLang(50),
            del  : mcLang(52)
        });
        $scope.mcLEB_Blocked.initTextSource({
            add  : mcLang(50),
            del  : mcLang(52)
        });

        var allowed = $scope.mcLEB_Allowed.editButtons({
            actions: {
                add  : $scope.allowedActions.add,
                del  : $scope.allowedActions.del
            },
            actionTitles: {
                add  : mcLang(1761), // "1761":"Добавить плагин",
                del  : mcLang(1762)  // "1762":"Удалить плагин?<br><b>\"%s\"</b>",
            },
            delName  : "value",
            fillItems: ["value"],
            editTitle: mcLang(1764), // "1764":"Название",
            list     : "allowedList" + $scope.Name
        });

        var blocked = $scope.mcLEB_Blocked.editButtons({
            actions: {
                add  : $scope.blockedActions.add,
                del  : $scope.blockedActions.del
            },
            actionTitles: {
                add  : mcLang(1761), // "1761":"Добавить плагин",
                del  : mcLang(1762)  // "1762":"Удалить плагин?<br><b>\"%s\"</b>",
            },
            delName  : "value",
            fillItems: ["value"],
            editTitle: mcLang(1764), // "1764":"Название",
            list     : "blockedList" + $scope.Name
        });

        view = webix.ui({
            type: "space",
            padding: 5,
            container: $scope.Name,
            id: $scope.Name,
            borderless: true,
            rows: [
                { cols: [
                    { view: "template", type: "header", template: mcService.Lang(1758) }, // "1758":"Доступ к плагинам",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: "layout", cols: [
                    { rows: [
                        { template: mcLang(1759), type: "header", autoheight: true}, // "1759":"Разрешенные плагины",

                        allowed.btnList,

                        { view: "list", id: "allowedList" + $scope.Name, select: true }
                    ]},

                    { width: 7},

                    { rows: [
                        { template: mcLang(1760), type: "header", autoheight: true}, // "1760":"Запрещенные плагины",

                        blocked.btnList,

                        { view: "list", id: "blockedList" + $scope.Name, select: true }
                    ]}
                ]}
            ]
        });

        $scope.allowedList = $$("allowedList" + $scope.Name);
        $scope.blockedList = $$("blockedList" + $scope.Name);

        mcService.disableContextMenu(view);
    } else {
        $scope.allowedList.clearAll();
        $scope.allowedList.parse($scope.data.allowedList);

        $scope.blockedList.clearAll();
        $scope.blockedList.parse($scope.data.blockedList);
    }

    return view;
}
"use strict";

function pluginAccessController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.PluginAccess;

    var angElement = document.getElementById($scope.Name);
    var view = null;

    $scope.mcLEB_Allowed = new window.mcWidgets.ListEditButtons($rootScope);
    $scope.mcLEB_Blocked = new window.mcWidgets.ListEditButtons($rootScope);

    $scope.allowedActions = {};
    $scope.blockedActions = {};

    $scope.data = {
        allowedList : {},
        blockedList : {}
    };

    function checkDuplicate (name){
        return mcService.inArrayLowerCase(name, $scope.data.allowedList) == -1 && mcService.inArrayLowerCase(name, $scope.data.blockedList) == -1;
    }

    function checkName(name){
        var _name = mcService.trim(name);
        var res   = false;

        if ((_name != '') && mcService.isSymbolicNumbers(_name) && checkDuplicate(_name)){
            res = true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1763)]); // "1763":"Название плагина не должно быть пустым и совпадать с уже существующим!",
        }

        return res;
    }

    function add(listName) {
        var form = this;
        var name = form.getChildViews()[0].getValue();

        if (checkName(name)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_add_allowed_or_blocked_plugins,
                mcConst.SessionID,
                name,
                listName == 'allowedList' ? 0 : 1,
                function () {
                    var list = $scope[listName];

                    list.add({
                        id   : webix.uid(),
                        value: name
                    });
                    list.select(list.getLastId());
                    list.scrollTo(0, 9999);

                    $scope.data[listName].push(name);
                }
            ]);
        } else {
            return true;
        }
    }

    function del(item, listName) {
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_delete_allowed_or_blocked_plugin,
            mcConst.SessionID,
            item.value,
            listName == 'allowedList' ? 0 : 1,
            function(){
                var r_id = $scope.data[listName].indexOf(item.value);
                var list = $scope[listName];

                list.remove(item.id);
                list.select(list.getFirstId());

                if (r_id != -1) {
                    $scope.data[listName].splice(r_id, 1);
                }
            }
        ]);
    }

    $scope.allowedActions.add = function () {
        return add.call(this, "allowedList");
    };

    $scope.allowedActions.del = function (item) {
        del(item, "allowedList");
    };

    $scope.blockedActions.add = function () {
        return add.call(this, "blockedList");
    };

    $scope.blockedActions.del = function (item) {
        del(item, "blockedList");
    };

    $scope.show = function (){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        view = initPluginAccess($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_allowed_and_blocked_plugins,
            mcConst.SessionID,
            function(data){
                $scope.data.allowedList = data.Allowed ? data.Allowed.split(',') : [];
                $scope.data.blockedList = data.Blocked ? data.Blocked.split(',') : [];

                $scope.show();
            }
        ]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.show();

        $scope.getData();
    });
}
function initSettingsNetwork($scope){
    "use strict";

    var labelWidth   = 380;
    var blockWidth   = 600;

    var ipType = [
        { id : '0', value : "IPv4"},// 0.0.0.0
        { id : '1', value : "IPv6"} // ::
    ];

    var settings = $$($scope.Name);

    if (settings){
        settings.destructor();
    }

    settings = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(591) }, // "591": "Сетевые настройки",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [
                { rows : [
                    { view: "text", id: "stgTCPPort", value: $scope.data.TCPPort, disabled: _gLock.TCPPort || false, labelWidth: labelWidth, label: mcService.Lang(593), width: blockWidth,
                        mcType: "port", on: {
                            onChange: $scope.change,
                            onTimedKeyPress: $scope.changeExc
                        }
                    }, //"593": "TCP порт",
                    { view: "select",  id: "stgIPVer",   value: $scope.data.IPVer.toString(),  disabled: _gLock.IPVer || false, labelWidth: labelWidth, label: mcService.Lang(592), width: blockWidth, options: ipType,          on: {onChange: $scope.changeIpType} },  //"592": "Версия IP",
                    { view: "select",  id: "stgBind",    value: $scope.data.Bind,    disabled: _gLock.Bind || false,  labelWidth: labelWidth, label: mcService.Lang(594), width: blockWidth, options: $scope.data.IPs, on: {onChange: $scope.change} }, // "594": "Привязка сервера к IP (bind)",
                    { view  : "text",  id: "stgExternalIP",value: $scope.data.ExternalIP,  disabled: _gLock.ExternalIP || false, labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(931), // "931":"IP или Host адрес сервера для внешних клиентов",
                        on: {
                            onTimedKeyPress: function() {
                                $scope.change.apply(this, arguments);
                            }
                        }
                    },
                    { height : 5 },
                    { template: mcService.insertIco("fa-info-circle") + mcService.Lang(643), width: blockWidth, autoheight: true, borderless: true, css: "_info selectable" } // "643": "<b>Описание</b>: IP адрес сервера для клиентов, которые подключаются извне (Интернет или другие сети), если сервер MyChat находится в DMZ или за NAT. Если сервер только в локальной сети &#151; оставить пустым",
                ]}, {}
            ]},
            { type: 'layout', padding: 5, cols: [
                { rows : [
                    { view: "checkbox", id: "stgUseConnPass", value: $scope.data.UseConnPass, labelWidth: 0, labelRight: mcService.Lang(595),  width: 450, css: "finger", on: {onChange: $scope.change} }, // "595": "Использовать пароль для подключения клиентов к серверу",
                    { cols: [
                        { view: "text",     id: "stgConnPass",    value: $scope.data.ConnPass,    labelWidth: labelWidth, type: "password",  width: blockWidth,
                            label: mcService.Lang(1720), // "1720":"Пароль доступа к серверу",
                            on: {
                                onTimedKeyPress: function (newV, oldV) {
                                    var newPwd = mcService.trim(this.getValue());

                                    if (newPwd || !$$("stgUseConnPass").getValue()){
                                        $scope.change.apply(this, [newPwd, oldV]);
                                    } else {
                                        this.setValue($scope.data.ConnPass);
                                    }
                                }
                            }
                        },
                        { view: "toggle", width: 30, offIcon: "eye", onIcon: "eye-slash",  type:"icon", css: "noBG", tooltip: mcLang(1100) + "/" + mcLang(1099).toLowerCase(), // "1100":"Скрыть", "1099":"Показать",
                            on: { onChange: function (val) {
                                var pwd = $$("stgConnPass");

                                if (val) {
                                    pwd.define('type', 'text');
                                } else {
                                    pwd.define('type', 'password');
                                }

                                pwd.refresh();
                                pwd.getInputNode().setAttribute("autocomplete", "new-password");
                            }}
                        }
                    ]}
                ]}, {}]
            },

            /*{ type: 'layout', padding: 5, cols: [
                { rows : [
                    { template: mcService.insertIco("fa-info-circle") + mcLang(2114), width: blockWidth, autoheight: true, borderless: true, css: "_info"}, // "2114":"Проверка доступности вашего сервера из интернета.<br><br>В процессе проверки будет отправлен запрос на mychat-server.com для теста ваших портов.",
                    { id: "stgCheckBtn", view: "button", value: mcLang(926), click: $scope.checkExternalConnections}, // "926":"Проверить подключение",
                    { id: "stgCheckConnectionsResult", template: "&nbsp;", css: "monospace selectable", width: blockWidth, autoheight: true, hidden: true}
                ]},
                {}
            ]},*/

            // { type: 'layout', padding: 5, rows : [
            //     { view: "checkbox", id: "stgOnlySecuredLogin", value: $scope.data.OnlySecuredLogin, labelWidth: 0, labelRight: mcService.Lang(875),  css: "finger", on: {onChange: $scope.change}, disabled: $scope.data.isFree } // "875":"Запретить подключение клиентам, у которых отключено шифрование",
            // ]},
            {}
        ]
    });

    // $scope.stgCheckBtn               = $$("stgCheckBtn");
    // $scope.stgCheckConnectionsResult = $$("stgCheckConnectionsResult");

    $$("stgExternalIP").getInputNode().setAttribute("autocomplete", "new-password");
    $$("stgConnPass").getInputNode().setAttribute("autocomplete", "new-password");
    $$("stgExternalIP").getInputNode().addEventListener("paste", function (event) {
        var txt = (event.clipboardData || window.clipboardData).getData('text');
        
        $scope.change.apply($$("stgExternalIP"), [txt]);
    });

    mcService.disableContextMenu(settings);

    return settings;
}

function settingsNetworkController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsNetwork;
    var angElement = document.getElementById($scope.Name);

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(data){
        if (
            !((Object.keys(data).length == 1 && (data.hasOwnProperty("UseConnPass") || data.hasOwnProperty("ConnPass"))) ||
              (Object.keys(data).length == 2 && data.hasOwnProperty("ConnPass") && data.hasOwnProperty("UseConnPass")))
        ){
            mcConst.restartOptions[0] = mcConst.restartItems.MyChat;

            $rootScope.$broadcast('NeedRestartServer', []);
        }

        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

/*
    $scope.checkExternalConnections = function (){
        if ($rootScope.mcStorage.SettingsNetwork.ExternalIP) {
            $rootScope.$broadcast(mcConst.lockInterface);

            $scope.stgCheckConnectionsResult.show();

            var url = "http" + ($rootScope.mcStorage.SettingsNetwork.WEBUseSSL ? "s" : "") + "://mychat-server.com" + ($rootScope.mcStorage.SettingsNetwork.WEBUseSSL ? ":8484" : "");

            var turnPort = $rootScope.mcStorage.SettingsNetwork.TURNPortTCP;

            if (!$rootScope.mcStorage.SettingsNetwork.TURNUseAutoConfig){
                var configFile = $rootScope.mcStorage.SettingsNetwork.TURNFullTextConfig;

                if (mcService.isString(configFile)){
                    configFile = configFile.replace(/\r/g, "").split('\n');

                    for (var i=0; i < configFile.length; i++){
                        var line = mcService.trim(configFile[i]);

                        if (line.indexOf("listening-port") === 0){
                            turnPort = line.split("=")[1];
                            turnPort = parseInt(turnPort);

                            break;
                        }
                    }
                }
            }

            var outData = {
                HOST : $rootScope.mcStorage.SettingsNetwork.ExternalIP,
                SSL  : $rootScope.mcStorage.SettingsNetwork.WEBUseSSL,
                WEB  : $rootScope.mcStorage.SettingsNetwork.WEBTCPPort,
                CORE : $rootScope.mcStorage.SettingsNetwork.TCPPort,
                TURN : isNaN(turnPort) ? $rootScope.mcStorage.SettingsNetwork.TURNPortTCP : turnPort,
                FTP  : $rootScope.mcStorage.SettingsNetwork.FTPPort
            };

            url = url + "/checkMyPorts?q=" + encodeURI(JSON.stringify(outData));

            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.checkPush,
                mcConst.SessionID,

                function (push) {
                    mcService.jsonp(url, function (result) {
                        $rootScope.$broadcast("hide" + mcConst.lockInterface);

                        var input = "Result: " + result + "<br><br>URL: " + url + "<br><br>Request: " + JSON.stringify(outData);

                        if (result === "incorrect data") {
                            $scope.stgCheckConnectionsResult.define("template", input);
                        } else {
                            var data = mcService.StringToObj(result);

                            if (mcService.isObject(data)) {
                                $scope.stgCheckConnectionsResult.define("template", mcService.myReplaceFormated(
                                    "#{HOST}<br>" +
                                    "#{SSL} <br>" +
                                    "#{WEB} <br>" +
                                    "#{CORE}<br>" +
                                    "#{TURN}<br>" +
                                    "#{PUSH}<br>" +
                                    "#{FTP} <br><br>" +
                                    "Request: " + JSON.stringify(outData),
                                    {
                                        HOST: "HOST: " + (data.HOST === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2117) // "2117":"Внешний адрес доступен",
                                            : mcService.insertIco("fa-close", "red") + data.HOST),
                                        SSL: "SSL : " + ($rootScope.mcStorage.SettingsNetwork.WEBUseSSL ? (data.SSL === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2118) // "2118":"Сертификат проверен",
                                            : mcService.insertIco("fa-close", "red") + data.SSL) : mcLang(2123)), // "2123":"Не используется",
                                        WEB: "WEB : " + (data.WEB === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2119) // "2119":"Web-сервер доступен",
                                            : mcService.insertIco("fa-close", "red") + data.WEB),
                                        CORE: "CORE: " + (data.CORE === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2120) // "2120":"MyChat доступен",
                                            : mcService.insertIco("fa-close", "red") + data.CORE),
                                        TURN: "TURN: " + (data.TURN === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2121) // "2121":"TURN для звонков доступен",
                                            : mcService.insertIco("fa-close", "red") + data.TURN),
                                        FTP: "FTP : " + (data.FTP === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2122) // "2122":"файловый сервер доступен",
                                            : mcService.insertIco("fa-close", "red") + data.FTP),
                                        PUSH: "PUSH: " + (push === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2124) // "2124":"Отправка PUSH сообщений",
                                            : mcService.insertIco("fa-close", "red") + push)
                                    }
                                ));
                            } else {
                                $scope.stgCheckConnectionsResult.define("template", input);
                            }
                        }

                        $scope.stgCheckConnectionsResult.refresh();
                    }, function () {
                        $rootScope.$broadcast("hide" + mcConst.lockInterface);

                        $scope.stgCheckConnectionsResult.define("template", mcLang(2116)); // "2116":"Нет доступа к mychat-server.com",
                        $scope.stgCheckConnectionsResult.refresh();
                    });
                }
            ]);
        } else {
            $scope.stgCheckConnectionsResult.show();
            $scope.stgCheckConnectionsResult.define("template", mcLang(2115) + " \"" + mcLang(931) + "\""); // "2115":"Не указан", "931":"IP или Host адрес сервера для внешних клиентов",
            $scope.stgCheckConnectionsResult.refresh();
        }
    };
*/

    $scope.changeIpType = function(newVal){
        // $scope.data.IPVer = newVal;
        $scope.data.IPs   = mcService.networkInterfaces(newVal, $scope.data.networkInterfaces);

        var ip = $$('stgBind');

        ip.define('options', $scope.data.IPs);
        ip.define('value', 0);

        ip.refresh();

        $scope.change.apply(this, [newVal]);
    };

    $scope.show = function(){
        $scope.data                   = $rootScope.mcStorage.SettingsNetwork || {};
        $scope.data.networkInterfaces = $rootScope.mcStorage.networkInterfaces;
        $scope.data.IPs               = mcService.networkInterfaces($scope.data.IPVer, $scope.data.networkInterfaces);
        $scope.data.isFree            = $rootScope.mcStorage.ServerInfo.Free;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsNetwork($scope);

        mcService.initResize(settings, $scope.Name);

        // $scope.stgCheckBtn.show();
        // $scope.stgCheckConnectionsResult.hide();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.getMcSettings($rootScope, $scope.show, true);
    });
}
function initSettingsInfo($scope) {
    "use strict";

    var labelWidth     = 200;
    var blockWidth     = 550;
    var textAreaHeight = 105;

    var settings = $$($scope.Name);

    if (settings){
        settings.destructor();
    }

    settings = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type: "header", template: mcService.Lang(596) }, // "596":"Информация о сервере",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5,
                cols : [
                { /*view: "form", borderless: true,*/ rows : [
                    { view: "text", id:'stgServName', disabled: $scope.isFree, value: $scope.data.ServName,  labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(604), // "604": "Название сервера",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { view: "text", id:'stgServAdmin', value: $scope.data.ServAdmin, labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(605), // "605": "Администратор",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { view: "text", id:'stgAdminEmail', disabled: $scope.isFree, value: $scope.data.AdminEmail,labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(606), // "606": "E-mail",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { view: "text", id:'stgAdminWEB',  value: $scope.data.AdminWEB,  labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(607), // "607": "WEB-site",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { view: "text", id:'stgRobotName', value: $scope.data.RobotName, labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(608), // "608": "Имя встроенного робота",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    }
                    // { view: "text", id:'stgRobotAvatarNum', value: $scope.data.RobotAvatarNum, labelWidth: labelWidth, width: blockWidth,
                    //     label: mcService.Lang(668), // "668": "Номер аватара робота",
                    //     on: {
                    //         onTimedKeyPress: $scope.change
                    //     }
                    // }
                ]}, {}]
            },

            { view: "template", type: "header", template: mcService.Lang(609) }, // "609": "Сообщение для клиента, передаваемое после подключения",
            { type: 'layout', padding: 5, rows : [
                { view: "textarea", id:'stgConnectMsg', value: $scope.data.ConnectMsg, css: 'textArea horizontalScroll',
                    on: {
                        onTimedKeyPress: $scope.change
                    }
                }
            ]},

            { view: "template", type: "header", template: mcService.Lang(610) }, // "610": "Сообщение для клиента, который подключается в приват к роботу",
            { type: 'layout', padding: 5, rows : [
                { view: "textarea", id:'stgRobotHelloMsg', value: $scope.data.RobotHelloMsg, scroll: "xy", css: 'textArea',
                    on: {
                        onTimedKeyPress: $scope.change
                    }
                }
            ]}
        ]
    });

    mcService.disableContextMenu(settings);

    return settings;
}
function settingsInfoController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsInfo;
    var angElement = document.getElementById($scope.Name);

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.show = function(data){
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};

        $scope.isFree = $rootScope.mcStorage.ServerInfo.Free;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsInfo($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, $scope.show);
    });
}

function initSettingsLogs($scope){
    "use strict";

    var btnWidth = 220;
    var logs     = $$($scope.Name);
    var logLevels= [];

    if (logs){
        logs.destructor();
    }

    Object.keys(mcConst._CMD_.serverLogLevel).forEach(function (t) {
        logLevels.push({
            id   : mcConst._CMD_.serverLogLevel[t],
            value: t
        });
    });

    logs = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type: "header", template: mcService.Lang(598) },
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5, cols: [
                { view: "select",   id: "stgSysEventsLogLevel", value:$scope.data.SysEventsLogLevel, label: mcService.Lang(1929), labelWidth: 200, width: 400, options: logLevels, css: "finger", on: {onChange: $scope.change} }, // "1929":"Уровень логирования",
                {}
            ]},
            { type: 'layout', padding : 5, cols : [{
                rows: [
                    { view: "checkbox", id: "stgLogFTP",       value:$scope.data.LogFTP,        labelRight: mcService.Lang(613), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "613": "Протокол FTP",
                    { view: "checkbox", id: "stgLogModerators",value:$scope.data.LogModerators, labelRight: mcService.Lang(614), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "614": "Дествия модераторов",
                    { view: "checkbox", id: "stgLogScripts",   value:$scope.data.LogScripts,    labelRight: mcService.Lang(615), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "615": "Протоколы работы скриптов MSL",
                    { view: "checkbox", id: "stgLogBBS",       value:$scope.data.LogBBS,        labelRight: mcService.Lang(616), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "616": "Доска объявлений",
                    { view: "checkbox", id: "stgLogConsole",   value:$scope.data.LogConsole,    labelRight: mcService.Lang(617), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "617": "Консольные команды",
                    { view: "checkbox", id: "stgLogBroadcasts",value:$scope.data.LogBroadcasts, labelRight: mcService.Lang(822), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "822":"Оповещения",
                    { view: "checkbox", id: "stgLogFiles",     value:$scope.data.LogFiles,      labelRight: mcService.Lang(618), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "618": "Передача файлов",
                    { hidden: true, view: "checkbox", id: "stgLogConf",      value:$scope.data.LogConf,       labelRight: mcService.Lang(31),  labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }, // "31" : "Конференции",
                    { hidden: true, view: "checkbox", id: "stgLogPrivates",  value:$scope.data.LogPrivates,   labelRight: mcService.Lang(620), labelWidth: 0, width: 400, css: "finger", on: {onChange: $scope.change} }  // "620": "Протоколы приватов",
                ]
            }, {}]},
            { type: 'layout', padding: 5, cols: [
                { view: "button", value: mcService.Lang(622), id: "", width: btnWidth, type: "danger", click: $scope.clearLogs }, // "622": "Очистить все протоколы",
                {}
            ]},
            {}
        ]
    });

    mcService.disableContextMenu(logs);

    return logs;
}


function settingsLogsController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsLogs;
    var angElement = document.getElementById($scope.Name);

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.clearLogs = function(){
        $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
            type  : "confirm-warning",
            text  : mcService.Lang(670), // "670": "Удалить все протоколы за все время работы сервера?",
            ok    : mcService.Lang(581), // "581": "Удалить",
            cancel: mcService.Lang(103), // "103": "Отмена",
            callback:function(yes){
                if (yes){
                    $rootScope.$broadcast('SendCMDToServer', [
                        mcConst.lockInterface,
                        mcConst._CMD_.cs_adm_remove_all_logs,
                        mcConst.SessionID
                    ]);

                    webix.message(mcService.Lang(671)); // "671": "Протоколы удалены",
                }
            }
        }));
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){ // data
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsLogs($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, $scope.show);
    });
}

function initSettingsFTP($scope){
    "use strict";

    var labelWidth   = 300;
    var blockWidth   = 500;

    var pool = [
        { id : '0', value : "10"},
        { id : '1', value : "30"},
        { id : '2', value : "50"},
        { id : '3', value : "100"},
        { id : '4', value : "200"},
        { id : '5', value : "400"},
        { id : '6', value : "800"},
        { id : '7', value : "1000"}
    ];
    var poolID = $scope.getPoolID($scope.data.FTPPortsPool.toString());

    var ftp = $$($scope.Name);

    if (ftp){
        ftp.destructor();
    }

    ftp = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            {  cols: [
                { view : "template", type : "header", template : mcService.Lang(599) }, // "599": "FTP файловый сервер",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            {
                type : 'layout',
                padding : 5,
                cols : [{
                    rows: [
                        { view: "checkbox", id: "stgFTPServer", value: $scope.data.FTPServer, labelWidth: 0, width: 400, css: "finger",
                            labelRight: mcService.Lang(623), // "623": "Включить встроенный FTP сервер",
                            on: {
                                onChange: $scope.change
                            }
                        }
                    ]
                }, {}]
            },
            { view : "template", type : "header", template : mcService.Lang(591) }, // "591": "Сетевые настройки",
            {
                type : 'layout',
                padding : 5,
                cols : [{
                    rows: [
                        { view: "select", id: "stgFTPBind", value: $scope.data.FTPBind, disabled: _gLock.FTPBind || false,  labelWidth: labelWidth, width: blockWidth, options: $scope.data.IPs,
                            label: mcService.Lang(594), // "594": "Привязка сервера к IP (bind)",
                            on: {
                                onChange: $scope.change
                            }
                        },
                        { cols: [
                            { view: "text", id: "stgFTPPort", value: $scope.data.FTPPort, disabled: _gLock.FTPPort || false, labelWidth: labelWidth, width: blockWidth - 70,
                                label: mcService.Lang(625), mcType: "port", //"625": "Диапазон TCP портов",
                                on: {
                                    onChange: $scope.changeStartPool,
                                    onTimedKeyPress: $scope.changeExc
                                }
                            },
                            { view: "template",id: "stgFtpEndPool", borderless: true, width: 70, template: function(){
                                return "<span style='line-height: 21px'>" + mcService.Lang(634) + " <b>" + ($scope.data.FTPPort + $scope.data.FTPPortsPool) + "</b></span>";
                            }}]
                        },
                        { view: "select", id: "stgFTPPortsPool",  disabled: _gLock.FTPPortsPool || false, value: poolID, labelWidth: labelWidth, width: blockWidth, options: pool,
                            label: mcService.Lang(626), // "626": "Пул портов",
                            on: {
                                onChange: $scope.changeEndPool
                            }
                        }
                    ]
                }, {}]
            }, /*{
                type : 'layout',
                padding : 5,
                cols : [{
                    rows: [
                        { view  : "text", id: "stgExternalIP", value: $scope.data.ExternalIP, disabled: _gLock.ExternalIP || false,  labelWidth : labelWidth,
                        // { view  : "text", id: "stgFTPExternalIP", value: $scope.data.FTPExternalIP, disabled: _gLock.FTPExternalIP || false,  labelWidth : labelWidth,
                            label: mcService.Lang(627), // "627": "IP адрес FTP сервера для внешних клиентов
                            on: {
                                onTimedKeyPress: function () {
                                    var inp = this.getInputNode();
                                    var pos = mcService.getCaretPosition(inp);
                                    var sel = mcService.getSelectedText(inp);
                                    var val = mcService.trim(this.getValue());

                                    if (mcService.isValidIpAddress(val) || val === "" || val.indexOf(":") !== -1){
                                        $scope.change.apply(this, arguments);

                                        this.$view.className = this.$view.className.replace("errorArea", "");
                                    } else
                                    if (this.$view.className.indexOf("errorArea") === -1) {
                                        this.$view.className += " errorArea";
                                    }

                                    mcService.setCaretPosition(inp, pos);
                                    mcService.setSelectionText(inp, sel.selectionStart, sel.selectionEnd);
                                }
                            }
                        }
                        // { height : 5 },
                        // { template: mcService.insertIco("fa-info-circle") + mcService.Lang(643), width: blockWidth, autoheight: true, borderless: true, css: "_info selectable" } // "643": "<b>Описание</b>: IP адрес FTP сервера для клиентов, которые подключаются извне (Интернет или другие сети), если сервер MyChat находится в DMZ или за NAT. Если сервер только в локальной сети &#151; оставить пустым",
                    ]
                }, {}]
            },*/
            { view : "template", type : "header", template : mcService.Lang(635) }, // "635": "Размещение файлов FTP сервера",
            {
                type : 'layout',
                padding : 5,
                cols : [{
                    view : 'form',
                    padding: 1,
                    rules: {
                        "pubDir"  : function (val){
                            return webix.rules.isNotEmpty(val) && this.elements["pubDir"].getValue() !== this.elements["privDir"].getValue();
                        },
                        "privDir" : function(val) {
                            return webix.rules.isNotEmpty(val) && this.elements["pubDir"].getValue() !== this.elements["privDir"].getValue();
                        }
                    },
                    borderless: true,
                    elements: [
                        { view: "text", id: "stgFTPPublicDir",   value: $scope.data.FTPPublicDir,  disabled: _gLock.FTPPublicDir || false,   labelPosition: "top",  width: blockWidth,
                            required : "true",
                            name     : "pubDir",
                            invalidMessage: mcLang(2069),   // "2069":"FTP пути не могут совпадать и не должны быть пустыми",
                            label    : mcService.Lang(628), // "628": "Общий каталог для всех пользователей сервера MyChat",
                            on       : {
                                onTimedKeyPress: $scope.checkDirs
                            }
                        },
                        { view: "text", id: "stgFTPPersonalDir", value: $scope.data.FTPPersonalDir,  disabled: _gLock.FTPPersonalDir || false, labelPosition: "top",  width: blockWidth,
                            required : "true",
                            name     : "privDir",
                            invalidMessage: mcLang(2069),   // "2069":"FTP пути не могут совпадать и не должны быть пустыми",
                            label    : mcService.Lang(629), // "629": "Каталог для зарегистрированных пользователей",
                            on       : {
                                onTimedKeyPress: $scope.checkDirs
                            }
                        }
                    ]
                }, {}]
            },
            { view : "template", type : "header", template : mcService.Lang(636) }, // "636": "Публичный доступ",
            {
                type : 'layout',
                padding : 5,
                cols : [{
                    rows: [
                        { view: "checkbox", id: "stgFTPPublicAccess",  value: $scope.data.FTPPublicAccess,   labelWidth: 0, width: 400, css: "finger" ,
                            labelRight: mcService.Lang(630), // "630": "Включить публичный доступ",
                            on: {
                                onChange: $scope.change
                            }
                        },

                        { view: "text",     id: "stgFTPPublicLogin",   value: $scope.data.FTPPublicLogin,    labelWidth: labelWidth - 150, width: blockWidth - 150 ,
                            label: mcService.Lang(631), // "631": "Публичный логин",
                            on: {
                                onTimedKeyPress: $scope.change
                            }
                        },
                        { cols: [
                            { view: "text",     id: "stgFTPPublicPass",    value: $scope.data.FTPPublicPass,     labelWidth: labelWidth - 150, width: blockWidth - 150, type: "password" ,
                                label: mcService.Lang(632), // "632": "Публичный пароль",
                                on: {
                                    onTimedKeyPress : function(){
                                        mcService.typeFlag('ftpDispLang', 'stgFTPPublicPass');

                                        $scope.change.apply(this, arguments);
                                    }
                                }
                            },
                            { view: "toggle", width: 30, offIcon: "eye", onIcon: "eye-slash",  type:"icon", css: "noBG", tooltip: mcLang(1100) + "/" + mcLang(1099).toLowerCase(), // "1100":"Скрыть", "1099":"Показать",
                                on: { onChange: function (val) {
                                    var pwd = $$("stgFTPPublicPass");

                                    if (val) {
                                        pwd.define('type', 'text');
                                    } else {
                                        pwd.define('type', 'password');
                                    }

                                    pwd.refresh();
                                    pwd.getInputNode().setAttribute("autocomplete", "new-password");
                                }}
                            },
                            { id : 'ftpDispLang',
                                template : 'EN',
                                width    : 23,
                                borderless : true
                            }
                        ]},

                        { view: "checkbox", id: "stgFTPPublicReadOnly",value: $scope.data.FTPPublicReadOnly, labelWidth: 0, width: 400, css: "finger" ,
                            labelRight: mcService.Lang(633), // "633": "Режим \"Только для чтения\"",
                            on: {
                                onChange: $scope.change
                            }
                        }
                    ]
                }, {}]
            },
            {}
        ]
    });

    $$("stgFTPPublicLogin").getInputNode().setAttribute("autocomplete", "new-password");
    $$("stgFTPPublicPass").getInputNode().setAttribute("autocomplete", "new-password");

    mcService.disableContextMenu(ftp);

    return ftp;
}
function settingsFTPController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsFTP;
    var angElement = document.getElementById($scope.Name);
    var pool = ["10","30","50","100","200","400","800","1000"];
    var backupData = {};

    $scope.data = {};

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        mcConst.restartOptions[2] = mcConst.restartItems.FTP;

        $rootScope.$broadcast('NeedRestartServer', []);

        backupData = mcService.Marge($scope.data, $rootScope.mcStorage.SettingsNetwork || {});

        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.checkDirs = function(){
        if (this.getFormView().validate()) {
            $scope.change.apply(this, arguments);
        } else {
            $rootScope.$broadcast('hide' + mcConst.dataModels.ApplyPanel, []);
        }
    };

    $scope._onApply = function (data) {
        if (data.FTPPublicLogin === '') {
            data.FTPPublicLogin = 'mcuser';

            $$('stgFTPPublicLogin').setValue(data.FTPPublicLogin);
        }

        if (data.FTPPublicPass === '') {
            data.FTPPublicPass = 'mychat';

            $$('stgFTPPublicPass').setValue(data.FTPPublicPass);
        }
    };

    $scope.getPoolID = function(id){
        return pool.indexOf(id);
    };

    $scope.getPoolVal = function(id){
        return pool[id];
    };

    $scope.changeStartPool = function(newVal){
        var endPool  = $$("stgFtpEndPool");
        var startPool= $$("stgFTPPortsPool");
        var val      = parseInt($scope.getPoolVal(startPool.getValue()));

        $scope.change.apply(this, [newVal]);

        endPool.define('template', "<span style='line-height: 21px'>" + mcService.Lang(634) + " <b>" + (parseInt(this.getValue()) + val) + "</b></span>");
        endPool.refresh();
    };

    $scope.changeEndPool = function(newVal){
        var endPool = $$("stgFtpEndPool");
        var val     = parseInt($$("stgFTPPort").getValue());
        var endVal  = parseInt($scope.getPoolVal(newVal));

        endPool.define('template', "<span style='line-height: 21px'>" + mcService.Lang(634) + " <b>" + (val + endVal) + "</b></span>");
        endPool.refresh();

        $scope.change.apply(this, [endVal]);
    };

    $scope.show = function(){
        $scope.data                   = mcService.Marge({}, $rootScope.mcStorage.SettingsNetwork || {});
        $scope.data.networkInterfaces = $rootScope.mcStorage.networkInterfaces;
        $scope.data.IPs               = mcService.networkInterfaces($scope.data.IPVer, $scope.data.networkInterfaces);

        backupData = mcService.Marge({}, $rootScope.mcStorage.SettingsNetwork || {});

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsFTP($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);

        $rootScope.ErrorActions[212] = null;
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, $scope.show);

        $rootScope.ErrorActions[212] = function () {
            $$("stgFTPPublicDir").setValue(backupData.FTPPublicDir);
            $$("stgFTPPersonalDir").setValue(backupData.FTPPersonalDir);
        };
    });
}


function initSettingsWEB ($scope){
    "use strict";

    var blockWidth = 550;
    var lbWdth     = 370;

    var hSeparate = function(){ return { height: 5}};

    var web = $$($scope.Name);

    if (web){
        web.destructor();
    }

    var compressStyle = [
        { id: '0', value: mcService.Lang(1528)}, // "1528":"без сжатия",
        { id: '1', value: mcService.Lang(1529)}, // "1529":"GZip",
        { id: '2', value: mcService.Lang(1530)}  // "1530":"Deflate",
    ];

    web = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(600) }, // "600": "WEB-сервисы",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            {
            type : 'layout',
            padding : 5,
            cols : [
                { width: blockWidth, rows: [
                    { view: "text", id: "stwWEBTCPPort",   value: $scope.data.WEBTCPPort, disabled: _gLock.WEBTCPPort || false,
                        label: mcService.Lang(593), width: 200, mcType: "port", on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc}}, // "593": "TCP порт",

                    { view: "checkbox",id: "stwWEBUseSSL", value: $scope.data.WEBUseSSL,  disabled: _gLock.WEBUseSSL || false, labelWidth: 0,
                        labelRight: mcService.Lang(1054), css: "finger", on: {onChange: $scope.changeUseCrypt} }, // "1054":"Использовать шифрование SSL",

                    { id: "whatSslKeyUse", hidden: !$scope.data.WEBUseSSL, rows: [
                        // { view: "label", label: mcLang(1809)}, // "1809":"Какие сертификаты использовать?",

                        // { id: "switchSslCase", view: "segmented", value: $scope.sslCaseUse, options: [
                        //     { id: $scope.sslCase.default, value: mcLang(1810) }, // "1810":"Встроенные",
                        //     { id: $scope.sslCase.custom,  value: mcLang(1811) }  // "1811":"Свои",
                        // ], on: {
                        //     onChange: $scope.changeSslUse
                        // }},

                        { id: "sslKeyUploadFields", /*hidden: $scope.sslCaseUse === $scope.sslCase.default,*/ rows: [
                            { cols: [
                                { view: "label", label: mcLang(1055)}, // "1055":"Публишный ключ (public.pem или sert.pem):",
                                { id: "statusWEBPublicKeyPath", view: "label", label: "[ " + ($scope.sslCaseUse == $scope.sslCase.default ? mcLang(1045) : mcLang(1046)) + " ]", width: 100, // "1045":"not exist", "1046":"есть",
                                    css: ($scope.sslCaseUse == $scope.sslCase.default ? "red" : "green")},

                                { view: "uploader", value: mcLang(1145), multiple: false, width: 150, //accept: "application/octet-stream", //"1145":"Загрузить",
                                    upload: "/uploading?sid=" + mcConst.SessionID + "&issert=true&sertfile=private.crt", accept: ".crt,.pem,.key,.cer",
                                    on: {
                                        onBeforeFileAdd  : $scope.beforeUpload,
                                        onFileUpload     : function (file) {
                                            $scope.uploadSuccess('WEBPublicKeyPath', file.fileName);
                                        },
                                        onFileUploadError: $scope.uploadError
                                    }
                                }
                            ]},

                            { cols: [
                                { view: "label", label: mcLang(1056)}, // "1056":"Приватный ключ (private.pem или key.pem):",
                                { id: "statusWEBPrivateKeyPath", view: "label", label: "[ " + ($scope.sslCaseUse == $scope.sslCase.default ? mcLang(1045) : mcLang(1046)) + " ]", width: 100, // "1045":"not exist", "1046":"есть",
                                    css: ($scope.sslCaseUse == $scope.sslCase.default ? "red" : "green")},

                                { view: "uploader", value: mcLang(1145), multiple: false, width: 150, //accept: "application/octet-stream", //"1145":"Загрузить",
                                    upload: "/uploading?sid=" + mcConst.SessionID + "&issert=true&sertfile=private.crt", accept: ".crt,.pem,.key,.cer",
                                    on: {
                                        onBeforeFileAdd  : $scope.beforeUpload,
                                        onFileUpload     : function (file) {
                                            $scope.uploadSuccess('WEBPrivateKeyPath', file.fileName);
                                        },
                                        onFileUploadError: $scope.uploadError
                                    }
                                }
                            ]},

                            { rows: [
                                { view: "template", template: mcLang(1615), autoheight: true, borderless: true, padding: 0}, // "1615":"Файл центра сертификации \"Certification authority\" (bundle.crt или root.crt):",
                                { cols: [
                                    {},
                                    { id: "statusWEBBundleKeyPath", view: "label", label: "[ " + (!$scope.data.WEBBundleKeyPath ? mcLang(1045) : mcLang(1046)) + " ]", width: 100, // "1045":"not exist", "1046":"есть",
                                        css: (!$scope.data.WEBBundleKeyPath ? "red" : "green")},

                                    { view: "uploader", value: mcLang(1145), multiple: false, width: 150, //accept: "application/octet-stream", //"1145":"Загрузить",
                                        upload: "/uploading?sid=" + mcConst.SessionID + "&issert=true&sertfile=private.crt", accept: ".crt,.pem,.key,.cer",
                                        on: {
                                            onBeforeFileAdd  : $scope.beforeUpload,
                                            onFileUpload     : function (file) {
                                                $scope.uploadSuccess('WEBBundleKeyPath', file.fileName);
                                            },
                                            onFileUploadError: $scope.uploadError
                                        }
                                    }
                                ]}
                            ]},
                            // CertificatePWD
                            { rows: [
                                { view: "text", id: "stwCertificatePWD", type: "password",  value: $scope.data.CertificatePWD,
                                    label: mcService.Lang(1980), labelWidth: 300, // "1980":"Пароль приватного ключа, если есть:",
                                    on: { onTimedKeyPress: $scope.change }
                                },

                                { id: "sslInfo" + $scope.Name, template: "&nbsp;", hidden: true, autoheight: true, borderless: true, css: "_info" }
                            ]},
                        ]},

                        { height: 5},

                        { rows: [
                            { view: "text", id: "stwHTTPNoSSLPort",   value: $scope.data.HTTPNoSSLPort, disabled: _gLock.WEBTCPPort || false, labelWidth: 130,
                                label: mcLang(2215), width: 300, mcType: "port", on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc}}, // "2215":"Резервный порт",

                            { template: mcService.insertIco("fa-info-circle") + mcLang(2216), autoheight: true, borderless: true, css: "_info" } // "2216":"Резервный порт используется для WEB-сервера без SSL шифрования, чтобы клиенты на XP могли отправлять и получать файлы, а также скачивать обновления",
                        ]}

                    ]},

                    { view: "text", id: "stwWEBBundleKeyPath",  value: $scope.data.WEBBundleKeyPath,  hidden: true, label: "", on: {onChange: $scope.change}}, // "1615":"Путь к файлу центра сертификации \"Certification authority\" (bundle.crt или root.crt):",
                    { view: "text", id: "stwWEBPublicKeyPath",  value: $scope.data.WEBPublicKeyPath,  hidden: true, label: "", on: {onChange: $scope.change}}, // "1055":"Публишный ключ (public.pem или sert.pem):",
                    { view: "text", id: "stwWEBPrivateKeyPath", value: $scope.data.WEBPrivateKeyPath, hidden: true, label: "", on: {onChange: $scope.change}} // "1056":"Приватный ключ (private.pem или key.pem):",

                    /*hSeparate(),
                    { template: mcService.insertIco("fa-info-circle") + mcService.Lang(640), autoheight: true, borderless: true, css: "_info" } // "640": "Описание: TCP порт встроенного WEB-сервера, который предназначен для работы веб-чата (Web'o'Chat) и удаленной консоли управления (вы сейчас находитесь в ней). Если изменить порт &#151; потребуется перезагрузка веб-сервера",
                    */
                ]}, {}
            ]
        }, {
            type    : "layout",
            id      : "generateSslKey" + $scope.Name,
            padding : 5,
            // hidden  : $scope.sslCaseUse !== $scope.sslCase.custom,
            cols    : [
                { width: blockWidth, rows: [
                    { cols: [
                        { view: "label", label: mcLang(2089), width: 300}, // "2089":"Бесплатные Let's Encrypt сертификаты:",
                        { view: "button", value: mcLang(2088), click: $scope.createSllCert, disabled: _gLock.GenerateCert || false}, // "2088":"Сгенерировать ключи",
                    ]},
                    { view: "checkbox", id: "stwNeedRenewCertLe", value: false, disabled: _gLock.UpdateCert || false, labelWidth: 0, labelRight: mcLang(2091), css: "finger" }, // "2091":"Обновить существующий сертификат",

                    hSeparate(),
                    { template: mcService.insertIco("fa-info-circle") + mcService.Lang(2090), autoheight: true, borderless: true, css: "_info" }, // "2090":"Для создания бесплатных сертификатов, веб-сервер должен работать на

                    hSeparate(),
                    { id: "certGenLog" + $scope.Name, view: "template", template: "&nbsp;", height: 250, hidden: true, css: "Courier font90 selectable", scroll:  true }
                ]}, {}
            ]
        }, {
            type : 'layout',
            padding : 5,
            cols : [
                { width: blockWidth, rows: [
                    { view: "checkbox", id: "stwLobbyEnable", value: $scope.data.LobbyEnable, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(1938), // "1938":"Включить страницу приветствия сервера",
                        on: { onChange: $scope.change }
                    },
                    // "ForumEnable" : true, // (7.1+) включить доступ ко встроенному форуму
                    // "KanbanEnable" : true, // (7.1+) включить доступ к канбан-доске
                    // "ChatEnable" : true // (7.1+) включить доступ к WEB-чату
                    { view: "checkbox", id: "stwForumEnable", value: $scope.data.ForumEnable, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(1967), // "1967":"Включить доступ ко встроенному форуму",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stwKanbanEnable", value: $scope.data.KanbanEnable, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(1968), // "1968":"Включить доступ к канбан-доске",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stwChatEnable", value: $scope.data.ChatEnable, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(1969), // "1969":"Включить доступ к WEB-чату",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stwAdminEnable", value: $scope.data.AdminEnable, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(1979), // "1979":"Доступ к консоли управления",
                        on: { onChange: $scope.change }
                    }
                ]}, {}
            ]
        }, {
            type : 'layout',
            padding : 5,
            cols : [
                { width: blockWidth, rows: [
                    // "AliasAdmin" : "admin", // (7.1+) папка-псевдоним, путь к админке
                    // "AliasAPI" : "API", // (7.1+) папка-псевдоним, путь к Integration API
                    // "AliasChat" : "chat", // (7.1+) папка-псевдоним, путь к WEB-чату
                    // "AliasFiles" : "files", // (7.1+) папка-псевдоним, путь к файлам, залитым на сервер
                    // "AliasForum" : "forum", // (7.1+) папка-псевдоним, путь ко встроенному форуму
                    // "AliasKanban" : "kanban", // (7.1+) папка-псевдоним, путь к канбан-доске
                    // "AliasSupport" : "support", // (7.1+) папка-псевдоним, путь к веб-чату поддержки и MyChat Guest
                    { view: "label", label: mcLang(1977)}, // "1977":"Псевдоним пути:",

                    { cols: [
                        { width: 10},
                        { rows: [
                            { view: "text", id: "stwAliasAdmin",  value: $scope.data.AliasAdmin,   labelWidth: lbWdth - 10, pathAlias: true, label: mcLang(1970), on: {onTimedKeyPress: function() { $scope.change.apply(this, arguments); }}}, // "1970":"Путь к административной консоли",
                            { view: "text", id: "stwAliasAPI",    value: $scope.data.AliasAPI,     labelWidth: lbWdth - 10, pathAlias: true, label: mcLang(1971), on: {onTimedKeyPress: function() { $scope.change.apply(this, arguments); }}}, // "1971":"Путь к Integration API",
                            { view: "text", id: "stwAliasChat",   value: $scope.data.AliasChat,    labelWidth: lbWdth - 10, pathAlias: true, label: mcLang(1972), on: {onTimedKeyPress: function() { $scope.change.apply(this, arguments); }}}, // "1972":"Путь к WEB-чату",
                            { view: "text", id: "stwAliasFiles",  value: $scope.data.AliasFiles,   labelWidth: lbWdth - 10, pathAlias: true, label: mcLang(1973), on: {onTimedKeyPress: function() { $scope.change.apply(this, arguments); }}}, // "1973":"Путь к файлам, загруженным на сервер",
                            { view: "text", id: "stwAliasForum",  value: $scope.data.AliasForum,   labelWidth: lbWdth - 10, pathAlias: true, label: mcLang(1974), on: {onTimedKeyPress: function() { $scope.change.apply(this, arguments); }}}, // "1974":"Путь ко встроенному форуму",
                            { view: "text", id: "stwAliasKanban", value: $scope.data.AliasKanban,  labelWidth: lbWdth - 10, pathAlias: true, label: mcLang(1975), on: {onTimedKeyPress: function() { $scope.change.apply(this, arguments); }}}, // "1975":"Путь к канбан-доске",
                            { view: "text", id: "stwAliasSupport",value: $scope.data.AliasSupport, labelWidth: lbWdth - 10, pathAlias: true, label: mcLang(1976), on: {onTimedKeyPress: function() { $scope.change.apply(this, arguments); }}}  // "1976":"Путь к веб-чату поддержки и MyChat Guest",
                        ]}
                    ]},
                    hSeparate(),
                    { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1978), autoheight: true, borderless: true, css: "_info" } // "1978":"В псевдонимах можно использовать только латинские буквы, цифры и знак \"_\"!",
                ]}, {}
            ]
        }, /*{
            type : 'layout',
            padding : 5,
            cols : [
                { width: blockWidth, rows: [
                    { view: "checkbox",id: "stwWEBUseCache",       value: $scope.data.WEBUseCache,             disabled: _gLock.WEBUseCache || false, labelWidth: 0, labelRight: mcService.Lang(1526), css: "finger", on: {onChange: $scope.change} }, // "1526":"Включить кеширование WEB-сервера",
                    { view: "select",  id: "stwWEBCacheCompress",  value: $scope.data.WEBCacheCompress || '0', disabled: _gLock.WEBCacheCompress || false, label: mcService.Lang(1527), options: compressStyle, labelWidth: 240, on: {onChange: $scope.change} }, // "1527":"Сжатие кешированных данных:",
                    hSeparate(),
                    { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1531), autoheight: true, borderless: true, css: "_info" } // "1531":"После изменения параметров: кеширование и сжатие данных, необходимо перезапустить Веб-сервер",
                ]}, {}
            ]
        },*/ {
            view : "template",
            type : "header",
            template : mcService.Lang(639) // "639": "Настройка STUN",
        }, {
            type    : "layout",
            padding : 5,
            rows: [{ cols : [{
                rows : [
                    { view: "checkbox", id: "stwTURNUseAutoConfig", value: $scope.data.TURNUseAutoConfig, labelWidth: 0, css: "finger", disabled: _gLock.TURNUseAutoConfig || false,
                        labelRight: mcService.Lang(1648), // "1648":"Использоваться автоматическую настройку STUN/TURN",
                        on: { onChange: $scope.changeEx }
                    },
                    { view: "text",     id: "stwExternalIP",  value: $scope.data.ExternalIP, labelWidth: lbWdth,  disabled: _gLock.ExternalIP || false, width: blockWidth,
                        hidden: !$scope.data.TURNUseAutoConfig,
                        label: mcService.Lang(931), // "931":"IP или Host адрес сервера для внешних клиентов",
                        on: { onTimedKeyPress: function() { $scope.change.apply(this, arguments); } }
                    },
                    { view: "text",     id: "stwTURNPortTCP", value: $scope.data.TURNPortTCP, labelWidth: lbWdth,  disabled: _gLock.ExternalIP || false, width: blockWidth,
                        hidden: !$scope.data.TURNUseAutoConfig, mcType: "port",
                        label: mcService.Lang(1650), // "1650":"TCP порт STUN/TURN",
                        on: { onTimedKeyPress: function() { $scope.change.apply(this, arguments); } }
                    }
                ]
            }, {}]
            }, { cols : [{
                rows : [
                    { view: "textarea", id: "stwTURNFullTextConfig", hidden: !!$scope.data.TURNUseAutoConfig, value: $scope.data.TURNFullTextConfig,  labelPosition: 'top', height: 500,
                        label: mcService.Lang(1649), // "1649":"Ручная настройка STUN/TURN",
                        on: {onTimedKeyPress: $scope.change}
                    },
                    hSeparate()
                ]
            }, { width: 17}]
            }, { cols : [{
                rows : [
                    { view: "textarea", id: "stwTURNExternalConfig", hidden: $scope.data.TURNType == '0', value: $scope.data.TURNExternalConfig,  labelPosition: 'top', height: 500,
                        label: mcService.Lang(1649), // "1649":"Ручная настройка STUN/TURN",
                        placeholder: mcLang(1654), // "1654":"Пример:\n{\n  url: 'stun:mychat-server.com:8888'\n}
                        on: {onTimedKeyPress: $scope.change}
                    },
                    hSeparate()
                ]
            }, { width: 17}]
            }]
        }, {}]
    });

    $scope.switchSslCase         = $$("switchSslCase");
    $scope.sslKeyUploadFields    = $$("sslKeyUploadFields");
    $scope.whatSslKeyUse         = $$("whatSslKeyUse");
    $scope.sslInfo               = $$("sslInfo" + $scope.Name);
    $scope.ExternalIP            = $$("stwExternalIP");
    $scope.stgTURNFullTextConfig = $$("stwTURNFullTextConfig");
    $scope.stgTURNPortTCP        = $$("stwTURNPortTCP");
    $scope.stgTURNUseAutoConfig  = $$("stwTURNUseAutoConfig");
    $scope.stgTURNExternalConfig = $$("stwTURNExternalConfig");
    $scope.generateSslKey        = $$("generateSslKey" + $scope.Name);

    $scope.certGenLog            = $$("certGenLog" + $scope.Name);
    $scope.stwNeedRenewCertLe    = $$("stwNeedRenewCertLe");

    $scope.stwWEBBundleKeyPath  = $$("stwWEBBundleKeyPath");
    $scope.stwWEBPublicKeyPath  = $$("stwWEBPublicKeyPath");
    $scope.stwWEBPrivateKeyPath = $$("stwWEBPrivateKeyPath");

    
    mcService.disableContextMenu(web);

    return web;
}

function settingsWEBController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsWEB;
    var angElement = document.getElementById($scope.Name);

    var defaultSslPath = {
        "public"  : "defaultPublicKey",
        "private" : "defaultPrivateKeyPath"
    };

    var customKeyValue = {
        "public"  : "defaultPublicKey",
        "private" : "defaultPrivateKeyPath",
        "root"    : ""
    };

    $scope.data = null;

    $rootScope.ErrorActions[231]  = function (){ // "231": "порт \"%s\" для службы \"%s\" уже занят другим работающим приложением",
        mcService.getMcSettings($rootScope, $scope.show, true);
    };

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        mcConst.restartOptions[1] = mcConst.restartItems.WEB;

        $rootScope.$broadcast('NeedRestartServer', []);

        customKeyValue.private = $scope.data.WEBPrivateKeyPath;
        customKeyValue.public  = $scope.data.WEBPublicKeyPath;
        customKeyValue.root    = $scope.data.WEBBundleKeyPath;

        $rootScope.mcStorage.SettingsNetwork.WEBTCPPort = $scope.data.WEBTCPPort;

        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.sslCase = {
        "default" : "default",
        "custom"  : "custom"
    };

    $scope.sslCaseUse = $scope.sslCase.default;

    // ========================================================

    $scope.createSllCert = function(){
        $scope.certGenLog.define('template', "&nbsp;");
        $scope.certGenLog.refresh();

        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.generateCert,
            mcConst.SessionID,

            $rootScope.mcStorage.SettingsNetwork.ExternalIP,
            mcService.convertIntToBool($scope.stwNeedRenewCertLe.getValue()),

            function (res) {
                var codeDesc = "";

                switch (res.Result) {
                    case 0:
                        $scope.uploadSuccess("WEBPublicKeyPath",  res.crt);
                        $scope.uploadSuccess("WEBPrivateKeyPath", res.key);

                        codeDesc = "All fine!"; // : "Failed!";
                    break;

                    case 1:
                        codeDesc = "Failed! File mc_private.key not generated";
                    break;

                    case 2:
                        codeDesc = "Failed! File mc_public.crt not generated";
                    break;

                    case 3:
                        codeDesc = "Failed! File mc_public.crt not updated";
                    break;

                    case 4:
                        codeDesc = "Failed! Can't copy cert files to server storage";
                    break;

                    default:
                        codeDesc = "Failed!";
                }

                $scope.certGenLog.show();
                $scope.certGenLog.define('template', function () {
                    return mcService.myReplaceFormated(
                        "Result Code: #{code} - #{codeDesc}<br><br>" +
                        "Run generator: #{runString}<br>" +
                        "Exit code: #{exitCode}<br><br>" +
                        "=============== Result Log ===============<br>" +
                        "#{result}",
                        {
                            runString: res.Path,
                            exitCode : res.Code,
                            result   : res.Log.replace(/\n/g, "<br>"),
                            code     : res.Result,
                            codeDesc : codeDesc
                        }
                    );
                });
                $scope.certGenLog.refresh();
            }
        ]);
    };

    $scope.beforeUpload = function(item){
        var name = item.name.toLowerCase();

        if (!name){
            webix.alert(mcLang(1562)); //"1562":"Пожалуйста, укажите путь к файлу ",

            return false;
        }
    };

    $scope.uploadSuccess = function (key, fileName) {
        $$("stw" + key).setValue(fileName);
        var label = $$("status" + key);

        label.setValue("[ " + mcLang(1046) + " ]"); // "1046":"есть",
        label.getNode().className = label.getNode().className.replace(' red', '') + " green";
    };

    $scope.uploadError = function (item, res) {
        var text = "";

        try {
            text = item ? "<br>" + JSON.stringify(item.context) : "";
        } catch (e){}

        webix.alert(mcLang(1563) + text + (res ? "<br>" + res : "")); // "1563":"При загрузке файла возникла ошибка:",
    };

    $scope.changeSslUse = function (newVal) {
        switch (newVal){
            case $scope.sslCase.default:
                $scope.sslKeyUploadFields.hide();
                $scope.generateSslKey.hide();

                $scope.stwWEBBundleKeyPath. setValue("");
                $scope.stwWEBPublicKeyPath. setValue(defaultSslPath.public);
                $scope.stwWEBPrivateKeyPath.setValue(defaultSslPath.private);
            break;

            case $scope.sslCase.custom:
                $scope.sslKeyUploadFields.show();
                $scope.generateSslKey.show();

                $scope.stwWEBBundleKeyPath.setValue(customKeyValue.root);
                $scope.stwWEBPublicKeyPath.setValue(customKeyValue.public);
                $scope.stwWEBPrivateKeyPath.setValue(customKeyValue.private);
            break;
        }
    };

    $scope.changeUseCrypt = function (newV, oldV) {
        $scope.whatSslKeyUse[newV == '1' ? 'show' : 'hide']();

        mcConst.changeProtocol = 'http' + (newV == '1' ? 's' : '') + ':';

        $scope.change.apply(this, arguments);
    };

    $scope.changeEx = function (newV, oldV){
        if (newV == 0){
            $scope.stgTURNFullTextConfig.show();
            $scope.ExternalIP.hide();
            $scope.stgTURNPortTCP.hide();
        } else {
            $scope.stgTURNFullTextConfig.hide();
            $scope.ExternalIP.show();
            $scope.stgTURNPortTCP.show();
        }

        $scope.change.apply(this, arguments);
    };

    $scope.changeTurnType = function (newV, oldV){
        if (newV == '0'){
            if ($scope.stgTURNUseAutoConfig.getValue()) $scope.stgTURNFullTextConfig.show();
            $scope.ExternalIP.show();
            $scope.stgTURNPortTCP.show();
            $scope.stgTURNUseAutoConfig.show();

            $scope.stgTURNExternalConfig.hide();
        } else {
            $scope.stgTURNFullTextConfig.hide();
            $scope.ExternalIP.hide();
            $scope.stgTURNPortTCP.hide();
            $scope.stgTURNUseAutoConfig.hide();

            $scope.stgTURNExternalConfig.show();
        }

        $scope.change.apply(this, arguments);
    };

    $scope.show = function(){
        $scope.data                   = mcService.Marge({}, $rootScope.mcStorage.SettingsNetwork || {});
        $scope.data.networkInterfaces = $rootScope.mcStorage.networkInterfaces;
        $scope.data.IPs               = mcService.networkInterfaces($scope.data.IPVer, $scope.data.networkInterfaces);

        $scope.data.IPs.shift();

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        customKeyValue.private = $scope.data.WEBPrivateKeyPath;
        customKeyValue.public  = $scope.data.WEBPublicKeyPath;
        customKeyValue.root    = $scope.data.WEBBundleKeyPath;

        if ($scope.data.WEBPublicKeyPath != defaultSslPath.public && $scope.data.WEBPrivateKeyPath != defaultSslPath.private){
            $scope.sslCaseUse = $scope.sslCase.custom;
        }

        var settings = initSettingsWEB($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();

        var host = $scope.data.ExternalIP ? $scope.data.ExternalIP : location.hostname;

        $scope.sslInfo.hide();

        if (!mcService.isValidIpAddress(host) && mcService.isValidHostName(host) &&
            location.protocol === "https:" && $scope.sslCaseUse === $scope.sslCase.custom && customKeyValue.private) {
            
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.checkSSL,
                mcConst.SessionID,

                host,
                mcConst.UserInfo.PortNode,

                function (info) {
                    $scope.sslInfo.define("template", mcService.myReplaceFormated(
                        "<span class='brown'>#{daysTitle}</span>: #{daysReam}<br>" +
                        "<span class='brown'>#{validTitle}</span>: #{valid}<br>" +
                        "<span class='brown'>#{fromTitle}</span>: #{from}<br>" +
                        "<span class='brown'>#{toTitle}</span>: #{to}",
                        {
                            daysTitle : mcLang(2086), // "2086":"Осталось дней:",
                            validTitle: mcLang(2087), // "2087":"Действительный:",
                            fromTitle : mcLang(2084), // "2084":"Выдан:",
                            toTitle   : mcLang(2085), // "2085":"Годен до:",

                            daysReam  : info.daysRemaining,
                            valid     : info.valid ? mcLang(114) : mcLang(113), // "114" :"Да", "113" :"Нет",
                            from      : info.validFrom ? mcService.formatDate(new Date(info.validFrom), "dd MMM yyyy") : " ",
                            to        : info.validTo ? mcService.formatDate(new Date(info.validTo), "dd MMM yyyy") : " "
                        }
                    ));

                    $scope.sslInfo.show();
                    $scope.sslInfo.refresh();
                }
            ]);
        }
    };

    // ========================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);

        $scope.data = null;
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.getMcSettings($rootScope, $scope.show, true);
    });
}


function initSettingsWebCache ($scope){
    "use strict";

    var blockWidth = 550;
    var lbWdth     = 265;

    var hSeparate = function(){ return { height: 5}};

    var webCache = $$($scope.Name);

    if (webCache){
        webCache.destructor();
    }

    webCache = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(2126) }, // "2126":"Кеширование WEB-сервера",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [
                { width: blockWidth, rows: [
                    { view: "checkbox",id: "stwWEBUseCache",       value: $scope.data.WEBUseCache,             disabled: _gLock.WEBUseCache || false, labelWidth: 0, labelRight: mcService.Lang(1526), css: "finger", on: {onChange: $scope.change} }, // "1526":"Включить кеширование WEB-сервера",

                    { id: "stwWEBCacheTotalSizeLimit",  view: "richselect", value: $scope.data.WEBCacheTotalSizeLimit, readOnly: true, label: mcLang(2127), // "2127":"Максимальный размер кеша",
                        on: { onChange: $scope.change}, labelWidth: lbWdth,
                        options: [
                            { id: 52428800,   value: "50 MB"  },
                            { id: 104857600,  value: "100 MB" },
                            { id: 314572800,  value: "300 MB" },
                            { id: 524288000,  value: "500 MB" },
                            { id: 838860800,  value: "800 MB" },
                            { id: 1073741824, value: "1 GB"   },
                            { id: 1610612736, value: "1,5 GB" }
                        ]
                    },
                    { id: "stwWEBCacheTTL", view: "slider", value: $scope.data.WEBCacheTTL, width: blockWidth, labelWidth: lbWdth, label: mcLang(2129), // "2129":"Время жизни файла в кеше (часов)",
                        height: 40, name: "stwWEBCacheTTL", moveTitle: true, title: "" + $scope.data.WEBCacheTTL,  min: 1, max: 72, step: 1, on: {
                            onChange: $scope.change,
                            onSliderDrag:function(){
                                this.define("title", "" + this.getValue());
                                this.refresh();
                            }
                        }
                    },
                    { id: "stwWEBCacheOneFileSizeLimit",  view: "richselect", value: $scope.data.WEBCacheOneFileSizeLimit, readOnly: true, label: mcLang(2128), // "2128":"Максимальный размер файла в кеше",
                        on: { onChange: $scope.change}, labelWidth: lbWdth,
                        options: [
                            { id: 1048576,    value: "1 MB"  },
                            { id: 5242880,    value: "5 MB"  },
                            { id: 10485760,   value: "10 MB" },
                            { id: 15728640,   value: "15 MB" },
                            { id: 20971520,   value: "20 MB" },
                            { id: 26214400,   value: "25 MB" },
                        ]
                    },
                ]}, {}
            ]
        }, {}]
    });

    mcService.disableContextMenu(webCache);

    return webCache;
}

function settingsWebCacheController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsWebCache;
    
    var angElement = document.getElementById($scope.Name);

    $scope.data = null;

    $rootScope.ErrorActions[231]  = function (){
        if ($scope.data) {
            $scope.show();
        }
    };

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        mcConst.restartOptions[1] = mcConst.restartItems.WEB;

        $rootScope.$broadcast('NeedRestartServer', []);

        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    // ========================================================

/*
    $scope.changeEx = function (newV, oldV){
        if (newV == 0){
            $scope.stgTURNFullTextConfig.show();
            $scope.ExternalIP.hide();
            $scope.stgTURNPortTCP.hide();
        } else {
            $scope.stgTURNFullTextConfig.hide();
            $scope.ExternalIP.show();
            $scope.stgTURNPortTCP.show();
        }

        $scope.change.apply(this, arguments);
    };
*/

    $scope.show = function(){
        // "WEBUseCache"              : true,    // включен или выключен кеш
        // "WEBCacheTotalSizeLimit"   : 1234567, // максимальный размер кеша в байтах
        // "WEBCacheTTL"              : 24,      // срок жизни файла в кеше, в часах
        // "WEBCacheOneFileSizeLimit" : 65535,   // максимальный размер одного файла, если больше - он в кеш не попадает
        // "WEBCachePaths"            : ""       // пути для кеширования
        $scope.data = mcService.Marge({}, $rootScope.mcStorage.SettingsNetwork || {});

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var cacheView = initSettingsWebCache($scope);

        mcService.initResize(cacheView, $scope.Name);

        cacheView.adjust();
    };

    // ========================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);

        $scope.data = null;
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.getMcSettings($rootScope, $scope.show, true);
    });
}

function initSettingsBackup($scope){
    "use strict";

    var labelWidth = 250;
    var blockWidth = 500;
    var btnWidth   = 240;
    var backup     = $$($scope.Name);

    if (backup){
        backup.destructor();
    }

    backup = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type: "header", template : mcService.Lang(601)}, // "601": "Резервные копии",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            {
            type : 'layout',
            padding : 5,
            cols : [{
                rows: [
                    { view: "checkbox", id: "stgBackupWeekly", value: $scope.data.BackupWeekly, labelWidth: 0, css: "finger",
                        labelRight: mcService.Lang(644), // "644": "Еженедельное автоматическое создание резервных копий базы данных сервера",
                        on: {
                            onChange: $scope.change
                        }
                    },
                    { view: "select",   id: "stgBackupDay",    value: $scope.data.BackupDay,    labelWidth: labelWidth, width: blockWidth, options: mcService.GetWeekDays(),
                        label: mcService.Lang(645), // "645": "День недели",
                        on: {
                            onChange: $scope.change
                        }
                    },
                    {cols : [
                        { view: "counter",  id: "stgBackupHours",   value: $scope.data.BackupHours,   labelWidth : labelWidth, step: 1, min: 0, max: 24,
                            label: mcService.Lang(653), // "653": "Время создания резервной копии",
                            on: {
                                onChange: $scope.change
                            }
                        },
                        { view: "counter",  id: "stgBackupMinutes", value: $scope.data.BackupMinutes, labelWidth : 5, label: "<b>:</b>", step: 1, min: 0, max: 59, width: 149,
                            on: {
                                onChange: $scope.change
                            }
                        }
                    ]}
                ]
            }, {}]
        }, {
            type : 'layout',
            padding : 5,
            cols : [{
                rows: [
                    { view: "text", id: "stgBackupsDir", value: $scope.data.BackupsDir,  disabled: _gLock.BackupsDir || false, labelPosition: "top",  width: blockWidth ,
                        label: mcService.Lang(654), // "654": "Каталог для хранения резервных копий базы данных",
                        on: {
                            onTimedKeyPress: function() {
                                $scope.change.apply(this, arguments);
                            }
                        }
                    }
                ]
            }, {}]
        }, {
            type : 'layout',
            padding : 5,
            cols : [{
                rows: [
                    {cols : [
                        { view: "checkbox", id: "stgPurgeOldBackups", value: $scope.data.PurgeOldBackups, labelWidth: 0, width: blockWidth, css: "finger",
                            labelRight: mcService.Lang(655), // "655": "Автоматически удалять файлы резервных копий",
                            on: { onChange: $scope.change }
                        },
                        { view: "counter",  id: "stgPurgeOldBackupsDays", value: $scope.data.PurgeOldBackupsDays, width: 110, step: 1, min: 1, max: 999,
                            on: { onChange: $scope.change }
                        },
                        { template: mcService.Lang(659) , width: 50, borderless: true}, // "659": "дней",
                        {}
                    ]}
                ]
            }, {}]
        }, {
            type : 'layout',
            padding : 5,
            cols : [
                { view: "button", value: mcService.Lang(656), id: "", width: btnWidth, click: $scope.backupDB }, // "656": "Сделать резервную копию сейчас",
                { width: 20 },
                { view: "button", value: mcService.Lang(657), disabled: _gLock.ClearAllDataBase || false, id: "stgClearAllDataBase", width: btnWidth, click: $scope.totalClearBase, type: "danger" }, // "657": "Полная очистка всех данных",
                {}
            ]
        }, {
            id   : "resultBackup" + $scope.Name,
            type : 'layout',
            padding : 5,
            hidden: true,
            cols : [
                { id: "backupName" + $scope.Name, view: "label", label: "", width: btnWidth * 1.3},
                // { id: "backupSize" + $scope.Name, view: "label", label: "", width: btnWidth},
                { width: 20 },
                { view: "button", value: mcService.Lang(1848), id: "", width: btnWidth * .7, click: $scope.downloadBackup }, // "1848":"Скачать",
                {}
            ]
        }, {}
        ]

    });

    $scope.resultBackup = $$("resultBackup" + $scope.Name);
    $scope.backupName   = $$("backupName" + $scope.Name);
    // $scope.backupSize   = $$("backupSize" + $scope.Name);

    

    mcService.disableContextMenu(backup);

    return backup;
}

function settingsBackupController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsBackup;
    var angElement = document.getElementById($scope.Name);
    var backupFile = "";

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.backupDB = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_make_backup_server_db,
            mcConst.SessionID,
            
            function(data){
                backupFile = data.FileName;

                webix.message(mcService.Lang(1001)); // "1001":"Резервная копия базы сервера создана!",

                $scope.resultBackup.show();
                $scope.backupName.setValue(backupFile + " (" + mcService.formatFileSize(data.FileSize, true) + ")");
                // $scope.backupSize.setValue(mcLang(1561) + mcService.formatNumber(data.FileSize)); // "1561":"Размер в байтах: ",
            }
        ]);
    };

    $scope.downloadBackup = function () {
        if (backupFile){
            var link = document.createElement('a');

            link.setAttribute('href', '/backupdb/' + backupFile + '?sid=' + mcConst.SessionID + "&uin=" + mcConst.UserInfo.UIN);
            link.setAttribute('download', backupFile);
            link.click();

            link = null;
        }
    };

    $scope.totalClearBase = function(){
        $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
            type  : "confirm-warning",
            text  : mcService.Lang(1002), // "1002":"Вы действительно хотите удалить ВСЕ данные сервера: пользователей, настройки, документы и вернуть его к первоначальному состоянию?",
            ok    : mcService.Lang(581), // "581": "Удалить",
            cancel: mcService.Lang(103), // "103": "Отмена",
            callback:function(yes){
                if (yes){
                    webix.alert({
                        title: mcService.Lang(1004), // "1004":"Внимание!",
                        ok   : mcService.Lang(12),   // "12" : "Закрыть",
                        type : "alert-error",
                        text : mcService.Lang(1003)  // "1003":"База данных полностью очищена, все пользовательские данные и документы удалены, перезапустите сервер",
                    });

                    setTimeout(function(){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_return_server_to_zero_state,
                            mcConst.SessionID,

                            function () {
                                webix.alert(mcLang(1944)); // "1944":"Все данные удалены, сервер выключен!<br>Запустите сервер вручную.",
                            }
                        ]);
                    }, 1000);
                } //else webix.alert(mcLang(1944)); // "1944":"Все данные удалены, сервер выключен!<br>Запустите сервер вручную.",
            }
        }));
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        $scope.data     = $rootScope.mcStorage.SettingsNetwork || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsBackup($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();

        if (backupFile){
            $scope.resultBackup.show();
            $scope.backupName.setValue(backupFile);
        }
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, $scope.show);
    });
}


function initSettingsService($scope){
    "use strict";

    var blockWidth = 400;

    var service    = $$($scope.Name);

    if (service){
        service.destructor();
    }

    service = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type: "header", template: mcService.Lang(602)}, // "602": "Обслуживание",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            {
            type : 'layout',
            padding : 5,
            cols : [{
                rows: [
                    // {cols : [
                    //     { view: "checkbox", id: "stgPurgeOldImages", value: $scope.data.PurgeOldImages, labelRight: mcService.Lang(660), labelWidth: 0, width: blockWidth, css: "finger", on: {onChange: $scope.change} }, // "660": "Автоматически удалять файлы изображений",
                    //     { view: "counter",  id: "stgPurgeOldImagesDays", value: $scope.data.PurgeOldImagesDays, width: 110, step: 1, min: 1, max: 999,
                    //         on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }, // "658": "старше",
                    //     { template: mcService.Lang(659) , width: 50, borderless: true}, // "659": "дней",
                    //     {}
                    // ]},
                    {cols : [
                        { view: "checkbox", id: "stgPurgeOldFiles", value: $scope.data.PurgeOldFiles, labelRight: mcService.Lang(1883), labelWidth: 0, width: blockWidth, css: "finger", on: {onChange: $scope.change} }, // "1883":"Автоматически удалять опубликованные файлы",
                        { view: "counter",  id: "stgPurgeOldFilesDays", value: $scope.data.PurgeOldFilesDays, width: 110, step: 1, min: 1, max: 999,
                            on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }, // "658": "старше",
                        { template: mcService.Lang(659) , width: 50, borderless: true}, // "659": "дней",
                        {}
                    ]}
                ]
            }, {}]
        }, {}]
    });

    mcService.disableContextMenu(service);

    return service;
}
"use strict";

function settingsServiceController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.SettingsService;
    var angElement = document.getElementById($scope.Name);

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });


    $scope.show = function(data){
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsService($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, $scope.show);
    });
}



"use strict";

function initSettingsAPI($scope){
    var labelWidth = 160;
    var blockWidth = 550;

    var api = $$($scope.Name);

    if (api){
        api.destructor();
    }

    api = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(603) }, // "603": "Integration API",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [{
                rows: [
                    { view: "checkbox", id: "stgIntegrationAPI",    value: $scope.data.IntegrationAPI, labelWidth: 0, width: blockWidth, css: "finger",
                        labelRight: mcService.Lang(661), // "661": "Включить поддержку интеграции со сторонним программным обеспечением",
                        on: {
                            onChange: $scope.change
                        }
                    },
                    { view: "text",     id: "stgIntegrationAPIKey", value: $scope.data.IntegrationAPIKey, labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(662), // "662": "Ключ Integration API",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { view: "button",   value: mcService.Lang(663), click: $scope.generateKey } // "663": "Сгенерировать",
                ]
            }, {}]
        }, {}]
    });

    mcService.disableContextMenu(api);

    return api;
}
"use strict";

function settingsAPIController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.SettingsAPI;
    var angElement = document.getElementById($scope.Name);

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.show = function(){ // data
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsAPI($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.generateKey = function(){
        var key = $$("stgIntegrationAPIKey");
        var val = mcService.RandomHash(20);

        key.define('value', val);
        key.refresh();

        $scope.change.apply(key, [val]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, $scope.show);
    });
}

function initSettingsSMTP($scope){
    "use strict";

    var backup = $$($scope.Name);
    var labelWidth = 250;
    var blockWidth = 500;
    var counterWidth = 350;

    var hSeparate  = function(){ return {height:4}};

    var mailType = [{id: '0', value: 'plain text'}, {id: '1', value: 'HTML'}];

    if (backup) {
        backup.destructor();
    }

    backup = webix.ui({
        type: "space",
        padding: 5,
        container: $scope.Name,
        id: $scope.Name,
        borderless: true,
        rows: [
            { cols: [
                { type: "header", template: mcService.Lang(921) }, // "921":"Настройка SMTP",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            {
                type: 'layout',
                padding: 5,
                cols: [
                    { rows: [
                        { view: "checkbox", id: "stgSMTPEnable", value: $scope.data.SMTPEnable, labelWidth: 0, css: "finger",
                            labelRight: mcService.Lang(922), // "922":"Включить сервис отправки электроной почпы",
                            on: {
                                onChange: $scope.changeEx
                            }
                        },
                        { view: "checkbox", id: "stgSMTPUseSSL", value: $scope.data.SMTPUseSSL, labelWidth: 0, css: "finger",
                            labelRight: mcService.Lang(924), // "924":"Использовать зашифрованое подключение SSL",
                            on: {
                                onChange: $scope.changeEx
                            }
                        }
                    ]}, {}
                ]
            },
            { type: 'layout', padding: 5, cols: [
                { rows: [
                    { cols: [
                        { view: "select", id: "booksSmtpOptions", labelWidth: labelWidth, width: blockWidth - 30, options: $scope.books,
                            label: mcService.Lang(1678), // "1678":"Шаблон настроек",
                            on: {onChange: $scope.setSmtpOptions}
                        },
                        {view: "button", type: "icon", icon: "question", click: function () {
                            var path = $scope.booksSmtpOptions.getValue();

                            mcService.goToHelp("/serverhelp/" + (mcConst.Lang === "uk" ? "ua" : mcConst.Lang) + "/index.html?" + $scope.books[mcService.findItemInArrayOfObj($scope.books, path, "id", true)].HelpLink, true);
                        }, width: 30}
                    ]},

                    { view: "text", id: 'stgSMTPHost',  value: $scope.data.SMTPHost, labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(923), // "923":"Адрес почтового сервера",
                        on: {onChange: $scope.changeEx, onTimedKeyPress: $scope.changeEx}
                    },
                    { view: "text", id: 'stgSMTPLogin', value: $scope.data.SMTPLogin, labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(1), // "1"  : "Логин",
                        on: {onTimedKeyPress: $scope.changeEx}
                    },

                        { cols: [
                            { view: "text",     id: "stgSMTPPassword",    value: $scope.data.SMTPPassword,     labelWidth: labelWidth, width: blockWidth, type: "password" ,
                                label: mcService.Lang(2), // "2"  : "Пароль",
                                on: {
                                    onTimedKeyPress : function(){
                                        mcService.typeFlag('stgDispLang', 'stgSMTPPassword');

                                        $scope.changeEx.apply(this, arguments);
                                    }
                                }
                            },
                            { view: "toggle", width: 30, offIcon: "eye", onIcon: "eye-slash",  type:"icon", css: "noBG", tooltip: mcLang(1100) + "/" + mcLang(1099).toLowerCase(), // "1100":"Скрыть", "1099":"Показать",
                                on: { onChange: function (val) {
                                        var pwd = $$("stgSMTPPassword");

                                        if (val) {
                                            pwd.define('type', 'text');
                                        } else {
                                            pwd.define('type', 'password');
                                        }

                                        pwd.refresh();
                                        pwd.getInputNode().setAttribute("autocomplete", "new-password");
                                    }}
                            },
                            { id : 'stgDispLang',
                                template   : 'EN',
                                width      : 23,
                                borderless : true
                            }
                        ]},

                    // { view: "text", id: 'stgSMTPPassword', value: $scope.data.SMTPPassword, labelWidth: labelWidth, width: blockWidth, type: "password",
                    //     label: mcService.Lang(2), // "2"  : "Пароль",
                    //     on: {onTimedKeyPress: $scope.changeEx}
                    // },

                    { view: "text", id: 'stgSMTPPort', value: $scope.data.SMTPPort,  labelWidth: labelWidth, width: counterWidth,
                        label: mcService.Lang(593), mcType: "port", // "593": "TCP порт",
                        on: {onTimedKeyPress: function () {
                            $scope.stgSMPTButtonCheck.disable();
                            $scope.changeExc.apply(this, arguments);
                        }, onChange: $scope.changeExc}
                    },
                    { view: "text", id: 'stgSMTPEmail', value: $scope.data.SMTPEmail, labelWidth: labelWidth, width: blockWidth,
                        label: mcService.Lang(70),  // "70" : "Email",
                        on: {onTimedKeyPress: $scope.changeEx}
                    },
                    { view: "select", id: "stgSMTPFormat", value: $scope.data.SMTPFormat, labelWidth: labelWidth, width: blockWidth, options: mailType,
                        label: mcService.Lang(925), // "925":"Формат отправляемого письма",
                        on: {onChange: $scope.changeEx}
                    },
                    { cols: [
                        { view: "button", value: mcService.Lang(926), id: "stgSMPTButtonCheck", width: 250, click: $scope.checkConnect }, // "926":"Проверить соединение",
                        { width: 30, id: "stgSTMPCheckSuccess", template: mcService.insertIco('fa-check'), css: "green", hidden: true, borderless: true},
                        { width: 30, id: "stgSTMPCheckFailed",  template: mcService.insertIco('fa-ban'), css: "red", hidden: true, borderless: true},
                        {}
                    ]}
                ]}, {}
            ]},
            { type: 'layout', padding: 5, id: "stgSMTPResultLog", hidden: true, gravity: 99, rows: [
                { view: "textarea", id: "stgSMTPResultLogText", value: "", css: "textArea"}
            ]},
            {}
        ]
    });

    $scope.booksSmtpOptions   = $$("booksSmtpOptions");
    $scope.stgSMPTButtonCheck = $$("stgSMPTButtonCheck");

    $$("stgSMTPEmail").getInputNode().setAttribute("autocomplete", "new-password");
    $$("stgSMTPPassword").getInputNode().setAttribute("autocomplete", "new-password");

    mcService.disableContextMenu(backup);

    return backup;
}


function settingsSMTPController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsSMTP;
    var angElement = document.getElementById($scope.Name);

    $scope.books = [];

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        $scope.stgSMPTButtonCheck.enable();
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.changeEx = function(){
        var value = this.getValue();

        if ((this.config.view !== "text") || (this.config.view === "text" && mcService.trim(value) !== $scope.data[this.config.id.replace('stg', '')])){
            $scope.stgSMPTButtonCheck.disable();
        }

        $scope.change.apply(this, arguments);
    };

    $scope.checkConnect = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_check_smtp,
            mcConst.SessionID,
            function (data){
                if (data.Ok) {
                    webix.message({ type:"info", text: mcService.Lang(929) , expire : mcConst.errMessageExpire * 2}); // "929":"Соединение успешно проверено!",

                    $$("stgSTMPCheckFailed").hide();
                    $$("stgSTMPCheckSuccess").show();
                } else {
                    //$rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(930)]); // "930":"Соединение отсутствует!",

                    $$("stgSTMPCheckSuccess").hide();
                    $$("stgSTMPCheckFailed").show();
                }

                var log = $$("stgSMTPResultLogText");

                $$("stgSMTPResultLog").show();

                log.setValue(data.Log);
                log.getInputNode().scrollTop = 9999;
            }
        ]);
    };

    $scope.setSmtpOptions = function (id) {
        if (id !== '0'){
            var info = $scope.books[mcService.findItemInArrayOfObj($scope.books, id, "id", true)];

            $$("stgSMTPHost").setValue(info.Server);
            $$("stgSMTPPort").setValue(info.Port);
            $$("stgSMTPUseSSL").setValue(info.Encrypted);
        }

    };

    $scope.show = function(){ // data
        $scope.data     = $rootScope.mcStorage.SettingsNetwork || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsSMTP($scope);

        $scope.stgSMPTButtonCheck.enable();

        mcService.initResize(settings, $scope.Name);

        settings.adjust();

        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_get_book,
            mcConst.SessionID,
            mcConst.Books.SMTP,
            function(data){
                $scope.books = [{
                    id : '0', value: mcLang(1821), HelpLink: "smtpoptions.htm" // "1821":"Отсутствует",
                }];

                data.Data.forEach(function (item) {
                    item.id    = item.Name;
                    item.value = item.Name;

                    $scope.books.push(item);
                });

                $scope.booksSmtpOptions.define("options", $scope.books);
                $scope.booksSmtpOptions.refresh();
            }
        ]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.getMcSettings($rootScope, $scope.show);
    });
}



function initSettingsFolders($scope){
    "use strict";

    var labelWidth = 250;
    var blockWidth = 500;
    var btnWidth   = 240;
    var folders     = $$($scope.Name);

    if (folders){
        folders.destructor();
    }

    folders = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type: "header", template : mcService.Lang(1941)}, // "1941":"Каталоги",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5, cols : [{
                rows: [
                    { view: "text", id: "stxBackupsDir", value: $scope.data.BackupsDir,  disabled: _gLock.BackupsDir || false, labelPosition: "top",  width: blockWidth ,
                        label: mcService.Lang(654), // "654": "Каталог для хранения резервных копий базы данных",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { height: 5},

                    { view: "text", id: "stxFTPPublicDir",   value: $scope.data.FTPPublicDir,  disabled: _gLock.FTPPublicDir || false,   labelPosition: "top",  width: blockWidth,
                        label: mcService.Lang(628), // "628": "Общий каталог для всех пользователей сервера MyChat",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { height: 5},

                    { view: "text", id: "stxFTPPersonalDir", value: $scope.data.FTPPersonalDir,  disabled: _gLock.FTPPersonalDir || false, labelPosition: "top",  width: blockWidth,
                        label: mcService.Lang(629), // "629": "Каталог для зарегистрированных пользователей",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { height: 5},

                    { view: "text", id: "stxFilesDir", value: $scope.data.FilesDir,  disabled: _gLock.FilesDir || false, labelPosition: "top",  width: blockWidth,
                        label: mcService.Lang(1943), // "1943":"Каталог кеша файлов для передачи через сервер",
                        on: {
                            onTimedKeyPress: $scope.change
                        }                                   
                    },
                    { height: 5},

                    { view: "text", id: "stxLogsDir", value: $scope.data.LogsDir,  disabled: _gLock.LogsDir || false, labelPosition: "top",  width: blockWidth,
                        label: mcService.Lang(1942), // "1942":"Каталог для хранения логов",
                        on: {
                            onTimedKeyPress: $scope.change
                        }
                    },
                    { height: 5}
                ]}, {}]
            }, 
        {}]
    });

    mcService.disableContextMenu(folders);

    return folders;
}

function settingsFoldersController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsFolders;
    var angElement = document.getElementById($scope.Name);
    var backupData = {};

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        if (backupData.FTPPublicDir !== $rootScope.mcStorage.SettingsNetwork.FTPPublicDir ||
            backupData.FTPPersonalDir !== $rootScope.mcStorage.SettingsNetwork.FTPPersonalDir){
            
            mcConst.restartOptions[2] = mcConst.restartItems.FTP;

            $rootScope.$broadcast('NeedRestartServer', []);
        }

        backupData = mcService.Marge($scope.data, $rootScope.mcStorage.SettingsNetwork || {});

        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};

        backupData = mcService.Marge({}, $rootScope.mcStorage.SettingsNetwork || {});

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsFolders($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);

        $rootScope.ErrorActions[212] = null;
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.getMcSettings($rootScope, $scope.show);

        $rootScope.ErrorActions[211] = $rootScope.ErrorActions[212] = function () {
            $$("stxFTPPublicDir").setValue(backupData.FTPPublicDir);
            $$("stxFTPPersonalDir").setValue(backupData.FTPPersonalDir);
        };

        $rootScope.ErrorActions[244] = $rootScope.ErrorActions[243] = function () {
            $$("stxBackupsDir").setValue(backupData.BackupsDir);
            $$("stxFilesDir").setValue(backupData.FilesDir);
            $$("stxLogsDir").setValue(backupData.LogsDir);
        };
    });
}


function initSettingsPlugins($scope){
    "use strict";

    var titleWidth = 130;
    var service    = $$($scope.Name);

    if (service){
        service.destructor();
    }

    service = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type: "header", template: mcService.Lang(824)}, // "824":"Плагины (дополнения)",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [{
                rows: [
                    // { cols : [
                        { cols: [
                            { id: "PluginsList" + $scope.Name, view: "datatable", scroll: 'y', maxWidth: 800, gravity: 10,
                                select         : "row",
                                resizeColumn   : true,
                                columns        : [
                                    { id: "Name", header: "Name", fillspace: true, sort: "string", css: "grid_area"},  //
                                    { id: "Version", header: "Version", width: 150, sort: "string", css: "grid_area"},  //
                                    { id: "state", header: "State", width: 150, sort: "string", css: "grid_area", template: function (){

                                    }},  //
                                ],
                                data: [],
                                on: {
                                    // onAfterEditStart: function () {
                                    //     asterisk.view_deleteUserGroup.disable();
                                    //     $scope.change();
                                    // },
                                    // onAfterEditStop: function () {
                                    //     asterisk.view_deleteUserGroup.enable();
                                    // }
                                    // onItemClick     : asterisk.clickByUser,
                                    // onBeforeEditStop: asterisk.editUser,
                                    // onCheck         : asterisk.editUser
                                }
                            },
                            { gravity: 0}
                        ]},

                        // { width: 10},

                        { rows: [
                            { cols: [
                                { id: "installBtn" + $scope.Name, view: "button", hidden: true, value: mcLang(2195)},                         // "2195":"Установить",
                                { id: "updateBtn" + $scope.Name,  view: "button", hidden: true, value: mcLang(53), css: "green applyButton"}, // "53" : "Обновить",
                                { id: "removeBtn" + $scope.Name,  view: "button", hidden: true, value: mcLang(52), type: "danger"},           // "52" : "Удалить",
                                { height: 30}
                            ]},

                            { cols: [
                                { template: "Name", width: titleWidth , borderless: true, autoheight: true},
                                { id: "Name" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            { cols: [
                                { template: "Description", width: titleWidth , borderless: true, autoheight: true},
                                { id: "Description" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            { cols: [
                                { template: "ReleaseDate", width: titleWidth , borderless: true, autoheight: true},
                                { id: "ReleaseDate" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            { cols: [
                                { template: "Size", width: titleWidth , borderless: true, autoheight: true},
                                { id: "Size" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            { cols: [
                                { template: "MyChatMinVer", width: titleWidth , borderless: true, autoheight: true},
                                { id: "MyChatMinVer" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            { cols: [
                                { template: "Version", width: titleWidth , borderless: true, autoheight: true},
                                { id: "Version" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            { cols: [
                                { template: "Email", width: titleWidth , borderless: true, autoheight: true},
                                { id: "Email" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            { cols: [
                                { template: "Link", width: titleWidth , borderless: true, autoheight: true},
                                { id: "Link" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            ]},

                            // { cols: [
                            //     { template: "Copyright", width: titleWidth , borderless: true, autoheight: true},
                            //     { id: "Copyright" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            // ]},

                            // { cols: [
                            //     { template: "WWW", width: titleWidth , borderless: true, autoheight: true},
                            //     { id: "WWW" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            // ]},

                            // { cols: [
                            //     { template: "Hash", width: titleWidth , borderless: true},
                            //     { id: "Hash" + $scope.Name, template: "&nbsp;", borderless: true},
                            // ]},

                            // { cols: [
                            //     { template: "Caption", width: titleWidth , borderless: true, autoheight: true},
                            //     { id: "Caption" + $scope.Name, template: "&nbsp;", borderless: true, autoheight: true},
                            // ]},

                            {}
                        ]}
                        // { view: "checkbox", id: "stgPurgeOldImages", value: $scope.data.PurgeOldImages, labelRight: mcService.Lang(660), labelWidth: 0, width: blockWidth, css: "finger", on: {onChange: $scope.change} }, // "660": "Автоматически удалять файлы изображений",
                        // { view: "counter",  id: "stgPurgeOldImagesDays", value: $scope.data.PurgeOldImagesDays, width: 110, step: 1, min: 1, max: 999,
                        //     on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }, // "658": "старше",
                        // { template: mcService.Lang(659) , width: 50, borderless: true}, // "659": "дней",
                        // {}
                    // ]},
                    // {cols : [
                    //     { view: "checkbox", id: "stgPurgeOldFiles", value: $scope.data.PurgeOldFiles, labelRight: mcService.Lang(1883), labelWidth: 0, width: blockWidth, css: "finger", on: {onChange: $scope.change} }, // "1883":"Автоматически удалять опубликованные файлы",
                    //     { view: "counter",  id: "stgPurgeOldFilesDays", value: $scope.data.PurgeOldFilesDays, width: 110, step: 1, min: 1, max: 999,
                    //         on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }, // "658": "старше",
                    //     { template: mcService.Lang(659) , width: 50, borderless: true}, // "659": "дней",
                    //     {}
                    // ]}
                ]
            }]
        }]
    });

    mcService.disableContextMenu(service);

    $scope.installBtn = $$("installBtn" + $scope.Name);
    $scope.updateBtn  = $$("updateBtn" + $scope.Name);
    $scope.removeBtn  = $$("removeBtn" + $scope.Name);

    $scope.PluginsList = $$("PluginsList" + $scope.Name);

    return service;
}
function settingsPluginsController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.SettingsPlugins;

    var angElement = document.getElementById($scope.Name);

    // mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
    //     return mcService.Lang(669); // "669": "Настройки сохранены!"
    // });

    $scope.getData = function (){
        // { "ver"  : 1, "data" : [{
        //     "Hash"          : "78xbd4t5793dh794y5hdx87777777777",
        //     "Size"          : 45875864,
        //     "MyChatMinVer"  : "8.10",
        //     "Name"          : "LiteManager",
        //     "CaptionEN"     : "Computer control (LiteManager)",
        //     "CaptionRU"     : "Управление компьютером через LiteManager",
        //     "CaptionUA"     : "Управління комп'ютером через LiteManager",
        //     "Version"       : "1.1",
        //     "Copyright"     : "© Alexey Pikurov / Network Software Solutions",
        //     "WWW"           : "https://nsoft-s.com",
        //     "Email"         : "hobit@nsoft-s.com",
        //     "ReleaseDate"   : "2021-08-17",
        //     "DescriptionRU" : "Удалённое управление компьютером...",
        //     "DescriptionEN" : "Computer remote control tool..",
        //     "DescriptionUA" : "Віддалене керування комп'ютером...",
        //     "Link"          : "https://nsoft-s.com/files/mychat/plugins/LiteManager.zip"
        // }]}

        $scope.PluginsList.clearAll();

        var params = JSON.stringify({
                url   : "https://nsoft-s.com/files/mychat/plugins/mychat-plugins.json",
                memory: true
            });

            $rootScope.SendCMDToServer([
            mcConst._CMD_.getUrl,
            mcConst.SessionID,

            params,

            function (res) {
                var list = mcService.StringToObj(res.data);

                $scope.PluginsList.parse(list);

                $rootScope.SendCMDToServer([
                    mcConst._CMD_.getUrl,
                    mcConst.SessionID,

                    {
                        url   : "https://nsoft-s.com/files/mychat.zip",
                        download: true,
                    }
                ]);
            }
        ]);

        // mcService.jsonp(location.protocol + "//nsoft-s.com/files/mychat/plugins/mychat-plugins.json", function (data) {
        // mcService.jsonp(location.protocol + "//mychat-server.com/stat.txt", function (data) {
        //     console.log(data);
        // }, function (err) {
        //     console.log(err);
        // }, "?");
    };

    $scope.show = function(data){
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsPlugins($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $scope.show();

        $scope.getData();
    });
}



"use strict";

function initSettingsGPS($scope){
    var labelWidth = 160;
    var blockWidth = 550;

    var api = $$($scope.Name);

    if (api){
        api.destructor();
    }

    api = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(2203) }, // "2203":"GPS трекинг",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [{
                rows: [
                    { type : 'layout', padding : 5, rows : [
                        { cols : [
                            { width: 430, template : mcService.Lang(2196), borderless: true},          //  "2196":"Отправлять текущую геопозицию на сервер, не чаще одного раза в",
                            { width: 110, view: "richselect", id: "stgUpdateGPSTime", value: $scope.data.UpdateGPSTime || 15,
                                options: [
                                    {id: 5,    value: mcLang(2200, 5)},  // "2200":"%s минут",
                                    {id: 10,   value: mcLang(2200, 10)}, // "2200":"%s минут",
                                    {id: 15,   value: mcLang(2200, 15)}, // "2200":"%s минут",
                                    {id: 30,   value: mcLang(2200, 30)}, // "2200":"%s минут",
                                    {id: 60,   value: mcLang(2197, 1)},  // "2197":"%s час",
                                    {id: 120,  value: mcLang(2198, 2)},  // "2198":"%s часа",
                                    {id: 240,  value: mcLang(2198, 4)},  // "2198":"%s часа",
                                    {id: 480,  value: mcLang(2199, 8)},  // "2199":"%s часов",
                                    {id: 720,  value: mcLang(2199, 12)}, // "2199":"%s часов",
                                    {id: 1440, value: mcLang(2198, 24)}  // "2198":"%s часа",
                                ],
                                on: {onChange: $scope.change} },
                            {}
                        ]},

                        { id: "stwGPSMistakeValue", view: "slider", value: $scope.data.GPSMistakeValue || 50, width: 550, labelWidth: 345, label: mcLang(2204), // "2204":"Точность отслеживания геопозиции в метрах",
                            height: 40, name: "stwGPSMistakeValue", moveTitle: true, title: "" + ($scope.data.GPSMistakeValue || 50),  min: 10, max: 500, step: 10, on: {
                                onChange: $scope.change,
                                onSliderDrag:function(){
                                    this.define("title", "" + this.getValue());
                                    this.refresh();
                                }
                            }
                        },

                        { view: "checkbox", id: "stgGPSRemoveOldGPSHistory", value: $scope.data.GPSRemoveOldGPSHistory, css: "finger", labelWidth : 0, 
                            labelRight: mcService.Lang(2206), // "2206":"Ограничить хранение истории геопозиции",
                            on: { onChange: function (val) {
                                if (val){
                                    $scope.stwGPSSaveHistoryDuration.enable();
                                } else {
                                    $scope.stwGPSSaveHistoryDuration.disable();
                                }

                                $scope.change.apply(this, arguments);
                            } }
                        },

                        { id: "stwGPSSaveHistoryDuration", view: "slider", value: $scope.data.GPSSaveHistoryDuration || 90, width: 550, labelWidth: 345, label: mcLang(2205), disabled: !$scope.data.GPSRemoveOldGPSHistory,// "2205":"Длительность хранения истории геопозиции в днях",
                            height: 40, name: "stwGPSSaveHistoryDuration", moveTitle: true, title: "" + ($scope.data.GPSSaveHistoryDuration || 90),  min: 10, max: 180, step: 10, on: {
                                onChange: $scope.change,
                                onSliderDrag:function(){
                                    this.define("title", "" + this.getValue());
                                    this.refresh();
                                }
                            }
                        },

                    ]},
                ]
            }, {}]
        }, {}]
    });

    $scope.stwGPSSaveHistoryDuration = $$("stwGPSSaveHistoryDuration");

    mcService.disableContextMenu(api);

    return api;
}
"use strict";

function settingsGpsController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.SettingsGPS;
    var angElement = document.getElementById($scope.Name);

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.show = function(){ // data
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initSettingsGPS($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.generateKey = function(){
        var key = $$("stgIntegrationAPIKey");
        var val = mcService.RandomHash(20);

        key.define('value', val);
        key.refresh();

        $scope.change.apply(key, [val]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, $scope.show);
    });
}

function initOthers($scope){
    "use strict";

    var _view = $$($scope.Name);
    var CUSTOMSTYLE = '9';

    if (_view){
        _view.destructor();
    }

    var fioList = mcService.GetFioFormatList();

    fioList.push({id: CUSTOMSTYLE, value: mcService.Lang(1024)});

    _view = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(672) }, // "672": "Дополнительно",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [{
                rows: [
                    { view: "checkbox", id: "stgBlockNickDublicates", value: $scope.data.BlockNickDublicates, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(674), // "674": "Запретить дублирование ников",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stgBlockEmailDuplicates", value: $scope.data.BlockEmailDuplicates, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(1813), // "1813":"Запретить дублирование Email-ов",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stgAllowMultiLogin", value: $scope.data.AllowMultiLogin, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(2113), // "2113":"Разрешить мультилогин",
                        on: { onChange: $scope.change }
                    },
                    // { view: "checkbox", id: "stgAutoLogout", value: $scope.data.AutoLogout, css: "finger", labelWidth : 0,
                    //     labelRight: mcService.Lang(675), // "675": "Автозавершение работы MyChat клиента при авторизации с другого компьютера",
                    //     on: { onChange: $scope.change }
                    // },
                    { view: "checkbox", id: "stgBlockNewRegistrations", value: $scope.data.BlockNewRegistrations, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(676), // "676": "Запретить регистрацию новых пользователей",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stgUseIPControlInTokens", value: $scope.data.UseIPControlInTokens, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(1908), // "1908":"Проверять IP адрес в токенах доступа к чату",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stgDisableScriptsDueToTimeout", value: $scope.data.DisableScriptsDueToTimeout, css: "finger", labelWidth : 0,
                        labelRight: mcService.Lang(2038), // "2038":"Отключать скрипты из-за превышения времени выполнения",
                        on: { onChange: $scope.change }
                    },
                    { view: "checkbox", id: "stgAutoImportantNotifiers", value: $scope.data.AutoImportantNotifiers, css: "finger", labelWidth : 0, disabled: $scope.isFree,
                        labelRight: mcService.Lang(2148), // "2148":"Автоматические важные уведомления о функциях MyChat",
                        on: { onChange: $scope.change }
                    },
                ]}, { width: 17 }]
            },

            { type : 'layout', padding : 5, cols : [
                { cols : [
                    { width: 400, template : mcService.Lang(2276), borderless: true},          //  "2276":"Период для редактирования собщений",
                    { width: 130, view: "richselect", id: "stgMaxSelfMsgEditTime", value: $scope.data.MaxSelfMsgEditTime || 15, options: [
                            {id: 10,  value: mcLang(2054)}, // "2054":"10 минут",
                            {id: 15,  value: mcLang(2277)}, // "2277":"15 минут",
                            {id: 30,  value: mcLang(2055)}, // "2055":"30 минут",
                            {id: 60,  value: mcLang(2056)}, // "2056":"1 час",
                            {id: 120, value: mcLang(2278)}, // "2278":"2 часа",
                            {id: 180, value: mcLang(2057)}, // "2057":"3 часа",
                        ],
                        on: {onChange: $scope.change} },
                    {}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [
                { cols : [
                    { width: 430, template : mcService.Lang(2188), borderless: true},          //  "2188":"Максимальное количество открытых диалогов",
                    { width: 100, view: "richselect", id: "stgMaxActivePrivateDialogsCount", value: $scope.data.MaxActivePrivateDialogsCount, options: ["50", "100", "150", "200", "250", "300", "350"],
                        on: {onChange: $scope.change} },
                    {}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [
                { cols : [
                    { width: 430, template : mcService.Lang(677), borderless: true},          //  "677": "Время для автоматической установки статуса \"Нет на месте\"",
                    { width: 100, view: "counter", id: "stgAutoAwayTime", label: "", value: $scope.data.AutoAwayTime, step: 1, min: 1, max: 100,
                        on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} },
                    { width: 60, template : mcService.Lang(681), borderless: true},           // "681": "минут",
                    {}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [
                { cols : [
                    { width: 370, template : mcService.Lang(2061), borderless: true},          //  "2061":"Максимальный размер файла при загрузке на сервер",
                    { width: 160, view: "richselect", id: "stgMaxUploadFileSize", value: $scope.data.MaxUploadFileSize, options: [
                            {id: "0"   , value: mcLang(2279)}, // "2279":"без ограничений",
                            {id: "2"   , value: "2 MB"}, // "2057":"3 часа",
                            {id: "4"   , value: "4 MB"}, // "2057":"3 часа",
                            {id: "8"   , value: "8 MB"}, // "2057":"3 часа",
                            {id: "16"  , value: "16 MB"}, // "2057":"3 часа",
                            {id: "32"  , value: "32 MB"}, // "2057":"3 часа",
                            {id: "64"  , value: "64 MB"}, // "2057":"3 часа",
                            {id: "128" , value: "128 MB"}, // "2057":"3 часа",
                            {id: "256" , value: "256 MB"}, // "2057":"3 часа",
                            {id: "512" , value: "512 MB"}, // "2057":"3 часа",
                            {id: "1024", value: "1024 MB"}, // "2057":"3 часа",
                        ],
                        on: {onChange: $scope.change} },
                    // { width: 100, view: "counter", id: "stgMaxUploadFileSize", label: "", value: $scope.data.MaxUploadFileSize, step: 1, min: 1, max: 100,
                    //     on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} },
                    // { width: 60, template : "MB", borderless: true},
                    {}
                ]}
            ]},

            { type : 'layout', padding : 5, rows : [
                {template : mcService.Lang(1917), borderless: true, autoheight: true},  // "1917":"Ограничить количество регистраций с одного:",
                { cols : [
                    { width: 130, rows: [
                        { view: "checkbox", id: "stgMaxRegFromOneIPLimit", value: $scope.data.MaxRegFromOneIPLimit, css: "finger", labelWidth : 0,
                            labelRight: mcService.Lang(1915), // "1915":"Ограничить количество регистраций с одного IP адреса",
                            on: { onChange: $scope.change }
                        },
                        { view: "checkbox", id: "stgMaxRegFromOneMACLimit", value: $scope.data.MaxRegFromOneMACLimit, css: "finger", labelWidth : 0,
                            labelRight: mcService.Lang(680), // "680": "Ограничить количество регистраций с одного MAC адреса",
                            on: { onChange: $scope.change }
                        },
                        { view: "checkbox", id: "stgMaxRegFromOneHWIDLimit", value: $scope.data.MaxRegFromOneHWIDLimit, css: "finger", labelWidth : 0,
                            labelRight: mcService.Lang(1916), // "1916":"Ограничить количество регистраций с одного HardwareID",
                            on: { onChange: $scope.change }
                        }
                    ]},
                    { width: 100, rows: [
                        { view: "counter", id: "stgMaxRegFromOneIPCount", label: "", value: $scope.data.MaxRegFromOneIPCount, step: 1, min: 1, max: 1000,
                            on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} },
                        { view: "counter", id: "stgMaxRegFromOneMACCount", label: "", value: $scope.data.MaxRegFromOneMACCount, step: 1, min: 1, max: 1000,
                            on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} },
                        { view: "counter", id: "stgMaxRegFromOneHWIDCount", label: "", value: $scope.data.MaxRegFromOneHWIDCount, step: 1, min: 1, max: 1000,
                            on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }
                    ]},
                    { width: 60, rows:[
                        {template : mcService.Lang(682), borderless: true},  // "682": "штук",
                        {template : mcService.Lang(682), borderless: true},  // "682": "штук",
                        {template : mcService.Lang(682), borderless: true}   // "682": "штук",
                    ]}, {}
                ]}
            ]},

            { type : 'layout', padding : 5, rows: [
                { template : mcService.Lang(1016), borderless: true, height: 26 }, // "1016":"Если пользователь давно не подключался к серверу",
                { cols : [
                    { view: "richselect", id: "stgOldDaysUserAction", value: $scope.data.OldDaysUserAction, options: mcService.getLangItemsFromList(683, 685), width: 372,
                        on: {onChange: $scope.change} // "1016":"Если пользователь давно не подключался к серверу",
                    },
                    { template : mcService.Lang(1017), borderless: true, width: 59 }, // "1017":"через",
                    { view: "counter", id: "stgOldDaysCount", value: $scope.data.OldDaysCount, label: "", width: 100, step: 1, min: 1, max: 900,
                        on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} //
                    },
                    { template : mcService.Lang(659), borderless: true, width: 60 }, // "659": "дней",
                    {}
                ]}
            ]},

            { type: 'layout', padding: 5, cols:[
                { rows: [
                    { template: mcService.Lang(1481), type: "header", hidden: !$scope.registered}, // "1481":"Данный раздел доступен только в коммерческой версии",
                    { view: "checkbox", id: "stgAdvertShow", value: $scope.data.AdvertShow, css: "finger", labelWidth : 0, disabled: _gLock.AdvertShow || $scope.registered,
                        labelRight: mcService.Lang(1018), // "1018":"Показывать рекламу на клиентах",
                        on: { onChange: $scope.change }
                    },

                    { view: "richselect", id: "stgAdsFile", options: [], disabled: _gLock.AdvertLink || $scope.registered, on: {
                        onChange: $scope.selectAdsFile
                    }},

                    { view: "text", id: "stgAdvertLink", value: $scope.data.AdvertLink, hidden: true, labelPosition: "top", disabled: _gLock.AdvertLink || $scope.registered,
                        label: mcService.Lang(1019), // "1019":"Ссылка на рекламный блок (URL)",
                        on: { onTimedKeyPress: $scope.change }
                    },

                    { cols: [
                        { width: 430, rows: [
                            {template : mcService.Lang(1020), borderless: true}, // "1020":"Размер рекламного блока в точках (по вертикали)",
                            {template : mcService.Lang(1021), borderless: true}  // "1021":"Частота обновления в минутах",
                        ]},
                        { width: 100, rows: [
                            { view: "counter", id: "stgAdvertHeight", label: "", value: $scope.data.AdvertHeight, disabled: _gLock.AdvertHeight || $scope.registered,
                                step: 1, min: 1, max: 100, on: { onChange: $scope.change, onTimedKeyPress: $scope.changeExc } },
                            { view: "counter", id: "stgAdvertQuantity", label: "", value: $scope.data.AdvertQuantity, disabled: _gLock.AdvertQuantity || $scope.registered,
                                step: 1, min: 1, max: 100, on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }
                        ]}
                    ]}
                ]}, {}
            ]},

            { type : 'layout', padding : 5, cols : [{
                rows: [
                    {cols : [
                        { view: "richselect",id: "stgDisplayNickStyle", value: $scope.data.DisplayNickStyle, options: fioList, labelPosition:"top", width: 530,// "1024":"Назначенный пользователем",
                            label: mcService.Lang(673), // "673": "Стиль отображения имен пользователей в чате",
                            on: {onChange: function(newV, oldV) {
                                if (newV == CUSTOMSTYLE){
                                    $$("stgDisplayNickFormat").show();
                                    $$("stgDisplayNickFormat_desc").show();
                                } else {
                                    $$("stgDisplayNickFormat").hide();
                                    $$("stgDisplayNickFormat_desc").hide();
                                }

                                $scope.change.apply(this, arguments);
                            }}
                        },
                        { view: "text", id: "stgDisplayNickFormat", hidden:true, value: $scope.data.DisplayNickFormat, options: fioList, labelPosition:"top", width: 450,// "1024":"Назначенный пользователем",
                            label: mcService.Lang(1025), // "1025":"Пользовательский формат отображения имен",
                            on: {onTimedKeyPress: $scope.change}
                        }, {}
                    ]}
                ]}, { width: 17 }]
            },
            {id: "stgDisplayNickFormat_desc", hidden:true, type : 'layout', padding : 5, cols : [
                {template : mcService.Lang(1026), height: 400, /*width: 620,*/ css: "_info selectable", borderless: true}, // "1026":"%uin% — UIN пользователя;<br>%
                // {}
            ]}, {}
        ]
    });

    if ($scope.data.DisplayNickStyle == CUSTOMSTYLE){
        $$("stgDisplayNickFormat").show();
        $$("stgDisplayNickFormat_desc").show();
    }

    $scope.stgAdsFile       = $$("stgAdsFile");
    $scope.stgAdvertLink    = $$("stgAdvertLink");

    mcService.disableContextMenu(_view);

    return _view;
}
function othersController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.Others;
    var angElement   = document.getElementById($scope.Name);
    var displayStyle = null;
    var noChange     = false;

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        if (displayStyle !== $scope.data.DisplayNickStyle){
            $rootScope.$broadcast('refreshUserManagerOnNextShow', []);
        }
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    $scope.selectAdsFile = function(id){
        var val = "";

        if (id === mcConst.emptyIndexS){
            $scope.stgAdvertLink.show();
        } else {
            $scope.stgAdvertLink.hide();
            val = id;
        }

        var old = $scope.stgAdvertLink.getValue();

        $scope.stgAdvertLink.setValue(val);

        if (!noChange){
            $scope.change.apply($scope.stgAdvertLink, [val, old]);
        }
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.AdsFiles,
            mcConst.SessionID,
            
            function (files) {
                var value   = "";
                var outLink = false;

                noChange = true;

                if ($scope.data.AdvertLink){
                    if (files.length) {
                        if (files.indexOf($scope.data.AdvertLink) >= 0) {
                            value = files[files.indexOf($scope.data.AdvertLink)];
                        } else {
                            value = $scope.data.AdvertLink
                            outLink = true;
                        }
                    } else {
                        value = $scope.data.AdvertLink;
                        outLink = true;
                    }
                } else {
                    value = mcConst.emptyIndexS;
                }

                files.forEach(function (fileName, i) {
                    files[i] = {
                        id   : fileName,
                        value: fileName
                    };
                });

                files.push({
                    id   : mcConst.emptyIndexS,
                    value: mcLang(2070) // "2070":"Указать свой URL",
                });

                $scope.stgAdsFile.define("options", files);
                $scope.stgAdsFile.setValue(outLink ? mcConst.emptyIndexS : value);
                $scope.stgAdvertLink.setValue(value); // value === mcConst.emptyIndexS || !outLink ? "" : value

                noChange = false;
            }
        ]);
    };

    $scope.show = function(){
        $scope.data = $rootScope.mcStorage.SettingsNetwork || {};
        $scope.registered = $rootScope.mcStorage.ServerInfo.Free;

        displayStyle = $scope.data.DisplayNickStyle;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initOthers($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();

        $scope.getData();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.getMcSettings($rootScope, $scope.show, true);
    });
}

function webSupportUsers($scope){
    "use strict";

    var thisView = $$($scope.Name);

    if (!thisView) {
        var fioList = mcService.GetFioFormatList();

        fioList.push({id:'9', value: mcService.Lang(1024)});
        fioList.unshift({id:'-1', value: mcService.Lang(2046)}); // "2046":"Использовать стандартный стиль",

        var disconnectOpt = [
            {id:'-1', value: mcLang(1613)}, // "1613":"никогда",
            {id: '0', value: mcLang(2054)}, // "2054":"10 минут",
            {id: '1', value: mcLang(2055)}, // "2055":"30 минут",
            {id: '2', value: mcLang(2056)}, // "2056":"1 час",
            {id: '3', value: mcLang(2057)}, // "2057":"3 часа",
            {id: '4', value: mcLang(2058)}, // "2058":"8 часов",
            {id: '5', value: mcLang(2059)}  // "2059":"сутки",
        ];

        var _guList = {
            view     : "list",
            select   : true,
            id       : "guList" + $scope.Name,
            data     : $scope.grData,
            height   : 150,
            navigation : true,
            template : function(obj) { return "ID:" + obj.ID + " " +obj.Name; },
            on       : {
                onSelectChange: function(id){
                    $scope.selectedItem = this.getItem(id);

                    if ($scope.selectedItem){
                        $scope.getGroupUsers($scope.selectedItem.ID);

                        $scope.showApplyPanel();
                    }
                }
            }
        };

        var _controls = {
            width : 150,
            id    : "controlBtns" + $scope.Name,
            rows  : [
                {view  : "button", value : mcService.Lang(50) , click: function(){ // "50" : "Добавить",
                    if ($scope.controlBtns.isEnabled()){
                        $scope.add();
                        $scope.showDialog();
                    }
                }},

                {view  : "button", value : mcService.Lang(859) , click: function(){ // "859":"Переименовать",
                    if ($scope.controlBtns.isEnabled()) {
                        $scope.edit();
                        $scope.showDialog();
                    }
                }},

                {view  : "button", value : mcService.Lang(52) , click: function(){ // "52" : "Удалить",
                    if ($scope.controlBtns.isEnabled()) {
                        $scope.del();
                    }
                }, type: "danger"}
            ]
        };

        thisView = webix.ui({
            type      : "space",
            padding   : 5,
            container : $scope.Name,
            id        : $scope.Name,
            borderless: true,
            rows      : [
                { type: "layout", rows: [

                    { cols: [
                        { view: "template", type: "header", template: mcService.Lang(938) }, // "938":"Web-поддержка",
                        { view: "toolbar", width: 36, cols: [
                            {view: "button", type: "icon", icon: "question", click: function () {
                                mcService.goToHelp();
                            }, width: 30}
                        ]}
                    ]},

                    { type: 'layout', padding: 5, rows : [
                        { view: "checkbox", id: "webSupportState", value: $scope.state, labelWidth: 0, css: "finger",
                            labelRight: mcService.Lang(941), // "941":"Включить службу Web-поддержки",
                            on: {
                                onChange: $scope.showApplyPanel
                            }
                        },

                        { view: "checkbox", id: "webSupportShowSelect", value: $scope.selectOperator, labelWidth: 0, css: "finger",
                            labelRight: mcService.Lang(2036), // "2036":"Показать выбор операторов"
                            on: {
                                onChange: $scope.showApplyPanel
                            }
                        },

                        { view: "checkbox", id: "webSupportInFrame", value: $scope.InFrame, labelWidth: 0, css: "finger",
                            labelRight: mcService.Lang(2050), // "2050":"Показать чат-поддержки во фрейме",
                            on: {
                                onChange: $scope.showApplyPanel
                            }
                        },

                        {cols: [
                            { view: "label", label: mcLang(2037), width: 130}, // "2037":"Требовать ввод:",

                            { view: "checkbox", id: "webSupportName", value: $scope.needName, labelWidth: 0, css: "finger", width: 100,
                                labelRight: mcService.Lang(129), // "129": "Имя",
                                on: {
                                    onChange: $scope.showApplyPanel
                                }
                            },

                            { view: "checkbox", id: "webSupportEmail", value: $scope.needEmail, labelWidth: 0, css: "finger", width: 100,
                                labelRight: mcService.Lang(70), // "70" : "Email",
                                on: {
                                    onChange: $scope.showApplyPanel
                                }
                            },

                            {}
                        ]},

                        { cols:[
                            { view: "select",id: "webWebSupportDisconnectIdleTime", value: $scope.DisconnectTime || -1, options: disconnectOpt, width: 350, labelWidth: 240,
                                label: mcService.Lang(2053), // "2053":"Отключить по бездействию через",
                                on: {onChange: $scope.showApplyPanel }
                            },
                            {}
                        ]},

                        { cols:[
                            { id: "webSupportPosition", view: "richselect", value: "1", label: mcLang(1315), width: 350, labelWidth: 100, options: { // "1315":"Позиция:", label: mcService.Lang(1315), labelAlign: "right", labelWidth: 85,
                                view     : "datasuggest",
                                textValue: "value",
                                body     : {
                                    template: function(obj){
                                        return "<img style='float:left' src='" + mcConst.imagesPath.all + "pos"+obj.id+".jpg'>" + obj.value;
                                    },
                                    type: {
                                        height: 150
                                    },
                                    data: [
                                        {id: '1',  value: mcService.Lang(1316)}, // "1316":"Справа, сверху",
                                        {id: '2',  value: mcService.Lang(1317)}, // "1317":"Справа, по центре",
                                        {id: '3',  value: mcService.Lang(1318)}, // "1318":"Справа, внизу",
                                        {id: '4',  value: mcService.Lang(1319)}, // "1319":"Внизу, справа",
                                        {id: '5',  value: mcService.Lang(1320)}, // "1320":"Внизу, по центру",
                                        {id: '6',  value: mcService.Lang(1321)}, // "1321":"Внизу, слева",
                                        {id: '7',  value: mcService.Lang(1322)}, // "1322":"Слева, сверху",
                                        {id: '8',  value: mcService.Lang(1323)}, // "1323":"Слева, по центру",
                                        {id: '9',  value: mcService.Lang(1324)}, // "1324":"Слева, внизу",
                                        {id: '10', value: mcService.Lang(1325)}, // "1325":"Сверху, справа",
                                        {id: '11', value: mcService.Lang(1326)}, // "1326":"Сверху, по центру",
                                        {id: '12', value: mcService.Lang(1327)}  // "1327":"Сверху, слева",
                                    ]
                                }},
                                on: {
                                    onChange: function(val){
                                        $scope.showApplyPanel();
                                    }
                                }
                            },
                            {}
                        ]}
                    ]}
                ]},

                { type : 'layout', padding : 5, cols : [{
                    rows: [
                        {cols : [
                            { view: "select",id: "webWebSupportDisplayNickStyle", value: $scope.NickStyle || -1, options: fioList, labelPosition:"top", width: 350,
                                label: mcService.Lang(673), // "673": "Стиль отображения имен пользователей в чате",
                                on: {onChange: function(newV, oldV) {
                                    if (newV == "9"){
                                        $$("webWebSupportDisplayNickFormat").show();
                                        $$("webDisplayNickFormatBtn").show();
                                    } else {
                                        $$("webWebSupportDisplayNickFormat").hide();
                                        $$("webDisplayNickFormatBtn").hide();
                                        $$("webDisplayNickFormat_desc").hide();
                                    }

                                    $scope.showApplyPanel();
                                }}
                            },
                            { view: "text", id: "webWebSupportDisplayNickFormat", hidden:true, value: $scope.NickFormat, options: fioList, labelPosition:"top", width: 350, keyPressTimeout: 500,
                                label: mcService.Lang(1025), // "1025":"Пользовательский формат отображения имен",
                                on: {onTimedKeyPress: $scope.showApplyPanel}
                            },
                            { view: "button", id: "webDisplayNickFormatBtn", hidden: true, value: "?", width: 30,
                                click: function () {
                                    var webDisplayNickFormat_desc = $$("webDisplayNickFormat_desc");

                                    if (webDisplayNickFormat_desc.isVisible()){
                                        webDisplayNickFormat_desc.hide();
                                    } else {
                                        webDisplayNickFormat_desc.show();
                                    }
                                }
                            }, {}
                        ]},

                        { template: mcLang(2103), borderless: true, autoheight: true}, // "2103":"Чат поддержки работает для:",

                        { cols:[
                            { id: "listType" + $scope.Name, view: "segmented", value: '1', labelAlign: "right", width: 500, labelWidth: 100, css: "hideOverflow", options: [
                                    { id: '0', value: mcService.Lang(1311)}, // "1311":"для пользователей",
                                    { id: '1', value: mcService.Lang(1312)}  // "1312":"для группы",
                                ], on: {
                                    onChange: $scope.showApplyPanel
                                }
                            },
                            {}
                        ]}

                    ]}, { width: 17 }
                ]},

                {id: "webDisplayNickFormat_desc", hidden:true, type : 'layout', padding : 5, cols : [
                    {template : mcService.Lang(1026), height: 350, /*width: 620,*/ css: "_info selectable", borderless: true}, // "1026":"%uin% — UIN пользователя;<br>%
                ]},

                { type: "layout", rows: [
                    { cols: [
                        { view: "template", type: "header", template: mcService.Lang(940) }, // "940":"Группы Web-поддержки",

                        { view: "toolbar", cols: [
                            {},

                            { view: "button", value: mcLang(2097), width: 180, click: function () { // "2097":"Скопировать скрипт",
                                mcService.copyTextToClipboard($scope.supportUhoCode.getValue(), mcLang(2098)); //"2098":"Скрипт скопирован",
                            }}
                        ]}
                    ]},

                    { cols: [
                        { cols: [
                            _guList,
                            _controls,
                        ]},

                        { view: "textarea", height: 80, id: "supportUhoCode" }
                    ]},

                    { view: "resizer"},

                    { cols:[
                        { rows: [
                            { type: 'header', height: 34, template: mcService.Lang(919) },// "919":"Пользователи группы",
                            {
                                // view: "list", navigation: true, drag: true, select: "multiselect",
                                id          : 'currentList' + $scope.Name,
                                view        : "datatable",
                                resizeColumn: true,
                                drag        : true,
                                select      : "row",
                                multiselect : true,
                                headerRowHeight: 25,
                                minColumnWidth : 70,
                                navigation  : false,
                                columns     : [
                                    { id:"UIN",         header:"UIN", width: 55,     sort:"int"},
                                    { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                                ],

                                // template: function(obj) {
                                //     return obj.DisplayName + " <span style='float:right'>(UIN: " + obj.UIN + ")</span>"
                                // },
                                on : {
                                    onSelectChange: function() {
                                        if (!mcService.convertIntToBool($scope.listType.getValue())) {
                                            $scope.showApplyPanel();
                                        }
                                    },
                                    onAfterDrop   : $scope.moveUsers
                                }, onContext:{}
                            }
                        ]},

                        { rows: [ // Guest group
                            { cols: [
                                { type: 'header', template: mcService.Lang(1632), width: 160 }, // "1632":"Все пользователи",
                                { view: "toolbar", height: 30, cols: [
                                    { view: "text", height: 34, keyPressTimeout: 500, placeholder: mcService.Lang(71), // "71" : "Введите текст для поиска",
                                        on : {
                                            onTimedKeyPress : function(){
                                                $scope.doFilter.apply(this, [$scope.allUserList]);
                                            }
                                        }
                                    },

                                    { view: "button", type: "iconButton", icon: "refresh", width: 30, css: "noBorder", click: function(){
                                        $scope.refresh('refresh');
                                    }}
                                ]}
                            ]},

                            { type: "header", rows: [{
                                // view : "list", navigation: true, drag: true, select: "multiselect",
                                // template: function(obj) {
                                //     return obj.DisplayName + " <span style='float:right'>(UIN: " + obj.UIN + ")</span>"
                                // },
                                id          : 'allUserList' + $scope.Name,
                                view        : "datatable",
                                resizeColumn: true,
                                drag        : true,
                                select      : "row",
                                multiselect : true,
                                headerRowHeight: 25,
                                minColumnWidth : 70,
                                navigation  : false,
                                columns     : [
                                    { id:"UIN",         header:"UIN", width: 55,     sort:"int"},
                                    { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                                ],
                                on : {
                                    onAfterDrop : $scope.moveUsers
                                }, onContext:{}
                            }]}
                        ]}
                    ]}
                ]},

                { cols: [
                    { view: "button", label: mcService.Lang(918), type: 'next', click: function(){ // "918":"Удалить пользователя из группы",
                        $scope.moveByButton('currentList', 'allUserList');
                    }},
                    { width: 10},
                    { view: "button", label: mcService.Lang(917), type: 'prev', click: function(){ // "917":"Переместить пользователя в группу",
                        $scope.moveByButton('allUserList', 'currentList');
                    }}
                ]}

            ]
        });

        $scope.allUserList    = $$('allUserList' + $scope.Name);
        $scope.currentList    = $$('currentList' + $scope.Name);
        $scope.guList         = $$("guList" + $scope.Name);
        $scope.supportUhoCode = $$("supportUhoCode");
        $scope.listType       = $$("listType" + $scope.Name);
        $scope.showSelect     = $$("webSupportShowSelect");

        $scope.controlBtns    = $$("controlBtns" + $scope.Name);

        $scope.webSupportState      = $$("webSupportState");
        $scope.webSupportShowSelect = $$("webSupportShowSelect");
        $scope.webSupportName       = $$("webSupportName");
        $scope.webSupportEmail      = $$("webSupportEmail");
        $scope.webSupportNickFormat = $$("webWebSupportDisplayNickFormat");
        $scope.webDisconnectTime    = $$("webWebSupportDisconnectIdleTime");
        $scope.webDisplayNickStyle  = $$("webWebSupportDisplayNickStyle");
        $scope.webSupportInFrame    = $$("webSupportInFrame");

        $scope.webSupportPosition   = $$("webSupportPosition");

        new mcService.ContextMenu($scope.allUserList, null, null, function(){
            $scope.regShowWindow(this.config.id, this);
        });
        new mcService.ContextMenu($scope.currentList, null, null, function(){
            $scope.regShowWindow(this.config.id, this);
        });

        mcService.disableContextMenu(thisView);
    }/* else {

        $scope.webSupportState     .setValue($scope.state);
        $scope.webSupportShowSelect.setValue($scope.selectOperator);
        $scope.webSupportName      .setValue($scope.needName );
        $scope.webSupportEmail     .setValue($scope.needEmail);
    }*/

    if (!$scope.showDialog){
        $scope.showDialog = function (){
            if ($scope.dialogWindow){
                $scope.dialogWindow.destructor();
            }

            $scope.dialogWindow = webix.ui({
                view     : "window",
                position : "center",
                modal    : true,
                width    : 300,
                head     : $scope.wndHead,
                body     : {
                    view : 'form',
                    rules:{
                        "Name"    : $scope.checkName//webix.rules.isNotEmpty
                    },
                    elements : [{
                        view     : "text",
                        id       : 'dialog' + $scope.Name,
                        label    : mcService.Lang(910), // "910":"Название группы прав",
                        name     : 'Name',
                        required : "true",
                        labelPosition : 'top'
                    }, {
                        cols : [{
                            view  : "button",
                            value : mcService.Lang(104), // "104": "Сохранить",
                            click : function() {
                                $scope.confirm.apply(this.getFormView());
                            }
                        }, {
                            view  : "button",
                            type  : "danger",
                            value : mcService.Lang(103), // "103": "Отмена",
                            click : function(){
                                $scope.dialogWindow.hide();
                            }
                        }]
                    }]
                },
                on : {
                    onShow : function(){
                        if ($scope.selectedItem) {
                            this.getChildViews()[1].getChildViews()[0].setValue($scope.selectedItem.Name);
                        }

                        this.getChildViews()[1].getChildViews()[0].focus();

                        $scope.regShowWindow(this.config.id, this);
                    }
                }
            });

            webix.UIManager.addHotKey("Enter", function() {
                $scope.confirm.apply($scope.dialogWindow.getChildViews()[1]);

                return false;
            }, $$('dialog' + $scope.Name));

            webix.UIManager.addHotKey("Esc", function() {
                $scope.dialogWindow.hide();

                return false;
            }, $$('dialog' + $scope.Name));

            $scope.dialogWindow.show();
        }
    }

    return thisView;
}
function webSupportController($scope, $rootScope){
    "use strict";

    $scope.Name   = mcConst.dataModels.WebSupport;
    $scope.state  = null;       // состояние сервиса
    $scope.grData = [];        // Данные, список групп веб-поддержки
    $scope.crData = null;        // Данные, список юзеров выбраной группы
    // $scope.reDraw = true;        // нужно ли перерисовать интерфейс
    $scope.guList = null;        // Список в интерфейсе, отображает $scope.grData

    $scope.userList      = null; // Данные, список всех пользователей на сервере
    $scope.selectedItem  = null; // Выбранная группа
    $scope.currentList   = null; // Список в интерфейсе, юзеры выбранной группы
    $scope.showDialog    = null;
    $scope.confirm       = null;
    $scope.dialogWindow  = null;
    $scope.exportConfig = {
        id      : '',
        text    : '',
        position: '1',
        uin     : '',
        url     : '',
        secure  : false
    };

    var defaultGroup ="Default Group";
    var angElement = document.getElementById($scope.Name);
    var __view     = null;
    var backupInfo = {};
    var canChange  = false;

    var uhoText = "<!--== MyChat Web Support ==-->\n" +
        "<script type=\"text/javascript\">\n" +
        "    window.__setMyChatOption = function (opt) {\n" +
        "        try {\n" +
        "            window.mc_uho_opt = Object.prototype.toString.call( opt ) === '[object Object]' ? opt : JSON.parse(opt);\n" +
        "            var run   = document.createElement(\"script\");\n" +
        "            run.type  = \"text/javascript\";\n" +
        "            run.async = true;\n" +
        "            run.src   = \"#{src}#{url}/chat/uho/supportUho.js\";\n" +
        "            var s     = document.getElementsByTagName(\"script\")[0];\n" +
        "            s.parentNode.insertBefore(run, s);\n" +
        "        } catch (e) {\n" +
        "            console.warn(e.message);\n" +
        "        }\n" +
        "    }\n" +
        "</script>\n" +
        "<script src=\"#{src}#{url}/getSupportOptions.js\" async type=\"text/javascript\"></script>";

    backupInfo[mcConst.serverOptionsNames.EnableWebSupport]  = "";
    backupInfo[mcConst.serverOptionsNames.ShowOperatorsList] = "";
    backupInfo[mcConst.serverOptionsNames.AskUserFields]     = "";
    backupInfo[mcConst.serverOptionsNames.DisplayNickStyle]  = "";
    backupInfo[mcConst.serverOptionsNames.DisplayNickFormat] = "";
    backupInfo[mcConst.serverOptionsNames.InFrame]           = "";
    backupInfo[mcConst.serverOptionsNames.SupportOptions]    = "";
    backupInfo[mcConst.serverOptionsNames.DisconnectIdleTime]= "";

    function getFields(){
        return ([].concat($scope.needName ? 'name' : []).concat($scope.needEmail ? "email" : [])).join(',');
    }

    function fillCode(){
        var url = mcService.createHostPath($rootScope.mcStorage.SettingsNetwork.ExternalIP, $rootScope.mcStorage.SettingsNetwork.WEBTCPPort, true);
        var ssl = location.protocol !== 'http:';

        if (!$scope.supportUhoCode.getValue() || ($scope.exportConfig.url !== url || $scope.exportConfig.secure !== ssl)){
            $scope.exportConfig.url    = url;
            $scope.exportConfig.secure = ssl;

            $scope.supportUhoCode.setValue(mcService.myReplaceFormated(uhoText, {
                url: $scope.exportConfig.url,
                src: $scope.exportConfig.secure ? "https://" : "http://"
            }));
        }
    }

    function fillData(info){
        $scope.state          =   info[mcConst.serverOptionsNames.EnableWebSupport];
        $scope.selectOperator = !!info[mcConst.serverOptionsNames.ShowOperatorsList];
        $scope.needName       =   info[mcConst.serverOptionsNames.AskUserFields].indexOf('name')  !== -1;
        $scope.needEmail      =   info[mcConst.serverOptionsNames.AskUserFields].indexOf('email') !== -1;
        $scope.NickStyle      =   info[mcConst.serverOptionsNames.DisplayNickStyle];
        $scope.NickFormat     =   info[mcConst.serverOptionsNames.DisplayNickFormat];
        $scope.DisconnectTime =   info[mcConst.serverOptionsNames.DisconnectIdleTime];
        $scope.InFrame        = !!info[mcConst.serverOptionsNames.InFrame];
        $scope.webSupOptions  =   mcService.StringToObj(info[mcConst.serverOptionsNames.SupportOptions]);

        $scope.webDisplayNickStyle .setValue($scope.NickStyle);
        $scope.webSupportNickFormat.setValue($scope.NickFormat);
        $scope.webSupportInFrame   .setValue($scope.InFrame);
        $scope.webDisconnectTime   .setValue($scope.DisconnectTime);
        $scope.webSupportShowSelect.setValue($scope.selectOperator);
        $scope.webSupportState     .setValue($scope.state);
        $scope.webSupportName      .setValue($scope.needName);
        $scope.webSupportEmail     .setValue($scope.needEmail);
        $scope.webSupportPosition  .setValue($scope.webSupOptions.position);
        $scope.listType            .setValue($scope.webSupOptions._type);
    }

    function fillGroups(data){
        canChange = false;

        $scope.guList.clearAll();
        $scope.guList.define('data', data);
        $scope.guList.refresh();

        if ($scope.webSupOptions.group !== void(0) && $scope.guList.getItem($scope.webSupOptions.group)) {
            $scope.guList.count() && $scope.guList.select($scope.webSupOptions.group);

            if ($scope.webSupOptions.url != $scope.exportConfig.url){
                $scope.showApplyPanel();
            }
        } else {
            $scope.selectFirstItemGroupList();
        }
    }

    // ====================================================================

    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        // HideClose: true,
        onApply: function(){
            var selected = $scope.currentList.getSelectedItem();
            var byGroup  = mcService.convertIntToBool($scope.listType.getValue());

            $scope.exportConfig.group = $scope.guList.getSelectedItem().ID;

            if (selected && selected.length) {
                $scope.exportConfig.uin = [];

                for (var i = 0; i < selected.length; i++) {
                    $scope.exportConfig.uin.push(selected[i].UIN);
                }
            } else
            if (!selected && !byGroup) {
                var allUsers = $scope.currentList.serialize();

                $scope.exportConfig.uin = [];

                for (var i = 0; i < allUsers.length; i++) {
                    $scope.exportConfig.uin.push(allUsers[i].UIN);
                }
            } else {
                $scope.exportConfig.uin = selected ? [selected.UIN] : [];
            }

            $scope.exportConfig.position = $scope.webSupportPosition.getValue();

            // === show select ===

            $scope.selectOperator = mcService.convertIntToBool($scope.showSelect.getValue());

            // ===================
            
            $scope.webSupOptions = {
                id      : $scope.exportConfig.id,
                text    : $scope.exportConfig.text,
                position: $scope.exportConfig.position,
                url     : $scope.exportConfig.url,
                secure  : $scope.exportConfig.secure,
                src     : $scope.exportConfig.secure ? "https://" : "http://",
                select  : $scope.selectOperator, //$scope.showSelect.getValue(),
                items   : byGroup ? $scope.exportConfig.group : "[" + $scope.exportConfig.uin.join(',') + "]",
                _uins   : $scope.exportConfig.uin,
                group   : $scope.exportConfig.group,
                _type   : byGroup,
                inFrame : $scope.InFrame ? "mcChatFrame" : "",
                fields  : getFields()
            };

            // === state ===

            $scope.state = mcService.convertIntToBool($scope.webSupportState.getValue());

            // === nick style ===

            $scope.NickStyle = $scope.webDisplayNickStyle.getValue();

            // === disconnect time ===

            $scope.DisconnectTime = $scope.webDisconnectTime.getValue();

            // === nick format ===

            $scope.NickFormat = mcService.trim($scope.webSupportNickFormat.getValue());

            // === in frame ===

            $scope.InFrame = mcService.convertIntToBool($scope.webSupportInFrame.getValue());

            // === need name email ===

            $scope.needName  = $scope.webSupportName.getValue();
            $scope.needEmail = $scope.webSupportEmail.getValue();

            // =====================

            backupInfo[mcConst.serverOptionsNames.EnableWebSupport]  = $scope.state;
            backupInfo[mcConst.serverOptionsNames.ShowOperatorsList] = $scope.selectOperator;
            backupInfo[mcConst.serverOptionsNames.AskUserFields]     = getFields();
            backupInfo[mcConst.serverOptionsNames.DisplayNickStyle]  = $scope.NickStyle;
            backupInfo[mcConst.serverOptionsNames.DisplayNickFormat] = $scope.NickFormat;
            backupInfo[mcConst.serverOptionsNames.InFrame]           = $scope.InFrame;
            backupInfo[mcConst.serverOptionsNames.SupportOptions]    = $scope.webSupOptions;
            backupInfo[mcConst.serverOptionsNames.DisconnectIdleTime]= $scope.DisconnectTime;

            // =====================

            var sendData = mcService.Marge({}, backupInfo);

            sendData.OptionsFields = Object.keys(sendData).join(',');
            sendData[mcConst.serverOptionsNames.SupportOptions] = JSON.stringify(sendData[mcConst.serverOptionsNames.SupportOptions]);

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_set_custom_options,
                mcConst.SessionID,

                JSON.stringify(sendData)
            ]);
        },
        onClose: function () {
            canChange = false;

            $scope.grData = [].concat($rootScope.mcStorage[mcConst.dataModels.WebSupport]);

            $scope.grData.forEach(function (el) {
                el.id = el.ID;
            });

            fillData(backupInfo);

            fillGroups($scope.grData);

            canChange = true;
        }
    };

    // ====================================================================

    $scope.showApplyPanel = function(){
        var selected = $scope.currentList.getSelectedItem();
        var byGroup  = mcService.convertIntToBool($scope.listType.getValue());

        if (!byGroup) {
            $scope.guList.disable();
            $scope.controlBtns.disable();
        } else {
            $scope.guList.enable();
            $scope.controlBtns.enable();
        }

        if (canChange && (selected || $scope.guList.getSelectedItem())) {
            $scope.changedData.data.ShowDesc = true;
            $scope.changedData.data.Header   = mcService.Lang(1534); // "1534":"Веб-поддержка",
            $scope.changedData.ApplyTitle    = mcService.Lang(1525); // "1525":"Сохранить изменения",

            $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
        }
    };

    $scope.checkDuplicate = function(name){
        var res = true;

        for (var i = 0; i < $scope.grData.length; i++){
            if ($scope.grData[i].Name == name){
                res = false;

                break;
            }
        }

        return res;
    };

    $scope.checkName = function(name){
        var _name = mcService.trim(name);
        var res   = false;

        if ((_name != '') && mcService.isSymbolicNumbers(_name) && $scope.checkDuplicate(_name)){
            res = true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(912)]); // "912":"Название группы не должно быть пустым и совпадать с уже существуюющей!",
        }

        return res;
    };

    $scope.add = function(clone){
        $scope.confirm = function (){
            var self = this;
            var name = self.getChildViews()[0].getValue();
            var isValid = this.validate();

            if (isValid){ // $scope.checkName(name)
                var params = [
                    mcConst._CMD_.cs_adm_add_websupport_group,
                    mcConst.SessionID,
                    name
                ];

                self.getParentView().hide();

                $rootScope.$broadcast('SendCMDToServer', params);
            }
        };

        if (!clone) $scope.selectedItem = null;

        $scope.wndHead      = mcService.Lang(911); // "911":"Добавление новой группы прав",
    };

    $scope.edit = function(){
        $scope.confirm = function (){
            if ($scope.selectedItem.ID) {
                var self = this;
                var name = self.getChildViews()[0].getValue();
                var _id  = $scope.selectedItem.ID;

                if ($scope.checkName(name, _id)){
                    var params = [
                        mcConst._CMD_.cs_adm_rename_websupport_group ,
                        mcConst.SessionID,
                        name,
                        _id
                    ];

                    self.getParentView().hide();

                    $rootScope.$broadcast('SendCMDToServer', params);
                }
            }
        };

        $scope.wndHead = mcService.Lang(914); // "914":"Переименовать группу прав",
    };

    $scope.del = function(){
        if ($scope.selectedItem){
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(913, $scope.selectedItem.Name), // "913":"Удалить группу \"%s\"?",
                ok    : mcService.Lang(581), // "581": "Удалить",
                cancel: mcService.Lang(103), // "103": "Отмена",
                callback:function(yes){
                    if (yes){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.cs_adm_delete_websupport_group,
                            mcConst.SessionID,
                            $scope.selectedItem.ID,
                            
                            function(){
                                $scope.refresh('remove');
                            }
                        ]);
                    }
                }
            }));
        }
    };

    $scope.moveByButton = function(from, to, onlyMove){
        var guList       = $scope.guList;

        if (!guList.count()) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_websupport_group,
                mcConst.SessionID,

                defaultGroup
            ]);

            setTimeout(function () {
                $scope.moveByButton(from, to, onlyMove);
            }, 100);
        } else {
            if (onlyMove && $scope[from].count()) {
                $scope[from].selectAll();
            }

            var selectedItems = $scope[from].getSelectedItem();

            if (mcService.isObject(selectedItems)) {
                selectedItems = [selectedItems];
            }

            if (selectedItems) {
                for (var i = 0; i < selectedItems.length; i++) {
                    // if (to === "currentList") {
                        $scope[to].add(selectedItems[i]);
                    // }
                    //
                    // if (from === "currentList") {
                        $scope[from].remove(selectedItems[i].id);
                    // }
                }

                $scope[to].sort("DisplayName", "asc", "string");

                if (!onlyMove) {
                    $scope.moveUsers.apply(null, [{
                        fromList: from + $scope.Name,
                        toList  : to + $scope.Name,
                        uList   : selectedItems
                    }]);
                }
            }
        }
    };

    $scope.moveUsers = function(context){
        var fromList = context.fromList || context.from.config.id;
        var toList   = context.toList   || context.to.config.id;
        var userList = [].concat(context.uList || context.source);
        var res      = [];
        var guList   = $scope.guList;

        if (!guList.count()) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_websupport_group,
                mcConst.SessionID,

                defaultGroup
            ]);

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_user_to_websupport_group,
                mcConst.SessionID,

                $$(toList).getItem(userList[0]).UIN,
                1 // Default Group ID
            ]);
        } else {
            if (fromList !== toList) {
                if (this && this.sort) {
                    this.sort("DisplayName", "asc", "string");
                }

                var item = $$(toList);

                for (var i = 0; i < userList.length; i++){
                    res.push(item.getItem(userList[i].id || userList[i]).UIN);
                }

                if (res.length > 0){
                    if (toList === ('allUserList' + $scope.Name)){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.cs_adm_delete_user_from_websupport,
                            mcConst.SessionID,

                            res.join(',')
                        ]);
                    } else {
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.cs_adm_add_user_to_websupport_group,
                            mcConst.SessionID,

                            res.join(','),
                            $scope.selectedItem.ID
                        ]);
                    }
                }
            }

            $scope.showApplyPanel();
        }

        // $$(fromList).unselectAll();
        //
        // return false;
    };

    $scope.doFilter = function (list){
        var value = this.getValue().toLowerCase();

        list.filter(function(obj){
            return (obj.DisplayName.toLowerCase().indexOf(value) >= 0) ||
                (obj.UIN.toString().indexOf(value) >= 0);
        })
    };

    $scope.getGroupUsers = function(id){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_websupport_group_users,
            mcConst.SessionID,
            id
        ]);
    };

    $scope.selectFirstItemGroupList = function(){
        var guList       = $scope.guList;
        var selectedItem = guList.getSelectedItem() || [];

        if (mcService.isObject(selectedItem)){ // when any list item selected
            $scope.getGroupUsers(selectedItem.ID);
        } else

        if (mcService.isArray(selectedItem) && selectedItem.length === 0){ // no list item selected
            guList.select(guList.getFirstId());
        }
    };

    $scope.refresh = function(cmd, data){
        var list = $scope.guList;

        switch (cmd){
            case 'modify':
                var item = list.getItem($scope.selectedItem.id);
                var m_id = mcService.getIdxByIdFromData($scope.grData, $scope.selectedItem.id);

                item.Name = data.Name;
                item.id   = item.ID;

                list.refresh();

                if (m_id) {
                    $scope.grData[m_id].Name = data.Name;
                }
            break;

            case 'add':
                data.id = data.ID;

                list.add(data);
                list.select(list.getLastId());
                list.scrollTo(0, 9999);

                $scope.grData.push(data);
                $rootScope.mcStorage[mcConst.dataModels.WebSupport] = $scope.grData;
            break;

            case 'remove':
                var r_id = mcService.getIdxByIdFromData($scope.grData, $scope.selectedItem.id);

                $scope.moveByButton('currentList', 'allUserList', true);

                canChange = false;

                list.remove($scope.selectedItem.id);

                var fID = list.getFirstId();

                if (!fID){
                    $scope.webSupOptions.group = 1; // default group id

                    $rootScope.$broadcast('SendCMDToServer', [
                        mcConst._CMD_.cs_adm_add_websupport_group,
                        mcConst.SessionID,

                        defaultGroup
                    ]);

                    list.add({
                        ID  : 1,
                        id  : 1,
                        Name: defaultGroup
                    });

                    fID = 1;
                }

                list.select(fID);

                $scope.webSupOptions.group = fID;
                $scope.webSupOptions.items = fID;

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst._CMD_.cs_adm_set_custom_options,
                    mcConst.SessionID,

                    JSON.stringify({
                        OptionsFields: mcConst.serverOptionsNames.SupportOptions,
                        WebSupportOptions: JSON.stringify($scope.webSupOptions)
                    })
                ]);

                if (r_id) {
                    $scope.grData.splice(r_id, 1);
                    $rootScope.mcStorage[mcConst.dataModels.WebSupport] = $scope.grData;
                }

                canChange = true;
            break;

            case 'refresh':
                // $scope.reDraw = true;
                $scope.getData();
            break;

            case 'refreshList':
                $scope.crData = data;

                $scope.crData.forEach(function (el) {
                    el.id = el.UIN;
                });

                $scope.currentList.clearAll();
                $scope.currentList.define('data', $scope.crData);
                $scope.currentList.refresh();

                if (!canChange){
                    if (!$scope.webSupOptions._type && $scope.webSupOptions._uins && $scope.webSupOptions._uins.length) {
                        $scope.webSupOptions._uins.forEach(function (id) {
                            if ($scope.currentList.count()){
                                $scope.currentList.select(id, true);
                            }
                        });
                    }
                    
                    canChange = true;
                }
            break;
        }

        $rootScope.mcStorage[mcConst.dataModels.WebSupport] = [].concat($scope.grData || []);
    };

    $scope.getData = function(){
        if ($scope.state === null /*|| $scope.reDraw*/){
            $rootScope.$broadcast('SendCMDToServer', [ // эти настройи храняться в общем наборе серверных настроек
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_custom_options,
                mcConst.SessionID,

                Object.keys(backupInfo).join(','),

                function(info){
                    backupInfo = info;

                    canChange = false;

                    fillData(info);
                }
            ]);
        }

        // if ($scope.reDraw){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_websupport_groups,
                mcConst.SessionID,

                function( data ){
                    canChange = false;

                    $rootScope.mcStorage[mcConst.dataModels.WebSupport] = data || [];

                    $scope.grData = [].concat($rootScope.mcStorage[mcConst.dataModels.WebSupport]);

                    $scope.grData.forEach(function (el) {
                        el.id = el.ID;
                    });

                    $scope.show();

                    fillGroups($scope.grData);

                    $scope.getAllUsers();

                    canChange = true;
                }
            ]);

            // $scope.reDraw = false;
        // } else {
        //     $scope.grData = _grData || [];
        //     $scope.reDraw = false;
        // }
    };

    $scope.getAllUsers = function(){
        $rootScope.$broadcast('getAllUserList', [false,
            function(){
                $scope.userList = webix.copy($rootScope.mcStorage[mcConst.dataModels.UserManager].Users);
                // $scope.reDraw   = true;

                var list = $scope.allUserList;

                $scope.userList.sort(function (a, b) {
                    return mcService.sortAB(a.DisplayName, b.DisplayName);
                });

                list.clearAll();
                list.define('data', $scope.userList);
                list.refresh();
            }, {
                // Params : 'NOTWEBOPERATORS',
                Filters: 'UIN,DISPLAYNAME'
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function (){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        __view = webSupportUsers($scope);

        mcService.initResize(__view, $scope.Name);
    };

    // ====================================================================

    $scope.$on('refresh' + $scope.Name, function(e, args){
        $scope.refresh.apply(null, args);
    });

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args) {
        $scope.exportConfig.text   = mcService.Lang(1328); // "1328":"Задать вопрос",
        $scope.exportConfig.id     = mcConst.UserInfo.HWID;

        canChange = false;

        $scope.show();

        canChange = true;

        if (!$scope.userList || !$scope.userList.length){
            mcService.getMcSettings($rootScope, function () {
                $scope.getData();

                fillCode();
            }, true);
        } else {
            $scope.getData();

            fillCode();
        }
    });
}

"use strict";

function initMyChatGuest($scope){
    var blockWidth = 550;
    var labelWidth = 120;
    var inviteMailPresetPreview = null;

    var api = $$($scope.Name);

    if (api){
        api.destructor();
    }

    function redrawPreview(){
        inviteMailPresetPreview.define('template', $$('stgInvitePreset').getValue());
        inviteMailPresetPreview.refresh();

        $scope.change.apply(this, arguments);
    }

    api = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { type: "layout", rows: [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(945) }, // "945":"MyChat Guest",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type : 'layout', padding : 5, rows: [{
                    view: "checkbox", id: "webEnableMyChatGuest", value: $scope.data.EnableMyChatGuest, labelWidth: 0, css: "finger",
                    labelRight: mcService.Lang(954), // "954":"Включить сервис приглашенийвнешних контактов MyChat Guest",
                    on: {
                        onChange: $scope.change
                    }}
                ]}
            ]},

            { view: "template", type: "header", template: mcService.Lang(932) }, // "932":"Текст и тема письма с приглашением",
            { cols: [
                {type: 'layout', padding: 5, rows : [
                    { view: "text", id:'stgSubjectEmailForInvite', value: $scope.data.SubjectEmailForInvite,  labelWidth: labelWidth,
                        label: mcService.Lang(934), on: {onTimedKeyPress: $scope.change}}, // "934":"Тема письма",
                    { template: mcService.Lang(933), height: 30, borderless: true }, // "933":"Шаблон письма приглашения",
                    {
                        view   : "textarea",
                        id     :'stgInvitePreset',
                        value  : $scope.data.InvitePreset,
                        css    : 'textArea',
                        on     : {
                            //onChange:        $scope.change,
                            onTimedKeyPress: redrawPreview
                        }
                    }
                ]}, { view:"resizer", borderless: true },
                { type: 'layout', rows: [
                    { template: mcService.Lang(936), height: 35, borderless: true }, // "936":"Предпросмотр письма",
                    { template: "&nbsp;", id: "inviteMailPresetPreview", autoheight: true, borderless: true},
                    {}
                ]}
            ]},

            { view:"resizer" },
            { template: mcService.insertIco("fa-info-circle") + mcService.Lang(935), autoheight: true, borderless: true, css: "_info selectable"}// "935":"<b>Константы</b>
        ]
    });

    inviteMailPresetPreview = $$('inviteMailPresetPreview');

    webix.ready(function(){
        redrawPreview.apply($$('stgInvitePreset'), []);
    });

    mcService.disableContextMenu(api);

    return api;
}
"use strict";

function mychatGuestController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.MyChatGuest;
    $scope.data = {};

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_custom_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    }, mcConst._CMD_.cs_adm_get_custom_options);

    var angElement = document.getElementById($scope.Name);

//    $scope.change = function(state){
//        if (canChange) {
//            var newState = mcService.convertIntToBool(state);
//
//            $rootScope.$broadcast('SendCMDToServer', [
//                mcConst._CMD_.cs_adm_set_custom_options,
//                mcConst.SessionID,
//                JSON.stringify({
//                    OptionsFields    : mcConst.serverOptionsNames.EnableMyChatGuest,
//                    EnableMyChatGuest: newState
//                })
//            ]);
//
//            if (newState){
//                webix.message(mcService.Lang(1008, mcService.Lang(945))); //  "1008":"Сервис \"%s\" включен", "945":"MyChat Guest",
//            } else {
//                webix.message(mcService.Lang(1009, mcService.Lang(945))); //  "1009":"Сервис \"%s\" отключен", "945":"MyChat Guest",
//            }
//        }
//    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initMyChatGuest($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_custom_options,
            mcConst.SessionID,
            "EnableMyChatGuest,SubjectEmailForInvite,InvitePreset",
            function(info){
                $scope.data = info; // [mcConst.serverOptionsNames.EnableMyChatGuest]
                $scope.data.OptionsFields = "EnableMyChatGuest,SubjectEmailForInvite,InvitePreset";

                $rootScope.mcStorage[mcConst._CMD_.cs_adm_get_custom_options] = info;

                $scope.show();
            }
        ]);
    });
}

function initHistory ($scope) {
    "use strict";

    function getOptions() {
        return {
            filter:function(item, value){
                return item.value.toString().toLowerCase().indexOf(value.toLowerCase()) !== -1;
            },
            width: 400,
            fitMaster:false,
            body:{
                template: function (obj) {
                    return mcService.myReplaceFormated(
                        "<span class='listTime'>#{date} -</span>#{uin} #{name}",
                        {
                            name: obj.value,
                            date: obj.date,
                            uin : obj.value.indexOf("noname") === 0 ? "" : obj.id.toString().length > 10 ? " [0]" : (" [" + obj.id.toString() + "]")
                        }
                    );
                }
            }
        };
    }
    function onEnter(code, where) {
        if (code === mcConst.keyCodes.enter) {
            $scope.filterFields[where] = this.getValue();
            this.blur();

            $scope.getLogs();
        }
    }

    // ------------------------------

    var web         = $$($scope.Name);
    var types       = [
        {id: "1", value: mcLang(1932)},    // "1932":"Серверные ошибки",
        {id: "2", value: mcLang(1931)},    // "1931":"Сетевые ошибки",
        {id: "3", value: mcLang(1933)},    // "1933":"Сообщения сервера",
        {id: "4", value: mcLang(1934)},    // "1934":"Сетевой трафик",
        {id: "5", value: mcLang(1937)}     // "1937":"Логи скриптов",
    ];
    var clientTypes = [];
    var __list      = mcService.Marge({}, mcConst._CMD_.ClientType);
    var timePeriods = [
        {id: "1",  value: mcLang(1921)}, // "1921":"1 час",
        {id: "3",  value: mcLang(1922)}, // "1922":"3 часа",
        {id: "6",  value: mcLang(1923)}, // "1923":"6 часов",
        {id: "24", value: mcLang(1924)}, // "1924":"сутки",
        {id: "-1", value: mcLang(1925)}  // "1925":"выбрать период",
    ];

    var logsType = []
        .concat(mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewSystemLog)  ? { id: "log_" + $scope.logTypes.system,   value: mcLang(1149)} : []) // "1149":"Системные протоколы",
        .concat(mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewFTPLog)     ? { id: "log_" + $scope.logTypes.ftp,      value: mcLang(1150)} : []) // "1150":"FTP протоколы",
        .concat(mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewNodeJSLogs) ? { id: "log_" + $scope.logTypes.nodejs,   value: mcLang(1151)} : []) // "1151":"NodeJS протоколы",
        .concat(mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewLogsAllPrivates) || mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewLogsSelfPrivates)
            ? { id: "log_" + $scope.logTypes.private,  value: mcLang(1147)} // "1147":"Переговоры в приватах",
            : [])
        .concat(mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewLogsAllChannels) ? { id: "log_" + $scope.logTypes.channels, value: mcLang(1148)} : [])  // "1148":"Переговоры в конференциях",
    ;
    // { id: "log_" + $scope.logTypes.audit,    value: mcLang(1213)}, // "1213":"Протокол аудита",
    // { id: "log_" + $scope.logTypes.script,   value: mcLang(1616)}  // "1616":"Логи скриптов",

    Object.keys(__list).forEach(function (t) {
        if (__list[t] !== mcConst._CMD_.ClientType.COMMON &&
            __list[t] !== mcConst._CMD_.ClientType.UNKNOWN)
        {
            clientTypes.push({
                id: __list[t],
                value : t
            });
        }
    });

    clientTypes.sort(function (a, b) {
        return mcService.sortAB(a.value, b.value);
    });

    if (!web){
        var nowDate = new Date();

        $scope.statListFilter = mcService.FilterFiled({
            listName     : "statList" + $scope.Name,
            searchText   : mcLang(54) + "...", // "54" : "Поиск",
            filterParams : ["value"]
        });

        web = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type : "header", template : mcService.Lang(1134) },// "1134":"Просмотр протоколов",

                    { view: "toolbar", width: 200, cols: [
                        { view: "toggle", onLabel: mcService.Lang(970), offLabel: mcService.Lang(964), click: function(){ // "970":"Показать настройки", "964":"Скрыть настройки",
                            if (this.getValue()){
                                $$("logsViewConfigurator").show();
                            } else {
                                $$("logsViewConfigurator").hide();
                            }

                            $scope.logsContainer.getNode().focus();
                        }}
                    ]},

                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},
                { type : 'layout', padding : 5, cols : [
                    { id: "logsViewConfigurator", width: 310, padding: 5, rows: [
                        { view: "richselect", id: "changeLogsType", label: mcService.Lang(1146), labelPosition: 'top', value: "log_system", options: logsType, // "1146":"Тип протоколов:",
                            on: { onChange: $scope.changeLogsType }
                        },

                        { height: 5 },

                        { id: "old_view" + $scope.Name, hidden: true, rows: [
                            { view : "template", type : "header", template : mcService.Lang(1152) },// "1152":"Период",
                            { height: 10 },

                            { view: "datepicker", id: "htrDateFrom", value: nowDate, format:"%d.%m.%Y", label: mcService.Lang(1135), css:"cPointer", // "1135":"От даты:",
                                // maxDate: nowDate,
                                // minDate: !$scope.isFree ? moment().subtract(30, 'days').format('DD.MM.YYYY') : "",
                                suggest:{
                                    type:"calendar",
                                    body:{
                                        maxDate: nowDate,
                                        minDate: $scope.isFree ? moment().subtract(30, 'days').format('DD.MM.YYYY') : "01.01.1900",
                                    }
                                },
                                on: { onChange: function(date){
                                    $$("htrDateTo").getPopup().getBody().define("minDate", date);
                                }}
                            },
                            { view: "datepicker", id: "htrDateTo", value: nowDate, format:"%d.%m.%Y", label: mcService.Lang(1136), css:"cPointer", // "1136":"До даты:",
                                suggest:{
                                    type:"calendar",
                                    body:{
                                        maxDate: nowDate,
                                        minDate: mcService.formatDate(nowDate, 'dd.mm.yyyy'),
                                    }
                                },
                                // minDate: mcService.formatDate(nowDate, 'dd.mm.yyyy'),
                                on:{ onChange: function(date){
                                    $$("htrDateFrom").getPopup().getBody().define("maxDate", date);
                                }}
                            },

                            { cols: [
                                { cols: [
                                    { view: "button", value: mcService.Lang(1137), click: function(){ // "1137":"Сегодня",
                                        var today = new Date();

                                        $scope.DateFrom.setValue(today);
                                        $scope.DateTo.setValue(today);
                                    }},
                                    { view: "button", value: mcService.Lang(1210), click: function(){ // "1210":"Неделя",
                                        $scope.DateFrom.setValue(new Date(nowDate.getTime() - mcConst.oneDay * 7));
                                        $scope.DateTo.setValue(new Date());
                                    }},
                                    { view: "button", value: mcService.Lang(1211), click: function(){ // "1211":"Месяц",
                                        $scope.DateFrom.setValue(new Date(nowDate.getTime() - mcConst.oneDay * 30));
                                        $scope.DateTo.setValue(new Date());
                                    }}
                                ]},
                                { view: "text", id: "sendBufferSize" + $scope.Name, label: mcService.Lang(1212), value: 65535, height: 22, hidden: true, labelWidth: 180}, // "1212":"Размер буфера",
                                { view: "toggle", type: "icon", offIcon:"sliders", onIcon:"check", width: 30, click: function(){
                                    var item = this.getParentView().getChildViews();

                                    if (this.getValue()){
                                        item[1].hide();
                                        item[0].show();
                                    } else {
                                        item[0].hide();
                                        item[1].show();
                                    }
                                }}
                            ]},

                            { id: "selectUser" + $scope.Name, hidden: true, rows: [
                                { height: 10 },
                                { view: "combo", id: "htrUser1", label: mcService.Lang(1139) + ":", options: getOptions(), // "1139":"Кто",
                                    on: { onChange: $scope.selectPairUser}
                                },
                                { view: "combo", id: "htrUser2", label: mcService.Lang(1140) + ":", options: getOptions()}  // "1140":"С кем",
                            ]},

                            { view: "combo", id: "selectChannel" + $scope.Name, options: $scope.channelList, hidden: true, keyPressTimeout: 100} // "1033":"Конференция",
                        ]},

                        { id: "new_view" + $scope.Name, rows: [
                            { id: "selectPeriod" + $scope.Name, view: "richselect", value: '1', options: timePeriods,
                                on: { onChange: $scope.changeTimePeriod }
                            },

                            { height: 5 },
                            
                            { id: "custom_period", hidden: true, rows: [
                                { cols: [
                                    { view: "datepicker", id: "htrDateFrom_new", value: nowDate, format:"%d.%m.%Y",
                                        // maxDate: nowDate,
                                        // minDate: !$scope.isFree ? moment().subtract(30, 'days').format('DD.MM.YYYY') : "",
                                        suggest:{
                                            type:"calendar",
                                            body:{
                                                maxDate: nowDate,
                                                minDate: $scope.isFree ? moment().subtract(30, 'days').format('DD.MM.YYYY') : "01.01.1900",
                                            }
                                        },
                                        label: mcService.Lang(1926), css:"cPointer", width: 160, labelWidth: 45,// "1926":"От:",
                                        on: { onChange: function(date){
                                            $scope.htrDateTo_new.getPopup().getBody().define("minDate", date);
                                        }}
                                    },
                                    { id: "fromHours",   view: "richselect", value: "00", options: mcService.numberList(24, true)},
                                    { view: "label", label: " : ", width: 8},
                                    { id: "fromMinutes", view: "richselect", value: "00", options: mcService.numberList(60, true)}
                                ]},

                                { cols: [
                                    { view: "datepicker", id: "htrDateTo_new", value: nowDate, format:"%d.%m.%Y",
                                        suggest:{
                                            type:"calendar",
                                            body:{
                                                minDate: mcService.formatDate(nowDate, 'dd.mm.yyyy'),
                                                maxDate: nowDate,
                                            }
                                        },
                                        // minDate: mcService.formatDate(nowDate, 'dd.mm.yyyy'),
                                        // maxDate: nowDate,
                                        label: mcService.Lang(1927), css:"cPointer",  width: 160, labelWidth: 45, // "1927":"До:",
                                        on:{ onChange: function(date){
                                            $scope.htrDateFrom_new.getPopup().getBody().define("maxDate", date);
                                        }}
                                    },
                                    { id: "toHours",   view: "richselect", value: "00", options: mcService.numberList(24, true)},
                                    { view: "label", label: " : ", width: 8},
                                    { id: "toMinutes", view: "richselect", value: "00", options: mcService.numberList(60, true)}
                                ]},

                                { height: 5 }
                            ]},

                            { cols: [
                                { width: 130, rows: [
                                    { view: "label", label: mcLang(1928)}, // "1928":"Тип",
                                    { view: "label", label: mcLang(1572)}, // "1572":"Тип приложения",
                                    { view: "label", label: mcLang(1935)}, // "1935":"CID",
                                    { view: "label", label: mcLang(135)},  // "135": "UIN",
                                    { view: "label", label: mcLang(141)},  // "141":"IP адрес",
                                    { view: "label", label: mcLang(142)},  // "142":"MAC адрес",
                                    { view: "label", label: mcLang(1916)}  // "1916":"HardwareID",
                                ]},
                                { rows: [
                                    { view: "richselect", options: types, value: '1', on: {onChange: function(newV){
                                        $scope.filterFields.Preset = newV;
                                    }}},
                                    { view: "richselect", options: clientTypes, value: mcConst._CMD_.ClientType.ALL, on: {onChange: function(newV){
                                        $scope.filterFields.ClientType = newV;
                                    }}},
                                    { id: "filterCID" + $scope.Name, view: "text",
                                        on: {
                                            onChange  : function(newV) { $scope.filterFields.CID = newV; },
                                            onKeyPress: function (code){ onEnter.apply(this, [code, "CID"])}
                                        }
                                    },
                                    { id: "filterUIN" + $scope.Name, view: "combo", value: '-1', options:{ fitMaster: false, width: 400 },
                                        on: {
                                            onChange  : function(newV) { $scope.filterFields.UIN = newV; },
                                            onKeyPress: function (code){ onEnter.apply(this, [code, "UIN"]); }
                                        }
                                    },
                                    { id: "filterIP" + $scope.Name, view: "text",
                                        on: {
                                            onChange  : function(newV) { $scope.filterFields.IP = newV; },
                                            onKeyPress: function (code){ onEnter.apply(this, [code, "IP"]); }
                                        }
                                    },
                                    { id: "filterMAC" + $scope.Name, view: "text",
                                        on: {
                                            onChange  : function(newV) { $scope.filterFields.MAC = newV; },
                                            onKeyPress: function (code){ onEnter.apply(this, [code, "MAC"]); }
                                        }
                                    },
                                    { id: "filterHWID" + $scope.Name, view: "text",
                                        on: {
                                            onChange  : function(newV) { $scope.filterFields.HWID = newV; },
                                            onKeyPress: function (code){ onEnter.apply(this, [code, "HWID"]); }
                                        }
                                    }
                                ]}
                            ]},

                            { id: "groupByCID" + $scope.Name, view: "checkbox", labelWidth: 0, labelRight: mcService.Lang(1930), css: "finger"}// "1930":"Группировать по CID-ам",
                        ]},

                        { height: 10 },

                        { id: "btnGenerateLogs", cols:[
                            { view: "button", value: mcService.Lang(1145), css: "applyButton", click: function(){ // "1145":"Сгенерировать протоколы",
                                $scope.getLogs();
                            }},

                            { id: "clearBtn" + $scope.Name, view: "button", value: mcService.Lang(619), hidden: true, type: "danger", //"619": "Очистить",
                                click: $scope.clearBtnClick
                            }
                        ]},

                        { id: "infoGenerateLogsContainer", hidden: true, cols: [
                            { template: mcService.insertIco('fa-spinner fa-spin'), borderless: true, width: 30},
                            { id: "infoGenerateLogs", template: " ", borderless: true },
                            { view: "button", id: "btnStopGenerateLogs", type: "icon", icon: "times", width: 30, click: $scope.spotLoadLogs}
                        ]},
                        
                        { id: "stat" + $scope.Name, hidden: true, rows:[
                            { id: "statCount" + $scope.Name, view: "label", label: ""},

                            { id: "statTabbar" + $scope.Name, view: "tabbar", multiview: true, height: 25, animate: false, value: "IP", tabMinWidth: 50,
                                options    : [
                                    { value: "IP",   id: 'IP'},
                                    { value: "MAC",  id: 'MAC'},
                                    { value: "HWID", id: 'HWID'},
                                    { value: "UIN",  id: 'UIN'}
                                ],
                                on: {
                                    onChange: function (id) {
                                        $scope.changeStatList(id);
                                    }
                                }
                            },

                            { height: 4},

                            $scope.statListFilter,

                            { id: "statList" + $scope.Name, view: "list", select: true, on: {
                                onItemClick: $scope.addItemToFiler,
                                onItemDblClick: function (item) {
                                    $scope.addItemToFiler(item);
                                    $scope.getLogs();
                                }
                            }}
                        ]},

                        { gravity: 0}
                    ]},
                    { rows: [
                        { id: "logsContainer", view: "scrollview", scroll: 'xy', body: {}, css: "selectableEx noMarginEx" }
                    ]}
                ]}
            ]
        });

        $scope.selectUser       = $$("selectUser" + $scope.Name);
        $scope.selectChannel    = $$("selectChannel" + $scope.Name);
        $scope.DateFrom         = $$("htrDateFrom");
        $scope.DateTo           = $$("htrDateTo");
        $scope.htrUser1         = $$("htrUser1");
        $scope.htrUser2         = $$("htrUser2");
        $scope.logsContainer    = $$("logsContainer");
        $scope.infoGenerateLogs = $$("infoGenerateLogs");
        $scope.clearBtn         = $$("clearBtn" + $scope.Name);

        $scope.new_view         = $$("new_view" + $scope.Name);
        $scope.old_view         = $$("old_view" + $scope.Name);
        $scope.custom_period    = $$("custom_period");
        $scope.groupByCID       = $$("groupByCID" + $scope.Name);
        $scope.htrDateFrom_new  = $$("htrDateFrom_new");
        $scope.htrDateTo_new    = $$("htrDateTo_new");
        $scope.fromHours        = $$("fromHours");
        $scope.fromMinutes      = $$("fromMinutes");
        $scope.toHours          = $$("toHours");
        $scope.toMinutes        = $$("toMinutes");
        $scope.selectPeriod     = $$("selectPeriod" + $scope.Name);

        $scope.stat             = $$("stat" + $scope.Name);
        $scope.statCount        = $$("statCount" + $scope.Name);
        $scope.statList         = $$("statList" + $scope.Name);
        $scope.statTabbar       = $$("statTabbar" + $scope.Name);

        $scope.filterUIN        = $$("filterUIN" + $scope.Name);
        $scope.filterMAC        = $$("filterMAC" + $scope.Name);
        $scope.filterIP         = $$("filterIP" + $scope.Name);
        $scope.filterHWID       = $$("filterHWID" + $scope.Name);
        $scope.filterCID        = $$("filterCID" + $scope.Name);

        $$("htrDateTo").getPopup().getBody().define("minDate", nowDate);
        $$("htrDateFrom").getPopup().getBody().define("maxDate", nowDate);

        $scope.logsContainer.getNode().setAttribute("tabindex", "-1");

        mcService.disableContextMenu($$("logsViewConfigurator"));
    } else {

    }

    return web;
}
function historyController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.History;

    $scope.userList              = [];
    $scope.channelList           = [];
    $scope.userListData          = [];
    $scope.selectUser            = null;
    $scope.logsType              = "los_system";
    $scope.currentScrollPosition = 0;
    $scope.loadingLogsInProgress = false;

    var historyChunk   = 50;
    var angElement     = document.getElementById($scope.Name);
    var privateCodes   = ["0001","0002","0003","0004","0005","0006","0007","0008","0009","000B","000C","0011","0012"];
    var channelCodes   = ["000D","000E","000F"];
    var findUsers      = {};
    var userPairs      = {};
    var userDictionary = {};
    var loadingImgList = {};
    var pairsDt        = {};
    var currentColor   = -1;
    var uniqueList     = {
        IP   : [],
        MAC  : [],
        HWID : [],
        UIN  : []
    };
    var prevMsgDate    = false;

    $scope.filterFields = {
        ClientType: "any",
        Preset    : "1",
        CID       : "-1",
        UIN       : "-1",
        IP        : "",
        MAC       : "",
        HWID      : ""
    };
    $scope.logTypes     = {
        system   : "system",
        ftp      : "ftp",
        nodejs   : "nodejs",
        audit    : "audit",
        private  : "private",
        channels : "channels",
        script   : "script"
    };
    
    $scope._today    = mcService.formatDate(new Date(), "dd MMM yyyy");
    $scope._tomorrow = mcService.formatDate(new Date(new Date().getTime() - mcConst.oneDay), "dd MMM yyyy");

    $rootScope.thumbsSize = mcConst.imageSize.big;

    window._historyAction = {};

    window._historyAction.deleteMessage = function(){
        var idx = this.getAttribute('Idx');
        var uid = $scope.selectChannel.getValue();
        var elm = "", param = "";

        if ($scope.logsType === "log_channels" && uid){
            elm   = this.parentElement.getElementsByClassName("messageText")[0];
            param = mcService.copy(elm.innerText, 0, 20) + (elm.innerText.length > 20 ? "..." : "");

            if (!param){
                param = "<div style='margin-left: 20px'>" + elm.innerHTML + "</div>";
            }

            $rootScope.$broadcast('addShowedWindow', [mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcLang(1885, param), // "1885":"Удалить сообщение?",
                ok    : mcService.Lang(581), // "581": "Удалить",
                cancel: mcService.Lang(103), // "103": "Отмена",

                callback:function(yes){
                    if (yes){
                        $rootScope.SendCMDToServer([
                            mcConst._CMD_.cs_adm_delete_conf_message,
                            mcConst.SessionID,

                            uid,
                            idx,

                            function () {
                                var elm = document.getElementById("hsMsg-" + idx);

                                if (elm){
                                    elm.innerHTML = "";
                                }
                            }
                        ]);
                    }
                }
            })]);
        } else
        if ($scope.logsType === "log_private") {
            elm   = this.parentElement.getElementsByClassName("messageText")[0];
            param = mcService.copy(elm.innerText, 0, 20) + (elm.innerText.length > 20 ? "..." : "");

            if (!param){
                param = "<div style='margin-left: 20px'>" + elm.innerHTML + "</div>";
            }

            $rootScope.$broadcast('addShowedWindow', [mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcLang(1885, param), // "1885":"Удалить сообщение?",
                ok    : mcService.Lang(581), // "581": "Удалить",
                cancel: mcService.Lang(103), // "103": "Отмена",

                callback:function(yes){
                    if (yes){
                        $rootScope.SendCMDToServer([
                            mcConst._CMD_.cs_adm_delete_private_message,
                            mcConst.SessionID,

                            $scope.htrUser1.getValue(),
                            $scope.htrUser2.getValue(),
                            idx,

                            function () {
                                var elm = document.getElementById("hsMsg-" + idx);

                                if (elm){
                                    elm.innerHTML = "";
                                }
                            }
                        ]);
                    }
                }
            })]);
        }
    };
    window._historyAction.seeRawData    = function rawData(data) {
        webix.alert({
            width : "500px",
            text  : "<span class='messageBreakAll selectable mc-left rawData'><span>" + data + "</span></span>"
        });
    };

    var deferredLoadImages = new function () {
        var items = {};

        this.addImage = function (idx, hash, src, href) {
            if (!items.hasOwnProperty(idx)) {
                items[idx] = [hash, src, href];
            }
        };

        this.load = function (cb) {
            var count      = Object.keys(items).length;
            var currentIdx = 0;

            Object.keys(items).forEach(function (idx) {
                var hash    = items[idx][0];
                var imgSrc  = items[idx][1];
                var lnkHref = items[idx][2];

                var _link   = document.getElementById('link_' + hash + idx);
                var _img    = document.getElementById('img_' + hash + idx);

                if (_img && _img.src && _link && _link.href){
                    _img.src   = imgSrc;
                    _link.href = lnkHref;

                    _img.onload = function () {
                        currentIdx ++;
                        delete items[idx];

                        if (currentIdx === count && cb){
                            cb();
                        }
                    };

                    _img.onerror = function () {
                        _img.src   = mcConst.imagesPath.loadImage;

                        currentIdx ++;
                        delete items[idx];

                        if (currentIdx === count && cb){
                            cb();
                        }
                    }
                }
            });
        };
    };

    function loadThumbs(info, isConf) {
        $rootScope.SendCMDToServer([
            mcConst._CMD_.cs_get_image_thumbs,
            mcConst.SessionID,

            info[0] , //.Hash     , // SHA1 хэш файла
            $rootScope.thumbsSize.x     , // произвольная ширина уменьшеной копии изображения
            $rootScope.thumbsSize.y     , // произвольная высота уменьшенной копии изображения
            info[1] , // FileName , // локальное название файла
            isConf ? mcConst.whereFiles.conf : mcConst.whereFiles.private,

            function (data) {
                var idx = "";

                if (loadingImgList.hasOwnProperty(data.Hash) && loadingImgList[data.Hash].length) {
                    idx = loadingImgList[data.Hash].shift();

                    var _link   = document.getElementById('link_' + data.Hash + idx);
                    var _img    = document.getElementById('img_' + data.Hash + idx);
                    var fileName= mcService.extractFileName(data.FileName);

                    var imgSrc  = mcService.getLocalHostPath($rootScope.isWebClient) + "/" + mcConst.pathAliases.AliasFiles + "/" + data.Hash + '-' + $rootScope.thumbsSize.xy + '.jpg';
                    var lnkHref = mcService.getLocalHostPath($rootScope.isWebClient) + "/" + mcConst.pathAliases.AliasFiles + "/" + data.Hash + "/" + encodeURI(fileName);

                    if (_img && _img.src && _link && _link.href){
                        _img.src   = imgSrc;
                        _link.href = lnkHref;

                        _img.onload = function () {
                            // scrollDown();
                        };

                        _img.onerror = function () {
                            _img.src   = mcConst.imagesPath.noImage;
                        }

                    } else {
                        deferredLoadImages.addImage(idx, data.Hash, imgSrc, lnkHref);
                    }
                } else {
                    console.error('Can\'t find image with hash: ' + data.Hash);
                }
            }
        ]);
    }

    function parseChunk (chunk){
        var res = chunk.split('\r');
        var cur = res[0].split('|');
        var usersPrivate = null;

        if (cur[0] && mcService.inArrayNoStrict(cur[1], privateCodes) !== -1){
            usersPrivate = {};

            usersPrivate[$$("htrUser1").getValue()] = $$("htrUser1").getText();
            usersPrivate[$$("htrUser2").getValue()] = $$("htrUser2").getText();
        }

        for (var i = 0; i < res.length; i ++){
            res[i] = res[i].replace(/L\$/, "").replace(/L\$/g, "<br>");

            cur = res[i].split('|');

            if (cur[0]) {
                if ( usersPrivate ){ // $scope.userList
                    cur[2] = $scope.userList[mcService.findItemInArrayOfObj($scope.userList, cur[2], 'id')].value; //usersPrivate[cur[2]];
                    cur[3] = $scope.userList[mcService.findItemInArrayOfObj($scope.userList, cur[3], 'id')].value; //usersPrivate[cur[3]];
                } else
                if (mcService.inArrayNoStrict(cur[1], channelCodes) !== -1 && $rootScope.mcStorage.UserManager){
                    if (!findUsers[cur[2]]){
                        var _users = $rootScope.mcStorage.UserManager.Users;
                        var _idx = mcService.findItemInArrayOfObj(_users, cur[2], 'UIN');

                        findUsers[cur[2]] = (_idx === -1) ? cur[2] : _users[_idx].DisplayName;
                    }

                    cur[2] = findUsers[cur[2]];
                }

                if (cur[1] === '0031'){
                    res[i] = mcService.myReplaceFormated("#{code} [#{time}] <span style='color: red'>#{txt}</span>", {
                        code: cur[1],
                        time: cur[0],
                        txt : mcService.myReplace(mcConst.SYSLOG[cur[1]], cur[2] + ": " + mcService.myReplace(mcConst.SrvErrorText[cur[2]], mcService.copy(cur, 3)))
                    });
                } else {
                    var temp = mcService.myReplace(mcConst.SYSLOG[cur[1]] || cur[2], mcService.copy(cur, 2));
                    
                    res[i] = mcService.myReplaceFormated("#{code} [#{time}] #{txt}", {
                        code: cur[1],
                        time: cur[0],
                        txt : temp ? temp.replace(/</g, "&lt;") : cur
                    });
                }
            }
        }

        return res.replace(/\</g, "&lt;").join('<br>');
    }

    function setList (source){
        var user1       = $scope.htrUser1.getList();
        
        userPairs       = {};
        userDictionary  = source.Users;
        $scope.userList = [];
        
        Object.keys(source.Users).forEach(function (uin) {
            var dt = mcService.utcTime(source.Users[uin]);
            var date = mcService.formatDate(dt, "dd MMM yyyy");

            $scope.userList.push({
                id   : uin.toString(),
                value: source.Users[uin].DisplayName,
                dt   : mcService.sortableDate(dt, true),
                date : $scope._today === date ? mcLang(1137) : ($scope._tomorrow === date ? mcLang(1890) : date) // "1137":"Сегодня", "1890":"Вчера",
            });
        });

        if (mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewLogsSelfPrivates) && !mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewLogsAllPrivates)){
            var dt   = mcService.utcTime(source.Users[mcConst.UserInfo.UIN]);
            var date = mcService.formatDate(dt, "dd MMM yyyy");

            user1.clearAll();
            user1.add({
                id   : mcConst.UserInfo.UIN.toString(),
                value: source.Users[mcConst.UserInfo.UIN].DisplayName,
                dt   : dt,
                date : $scope._today === date ? mcLang(1137) : ($scope._tomorrow === date ? mcLang(1890) : date) // "1137":"Сегодня", "1890":"Вчера",
            });
        } else
        if (mcService.checkRights(mcConst._CMD_.RS.QWEBAllowViewLogsAllPrivates)) {
            user1.parse($scope.userList);
            user1.sort(function (a, b) {
                return mcService.sortAB(b.dt, a.dt);
            });
        }

        $scope.htrUser1.refresh();

        userPairs = source.Pairs;
        pairsDt   = source.PairsDT;
    }

    function getPrivateChunk(uin1, uin2, id1, id2) {
        var interval = (this && this.hasOwnProperty("go") && mcService.isBoolean(this.go)) ? this : {
            from: -1,
            to: -1,
            go: false
        };

        interval.go = id2 - id1 >= historyChunk;

        if (interval.go){
            interval.from = id2 - historyChunk;
            interval.to   = id2;
        } else {
            interval.from = id1;
            interval.to   = id2;
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_history_private,
            mcConst.SessionID,

            interval.from,
            interval.to,
            uin1,
            uin2,

            function (info) {
                addMSG(uin1, info);

                if (interval.go){
                    return getPrivateChunk.apply(interval, [uin1, uin2, id1, interval.from]);
                }
            }
        ]);
    }

    function getConfChunk(uid, id1, id2) {
        var interval = (this && this.hasOwnProperty("go") && mcService.isBoolean(this.go)) ? this : {
            from: -1,
            to: -1,
            go: false
        };

        interval.go = id2 - id1 >= historyChunk;

        if (interval.go){
            interval.from = id2 - historyChunk;
            interval.to   = id2;
        } else {
            interval.from = id1;
            interval.to   = id2;
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_history_conf,
            mcConst.SessionID,

            interval.from,
            interval.to,
            uid,

            function (info) {
                userDictionary = info.Users;

                addMSG(0, info);

                if (interval.go){
                    return getConfChunk.apply(interval, [uid, id1, interval.from]);
                }
            }
        ]);
    }

    function parseLink(source) {
        return source ? mcService.ReplaceURLs(source, { callback: function(text, link){
                var res = "";

                if (/png|jpg|jpeg$/.test(link)){
                    res = '<br/><img class="thumbImage" src="' + link + '">';
                }

                return link ? '<a href="' + link + '" title="' + link + '" target="_blank">' + (res || text) + '</a>' : text;
            }}) : ""
    }

    function addMSG (fromUin, messages){
        var target = $scope.logsContainer.getNode();
        var res    = [];
        var isConf = !!messages.UID;
        var changeSt = 0;

        messages.Data.forEach(function (msg) {
            var div      = "";
            var text     = !msg.MsgType ? msg.Msg.split('L$') : msg.Msg.split(mcConst.CRLF); //msg.Msg.split(mcConst.CRLF);
            var info     = msg.Msg.split(mcConst.CRLF);
            var uin      = msg.UINFrom;
            var nick     = userDictionary[uin].DisplayName;
            var time     = mcService.utcTime(msg).split('.');
            var date     = "";
            var hash     = info[0];
            var userName = "";
            var prevItem = res[res.length - 1] || null; // msg.History ? target.firstChild : target.lastChild;
            var same     = prevItem ? prevItem.uin === uin : false;

            function __text() {
                if (!msg.MsgType) {
                    text.shift();
                }

                for (var i = 0; i < text.length; i++){
                    text[i] = text[i].replace(/</ig, "&lt;");

                    if (!msg.MsgType) {
                        text[i] = text[i].replace(/\u000b/ig, "");
                    }
                }

                text = mcService.replaceMcComponents(text.join('<br/>'), true, null, nick);

                text = mcService.ReplaceURLs(text, { callback: function(text, link){
                    var res = "";

                    if (/png|jpg|jpeg$/.test(link)){
                        res = '<br/><img class="thumbImage" src="' + link + '">';
                    }

                    return link ? '<a href="' + link + '" title="' + link + '" target="_blank">' + (res || text) + '</a>' : text;
                }});
            }

            function __links() {
                var link  = mcService.StringToObj(msg.Msg);
                var local = "";

                if (msg.MsgType === mcConst._CMD_.msgType.LAN_LINK && link.Link /*&& link.Link.indexOf('\\\\') === 0*/) {
                    if (msg.MsgType === mcConst._CMD_.msgType.LAN_LINK && link.Link.indexOf(link.Desc) !== -1){
                        link.Desc = "Local lan link: " + link.Link;
                    } else {
                        local = ": " + link.Link;
                    }

                    link.Link = link.Link.indexOf('\\\\\\\\') === 0 ? "local:" + link.Link.replace(/\\/g, "/") : "folder:" + link.Link;
                } else {
                    link.Link = link.Link ? (link.Link.toLocaleLowerCase().indexOf("http") === -1 ? "http://" + link.Link : link.Link) : link;
                }

                text = mcService.myReplaceFormated(
                    "<a href='#{link}' title='#{title}#{local}' target='_blank'>#{title}</a>",
                    {
                        link : link.Link,
                        title: link.Desc,
                        local: local
                    }
                );
            }

            function __images_old() {
                text = mcService.myReplaceFormated(
                    '<a id="link_#{idx}" href="" target="_blank"><img id="img_#{idx}" class="messageImg" src="#{loadImage}" dt="#{dt}" alt=""></a>',
                    {
                        idx      : info[0] + msg.Idx,
                        loadImage: mcConst.imagesPath.loadImage,
                        dt       : info[2]
                    }
                );

                if (!loadingImgList.hasOwnProperty(hash)) {
                    loadingImgList[hash] = [msg.Idx];
                } else {
                    loadingImgList[hash].push(msg.Idx);
                }

                setTimeout(function () {
                    loadThumbs(info, isConf);
                }, 1);
            }

            function __images_new() {
                info = mcService.StringToObj(info[0]);
                hash = info.Hash;

                text = mcService.myReplaceFormated(
                    '<a id="link_#{idx}" href="" target="_blank"><img id="img_#{idx}" class="messageImg" src="#{loadImage}" dt="#{dt}" alt=""></a>',
                    {
                        idx      : info.Hash + msg.Idx,
                        loadImage: mcConst.imagesPath.loadImage,
                        dt       : info.UTCWriteTime
                    }
                );

                if (!loadingImgList.hasOwnProperty(hash)) {
                    loadingImgList[hash] = [msg.Idx];
                } else {
                    loadingImgList[hash].push(msg.Idx);
                }

                setTimeout(function () {
                    loadThumbs([info.Hash, info.FileName], isConf);
                }, 1);
            }

            function __files_new(){
                info = mcService.StringToObj(info[0]);
                hash = info.Hash;

                var filePath = info.FileName;
                var fileDT   = info.UTCWriteTime;
                var fileSize = info.Size;
                var fileName = mcService.extractFileName(filePath);

                text =  mcService.myReplaceFormated(
                    // file name
                    '<a id="link_#{hash}#{id}" ' +
                    'hash="#{hash}" ' +
                    'filepath="#{filepath}" ' +
                    'filedt="#{filedt}" ' +
                    'filesize="#{filesize}" ' +
                    'href="#{href}" ' +
                    'nick="#{nick}" ' +
                    'uin="#{uin}" ' +
                    'target="_blank" ' +
                    'class="fileLink"' +
                    '>#{file}</a>&nbsp;&nbsp;' +

                    // file size
                    '(#{formatedSize})</span>',
                    {
                        id      : msg.Idx,
                        nick    : nick,
                        uin     : uin,
                        hash    : hash,
                        href    : mcService.getLocalHostPath($rootScope.isWebClient) + "/" + mcConst.pathAliases.AliasFiles + "/" + hash + "/" + encodeURI(fileName),
                        file    : fileName,
                        time    : time,
                        filepath: filePath,
                        filedt  : fileDT,
                        filesize: fileSize,
                        formatedSize: mcService.formatFileSize(fileSize)
                    }
                );
            }

            function __files_old() {
                var filePath = info[1];
                var fileDT   = info[2];
                var fileSize = info[3];
                var fileName = mcService.extractFileName(filePath);

                text =  mcService.myReplaceFormated(
                    // file name
                    '<a id="link_#{hash}#{id}" ' +
                    'hash="#{hash}" ' +
                    'filepath="#{filepath}" ' +
                    'filedt="#{filedt}" ' +
                    'filesize="#{filesize}" ' +
                    'href="#{href}" ' +
                    'nick="#{nick}" ' +
                    'uin="#{uin}" ' +
                    'target="_blank" ' +
                    'class="fileLink"' +
                    '>#{file}</a>&nbsp;&nbsp;' +

                    // file size
                    '(#{formatedSize})</span>',
                    {
                        id      : msg.Idx,
                        nick    : nick,
                        uin     : uin,
                        hash    : hash,
                        href    : mcService.getLocalHostPath($rootScope.isWebClient) + "/" + mcConst.pathAliases.AliasFiles + "/" + hash + "/" + encodeURI(fileName),
                        file    : fileName,
                        time    : time,
                        filepath: filePath,
                        filedt  : fileDT,
                        filesize: fileSize,
                        formatedSize: mcService.formatFileSize(fileSize)
                    }
                );
            }
            
            function __forum() {
                var forumMsg = JSON.parse(text);

                // Msg: {
                //    Avatar     : 111
                //    DisplayName: "Алексей Пикуров"
                //    Path       : "s1/t8"
                //    PostID     : 53
                //    Sex        : 1
                //    Topic      : "MyChat"
                //    UIN        : 6
                //    What       : 1
                // }

                text = mcService.myReplaceFormated(
                    "<div>#{msgType}</div>" +
                    "<div>#{topic}</div>" +
                    "<a href='#{link}' target='_blank'>#{linkText}</a>",
                    {
                        msgType : forumMsg.What === mcConst.ForumNotify.POST_CREATED
                            ? mcLang(1994) + forumMsg.DisplayName  // "1994":"Форум. Новое сообщение от ",
                            : mcLang(1995) + forumMsg.DisplayName, // "1995":"Форум. Модификация сообщения ",
                        topic : mcLang(1996) + forumMsg.Topic, // "1996":"Тема: ",
                        linkText: mcLang(1997), // "1997":"Перейти на форум",
                        link : "/forum/#" + forumMsg.Path
                    }
                );
            }
            
            function __kanban(){
                var kMSG = JSON.parse(msg.Msg);

                switch (kMSG.What){
                    case mcConst.KanbanEvents.TASK_ADDED: case mcConst.KanbanEvents.TASK_PERFORMER_CHANGED:
                        text = mcLang(1988, [ // "1988":"<a href='%s' target='_blank'>Новое задание</a> от %s<br>Задание:<br>%s<br>Описание:<br>%s",
                            mcService.createKanbanLink(kMSG.ProjectID, kMSG.TaskID),
                            kMSG.DisplayName,
                            parseLink(kMSG.TaskName),
                            parseLink(kMSG.Description)
                        ]);

                        break;

                    case mcConst.KanbanEvents.COMMENT_ADDED:
                        text = mcLang(1989, [ // "1989":"<a href='%s' target='_blank'>Новый комментарий</a> от %s<br>Задание:<br>%s<br>Комментарий:<br>%s",
                            mcService.createKanbanLink(kMSG.ProjectID, kMSG.TaskID, kMSG.CommentID),
                            kMSG.DisplayName,
                            parseLink(kMSG.TaskName),
                            parseLink(kMSG.Comment)
                        ]);
                        break;

                    case mcConst.KanbanEvents.TASK_MOVED:
                        text = mcLang(1990, [ // "1990":"<a href='%s' target='_blank'>Задание перемещено</a> пользователем %s<br>Задание:<br>%s<br>Откуда и куда:<br>%s",
                            mcService.createKanbanLink(kMSG.ProjectID, kMSG.TaskID),
                            kMSG.DisplayName,
                            parseLink(kMSG.TaskName),
                            kMSG.OldStageName + " &gt; " + kMSG.StageName
                        ]);
                        break;

                    case mcConst.KanbanEvents.TASK_CHANGED:
                        text = mcLang(1991, [ // "1991":"<a href='%s' target='_blank'>Задание изменено</a> пользователем %s<br>Задание:<br>%s<br>Описание:<br>%s",
                            mcService.createKanbanLink(kMSG.ProjectID, kMSG.TaskID),
                            kMSG.DisplayName,
                            parseLink(kMSG.TaskName),
                            parseLink(kMSG.Description)
                        ]);
                        break;

                    case mcConst.KanbanEvents.TASK_DELETED:
                        text = mcLang(1992, [ // "1992":"<a href='%s' target='_blank'>Задание удалено</a> пользователем %s<br>Задание:<br>%s<br>Описание:<br>%s<br>Проект:<br>%s",
                            mcService.createKanbanLink(kMSG.ProjectID, kMSG.TaskID),
                            kMSG.DisplayName,
                            parseLink(kMSG.TaskName),
                            parseLink(kMSG.Description),
                            kMSG.ProjectName
                        ]);
                        break;

                    case mcConst.KanbanEvents.PROJECT_CLOSED:
                        text = mcLang(1993, [ // "1993":"<a href='%s' target='_blank'>Проект закрыт</a> пользователем %s<br>Проект:<br>%s",
                            mcService.createKanbanLink(kMSG.ProjectID, kMSG.TaskID),
                            kMSG.DisplayName,
                            kMSG.ProjectName
                        ]);
                        break;
                }
            }
            
            function __comment_type_21(){
                text = (msg.Text || msg.Msg).split(mcConst.CRLF);

                for (var i = 0; i < text.length; i++){
                    text[i] = text[i].replace(/</ig, "&lt;");

                    if (!msg.MsgType) {
                        text[i] = text[i].replace(/\u000b/ig, "");
                    }
                }

                text = mcService.ReplaceURLs(text.join('<br/>'), { callback: function(text, link){
                        var res = "";

                        if (/png|jpg|jpeg$/.test(link)){
                            res = '<br/><img class="thumbImage" src="' + link + '">';
                        }

                        return link ? '<a href="' + link + '" title="' + link + '" target="_blank">' + (res || text) + '</a>' : text;
                    }});
            }
            
            function __private_redirect() {
                var rdData = mcService.StringToObj(msg.Msg);

                text = mcLang(2049, [rdData.DisplayName, rdData.DisplayNameFrom, rdData.DisplayNameTo]); // "2049":"Пользователь <span class='blue'>%s</span> перенаправлен от <span class='blue'>%s</span> к <b>--></b> <span class='blue'>%s</span>",                
            }
            
            function __barcode() {
                var barData = mcService.StringToObj(msg.Msg);
                var type    = barData.Format.replace(/[_|-]/g, "").toLowerCase();

                if (barData && barData.Data) {
                    if (type === "qrcode") {
                        text = "<span id='qrcode_id_" + msg.Idx + "'></span>";

                        setTimeout(function (){
                            new QRCode(document.getElementById("qrcode_id_" + msg.Idx), {
                                text         : barData.Data,
                                width        : 200,
                                height       : 200,
                                colorDark    : "#131313",
                                colorLight   : "#ffffff",
                                correctLevel : QRCode.CorrectLevel.H
                            });
                        }, 700);
                    } else {
                        var barcode = webix.ui({
                            view : "barcode",
                            type : type,
                            value: barData.Data
                        });
                        var barNode = barcode.getNode();

                        text = barNode.outerHTML.replace("<canvas ", "<img src=\"" + barNode.firstChild.toDataURL() + "\" ").replace("canvas>", "img>");

                        barcode.destructor();
                        barcode = null;
                    }
                } else {
                    text = "<br>---- Incorrect Barcode Data ----<br><br>";
                }
            }
            
            function __call() {
                text = "Media Call: " + msg.Msg;
            }

            function __conf_create() {
                var confInfo = mcService.StringToObj(msg.Msg);

                if (confInfo.JoinUsers) {
                    var uList = confInfo.JoinUsers.split(",");

                    // if (!mcService.isObjectEmpty(userDictionary)){
                    //     uList.forEach(function (uin, id){
                    //         uList[id] = userDictionary[uin].DisplayName;
                    //     });
                    // }

                    text = mcLang(2242, [confInfo.Name, confInfo.Topic, uList.length, confInfo.JoinUsers]); // "2242":"Конференция \"%s\" создана, тема: \"%s\". Приглашены %s %s",
                } else {
                    text = mcLang(2243, [confInfo.Name, confInfo.Topic]); // "2243":"Конференция \"%s\" создана, тема: \"%s\"",
                }
            }

            function __replay() {
                var replyMsg    = mcService.StringToObj(msg.Msg);
                var originalMsg = mcService.StringToObj(replyMsg.Original);

                if (originalMsg) {
                    originalMsg.uin = originalMsg.UIN;
                    originalMsg.time = originalMsg.dtUTC ? mcService.utcTime(originalMsg.dtUTC).split('.') : "";
                    originalMsg.msgIdx = originalMsg.Idx;


                }

            }
            
            date = time[0] + "." + time[1] + "." + time[2];
            time = time[3] + ":" + time[4] + ":" + time[5];

            if (!same || (prevItem && prevItem.postDate !== date) || mcConst._CMD_.msgType.KANBAN_NOTIFY){
                if (isConf && !same){
                    changeSt = changeSt === 1 ? 2 : 1;
                }

                userName = mcService.myReplaceFormated(
                    '<div id="__#{id}" class="grayBorderTop">' +
                        '<div class="messageUserName" uin="#{uin}">' +
                            '#{nick}<span class="gray">#{edit}</span><span class="messageTime messageTimeHistory">#{date}</span>' +
                        '</div>' +
                    '</div>',
                    {
                        uin  : uin,
                        id   : msg.Idx,
                        nick : nick,
                        edit : msg.Mod === mcConst._CMD_.msgMods.MODIFIED ? ' modified' : '',
                        date : date
                    }
                );
            }

            switch (msg.MsgType){
                case mcConst._CMD_.msgType.INTEGRATION_API:
                case mcConst._CMD_.msgType.OLD_SHIT:
                case mcConst._CMD_.msgType.TEXT:
                    __text();
                break;

                case mcConst._CMD_.msgType.LAN_LINK:
                case mcConst._CMD_.msgType.ANY_LINK:
                    __links();
                break;
                                    
                case mcConst._CMD_.msgType.IMAGE:
                case mcConst._CMD_.msgType.CLIPBOARD_EXCEL:
                    __images_old();
                break;

                case mcConst._CMD_.msgType.EXCEL_NEW:
                case mcConst._CMD_.msgType.IMAGE_NEW:
                    __images_new();
                break;

                case mcConst._CMD_.msgType.FILE_NEW:
                    __files_new();
                break;

                case mcConst._CMD_.msgType.FILE:
                    __files_old();
                break;

                case mcConst._CMD_.msgType.FORUM_NOTIFY:
                    __forum();
                break;

                case mcConst._CMD_.msgType.KANBAN_NOTIFY:
                    __kanban();
                break;

                case mcConst._CMD_.msgType.COMMENT:
                    __comment_type_21();
                break;

                case mcConst._CMD_.msgType.PRIVATE_REDIRECT:
                    __private_redirect();
                break;

                case mcConst._CMD_.msgType.BARCODE:
                    __barcode();
                break;

                case mcConst._CMD_.msgType.MEDIA_CALL:
                    __call();
                break;

                case mcConst._CMD_.msgType.CONF_JUST_CREATED:
                    __conf_create();
                break;

                case mcConst._CMD_.msgType.REPLY:
                    __replay();
                break;

                case mcConst._CMD_.msgType.TEXT_MODIFY:
                    text = null;
                break;

                default:
                    text = "Tech message: " + (msg.Msg || "");

                    // ClientType: -1
                    // Idx: 1
                    // Mod: 0
                    // Msg: "{\"UID\":3,\"ConfType\":1,\"Topic\":\"\",\"Name\":\"\\u0456\\u0432\\u0430\\u0456\\u0432\\u0430\"}"
                    // MsgType: 38
                    // Status: 3
                    // UINFrom: 0
                    // dtUTC: "27.05.2022.09.03.31"
            }

            if (text !== null){
                div = mcService.myReplaceFormated(
                    "<div id='hsMsg-#{Idx}' Idx='#{Idx}' class='#{className} showOnHover' uin='#{uin}' postDate='#{postDate}' style='#{style}'>" +
                        "<span>#{userName}</span>" +
                        ((mcService.checkRights(mcConst._CMD_.RS.QAdmAccessToRemoveConfMessages) && isConf) || (mcService.checkRights(mcConst._CMD_.RS.QAdmAccessToRemovePrivMessages) && !isConf)
                            ? "<span class='webix_icon fa-trash-o fAwesome needShow messageTrash' Idx='#{Idx}' onclick='window._historyAction.deleteMessage.apply(this)' title='#{delHint}'></span>"
                            : "") +
                        "<span class='messageText'>#{text}</span>" +
                        "<span class='messageTime'>#{time}</span>" +
                    "</div>",
                    {
                        className : (!isConf && uin == fromUin) || (isConf && changeSt === 1) ? "messageMy" : "messageUser",
                        userName  : userName,
                        uin       : uin,
                        Idx       : msg.Idx,
                        postDate  : date,
                        style     : "wordBreak: break-word",
                        text      : text,
                        time      : time,
                        delHint   : mcLang(52) // "52" : "Удалить",
                    }
                );

                res.push({
                    postDate: date,
                    uin: uin,
                    msg: div
                });
            }
        });
        
        var out = document.createElement("div");
        out.innerHTML = res.map(function (item) {
            return item.msg;
        }).join('');

        target.insertBefore(out, target.firstChild);
    }

    function parseOtherLogs(data) {
        if (data.FirstChunk && !data.LastChunk || ($$("btnGenerateLogs").isVisible() && $scope.loadingLogsInProgress)) {
            $scope.loadingLogsInProgress = true;

            $$("btnGenerateLogs").hide();
            $$("infoGenerateLogsContainer").show();
        }

        if (data.LastChunk) {
            setTimeout(function(){
                $$("infoGenerateLogsContainer").hide();
                $$("btnGenerateLogs").show();
            }, 200);

            $scope.loadingLogsInProgress = false;
        }

        setTimeout(function(){
            var state = $scope.infoGenerateLogs.getNode();
            var leftPart  = Math.round(parseInt(data.Chunk.split('/')[0]) / 1024);
            var rightPart = Math.round(parseInt(data.Chunk.split('/')[1]) / 1024);

            state.innerHTML = mcService.myReplaceFormated("<div class='logState'>#{txt} #{date}</div>", {
                txt : mcService.Lang(1209, leftPart + '/' + rightPart + "Kb"), // "1209":"Загрузка %s",;
                date: data.Date
            });
        }, 0);

        var container = $scope.logsContainer.getNode();
        var item = document.createElement('pre'); // webix.html.create('pre', {}, data.Source); //

        if (data.Type === $scope.logTypes.nodejs){
            item.innerHTML = data.Source.replace(/\</g, "&lt;").replace(/\r\r/g, "\r");
        } else {
            item.innerHTML = parseChunk(data.Source);
        }

        var prevState = container.scrollHeight;

        if (container.scrollTop !== 0 && !data.FirstChunk) {
            $scope.currentScrollPosition = container.scrollTop;
        }

        webix.html.insertBefore(item, container.firstChild, container);

        if (data.FirstChunk){
            setTimeout(function(){
                $scope.currentScrollPosition = container.scrollHeight;
                container.scrollTop = $scope.currentScrollPosition;
            }, 100);
        } else {
            $scope.currentScrollPosition += container.scrollHeight - prevState;
        }

        container.scrollTop = $scope.currentScrollPosition;
    }

    function parseSysLogs(newFrom) {
        var dtUTCFrom  = "";
        var dtUTCTo    = ""; //mcService.formatDate($scope.htrDateTo_new.getValue(), "dd.mm.yyyy") + "." + $scope.toHours.getValue() + "." + $scope.toMinutes.getValue();
        var GroupByCID = mcService.convertIntToBool($scope.groupByCID.getValue());

        var ClientType = $scope.filterFields.ClientType || "any";
        var Preset     = $scope.filterFields.Preset || "1";
        var CID        = $scope.filterFields.CID    || -1;
        var UIN        = $scope.filterFields.UIN    || -1;
        var IP         = $scope.filterFields.IP     || "";
        var MAC        = $scope.filterFields.MAC    || "";
        var HWID       = $scope.filterFields.HWID   || "";

        var selectPeriod = $scope.selectPeriod.getValue();

        if (selectPeriod === "-1"){
            dtUTCTo = newFrom || mcService.formatDate(
                mcService.utcTime($scope.htrDateTo_new.getValue().setHours($scope.toHours.getValue(), $scope.toMinutes.getValue()), true),
                "dd.mm.yyyy.hh.nn.ss"
            );

            dtUTCFrom = mcService.formatDate(
                mcService.utcTime($scope.htrDateFrom_new.getValue().setHours($scope.fromHours.getValue(), $scope.fromMinutes.getValue()), true),
                "dd.mm.yyyy.hh.nn.ss"
            );
        } else {
            dtUTCTo = newFrom || mcService.formatDate(
                mcService.utcTime(new Date((new Date()).getTime()), true),
                "dd.mm.yyyy.hh.nn.ss"
            );

            dtUTCFrom = mcService.formatDate(
                mcService.utcTime(new Date((new Date()).getTime() - mcConst.oneHour * selectPeriod), true),
                "dd.mm.yyyy.hh.nn.ss"
            );
        }

        $rootScope.$broadcast('SendCMDToServer', [].concat(newFrom ? [] : mcConst.lockInterface).concat([
            mcConst._CMD_.cs_adm_get_system_logs,
            mcConst.SessionID,

            dtUTCFrom,    // с какой даты начинать (UTC, формат dd.mm.yyyy.hh.nn.ss.zzz)
            dtUTCTo,      // до какой даты (UTC, формат dd.mm.yyyy.hh.nn.ss.zzz)
            Preset,       // типы сообщений, которые нужно увидеть, текстовая строка, числа через запятую
            CID,          // CID, если не важен, то -1
            UIN,          // UIN, если не важен, то -1
            ClientType,   // тип приложения, если не важен, то пустая строка
            IP,           // IP адрес клиента, если не важен, то пустая строка
            MAC,          // MAC адрес клиента, если не важен, то пустая строка
            HWID,         // HardwareID клиента, если не важен, то пустая строка
            GroupByCID,   // группировать записи по CID либо нет

            function (data) {
                var container = $scope.logsContainer.getNode();
                var msgs      = data.Data;
                var res       = document.createElement('div');
                var currentCID= 0;

                if (container.scrollTop !== 0) {
                    $scope.currentScrollPosition = container.scrollTop;
                }

                msgs.forEach(function (_msg) {
                    var overData       = "";
                    var currentMsgDate = mcService.formatDate(mcService.utcTime(_msg), "dd.mm.yyyy");

                    if (currentColor === 4 && currentCID !== _msg.CID) {
                        currentColor = 0;
                    }

                    if ((_msg.Error === 165 || _msg.Error === 102) && _msg.Params[1] && _msg.Params[1].length > 50) { // Ошибка #0165: ошибка парсинга
                        switch (_msg.Error) {
                            case 165:
                                overData = _msg.Params[1] + " ";

                                // _msg.Params[1] = mcService.copy(overData, 0, 30);
                                _msg.Params[1] = "RAW DATA";
                            break;

                            case 102:
                                overData = _msg.Params[0] + " ";

                                _msg.Params[0] = "RAW DATA";
                            break;
                        }

                        overData = mcService.myReplaceFormated(
                            "<span class='_infoBorder finger' onclick='#{click}'>#{title}</span>&nbsp;",
                            {
                                // title: mcLang(2095), // "2095":"Данные",
                                title: "RAW DATA",
                                click: "(window._historyAction.seeRawData).apply(null, [\"" + overData.replace(/\"/g, '\\"') + "\"])"
                            }
                        );
                    }

                    currentColor = currentCID === _msg.CID ? currentColor : ++currentColor;

                    currentCID = _msg.CID;

                    var item       = document.createElement('pre');
                    item.className = "messageBreakAll logBg" + currentColor;
                    item.innerHTML = mcService.myReplaceFormated(
                        "[#{time} #{CID}]: " +
                        overData +
                        mcLang({
                            id   : _msg.Type,
                            from : "system",
                            items: _msg.Params,
                            html : true
                        }) +

                        "#{date}",

                        mcService.Marge(mcService.Marge({}, _msg), {
                            date   : prevMsgDate && prevMsgDate !== currentMsgDate
                                        ? "<div class='lh35 bgNormal'> - " + prevMsgDate + " - </div>"
                                        : "",
                            time   : mcService.formatDate(mcService.utcTime(_msg), "hh:nn:ss:zzz"),
                            helpURL: _msg.Error ? mcService.getLocalHostPath(true) + "/serverhelp/index.html?mychatservererrors" + mcService.forvardZero(_msg.Error, 4) + ".htm" : "",
                            CID    : _msg.CID
                            // CID    : mcService.forvardZero(_msg.CID, 3, "&nbsp;")
                        })
                    );

                    prevMsgDate = currentMsgDate;

                    webix.html.insertBefore(item, res.firstChild, res);

                    if (_msg.IP && uniqueList.IP.indexOf(_msg.IP) === -1){
                        uniqueList.IP.push(_msg.IP);
                    }

                    if (_msg.MAC && uniqueList.MAC.indexOf(_msg.MAC) === -1){
                        uniqueList.MAC.push(_msg.MAC);
                    }

                    if (_msg.HWID && uniqueList.HWID.indexOf(_msg.HWID) === -1){
                        uniqueList.HWID.push(_msg.HWID);
                    }
                    
                    if (mcService.findItemInArrayOfObj(uniqueList.UIN, _msg.UIN, "id") === -1){
                        var idx = mcService.findItemInArrayOfObj($scope.userListData, _msg.UIN, "id");

                        if (idx !== -1 && _msg.UIN !== -1) {
                            uniqueList.UIN.push({
                                id   : _msg.UIN.toString(),
                                value: $scope.userListData[idx].value
                            });
                        }
                    }
                });

                $scope.currentScrollPosition = container.scrollHeight;

                webix.html.insertBefore(res, container.firstChild, container);

                container.scrollTop = container.scrollHeight - $scope.currentScrollPosition;

                $scope.statCount.config.countMsg = msgs.length + ($scope.statCount.config.countMsg || 0);

                $scope.statCount.define("label", mcLang(1936, mcService.formatNumber($scope.statCount.config.countMsg || "0"))); // "1936":"Всего записей:",
                $scope.statCount.refresh();

                $scope.changeStatList($scope.statTabbar.getValue());

                if (!newFrom){
                    $scope.currentScrollPosition = container.scrollHeight;
                    container.scrollTop = $scope.currentScrollPosition;
                }

                if (!data.NoMore){
                    var more = document.createElement('div');

                    more.innerHTML    = mcService.insertIco("fa-angle-double-up") + " Load more " + mcService.insertIco("fa-angle-double-up");
                    more.dtUTCToFrame = data.dtUTCToFrame;
                    more.className    = "finger byCenter _headerLoadMore fAwesome";

                    more.onclick = function () {
                        container.removeChild(more);
                        parseSysLogs(this.dtUTCToFrame);
                    };

                    webix.html.insertBefore(more, container.firstChild, container);

                    $scope.loadMoreHotKeys(container, more, data.dtUTCToFrame);
                }

                $scope.logsContainer.getNode().focus();
            }
        ]));
    }

    // =================================================================

    $scope.registerEditHotKeys = function () {
        $rootScope.hotKeyDispatcher.addPreset($scope.Name + "Preset", [{
            key:  mcConst.keyCodes.enter,
            ctrlKey: true,
            func: $scope.getLogs
        }, {
            key:  mcConst.keyCodes.delete,
            ctrlKey: true,
            func: $scope.clearBtnClick
        }], document);
    };

    $scope.removeHotKey = function(){
        $rootScope.hotKeyDispatcher.removePreset($scope.Name + "Preset");
    };

    $scope.loadMoreHotKeys = function (container, moreBtn, date) {
        // var container = $scope.logsContainer.getNode();

        $rootScope.hotKeyDispatcher.addPreset($scope.Name + "LoadMore", [{
            key:  mcConst.keyCodes.aup,
            func: function () {
                if (container.scrollTop === 0){
                    container.removeChild(moreBtn);
                    parseSysLogs(date);

                    $scope.removeLoadMoreHotKey();
                } else {
                    return true;
                }
            }
        }, {
            key:  mcConst.keyCodes.pageup,
            func: function () {
                if (container.scrollTop === 0){
                    container.removeChild(moreBtn);
                    parseSysLogs(date);

                    $scope.removeLoadMoreHotKey();
                } else {
                    return true;
                }
            }
        }], $scope.logsContainer.getNode());
    };

    $scope.removeLoadMoreHotKey = function(){
        $rootScope.hotKeyDispatcher.removePreset($scope.Name + "LoadMore");
    };

    $scope.changeStatList = function (id) {
        if ($scope.statListFilter.thisFilter) {
            $scope.statListFilter.thisFilter.setValue("");
        }
        $scope.statList.clearAll();
        $scope.statList.parse(uniqueList[id]);
    };

    $scope.addItemToFiler = function (item) {
        var el = $scope["filter" + $scope.statTabbar.getValue()];

        el.setValue(item.id || item);
        el.focus();
    };

    $scope.changeTimePeriod = function (nval) {
        if (nval === "-1"){
            var nowDate    = new Date();
            var nowHours   = nowDate.getHours();
            var nowMinutes = nowDate.getMinutes();

            if (nowHours < 10) {
                nowHours = "0" + nowHours;
            }

            if (nowMinutes < 10){
                nowMinutes = "0" + nowMinutes;
            }

            $scope.toHours  .setValue(nowHours);
            $scope.toMinutes.setValue(nowMinutes);
            $scope.htrDateTo_new.setValue(nowDate);

            $scope.custom_period.show();
        } else {
            $scope.custom_period.hide();
        }
    };

    $scope.statListFilter = null; 

    $scope.selectPairUser = function (uin) {
        var _list = [];
        var user2 = $scope.htrUser2.getPopup().getBody();

        user2.clearAll();

        if (userPairs.hasOwnProperty(uin)){
            userPairs[uin].forEach(function (_uin) {
                var dt = mcService.utcTime(pairsDt[mcService.LessOfTwo(_uin, uin, true)]);
                var date = mcService.formatDate(dt, "dd MMM yyyy");

                _list.push({
                    id   : _uin.toString(),
                    value: userDictionary[_uin] ? userDictionary[_uin].DisplayName : "noname (" + _uin + ")",
                    dt   : mcService.sortableDate(dt, true),
                    date : $scope._today === date ? mcLang(1137) : ($scope._tomorrow === date ? mcLang(1890) : date) // "1137":"Сегодня", "1890":"Вчера",
                });
            });

            user2.parse(_list);
            user2.sort(function (a, b) {
                return mcService.sortAB(b.dt, a.dt);
            });

            $scope.htrUser2.refresh();
        }
    };

    $scope.getChannelList = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_all_text_confs,
            mcConst.SessionID,
            function(data){
                var options   = {
                    filter:function(item, value){
                        return item.value.toString().toLowerCase().indexOf(value.toLowerCase()) !== -1;
                    },
                    width: 400,
                    fitMaster:false,
                    body:{
                        template: function (obj) {
                            return obj.dt ? mcService.myReplaceFormated(
                                "<span class='listTime'>#{date} -</span> #{name}",
                                {
                                    name: obj.value,
                                    date: obj.date
                                }
                            ) : obj.id + obj.value;
                        }
                    }
                };

                for (var i in data){
                    var dt = mcService.utcTime(data[i]);
                    var date = mcService.formatDate(dt, "dd MMM yyyy");

                    $scope.channelList.push({
                        id   : i.toString(),
                        value: data[i].Name,
                        dt   : mcService.sortableDate(dt, true),
                        date : $scope._today === date ? mcLang(1137) : ($scope._tomorrow === date ? mcLang(1890) : date) // "1137":"Сегодня", "1890":"Вчера",
                    })
                }

                options.body.data = $scope.channelList;

                $scope.selectChannel.define('options', options);
                $scope.selectChannel.getList().sort(function(a, b){
                    return mcService.sortAB(b.dt, a.dt);
                });
                $scope.selectChannel.refresh();
                $scope.selectChannel.setValue($scope.selectChannel.getPopup().getBody().getFirstId());
            }
        ]);
    };

    $scope.clearBtnClick = function () {
        $scope.filterUIN .setValue("-1");
        $scope.filterMAC .setValue("");
        $scope.filterIP  .setValue("");
        $scope.filterHWID.setValue("");
        $scope.groupByCID.setValue(false);
        $scope.filterCID .setValue("");
        $scope.clearLogs();
        $scope.htrUser1.setValue("");
        $scope.htrUser2.setValue("");

        $scope.changeTimePeriod($scope.selectPeriod.getValue());
    };

    $scope.clearLogs = function(){
        var container = $scope.logsContainer.getNode();

        container.innerHTML = "";
        $scope.currentScrollPosition = container.offsetHeight;
        container.scrollTop = $scope.currentScrollPosition;

        $scope.clearBtn.hide();

        currentColor = -1;

        $scope.statCount.config.countMsg = 0;
        $scope.statCount.define("label", " ");
        $scope.statCount.refresh();
        
        $scope.stat.hide();

        uniqueList = {
            IP   : [],
            MAC  : [],
            HWID : [],
            UIN  : []
        };

        $scope.statList.clearAll();

        if ($scope.statListFilter.thisFilter) {
            $scope.statListFilter.thisFilter.setValue("");
        }

        prevMsgDate = false;

        container.className = container.className.replace(" Courier", "");
    };

    $scope.spotLoadLogs = function(){
        if ($scope.loadingLogsInProgress) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.StopLogs,
                mcConst.SessionID
            ]);

            $$("infoGenerateLogsContainer").hide();
            $$("btnGenerateLogs").show();

            $scope.loadingLogsInProgress = false;
        }
    };

    $scope.changeLogsType = function(val){
        var date = new Date();

        $scope.clearLogs();

        $scope.htrUser1.setValue("");
        $scope.htrUser2.setValue("");

        $scope.logsType = val;// || $scope.logsType;

        if ($scope.logsType === "log_private" || $scope.logsType === "log_channels"){
            $scope.DateFrom.setValue(date);
            $scope.DateTo  .setValue(date);
            $scope.htrUser1.setValue("");
            $scope.htrUser2.setValue("");
        }

        switch ($scope.logsType){
            case "log_system":
                $scope.old_view.hide();
                $scope.new_view.show();
            break;

            case "log_private":
                $scope.new_view.hide();
                $scope.old_view.show();
                $scope.selectChannel.hide();
                $scope.selectUser.show();
                $scope.getAllUsers();
            break;

            case "log_channels":
                $scope.new_view.hide();
                $scope.old_view.show();
                $scope.selectUser.hide();
                $scope.selectChannel.show();
                $scope.getChannelList();
            break;

            default:
                $scope.new_view.hide();
                $scope.old_view.show();
                $scope.selectUser.hide();
                $scope.selectChannel.hide();
        }
    };

    $scope.getLogs = function(){
        $scope.clearLogs();

        loadingImgList = {};

        var _type  = mcService.copy($scope.logsType, 4);
        var dtFrom = moment($scope.DateFrom.getValue()).startOf("day").toDate().getTime();//$scope.DateFrom.getValue().getTime();
        var dtTo   = moment($scope.DateTo.getValue()).endOf("day").toDate().getTime();//$scope.DateFrom.getValue().getTime();
        var params = {
            BufferSize : $$("sendBufferSize" + $scope.Name).getValue()
        };

        switch (_type){
            case $scope.logTypes.system:
                $scope.stat.show();

                parseSysLogs();
            break;

            case $scope.logTypes.private:
                params.UIN1 = $scope.htrUser1.getValue();
                params.UIN2 = $scope.htrUser2.getValue();

                $scope.logsContainer.getNode().className += " Courier";

                if (!params.UIN1 || !params.UIN2) {
                    return false;
                }

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_history_info_private,
                    mcConst.SessionID,

                    mcService.utcTime(dtFrom, true),
                    mcService.utcTime(dtTo, true),

                    params.UIN1,
                    params.UIN2,

                    function (info) {
                        getPrivateChunk(mcService.LessOfTwo(params.UIN1, params.UIN2).min, mcService.LessOfTwo(params.UIN1, params.UIN2).more, info.StartConvID, info.EndConvID);
                    }
                ]);
            break;

            case $scope.logTypes.channels:
                params.UID = $scope.selectChannel.getValue();

                if (!params.UID){
                    return false;
                }

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_history_info_conf,
                    mcConst.SessionID,

                    mcService.utcTime(dtFrom, true),
                    mcService.utcTime(dtTo, true),
                    params.UID,

                    function (info) {
                        getConfChunk(params.UID, info.StartConvID, info.EndConvID);
                    }
                ]);
            break;

            default:
                $scope.logsContainer.getNode().className += " Courier";

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.Logs,
                    mcConst.SessionID,

                    _type,
                    dtFrom,
                    dtTo,
                    JSON.stringify(params)
                ]);
        }

        if (_type !== $scope.logTypes.system){
            $scope.stat.hide();
            $scope.statCount.config.countMsg = 0;
        }

        $scope.clearBtn.show();

        return true;
    };

    $scope.getAllUsers = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_history_private_user_pairs,
            mcConst.SessionID,

            setList
        ]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        $scope.isFree = mcConst.LicenseInfo.IsFree;

        var settings = initHistory($scope, $rootScope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('LogsChunk', function(e, args){
        parseOtherLogs.apply(null, args)
    });

    $scope.$on('hide' + $scope.Name, function(){
        $scope.spotLoadLogs();

        $scope.removeHotKey();

        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $scope.show.apply(null, args);

        mcService.getAllUserForFillList($scope.userListData, function (data){
            // $scope.regularUserList = data;
            $scope.userListData = mcService.transformDataObject(data, [['DisplayName', 'value'], ['UIN', 'id']]);

            $scope.userListData.forEach(function (t, i) {
                t.value = t.value + "<span style='float:right'>(UIN: " + data[i].UIN + ")</span>"
            });

            $scope.userListData.unshift({
                id   : '-1',
                value: "-----------"
            });

            $scope.filterUIN.getPopup().getList().parse($scope.userListData);

            $scope.registerEditHotKeys();
        }, $rootScope);
    });
}

/**
 * Created by Gifer on 30.07.2015.
 */

"use strict";

function initBBS($scope){
    var _view = $$($scope.Name);

    function listTempl(obj){
        return obj.DisplayName + "<span class='toRight'>" + mcService.sortableDate(obj.dtCreated) + "</span>";
    }

    if (!_view){
        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type: "header", template : mcService.Lang(1515) }, // "1515":"Доска объявлений",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: 'layout', cols : [
                    { view: "tabview", id: "bbsWrapper", cells: [
                        { header: mcService.Lang(1517), body: { id: "headActive", rows: [ // "1517":"Актуальные сообщения",
                            { cols: [
                                { view: "button", gravity: 1, value: mcService.Lang(1524), click: $scope.addNewBbs}, // "1524":"Добавить объявление",

                                { gravity: 2, rows: [
                                    new mcService.ListButtonSet({
                                        type   : 'text',
                                        actions: $scope.activeBbsActions,
                                        list   : "activeBbsList",
                                        visibleBtns: {
                                            add: false,
                                            del: true,
                                            cls: true
                                        },
                                        selectedItem: "DisplayName",
                                        regShowWindow: $scope.regShowWindow
                                    })
                                ]}
                            ]},
                            {
                                view    : "list",
                                id      : "activeBbsList",
                                select  : true,
                                template: listTempl,
                                on: { onItemClick: $scope.selectBBS}
                            }
                        ]}},

                        { header: mcService.Lang(1518), body: { view: "list", id: "archiveBbsList", select: true, // "1518":"Архив объявлений",
                            template: listTempl,
                            on: { onItemClick: $scope.selectBBS}
                        }}
                    ]},

                    { view : "resizer" },

                    { hidden: true, id: "selectedBbsInfo", rows: [
                        { type: "header", template: mcService.Lang(1516), borderless: true}, // "1516":"Содержимое объявления",

                        { padding: 5, rows: [
                            { id: "bbsDisplayName", template: mcService.Lang(1523), autoheight: true, borderless: true}, // "1523":"Автор",

                            { cols: [
                                { rows: [
                                    { view: "datepicker", id: "bbsdtCreated", disabled: true, timepicker: true, labelWidth: 120, width: 300, format:"%d.%m.%Y %H:%i", label: mcService.Lang(1521), css:"cPointer"}, // "1521":"Опубликовано:",

                                    { view: "datepicker", id: "bbsdtActualTo", timepicker: true, labelWidth: 120, format:"%d.%m.%Y %H:%i", label: mcService.Lang(1522), css:"cPointer", // "1522":"Актуально до:",
                                        on: { onChange: function(date){
                                            $scope.updExpire = date;

                                            $scope.changeCurrentBBS();
                                        }, onAfterRender: function(){
                                            this.getPopup().getBody().define("minDate", new Date());
                                        }}
                                    }
                                ]}, {}
                            ]},

                            { view: "checkbox", id: "bbsSticky", value: '0', labelWidth: 0, css: "finger",
                                labelRight: mcService.Lang(1519), // "1519":"\"Прилепленное\" объявление",
                                on: {
                                    onChange: function(val){
                                        $scope.updSticked = val;

                                        $scope.changeCurrentBBS();
                                    }
                                }
                            },

                            { height: 5},
                            { template: mcService.Lang(1520), borderless: true, autoheight: true}, // "1520":"Текст сообщения:",
                            { view: "textarea", id: "bbsMsg", value: '', on: {
                                onTimedKeyPress: function(){
                                    var tt = this.getValue();

                                    if ($scope.updText != tt) {
                                        $scope.updText = tt;

                                        $scope.changeCurrentBBS();
                                    }
                                }
                            }},

                            { cols: [
                                { view: "button", id: "bbsRollbackBtn", value: mcService.Lang(1614), disabled: true, width: 200, click: $scope.rollbackBBS, type: "danger"}, //  "1614":"Отмена изменений",
                                {},
                                { view: "button", id: "bbsUpdateBtn", value: mcService.Lang(1525), disabled: true, width: 200, click: $scope.updateBBS} //  "1525":"Сохранить изменения?",
                            ]}
                        ]}
                    ]}
                ]}
            ]
        });

        $scope.windowAddNewBBS = webix.ui({
            view     : "window",
            position : "center",
            modal    : true,
            width    : 400,
            head     : mcService.Lang(1524), // "1524":"Добавить объявление"
            body     : { view: "form", rules: {newBbsText: webix.rules.isNotEmpty}, elements: [
                { template: mcService.Lang(1520), borderless: true, height: 20}, //"1520":"Текст сообщения:",

                { view: "textarea", name: "newBbsText", height: 200, on: {
                    onChange: function(val){
                        $scope.newText = val;
                    }
                }},

                { view: "checkbox", value: $scope.newSticked, labelWidth: 0, css: "finger", labelRight: mcService.Lang(1519), on: { // "1519":"\"Прилепленное\" объявление",
                    onChange: function(val){
                        $scope.newSticked = val;
                    }
                }},

                { view: "datepicker", timepicker: true, value: new Date((new Date()).setHours(23,50,0)), labelWidth: 120, format:"%d.%m.%Y %H:%i", label: mcService.Lang(1522), css:"cPointer", // "1522":"Актуально до:",
                    on:{ onChange: function(date){
                        $scope.newExpire = date;
                    }, onAfterRender: function(){
                        this.getPopup().getBody().define("minDate", new Date());
                    }}
                },

                { cols: [
                    { view: "button", value: mcService.Lang(103), type: "danger", click: function(){ // "103": "Отмена",
                        this.getTopParentView().hide();
                    }},
                    { view: "button", value: mcService.Lang(104), click: function(){ // "104": "Сохранить",
                        if (this.getFormView().validate()){
                            this.getTopParentView().hide();

                            $scope.saveNewBBS();
                        }
                    }}
                ]}
            ]}, on: {
                onShow: function(){
                    var txt = this.getChildViews()[1].getChildViews()[1];

                    $scope.newExpire = new Date((new Date()).setHours(23,50,0));

                    txt.setValue('');
                    txt.focus();
                }
            }
        });

        $scope.bbsWrapper      = $$("bbsWrapper");
        $scope.activeBbsList   = $$("activeBbsList");
        $scope.archiveBbsList  = $$("archiveBbsList");
        $scope.selectedBbsInfo = $$("selectedBbsInfo");
        $scope.bbsUpdateBtn    = $$("bbsUpdateBtn");
        $scope.bbsRollbackBtn  = $$("bbsRollbackBtn");

        $scope.bbsDisplayName  = $$("bbsDisplayName");
        $scope.bbsdtCreated    = $$("bbsdtCreated");
        $scope.bbsdtActualTo   = $$("bbsdtActualTo");
        $scope.bbsSticky       = $$("bbsSticky");
        $scope.bbsMsg          = $$("bbsMsg");

        $scope.bbsWrapper.getTabbar().attachEvent('onChange', $scope.selectTab);
    } else {
        //$scope.clearInfo();

        $scope.activeBbsList.clearAll();
        $scope.archiveBbsList.clearAll();

        $scope.bbsWrapper.enable();
        $scope.bbsUpdateBtn.disable();
    }

    return _view;
}


/**
 * Created by Gifer on 30.07.2015.
 */

"use strict";

function bbsController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.BBS;
    $scope.data = null;
    $scope.canChange = true;

    $scope.bbsList        = [];
    $scope.bbsArchiveList = [];

    $scope.activeBbsActions   = {};
    $scope.arrchiveBbsActions = {};
    $scope.Text = "";

    var createOrUpdate = null;

    // mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_update_auto_conf, function(){
    //     return mcService.Lang(669); // "669": "Настройки сохранены!"
    // }, $scope.Name);

    var _view = document.getElementById($scope.Name);

    function disableBTN (){
        $scope.bbsUpdateBtn.disable();
        $scope.bbsRollbackBtn.disable();
    }

    //===================================================

    $scope.activeBbsActions.del = function(item){
        disableBTN();

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_bbs_del_messages,
            mcConst.SessionID,
            $scope.activeBbsList.getItem($scope.activeBbsList.getSelectedId()).ID,
            item.ID,
            function(){
                if (!$scope.activeBbsList.serialize().length){
                    $scope.selectedBbsInfo.hide();
                } else {
                    $scope.activeBbsList.select($scope.activeBbsList.getFirstId());
                    $scope.selectBBS.call($scope.activeBbsList, $scope.activeBbsList.getFirstId())
                }
            }
        ]);
    };

    $scope.activeBbsActions.clear = function(){
        disableBTN();

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_bbs_clear_actual,
            mcConst.SessionID,
            function (){
                $scope.activeBbsList.clearAll();
                $scope.selectedBbsInfo.hide();
            }
        ]);
    };

    //===================================================

    $scope.updateBBS = function(){
        if ($scope.selectedBBS){
            $scope.Text = $scope.updText;

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_bbs_modify_msg,
                mcConst.SessionID,
                $scope.selectedBBS,
                mcService.isString($scope.updExpire) ? $scope.updExpire : mcService.formatDate($scope.updExpire, 'dd.mm.yyyy.hh.nn.ss'),
                mcService.convertIntToBool($scope.updSticked),
                $scope.updText
            ]);

            disableBTN();
        }
    };

    $scope.changeCurrentBBS = function(){
        if ($scope.canChange){
            $scope.bbsUpdateBtn.enable();
            $scope.bbsRollbackBtn.enable();
        } else {
            //console.log('!!!');
        }
    };

    $scope.saveNewBBS = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_add_bbs_message,
            mcConst.SessionID,
            mcService.formatDate($scope.newExpire, 'dd.mm.yyyy.hh.nn.ss'),
            mcService.convertIntToBool($scope.newSticked),
            $scope.newText
        ]);

        createOrUpdate = function( data ){
            $scope.activeBbsList.add({
                ID          : data.ID,          // идентификатор объявления
                UIN         : data.UIN,         // идентификатор создателя объявления
                DisplayName : data.DisplayName, // отображаемое имя создателя объявления
                dtCreated   : data.dtCreated    // дата и время создания объявления
            });

            var lastId = $scope.activeBbsList.getLastId();

            $scope.activeBbsList.select(lastId);
            $scope.selectBBS.call($scope.activeBbsList, lastId);
            $scope.activeBbsList.sort("ID", "desc");
        };
    };

    $scope.rollbackBBS = function(){
        $scope.bbsMsg.setValue($scope.Text);
        $scope.updText = $scope.Text;

        disableBTN();
    };

    $scope.addNewBbs = function(){
        $scope.newText = '';
        $scope.newSticked = 0;
        $scope.newExpire = new Date();

        $scope.windowAddNewBBS.show();
    };

    $scope.clearInfo = function(){
        $scope.bbsDisplayName.define('template', '');
        $scope.bbsDisplayName.refresh();

        $scope.bbsdtCreated.setValue('');
        $scope.bbsdtActualTo.setValue('');
        $scope.bbsSticky.setValue('0');
        $scope.bbsMsg.setValue('');

        disableBTN();
    };

    $scope.selectBBS = function( id ){
        var elem = this.getItem(id);
        var archive = false;

        disableBTN();

        if (elem){
            archive = $scope.bbsWrapper.getValue() === 'archiveBbsList';
            $scope.canChange = false;

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_bbs_get_msg,
                mcConst.SessionID,
                elem.ID,
                function( data ){
                    $scope.data = data;

                    for (var i in $scope.data){
                        var item = $$('bbs' + i);

                        if (item)
                        if (item.setValue){
                            if (i.indexOf('dt') === 0) {
                                item.setValue(new Date(mcService.formatDate($scope.data[i], 'yyyy.mm.dd hh:nn:ss')));
                            } else {
                                item.setValue($scope.data[i]);
                            }

                            if (i == 'Msg'){
                                archive ? item.define('readonly', true) : item.define('readonly', false);
                            } else
                            if (i != 'dtCreated') archive ? item.disable() : item.enable();
                        } else {
                            item.define('template', mcService.Lang(1523) + ": " + $scope.data[i]); //"1523":"Автор",
                            item.refresh();
                        }
                    }

                    $scope.selectedBBS = elem.ID;
                    $scope.updExpire   = $scope.data.dtActualTo;
                    $scope.updSticked  = $scope.data.Sticky;
                    $scope.Text        = $scope.data.Msg;
                    $scope.updText     = $scope.data.Msg;

                    $scope.selectedBbsInfo.show();

                    $scope.canChange = true;
                }
            ]);
        }
    };

    $scope.selectTab = function(val){
        var list = val != 'archiveBbsList' ? $scope.activeBbsList : $scope.archiveBbsList;

        $scope.clearInfo();

        if (list.serialize().length){
            $scope.selectedBbsInfo.show();

            list.select(list.getFirstId());
            $scope.selectBBS.call(list, list.getFirstId())
        } else {
            $scope.selectedBbsInfo.hide();
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_bbs_msg_list,
            mcConst.SessionID,
            true,
            function( data ){
                $scope.bbsList = data;

                $scope.activeBbsList.parse($scope.bbsList);
                $scope.activeBbsList.sort("#ID#", "desc");
            }
        ]);

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_bbs_msg_list,
            mcConst.SessionID,
            false,
            function( data ){
                $scope.bbsArchiveList = data;

                $scope.archiveBbsList.parse($scope.bbsArchiveList);
                $scope.archiveBbsList.sort(function(a,b){
                    return mcService.sortAB(mcService.sortableDate(a.dtCreated), mcService.sortableDate(b.dtCreated))
                });

                $scope.bbsWrapper.getTabbar().setValue('headActive');
                $scope.selectTab('headActive');
            }
        ]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, _view);

        var settings = initBBS($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    //===================================================

    $scope.$on('bbsInfoDetail', function(e, args){
        var info = args[0];

        if (createOrUpdate){
            createOrUpdate(info);
            createOrUpdate = null;
        }
    });

    $scope.$on('hide' + $scope.Name, function(){
        $scope.selectedBbsInfo.hide();

        mcService.hideView(_view);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.canChange = true;

        $scope.getData();

        $scope.show();
    });
}

/**
 * Created by Gifer on 07.10.2015.
 */

"use strict";

function initWorkTime($scope){
    var _view = $$($scope.Name);

    if (!_view){
        var reportTypes = [
            { id: '1', value: mcLang(1583)} //"1583":"Список используемых программ",
        ];

        var searchBar = mcService.FilterFiled({
            listName     : "allUsers" + $scope.Name,
            bottomSpacer : 4,
            filterParams : [
                "UIN",
                "DisplayName"
            ]
        });

        var date = new Date();

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { view: "template", type: "header", template : mcService.Lang(1582) }, // "1582":"Контроль рабочего времени",

                { type: 'layout', padding: 5, cols: [{
                    width: 300,
                    rows: [{
                        view: "richselect", options: reportTypes, value: '1'
                    },{
                        view: "datepicker", id: "rptDateFrom", value: date, maxDate: date, format:"%d.%m.%Y", label: mcService.Lang(1135), css:"cPointer", // "1135":"От даты:",
                        on: { onChange: function(date){
                            $$("rptDateTo").getPopup().getBody().define("minDate", date);
                        }}
                    },{
                        view: "datepicker", id: "rptDateTo", value: date, minDate: mcService.formatDate(date, 'dd.mm.yyyy'), format:"%d.%m.%Y", label: mcService.Lang(1136), css:"cPointer", // "1136":"До даты:",
                        on:{ onChange: function(date){
                            $$("rptDateFrom").getPopup().getBody().define("maxDate", date);
                        }}
                    }, searchBar, {
                        id: "allUsers" + $scope.Name, view: "list", data: $scope.usersList, select: true, template: "#UIN#: #DisplayName#"
                    }, {
                        view: "button", value: mcLang(1584)  //"1584":"Создать отчет",
                    }]
                },

                { view: "resizer" },

                {
                    rows: [{
                        view: "datatable",
                        id: $scope.Name + "Type1",
                        columns: [
                            {id: "AppName", header: mcLang(1585), width: 240}, // "1585":"Название программы",
                            {id: "AppPath", header: mcLang(1586), fillspace:true}  // "1586":"Путь к программе",
                        ]
                    }, {
                        view: "datatable",
                        id: $scope.Name + "Type2",
                        hidden: true,
                        columns: [
                            {id: "AppName", header: mcLang(1585), width: 240}, // "1585":"Название программы",
                            {id: "AppPath", header: mcLang(1586), fillspace:true}  // "1586":"Путь к программе",
                        ]
                    }]
                }]}
            ]
        });

        $scope.allUsers = $$("allUsers" + $scope.Name);
    } else {
    }

    return _view;
}

/**
 * Created by Gifer on 30.07.2015.
 */

"use strict";

function workTimeController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.WorkTime;
    $scope.usersList = [];

    var _view = document.getElementById($scope.Name);
    var workTime  = null;

    //===================================================

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.getData = function(){
        mcService.getAllUserForFillList($scope.usersList, function(users){
            $scope.usersList = [].concat(users);

            $scope.allUsers.clearAll();
            $scope.allUsers.parse($scope.usersList);
            $scope.allUsers.sort("UIN", "asc", "int");
        }, $rootScope);
/*
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_bbs_msg_list,
            mcConst.SessionID,
            true,
            function( data ){
                $scope.bbsList = data;

                $scope.activeBbsList.parse($scope.bbsList);
                $scope.activeBbsList.sort("#ID#", "desc");
            }
        ]);
*/
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, _view);

        workTime = initWorkTime($scope);

        mcService.initResize(workTime, $scope.Name);

        workTime.adjust();
    };

    //===================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(_view);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.getData();

        $scope.show();
    });
}

"use strict";

function initUpdates($scope){
    var view = $$($scope.Name);
    var block = 500;

    if (!view){
        webix.type(webix.ui.list, {
            name:"myUploader",
            template:function(f,type){
                var html = mcService.myReplaceFormated(
                    "<div class='uploader_overall'>" +
                        "<div class='uploader_name'>#{name}</div>" +
                        "<div class='uploader_status'>" +
                            "<div class='uploader_progress #{statusCl}' style='width:#{width}'></div>" +
                            "<div class='uploader_message #{statusCl}'>#{txt}</div>" +
                        "</div>"+
                    "</div>",
                    {
                        name    : f.name,
                        statusCl: f.status,
                        width   : f.status == 'transfer' || f.status == "server" ? f.percent + "%" : "0px",
                        txt     : type.status(f)
                    }
                );

                return html;
            },
            status:function(f){
                var messages = {
                    server: f.sizetext + " - Done!",
                    error: "Error",
                    client: "Ready",
                    transfer:  f.sizetext + " " + f.percent+"%"
                };
                return messages[f.status]

            },
            height: 35
        });

        view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(1555) }, // "1555":"Обновления",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                // === WINDOWS ===
                { type : 'layout', padding : 5, cols : [{
                    minWidth: block,
                    rows: [
                        { id: "updFileUpdExist", template: "Win32: " + mcLang(1558), borderless: true, autoheight: true}, // "1558":"Файл для обновления клиентов не загружен на сервер",
                        { id: "updFileInfo", hidden: !$scope.updateData.PacketExists_win32,  rows: [
                            { id: "updFileVersion", template: " ", autoheight: true, borderless: true},
                            { id: "updFileSize", template: " ", autoheight: true, borderless: true}
                        ]},

                        { cols: [
                            { id: "updBtnUpdater",  view: "uploader", value: mcLang(1559) + ": " + $scope.fileName,  upload: "/uploading?sid=" + mcConst.SessionID, multiple: false,  //"1559":"Загрузить файл обновлений",
                                accept: ".exe", minWidth: 400,
                                on: {
                                    onBeforeFileAdd  : function(item){
                                        var name = item.name.toLowerCase();

                                        if (mcService.extractFileExtension(name) !== "exe") {
                                            webix.alert(mcLang(2217)); //"2217":"Указан неправлиный тип файла",

                                            return false;
                                        } else
                                        if (name !== $scope.fileName){
                                            webix.alert(mcLang(1562) + " " + $scope.fileName); //"1562":"Пожалуйста, укажите путь к файлу ",

                                            return false;
                                        }

                                        $scope.uploadProgress.show();
                                    },
                                    onFileUpload     : function () {
                                        $scope.loadUpdateFile("win32", $scope.fileName);
                                    },
                                    onFileUploadError: $scope.uploadError
                                }, link: "uploadProgress"
                            },
                            {}
                        ]},

                        { id: "uploadProgress", hidden: true, view: "list", type: "myUploader", height: 35, scroll: false, borderless: true, select: false},
                    ]
                }, {}
                ]},

                // === WIN32NEXT ===
                { type : 'layout', padding : 5, cols : [{
                    minWidth: block,
                    rows: [
                        { id: "updFileUpdExistWin32next", template: "Win32 Alt: " + mcLang(1558), borderless: true, autoheight: true}, // "1558":"Файл для обновления клиентов не загружен на сервер",
                        { id: "updFileInfoWin32next", hidden: !$scope.updateData.PacketExists_win32next,  rows: [
                            { id: "updFileVersionWin32next", template: " ", autoheight: true, borderless: true},
                            { id: "updFileSizeWin32next", template: " ", autoheight: true, borderless: true}
                        ]},

                        { cols: [
                            { id: "updBtnUpdaterWin32next",  view: "uploader", value: mcLang(1559) + ": " + $scope.fileWin32next,  upload: "/uploading?sid=" + mcConst.SessionID, multiple: false, //"1559":"Загрузить файл обновлений",
                                accept:".zip", minWidth: 400,
                                on: {
                                    onBeforeFileAdd  : function(item){
                                        var name = item.name.toLowerCase();

                                        if (mcService.extractFileExtension(name) !== "zip") {
                                            webix.alert(mcLang(2217)); //"2217":"Указан неправлиный тип файла",

                                            return false;
                                        } else
                                        if (name !== $scope.fileWin32next){
                                            webix.alert(mcLang(1562) + " " + $scope.fileWin32next); //"1562":"Пожалуйста, укажите путь к файлу ",

                                            return false;
                                        }

                                        $scope.uploadProgressWin32next.show();
                                    },
                                    onFileUpload     : function () {
                                        $scope.loadUpdateFile("win32next", $scope.fileWin32next);
                                    },
                                    onFileUploadError: $scope.uploadError
                                }, link: "uploadProgressWin32next"
                            },
                            {}
                        ]},

                        { id: "uploadProgressWin32next", hidden: true, view: "list", type: "myUploader", height: 35, scroll: false, borderless: true, select: false},
                    ]}, {}
                ]},

                // === MACOS ===
                { type : 'layout', padding : 5, cols : [{
                    minWidth: block,
                    rows: [
                        { id: "updFileUpdExistMac", template: "macOS: " + mcLang(1558), borderless: true, autoheight: true}, // "1558":"Файл для обновления клиентов не загружен на сервер",
                        { id: "updFileInfoMac", hidden: !$scope.updateData.PacketExists_mac,  rows: [
                            { id: "updFileVersionMac", template: " ", autoheight: true, borderless: true},
                            { id: "updFileSizeMac", template: " ", autoheight: true, borderless: true}
                        ]},

                        { cols: [
                            { id: "updBtnUpdaterMac",  view: "uploader", value: mcLang(1559) + ": " + $scope.fileMac,  upload: "/uploading?sid=" + mcConst.SessionID, multiple: false, //"1559":"Загрузить файл обновлений",
                                accept:".zip", minWidth: 400,
                                on: {
                                    onBeforeFileAdd  : function(item){
                                        var name = item.name.toLowerCase();

                                        if (mcService.extractFileExtension(name) !== "zip") {
                                            webix.alert(mcLang(2217)); //"2217":"Указан неправлиный тип файла",

                                            return false;
                                        } else
                                        if (name !== $scope.fileMac){
                                            webix.alert(mcLang(1562) + " " + $scope.fileMac); //"1562":"Пожалуйста, укажите путь к файлу ",

                                            return false;
                                        }

                                        $scope.uploadProgressMac.show();
                                    },
                                    onFileUpload     : function () {
                                        $scope.loadUpdateFile("mac", $scope.fileMac);
                                    },
                                    onFileUploadError: $scope.uploadError
                                }, link: "uploadProgressMac"
                            },
                            {}
                        ]},

                        { id: "uploadProgressMac", hidden: true, view: "list", type: "myUploader", height: 35, scroll: false, borderless: true, select: false},
                    ]}, {}
                ]},

                // === LINUX x64 ===
                { type : 'layout', padding : 5, cols : [{
                    minWidth: block,
                    rows: [
                        { id: "updFileUpdExistLinux", template: "Linux x64: " + mcLang(1558), borderless: true, autoheight: true}, // "1558":"Файл для обновления клиентов не загружен на сервер",
                        { id: "updFileInfoLinux", hidden: !$scope.updateData.PacketExists_linux,  rows: [
                            { id: "updFileVersionLinux", template: " ", autoheight: true, borderless: true},
                            { id: "updFileSizeLinux", template: " ", autoheight: true, borderless: true}
                        ]},

                        { cols: [
                            { id: "updBtnUpdaterLinux",  view: "uploader", value: mcLang(1559) + ": " + $scope.fileLinux,  upload: "/uploading?sid=" + mcConst.SessionID, multiple: false, //"1559":"Загрузить файл обновлений",
                                accept:".zip", minWidth: 400,
                                on: {
                                    onBeforeFileAdd  : function(item){
                                        var name = item.name.toLowerCase();

                                        if (mcService.extractFileExtension(name) !== "zip") {
                                            webix.alert(mcLang(2217)); //"2217":"Указан неправлиный тип файла",

                                            return false;
                                        } else
                                        if (name !== $scope.fileLinux){
                                            webix.alert(mcLang(1562) + " " + $scope.fileLinux); //"1562":"Пожалуйста, укажите путь к файлу ",

                                            return false;
                                        }

                                        $scope.uploadProgressLinux.show();
                                    },
                                    onFileUpload     : function () {
                                        $scope.loadUpdateFile("linux", $scope.fileLinux);
                                    },
                                    onFileUploadError: $scope.uploadError
                                }, link: "uploadProgressLinux"
                            },
                            {}
                        ]},

                        { id: "uploadProgressLinux", hidden: true, view: "list", type: "myUploader", height: 35, scroll: false, borderless: true, select: false},
                    ]}, {}
                ]},

                // === LINUX x86 ===
                /*{ type : 'layout', padding : 5, cols : [{
                    minWidth: block,
                    rows: [
                        { id: "updFileUpdExistLinux32", template: "Linux x86: " + mcLang(1558), borderless: true, autoheight: true}, // "1558":"Файл для обновления клиентов не загружен на сервер",
                        { id: "updFileInfoLinux32", hidden: !$scope.updateData.PacketExists_linux32,  rows: [
                            { id: "updFileVersionLinux32", template: " ", autoheight: true, borderless: true},
                            { id: "updFileSizeLinux32", template: " ", autoheight: true, borderless: true}
                        ]},

                        { cols: [
                            { id: "updBtnUpdaterLinux32",  view: "uploader", value: mcLang(1559) + ": " + $scope.fileLinux32,  upload: "/uploading?sid=" + mcConst.SessionID, multiple: false, //"1559":"Загрузить файл обновлений",
                                accept:".zip", minWidth: 400,
                                on: {
                                    onBeforeFileAdd  : function(item){
                                        var name = item.name.toLowerCase();

                                        if (mcService.extractFileExtension(name) !== "zip") {
                                            webix.alert(mcLang(2217)); //"2217":"Указан неправлиный тип файла",

                                            return false;
                                        } else
                                        if (name !== $scope.fileLinux32){
                                            webix.alert(mcLang(1562) + " " + $scope.fileLinux32); //"1562":"Пожалуйста, укажите путь к файлу ",

                                            return false;
                                        }

                                        $scope.uploadProgressLinux32.show();
                                    },
                                    onFileUpload     : function () {
                                        $scope.loadUpdateFile("linux32", $scope.fileLinux32);
                                    },
                                    onFileUploadError: $scope.uploadError
                                }, link: "uploadProgressLinux32"
                            },
                            {}
                        ]},

                        { id: "uploadProgressLinux32", hidden: true, view: "list", type: "myUploader", height: 35, scroll: false, borderless: true, select: false},
                    ]}, {}
                ]},*/

                { type : 'layout', padding : 5, cols : [
                    { cols : [//{
                        { id: "updEnableUpdatesDownloadLimit", view: "checkbox", value: $scope.data.EnableUpdatesDownloadLimit, labelWidth: 0, width: 340, css: "finger",
                            labelRight: mcLang(1896), // "1896":"Включить лимит скачиваний обновления",
                            on: {
                                onChange: $scope.change
                            }},
                        { id: "updLimitUpdateDownloads", view: "text", value: $scope.data.LimitUpdateDownloads || "0", labelWidth: 0, width: 60, mcType: "port",  // "1896":"Лимит одновременных скачиваний файла обновления",
                            on: {
                                onTimedKeyPress: $scope.change
                            }
                        }, {}
                    ]}, {}
                ]},

                { type : 'layout', padding : 5, cols : [
                    { template: mcService.insertIco("fa-info-circle") + mcLang(2143), width: 550, autoheight: true, borderless: true, css: "_info selectable" }, // "2143":"Если у вас медленные каналы связи и при скачивании обновлений клиентские приложения \"забивают\" канал на длительное время — попробуйте установить это ограничение. По умолчанию ограничений нет (лимит = 0).",
                    {}
                ]},
            ]
        });

        // === WINDOWS ===
        $scope.updFileInfo     = $$("updFileInfo");
        $scope.updFileUpdExist = $$("updFileUpdExist");
        $scope.updFileVersion  = $$("updFileVersion");
        $scope.updFileSize     = $$("updFileSize");
        $scope.uploadProgress  = $$("uploadProgress");
        $scope.updBtnUpdater   = $$("updBtnUpdater");

        // === WIN32NEXT ===
        $scope.updFileInfoWin32next     = $$("updFileInfoWin32next");
        $scope.updFileUpdExistWin32next = $$("updFileUpdExistWin32next");
        $scope.updFileVersionWin32next  = $$("updFileVersionWin32next");
        $scope.updFileSizeWin32next     = $$("updFileSizeWin32next");
        $scope.uploadProgressWin32next  = $$("uploadProgressWin32next");
        $scope.updBtnUpdaterWin32next   = $$("updBtnUpdaterWin32next");

        // === MACOS ===
        $scope.updFileInfoMac     = $$("updFileInfoMac");
        $scope.updFileUpdExistMac = $$("updFileUpdExistMac");
        $scope.updFileVersionMac  = $$("updFileVersionMac");
        $scope.updFileSizeMac     = $$("updFileSizeMac");
        $scope.uploadProgressMac  = $$("uploadProgressMac");
        $scope.updBtnUpdaterMac   = $$("updBtnUpdaterMac");

        // === LINUX ===
        $scope.updFileInfoLinux     = $$("updFileInfoLinux");
        $scope.updFileUpdExistLinux = $$("updFileUpdExistLinux");
        $scope.updFileVersionLinux  = $$("updFileVersionLinux");
        $scope.updFileSizeLinux     = $$("updFileSizeLinux");
        $scope.uploadProgressLinux  = $$("uploadProgressLinux");
        $scope.updBtnUpdaterLinux   = $$("updBtnUpdaterLinux");

        // === LINUX32 ===
        // $scope.updFileInfoLinux32     = $$("updFileInfoLinux32");
        // $scope.updFileUpdExistLinux32 = $$("updFileUpdExistLinux32");
        // $scope.updFileVersionLinux32  = $$("updFileVersionLinux32");
        // $scope.updFileSizeLinux32     = $$("updFileSizeLinux32");
        // $scope.uploadProgressLinux32  = $$("uploadProgressLinux32");
        // $scope.updBtnUpdaterLinux32   = $$("updBtnUpdaterLinux32");

        mcService.disableContextMenu(view);
    } else {

    }

    return view;
}
"use strict";

function updatesController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.Updates;
    $scope.updateData   = {};
    $scope.fileName     = "";
    $scope.fileMac      = "updatemac.zip";
    $scope.fileLinux    = "updatelinux.zip";
    // $scope.fileLinux32  = "updatelinux32.zip";
    $scope.fileWin32next= "updatewin32next.zip";

    // ======= Error Actions ==========

    $rootScope.ErrorActions[164] = // "164": "ошибка загрузки файла обновления, неверная версия",
    $rootScope.ErrorActions[163] = function(){ // "163": "ошибка загрузки файла обновления, файл повреждён",
        $scope.uploadProgress.hide();
        $scope.uploadProgressMac.hide();
        $scope.uploadProgressLinux.hide();
        // $scope.uploadProgressLinux32.hide();
        $scope.uploadProgressWin32next.hide();
    };

    // ================================

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_server_options, function(){
        mcConst.restartOptions[1] = mcConst.restartItems.WEB;

        $rootScope.$broadcast('NeedRestartServer', []);

        return mcService.Lang(669); // "669": "Настройки сохранены!"
    });

    var angElement = document.getElementById($scope.Name);
    var view = null;

    function parseInfo( data ){
        $scope.updateData = data;
        $scope.data = $rootScope.mcStorage.SettingsNetwork;

        $scope.fileName = "mcclient-v" + ($scope.updateData.PacketExists_win32 ? $scope.updateData.Version_win32 : window.__serverVer).replace(/\./g, '-') + ".exe";

        $scope.show();

        // === WINDOWS ===
        if ($scope.updateData.PacketExists_win32){
            $scope.updFileInfo.show();

            $scope.updFileUpdExist.define('template', "<span class='brown bolder'>Win32</span>: <span class='green _grName'>" + mcLang(1557) + "</span>"); // "1557":"На сервере есть файл для обновления клиентов",
            $scope.updFileVersion .define("template", mcLang(1560) + "<span class='green _grName'>" + $scope.updateData.Version_win32 + "</span>"); // "1560":"Версия пакета обновления: ",
            $scope.updFileSize    .define("template", mcLang(1561) + "<span class='green _grName'>" + mcService.formatNumber($scope.updateData.Size_win32) + "</span>"); // "1561":"Размер в байтах: ",
            $scope.updBtnUpdater  .define('value',    mcLang(1559) + ": " + $scope.fileName);

            $scope.updFileUpdExist.refresh();
            $scope.updFileVersion .refresh();
            $scope.updFileSize    .refresh();
            $scope.updBtnUpdater  .refresh();
        } else {
            $scope.updFileInfo.hide();
        }

        // === WIN32NEXT ===
        if ($scope.updateData.PacketExists_win32next){
            $scope.updFileInfoWin32next.show();

            $scope.updFileUpdExistWin32next.define('template', "<span class='brown bolder'>Win32next</span>: <span class='green _grName'>" + mcLang(1557) + "</span>"); // "1557":"На сервере есть файл для обновления клиентов",
            $scope.updFileVersionWin32next .define("template", mcLang(1560) + "<span class='green _grName'>" + $scope.updateData.Version_win32next + "</span>"); // "1560":"Версия пакета обновления: ",
            $scope.updFileSizeWin32next    .define("template", mcLang(1561) + "<span class='green _grName'>" + mcService.formatNumber($scope.updateData.Size_win32next) + "</span>"); // "1561":"Размер в байтах: ",
            $scope.updBtnUpdaterWin32next  .define('value',    mcLang(1559) + ": " + $scope.fileWin32next);

            $scope.updFileUpdExistWin32next.refresh();
            $scope.updFileVersionWin32next .refresh();
            $scope.updFileSizeWin32next    .refresh();
            $scope.updBtnUpdaterWin32next  .refresh();
        } else {
            $scope.updFileInfoWin32next.hide();
        }

        // === MACOS ===
        if ($scope.updateData.PacketExists_mac){
            $scope.updFileInfoMac.show();

            $scope.updFileUpdExistMac.define('template', "<span class='brown bolder'>macOS</span>: <span class='green _grName'>" + mcLang(1557) + "</span>"); // "1557":"На сервере есть файл для обновления клиентов",
            $scope.updFileVersionMac .define("template", mcLang(1560) + "<span class='green _grName'>" + $scope.updateData.Version_mac + "</span>"); // "1560":"Версия пакета обновления: ",
            $scope.updFileSizeMac    .define("template", mcLang(1561) + "<span class='green _grName'>" + mcService.formatNumber($scope.updateData.Size_mac) + "</span>"); // "1561":"Размер в байтах: ",
            $scope.updBtnUpdaterMac  .define('value',    mcLang(1559) + ": " + $scope.fileMac);

            $scope.updFileUpdExistMac.refresh();
            $scope.updFileVersionMac .refresh();
            $scope.updFileSizeMac    .refresh();
            $scope.updBtnUpdaterMac  .refresh();
        } else {
            $scope.updFileInfoMac.hide();
        }

        // === LINUX ===
        if ($scope.updateData.PacketExists_linux){
            $scope.updFileInfoLinux.show();

            $scope.updFileUpdExistLinux.define('template', "<span class='brown bolder'>Linux x64</span>: <span class='green _grName'>" + mcLang(1557) + "</span>"); // "1557":"На сервере есть файл для обновления клиентов",
            $scope.updFileVersionLinux .define("template", mcLang(1560) + "<span class='green _grName'>" + $scope.updateData.Version_linux + "</span>"); // "1560":"Версия пакета обновления: ",
            $scope.updFileSizeLinux    .define("template", mcLang(1561) + "<span class='green _grName'>" + mcService.formatNumber($scope.updateData.Size_linux) + "</span>"); // "1561":"Размер в байтах: ",
            $scope.updBtnUpdaterLinux  .define('value',    mcLang(1559) + ": " + $scope.fileLinux);

            $scope.updFileUpdExistLinux.refresh();
            $scope.updFileVersionLinux .refresh();
            $scope.updFileSizeLinux    .refresh();
            $scope.updBtnUpdaterLinux  .refresh();
        } else {
            $scope.updFileInfoLinux.hide();
        }

        // === LINUX32 ===
        /*if ($scope.updateData.PacketExists_linux32){
            $scope.updFileInfoLinux32.show();

            $scope.updFileUpdExistLinux32.define('template', "<span class='brown bolder'>Linux x86</span>: <span class='green _grName'>" + mcLang(1557) + "</span>"); // "1557":"На сервере есть файл для обновления клиентов",
            $scope.updFileVersionLinux32 .define("template", mcLang(1560) + "<span class='green _grName'>" + $scope.updateData.Version_linux32 + "</span>"); // "1560":"Версия пакета обновления: ",
            $scope.updFileSizeLinux32    .define("template", mcLang(1561) + "<span class='green _grName'>" + mcService.formatNumber($scope.updateData.Size_linux32) + "</span>"); // "1561":"Размер в байтах: ",
            $scope.updBtnUpdaterLinux32  .define('value',    mcLang(1559) + ": " + $scope.fileLinux32);

            $scope.updFileUpdExistLinux32.refresh();
            $scope.updFileVersionLinux32 .refresh();
            $scope.updFileSizeLinux32    .refresh();
            $scope.updBtnUpdaterLinux32  .refresh();
        } else {
            $scope.updFileInfoLinux32.hide();
        }*/

        $scope.uploadProgress.hide();
        $scope.uploadProgressMac.hide();
        $scope.uploadProgressLinux.hide();
        // $scope.uploadProgressLinux32.hide();
        $scope.uploadProgressWin32next.hide();
    }

    $scope.loadUpdateFile = function (type, file){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_upload_update_packet,
            mcConst.SessionID,
            type,
            file // $scope.fileName
        ]);

        // $scope.getData();
    };

    $scope.uploadError = function(item, res){
        var text = "";

        try {
            text = item ? "<br>" + JSON.stringify(item.context) : "";
        } catch (e){}

        webix.alert(mcLang(1563) + text + (res ? "<br>" + res : "")); // "1563":"При загрузке файла возникла ошибка:",

        $scope.uploadProgress.hide();
        $scope.uploadProgressMac.hide();
        $scope.uploadProgressLinux.hide();
        // $scope.uploadProgressLinux32.hide();
        $scope.uploadProgressWin32next.hide();
    };

    // =============================================

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_update_packet_data,
            mcConst.SessionID
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        view = initUpdates($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();
    };

    $scope.$on('on_sc_adm_update_packet_data', function (e, args){
        parseInfo.apply(null, args);
    })

    $scope.$on('hide' + $scope.Name, function() {
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        mcService.getMcSettings($rootScope, $scope.getData);
    });

}
/**
 * Created by Gifer on 30.07.2015.
 */

function initMCScripts($scope){
    "use strict";

    var _view = $$($scope.Name);

    if (!_view){
        var searchBar = new mcService.FilterFiled({
            listName : "eventsList" + $scope.Name,
            filterParams : [ "value" ]
        });

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type: "header", width: 150, template : mcService.Lang(1589) }, // "1589":"Скрипты",
                    { view: "template", id: "scriptPath" + $scope.Name, type: "header", template : " " },
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},


                { rows: [
                    { type: 'layout', minHeight: 100, cols : [
                        { width: 270, rows: [
                            { view    : "button",
                                value : mcLang(1614), // "1614":"Отмена изменений",
                                hidden: true,
                                id    : "scriptRollback" + $scope.Name,
                                type  : "danger",
                                click : $scope.rollback
                            },
                            { id: "wrapperEventsList" + $scope.Name, rows: [
                                { height: 3},
                                searchBar,

                                {
                                    view   : "tree",
                                    id     : "eventsList" + $scope.Name,
                                    select : true,
                                    css    : "anyListSelect",
                                    activeTitle: true,
                                    template: function(obj, common){
                                        var res = '';

                                        //common.icon(obj, common) common.folder(obj, common) common.checkbox(obj, common) +"<span style='float:left;padding:0;width:6px;height:100%;background:none;'></span>"
                                        /*switch (obj.$level) {
                                            case 1: case 2: res = common.icon(obj, common) + common.folder(obj, common) + obj.value; break;
                                            case 3: case 4:
                                                if (obj.)
                                                res = "<span style='float:left;padding:0;width:24px;height:100%;background:none;'></span>" +
                                                ($scope.noLibraryScript(obj) ? common.checkbox(obj, common) : common.folder(obj, common)) + "&nbsp;" + obj.value;
                                            break;
                                        }*/

                                        if (obj.folder){
                                            res = common.icon(obj, common) + common.folder(obj, common) + obj.value;
                                        } else {
                                            res = "<span style='float:left;padding:0;width:24px;height:100%;background:none;'></span>" +
                                                  ($scope.noLibraryScript(obj) ? common.checkbox(obj, common) : common.folder(obj, common)) + "&nbsp;" + obj.value;
                                        }

                                        return res;
                                    },
                                    //threeState: true,
                                    data : [],
                                    on   : {
                                        onAfterSelect: $scope.onSelectEvent,
                                        onItemCheck: $scope.onOffScript,
                                        onViewResize: function () {
                                            console.log(arguments);
                                        }
                                    },
                                    onContext: {}
                                }
                            ]}
                        ]},

                        { view: "resizer" },

                        { rows: [
                            {
                                height: 30,
                                cols: [
                                    { view: "button", id: "btnNew"   + $scope.Name, value: mcLang(1597), click: function() {  // "1597":"Создать",
                                        $scope.showDialog();
                                    }, tooltip: mcLang(1597) + " | Alt + N"},
                                    { view: "button", id: "btnSave"  + $scope.Name, value: mcLang(104), disabled: true, click: $scope.saveScript, tooltip: mcLang(104) + " | Ctrl + S | F2" },  // "104": "Сохранить",
                                    { view: "button", id: "btnDelete"+ $scope.Name, value: mcLang(52), disabled: true, type: "danger", tooltip: mcLang(52) + " | Alt + Del", click: $scope.deleteScript },   // "52" : "Удалить",
                                    { view: "button", id: "btnCheck" + $scope.Name, value: mcLang(1590), disabled: true, click: $scope.checkScript, tooltip: mcLang(1590) + " | Ctrl + F9" }, // "1590":"Проверить",
                                    { view: "button", id: "btnRun"   + $scope.Name, value: mcLang(1591), disabled: true, click: $scope.scriptRun, tooltip: mcLang(1591) + " | F9" }, // "1591":"Выполнить",
                                    {},
                                    { view: "icon", icon: 'info', width: 36, click: $scope.showScriptInfo, tooltip: mcLang(1784) + " | Ctrl + I"} // "1784":"Информация",
                                ]
                            },
                            {
                                id  : "scriptViewArea",
                                view: "codemirror-editor",
                                css : "codemirror-editor",
                                mode: {
                                    name: "pascal",
                                    globalVars: true
                                    //cursorActivity: $scope.cursorActivity
                                },
                                autoheight : true,
                                lineNumbers: true,

                                on: {
                                    onReady: function () {
                                        this.editor.on('change', $scope.onChangeScript);
                                        this.editor.on('focus', function () {
                                            if (leftContext) {
                                                leftContext.hide();
                                            }
                                        });
                                    }
                                }
                            }
                        ]}
                    ]},

                    { id: "consoleResizer" + $scope.Name, view: "resizer"},
                    { id: "console" + $scope.Name, template: ' ', height: 140, css: "Courier selectableEx _logConsole", scroll: true, minHeight: 50},

                    { type: 'layout', height: 30, css: "grayBorderTop", padding: 0, cols: [
                        {},
                        { view: "button", type: "icon", icon: "trash", label: mcLang(619), width: 100, align: 'center', click: $scope.clearConsole} // "619": "Очистить",
                    ]}
                ]}
            ]
        });

        $scope.scriptPath     = $$("scriptPath" + $scope.Name);
        $scope.eventsList     = $$("eventsList" + $scope.Name);
        $scope.consoleResizer = $$("consoleResizer" + $scope.Name);
        $scope.consoleWrapper = $$("consoleWrapper" + $scope.Name);
        $scope.console        = $$("console" + $scope.Name);
        $scope.scriptViewArea = $$("scriptViewArea");
        $scope.scriptRollback = $$("scriptRollback" + $scope.Name);
        $scope.wrapperEventsList = $$("wrapperEventsList" + $scope.Name);

        $scope.btnNew         = $$("btnNew"   + $scope.Name);
        $scope.btnSave        = $$("btnSave"  + $scope.Name);
        $scope.btnDelete      = $$("btnDelete"+ $scope.Name);
        $scope.btnCheck       = $$("btnCheck" + $scope.Name);
        $scope.btnRun         = $$("btnRun"   + $scope.Name);

        $scope.editorReadOnly(true);

        var leftContext = webix.ui({
            view  : "context",
            width : 220,
            master: $scope.eventsList,
            body  : { rows: [
                { view: "button", value: mcLang(1597) + " | Alt + N", click: function(){ // "1597":"Создать",
                    this.getTopParentView().hide();

                    $scope.showDialog();
                }},
                { view: "button", id: "scriptContextMenuDelete", value: mcLang(52) + " | Alt + Del", type: "danger", click: function(){ // "52" : "Удалить",
                    this.getTopParentView().hide();

                    $scope.deleteScript();
                }}
            ]},
            on: {
                onBeforeShow: function (e) {
                    var _id = e.target.getAttribute('webix_tm_id');
                    var id  = parseInt(_id);
                    var res = isNaN(id);

                    if (!this.delBtn) {
                        this.delBtn = $$("scriptContextMenuDelete");
                    }

                    if (!res) {
                        this.delBtn.show();
                        this.selectedID = id;

                        $scope.eventsList.select(_id);
                    } else
                    if (mcService.findItemInArrayOfObj($scope.treeEventsList, _id, "id") === -1){
                        this.delBtn.hide();

                        $scope.eventsList.select(_id);
                    } else {
                        this.getTopParentView().hide();

                        return false;
                    }
                }
            }
        });

        mcService.disableContextMenu(_view, ["CodeMirror-line", "_logConsole"]);
    } else {

    }

    if (!$scope.showDialog){
        $scope.showDialog = function (){
            if ($scope.dialogWindow){
                $scope.dialogWindow.show();
            } else {
                $scope.dialogWindow = webix.ui({
                    view     : "window",
                    position : "center",
                    modal    : true,
                    width    : 350,
                    head     : mcLang(1605), // "1605":"Создание нового скрипта",
                    body     : {
                        view : 'form',
                        rules:{
                            "Name"   : $scope.checkNewScript,
                            "Event"  : function(id){ return id != '-1' }
                        },
                        elements : [{
                            view     : "text",
                            id       : 'dialog' + $scope.Name,
                            label    : mcService.Lang(1606), // "1606":"Название:",
                            name     : 'Name',
                            required : "true",
                            labelPosition : 'top',
                            invalidMessage: mcLang(1850) // "1850":"В названии скрипта можно использовать латинские буквы и символы: \"-\" и \"_\"",
                        }, {
                            view     : "richselect",
                            id       : 'richselect' + $scope.Name,
                            label    : mcService.Lang(1607), // "1607":"Событие:",
                            name     : 'Event',
                            required : "true",
                            value    : '-1',
                            labelPosition : 'top',
                            options  : [].concat($scope.treeEventsList[0].data)
                                         .concat($scope.treeEventsList[1].data)
                                         .concat($scope.treeEventsList[2].data)
                                         .concat($scope.treeEventsList[3].data)
                        }, {
                            cols : [{
                                view  : "button",
                                value : mcService.Lang(104), // "104": "Сохранить",
                                click : $scope.onEnter
                                /*function() {
                                    var isValid = this.getFormView().validate();

                                    if (isValid) {
                                        $scope.createNewScript(this.getFormView().getValues());
                                        $scope.dialogWindow.hide();
                                    }
                                }*/
                            }, {
                                view  : "button",
                                type  : "danger",
                                value : mcService.Lang(103), // "103": "Отмена",
                                click : $scope.onEsc
                                /*function(){
                                    $scope.dialogWindow.hide();
                                }*/
                            }]
                        }]
                    },
                    on : {
                        onShow : function(){
                            $scope.removeHotKeys();
                            $scope.registerNewScriptKeys();

                            var self = this;
                            var event = $scope.eventsList.getSelectedItem();
                            var eventID = '-1';

                            if (event){
                                switch (event.$level){
                                    case 3: eventID = event.$parent; break;
                                    case 2: eventID = event.id; break;
                                }
                            }

                            self.getChildViews()[1].setValues({
                                Name: '',
                                Event: eventID
                            });

                            setTimeout(function(){
                                self.getChildViews()[1].getChildViews()[0].focus();
                            }, 10);

                            $scope.regShowWindow(this.config.id, this);
                        },
                        onHide : function () {
                            $scope.removeNewScriptKeys();
                            $scope.registerMenuKeys();
                        }
                    }
                });

                $scope.dialogWindow.show();
            }
        }
    }

    return _view;
}

 /**
 * Created by Gifer on 30.07.2015.
 */

function mcScriptsController($scope, $rootScope){
     "use strict";

     $scope.Name = mcConst.dataModels.MCScripts;

    var _view = document.getElementById($scope.Name);
    var scriptView = null;
    var _scripts = {};
    var currentScriptID = -1;
    var dontSend = false;

    var MSG_OK       = 0;
    var MSG_ERROR    = 1;
    var MSG_CLEAR    = 2;
    var MSG_RUN      = 3;
    var MSG_RUNERROR = 4;
    var MSG_LOG      = 5;

    var PRESET_MENU  = "scriptMenu";
    var PRESET_NEWSCRIPT = "PRESET_NEWSCRIPT";

    var eventTreeState = null;
    var scriptInEdit   = false;

    $scope.disableCheck  = true;

    function inLibrary(item) {
        return ['Custom', 'Service', 'Examples', 'Kanban'].indexOf(item) >= 0;
    }

    function sortTree() {
        $scope.eventsList.sort("sortValue", "asc", function (a, b) {
            return a.toString().indexOf('__') == (a.toString().length - 2) ? mcService.sortAB(parseInt(a), parseInt(b)) : mcService.sortAB(a, b);
        });
    }

    function fillScriptsList(list){
        $scope.disableCheck = true;

        if (list && mcService.isArray(list) && list.length){
            for (var i = 0; i < list.length; i++){
                if ($scope.eventsList.getItem(list[i].Event)){
                    $scope.eventsList.add({
                        id        : list[i].ID,
                        sortValue : inLibrary(list[i].Event) ? list[i].ScriptName : '__',
                        value     : list[i].ScriptName
                    }, list[i].ScriptPosition, list[i].Event);

                    if (list[i].Enabled) {
                        $scope.eventsList.checkItem(list[i].ID);
                    }
                }
            }

            sortTree();

            if (eventTreeState){
                $scope.eventsList.setState(eventTreeState);
            }
        }

        $scope.disableCheck = false;

        if ($rootScope.adminOptions.currentScript){
            var item = $scope.eventsList.getItem($rootScope.adminOptions.currentScript);

            if (item){
                dontSend = true;

                $scope.eventsList.open(item.$parent);
                $scope.eventsList.select($rootScope.adminOptions.currentScript);
                $scope.eventsList.showItem($rootScope.adminOptions.currentScript);

                dontSend = false;
            }
        }
    }

    function addLog(type, message){
        var consoleView = $scope.console.$view.firstChild;
        var logDiv      = document.createElement('pre');
        var sName       = _scripts[currentScriptID] ? " \"" + _scripts[currentScriptID].ScriptName + "\"" : "";

        function focusOnEditor(){
            setTimeout(function(){
                $scope.scriptViewArea.focus();
            }, 50);
        }

        switch (type){
            case MSG_OK:
                logDiv.innerHTML = "[" + mcService.formatDate(message.dt, "hh:nn:ss") + "] (Check" + sName + "): " + "<span class='green'>" + mcLang(1593) + "</span>"; // "1593":"Скрипт скомпилирован без ошибок",

                $scope.regShowWindow(mcService.RandomHash(4), webix.alert(mcLang(1593), focusOnEditor)); // "1593":"Скрипт скомпилирован без ошибок",
                break;

            case MSG_RUN:
                logDiv.innerHTML =
                    "[" + mcService.formatDate(message.dt, "hh:nn:ss") + "] (Run" + sName + "): " + "<span class='green'>" + mcLang(1596, message.Time) + "</span><br>" + // "1596":"Время выполнения скрипта: %s миллисекунд",); // "1595":"Скрипт выполнен без ошибок",
                    "[" + mcService.formatDate(message.dt, "hh:nn:ss") + "] (Run" + sName + "): " + "<span class='green'>" + mcLang(1595) + "</span><br>"; // "1595":"Скрипт выполнен без ошибок",

                $scope.regShowWindow(mcService.RandomHash(4), webix.alert(mcLang(1595) + "<br>" + mcLang(1596, message.Time), focusOnEditor)); // "1595":"Скрипт выполнен успешно.<br>Время выполнения <b>%s</b> мс",
            break;

            case MSG_ERROR:
                logDiv.innerHTML = "[" + mcService.formatDate(message.dt, "hh:nn:ss") + "] (Error" + sName + "): " + "<span class='red'>" + message.ErrMsg + "</span>";

                $scope.regShowWindow(mcService.RandomHash(4), webix.alert(message.ErrMsg, focusOnEditor));
            break;

            case MSG_RUNERROR:
                logDiv.innerHTML =
                    "[" + mcService.formatDate(message.dt, "hh:nn:ss") + "] (RunError" + sName + "): " + "<span class='red'>" + mcLang(1596, message.Time) + "</span><br>" + // "1596":"Время выполнения скрипта: %s миллисекунд",
                    "[" + mcService.formatDate(message.dt, "hh:nn:ss") + "] (RunError" + sName + "): " + "<span class='red'>" + message.ErrMsg + "</span>";

                $scope.regShowWindow(mcService.RandomHash(4), webix.alert(message.ErrMsg, focusOnEditor()));
            break;

            case MSG_LOG:
                logDiv.innerHTML = "[" + mcService.formatDate(message.dt, "hh:nn:ss") + "] (Log" + sName + "): " + (message.Tag ? "[" + message.Tag + "] " : "") + message.Msg.replace(/</g, "&lt;");
            break;

            case MSG_CLEAR:
                $scope.console.define('template', "");
                $scope.console.refresh();
            break;
        }

        if (type !== MSG_CLEAR){
            consoleView.appendChild(logDiv);

            $scope.console.$view.scrollTop = consoleView.scrollHeight;
        }
    }

    function checkScriptAnswer(data){
        if (data.Ok){
            addLog(MSG_OK, data);
        } else {
            var editor = $scope.scriptViewArea.editor;

            editor.addLineClass(data.Row - 1, "background", "bgRed");
            editor.setCursor({line: data.Row - 1, ch: data.Col - 1});

            $scope.errorCursor = data.Row - 1;

            editor.on("cursorActivity", $scope.cursorActivity);

            addLog(MSG_ERROR, data);
        }
    }

    function checkScriptRun(data){
        if (data.Ok){
            addLog(MSG_RUN, data);
        } else {
            var editor = $scope.scriptViewArea.editor;

            editor.addLineClass(data.Row - 1, "background", "bgRed");
            editor.setCursor({line: data.Row - 1, ch: data.Col - 1});

            $scope.errorCursor = data.Row - 1;

            editor.on("cursorActivity", $scope.cursorActivity);

            addLog(MSG_RUNERROR, data);

            $scope.disableCheck = true;

            _scripts[currentScriptID].checked = false;

            $scope.eventsList.uncheckItem(currentScriptID);

            $scope.disableCheck = false;
        }
    }

    function findDuplicate(name){
        var flag = false;

        for (var i = 0; i < _scripts.length; i++){
            if (_scripts[i].ScriptName == name){
                flag = true;
                break;
            }
        }

        return flag;
    }

    function saveScriptAnswer(data){
        _scripts[data.ID] = mcService.Marge(_scripts[data.ID], data);
        _scripts[data.ID].changed = false;
        $scope.btnSave.disable();

        webix.message(mcLang(1608)); //  "1608":"Скрипт сохранен!",

        hideRollback();
        $scope.scriptViewArea.focus();
    }

    function displayPath(path){
        $scope.scriptPath.define('template', path || " ");
        $scope.scriptPath.refresh();
    }

    function noScript(){
        displayPath(' ');

        currentScriptID = -1;
        $scope.scriptViewArea.setValue('');
        $scope.editorReadOnly(true);

        hideRollback();
    }

    function showRollback(){
        scriptInEdit = true;

        $scope.btnNew.disable();
        $scope.wrapperEventsList.disable();
        //$scope.eventsList.disable();
        //$scope.eventsList.scrollTo(0,0);

        $scope.scriptRollback.show();
    }

    function hideRollback(){
        scriptInEdit = false;

        $scope.btnNew.enable();
        //$scope.eventsList.enable();
        $scope.wrapperEventsList.enable();
        $scope.scriptRollback.hide();
    }
    
    function clearConsole() {
        addLog(MSG_CLEAR);
    }

    //===================================================

    $scope.cursorActivity = function () {
        if ($scope.errorCursor){
            var editor = $scope.scriptViewArea.editor;

            editor.removeLineClass($scope.errorCursor, "background", "bgRed");

            $scope.errorCursor = null;

            editor.off("cursorActivity");
        }
    };

    $scope.noLibraryScript = function(obj){
        return mcService.findItemInArrayOfObj($scope.treeEventsList[3].data, obj.$parent, "id") === -1;
    };

    $scope.registerNewScriptKeys = function(){
        $rootScope.hotKeyDispatcher.addPreset(PRESET_NEWSCRIPT, [{
            key    :  mcConst.keyCodes.enter,
            func   : $scope.onEnter
        }, {
            key    :  mcConst.keyCodes.esc,
            func   : $scope.onEsc
        }], document);
    };

    $scope.removeNewScriptKeys = function () {
        $rootScope.hotKeyDispatcher.removePreset(PRESET_NEWSCRIPT);
    };

    $scope.registerMenuKeys = function(){
        $rootScope.hotKeyDispatcher.addPreset(PRESET_MENU, [{
            key:  mcConst.keyCodes.s,
            ctrlKey: true,
            func: $scope.saveScript
        },{
            key:  mcConst.keyCodes.space,
            ctrlKey: true,
            func: function(){
                return false;
            }
        },{
            key:  mcConst.keyCodes.i,
            ctrlKey: true,
            func: $scope.showScriptInfo
        },{
            key:  mcConst.keyCodes.y,
            ctrlKey: true,
            func: function(){
                var editor = $scope.scriptViewArea.editor;

                if (editor.hasFocus()){
                    var pos = editor.getCursor();

                    editor.setSelection({line: pos.line, ch: 0}, {line: pos.line + 1, ch:0});
                    editor.replaceSelection('');
                }
            }
        }], _view);

        $rootScope.hotKeyDispatcher.addPreset(PRESET_MENU + "global", [{
            key:  mcConst.keyCodes.n,
            altKey: true,
            skipDefault: true,
            func: $scope.showDialog
        },{
            key:  mcConst.keyCodes.f2,
            skipDefault: true,
            func: $scope.saveScript
        },{
            key:  mcConst.keyCodes.delete,
            altKey: true,
            skipDefault: true,
            func: $scope.deleteScript
        },{
            key:  mcConst.keyCodes.f9,
            ctrlKey: true,
            skipDefault: true,
            func: $scope.checkScript
        },{
            key:  mcConst.keyCodes.f9,
            skipDefault: true,
            func: $scope.scriptRun
        }], document);
    };

    $scope.treeEventsList = [{
        id   : "es",
        value: "Chat events",
        open : true,
        sortValue: '__',
        folder: true,
        data : [
            { id:"OnADUserImport",       value:"OnADUserImport",     folder: true, sortValue: '1__'},
            { id:"OnBBSMessage",         value:"OnBBSMessage",       folder: true, sortValue: '2__'},
            { id:"OnBeforeRegister",     value:"OnBeforeRegister",   folder: true, sortValue: '3__'},
            { id:"OnBroadcastMessage",   value:"OnBroadcastMessage", folder: true, sortValue: '4__'},
            { id:"OnChatServerStart",    value:"OnChatServerStart",  folder: true, sortValue: '5__'},
            { id:"OnChatServerStop",     value:"OnChatServerStop",   folder: true, sortValue: '6__'},
            { id:"OnClientConnect",      value:"OnClientConnect",    folder: true, sortValue: '7__'},
            { id:"OnClientDisconnect",   value:"OnClientDisconnect", folder: true, sortValue: '8__'},
            { id:"OnClientPluginSendRawData",   value:"OnClientPluginSendRawData", folder: true, sortValue: '9__'},
            { id:"OnClientRemoteExec",   value:"OnClientRemoteExec", folder: true, sortValue: '10__'},
            { id:"OnConfJoin",           value:"OnConfJoin",         folder: true, sortValue: '11__'},
            { id:"OnConfKick",           value:"OnConfKick",         folder: true, sortValue: '12__'},
            { id:"OnConfLeave",          value:"OnConfLeave",        folder: true, sortValue: '13__'},
            { id:"OnConfMessage",        value:"OnConfMessage",      folder: true, sortValue: '14__'},
            { id:"OnFTPServerStart",     value:"OnFTPServerStart",   folder: true, sortValue: '15__'},
            { id:"OnFTPServerStop",      value:"OnFTPServerStop",    folder: true, sortValue: '16__'},

            { id:"OnMediaCallFinished",  value:"OnMediaCallFinished",folder: true, sortValue: '17__'},
            { id:"OnMediaCallRequest",   value:"OnMediaCallRequest", folder: true, sortValue: '18__'},
            { id:"OnMediaCallStarted",   value:"OnMediaCallStarted", folder: true, sortValue: '19__'},

            { id:"OnPrivateMessage",     value:"OnPrivateMessage",   folder: true, sortValue: '20__'},
            { id:"OnPrivateRequest",     value:"OnPrivateRequest",   folder: true, sortValue: '21__'},
            { id:"OnRegistered",         value:"OnRegistered",       folder: true, sortValue: '22__'},
            { id:"OnRemoteUserRequest",  value:"OnRemoteUserRequest",folder: true, sortValue: '23__'},
            { id:"OnRequestByREST",      value:"OnRequestByREST",    folder: true, sortValue: '24__'},
            { id:"OnSendAdvertBanner",   value:"OnSendAdvertBanner", folder: true, sortValue: '25__'},
            { id:"OnUserBlock",          value:"OnUserBlock",        folder: true, sortValue: '26__'},
            { id:"OnUserChangeProfile",  value:"OnUserChangeProfile",folder: true, sortValue: '27__'},
            { id:"OnUserLogin",          value:"OnUserLogin",        folder: true, sortValue: '28__'},
            { id:"OnUserStateChange",    value:"OnUserStateChange",  folder: true, sortValue: '29__'},
            //{ id:"OnUserDisconnect",     value:"OnUserDisconnect", sortValue: '__'}
            //{ id:"OnADUserImport",       value:"OnADUserImport"}
        ]
    }, {
        id   : "ke",
        value: "Kanban events",
        open : true,
        folder: true,
        sortValue: '__',
        data : [
            { id:"OnKanbanCommentAdd",    value:"OnKanbanCommentAdd",    folder: true, sortValue: '1__'},
            { id:"OnKanbanCommentDelete", value:"OnKanbanCommentDelete", folder: true, sortValue: '2__'},
            { id:"OnKanbanProjectAdd",    value:"OnKanbanProjectAdd",    folder: true, sortValue: '3__'},
            { id:"OnKanbanProjectClose",  value:"OnKanbanProjectClose",  folder: true, sortValue: '4__'},
            { id:"OnKanbanProjectDelete", value:"OnKanbanProjectDelete", folder: true, sortValue: '5__'},
            { id:"OnKanbanProjectModify", value:"OnKanbanProjectModify", folder: true, sortValue: '6__'},
            { id:"OnKanbanProjectReopen", value:"OnKanbanProjectReopen", folder: true, sortValue: '7__'},
            { id:"OnKanbanStageAdd",      value:"OnKanbanStageAdd",      folder: true, sortValue: '8__'},
            { id:"OnKanbanStageDelete",   value:"OnKanbanStageDelete",   folder: true, sortValue: '9__'},
            { id:"OnKanbanStageModify",   value:"OnKanbanStageModify",   folder: true, sortValue: '10__'},
            { id:"OnKanbanTaskAdd",       value:"OnKanbanTaskAdd",       folder: true, sortValue: '11__'},
            { id:"OnKanbanTaskDelete",    value:"OnKanbanTaskDelete",    folder: true, sortValue: '12__'},
            { id:"OnKanbanTaskModify",    value:"OnKanbanTaskModify",    folder: true, sortValue: '13__'},
            { id:"OnKanbanTaskMove",      value:"OnKanbanTaskMove",      folder: true, sortValue: '14__'},
            { id:"OnKanbanTaskTake",      value:"OnKanbanTaskTake",      folder: true, sortValue: '15__'}
        ]
    }, {
        id   : "uds",
        value: "User defined scripts",
        open : true,
        sortValue: '__',
        folder: true,
        data : [
            { id:"second",   value:"Every second",     folder: true, sortValue: '1__'},
            { id:"seconds30",value:"Every 30 seconds", folder: true, sortValue: '2__'},
            { id:"minute",   value:"Every minute",     folder: true, sortValue: '3__'},
            { id:"minutes5", value:"Every 5 minutes",  folder: true, sortValue: '4__'},
            { id:"minutes15",value:"Every 15 minutes", folder: true, sortValue: '5__'},
            { id:"hour",     value:"Every hour",       folder: true, sortValue: '6__'},
            { id:"hours4",   value:"Every 4 hours",    folder: true, sortValue: '7__'},
            { id:"hours8",   value:"Every 8 hours",    folder: true, sortValue: '8__'},
            { id:"day",      value:"Every day",        folder: true, sortValue: '9__'},
            { id:"week",     value:"Every week",       folder: true, sortValue: '10__'},
            { id:"month",    value:"Every month",      folder: true, sortValue: '11__'}
        ]
    }, {
        id   : "lib",
        value: "Library",
        open : true,
        sortValue: '__',
        folder: true,
        data : [
            { id:"Custom",     value:"Custom",   folder: true, sortValue: '1__'},
            { id:"Service",    value:"Service",  folder: true, sortValue: '2__'},
            { id:"Examples",   value:"Examples", folder: true, sortValue: '3__'}
        ]
    }];

    $scope.rollback = function(){
        if (currentScriptID != '-1' && _scripts.hasOwnProperty(currentScriptID)){
            _scripts[currentScriptID] = null;

            delete _scripts[currentScriptID];

            var id = currentScriptID;
            currentScriptID = '-1';

            $scope.onSelectEvent(id);

            hideRollback();
        }
    };

    $scope.scriptRun = function(){
        if (currentScriptID != -1){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_script_run,
                mcConst.SessionID,
                currentScriptID,
                $scope.scriptViewArea.getValue(),
                checkScriptRun
            ]);

            return false;
        }
    };

    $scope.checkScript = function(){
        if (currentScriptID != -1){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_script_check_syntax,
                mcConst.SessionID,
                
                $scope.scriptViewArea.getValue(),
                _scripts[currentScriptID].ScriptName,

                checkScriptAnswer
            ]);
        }
    };

    $scope.saveScript = function(){
        if (scriptInEdit === false){
            return false;
        } else
        if (currentScriptID != -1){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_script_save,
                mcConst.SessionID,
                currentScriptID,
                $scope.scriptViewArea.getValue(),
                saveScriptAnswer
            ]);

            return false;
        }
    };

    $scope.setEventsState = function(state){
        for (var i in state){
            $scope.eventsList.checkItem(state[i]);
        }
    };

    $scope.onOffScript = function(id){
        if (!$scope.disableCheck){
            var item = $scope.eventsList.getItem(id);

            if (item.$level === 3){
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_script_onoff,
                    mcConst.SessionID,
                    id,
                    item.checked,
                    function(){
                        if (_scripts.hasOwnProperty(id)){
                            _scripts[id].checked = item.checked;
                        }

                        webix.message(mcLang(1594) + " " + (item.checked? mcLang(110) : mcLang(109))); // "1594":"Скрипт", "110": "включен", "109": "выключен",
                    }
                ]);
            }
        }
    };

    $scope.onSelectEvent = function(id){

        var item = $scope.eventsList.getItem(id);

        if (item.$level === 3){
            if (_scripts.hasOwnProperty(id)) {
                $scope.displayScript(id);
            } else {
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_script,
                    mcConst.SessionID,
                    id,
                    function(data){
                        _scripts[id] = data;

                        $scope.displayScript(id);
                    }
                ]);
            }

            if (!dontSend) {
                $rootScope.$broadcast('saveAdminOptions', [id, "currentScript"]);

                dontSend = false;
            }
        } else {
            noScript();

            $scope.disableButtons();
        }
    };

    $scope.editorReadOnly = function(readonly){
        $scope.scriptViewArea.editor.setOption("readOnly", readonly);
    };

    $scope.createNewScript = function(values) {
        // if ((new RegExp(/^[a-zA-Z0-9\-\_]+$/)).test(values.Name)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_script_create,
                mcConst.SessionID,
                values.Name,
                values.Event,
                function(data){
                    $scope.eventsList.add({
                        id        : data.ID,
                        sortValue : inLibrary(data.Event) ? data.ScriptName : '__',
                        value     : data.ScriptName
                    }, data.ScriptPosition, data.Event);

                    _scripts[data.ID] = data;

                    $scope.eventsList.open(data.Event);
                    $scope.eventsList.select(data.ID);

                    sortTree();

                    $scope.editorReadOnly(false);
                }
            ]);
        // } else {
        //     webix.alert(mcLang(1850)); // "1850":"В названии скрипта можно использовать латинские буквы и символы: \"-\" и \"_\"",
        //
        //     return false;
        // }
    };

    $scope.deleteScript = function(){
        if (currentScriptID != -1){
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(1609, _scripts[currentScriptID].ScriptName), // "1609":"Удалить скрипт \"%s\"?",
                ok    : mcService.Lang(581), // "581": "Удалить",
                cancel: mcService.Lang(103), // "103": "Отмена",
                callback:function(yes){
                    if (yes){
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_script_delete,
                            mcConst.SessionID,
                            
                            currentScriptID,

                            function(data){
                                var event = data.Event;

                                for (var i in data){
                                    if (_scripts.hasOwnProperty(i)){
                                        _scripts[i].ScriptPosition = data[i];
                                    }
                                }

                                $scope.eventsList.remove(currentScriptID);
                                $scope.eventsList.select(event);

                                delete data.Event;
                                delete _scripts[currentScriptID];

                                $scope.disableButtons();

                                noScript();
                            }
                        ]);
                    }
                }
            }));
        }
    };

    $scope.checkNewScript = function(name){
        var flag = false;

        if (name != '' && !findDuplicate(name) && (new RegExp(/^[a-zA-Z0-9\-\_]+$/)).test(name)){
            flag = true;
        }

        return flag;
    };

    $scope.showScriptInfo = function(){
        if (_scripts.hasOwnProperty(currentScriptID)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_script_info,
                mcConst.SessionID,
                currentScriptID,
                function (scrpt) {
                    var timeCreate = mcService.utcTime(scrpt.dtCreated, false, "dd.mm.yyyy hh:nn");
                    var timeModify = mcService.utcTime(scrpt.dtLastModified, false, "dd.mm.yyyy hh:nn");
                    var timeStart  = mcService.utcTime(scrpt.dtLastStart, false, "dd.mm.yyyy hh:nn");

                    webix.alert({
                        title: scrpt.ScriptName,
                        width: "440px",
                        text:
                        "<div class='mc-left mc-paddingW10'>"+
                        "<span class='mc-right w200'>" + mcLang(1598) + "</span> <b>"  + scrpt.CreatorDisplayName + " (uin " + scrpt.UINCreator  + ")</b><br>" + // "1598":"Кто создал:",
                        "<span class='mc-right w200'>" + mcLang(1599) + ":</span> <b>" + (scrpt.dtLastStart.indexOf('1900') > 0 ? mcLang(1613) : timeCreate) + "</b><br><br>" + // "1599":"Дата создания:",      "1613":"никогда",
                        "<span class='mc-right w200'>" + mcLang(1600) + "</span> <b>"  + scrpt.LastChangedDisplayName + " (uin " + scrpt.UINLastChanged + ")</b><br>" + // "1600":"Кто менял",
                        "<span class='mc-right w200'>" + mcLang(1601) + "</span> <b>"  + (scrpt.dtLastStart.indexOf('1900') > 0 ? mcLang(1613) : timeModify) + "</b><br><br>" + // "1601":"Дата изменения:",     "1613":"никогда",
                        "<span class='mc-right w200'>" + mcLang(1602) + "</span> <b>"  + (scrpt.dtLastStart.indexOf('1900') > 0 ? mcLang(1613) : timeStart) + "</b><br>" + // "1602":"Дата последнего запуска:", "1613":"никогда",
                        "<span class='mc-right w200'>" + mcLang(1513) + ":</span> <b>" + (scrpt.Enabled ? mcLang(110) : mcLang(109)) + "</b><br>" +// "1513":"Состояние", "110": "включен", "109": "выключен",
                        "<span class='mc-right w200'>" + mcLang(1603) + "</span> <b>"  + scrpt.StatRunsCount + "</b><br>" +// "1603":"Количество запусков:",
                        "<span class='mc-right w200'>" + mcLang(1604) + "</span> <b>"  + scrpt.LastRunDuration + "</b> " + mcLang(1719) +// "1604":"Время выполниения:", "1719":"мс",
                        "</div>"
                    });
                }
            ]);
        }
    };

    $scope.displayScript = function(id){
        if (_scripts.hasOwnProperty(currentScriptID)){
            _scripts[currentScriptID].SourceText = $scope.scriptViewArea.getValue();
        }

        if (_scripts.hasOwnProperty(id)){
            if (currentScriptID != id){
                currentScriptID = '-1';

                $scope.scriptViewArea.setValue(_scripts[id].SourceText);

                currentScriptID = id;

                var event = $scope.eventsList.getItem(id).$parent;
                var eventList = $scope.eventsList.getItem($scope.eventsList.getItem(event).$parent);

                displayPath(eventList.value + ' / ' + event + ' / ' + "<b>" + _scripts[id].ScriptName + "</b>");
                $scope.enableButtons();

                if (_scripts[id].changed){
                    $scope.btnSave.enable();
                } else {
                    $scope.btnSave.disable();
                }

                $scope.scriptViewArea.focus();
                $scope.editorReadOnly(false);
            }
        } else {
            noScript();
        }
    };

    $scope.enableButtons = function(){
        //$scope.btnSave.enable();
        $scope.btnCheck.enable();
        $scope.btnRun.enable();
        $scope.btnDelete.enable();
    };

    $scope.disableButtons = function(){
        $scope.btnSave.  disable();
        $scope.btnCheck. disable();
        $scope.btnRun.   disable();
        $scope.btnDelete.disable();
    };

    $scope.onEsc = function() {
        $scope.dialogWindow.hide();
        $scope.scriptViewArea.focus();

        return false;
    };

    $scope.onEnter = function() {
        var form = $scope.dialogWindow.getChildViews()[1];
        var isValid = form.validate();

        if (isValid) {
            $scope.createNewScript(form.getValues());
            $scope.dialogWindow.hide();
        } else {
            $scope.dialogWindow.getBody().elements['Name'].focus();
        }

        return false;
    };

    $scope.removeHotKeys = function(){
        $rootScope.hotKeyDispatcher.removePreset(PRESET_MENU);
        $rootScope.hotKeyDispatcher.removePreset(PRESET_MENU + "global");
    };

    $scope.getData = function(){
        $scope.eventsList.clearAll();
        $scope.eventsList.parse(webix.copy($scope.treeEventsList));

        sortTree();

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_script_event_states,
            mcConst.SessionID,
            fillScriptsList
        ]);
    };

    $scope.onChangeScript = function(){
        if (currentScriptID != '-1'){//_scripts.hasOwnProperty(currentScriptID) &&
            if (_scripts.hasOwnProperty(currentScriptID) && !_scripts[currentScriptID].changed) {

                _scripts[currentScriptID].changed = true;

                showRollback();
                $scope.btnSave.enable();

                if ($scope.eventsList.getSelectedId() != currentScriptID) {
                    $scope.eventsList.select(currentScriptID);
                    $scope.eventsList.open($scope.eventsList.getItem(currentScriptID).$parent, true);
                }
            }
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.clearConsole = clearConsole;

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, _view);

        scriptView = initMCScripts($scope);

        mcService.initResize(scriptView, $scope.Name);

        scriptView.adjust();

        $scope.registerMenuKeys();
    };

    //===================================================

    $scope.$on('scriptConsoleLog', function(e, args){
        if (args[0] === 'clear'){
            addLog(MSG_CLEAR);
        } else {
            addLog(MSG_LOG, args[0]);
        }
    });

    $scope.$on('scriptClearConsoleLog', function(){
        clearConsole();
    });

    $scope.$on('hide' + $scope.Name, function(){
        eventTreeState = $scope.eventsList.getState();

        _scripts = {};

        mcService.hideView(_view);

        $scope.removeHotKeys();
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
        $scope.getData();
    });
}

















/**
 * Created by Gifer on 30.07.2015.
 */

"use strict";

function initReboot($scope){
    var _view = $$($scope.Name);

    if (!_view){
        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { view: "template", type: "header", template : mcService.Lang(1618) }, // "1618":"Перезагрузка",

                { type: 'layout', padding: 10, rows: [
                    { cols: [
                        { width: 500, rows: [
                            { view: "button", value: mcLang(1619, "Web"), click: function(){   // "1619":"Перезагрузить %s сервер",
                                $scope.reboot('Web');
                            }}, { height: 10 },
                            { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1620), autoheight: true, borderless: true, css: "_info selectable" } // "1620":"При перезагрузке Web сервера будет выгружена из памяти и заново запущен сервис \"node.exe\", при этом прекратятся все звонки и отключаться все пользователи Web-чата",
                        ]},
                        {}
                    ]}
                ]},

                { type: 'layout', padding: 10, rows: [
                    { cols: [
                        { width: 500, rows: [
                            { view: "button", value: mcLang(1619, "FTP"), click: function(){   // "1619":"Перезагрузить %s сервер",
                                $scope.reboot('FTP');
                            }}, { height: 10 },
                            { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1621), autoheight: true, borderless: true, css: "_info selectable" } // "1621":"При перезагрузке FTP сервера будет прекращена вся передача изображений, загрузка обновлений, а также доступ к публичным и персональным папкам пользователей.",
                        ]},
                        {}
                    ]}
                ]},

                { type: 'layout', padding: 10, rows: [
                    { cols: [
                        { width: 500, rows: [
                            { view: "button", value: mcLang(1619, "MyChat"), click: function(){// "1619":"Перезагрузить %s сервер",
                                $scope.reboot('MyChat');
                            }, type: "danger"}, { height: 10 },
                            { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1622), autoheight: true, borderless: true, css: "_info selectable" } // "1622":"Перезагрузва всего серера чата, во время перезагрузки будут отключены абсолютно все пользователи и временно прекратят работу все встроенный сервисы MyChat.",
                        ]},
                        {}
                    ]}
                ]}
            ]
        });
    }

    return _view;
}


/**
 * Created by Gifer on 30.07.2015.
 */

"use strict";

function rebootController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.Reboot;

    var _view = document.getElementById($scope.Name);

   //===================================================

    $scope.reboot = function(srv){
        $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
            type  : "confirm-warning",
            text  : mcService.Lang(1619, srv) + "?", // "1619":"Перезагрузить %s сервер",
            ok    : mcService.Lang(114), // "114": "да",
            cancel: mcService.Lang(113), // "113": "нет",
            callback:function(yes){
                if (yes) {
                    var opt = []
                        .concat(srv === "FTP" ? [] : mcConst.lockInterface)
                        .concat([
                            mcConst._CMD_.cs_adm_restart_server_services,
                            mcConst.SessionID,
                            srv === "MyChat",
                            srv === "Web",
                            srv === "FTP"
                        ]);

                    if (srv === "MyChat" || srv === "Web"){
                        $rootScope.$broadcast('hide' + mcConst.lockInterface, []); // unlock
                        $rootScope.$broadcast('StopPingTimer' ,[]);

                        $rootScope.$broadcast('ErrorMsg', ['223', mcConst.ErrorText['223'], '', function(){
                            mcService.SaveSessionSettings(mcConst.LoginInfo.login, "", "", "");

                            mcService.reloadOrChangeProtocol();
                        }]);
                    }

                    $rootScope.$broadcast('SendCMDToServer', opt);
                }
            }
        }));
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, _view);

        var settings = initReboot($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    //===================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(_view);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
    });
}

"use strict";

function initPresetManager($scope){
    var _view          = $$($scope.Name);
    var labelWidth     = 200;
    var blockWidth     = 600;
    var headerList     = {
        '1':  mcLang(591),  // "591":"Сетевые настройки",
        '2':  mcLang(1345), // "1345":"Настройки прокси",
        '3':  mcLang(1350), // "1350":"Общие",
        '4':  mcLang(1357), // "1357":"Окно чата",
        '5':  mcLang(1367), // "1367":"Показывать окно чата поверх всех окон",
        '6':  mcLang(1371), // "1371":"Формат даты/времени в протоколах сообщений",
        '7':  mcLang(1373), // "1373":"Информационные окошки в системном трее",
        '8':  mcLang(1336), // "1336":"Горчие клавиши",
        '9':  mcLang(1402), // "1402":"Звуки",
        '10': mcLang(29),   // "29" : "Сообщения",
        '11': mcLang(1430), // "1430":"Системные события",
        '12': mcLang(598),  // "598": "Протоколирование",
        '13': mcLang(1445), // "1445":"Загрузка истории сообщений в приват",
        '14': mcLang(1451), // "1451":"Максимальный размер истории сообщений в окне (штук)",
        '15': mcLang(838),  // "838":"Файлы",
        '16': mcLang(1461), // "1461":"Интерфейс клиаента чата",
        '17': mcLang(1464), // "1464":"Обновления",
        '18': mcLang(574),  // "574":"Дополнительно",
        '19': mcLang(1851)  // "1851":"Звонки",
    };

    var keys = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
        "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "Space", "Ins", "Del",
        "Home", "End", "PageUp", "PageDown", "Up", "Down", "Left", "Right", "F1", "F2", "F3", "F4", "F5", "F6",
        "F7", "F8", "F9", "F10", "F11", "F12", "Esc"];

    if (!_view){
        var hideState = true;

        $scope.allOptionsSet = []
            // { id: "NetworkReconnectTime",  head: 1, value: mcService.Lang(1342) + " N " + mcService.Lang(1343)}] // "1342":"Соединяться каждые",
            .concat($scope.isFree ? [] : [{ id: "NetworkSecured",  head: 1, value: mcService.Lang(1054)}])  // "1054":"Использовать шифрование SSL",
            .concat([
            { id: "NetworkProxyType",  head: 2, value: mcService.Lang(1346)},  // "1346":"Тип прокси:",
            { id: "NetworkProxyHost",  head: 2, value: mcService.Lang(1347)},  // "1347":"Адрес прокси:",
            { id: "NetworkProxyPort",  head: 2, value: mcService.Lang(1348)},  // "1348":"Порт прокси:",
            { id: "NetworkProxyAuth",  head: 2, value: mcService.Lang(1349)},  // "1349":"Нужна авторизация",
            { id: "NetworkProxyUserName",  head: 2, value: mcService.Lang(1)},     // "1"  : "Логин",
            { id: "NetworkProxyUserPass",  head: 2, value: mcService.Lang(2)},     // "2"  : "Пароль",

            { id: "SecurityOptionsPassword",  head: 3, value: mcService.Lang(1663)},  // "1663":"Пароль на вход в раздел настроек",
            { id: "GeneralWindowsStart",  head: 3, value: mcService.Lang(1351)},  // "1351":"Запускать MyChat Client после старта Windows",
            { id: "GeneralConfirmExit",  head: 3, value: mcService.Lang(1352)},  // "1352":"Спрашивать подтверждение перед выходом из программы",
            { id: "GeneralStartPassword", head: 3, value: mcService.Lang(1333)},  // "1333":"Спрашивать пароль при каждом подключении к серверу",
            { id: "GeneralMainWindow", head: 3, value: mcService.Lang(1353)},  // "1353":"Действие с главным окном после старта",
            { id: "SpecialMessagesFontSize", head: 3, value: mcService.Lang(1664)},  // "1664":"Размер шрифта для сообщений",
            // { id: "SpecialToolsPanelType", head: 3, value: mcService.Lang(1665)},  // "1665":"Тип главной панели инструментов",
            //{ id: "SpecialPagesPanel", head: 3, value: mcService.Lang(1666)},  // "1666":"Ориентация панели с закладками ",
            { id: "GeneralRememberOpenContactGroups", head: 3, value: mcService.Lang(1724)},  // "1724":"Запоминать раскрытые группы контактов",

            { id: "GeneralShowSendButton", head: 4, value: mcService.Lang(1358)},  // "1358":"Показывать в каналах и приватах кнопку для отправки сообщения",
            { id: "GeneralCtrlEnterSend", head: 4, value: mcService.Lang(1359)},  // "1359":"Отправлять сообщения комбинацией Ctrl+Enter",
            { id: "GeneralSpellCheck", head: 4, value: mcService.Lang(1360)},  // "1360":"Проверка правописания",
            { id: "GeneralAutoHideMainWindow", head: 4, value: mcService.Lang(1361)},  // "1361":"Автоматическое скрытие окна MyChat Client в трей при бездействии пользователя",
            //{ id: "GeneralShowUsersCounterOnTheTabs", head: 4, value: mcService.Lang(1363)},  // "1363":"Показывать на закладках каналов счётчик пользователей",
            //{ id: "GeneralOpenPrivateByOneClick", head: 4, value: mcService.Lang(1364)},  // "1364":"Открывать приваты одинарным кликом",
            // { id: "GeneralDoubleClickPagesClose", head: 4, value: mcService.Lang(1365)},  // "1365":"Закрывать закладки разговоров двойным щелчком мыши",
            { id: "GeneralFadeWindows", head: 4, value: mcService.Lang(1366)},  // "1366":"Использовать эффект \"проявки\" при показе диалоговых окон",
            //{ id: "GeneralShowMainToolsPanel", head: 4, value: mcService.Lang(1660)},  // "1660":"Показывать главную панель инструментов",
            // { id: "GeneralShowTipOfTheDay", head: 4, value: mcService.Lang(1661)},  // "1661":"Показывать панель советов или нет",
            // { id: "GeneralTipOfTheDayNum", head: 4, value: mcService.Lang(1716)},  // "1716":"Номер \"Совета дня\" в панели советов (Shift+F3)",
            { id: "GeneralQuickMsgAutoSend", head: 4, value: mcService.Lang(1662)},  // "1662":"Мгновенная отправка в чат шаблонных сообщений",
            { id: "InputFieldSize", head: 4, value: mcService.Lang(2106)},  // "2106":"Размер поля для ввода текста",
            { id: "ShowConfBigImage", head: 4, value: mcService.Lang(2184)},  // "2184":"Показывать большое изображение конференций в панели информации (Ctrl + /)",

            { id: "EventsAutoOpenIncomingMessage", head: 5, value: mcService.Lang(2040)}, // "2040":"Автоматически переключаться на входящие сообщения",

            { id: "EventsPopupOnNewBBS", head: 5, value: mcService.Lang(1368)}, // "1368":"При новом сообщении на доске объявлений",
            { id: "EventsPopupOnChannelMessage", head: 5, value: mcService.Lang(1369)}, // "1369":"При получении нового сообщения в канале",
            { id: "EventsPopupOnPrivateMessage", head: 5, value: mcService.Lang(1370)}, // "1370":"При получении нового сообщения в привате",

            // { id: "EventsTimeStamp", head: 6, value: mcService.Lang(1372)}, // "1372":"Показывать штапм даты и времени:",
            // { id: "EventsDateTimeStampFormat", head: 6, value: mcService.Lang(1684)}, // "1684":"Формат дати и времени:",

            //{ id: "EventsOpenPrivateOnPersonalOrAlert", head: 7, value: mcService.Lang(1381)}, // "1381":"Открывать приват при получении личного или алерт сообщения",
            { id: "EventsShowPopupTrayWindow", head: 7, value: mcService.Lang(1374)}, // "1374":"Показывать всплывающие информационные окошки в системном трее",
            { id: "EventsTrayBBSMsg", head: 7, value: mcService.Lang(1368)}, // "1368":"При новому повідомленні на дошці оголошень",
            { id: "EventsTrayChMsg", head: 7, value: mcService.Lang(1369)}, // "1369":"При получении нового сообщения в конференциях",
            { id: "EventsTrayPvMsg", head: 7, value: mcService.Lang(1370)}, // "1370":"При получении нового сообщения в привате",
            { id: "EventsTrayDontHide", head: 7, value: mcService.Lang(1334)}, // "1334":"Что делать со всплывающим окном?",
            { id: "EventsTrayBlinkOnTaskBar", head: 7, value: mcService.Lang(1842)}, // "1842":"Мигать на панели задач, если есть непрочитанные сообщения",

            { id: "HotKeysEscHide", head: 8, value: mcService.Lang(1382)}, // "1382":"Прятать в трей окно чата по клавише ESC",
            { id: "HotKeysUseGlobalHotKeys", head: 8, value: mcService.Lang(1335)}, // "1335":"Использовать глобальные \"горячие\" клавиши",
            { id: "HotKeysHotKeyMyChat", head: 8, value: mcService.Lang(1383)}, // "1383":"Показать / спрятать главное окно чата",
            { id: "HotKeysHotKeyMyChatScreenShot", head: 8, value: mcService.Lang(1384)}, // "1384":"Передать снимок экрана",

            { id: "HotKeyVoiceCall", head: 8, value: mcService.Lang(2062)}, // "2062":"Голосовой звонок",
            { id: "HotKeyVideoCall", head: 8, value: mcService.Lang(2063)}, // "2063":"Видео звонок",
            { id: "HotKeyMaximizeMainForm", head: 8, value: mcService.Lang(2064)}, // "2064":"Развернуть окно чата на весь экран",
            { id: "HotKeyVoiceCallWithScreenShare", head: 8, value: mcService.Lang(2065)}, // "2065":"Голосовой звонок с демонстрацией экрана",

            { id: "SoundsAllSoundsOff", head: 9, value: mcService.Lang(1403)}, // "1403":"Отключить все используемые звуки в программе",
            { id: "SoundsAllSoundsOffCustom", head: 9, value: mcService.Lang(1681)}, // "1681":"Выборочное включение/выключение звуков",
            { id: "SoundsFilesCustom", head: 9, value: mcService.Lang(1694)}, // "1694":"Настройка файлов звуковых сигналов",

            { id: "SysEventsAutoFillBroadcastUsersList", head: 10, value: mcService.Lang(1424)}, // "1424":"Заполнять автоматически список людей при создании оповещения",
            { id: "SysEventsShowImagesInChat", head: 10, value: mcService.Lang(1425)}, // "1425":"Показывать изображения в тексте чата",
            { id: "SysEventsImagesThumbsSize", head: 10, value: mcService.Lang(1822)}, // "1822":"Размер миниатюр изображений в чате",
            { id: "SysEventsUseMessagesFontLayouts", head: 10, value: mcService.Lang(1426)}, // "1426":"Использовать шрифтовую разметку сообщений",
            { id: "SysEventsDisableEmotions", head: 10, value: mcService.Lang(1427)}, // "1427":"Отключить использование графических смайликов",
            // { id: "SysEventsEnableSmileysAnimation", head: 10, value: mcService.Lang(1428)}, // "1428":"Включить анимацию смайликов",
            // { id: "SysEventsAutoreplaceSmileys", head: 10, value: mcService.Lang(1429)}, // "1429":"Включить автозамену набираемого текста на графические смайлики",
            { id: "SysEventsShowPrivateDeliveryStatuses", head: 10, value: mcService.Lang(2039)}, // "2039":"Показывать статусы доставки сообщений",
            { id: "SmartTextSelection", head: 10, value: mcService.Lang(2108)}, // "2108":"\"Умное\" выделение текста мышкой, по словам\n",
            { id: "ShowElisaInConfs", head: 10, value: mcService.Lang(2271)}, // "2271":"Показывать робота в автосоздаваемых конференциях",

            // { id: "SysEventsShowSysEvents", head: 11, value: mcService.Lang(1431)}, // "1431":"Показывать системные сообщения в каналах чата",
            // { id: "SysEventsEnterTxtxCh", head: 11, value: mcService.Lang(1432)}, // "1432":"*** Пользователь вошёл в канал",
            // { id: "SysEventsLeaveTxtxCh", head: 11, value: mcService.Lang(1433)}, // "1433":"*** Пользователь вышел из канала",
            // { id: "SysEventsQuitChat", head: 11, value: mcService.Lang(1434)}, // "1434":"*** Пользователь отключился от сервера",
            // { id: "SysEventsChangeTheme", head: 11, value: mcService.Lang(1435)}, // "1435":"*** Пользователь установил новую тему канала",
            // { id: "SysEventsBanUser", head: 11, value: mcService.Lang(1436)}, // "1436":"*** Пользователь наказал пользователя",
            // { id: "SysEventsTurnOut", head: 11, value: mcService.Lang(1437)}, // "1437":"*** Пользователь выгнал пользователя из канала",
            // { id: "SysEventsIgnore", head: 11, value: mcService.Lang(1438)}, // "1438":"*** Пользователь проигнорировал ваше сообщение",
            // { id: "SysEventsConnectionLost", head: 11, value: mcService.Lang(1439)}, // "1439":"*** Произошел обрыв связи, вы отключены от сервера",
            // { id: "SysEventsConnectionRestored", head: 11, value: mcService.Lang(1440)}, // "1440":"*** Связь восстановлена",

            { id: "LogsServer", head: 12, value: mcService.Lang(1442)}, // "1442":"Лог соединения с MyChat сервером",
            { id: "LogsFTP", head: 12, value: mcService.Lang(2240)}, // "2240":"Лог FTP",
            { id: "LogsTxtChannels", head: 12, value: mcService.Lang(1444)}, // "1444":"Текстовые каналы",
            { id: "LogsPrivates", head: 12, value: mcService.Lang(1441)}, // "1441":"Cообщения в приватах",

            { id: "LoadHistoryToConf", head: 13, value: mcService.Lang(1880)}, // "1880":"Загружать историю в конференции",
            { id: "LoadHistoryToPrivate", head: 13, value: mcService.Lang(1881)}, // "1881":"Загружать историю в приваты",

            // { id: "AutoLoadBroadcastFiles", head: 15, value: mcService.Lang(1910)}, // "1910":"Автоматически скачивать приложенные файлы из оповещений",
            { id: "SendFilesSayYes", head: 15, value: mcService.Lang(1452)}, // "1452":"Принимать файлы от пользователей из списка контактов, не задавая вопросов",
            //{ id: "SendFilesRenameRecievedDuplicates", head: 15, value: mcService.Lang(1453)}, // "1453":"Переименовывать файлы-дубликаты при приеме, не перезаписывая поверху",
            { id: "63", head: 15, value: mcService.Lang(1454)}, // "1454":"Порты для передачи файлов",
            { id: "SendFilesInputFilesDir", head: 15, value: mcService.Lang(1457)}, // "1457":"Сохранять файлы, которые присылают пользователи, в:",
            { id: "SendFilesRememberSelectInputFilesFolder", head: 15, value: mcService.Lang(1460)}, // "1460":"Запомнить выбранную папку для каждого пользователя",
            { id: "SendFilesBufferSize", head: 15, value: mcService.Lang(1459)}, // "1459":"Размер буфера:",

            // { id: "GeneralDisableAvatars", head: 16, value: mcService.Lang(1462)}, // "1462":"Не показывать аватары",
            { id: "LanguagesLanguage", head: 16, value: mcService.Lang(6)},    // "6"  : "Язык интерфейса",
            // { id: "SmileysSmileysSet", head: 16, value: mcService.Lang(1693)}, // "1693":"Название используемого набора смайлов",
            { id: "InterfaceTrayIconListNumber", head: 16, value: mcService.Lang(1826)}, // "1826":"Иконка в трее",
            { id: "InterfaceCommonBackground", head: 16, value: mcService.Lang(1830)}, // "1830":"Фон для конференций и приватов",
            { id: "InterfaceBackgroundPlacement", head: 16, value: mcService.Lang(1832)}, // "1832":"Расположение фона",
            { id: "InterfaceExtRightPanelVisible", head: 16, value: mcService.Lang(2212)}, // "2212":"Показывать информационную панель о пользователе/конференции (Ctrl + /)",

            { id: "GeneralDailyUpdatesCheck", head: 17, value: mcService.Lang(1465)}, // "1465":"Еженедельно проверять наличие новой верии MyChat",
            // { id: "71", head: 17, value: mcService.Lang(1469)}, // "1469":"Способ обновления",

            // { id: "UpdateUpdateDomain", head: 17, value: mcService.Lang(123)},
            // { id: "UpdateUpdateLogin", head: 17, value: mcService.Lang(1)},
            // { id: "UpdateUpdatePassword", head: 17, value: mcService.Lang(2)},
            { id: "UpdateSilentMode", head: 17, value: mcService.Lang(2068)}, // "2068":"\"Тихий\" режим, не показывать окно скачивания пакета обновления",
            // { id: "UpdateForceUpdateFromMyChatServerInActiveDirectory", head: 17, value: mcService.Lang(1468)}, // "1468":"При работе в Active Directory принудительно обновляться через MyChat Server",

            { id: "AdditionalPrivateInfoFields", head: 18, value: mcService.Lang(1470)}, // "1470":"Список информационных полей, которые показываются в приватном чате",
            { id: "AdditionalProgramCaption", head: 18, value: mcService.Lang(1471)}, // "1471":"Заголовок программы",
            { id: "AdditionalSystemTrayText", head: 18, value: mcService.Lang(1472)}, // "1472":"Хинт в системном лотке (трее)",
            { id: "AdditionalExtOptions", head: 18, value: mcService.Lang(2041)}, // "2041":"Расширенные настройки",

            // { id: "Transport",          head: 19, value: mcService.Lang(1852)}, // "1852":"Сетевой транспорт",
            { id: "IceTransportPolicy", head: 19, value: mcService.Lang(1856)}  // "1856":"Метод связи",
        ]);

        // == "591":"Сетевые настройки", ==
        var rmctrlHeader1 = { rows: [
            { template: headerList['1'], id: "rmctrlHeader1", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
            //             { id: "rcitm_NetworkReconnectTime", head: 1, hidden: hideState, cols: [
            //                     { template: mcService.Lang(1342), borderless: true, width: 150 }, // "1342":"Соединяться каждые",
            //                     { id: "sub_NetworkReconnectTime", head: 1, view: "counter", value: 10, step: 1, min: 1, max: 999, width: 102, on: { onChange: $scope.showApplyPanel}},
            //                     { template: mcService.Lang(1343), borderless: true} // "1343":"секунд после разрыва соединения",
            //                 ]},
                        { id: "rcitm_NetworkSecured", head: 1, view: "checkbox", hidden: $scope.isFree || hideState, labelRight: mcService.Lang(1054), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}} // "1054":"Использовать шифрование SSL",
                ]},
                {gravity:0}
            ]}
        ]};

        // == "1345":"Настройки прокси", ==
        var rmctrlHeader2 = { rows: [
            { template: headerList['2'], head: 2, id: "rmctrlHeader2", hidden: true, css: "webixBGBlue", height: 26},

            { cols: [
                { /*maxWidth: blockWidth,*/ rows: [
                    { id: "rcitm_NetworkProxyType", head: 2, view: "select", hidden: hideState, label: mcService.Lang(1346), labelWidth: labelWidth, value: "1", options: [ // "1346":"Тип прокси:",
                        { id: "0", value: "NONE"},
                        { id: "1", value: "SOCKS4"},
                        { id: "2", value: "SOCKS5"}
                    ], on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_NetworkProxyHost", head: 2, view: "text", hidden: hideState, label: mcService.Lang(1347), labelWidth: labelWidth, on: { onTimedKeyPress: $scope.showApplyPanel}},

                    { id: "rcitm_NetworkProxyPort", head: 2, padding: 0, hidden: hideState, cols: [
                        { id: "sub_NetworkProxyPort", head: 2, view: "counter", label: mcLang(1348), labelWidth: labelWidth, value: 1020, step: 1, min: 1, max: 65000, maxWidth: blockWidth, on: { onChange: $scope.showApplyPanel}},
                        {gravity:0}
                    ]},
                    //{ id: "rcitm_NetworkProxyPort", head: 2, view: "text", hidden: hideState, label: mcService.Lang(1348), labelWidth: labelWidth, on: { onTimedKeyPress: $scope.showApplyPanel}}, // "1348":"Порт прокси:",

                    { id: "rcitm_NetworkProxyAuth", head: 2, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1349), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1349":"Нужна авторизация",
                    { id: "rcitm_NetworkProxyUserName", head: 2, view: "text", hidden: hideState, label: mcService.Lang(1), labelWidth: labelWidth, on: { onTimedKeyPress: $scope.showApplyPanel}}, // "1"  : "Логин",
                    { id: "rcitm_NetworkProxyUserPass", head: 2, view: "text", hidden: hideState, type: "password", label: mcService.Lang(2), labelWidth: labelWidth, on: { onTimedKeyPress: $scope.showApplyPanel}} // "2"  : "Логин",
                ]},
                { gravity: 0}
            ]}
        ]};

        // == "1350":"Общие" ==
        var rmctrlHeader3 = { rows: [
            { template: headerList['3'], head: 3, id: "rmctrlHeader3", hidden: true, css: "webixBGBlue", height: 26},

            { cols: [
                { maxWidth: blockWidth, rows: [
                    { id: "rcitm_SecurityOptionsPassword", head: 3, view: "text", hidden: hideState, type: "password", label: mcService.Lang(1663), labelWidth: 250, on: { onTimedKeyPress: $scope.showApplyPanel}} // "1663":"Пароль на вход в раздел настроек",
                ]},
                { gravity: 0}
            ]},

            {cols: [
                    {rows:[
                            { id: "rcitm_GeneralWindowsStart", head: 3, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1351), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_GeneralConfirmExit", head: 3, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1352), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_GeneralStartPassword", head: 3, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1333), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_GeneralMainWindow", head: 3, view: "radio", hidden: hideState, value: "0", vertical: true, label: mcService.Lang(1353), labelPosition: "top", height: 100, options: [
                                    { id: "0", value: mcService.Lang(683)},  // "683": "Ничего не делать",
                                    { id: "1", value: mcService.Lang(1355)}, // "1355":"Прятать окно MyChat в трей после старта",
                                    { id: "2", value: mcService.Lang(1356)}  // "1356":"Разворачивать главное окно на весь экран после старта",
                                ], on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_SpecialMessagesFontSize", head: 3, view: "radio", hidden: hideState, value: "0", vertical: true, label: mcService.Lang(1664), labelPosition: "top", height: 120, options: [// "1664":"Размер шрифта для сообщений",
                                    { id: "0", value: mcService.Lang(1667)}, // "1667":"маленький",
                                    { id: "1", value: mcService.Lang(1668)}, // "1668":"обычный",
                                    { id: "2", value: mcService.Lang(1669)}, // "1669":"большой",
                                    { id: "3", value: mcService.Lang(1670)}  // "1670":"очень большой",
                                ], on: { onChange: $scope.showApplyPanel}},
                            /*{ id: "rcitm_SpecialToolsPanelType", head: 3, view: "radio", hidden: hideState, value: "1", vertical: true, label: mcService.Lang(1665), labelPosition: "top", height: 70, options: [ // "1665":"Тип главной панели инструментов",
                             { id: "1", value: mcService.Lang(1671)}, // "1671":"полноразмерная",
                             { id: "2", value: mcService.Lang(1672)}  // "1672":"маленькая",
                             ], on: { onChange: $scope.showApplyPanel}},*/
                            //{ id: "rcitm_SpecialPagesPanel", head: 3, view: "radio", hidden: hideState, value: "1", vertical: true, label: mcService.Lang(1666), labelPosition: "top", height: 60, options: [ // "1666":"Ориентация панели с закладками ",
                                    //{ id: "1", value: mcService.Lang(1673)},  // "1673":"вверху",
                                    // { id: "2", value: mcService.Lang(1674)},  // "1674":"справа",
                                    //{ id: "3", value: mcService.Lang(1675)}  // "1675":"снизу",
                                    // { id: "4", value: mcService.Lang(1676)}   // "1676":"слева",
                                //], on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_GeneralRememberOpenContactGroups", head: 3, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1724), labelWidth: 0, value: true, css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1724":"Запоминать раскрытые группы контактов",
                            { id: "rcitm_ShowConfBigImage", head: 3, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2184), labelWidth: 0, value: true, css: "finger", on: { onChange: $scope.showApplyPanel}} // "2184":"Показывать большое изображение конференций в панели информации (Ctrl + /)",
                        ]},
                    {gravity:0}
                ]}
        ]};

        // == "1357":"Окно чата" ==
        var rmctrlHeader4 = { rows: [
            { template: headerList['4'], head: 4, id: "rmctrlHeader4", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
                    { id: "rcitm_GeneralShowSendButton", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1358), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_GeneralCtrlEnterSend", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1359), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_GeneralSpellCheck", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1360), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_GeneralAutoHideMainWindow", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1361), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1361":"Автоматическое скрытие окна MyChat Client в трей при бездействии пользователя",
                    /*{ id: "rcitm_17", hidden: hideState, cols: [
                     { view: "checkbox", labelRight: mcService.Lang(1361), labelWidth: 0, value: "", css: "finger", width: 350},
                     { id: "", view: "counter", value: 10, step: 1, min: 1, max: 999, width: 102},
                     { template: mcService.Lang(681), width: 60, borderless: true } // "681": "минут",
                     ]},*/
                    //{ id: "rcitm_GeneralShowUsersCounterOnTheTabs", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1363), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    //{ id: "rcitm_GeneralOpenPrivateByOneClick", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1364), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    // { id: "rcitm_GeneralDoubleClickPagesClose", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1365), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_GeneralFadeWindows", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1366), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    //{ id: "rcitm_GeneralShowMainToolsPanel", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1660), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_GeneralQuickMsgAutoSend", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1662), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},

                    { id: "rcitm_CloseDialogsByDoubleClick", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2111), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2111":"Закрывать диалоги средней кнопкой мышки",
                    { id: "rcitm_CloseDialogsByMiddleClick", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2112), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2112":"Закрывать диалоги двойным кликом левой кнопки мышки",

                    // { id: "rcitm_GeneralShowTipOfTheDay", head: 4, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1661), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    // { id: "rcitm_GeneralTipOfTheDayNum", head: 4, view: "counter", label: mcLang(1716), labelWidth: 320, hidden: hideState, value: 1, step: 1, min: 1, max: 999, /*width: 500,*/ on: { onChange: $scope.showApplyPanel}} // "1716":"Номер \"Совета дня\" в панели советов (Shift+F3)",

                    { id: "rcitm_InputFieldSize", head: 4, view: "select", hidden: hideState, label: mcService.Lang(2106), labelWidth: 300, width: blockWidth, value: "0", options: [ // "2106":"Размер поля для ввода текста",
                        { id: "1", value: "auto"},
                        { id: "2", value: "20%"},
                        { id: "3", value: "30%"},
                        { id: "4", value: "50%"}
                    ], on: { onChange: $scope.showApplyPanel}},
                ]},
                {gravity:0}
            ]}
        ]};

        // == "1367":"Показывать окно чата поверх всех окон", ==
        var rmctrlHeader5 = { rows: [
            { template: headerList['5'], head: 5, id: "rmctrlHeader5", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                    {rows:[
                            { id: "rcitm_EventsAutoOpenIncomingMessage", head: 5, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2040), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2040":"Автоматически переключаться на входящие сообщения",

                            { id: "rcitm_EventsPopupOnNewBBS",         head: 5, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1368), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_EventsPopupOnChannelMessage", head: 5, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1369), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_EventsPopupOnPrivateMessage", head: 5, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1370), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}
                        ]},
                    {gravity:0}
                ]}
        ]};

        // == "1371":"Формат даты/времени в протоколах сообщений", ==
        var rmctrlHeader6 = { rows: [
            { template: headerList['6'], head: 6, id: "rmctrlHeader6", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows: [
                    // { id: "rcitm_EventsTimeStamp", head: 6, hidden: hideState, view: "checkbox", labelRight: mcService.Lang(1372), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                    // { id: "rcitm_EventsDateTimeStampFormat", head: 6, hidden: hideState, /*width: 400,*/ label: mcLang(1684), labelWidth: labelWidth, view: "text", value: "[hh:mm:ss]", on: { onTimedKeyPress: $scope.showApplyPanel}} // // "1684":"Формат дати и времени:",
                ]},
                {gravity:0}
            ]}

            /*{ id: "rcitm_EventsTimeStamp", head: 6,  cols: [
            ]}*/
        ]};

        // == "1373":"Информационные окошки в системном трее", ==
        var rmctrlHeader7 = { rows: [
            { template: headerList['7'], head: 7, id: "rmctrlHeader7", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                    {rows:[
                            //{ id: "rcitm_EventsOpenPrivateOnPersonalOrAlert", head: 7, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1381), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_EventsShowPopupTrayWindow", head: 7, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1374), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            { id: "rcitm_EventsTrayBBSMsg", head: 7, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1368), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1368":"При новому повідомленні на дошці оголошень",
                            { id: "rcitm_EventsTrayChMsg", head: 7, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1369), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1369":"При получении нового сообщения в конференциях",
                            { id: "rcitm_EventsTrayPvMsg", head: 7, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1370), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1370":"При получении нового сообщения в привате",
                            { id: "rcitm_EventsTrayDontHide", head: 7, hidden: hideState, rows: [
                                    { id: "sub1_EventsTrayDontHide", head: 7, view: "radio", value: "1", vertical: true, /*width: 200,*/ label: mcService.Lang(1334), labelPosition: "top", css: "finger", height: 70, options:[ // "1334":"Что делать со всплывающим окном?",
                                            { id: "1", value: mcService.Lang(1378)}, // "1378":"Показывать и не прятать",
                                            { id: "0", value: mcService.Lang(1380)} // "1380":"Скрывать после:",
                                        ], on: { onChange: $scope.showApplyPanel}},
                                    { cols: [
                                            { width: 25 },
                                            { id: "sub2_EventsTrayDontHide", head: 7, view: "counter", value: 10, step: 1, min: 1, max: 999, width: 100, on: { onChange: $scope.showApplyPanel}},
                                            { template: mcService.Lang(1379), borderless: true } // "1379":"секунд",
                                        ]}
                                ]},
                            { id: "rcitm_EventsTrayBlinkOnTaskBar", head: 7, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1842), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1370":"При получении нового сообщения в привате",
                        ]},
                    {gravity:0}
                ]}
        ]};

        // == "1336":"Горчие клавиши", ==
        var rmctrlHeader8 = { rows: [
            { template: headerList['8'], head: 8, id: "rmctrlHeader8", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                    {rows:[
                            { id: "rcitm_HotKeysEscHide", head: 8, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1382), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1382":"Прятать в трей окно чата по клавише ESC",
                            { id: "rcitm_HotKeysUseGlobalHotKeys", head: 8, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1335), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1335":"Использовать глобальные \"горячие\" клавиши",
                            { id: "rcitm_HotKeysHotKeyMyChat", head: 8, hidden: hideState, rows: [
                                    { template: mcService.Lang(1383), borderless: true, autoheight: true}, // "1383":"Показать / спрятать главное окно чата",
                                    { cols: [
                                            { id: "sub_HotKeysHotKeyMyChat_Ctrl", head: 8, view: "checkbox", labelRight: "Ctrl", labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChat_Alt", head: 8, view: "checkbox", labelRight: "Alt",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChat_Shift", head: 8, view: "checkbox", labelRight: "Shift",labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChat_Win", head: 8, view: "checkbox", labelRight: "Win",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChat_key", head: 8, view: "select", value: "F12", width: 100, options: keys, on: { onChange: $scope.showApplyPanel}}
                                        ]}
                                ]},

                            { id: "rcitm_HotKeyVoiceCall", head: 8, hidden: hideState, rows: [
                                    { template: mcService.Lang(2062), borderless: true, autoheight: true}, // "2062":"Голосовой звонок",
                                    { cols: [
                                            { id: "sub_HotKeyVoiceCall_Ctrl", head: 8, view: "checkbox", labelRight: "Ctrl", labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVoiceCall_Alt", head: 8, view: "checkbox", labelRight: "Alt",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVoiceCall_Shift", head: 8, view: "checkbox", labelRight: "Shift",labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVoiceCall_key", head: 8, view: "select", value: "F12", width: 100, options: keys, on: { onChange: $scope.showApplyPanel}}
                                        ]}
                                ]},
                            { id: "rcitm_HotKeyVideoCall", head: 8, hidden: hideState, rows: [
                                    { template: mcService.Lang(2063), borderless: true, autoheight: true}, // "2063":"Видео звонок",
                                    { cols: [
                                            { id: "sub_HotKeyVideoCall_Ctrl", head: 8, view: "checkbox", labelRight: "Ctrl", labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVideoCall_Alt", head: 8, view: "checkbox", labelRight: "Alt",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVideoCall_Shift", head: 8, view: "checkbox", labelRight: "Shift",labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVideoCall_key", head: 8, view: "select", value: "F12", width: 100, options: keys, on: { onChange: $scope.showApplyPanel}}
                                        ]}
                                ]},
                            { id: "rcitm_HotKeyMaximizeMainForm", head: 8, hidden: hideState, rows: [
                                    { template: mcService.Lang(2064), borderless: true, autoheight: true}, // "2064":"Развернуть окно чата на весь экран",
                                    { cols: [
                                            { id: "sub_HotKeyMaximizeMainForm_Ctrl", head: 8, view: "checkbox", labelRight: "Ctrl", labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyMaximizeMainForm_Alt", head: 8, view: "checkbox", labelRight: "Alt",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyMaximizeMainForm_Shift", head: 8, view: "checkbox", labelRight: "Shift",labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyMaximizeMainForm_key", head: 8, view: "select", value: "F12", width: 100, options: keys, on: { onChange: $scope.showApplyPanel}}
                                        ]}
                                ]},
                            { id: "rcitm_HotKeyVoiceCallWithScreenShare", head: 8, hidden: hideState, rows: [
                                    { template: mcService.Lang(2065), borderless: true, autoheight: true}, // "2065":"Голосовой звонок с демонстрацией экрана",
                                    { cols: [
                                            { id: "sub_HotKeyVoiceCallWithScreenShare_Ctrl", head: 8, view: "checkbox", labelRight: "Ctrl", labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVoiceCallWithScreenShare_Alt", head: 8, view: "checkbox", labelRight: "Alt",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVoiceCallWithScreenShare_Shift", head: 8, view: "checkbox", labelRight: "Shift",labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeyVoiceCallWithScreenShare_key", head: 8, view: "select", value: "F12", width: 100, options: keys, on: { onChange: $scope.showApplyPanel}}
                                        ]}
                                ]},

                            { id: "rcitm_HotKeysHotKeyMyChatScreenShot", head: 8, hidden: hideState, rows: [
                                    { template: mcService.Lang(1384), borderless: true, autoheight: true}, // "1384":"Передать снимок экрана",
                                    { cols: [
                                            { id: "sub_HotKeysHotKeyMyChatScreenShot_Ctrl", head: 8, view: "checkbox", labelRight: "Ctrl", labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChatScreenShot_Alt", head: 8, view: "checkbox", labelRight: "Alt",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChatScreenShot_Shift", head: 8, view: "checkbox", labelRight: "Shift",labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChatScreenShot_Win", head: 8, view: "checkbox", labelRight: "Win",  labelWidth: 0, value: "", css: "finger", width: 60, on: { onChange: $scope.showApplyPanel}},
                                            { id: "sub_HotKeysHotKeyMyChatScreenShot_key", head: 8, view: "select", value: "C", width: 100, options: keys, on: { onChange: $scope.showApplyPanel}}
                                        ]}
                                ]}
                        ]},
                    {gravity:0}
                ]}
        ]};

        // == "1402":"Звуки", ==
        var rmctrlHeader9 = { rows: [
            { template: headerList['9'], head: 9, id: "rmctrlHeader9", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                    {rows:[
                            { id: "rcitm_SoundsAllSoundsOff", head: 9, hidden: hideState, rows: [
                                    { id: "sub_SoundsAllSoundsOff", head: 9, view: "checkbox", labelRight: mcService.Lang(1403), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}} // "1403":"Включить все звуки",
                                ]},

                            { cols: [
                                    { /*maxWidth: blockWidth,*/ rows: [
                                            { id: "rcitm_SoundsAllSoundsOffCustom", head: 9, hidden: hideState, rows: [
                                                    { template: mcLang(1681), borderless: true, autoheight: true}, // "1681":"Выборочное включение/выключение звуков",
                                                    { padding: 2, rows: [
                                                            { view: "scrollview", height: 300, body: { padding: 7, rows: [
                                                                        { id: "rcitm_SoundsSndError", head: 9, view: "checkbox", labelRight: mcService.Lang(1386), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1386":"Ошибка",
                                                                        { id: "rcitm_SoundsSndJoin", head: 9, view: "checkbox", labelRight: mcService.Lang(1404), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1404":"Пользователь заходит в канал",
                                                                        { id: "rcitm_SoundsSndLeave", head: 9, view: "checkbox", labelRight: mcService.Lang(1405), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1405":"Пользователь покидает канал",
                                                                        { id: "rcitm_SoundsSndChat", head: 9, view: "checkbox", labelRight: mcService.Lang(1406), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1406":"Новое сообщение в канале",
                                                                        { id: "rcitm_SoundsSndStatus", head: 9, view: "checkbox", labelRight: mcService.Lang(1407), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1407":"Изменения в чате (смена ника, аватара, темы канала и т.д.)",
                                                                        { id: "rcitm_SoundsSndSignal", head: 9, view: "checkbox", labelRight: mcService.Lang(1408), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1408":"Сигнал",
                                                                        { id: "rcitm_SoundsSndChatType", head: 9, view: "checkbox", labelRight: mcService.Lang(1409), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1409":"Ввод текст",
                                                                        { id: "rcitm_SoundsSndChatBS", head: 9, view: "checkbox", labelRight: mcService.Lang(1410), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1410":"Правка текста (BS, Del)",
                                                                        { id: "rcitm_SoundsSndChatRet", head: 9, view: "checkbox", labelRight: mcService.Lang(1411), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1411":"Ввод текста (Enter)",
                                                                        { id: "rcitm_SoundsSndNewMsg", head: 9, view: "checkbox", labelRight: mcService.Lang(1412), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1412":"Новое сообщение на доске объявлений",
                                                                        { id: "rcitm_SoundsSndPrivate", head: 9, view: "checkbox", labelRight: mcService.Lang(1413), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1413":"Новое сообщение в привате",
                                                                        { id: "rcitm_SoundsSndBadWord", head: 9, view: "checkbox", labelRight: mcService.Lang(1414), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1414":"Плохие слова",
                                                                        { id: "rcitm_SoundsSndBroadcast", head: 9, view: "checkbox", labelRight: mcService.Lang(1415), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1415":"Новое оповещение",
                                                                        { id: "rcitm_SoundsSndScreenShot", head: 9, view: "checkbox", labelRight: mcService.Lang(1416), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1416":"Снимок экрана",
                                                                        { id: "rcitm_SoundsSndFilesExchangeRequest", head: 9, view: "checkbox", labelRight: mcService.Lang(1417), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1417":"Запрос на передачу файлов",
                                                                        { id: "rcitm_SoundsSndFilesExchangeDone", head: 9, view: "checkbox", labelRight: mcService.Lang(1418), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1418":"Передача файлов завершена",
                                                                        { id: "rcitm_SoundsSndMediaCall", head: 9, view: "checkbox", labelRight: mcService.Lang(1419), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1419":"Медиазвонок, сигнал вызова",
                                                                        { id: "rcitm_SoundsSndMediaBusy", head: 9, view: "checkbox", labelRight: mcService.Lang(1420), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1420":"Медиазвонок, сигнал \"занято\"",
                                                                        { id: "rcitm_SoundsSndMediaCallReject", head: 9, view: "checkbox", labelRight: mcService.Lang(1421), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1421":"Медиазвонок, обрыв связи",
                                                                        { id: "rcitm_SoundsSndMediaIncomingCall", head: 9, view: "checkbox", labelRight: mcService.Lang(1422), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1422":"Медиазвонок, входящий звонок",
                                                                        { id: "rcitm_SoundsSndMediaEndCall", head: 9, view: "checkbox", labelRight: mcService.Lang(1423), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}  // "1423":"Медиазвонок, конец связи",
                                                                    ]}}
                                                        ]}
                                                ]}
                                        ]},
                                    { gravity: 0}
                                ]},
                        ]},
                    {gravity:0}
            ]},

            { cols: [
                { /*maxWidth: blockWidth,*/ rows: [
                    { id: "rcitm_SoundsFilesCustom", head: 9, hidden: hideState, rows: [
                        { template: mcLang(1694), borderless: true, autoheight: true}, // "1694":"Настройка файлов звуковых сигналов",
                        { padding: 2, rows: [
                            { view: "scrollview", height: 300, body: { padding: 7, rows: [
                                { id: "rcitm_SoundsSndNewMsgFile", head: 9, view: "text", label: mcService.Lang(1695), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1695":"Файл звука нового сообщения на доске объявлений",
                                { id: "rcitm_SoundsSndBadWordFile", head: 9, view: "text", label: mcService.Lang(1696), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1696":"Файл звука \"плохих слов\" фильтра нецензурных выражений",
                                { id: "rcitm_SoundsSndLeaveFile", head: 9, view: "text", label: mcService.Lang(1697), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1697":"Файл звука пользователей, которые покидают конференцию",
                                { id: "rcitm_SoundsSndJoinFile", head: 9, view: "text", label: mcService.Lang(1698), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1698":"Файл звука пользователей, которые входят в конференцию",
                                { id: "rcitm_SoundsSndChatTypeFile", head: 9, view: "text", label: mcService.Lang(1699), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1699":"Файл звука набора сообщения",
                                { id: "rcitm_SoundsSndChatBSFile", head: 9, view: "text", label: mcService.Lang(1700), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1700":"Файл звука нажатия BS либо Del при наборе сообщения",
                                { id: "rcitm_SoundsSndStatusFile", head: 9, view: "text", label: mcService.Lang(1701), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1701":"Файл звука статусного сообщения",
                                { id: "rcitm_SoundsSndErrorFile", head: 9, view: "text", label: mcService.Lang(1702), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1702":"Файл звука сообщения об ошибке",
                                { id: "rcitm_SoundsSndPrivateFile", head: 9, view: "text", label: mcService.Lang(1703), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1703":"Файл звука входящего приатного сообщения",
                                { id: "rcitm_SoundsSndChatRetFile", head: 9, view: "text", label: mcService.Lang(1704), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1704":"Файл звука нажатия \"Enter\" при отправке сообщеия в чат",
                                { id: "rcitm_SoundsSndSignalFile", head: 9, view: "text", label: mcService.Lang(1705), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1705":"Файл звука \"будильника\" в привате",
                                { id: "rcitm_SoundsSndChatFile", head: 9, view: "text", label: mcService.Lang(1706), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1706":"Файл звука сообщения в текстовой конференции",
                                { id: "rcitm_SoundsSndBroadcastFile", head: 9, view: "text", label: mcService.Lang(1707), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1707":"Файл звука входящего оповещения",
                                { id: "rcitm_SoundsSndScreenShotFile", head: 9, view: "text", label: mcService.Lang(1708), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1708":"Файл звука снятия скриншота",
                                { id: "rcitm_SoundsSndFilesExchangeRequestFile", head: 9, view: "text", label: mcService.Lang(1709), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1709":"Файл звука запроса на передачу файлов",
                                { id: "rcitm_SoundsSndFilesExchangeDoneFile", head: 9, view: "text", label: mcService.Lang(1710), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1710":"Файл звука окончания передачи файлов",
                                { id: "rcitm_SoundsSndMediaBusyFile", head: 9, view: "text", label: mcService.Lang(1711), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1711":"Файл звука \"занято\" для медиа звонка",
                                { id: "rcitm_SoundsSndMediaCallFile", head: 9, view: "text", label: mcService.Lang(1712), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1712":"Файл звука исходящего медиа звонка",
                                { id: "rcitm_SoundsSndMediaCallRejectFile", head: 9, view: "text", label: mcService.Lang(1713), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1713":"Файл звука отмены входящего медиа звонка",
                                { id: "rcitm_SoundsSndMediaEndCallFile", head: 9, view: "text", label: mcService.Lang(1714), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, //"1714":"Файл звука окончания медиа звонка",
                                { id: "rcitm_SoundsSndMediaIncomingCallFile", head: 9, view: "text", label: mcService.Lang(1715), labelPosition: "top", value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}  //"1715":"Файл звука входящего медиа звонка",
                            ]}}
                        ]}
                    ]}
                ]},
                { gravity: 0}
            ]}
        ]};

        // == "29" : "Сообщения", ==
        var rmctrlHeader10 = { rows: [
            { template: headerList['10'], head: 10, id: "rmctrlHeader10", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
                    { id: "rcitm_SysEventsAutoFillBroadcastUsersList", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1424), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1424":"Заполнять автоматически список людей при создании оповещения",
                    { id: "rcitm_SysEventsShowImagesInChat", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1425), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1425":"Показывать изображения в тексте чата",

                    { id: "rcitm_HRUserMessages", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2109), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2109":"Отделять горизонтальной чертой сообщения одного человека",
                    { id: "rcitm_HRUnreadMessages", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2110), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2110":"Отделять горизонтальной чертой непрочитанные сообщения в чатах",

                    { id: "rcitm_SysEventsImagesThumbsSize", head: 10, view: "select", hidden: hideState, label: mcService.Lang(1822), labelWidth: 300, width: blockWidth, value: "0", options: [ // "1822":"Размер миниатюр изображений в чате",
                        { id: "0", value: mcLang(1823)}, // "1823":"маленькое (120х120)",
                        { id: "1", value: mcLang(1824)}, // "1824":"обычное (150х150)",
                        { id: "2", value: mcLang(1825)}, // "1825":"большое (200х200)",
                        { id: "3", value: mcLang(2067)}  // "2067":"огромные (400х400)",
                    ], on: { onChange: $scope.showApplyPanel}},

                    { id: "rcitm_SysEventsUseMessagesFontLayouts", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1426), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1426":"Использовать шрифтовую разметку сообщений",
                    { id: "rcitm_SysEventsDisableEmotions", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1427), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1427":"Использовать графические смайлики",
                    { id: "rcitm_SysEventsEnableSmileysAnimation", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1428), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1428":"Включить анимацию смайликов",
                    { id: "rcitm_SysEventsAutoreplaceSmileys", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1429), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1429":"Включить автозамену набираемого текста на графические смайлики",
                    { id: "rcitm_SysEventsShowPrivateDeliveryStatuses", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2039), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},  // "2039":"Показывать статусы доставки сообщений",

                    { id: "rcitm_SmartTextSelection", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2108), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},  // "2108":"\"Умное\" выделение текста мышкой, по словам\n",
                    { id: "rcitm_ShowElisaInConfs", head: 10, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2271), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}     // "2271":"Показывать робота в автосоздаваемых конференциях",
                ]},
                {gravity:0}
            ]}
        ]};

        // == "1430":"Системные сообщения", ==
        var rmctrlHeader11 = { rows: [
            { template: headerList['11'], head: 11, id: "rmctrlHeader11", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
                    { id: "rcitm_SysEventsShowSysEvents", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1431), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1431":"Показывать системные сообщения в каналах чата",
                    { id: "rcitm_SysEventsEnterTxtxCh", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1432), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1432":"*** Пользователь вошёл в канал",
                    { id: "rcitm_SysEventsLeaveTxtxCh", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1433), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1433":"*** Пользователь вышел из канала",
                    { id: "rcitm_SysEventsQuitChat", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1434), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1434":"*** Пользователь отключился от сервера",
                    { id: "rcitm_SysEventsChangeTheme", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1435), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1435":"*** Пользователь установил новую тему канала",
                    { id: "rcitm_SysEventsBanUser", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1436), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1436":"*** Пользователь наказал пользователя",
                    { id: "rcitm_SysEventsTurnOut", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1437), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1437":"*** Пользователь выгнал пользователя из канала",
                    { id: "rcitm_SysEventsIgnore", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1438), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1438":"*** Пользователь проигнорировал ваше сообщение",
                    { id: "rcitm_SysEventsConnectionLost", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1439), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1439":"*** Произошел обрыв связи, вы отключены от сервера",
                    { id: "rcitm_SysEventsConnectionRestored", head: 11, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1440), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}} // "1440":"*** Связь восстановлена",
                ]},
                {gravity:0}
            ]}
        ]};

        // == "598": "Протоколирование", ==
        var rmctrlHeader12 = { rows: [
            { template: headerList['12'], head: 12, id: "rmctrlHeader12", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
                    { id: "rcitm_LogsServer", head: 12, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1442), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1442":"Лог соединения с MyChat сервером",
                    { id: "rcitm_LogsFTP", head: 12, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2240), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2240":"Лог FTP",
                    { id: "rcitm_LogsTxtChannels", head: 12, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1444), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1444":"Текстовые каналы",
                    { id: "rcitm_LogsPrivates", head: 12, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1441), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}} // "1441":"Cообщения в приватах",
                ]},
                {gravity:0}
            ]}
        ]};

        // == "1445":"Автоматическая загрузка истории сообщений в окно", ==
        var rmctrlHeader13 = { rows: [
            { template: headerList['13'], head: 13, id: "rmctrlHeader13", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
            // { id: "rcitm_57", head: 13, hidden: hideState, rows: [
                /*{ cols: [
                    { id: "rcitm_SysEventsLoadHistoryType", head: 13, view: "radio", value: "0", vertical: true, width: 280, label: mcService.Lang(1449), labelPosition: "top", css: "finger", height: 70, options:[ // "1449":"Варианты загрузки истории сообщений",
                        { id: "0", value: mcService.Lang(1446)}, // "1446":"Не загружать историю сообщений",
                        { id: "1", value: mcService.Lang(1447)} // "1447":"Загружать последние N сообщений",

                    ], on: { onChange: $scope.showApplyPanel}},
                    { rows: [
                        { height: 42 },
                        { cols: [
                            { id: "rcitm_SysEventsHistory_1_Num", head: 13, view: "counter", value: 10, step: 1, min: 1, max: 999, width: 100, on: { onChange: $scope.showApplyPanel}},
                            { template: mcService.Lang(1450), borderless: true} // "1450":"сообщений",
                        ]}
                    ]}
                ]},*/
                // { cols: [
                //     { width: 30},
                    { id: "rcitm_LoadHistoryToConf", head: 13, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1880), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1880":"Загружать историю в конференции",
                // ]},
                // { cols: [
                //     { width: 30},
                    { id: "rcitm_LoadHistoryToPrivate", head: 13, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1881), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}} // "1881":"Загружать историю в приваты",
                // ]},
            // ]}
                    ]},
                {gravity:0}
            ]}
        ]};

        // == "838":"Файлы", ==
        var rmctrlHeader15 = { rows: [
            { template: headerList['15'], head: 15, id: "rmctrlHeader15", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
                    // { id: "rcitm_AutoLoadBroadcastFiles", head: 15, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1910), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1910":"Автоматически скачивать приложенные файлы из оповещений",
                    { id: "rcitm_SendFilesSayYes", head: 15, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1452), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1452":"Принимать файлы от пользователей из списка контактов, не задавая вопросов",
                    //{ id: "rcitm_SendFilesRenameRecievedDuplicates", head: 15, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1453), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1453":"Переименовывать файлы-дубликаты при приеме, не перезаписывая поверху",
                    { id: "rcitm_63", head: 15, hidden: hideState, cols: [
                            { id: "rcitm_SendFilesRandomPorts", head: 15, view: "radio", value: "1", vertical: true, width: 200, label: mcService.Lang(1454), labelPosition: "top", css: "finger", height: 70, options:[ // "1454":"Порты для передачи файлов",
                                    { id: "0", value: mcService.Lang(1455)}, // "1455":"Фиксированные",
                                    { id: "1", value: mcService.Lang(1456)}  // "1456":"Случайные, из диапазона",
                                ], on: { onChange: $scope.showApplyPanel}},
                            { rows: [
                                    { height: 13},
                                    { cols: [
                                            //{ width: 24},
                                            { id: "rcitm_SendFilesBasePort", head: 15, view: "counter", value: 10, step: 1, min: 1, max: 65000, width: 130, labelWidth: 30, label: "&nbsp;", on: { onChange: $scope.showApplyPanel}},
                                            { id: "rcitm_SendFilesDataPort", head: 15, view: "counter", value: 10, step: 1, min: 1, max: 65000, width: 130, labelWidth: 30, label: "&nbsp;", on: { onChange: $scope.showApplyPanel}},
                                            {}
                                        ]},
                                    { cols: [
                                            { id: "rcitm_SendFilesRandomPortStart", head: 15, view: "counter", value: 10, label: mcService.Lang(1339), labelWidth: 30, step: 1, min: 1, max: 65000, width: 130, on: { onChange: $scope.showApplyPanel}}, // "1339":"от",
                                            { id: "rcitm_SendFilesRandomPortEnd", head: 15, view: "counter", value: 10, label: mcService.Lang(634),  labelWidth: 30, step: 1, min: 1, max: 65000, width: 130, on: { onChange: $scope.showApplyPanel} }, // "634": "до",
                                            {}
                                        ]}
                                ]},
                            {gravity: 0}
                        ]},

                    { cols: [
                            {rows: [
                                { id: "rcitm_SendFilesInputFilesDir", head: 15, hidden: hideState, view: "text", value: "", label: mcService.Lang(1457), labelPosition: "top", on: { onTimedKeyPress: $scope.showApplyPanel}} // "1457":"Сохранять файлы, которые присылают пользователи, в:",
                            ]}
                        ]},

                    { id: "rcitm_SendFilesRememberSelectInputFilesFolder", head: 15, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1460), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1460":"Запомнить выбранную папку для каждого пользователя",

                    {cols:[
                            {rows:[
                                { id: "rcitm_SendFilesBufferSize", head: 15, view: "select", hidden: hideState, label: mcService.Lang(1459), labelWidth: 120, width: 235, value: "1", options: [ // "1459":"Размер буфера:",
                                        { id: "0", value: "8 KB"},
                                        { id: "1", value: "16 KB"},
                                        { id: "2", value: "32 KB"},
                                        { id: "3", value: "64 KB"},
                                        { id: "4", value: "128 KB"},
                                        { id: "5", value: "256 KB"},
                                        { id: "6", value: "512 KB"}
                                    ], on: { onChange: $scope.showApplyPanel}}
                            ]},
                            {gravity: 0}
                    ]}
                ]}
            ]}
        ]};

        // == "1461":"Интерфейс клиаента чата", ==
        var rmctrlHeader16 = { rows: [
            { template: headerList['16'], head: 16, id: "rmctrlHeader16", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
                    { id: "rcitm_InterfaceExtRightPanelVisible", head: 16, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2212), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2212":"Показывать информационную панель о пользователе/конференции (Ctrl + /)",
                    { id: "rcitm_LanguagesLanguage", head: 16, view: "select", hidden: hideState, label: mcService.Lang(6), labelWidth: 300, width: blockWidth, value: "russian.ini", options: [ // "6"  : "Язык интерфейса",
                        { id: "russian.ini",   value: "Русский"},
                        { id: "ukrainian.ini", value: "Українська"},
                        { id: "english.ini",   value: "English"},
                        { id: "polish.ini",    value: "Polski"}
                    ], on: { onChange: $scope.showApplyPanel}},
                    // { id: "rcitm_SmileysSmileysSet", head: 16, view: "select", hidden: hideState, label: mcService.Lang(1693), labelWidth: 300, width: 500, value: "classic", options: [ // "1693":"Название используемого набора смайлов",
                    //         { id: "classic", value: "classic"},
                    //         { id: "extended",value: "extended"},
                    //         { id: "newyear", value: "newyear"},
                    //         { id: "skype",   value: "skype"},
                    //         { id: "static",  value: "static"}
                    //     ], on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_InterfaceTrayIconListNumber",  head: 16, view: "select", hidden: hideState, label: mcService.Lang(1826), labelWidth: 300, width: blockWidth, value: "classic", options: [ // "1826":"Иконка в трее",
                            { id: "0", value: mcLang(1827)}, // "1827":"Стандартная",
                            { id: "1", value: mcLang(1828)}, // "1828":"Вариант 2",
                            { id: "2", value: mcLang(1829)}  // "1829":"Вариант 3",
                        ], on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_InterfaceCommonBackground",    head: 16, view: "select", hidden: hideState, label: mcService.Lang(1830), labelWidth: 300, width: blockWidth, value: "classic", options: [ // "1830":"Фон для конференций и приватов",
                            { id: "-", value: mcLang(1831)}, // "1831":"не установлен",
                            { id: "gradient1.bmp", value: "gradient1.bmp"}, // "1828":"Вариант 2",
                            { id: "gradient2.bmp", value: "gradient2.bmp"}  // "1829":"Вариант 3",
                        ], on: { onChange: $scope.showApplyPanel}},
                    { id: "rcitm_InterfaceBackgroundPlacement", head: 16, view: "select", hidden: hideState, label: mcService.Lang(1832), labelWidth: 300, width: blockWidth, value: "classic", options: [ // "1832":"Расположение фона",
                            { id: "0", value: mcLang(1833)}, // "1833":"По центру",
                            { id: "1", value: mcLang(1834)}, // "1834":"Замостить",
                            { id: "2", value: mcLang(1835)}  // "1835":"Растянуть",
                        ], on: { onChange: $scope.showApplyPanel}}
                ]},
                {gravity:0}
            ]}
        ]};

        // == "1464":"Обновления", ==
        var rmctrlHeader17 = { rows: [
            { template: headerList['17'], head: 17, id: "rmctrlHeader17", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                {rows:[
                    { id: "rcitm_GeneralDailyUpdatesCheck", head: 17, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1465), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "1465":"Еженедельно проверять наличие новой верии MyChat",

                    /*{ id: "rcitm_71", head: 17, hidden: hideState, rows: [
                        { id: "rcitm_UpdateUseAccountForUpdates", head: 17, view: "radio", value: "1", vertical: true, width: 300, label: mcService.Lang(1469), labelPosition: "top", css: "finger", height: 70, options:[ // "1469":"Способ обновления",
                            { id: "0", value: mcService.Lang(1466)}, // "1466":"Обновлять под текущей учетной записью",
                            { id: "1", value: mcService.Lang(1467)}  // "1467":"Указать учетную запись для обновления",
                        ], on: { onChange: $scope.showApplyPanel}},

                        { id: "rcitm_UpdateUpdateDomain",   head: 17, view: "text", /!*hidden: hideState,*!/ label: mcService.Lang(123), labelWidth: 120, width: 300, on: { onTimedKeyPress: $scope.showApplyPanel}}, // "123": "Имя домена",
                        { id: "rcitm_UpdateUpdateLogin",    head: 17, view: "text", /!*hidden: hideState,*!/ label: mcService.Lang(1), labelWidth: 120, width: 300, on: { onTimedKeyPress: $scope.showApplyPanel}}, // "1"  : "Логин",
                        { id: "rcitm_UpdateUpdatePassword", head: 17, view: "text", /!*hidden: hideState,*!/ type: "password", label: mcService.Lang(2), labelWidth: 120, width: 300, on: { onTimedKeyPress: $scope.showApplyPanel}}, // "2"  : "Пароль",
                    ]},*/

                    { id: "rcitm_UpdateSilentMode", head: 17, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(2068), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}}, // "2068":"\"Тихий\" режим, не показывать окно скачивания пакета обновления",
                    // { id: "rcitm_UpdateForceUpdateFromMyChatServerInActiveDirectory", head: 17, view: "checkbox", hidden: hideState, labelRight: mcService.Lang(1468), labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}} // "1468":"При работе в Active Directory принудительно обновляться через MyChat Server",
                ]},
                {gravity:0}
            ]}
        ]};

        // == "574":"Дополнительно", ==
        var rmctrlHeader18 = { rows: [
            { template: headerList['18'], head: 18, id: "rmctrlHeader18", hidden: true, css: "webixBGBlue", height: 26},

            { cols: [
                { maxWidth: blockWidth, rows: [
                    { id: "rcitm_AdditionalPrivateInfoFields", head: 18, view: "text", hidden: hideState, label: mcService.Lang(1470), labelPosition: "top", value: "", on: { onTimedKeyPress: $scope.showApplyPanel}}, // "1470":"Список информационных полей, которые показываются в приватном чате",
                    { id: "rcitm_AdditionalProgramCaption", head: 18, view: "text", hidden: hideState, label: mcService.Lang(1471), labelPosition: "top", value: "", on: { onTimedKeyPress: $scope.showApplyPanel}}, // "1471":"Заголовок программы",
                    { id: "rcitm_AdditionalSystemTrayText", head: 18, view: "textarea", hidden: hideState, label: mcService.Lang(1472), labelPosition: "top", value: "", height: 85, css: "fixTextarea", on: { onTimedKeyPress: $scope.showApplyPanel}},  // "1472":"Хинт в системном лотке (трее)",
                    { id: "rcitm_AdditionalExtOptions", head: 18, view: "textarea", hidden: hideState, label: mcService.Lang(2041), labelPosition: "top", value: "", height: 120, css: "fixTextarea", on: { onTimedKeyPress: $scope.showApplyPanel}}  // "2041":"Расширенные настройки",
                ]},
                { gravity: 0}
            ]}
        ]};

        // == "1851":"Звонки", ==
        var rmctrlHeader19 = { rows: [
            { template: headerList['19'], head: 19, id: "rmctrlHeader19", hidden: true, css: "webixBGBlue", height: 26},

            {cols: [
                    {rows:[
                            // { id: "rcitm_Transport", head: 19, hidden: hideState,  cols: [
                            //     { template: mcLang(1852), borderless: true, autoheight: true, width: 200}, // "1852":"Сетевой транспорт",
                            //     { id: "rcitm_MediaNetworkTransportTCP", head: 19, view: "checkbox", width: 60, labelRight: "TCP", labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            //     { id: "rcitm_MediaNetworkTransportUDP", head: 19, view: "checkbox", width: 60, labelRight: "UDP", labelWidth: 0, value: "", css: "finger", on: { onChange: $scope.showApplyPanel}},
                            //     {}
                            // ]},

                            { id: "rcitm_IceTransportPolicy", head: 19, view: "select", hidden: hideState, label: mcService.Lang(1856), labelWidth: 200, width: blockWidth, value: "classic", options: [ //  "1856":"Метод связи",
                                    { id: "relay", value: mcLang(1854)}, // "1854":"Через сервер",
                                    { id: "all",   value: mcLang(1855)}  // "1855":"Напрямую и через сервер",
                                ], on: { onChange: $scope.showApplyPanel}}
                        ]},
                    {gravity:0}
                ]}
        ]};

        //================= VIEW ==========================================================

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { type: "header", template: mcService.Lang(1688)}, // "1688":"Наборы настроек клиентов",
                    { cols: [
                        { type: "header", template: mcService.Lang(1332)},  // "1332":"Доступны настройки:",
                        { view: "toolbar", width: 36, cols: [
                            {view: "button", type: "icon", icon: "question", click: function () {
                                mcService.goToHelp();
                            }, width: 30}
                        ]}
                    ]}
                ]},

                { id: "rcEmptyPresetList", type: "layout", height: 40, padding: 4, rows: [
                    { cols: [
                        { view: "button", value: mcLang(1689), width: 250, click: $scope.addPreset}, // "1689":"Добавить набор настроек",
                        {}
                    ]}
                ]},

                { id: "rcPresetWrapper", type: "layout", hidden: true, cols: [
                    { minWidth: 200, rows: [ // факинг шыт, список всех возможных настроек клиента
                        { view: "layout", height: 32, cols: [
                            { id: "rcPresetList", view: "richselect", gravity: 3, value: '-1', options: [], on: {
                                onChange: $scope.selectPresetList
                            }},

                            { id: "rcAddPresetList",  view: "button", value: mcService.Lang(50),  click: $scope.addPreset, css: "applyButton"}, // "50" : "Добавить",
                            { id: "rcDelPresetList",  view: "button", value: mcService.Lang(52),  click: $scope.delPreset, type: "danger"}, // "52" : "Удалить",
                            { width: 7}
                        ]},

                        { view: "scrollview", borderless: true, body: { padding: 7, rows: [
                            { id: "emptySetConfig", hidden: false, padding: 7, rows: [
                                { template: mcService.Lang(1337), css: "emptySetConfig", autoheight: true} // "1337":"Список настроек пуст. Выберите необходимые для отправки настройки из списка \"Доступных Настроек\", справа",
                            ]},

                            rmctrlHeader1, rmctrlHeader2, rmctrlHeader3, rmctrlHeader4, rmctrlHeader5, rmctrlHeader6, rmctrlHeader7,
                            rmctrlHeader8, rmctrlHeader9, rmctrlHeader10, rmctrlHeader11, rmctrlHeader12, rmctrlHeader13,
                            rmctrlHeader15, rmctrlHeader16, rmctrlHeader17, rmctrlHeader18, rmctrlHeader19
                        ]}}
                    ]},

                    { view: "resizer" },

                    { rows: [
                        { height: 4 },

                        new mcService.FilterFiled({
                            listName : "allConfigurationList",
                            onClear  :  function(){
                                var list = [];

                                for (var i in $scope.selectionState){
                                    if ($scope.selectionState[i]) {
                                        list.push(i);
                                    }
                                }

                                if (list.length > 0 ){
                                    $scope.allConfigurationList.select(list, true);
                                }
                            }
                        }),

                        { view: "unitlist", id: "allConfigurationList", data: $scope.allOptionsSet, multiselect: "touch", select: true,
                            tooltip:{
                                template: "#value#",
                                dx: -10,
                                dy: 20
                            },
                            uniteBy: function(obj){
                                return headerList[obj.head] || 'No set';
                            },
                            on: {
                                onBeforeSelect: $scope.showHideItems,
                                onBeforeUnSelect: $scope.showHideItems,
                                onItemClick: $scope.selectPresetItem
                            }, onContext:{}
                        }
                    ]}
                ]}
            ]
        });

        $scope.PresetWrapper         = $$("rcPresetWrapper");
        $scope.emptySetConfig        = $$("emptySetConfig");

        $scope.rcPresetList          = $$("rcPresetList");
        $scope.rcAddPresetList       = $$("rcAddPresetList");
        $scope.rcDelPresetList       = $$("rcDelPresetList");

        $scope.allConfigurationList  = $$("allConfigurationList");
        $scope.rcEmptyPresetList     = $$("rcEmptyPresetList");

        new mcService.ContextMenu($scope.allConfigurationList, null, $scope.contextMenuActions, function(){
            $scope.regShowWindow(this.config.id, this);
        });

        mcService.disableContextMenu(_view);
    } else {

    }

    return _view;
}


"use strict";

function presetManagerController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.PresetManager;
    $scope.allUserList    = null;
    $scope.selectionState = {};

    var angElement       = document.getElementById($scope.Name);
    var serverPresetList = [];
    var selectedSetItems = {}; // '1' : 2 // номер хидера : количество включенных
    var canChange        = false;
    var canChangeCount   = 0;
    var nanPresent       = 0;
    var nanList          = {};
    var clearPresetList  = true;
    var defaultPreset    = null;

    var itemList = [
        "NetworkReconnectTime",
        "NetworkSecured",
        "NetworkProxyType","NetworkProxyHost","NetworkProxyPort",
        "NetworkProxyAuth","NetworkProxyUserName","NetworkProxyUserPass","GeneralWindowsStart","GeneralConfirmExit",
        "GeneralStartPassword","GeneralDailyUpdatesCheck","GeneralFadeWindows",
        "GeneralMainWindow",
        "GeneralShowSendButton","GeneralCtrlEnterSend",
        "GeneralQuickMsgAutoSend","GeneralSpellCheck","GeneralAutoHideMainWindow",
        "EventsShowPopupTrayWindow","EventsPopupOnNewBBS","EventsPopupOnChannelMessage","EventsPopupOnPrivateMessage",
        "EventsTrayBBSMsg","EventsTrayChMsg","EventsTrayPvMsg",
        "EventsTrayDontHide","EventsTrayWindowDuration","HotKeysHotKeyMyChat",
        "HotKeysHotKeyMyChatScreenShot","HotKeysUseGlobalHotKeys","HotKeysEscHide","SoundsAllSoundsOff",
        "SoundsSndNewMsg","SoundsSndBadWord","SoundsSndLeave","SoundsSndJoin","SoundsSndChatType","SoundsSndChatBS",
        "SoundsSndStatus","SoundsSndError","SoundsSndPrivate","SoundsSndChatRet","SoundsSndSignal","SoundsSndChat",
        "SoundsSndBroadcast","SoundsSndFilesExchangeRequest","SoundsSndFilesExchangeDone","SoundsSndScreenShot",
        "SoundsSndMediaBusy","SoundsSndMediaCall","SoundsSndMediaCallReject","SoundsSndMediaEndCall",
        "SoundsSndMediaIncomingCall","SoundsSndNewMsgFile","SoundsSndBadWordFile","SoundsSndLeaveFile","SoundsSndJoinFile",
        "SoundsSndChatTypeFile","SoundsSndChatBSFile","SoundsSndStatusFile","SoundsSndErrorFile","SoundsSndPrivateFile",
        "SoundsSndChatRetFile","SoundsSndSignalFile","SoundsSndChatFile","SoundsSndBroadcastFile","SoundsSndScreenShotFile",
        "SoundsSndFilesExchangeRequestFile","SoundsSndFilesExchangeDoneFile","SoundsSndMediaBusyFile","SoundsSndMediaCallFile",
        "SoundsSndMediaCallRejectFile","SoundsSndMediaEndCallFile","SoundsSndMediaIncomingCallFile",

        // "GeneralTipOfTheDayNum","GeneralShowTipOfTheDay", /*"GeneralDisableAvatars",*/
        /*"GeneralOpenPrivateByOneClick",*/ /*"GeneralDoubleClickPagesClose",*/ /*"GeneralShowUsersCounterOnTheTabs",*/ //"GeneralShowMainToolsPanel",
        // "SmileysSmileysSet", "EventsTimeStamp", /*"SendFilesRenameRecievedDuplicates",*/
        // "EventsDateTimeStampFormat", "SysEventsShowSysEvents", "SysEventsEnterTxtxCh","SysEventsLeaveTxtxCh","SysEventsQuitChat","SysEventsChangeTheme","SysEventsBanUser",
        // "SysEventsTurnOut","SysEventsIgnore","SysEventsConnectionLost","SysEventsConnectionRestored",
        // "SysEventsLoadHistoryType","SysEventsHistory_1_Num", /*"SpecialToolsPanelType","SpecialPagesPanel",*/

        "SysEventsEnableSmileysAnimation","SysEventsAutoreplaceSmileys",
        "SysEventsShowPrivateDeliveryStatuses", "SysEventsDisableEmotions", "SysEventsUseMessagesFontLayouts",
        "LogsServer","LogsTxtChannels", "LogsPrivates","LogsFTP",
        "SecurityOptionsPassword","LanguagesLanguage","SendFilesInputFilesDir","SendFilesBasePort","SendFilesDataPort",
        "SendFilesBufferSize","SendFilesSayYes","SendFilesRememberSelectInputFilesFolder","SendFilesRandomPorts",
        "SendFilesRandomPortStart","SendFilesRandomPortEnd","Colorscolor_ch_pv_back",
        "Colorscolor_inp_back","Colorscolor_userslist_back","Colorscolor_userslist_text","Colorscolor_own_nick_text",
        "Colorscolor_active_link","Colorscolor_visited_link","Colorscolor_timestamp","Colorscolor_hello_nick",
        "Colorscolor_users_nick_text","UpdateUseAccountForUpdates",/*"UpdateUpdateLogin","UpdateUpdatePassword",*/
        /*"UpdateUpdateDomain","UpdateForceUpdateFromMyChatServerInActiveDirectory",*/"SpecialMessagesFontSize",
        "AdditionalPrivateInfoFields","AdditionalProgramCaption",
        "AdditionalSystemTrayText","InterfaceTrayIconListNumber","SysEventsAutoFillBroadcastUsersList",
        "SysEventsShowImagesInChat", "GeneralRememberOpenContactGroups", "SysEventsImagesThumbsSize", "InterfaceTrayIconListNumber",
        "InterfaceCommonBackground", "InterfaceBackgroundPlacement", "EventsTrayBlinkOnTaskBar",
        // "MediaNetworkTransportTCP", "MediaNetworkTransportUDP",
        "IceTransportPolicy", "LoadHistoryToConf", "LoadHistoryToPrivate", // "AutoLoadBroadcastFiles",
        "EventsAutoOpenIncomingMessage", "AdditionalExtOptions", "HotKeyVoiceCall", "HotKeyVideoCall", "HotKeyMaximizeMainForm",
        "HotKeyVoiceCallWithScreenShare", "UpdateSilentMode",
        "InputFieldSize", "SmartTextSelection", "HRUserMessages", "HRUnreadMessages", "CloseDialogsByDoubleClick", "CloseDialogsByMiddleClick",
        "InterfaceExtRightPanelVisible", "ShowElisaInConfs"
    ];

    var conformity = {
        "NetworkProxyPort" : {
            set : function(val){
                selectSettingsItem("NetworkProxyPort");

                $$("sub_NetworkProxyPort").setValue(val);
            },
            get : function(){
                return $$("rcitm_NetworkProxyPort").config.hidden ? null : $$("sub_NetworkProxyPort").getValue();
            }
        },
        "EventsTrayDontHide" : {
            set : function(val){
                selectSettingsItem("EventsTrayDontHide");

                $$("sub1_EventsTrayDontHide").setValue(mcService.convertBool(val));
            },
            get : function(){
                return $$("rcitm_EventsTrayDontHide").config.hidden ? null : mcService.convertIntToBool($$("sub1_EventsTrayDontHide").getValue());
            }
        },
        "EventsTrayWindowDuration" : {
            set : function(val){
                selectSettingsItem("EventsTrayDontHide");

                $$("sub2_EventsTrayDontHide").setValue(val);
            },
            get : function(){
                return $$("rcitm_EventsTrayDontHide").config.hidden ? null : $$("sub2_EventsTrayDontHide").getValue();
            }
        },
        "HotKeysHotKeyMyChat" : {
            set : function(val){
                setHotKey("HotKeysHotKeyMyChat", val);
            },
            get : function(){
                return getHotKey("HotKeysHotKeyMyChat");
            }
        },
        "HotKeyVoiceCall" : {
            set : function(val){
                setHotKey("HotKeyVoiceCall", val);
            },
            get : function(){
                return getHotKey("HotKeyVoiceCall");
            }
        },
        "HotKeyVideoCall" : {
            set : function(val){
                setHotKey("HotKeyVideoCall", val);
            },
            get : function(){
                return getHotKey("HotKeyVideoCall");
            }
        },
        "HotKeyMaximizeMainForm" : {
            set : function(val){
                setHotKey("HotKeyMaximizeMainForm", val);
            },
            get : function(){
                return getHotKey("HotKeyMaximizeMainForm");
            }
        },
        "HotKeyVoiceCallWithScreenShare" : {
            set : function(val){
                setHotKey("HotKeyVoiceCallWithScreenShare", val);
            },
            get : function(){
                return getHotKey("HotKeyVoiceCallWithScreenShare");
            }
        },
        "HotKeysHotKeyMyChatScreenShot" : {
            set : function(val){
                setHotKey("HotKeysHotKeyMyChatScreenShot", val);


            },
            get : function(){
                return getHotKey("HotKeysHotKeyMyChatScreenShot");
            }
        },
        "SoundsAllSoundsOff" : {
            set : function(val){
                selectSettingsItem("SoundsAllSoundsOff");

                $$("sub_SoundsAllSoundsOff").setValue(mcService.convertBool(val));
            },
            get : function(){
                return $$("rcitm_SoundsAllSoundsOff").config.hidden ? null : mcService.convertIntToBool($$("sub_SoundsAllSoundsOff").getValue());
            }
        },
        "SendFilesRandomPorts" : {
            set : function(val){
                $$("rcitm_SendFilesRandomPorts").setValue(mcService.convertBool(val));


            },
            get : function(){
                return $$("rcitm_63").config.hidden ? null : mcService.convertIntToBool($$("rcitm_SendFilesRandomPorts").getValue());
            }
        },
        // "UpdateUseAccountForUpdates" : {
        //     set : function(val){
        //         selectSettingsItem("71");
        //
        //         $$("rcitm_UpdateUseAccountForUpdates").setValue(mcService.convertBool(val));
        //     },
        //     get : function(){
        //         return $$("rcitm_71").config.hidden ? null : mcService.convertIntToBool($$("rcitm_UpdateUseAccountForUpdates").getValue());
        //     }
        // },
        // "NetworkReconnectTime" : {
        //     set : function(val){
        //         selectSettingsItem("NetworkReconnectTime");
        //
        //         $$("sub_NetworkReconnectTime").setValue(mcService.convertBool(val));
        //     },
        //     get : function(){
        //         return $$("rcitm_NetworkReconnectTime").config.hidden ? null : $$("sub_NetworkReconnectTime").getValue();
        //     }
        // }
    };

    ["SendFilesBasePort","SendFilesDataPort","SendFilesRandomPortStart","SendFilesRandomPortEnd"].forEach(function(elem){
        conformity[elem] = {
            set : function(val){
                selectSettingsItem("63");

                $$("rcitm_" + elem).setValue(mcService.convertBool(val));
            },
            get : function(){
                return $$("rcitm_63").config.hidden ? null : $$("rcitm_" + elem).getValue();
            }
        }
    });

    // ["SysEventsLoadHistoryType", "SysEventsHistory_1_Num"].forEach(function(elem){
    //     conformity[elem] = {
    //         set : function(val){
    //             selectSettingsItem("57");
    //
    //             $$("rcitm_" + elem).setValue(mcService.convertBool(val));
    //         },
    //         get : function(){
    //             return $$("rcitm_57").config.hidden ? null : $$("rcitm_" + elem).getValue();
    //         }
    //     };
    // });

    // ["LoadHistoryToConf", "LoadHistoryToPrivate"].forEach(function(elem){
    //     conformity[elem] = {
    //         set : function(val){
    //             selectSettingsItem("57");
    //
    //             $$("rcitm_" + elem).setValue(mcService.convertBool(val));
    //         },
    //         get : function(){
    //             return $$("rcitm_57").config.hidden ? null : mcService.convertIntToBool($$("rcitm_" + elem).getValue());
    //         }
    //     };
    // });

    // ["MediaNetworkTransportTCP", "MediaNetworkTransportUDP"].forEach(function(elem){
    //     conformity[elem] = {
    //         set : function(val){
    //             selectSettingsItem("Transport");
    //
    //             $$("rcitm_" + elem).setValue(mcService.convertBool(val));
    //         },
    //         get : function(){
    //             return $$("rcitm_Transport").config.hidden ? null : $$("rcitm_" + elem).getValue();
    //         }
    //     };
    // });

    ["SoundsSndError","SoundsSndJoin","SoundsSndLeave","SoundsSndChat","SoundsSndStatus","SoundsSndSignal",
    "SoundsSndChatType","SoundsSndChatBS","SoundsSndChatRet","SoundsSndNewMsg","SoundsSndPrivate",
    "SoundsSndBadWord","SoundsSndBroadcast","SoundsSndScreenShot","SoundsSndFilesExchangeRequest",
    "SoundsSndFilesExchangeDone","SoundsSndMediaCall","SoundsSndMediaBusy","SoundsSndMediaCallReject",
    "SoundsSndMediaIncomingCall","SoundsSndMediaEndCall"].forEach(function(elem){
        conformity[elem] = {
            set : function(val){
                selectSettingsItem("SoundsAllSoundsOffCustom");

                $$("rcitm_" + elem).setValue(mcService.convertBool(val));
            },
            get : function(){
                return $$("rcitm_SoundsAllSoundsOffCustom").config.hidden ? null : mcService.convertIntToBool($$("rcitm_" + elem).getValue());
            }
        };
    });

    ["SoundsSndNewMsgFile","SoundsSndBadWordFile","SoundsSndLeaveFile","SoundsSndJoinFile","SoundsSndChatTypeFile",
    "SoundsSndChatBSFile","SoundsSndStatusFile","SoundsSndErrorFile","SoundsSndPrivateFile","SoundsSndChatRetFile",
    "SoundsSndSignalFile","SoundsSndChatFile","SoundsSndBroadcastFile","SoundsSndScreenShotFile",
    "SoundsSndFilesExchangeRequestFile","SoundsSndFilesExchangeDoneFile","SoundsSndMediaBusyFile","SoundsSndMediaCallFile",
    "SoundsSndMediaCallRejectFile","SoundsSndMediaEndCallFile","SoundsSndMediaIncomingCallFile"].forEach(function(elem){
        conformity[elem] = {
            set : function(val){
                selectSettingsItem("SoundsFilesCustom");

                $$("rcitm_" + elem).setValue(val);
            },
            get : function(){
                return $$("rcitm_SoundsFilesCustom").config.hidden ? null : $$("rcitm_" + elem).getValue();
            }
        };
    });

    // ===============================================================

    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        onApply : function(){
            if (nanPresent === 0){
                clearChangedData();

                $scope.savePreset();
            } else {
                webix.alert(mcLang(1691)); // "1691":"Нельзя сохранять, пока есть ошибка в настройках!",

                return false;
            }
        },
        onClose : function(){
            $scope.selectPresetList($scope.rcPresetList.getValue());

            clearChangedData();
        }
    };

    function clearChangedData (){
        $scope.changedData.data.Items    = {};
        $scope.changedData.data.Desc     = "";

        $scope.rcPresetList   .enable();
        $scope.rcAddPresetList.enable();
        $scope.rcDelPresetList.enable();

        for (var i in nanList){
            nanList[i].getNode().className = "webix_view webix_control webix_el_counter";
        }

        nanList = {};
    }

    // ===============================================================

    function fillPresetsList(list){
        var presets = mcService.transformDataObject(list, [["Name", "value"], ["ID", "id"]]).sort(function(a, b){
            return mcService.sortAB(parseInt(a.value), parseInt(b.value));
        });

        $scope.rcPresetList.define('options', presets);
        $scope.rcPresetList.refresh();
    }

    function setHotKey(name, val){
        val = val.replace(/\</ig, "").replace(/\>/ig, "").split("+");

        $$("sub_" + name +"_Ctrl").setValue(false);
        $$("sub_" + name +"_Alt").setValue(false);
        $$("sub_" + name +"_Shift").setValue(false);
        if ($$("sub_" + name +"_Win")) $$("sub_" + name +"_Win").setValue(false);

        for (var i = 0; i < val.length-1; i++){
            $$("sub_" + name + "_" + val[i]).setValue(true);
        }

        $$("sub_" + name + "_key").setValue(val[val.length - 1]);

        selectSettingsItem(name);
    }

    function getHotKey(name){
        return  $$("rcitm_" + name).config.hidden ? null :
                (($$("sub_" + name +"_Win") && $$("sub_" + name + "_Win").getValue()  == 1 ? "Win+" : "") +
                 ($$("sub_" + name + "_Ctrl").getValue() == 1 ? "Ctrl+" : "") +
                 ($$("sub_" + name + "_Alt").getValue()  == 1 ? "Alt+" : "") +
                 ($$("sub_" + name + "_Shift").getValue()== 1 ? "Shift+" : "") +
                  $$("sub_" + name + "_key").getValue());
    }

    function collectionProfileOptions(){
        var res = {};
        var val = null;
        var item = null;
        var element = null;

        for (var i = 0; i < itemList.length; i ++){
            item = itemList[i];
            val  = null;

            if (conformity.hasOwnProperty(item)){
                val = conformity[item].get();

                if (val !== null) {
                    res[item] = val;
                }
            } else {
                element = $$("rcitm_" + item);

                if (element && !element.config.hidden){
                    if (element.config.view === "checkbox") {
                        res[item] = mcService.convertIntToBool(element.getValue());
                    } else {
                        res[item] = element.getValue();
                    }
                }
            }
        }

        return res;
    }

    function showOnlyAddButton(){
        $scope.PresetWrapper.hide();
        $scope.rcEmptyPresetList.show();
    }

    function hideOnlyAddButton(){
        $scope.rcEmptyPresetList.hide();
        $scope.PresetWrapper.show();

        $scope._view.adjust();
    }

    function selectSettingsItem(item){
        if (clearPresetList){
            $scope.showHideItems(item, true);
            $scope.allConfigurationList.select(item, true);
        }
    }

    function checkCanChange() {
        if (canChangeCount){
            canChangeCount --;

            if (!canChangeCount){
                canChange = true;
            }
        }
    }
    // ==================================================

    $scope.showApplyPanel = function (newV, oldV){
        // checkCanChange();

        if (canChange){
            if (this.config && this.config.view === 'counter'){
                if (isNaN(newV)){
                    webix.alert(mcLang(1692)); //  "1692":"Поле должно содержать число!",

                    if (!isNaN(oldV)) {
                        nanPresent ++;
                    }

                    this.getNode().className = "webix_view webix_control webix_el_counter bgRed";

                    if (!nanList.hasOwnProperty(this.config.id)){
                        nanList[this.config.id] = this;
                    }

                    return;
                } else
                if (isNaN(oldV)){
                    nanPresent --;

                    this.getNode().className = "webix_view webix_control webix_el_counter";

                    if (nanList.hasOwnProperty(this.config.id)){
                        delete nanList[this.config.id];
                    }
                }

                this.setValue(Math.abs(this.getValue()));
            }

            $scope.changedData.data.ShowDesc = true;

            $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);

            $scope.rcPresetList   .disable();
            $scope.rcAddPresetList.disable();
            $scope.rcDelPresetList.disable();
        }
    };

    $scope.contextMenuActions = function (action){
        switch (action){
            case 'clear':
                $scope.clearAllSettings();
                break;

            case 'selectAll':
                for (var i = 0; i < $scope.allOptionsSet.length; i++){
                    $scope.showHideItems($scope.allOptionsSet[i].id, true);
                }
                break;

            case 'invert':
                var list = $scope.allConfigurationList;

                for (var i = 0; i < $scope.allOptionsSet.length; i++){
                    $scope.showHideItems($scope.allOptionsSet[i].id, list.isSelected($scope.allOptionsSet[i].id));
                }
                break;
        }

        $scope.showApplyPanel();
    };

    $scope.selectPresetItem = function(id, e){
        var shift = e.shiftKey;

        setTimeout(function(){
            var selected = $scope.allConfigurationList.getSelectedId();

            if (mcService.isArray(selected) && shift){
                for (var i = 0; i < selected.length; i++){
                    $scope.showHideItems(selected[i], true);
                }
            }
        }, 20);

        $scope.showApplyPanel();
    };

    $scope.selectPresetList = function(_id, _source){
        if (_id !== -1) {
            var source  = mcService.isArray(_source) ? _source : serverPresetList;
            var id      = mcService.findItemInArrayOfObj(source, _id, "ID");
            var body    = JSON.parse(source[id].Body);
            var element = null;
            var _defaultPreset = JSON.parse(defaultPreset[0].Body);

            if (clearPresetList) {
                $scope.clearAllSettings();
            }

            $rootScope.$broadcast('hide' + mcConst.dataModels.ApplyPanel, []);

            canChange  = false;
            nanPresent = 0;
            canChangeCount = Object.keys(body).length;

            for (var item in _defaultPreset){
            // for (var item in body){
                var hasItem    = body.hasOwnProperty(item);
                var currentVal = hasItem ? body[item] : _defaultPreset[item];

                if (conformity.hasOwnProperty(item)){

                    hasItem && conformity[item].set(currentVal);
                } else {
                    element = $$("rcitm_" + item);

                    if (element){
                        if (hasItem && element.config.hidden && (_source === undefined || !mcService.isArray(_source))){
                            $scope.allConfigurationList.select(item, true);
                        }

                        if (element.config.view === "checkbox") {
                            element.setValue(mcService.convertIntToBool(currentVal));
                        } else {
                            element.setValue(currentVal);
                        }
                    }
                }
            }
            
            canChange       = true;
            clearPresetList = true;
        }
    };

    $scope.addPreset  = function(){
        function save(){
            var name = this.getFormView().getChildViews()[0].getValue();

            if (this.getFormView().validate() && mcService.findItemInArrayOfObj(serverPresetList, name, 'Name') === -1){
                var newBody = clearPresetList ? "{}" : JSON.stringify(collectionProfileOptions());

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_create_client_options_preset,
                    mcConst.SessionID,
                    name,
                    newBody,
                    
                    function(data){
                        serverPresetList.push({
                            "ID"        : data.ID,   // идентификатор шаблона, число
                            "Name"      : name,      // название шаблона
                            "Body"      : newBody,   // содержимое шаблона, JSON объект, формат объекта как в команде sc_apply_client_settings
                            "CRC32"     : data.CRC32,// контрольная сумма шаблона
                            "RolesList" : ""         // список ролей (групп прав), для кого применять шаблон. Если пустой - не применять никому
                        });

                        fillPresetsList(serverPresetList);

                        if (clearPresetList){
                            $scope.selectPresetList(1, defaultPreset);
                        }

                        $scope.rcPresetList.setValue(serverPresetList[serverPresetList.length - 1].ID + "");

                        hideOnlyAddButton();
                    }
                ]);

                wnd.close();
            } else {
                webix.alert(mcLang(1679)); // "1679":"Название настроек не может быть пустыи или совпадать с существующим!",
            }
        }

        var wnd = webix.ui({
            view    : "window",
            position: "center",
            modal   : true,
            width   : 300,
            head    : mcLang(1677), // "1677":"Укажите название шаблона настроек",
            body    : { view: "form", rules: {'_rcPresetName': webix.rules.isNotEmpty}, elements:[
                { view: "text", name: "_rcPresetName" },
                { view: "checkbox", labelRight: mcLang(1717), value : !clearPresetList, labelWidth: 0, css: "finger", on: { // "1717":"Не очищать текущие настройки",
                    onChange: function(newV){
                        clearPresetList = !mcService.convertIntToBool(newV);
                    }
                }},
                { cols: [
                    { view: "button", value: mcLang(13), click: save }, //"13" : "Ок",
                    { view: "button", value: mcLang(103), type: "danger", click: function(){ // "103": "Отмена",
                        wnd.close();
                    }}
                ]}
            ]}, on: {
                onShow: function(){
                    var self = this;
                    this.getChildViews()[1].getChildViews()[0].focus();

                    $rootScope.hotKeyDispatcher.addPreset('addPreset' + $scope.Name, [{
                        key :  mcConst.keyCodes.esc,
                        func: function() {
                            self.close();
                        }
                    }, {
                        key :  mcConst.keyCodes.enter,
                        func: function() {
                            save.apply(self.getChildViews()[1].getChildViews()[0]);
                        }
                    }], document, true);
                },
                onDestruct: function(){
                    $rootScope.hotKeyDispatcher.removePreset('addPreset' + $scope.Name);
                }
            }
        });

        $scope.regShowWindow(mcService.RandomHash(5), wnd);

        wnd.show();
    };

    $scope.savePreset = function(){
        var id   = $scope.rcPresetList.getValue();
        var body = JSON.stringify(collectionProfileOptions());

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_update_client_options_preset,
            mcConst.SessionID,
            id,
            body,
            function(){
                webix.message(mcLang(1683)); // "1683":"Набор настроек изменен",

                serverPresetList[mcService.findItemInArrayOfObj(serverPresetList, id, "ID")].Body = body;

                $rootScope.$broadcast('hide' + mcConst.dataModels.ApplyPanel, []);
            }
        ]);
    };

    $scope.delPreset  = function(){
        var id     = $scope.rcPresetList.getValue();
        var listID = mcService.findItemInArrayOfObj(serverPresetList, id, "ID");

        $scope.regShowWindow(mcService.RandomHash(5), webix.confirm({
            type  : "confirm-warning",
            text  : mcService.Lang(1686, serverPresetList[listID].Name),// "1686":"Удалить набор:\n<b>%s</b>?",
            ok    : mcService.Lang(114), // "114": "да",
            cancel: mcService.Lang(113), // "113": "нет",
            callback: function (yes) {
                if (yes) {
                    $rootScope.$broadcast('SendCMDToServer', [
                        mcConst.lockInterface,
                        mcConst._CMD_.cs_adm_del_client_options_preset,
                        mcConst.SessionID,
                        id,
                        function(){
                            $scope.clearAllSettings();

                            serverPresetList.splice(listID, 1);

                            if (serverPresetList.length == 0){
                                showOnlyAddButton();
                            } else {
                                fillPresetsList(serverPresetList);

                                $scope.rcPresetList.setValue(serverPresetList[0].ID + "");
                            }

                            webix.message(mcLang(1685)); // "1685":"Набор успешно удален",
                        }
                    ]);
                }
            }
        }));
    };

    $scope.clearAllSettings = function(){
        canChange      = false;
        canChangeCount = Object.keys(itemList).length;

        itemList.forEach(function (item) {
            var element = null;

            if (conformity.hasOwnProperty(item)){
                conformity[item].set("");
            } else {
                element = $$("rcitm_" + item);

                if (element){
                    if (element.config.view === "checkbox") {
                        element.setValue(false);
                    } else {
                        element.setValue("");
                    }
                }
            }
        });

        $$("allConfigurationList").unselectAll();

        canChange      = true;
    };

    $scope.showHideItems = function(id, enabled){
        var item   = $$("rcitm_" + id);
        var head   = item.config.head;
        var parent = $$("rmctrlHeader" + head);

        if (item && !item.config.hidden && enabled){
            return;
        }

        if (!selectedSetItems[head]){
            selectedSetItems[head] = 0;
        }

        if (enabled){
            if (item.config.hidden){
                selectedSetItems[head] ++;
            }

            if (!$scope.emptySetConfig.config.hidden){
                $scope.emptySetConfig.hide();
            }

            parent.show();
            item.show();
        } else {
            if (!item.config.hidden && selectedSetItems[head] > 0) {
                selectedSetItems[head] --;
            }

            if (selectedSetItems[head] == 0){
                var res = 0;

                for (var i in selectedSetItems){
                    res += selectedSetItems[i];
                }

                if (res === 0){
                    $scope.emptySetConfig.show();
                }

                parent.hide();
            }

            item.hide();
        }

        $scope.selectionState[id] = enabled;
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_client_options_presets,
            mcConst.SessionID,
            function(presets){ // [ddd dd mmm hh:nn:ss]
                if (presets && presets.length > 0){
                    serverPresetList = presets;

                    defaultPreset = [serverPresetList.shift()];

                    var backupID = $scope.rcPresetList.getValue();

                    fillPresetsList(serverPresetList);

                    var _list = $scope.rcPresetList.getList();

                    if (_list.getItem(backupID)) {
                        $scope.rcPresetList.setValue(-1);
                        $scope.rcPresetList.setValue(backupID);
                    } else
                    if (serverPresetList.length > 0) {
                        $scope.rcPresetList.setValue(-1);
                        $scope.rcPresetList.setValue(serverPresetList[0].ID);

                        hideOnlyAddButton();
                    }
                }

                if ($rootScope.addNewPreset === true){
                    $rootScope.addNewPreset = false;

                    $scope.addPreset();
                }
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        $scope._view = initPresetManager($scope);

        mcService.initResize($scope._view, $scope.Name);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        mcService.getMcSettings($rootScope, function () {
            $scope.isFree = $rootScope.mcStorage.ServerInfo.Free;

            $scope.show.apply(null, args);

            $scope.getData();
        }, true);
    });
}


"use strict";

function initRemoteSettings($scope){
    var _view          = $$($scope.Name);

    if (!_view){
        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(1329)}, // "1329":"Назначение настроек клиентам",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: "layout", padding: 4, cols: [{
                    id           : "rcGroupList" + $scope.Name,
                    view         : "datatable",
                    resizeColumn : true,
                    select       : "row",
                    width        : 650,
                    editable     : true,
                    columns: [
                        { id:"Name",   header: mcLang(144),  css: "grid_area", sort: "string", width: 320}, //"144":"Группа прав",
                        { id:"Preset", header: mcLang(1678), css: "grid_area", editor: "fastselect", fillspace: true, options: [ //"1678":"Название набора настроек",
                            { id: '0', value: mcLang(1658) } // "1658":"-- ничего не выбрано --"
                        ]}
                    ],
                    on: {
                        onEditorChange: $scope.changeGroupPreset
                    }
                },{}]},

                { type: "layout", height: 40, padding: 4, cols: [
                    { id: "rmAddNewPreset", view: "button", value: mcLang(1689), width: 250, click: function() {
                        $scope.gotoPresets(true);
                    }}, // "1689":"Добавить набор настроек",
                    { width: 10},
                    { id: "rmGoToPresets", view: "button", value: mcLang(1690), click: $scope.gotoPresets, css: "trBG webixBlue", width: 395}, // "1690":"Перейти в раздел редактирования настроек",
                    {}
                ]}
            ]
        });

        $scope.rmGoToPresets  = $$("rmGoToPresets");
        $scope.rmAddNewPreset = $$("rmAddNewPreset");


        $scope.rcGroupList = $$("rcGroupList" + $scope.Name);

        mcService.disableContextMenu(_view);
    } else {

    }

    return _view;

}

"use strict";

function remoteSettingsController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.RemoteSettings;
    $scope.allUserList    = null;
    $scope.selectionState = {};

    var angElement       = document.getElementById($scope.Name);
    var presetMenuList   = [];
    var groupsAndPreset  = [];
                                        
    // ===============================================================

    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        onApply : function(){
            var data = [];

            Object.keys($scope.changedData.data.Items).forEach(function(key) {
                data.push(key + ":" + $scope.changedData.data.Items[key]);
            });

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_apply_roles_to_options_presets,
                mcConst.SessionID,
                JSON.stringify(data),
                function(){
                    clearChangedData();

                    webix.message(mcService.Lang(1687)); // "1687":"Настройки назначены!",
                }
            ]);
        },
        onClose : function(){
            setTimeout(function(){
                fillGrid(groupsAndPreset);
            }, 100);

            clearChangedData();
        }
    };

    function clearChangedData (){
        $scope.changedData.data.Items    = {};
        $scope.changedData.data.Desc     = "";
        $scope.changedData.data.ShowDesc = false;

        unlockBtns();
    }

    // ============================================================

    function lockBtns(){
        $scope.rmGoToPresets .disable();
        $scope.rmAddNewPreset.disable();
    }

    function unlockBtns(){
        $scope.rmGoToPresets .enable();
        $scope.rmAddNewPreset.enable();
    }

    function fillGrid(presets){
        $scope.rcGroupList.clearAll();
        $scope.rcGroupList.parse(webix.copy(presets));
    }

    function fillGroupListAndMenus(roles, presets){
        var columns = webix.toArray($scope.rcGroupList.config.columns);

        groupsAndPreset = [];

        roles.forEach(function(item){
            groupsAndPreset.push({
                id    : item.ID,
                Name  : item.Name,
                Preset: '0'
            });
        });

        presets.shift(); // remove default preset set

        presets.forEach(function(itemPreset){
            itemPreset.RolesList = itemPreset.RolesList == '' ? [] : itemPreset.RolesList.split(',');

            itemPreset.RolesList.forEach(function(role){
                var id = mcService.findItemInArrayOfObj(groupsAndPreset, role,  "id");

                if (id >= 0){
                    groupsAndPreset[id].Preset = itemPreset.ID;
                }
            });
        });

        fillGrid(groupsAndPreset);

        presetMenuList = [
            { id: '0', value: mcLang(1658) } // "1658":"-- ничего не выбрано --"
        ].concat(mcService.transformDataObject(presets, [["Name", "value"], ["ID", "id"]]).sort(function(a, b){
            return mcService.sortAB(parseInt(a.value), parseInt(b.value));
        }));

        columns[1] = {
            id        : "Preset",
            header    : mcLang(1678),
            css       : "grid_area",
            editor    : "select",
            fillspace : true,
            options   : webix.copy(presetMenuList)
        };

        $scope.rcGroupList.refreshColumns();

    }

    // ==================================================

    $scope.gotoPresets = function(addNew){
        if (addNew === true){
            $rootScope.addNewPreset = true;
        }

        $rootScope.$broadcast('setLocation', ['/navTools/' + mcConst.dataModels.PresetManager + '/']);
        $rootScope.$broadcast('changeLocation', []);
    };

    $scope.changeGroupPreset = function(editor, newV){
        $scope.changedData.data.ShowDesc = true;

        $scope.changedData.data.Items[this.getSelectedItem().id] = newV;

        $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);

        lockBtns();
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_client_options_presets,
            mcConst.SessionID,
            function(presets){
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_list_roles,
                    mcConst.SessionID,
                    function(roles){
                        $rootScope.mcStorage[mcConst.dataModels.GroupRights] = roles;

                        fillGroupListAndMenus(roles, presets);
                    }
                ]);
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initRemoteSettings($scope);

        mcService.initResize(settings, $scope.Name);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $scope.show.apply(null, args);

        $scope.getData();
    });

}


/**
 * Created by Gifer on 30.07.2015.
 */

"use strict";

function initRelocation($scope){
    var _view = $$($scope.Name);
    var labelWidth = 320;

    if (!_view){
        var userCase = [
            { id: '1', value: mcLang(1771), width: 105}, // "1771":"Все онлайн",
            { id: '2', value: mcLang(1659), width: 210} // "1659":"Выбрать пользователей",
        ];

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type: "header", template: mcService.Lang(1765) }, // "1765":"Перенос сервера",
                    { view: "toolbar", width: 36, cols: [
                        { view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1773), autoheight: true, borderless: true, css: "_info selectable" }, // "1773":"С помощью этого инструмента вы можете настроить

                { type: "layout", padding: 5, cols: [
                    { width: labelWidth * 2, rows: [
                        { id: "primaryHost" + $scope.Name, view: "text", label: mcLang(1767), labelWidth: labelWidth, value: "" }, // "1767":"IP адрес или DNS имя сервера",
                        { id: "primaryPort" + $scope.Name, view: "counter", value: 2004, labelWidth: labelWidth, label: mcService.Lang(593), width: 440,
                            step: 1, min: 1, max: 65534, css: 'specCounter' }, //"593": "TCP порт",

                        { id: "alternativeHost" + $scope.Name, view: "text", label: mcLang(1768), labelWidth: labelWidth, value: "" }, // "1768":"Альтернативный IP адрес или DNS имя сервера",
                        { id: "alternativePort" + $scope.Name, view: "counter", value: 2004, labelWidth: labelWidth, label: mcService.Lang(593), width: 440,
                            step: 1, min: 1, max: 65534, css: 'specCounter' }, //"593": "TCP порт",

                        { id: "servName" + $scope.Name, view: "text", label: mcLang(604), labelWidth: labelWidth, value: ""}, // "604": "Название сервера",
                        { id: "servDesc" + $scope.Name, view: "textarea", label: mcLang(1769), labelWidth: labelWidth, value: "", height: 100}, // "1769":"Описание сервера",

                        { id: "servPwd" + $scope.Name, view: "text", type: "password", value: "", label:  mcLang(3), labelWidth: labelWidth} // "3"  : "Пароль к серверу",
                    ]}, {}
                ]},

                { type: "layout", padding: 5, cols: [
                    { rows: [
                        { view: "segmented", options: userCase, value: 1, width: labelWidth * 2, label: mcLang(1772), labelWidth: labelWidth, on: { // "1772":"Кому отправлять настройки сервера?",
                            onChange: function (newV) {
                                var list = $$("selectUsers" + $scope.Name);

                                if (newV == 2) {
                                    $scope.getOnlineUsers();

                                    list.show();

                                    $scope.sendTo = 1;
                                } else {
                                    list.hide();

                                    $scope.sendTo = 0;
                                }
                            }
                        }},

                        { id: "selectUsers" + $scope.Name, hidden: true, cols: [
                            { width: labelWidth},
                            { rows: [
                                { height: 5},
                                new mcService.FilterFiled({
                                    listName : "onlineUsers" + $scope.Name,
                                    filterParams : ["DisplayName", "UIN"]
                                }),

                                { id: "onlineUsers" + $scope.Name, view: "list", select: true, multiselect: "touch", data: [], width: labelWidth, height: 300,
                                    template: function (obj) {
                                        return obj.DisplayName + "<span class='toRight'>(UIN: " + obj.UIN + ")</span>";
                                    }, onContext:{}
                                },
                                { view: "button", value: mcLang(53), click: $scope.getOnlineUsers} // "53" : "Обновить",
                            ]},
                            {}
                        ]}
                    ]}, {}
                ]},

                { type: "layout", padding: 5, rows: [
                    { cols: [
                        { view: "button", value: mcLang(1770), width: labelWidth, click: $scope.send}, // "1770":"Отправить клиентам парамерты сервера",
                        {}
                    ]},

                    { height: 5},

                    { view: "checkbox", id: "immediately" + $scope.Name, value: false, labelRight: mcService.Lang(1781), labelWidth: 0, css: "finger"} // "1781":"Немедленно перенаправить всех выбранных пользователей баз ожидания переподключения",
                ]}
            ]
        });

        $scope.onlineUsers     = $$("onlineUsers" + $scope.Name);
        $scope.primaryHost     = $$("primaryHost" + $scope.Name);
        $scope.alternativeHost = $$("alternativeHost" + $scope.Name);

        new mcService.ContextMenu($scope.onlineUsers, null, null, function(){
            $scope.regShowWindow(this.config.id, this);
        });
    }

    return _view;
}


/**
 * Created by Gifer on 30.07.2015.
 */

"use strict";

function relocationController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.Relocation;

    var element = document.getElementById($scope.Name);
    var view = null;

    $scope.sendTo = 0; // 0 - to all, 1 - to selected users

    function checkData(_host) {
        var host = mcService.trim(_host);

        if (host != "") {
            if (mcService.isFormatedLikeIP(host)) {
                return mcService.isValidIpAddress(host);
            }

            return mcService.isValidIpAddressV6(host) || mcService.isValidHostName(host);
        }
    }

   //===================================================

    $scope.send = function () {
        var items       = $scope.onlineUsers.getSelectedId();
        var primary     = $scope.primaryHost.getValue();
        var alternative = $scope.alternativeHost.getValue();
        var Port1       = $$("primaryPort" + $scope.Name).getValue();
        var Port2       = $$("alternativePort" + $scope.Name).getValue();
        var ServName    = mcService.trim($$("servName" + $scope.Name).getValue().toString());

        if (!checkData(primary) || (alternative != "" && !checkData(alternative))){
            $scope.regShowWindow(mcService.RandomHash(7), webix.alert(mcLang(1777))); // "1777":"Укажите корректный IP или DNS имя сервера",
        } else

        if (isNaN(Port1) || (!isNaN(Port1) && (Port1 < 1 || Port1 > 65534)) ||
            (alternative != "" && (isNaN(Port2) || (!isNaN(Port2) && (Port2 < 1 || Port2 > 65534))))){
            $scope.regShowWindow(mcService.RandomHash(7), webix.alert(mcLang(1782))); // "1782":"Укажите корректный TCP порт",
        } else

        if (ServName == "") {
            $scope.regShowWindow(mcService.RandomHash(7), webix.alert(mcLang(1783))); // "1783":"Укажите название сервера",
        } else

        if ($scope.sendTo == 0 || ($scope.sendTo == 1 && items)) {
            $scope.regShowWindow(mcService.RandomHash(7), webix.confirm({
                type  : "confirm-warning",
                text  : mcService.Lang(1774, $scope.sendTo ? mcLang(1776) : mcLang(1775)), // "1774":"Разослать %s пользователям новые параметры сервера?", "1776":"выбранным", "1775":"всем",
                ok    : mcService.Lang(13), // "13" : "Ок",
                cancel: mcService.Lang(103), // "103": "Отмена",
                callback:function(yes){
                    if (yes){
                        var Immediately = mcService.convertIntToBool($$("immediately" + $scope.Name).getValue());
                        var UINS  = $scope.sendTo ? (mcService.isArray(items) ? items.join(','): items): "online";
                        var IP1   = mcService.trim(primary);
                        var IP2   = mcService.trim(alternative);

                        var Desc     = mcService.trim($$("servDesc" + $scope.Name).getValue().toString());
                        var Pass     = mcService.trim($$("servPwd"  + $scope.Name).getValue().toString());

                        if (isNaN(Port2)){
                            Port2 = 2004;
                        }

                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_change_mychat_server,
                            mcConst.SessionID,
                            Immediately,
                            UINS     ,  // список UIN-ов пользователей, для которых предназначена эта команда, через запятую. Все пользователи должны быть онлайн
                            IP1      ,  // основной адрес сервера чата
                            Port1    ,  // порт для подключения
                            IP2      ,  // резервный адрес сервера чата
                            Port2    ,  // второй порт для подключения
                            ServName ,  // название для сервера (условно)
                            Desc     ,  // описание сервера (условно)
                            Pass     ,  // пароль для доступа к серверу (если указан на сервере, иначе - пустая строка)
                            function(){
                                webix.alert(mcLang(1779)); // "1779":"Новые настройки серевра отправлены!",
                            }
                        ]);
                    }
                }
            }));
        } else {
            $scope.regShowWindow(mcService.RandomHash(7), webix.alert(mcLang(1778))); // "1778":"Выберите пользователей для отправки настроек!",
        }
    };

    $scope.getOnlineUsers = function () {
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_online_users_list,
            mcConst.SessionID,
            function( data ) {
                $scope.onlineUsers.clearAll();

                data.forEach(function (item, idx) {
                    data[idx].id = data[idx].UIN;
                });

                $scope.onlineUsers.parse(data);
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, element);

        view = initRelocation($scope);

        mcService.initResize(view, $scope.Name);
    };

    //===================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(element);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
    });
}

"use strict";

function initBots($scope){
    var _view = $$($scope.Name);

    if (!_view){
        var quiz = { id: "view_quiz", hidden: $scope.shovedView !== $scope.const.QUIZ, rows: [
            { view: "checkbox", id: "enable" + $scope.const.QUIZ, value: '', labelWidth: 0, css: "finger",
                labelRight: mcService.Lang(1753, mcLang(1889)), // "1753":"Включить интеграцию с %s", "1889":"Викторина",
                on: { onItemClick: $scope.change }
            },

            { height: 5},

            {}
        ]};

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { type: "layout", cols: [
                    { view: "template", type : "header", template : mcService.Lang(1888) }, // "1888":"Боты",
                    { view: "toolbar", width: 150, cols: [
                        { view: "toggle", value: false,
                            offLabel: mcLang(1750), // "1750":"Скрыть список",
                            onLabel : mcLang(1751), // "1751":"Показать список",
                            click   : $scope.showHideList
                        }
                    ]},
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: 'layout', padding: 5, cols: [
                    { id: "botsList" + $scope.Name, view: "list", width: 200, select: true, data: [
                        { id: $scope.const.QUIZ,   value: mcLang(1889)}
                    ], scroll: false,
                        on: {
                            onAfterSelect: $scope.selectBot
                        }
                    },

                    { id: "botSpacer" + $scope.Name, width: 7},

                    quiz
                ]}
            ]
        });

        $scope.botsList  = $$("botsList" + $scope.Name);
        $scope.botSpacer = $$("botSpacer" + $scope.Name);
        
        $scope.enableQuiz = $$("enable" + $scope.const.QUIZ);

        // =========================

        mcService.disableContextMenu(_view, ["selectable"]);
    }

    return _view;
}
"use strict";

function botsController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.Bots;

    var cantShowApplyForm= false;
    var angElement       = document.getElementById($scope.Name);
    var view             = null;

    $scope.const         = {
        QUIZ : "quiz"
    };
    $scope.update        = {};
    $scope.shovedView    = $scope.const.QUIZ;

    function saveData(where) {
        var outData = "";

        switch (where){
            case $scope.const.QUIZ:
                outData = {
                    // название инструмента, от него зависит набор настроек
                    name     : $scope.const.QUIZ
                };
            break;
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_set_integration_tool_options,
            mcConst.SessionID,

            JSON.stringify(outData),

            function () {
                $scope[where] = mcService.Marge($scope[where], outData);

                switch (where){
                    case $scope.const.QUIZ:
                        // $scope.btnAddDel.enable();
                    break;
                }

                $scope.fillIntegrationTool(where);
            }
        ]);
    }

    //========================================================
    
    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_custom_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    }, mcConst._CMD_.cs_adm_get_custom_options);

    // ================ QUIZ ======================

    $scope[$scope.const.QUIZ] = {
        name    : $scope.const.QUIZ,
        pattern : "",
        enabled : false,
        itemList: {
            users : [],
            groups: [],
            confs : []
        },
        changing: ""
    };

    $scope.showHideList = function () {
        if ($scope.botsList.isVisible()){
            $scope.botsList.hide();
            $scope.botSpacer.hide();
        } else {
            $scope.botsList.show();
            $scope.botSpacer.show();
        }
    };

    // ================ APPLY FORM ====================
    
    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        onApply : function(){
            saveData($scope.shovedView);

            $scope.botsList.enable();

            cantShowApplyForm = false;
        },
        onClose: function () {
            $scope.fillIntegrationTool($scope.botsList.getSelectedId());

            $scope.botsList.enable();

            cantShowApplyForm = false;
        }
    };

    $scope.change = function () {
        if (!cantShowApplyForm) {
            cantShowApplyForm = true;

            $scope.changedData.data.ShowDesc = true;
            $scope.changedData.data.Header   = mcService.Lang(1525) + "?"; // "1525":"Сохранить изменения",
            $scope.changedData.ApplyTitle    = mcService.Lang(104);        // "104": "Сохранить",

            // $scope.btnAddDel.disable();
            $scope.botsList.disable();

            $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
        }
    };

    //========================================================

    $scope.fillIntegrationTool = function (where) {
        switch (where) {
            case $scope.const.QUIZ:
                $scope.enableQuiz.setValue($scope[where].enabled);
            break;
        }
    };

    $scope.selectBot = function (newView) {
        if ($scope.shovedView !== newView) {
            $$("view_" + $scope.shovedView).hide();

            $scope.shovedView = newView;

            $$("view_" + $scope.shovedView).show();

            $scope.getData(newView);
        }
    };

    $scope.getData = function (where) {
        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_integration_tool_options,
            mcConst.SessionID,
            where,
            
            function( data ){
                cantShowApplyForm = true;

                switch (data.name){
                    case $scope.const.QUIZ:
                        
                    break;
                }
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        view = initBots($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();
    };

    //========================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();

        $scope.botsList.select($scope.const.QUIZ);

        // $scope.getData($scope.const.QUIZ);
    });

}
"use strict";

function initTotalClear($scope){
    var labelWidth = 250;
    var blockWidth = 500;
    var btnWidth   = 240;
    var totalClear = $$($scope.Name);

    if (totalClear){
        totalClear.destructor();
    }

    totalClear = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type: "header", template : mcService.Lang(1945)}, // "1945":"Очистка",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5, rows : [
                { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1954), autoheight: true, borderless: true, css: "_info selectable" } // "1954":"ВНИМАНИЕ! Данные удаленные в этом разделе нельзя восстановить!",
            ]},

            { height: 5 },

            { type: 'layout', padding: 5, cols : [{
                rows: [
                    { view: "button", type: "icon", css: "border1", label: mcLang(1946), height: 60, click: $scope.Conf},         // "1946":"Conf",
                    { view: "button", type: "icon", css: "border1", label: mcLang(1947), height: 60, click: $scope.Private}       // "1947":"Private",
                ]}, {}]
            },

            { height: 5 },

            { type: 'layout', padding: 5, cols : [{
                rows: [
                    { view: "button", type: "icon", css: "border1", label: mcLang(1948), height: 60, click: $scope.BBS},          // "1948":"BBS",
                    { view: "button", type: "icon", css: "border1", label: mcLang(1949), height: 60, click: $scope.Broadcast}     // "1949":"Broadcast",
                ]}, {}]
            },

            { height: 5 },

            { type: 'layout', padding: 5, cols : [{
                rows: [
                    { view: "button", type: "icon", css: "border1", label: mcLang(1950), height: 60, click: $scope.File},         // "1950":"File",
                    { view: "button", type: "icon", css: "border1", label: mcLang(1951), height: 60, click: $scope.Backup}        // "1951":"Backup",
                ]}, {}]
            },

            { height: 5 },

            { type: 'layout', padding: 5, cols : [{
                rows: [
                    { view: "button", type: "icon", css: "border1", label: mcLang(1952), height: 60, click: $scope.TextLog}       // "1952":"TextLog",
                ]}, {}]
            },

            { height: 5 },

            { type: 'layout', padding: 5, cols : [{
                rows: [
                    { view: "button", css: "border1", value: mcLang(1953), height: 60, click: $scope.Annihilation}  // "1953":"All",
                ]}, {}]
            },
        {}]
    });

    mcService.disableContextMenu(totalClear);

    return totalClear;
}

"use strict";

function totalClearController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.TotalClear;

    var angElement = document.getElementById($scope.Name);
    var pwdWnd = null;
    var TOTAL_CLEAR = "annihilation";

    function showEnterPassword(what) {
        if (pwdWnd) {
            pwdWnd.destructor();
        }

        pwdWnd = webix.ui({
            view     : "window",
            position : "center",
            // width    : 250,
            head     : mcLang(1957, [mcConst.UserInfo.Nick, mcConst.UserInfo.UIN]), // "1957":"Введите пароль %s",
            modal    : true,
            body     : {
                view : 'form',
                rules: { "password" : webix.rules.isNotEmpty },
                elements : [{ cols: [{
                    view : "text",
                        // placeholder: mcService.Lang(2), // "2"  : "Пароль",
                        type       : 'password',
                        name       : 'password',
                        required   : "true",
                        keyPressTimeout: 100,
                        on         : {
                            onTimedKeyPress : function(){
                                var lng      = $$('clearDispLang');
                                var lastChar = pwdWnd.getBody().elements['password'].getValue();

                                lastChar = lastChar[lastChar.length - 1];

                                if (lastChar){
                                    if (lastChar.match(/[a-zA-Z]/)) {
                                        lng.define('template', 'EN');
                                        lng.refresh();
                                    } else
                                    if (lastChar.match(/[а-яА-Я]/)){
                                        lng.define('template', 'RU');
                                        lng.refresh();
                                    } else
                                    if (lastChar.match(/[їЇіІєЄ]/)){
                                        lng.define('template', 'UA');
                                        lng.refresh();
                                    }
                                }
                            }
                        }
                    }, {
                        id       : 'clearDispLang',
                        template : 'EN',
                        width    : 23,
                        borderless : true
                    }]}, {
                    cols : [{
                        view  : "button",
                        value : mcLang(13), //     "13" : "Ок",
                        name  : "save",
                        on    : {onItemClick: function () {
                            var form     = pwdWnd.getBody();
                            var isValid  = form.validate();
                            var pwd1     = form.elements['password'];
                            var pwd1Val  = pwd1.getValue();

                            if (isValid){
                                if (pwdWnd) pwdWnd.hide();

                                what.push(pwd1Val);

                                $rootScope.$broadcast('SendCMDToServer', [
                                    mcConst.lockInterface,
                                    mcConst._CMD_.cs_adm_remove_conversations,
                                    mcConst.SessionID]
                                    .concat(what)
                                    .concat([function () {
                                        webix.message(mcLang(1956)); // "1956":"Операция удаления закончена!",
                                    }])
                                );
                            }
                        }}
                    }, {
                        view  : "button",
                        type  : "danger",
                        value : mcService.Lang(103), // "103": "Отмена",
                        click : function () {
                            if (pwdWnd) pwdWnd.hide();
                        }
                    }]
                }]
            },
            on: {
                onShow: function () {
                    pwdWnd.getBody().elements['password'].focus();
                    
                    $scope.registerHotKeys();
                },
                onHide: function () {
                    $scope.removeHotKey();
                }
            }
        });

        pwdWnd.show();

        return pwdWnd;
    }

    // ===============================================================

    $scope.registerHotKeys = function(){
        $rootScope.hotKeyDispatcher.addPreset(TOTAL_CLEAR, [{
            key    :  mcConst.keyCodes.enter,
            func   : function () {
                if (pwdWnd) {
                    var form = pwdWnd.getBody();
                    var save = form.elements['save'];

                    save.callEvent("onItemClick");
                }
            }
        }, {
            key    :  mcConst.keyCodes.esc,
            func   : function () {
                if (pwdWnd){
                    pwdWnd.hide();
                }
            }
        }], document);
    };

    $scope.removeHotKey = function(){
        $rootScope.hotKeyDispatcher.removePreset(TOTAL_CLEAR);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.Conf = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            true, // "Conf"
            false, // "Private"
            false, // "BBS"
            false, // "Broadcast"
            false, // "File"
            false, // "Backup"
            false  // "TextLog"
        ]));
    };

    $scope.Private = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            false, // "Conf"
            true , // "Private"
            false, // "BBS"
            false, // "Broadcast"
            false, // "File"
            false, // "Backup"
            false  // "TextLog"
        ]));
    };

    $scope.BBS = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            false, // "Conf"
            false, // "Private"
            true , // "BBS"
            false, // "Broadcast"
            false, // "File"
            false, // "Backup"
            false  // "TextLog"
        ]));
    };

    $scope.Broadcast = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            false, // "Conf"
            false, // "Private"
            false, // "BBS"
            true , // "Broadcast"
            false, // "File"
            false, // "Backup"
            false  // "TextLog"
        ]));
    };

    $scope.File = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            false, // "Conf"
            false, // "Private"
            false, // "BBS"
            false, // "Broadcast"
            true , // "File"
            false, // "Backup"
            false  // "TextLog"
        ]));
    };

    $scope.Backup = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            false, // "Conf"
            false, // "Private"
            false, // "BBS"
            false, // "Broadcast"
            false, // "File"
            true , // "Backup"
            false  // "TextLog"
        ]));
    };

    $scope.TextLog = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            false, // "Conf"
            false, // "Private"
            false, // "BBS"
            false, // "Broadcast"
            false, // "File"
            false, // "Backup"
            true   // "TextLog"
        ]));
    };

    $scope.Annihilation = function () {
        $scope.regShowWindow(mcService.RandomHash(4), showEnterPassword([
            true, // "Conf"
            true, // "Private"
            true, // "BBS"
            true, // "Broadcast"
            true, // "File"
            true, // "Backup"
            true  // "TextLog"
        ]));
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initTotalClear($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
    });
}


function initForum($scope){
    "use strict";

    function myFolder(obj) {
        var marker = "marker_" + (obj.Color || 0);
        // var res    = "<div class='webix_tree_file " + marker + "'></div>";
        var res    = "<span class='" + marker + "'>" + mcService.insertIco("fa-file", "fontSize12") + "</span>";

        if (obj.icon) {
            // res = "<div class='webix_tree_file webix_tree_" + obj.icon + " " + marker + "'></div>";
            res = "<div class='webix_tree_" + obj.icon + "'>" + mcService.insertIco("fa-file", "fontSize12") + "</div>";
        }

        if (obj.$count || obj.Type === mcConst.msgTypes.section){
            if (obj.open) {
                // res = "<div class='webix_tree_folder_open " + marker + "'></div>";
                res = "<span class='" + marker + "'>" + mcService.insertIco("fa-folder-open") + "</span>&nbsp;";
            } else {
                // res = "<div class='webix_tree_folder " + marker + "'></div>";
                res = "<span class='" + marker + "'>" + mcService.insertIco("fa-folder") + "</span>";
            }
        }

        return res;
    }
    
    var view = $$($scope.Name);

    if (!view){
        view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(1981) }, // "1981":"Управление подписками на форум",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type : 'layout', padding : 5, cols : [{
                    rows: [
                        { id: "forumTree" + $scope.Name, view: "tree", type:"lineTree", css: "finger forumTree", select: true,
                            template:function(obj, common){
                                return common.icon(obj, common).replace(/webix_tree_img/g, 'marginRight3 webix_tree_img') + myFolder(obj) + "<span>" + obj.Caption + "</span>"; //res;
                            },
                            on: {
                                // onAfterRender      : $scope.editButtons.attachContext,
                                onAfterSelect      : $scope.selectForumElement,
                                onBeforeContextMenu: function (id) {
                                    this.select(id);
                                },
                                onItemDblClick     : function (id) {
                                    var item = this.getItem(id);

                                    if (item.Type === mcConst.msgTypes.section){
                                        this[item.open ? "close" : "open"](id);
                                    }
                                }
                            }, onContext: {}
                        }
                    ]
                },  { view : "resizer" }, {
                    rows: [
                        { rows: [
                            { type: 'header', height: 30, template: mcService.Lang(1722) }, // "1722":"Группы пользователей",

                            new mcService.ListButtonSet({
                                type   : 'combo',
                                actions: $scope.groupActions,
                                list   : "forumGroupList" + $scope.Name,
                                selectedItem: "Name",
                                regShowWindow: $scope.regShowWindow
                            }),

                            { height: 3 },

                            mcService.FilterFiled({
                                listName     : "forumGroupList" + $scope.Name,
                                filterParams : ["Name"]
                            }),

                            { id : "forumGroupList" + $scope.Name,
                                view      : "list",
                                select    : true,
                                navigation: true,
                                template  : "#Name#", //&nbsp;&nbsp;<span style='opacity: .85; font-size: 90%;'>#comments#</span>"
                                on        : {
                                    // onAfterSelect : $scope.selectGroup
                                }
                            }
                        ]},

                        { view : "resizer" },

                        { rows: [
                            { type: 'header', height: 30, template: mcService.Lang(1982) }, // "1982":"Индивидуально подписанные пользователи",

                            new mcService.ListButtonSet({
                                type   : 'combo',
                                actions: $scope.userActions,
                                list   : "forumUserList" + $scope.Name,
                                selectedItem: "value",
                                regShowWindow: $scope.regShowWindow
                            }),

                            { height: 3},

                            mcService.FilterFiled({
                                listName     : 'forumUserList' + $scope.Name,
                                filterParams : ["DisplayName"]
                            }),

                            { id : 'forumUserList' + $scope.Name,
                                view      : "list",
                                template  : function usersTemplate(obj){
                                    return obj.value + " <span style='float:right'>(UIN: " + obj.id + ")</span>";
                                },
                                navigation: true,
                                select    : "multiselect",
                                on        : {
                                    // onAfterSelect: $scope.removeUser.enable
                                }
                            }
                        ]}
                    ]
                }] }
            ]
        });

        $scope.forumTree        = $$("forumTree" + $scope.Name);
        $scope.forumGroupList   = $$("forumGroupList" + $scope.Name);
        $scope.forumUserList    = $$('forumUserList' + $scope.Name);

        mcService.disableContextMenu(view);
    } else {

    }

    return view;
}
"use strict";

function forumController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.Forum;

    var angElement = document.getElementById($scope.Name);
    var view       = null;
    var structCash = {};
    var ROOT       = 'root';
    var CLEAR_GROUPS = 1;
    var CLEAR_USERS  = 2;

    $scope.currentSection = 0;
    $scope.forumStruct    = [];

    $scope.groupActions   = {};
    $scope.userGroups     = [];
    $scope.currentForumGroups = [];

    $scope.currentForumUsers = [];
    $scope.userActions    = {};
    $scope.usersList      = [];

    var currentForumType = 0;
    var currentForumID   = 0;
    var topicList        = [];
    var sectionList      = [];

    // =============================================

    $scope.userActions.preview  = function (field) {
        field.define('options', $scope.usersList);
        field.getList().define('template', "#value# (#id#)");
        field.refresh();

        $scope.usersList[0] && field.setValue($scope.usersList[0].id);
    };

    $scope.userActions.save     = function (field) {
        if (currentForumType && currentForumID){
            var item = field.getList().getItem(field.getValue());

            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_forum_add_subs_user,
                mcConst.SessionID,

                currentForumID  , // индекс секции либо темы
                currentForumType, // что конкретно нам нужно, 1 - секция, 2 - тема
                item.id         , // индекс группы, которую следует добавить в подписку

                function () {
                    if (!$scope.forumUserList.getItem(item.id)){
                        $scope.forumUserList.add({
                            id   : item.id,
                            value: $scope.usersList[mcService.findItemInArrayOfObj($scope.usersList, item.id, "id")].value
                        });
                    }
                }
            ]);

            return true;
        }
    };

    $scope.userActions.del      = function (selectedItem) {
        if (currentForumType && currentForumID){
            var items = selectedItem.id;

            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_forum_delete_subs_user,
                mcConst.SessionID,

                currentForumID  , // индекс секции либо темы
                currentForumType, // что конкретно нам нужно, 1 - секция, 2 - тема
                items             // индекс группы, которую следует добавить в подписку
            ]);
        }
    };

    $scope.userActions.clear    = function () {
        if (currentForumType && currentForumID){
            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_forum_clear_subs,
                mcConst.SessionID,

                currentForumID  , // индекс секции либо темы
                currentForumType, // что конкретно нам нужно, 1 - секция, 2 - тема
                CLEAR_USERS
            ]);

            return true;
        }
    };

    // =============================================

    $scope.groupActions.preview = function (field) {
        field.define('options', $scope.userGroups);
        field.getList().define('template', "#Name#");
        field.refresh();
        $scope.userGroups[0] && field.setValue($scope.userGroups[0].id);
    };

    $scope.groupActions.save    = function (field) {
        if (currentForumType && currentForumID){
            var item = field.getList().getItem(field.getValue());

            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_forum_add_subs_group,
                mcConst.SessionID,

                currentForumID  , // индекс секции либо темы
                currentForumType, // что конкретно нам нужно, 1 - секция, 2 - тема
                item.ID         , // индекс группы, которую следует добавить в подписку

                function () {
                    if (!$scope.forumGroupList.getItem(item.ID)){
                        $scope.forumGroupList.add({
                            id   : item.ID,
                            ID   : item.ID,
                            Name: field.getText()
                        });
                    }
                }
            ]);

            return true;
        }
    };

    $scope.groupActions.del     = function (selectedItem) {
        if (currentForumType && currentForumID){
            var items = selectedItem.id;

            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_forum_delete_subs_group,
                mcConst.SessionID,

                currentForumID  , // индекс секции либо темы
                currentForumType, // что конкретно нам нужно, 1 - секция, 2 - тема
                items             // индекс группы, которую следует добавить в подписку
            ]);
        }
    };

    $scope.groupActions.clear   = function () {
        if (currentForumType && currentForumID){
            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_forum_clear_subs,
                mcConst.SessionID,

                currentForumID  , // индекс секции либо темы
                currentForumType, // что конкретно нам нужно, 1 - секция, 2 - тема
                CLEAR_GROUPS
            ]);

            return true;
        }
    };

    // =============================================

    $scope.selectForumElement = function (id) {
        var item = this.getItem(id);

        currentForumType = item.Type;        // что конкретно нам нужно, 1 - секция, 2 - тема
        currentForumID   = id.split('_')[1]; // idParentSection_idChildTopicOrSection

        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_forum_get_subs_users,
            mcConst.SessionID,

            currentForumID,
            currentForumType,

            function (users) {
                $rootScope.SendCMDToServer([
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_forum_get_subs_groups,
                    mcConst.SessionID,

                    currentForumID,
                    currentForumType,

                    function (groups) {
                        // === sections ===
                        
                        $scope.currentForumGroups = groups.List ? groups.List.split(',') : [];

                        $scope.currentForumGroups = $scope.currentForumGroups.map(function (id) {
                            var idx  = mcService.findItemInArrayOfObj($scope.userGroups, id, "ID");
                            var name = "not found";

                            if (idx !== -1){
                                name = $scope.userGroups[idx].Name;
                            }

                            return {
                                id  : id,
                                ID  : id,
                                Name: name
                            };
                        });

                        $scope.forumGroupList.clearAll();
                        $scope.forumGroupList.parse($scope.currentForumGroups);

                        // === topics ===

                        $scope.currentForumUsers = users.List ? users.List.split(',') : [];

                        $scope.currentForumUsers = $scope.currentForumUsers.map(function (id) {
                            var idx  = mcService.findItemInArrayOfObj($scope.usersList, id, "id");
                            var name = "not found";

                            if (idx !== -1){
                                name = $scope.usersList[idx].value;
                            }

                            return {
                                id   : id,
                                value: name
                            };
                        });

                        $scope.forumUserList.clearAll();
                        $scope.forumUserList.parse($scope.currentForumUsers);
                    }
                ]);
            }
        ]);
    };

    $scope.getData = function () {
        var task = new mcService.TaskList();

        task.AddTask(function () {
            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_forum_get_structure,
                mcConst.SessionID,

                function (data) {
                    $scope.forumStruct = [{ id: "1_0", ID: "0", Color: 0, Caption: "Forum Home", ParentID: ROOT, data: []}];

                    $scope.show(data);

                    task.Next();
                }
            ]);
        });

        task.AddTask(function () {
            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_user_groups,
                mcConst.SessionID,

                function (data) {
                    $scope.userGroups = data;

                    $scope.userGroups.forEach(function (item) {
                        item.id    = item.ID;
                        item.value = item.Name;
                    });
                    
                    task.Next();
                }
            ]);
        });

        task.AddTask(function () {
            mcService.getAllUserForFillList($scope.usersList, function fill_uList (data){
                $scope.usersList = mcService.transformDataObject(webix.copy(data), [['DisplayName', 'value'], ['UIN', 'id']]);

                $scope.usersList.sort(function (a, b) {
                    return mcService.sortAB(parseInt(a.id), parseInt(b.id));
                });

                var firstItem = $scope.forumTree.getFirstId();

                $scope.forumTree.select(firstItem);
                $scope.forumTree.open(firstItem);
            }, $rootScope);
        });

        task.Run();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(data){
        var empty = [].concat($scope.forumStruct);

        sectionList = [];
        topicList   = [];
        $scope.usersList = [];

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        data = mcService.StringToObj(mcService.isObject(data) ? data.Data : data);

        data.forEach(function (item) {
            if (item.Type === mcConst.msgTypes.section){
                sectionList.push(item);
            } else

            if (item.Type === mcConst.msgTypes.topic){
                topicList.push(item);
            }
        });

        structCash = {"1_0": {
            Item: empty[0],
            Data: empty[0].data
        }};

        $scope.forumStruct = mcService.buildForumStructure(empty, data, ["0"], structCash);

        view = initForum($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();

        $scope.forumTree.parse($scope.forumStruct[0].data);
    };

    $scope.$on('hide' + $scope.Name, function() {
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.getData();
    });

}
"use strict";

function initIntegrations($scope){
    var _view = $$($scope.Name);

    if (!_view){
        var telegramView = $scope[$scope.iNames.TELEGRAM].getView();
        var phpbb3View   = $scope[$scope.iNames.PHPBB3]  .getView();
        var geoipView    = $scope[$scope.iNames.GEOIP]   .getView();
        var icqView      = $scope[$scope.iNames.ICQ]     .getView();
        var quizView     = $scope[$scope.iNames.QUIZ]    .getView();
        var asteriskView = $scope[$scope.iNames.ASTERISK].getView();
        var turbosmsView = $scope[$scope.iNames.TURBOSMS].getView();

        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { type: "layout", cols: [
                    { view: "template", type : "header", template : mcService.Lang(1740) }, // "1740":"Интеграция",
                    { view: "toolbar", width: 150, cols: [
                        { view: "toggle", value: false,
                            offLabel: mcLang(1750), // "1750":"Скрыть список",
                            onLabel : mcLang(1751), // "1751":"Показать список",
                            click   : $scope.showHideIntList
                        }
                    ]},
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: 'layout', padding: 5, cols: [
                    { id: "integrationList" + $scope.Name, view: "list", width: 200, select: true, data: [
                        { id: $scope.iNames.ASTERISK, value: "Asterisk"},
                        { id: $scope.iNames.GEOIP,    value: "GeoIP"},
                        { id: $scope.iNames.PHPBB3,   value: "phpBB 3"},
                        { id: $scope.iNames.TELEGRAM, value: "Telegram Bot"},
                        { id: $scope.iNames.TURBOSMS, value: "TurboSMS"},
                        { id: $scope.iNames.QUIZ,     value: mcLang(2000)} // "2000":"Викторина",
                        // { id: $scope.icq.name,      value: "ICQ"}
                    ], scroll: false,
                        on: {
                            onAfterSelect: $scope.selectIntegration
                        }
                    },

                    { id: "intSpacer" + $scope.Name, width: 7},

                    telegramView,
                    phpbb3View,
                    icqView,
                    geoipView,
                    quizView,
                    asteriskView,
                    turbosmsView
                ]}
            ]
        });

        $scope.integrationList = $$("integrationList" + $scope.Name);
        $scope.intSpacer       = $$("intSpacer" + $scope.Name);

        // ===== PHPBB 3 ===========
        $scope[$scope.iNames.PHPBB3]  .initView();

        // ===== TELEGRAM ==========
        $scope[$scope.iNames.TELEGRAM].initView();

        // ===== ICQ ===============
        $scope[$scope.iNames.ICQ]     .initView();

        // ===== GEOIP ===============
        $scope[$scope.iNames.GEOIP]   .initView();

        // ===== ASTERISK ============
        $scope[$scope.iNames.ASTERISK].initView();

        // ===== TURBOSMS ============
        $scope[$scope.iNames.TURBOSMS].initView();

        mcService.disableContextMenu(_view, ["selectable"]);
    }

    return _view;
}
function integrationsController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.Integrations;

    var cantShowApplyForm = false;
    var angElement        = document.getElementById($scope.Name);
    var view              = null;

    $scope.iNames     = {
        PHPBB3   : "phpbb3",
        TELEGRAM : "telegram",
        ICQ      : "icq",
        GEOIP    : "geoip",
        QUIZ     : "quiz",
        ASTERISK : "asterisk",
        TURBOSMS : "turbosms"
    };
    $scope.update     = {};
    $scope.shovedView = $scope.iNames.ASTERISK;
    // $scope.shovedView = $scope.iNames.GEOIP;

    // ========================================================

    function saveData(where) {
        var outData = $scope[where].saveData();

        $rootScope.$broadcast('SendCMDToServer', [
            // mcConst.lockInterface,
            mcConst._CMD_.cs_adm_set_integration_tool_options,
            mcConst.SessionID,

            JSON.stringify(outData),

            function () {
                $scope[where].fillOptions(outData);

                switch (where){
                    case $scope.iNames.PHPBB3:
                        $scope[where].btnAddDel.enable();
                        
                        $scope.getData(where);
                    break;

                    // case $scope.iNames.TELEGRAM:
                        // $scope.telegram.connectBot();
                    // break;
                    default:
                        $scope.fillIntegrationTool(where);
                }


            }
        ]);
    }

    function fillScriptList(scriptsList) {
        if (scriptsList && mcService.isArray(scriptsList) && scriptsList.length){
            var list = [
                { id: "-1", value: mcLang(140)} // "140": "Ничего не выбрано",
            ];

            for (var i = 0; i < scriptsList.length; i++){
                if (scriptsList[i].Event === "OnRequestByREST")  {
                    list.push({
                        id    : scriptsList[i].ID,
                        value : scriptsList[i].ScriptName
                    });
                }
            }
        }

        $scope.fillIntegrationTool($scope.iNames.TELEGRAM);
    }

    //========================================================
    
    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_custom_options, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    }, mcConst._CMD_.cs_adm_get_custom_options);

    // ================ APPLY FORM ====================
    
    $scope.changedData = {
        data : {
            Desc    : "",
            Items   : {},
            ShowDesc: false,
            Reopen  : false
        },
        onApply : function(){
            saveData($scope.shovedView);

            $scope.integrationList.enable();

            cantShowApplyForm = false;
        },
        onClose: function () {
            $scope.fillIntegrationTool($scope.integrationList.getSelectedId());

            $scope.integrationList.enable();

            cantShowApplyForm = false;
        }
    };

    $scope.change = function () {
        if (!cantShowApplyForm) {
            cantShowApplyForm = true;

            $scope.changedData.data.ShowDesc = true;
            $scope.changedData.data.Header   = mcService.Lang(1525) + "?"; // "1525":"Сохранить изменения",
            $scope.changedData.ApplyTitle    = mcService.Lang(104);        // "104": "Сохранить",

            if ($scope[$scope.iNames.PHPBB3].btnAddDel && $scope.integrationList.getSelectedId() === $scope.iNames.PHPBB3) {
                $scope[$scope.iNames.PHPBB3].btnAddDel.disable();
            }

            $scope.integrationList.disable();

            $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [$scope.changedData]);
        }
    };

    //========================================================

    $scope.showHideIntList = function () {
        if ($scope.integrationList.isVisible()){
            $scope.integrationList.hide();
            $scope.intSpacer.hide();
        } else {
            $scope.integrationList.show();
            $scope.intSpacer.show();
        }
    };

    $scope.saveData = saveData;

    $scope.fillIntegrationTool = function (where, data) {
        $scope[where].fillTool(data);

        cantShowApplyForm = false;
    };

    $scope.selectIntegration = function (newView) {
        if ($scope.shovedView !== newView) {
            $$("view_" + $scope.shovedView).hide();

            $scope.shovedView = newView;

            $$("view_" + $scope.shovedView).show();

            $scope[newView].initView();

            $scope.getData(newView);
        }
    };

    $scope.getData = function (where) {
        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_integration_tool_options,
            mcConst.SessionID,
            where,
            
            function( data ){
                cantShowApplyForm = true;

                if ($scope[data.name]) $scope[data.name].fillOptions(data);

                switch (data.name){
                    case $scope.iNames.QUIZ:
                        $scope[data.name].fillView(function () {
                            $scope.fillIntegrationTool(data.name, data);
                        });
                    break;

                    case $scope.iNames.TELEGRAM:
                        $scope[data.name].fillView(fillScriptList);
                    break;

                    case $scope.iNames.PHPBB3:
                    case $scope.iNames.ICQ:
                    case $scope.iNames.GEOIP:
                    case $scope.iNames.ASTERISK:
                    case $scope.iNames.TURBOSMS:
                        $scope.fillIntegrationTool(data.name, data);
                    break;
                }
            }
        ]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        view = initIntegrations($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();
    };

    //========================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();

        $scope.integrationList.select($scope.shovedView);

        $scope.getData($scope.shovedView);
    });

    // ================ TELEGRAM =============================
    $scope[$scope.iNames.TELEGRAM] = new ToolTelegram($scope, $rootScope, {
        name      : $scope.iNames.TELEGRAM,
        BotID     : "",
        ScriptID  : -1,
        BotChecked: false,
        Users     : []
    });

    // ================ PHPBB3   ======================
    $scope[$scope.iNames.PHPBB3]   = new ToolPhpBB($scope, $rootScope, {
        name    : $scope.iNames.PHPBB3,
        pattern : "",
        enabled : false,
        itemList: {
            users : [],
            groups: [],
            confs : []
        },
        changing: ""
    });

    // =============== ICQ ============================
    $scope[$scope.iNames.ICQ]      = new ToolIcq($scope, $rootScope, {
        name       : $scope.iNames.ICQ,
        autoApprove: false,
        Users      : []
    });

    // =============== GEOIP ============================
    $scope[$scope.iNames.GEOIP]    = new ToolGeoIP($scope, $rootScope, {
        name   : $scope.iNames.GEOIP,
        enabled: false
    });

    // =============== QUIZ ============================
    $scope[$scope.iNames.QUIZ]     = new ToolQuiz($scope, $rootScope, {
        name   : $scope.iNames.QUIZ,
        enabled: false
    });

    // =============== ASTERISK ============================
    $scope[$scope.iNames.ASTERISK]     = new ToolAsterisk($scope, $rootScope, {
        name     : $scope.iNames.ASTERISK,
        enabled  : false,
        status   : 0,
        State    : 0,
        Username : "",
        Secret   : "",
        Host     : "",
        Port     : 0,
        Channel  : "SIP",
        Context  : "from-internal",
        Priority : 1,
        Timeout  : 1,
        ServersList: "",
        grData   : []
    });

    // =============== TURBOSMS ============================
    $scope[$scope.iNames.TURBOSMS]     = new ToolTurbosms($scope, $rootScope, {
        name       : $scope.iNames.TURBOSMS,
        enabled    : false,
        token      : "",
        type       : "SMS",
        sender     : "Market",
        prefix     : 380
    });
}
"use strict";

function initCustomMenu($scope){
    var view = $$($scope.Name);
    var block = 500;

    if (!view){
        $scope.mcLEB.initTextSource({
            add  : mcLang(50),
            del  : mcLang(52)
        });

        $scope.editMenuListBtn = $scope.mcLEB.editButtons({
            actions: {
                add  : $scope.menuListActions.save,
                del  : $scope.menuListActions.del
            },
            actionTitles: {
                add  : mcLang(2221), // "2221":"Добавить меню",
                del  : mcLang(2222)  // "2222":"Удалить меню?<br><b>\"%s\"</b>",
            },
            delName  : "MenuName",
            fillItems: ["MenuName"],
            editTitle: mcLang(2220), // "2220":"Название меню",
            list     : "customMenuList"
        });

        view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(2218) }, // "2218":"Пользовательское меню",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: 'layout', cols : [
                    { id: "customMenuWrapper", width: 300, rows: [
                        $scope.editMenuListBtn.btnList,

                        { view: "list", id: "customMenuList", select: true, template: "#MenuName#", on: { // template: "#ConfName# <i>(UID: #UID#)</i>",
                            onAfterSelect: $scope.selectMenu
                        }}
                    ]},

                    { view : "resizer" },
                        
                    { id: "menuDetailsWrapper", hidden: true, padding: 5, maxWidth: 600, gravity: 99, rows: [
                        { id: "menuNameEdit", view: "text", label: mcLang(2220), labelWidth: 150, on: { // "2220":"Название меню",
                            onTimedKeyPress: $scope.showApplyPanel,
                            onChange: $scope.showApplyPanel
                        }},

                        { id: "menuCodeText", view: "textarea", gravity: 3, css: "textArea", on: {
                            onTimedKeyPress: $scope.showApplyPanel,
                            onChange: $scope.showApplyPanel
                        }},

                        { height: 5},

                        { id: "selectGroup" + $scope.Name, gravity: 1, rows: [
                            { type: 'header', template: mcService.Lang(2223)}, // "2223":"Группы пользователей, подключенные к меню",

                            new mcService.ListButtonSet({
                                type   : 'combo',
                                actions: $scope.groupsActions,
                                list   : "groupList" + $scope.Name,
                                selectedItem: "Name",
                                visibleBtns: {
                                    add: true,
                                    del: true,
                                    cls: false
                                },
                                regShowWindow: $scope.regShowWindow,
                                _back: $scope.groupContainerBack
                            }),

                            { view : "list", id: "groupList" + $scope.Name, select: true, template: "#Name#"},
                        ]}
                    ]},

                    { gravity: 1}
                ]},
            ]
        });

        $scope.customMenuWrapper    = $$("customMenuWrapper");
        $scope.customMenuList       = $$("customMenuList");
        $scope.menuCodeText         = $$("menuCodeText");
        $scope.menuDetailsWrapper   = $$("menuDetailsWrapper");
        $scope.menuNameEdit         = $$("menuNameEdit");
        $scope.groupList            = $$("groupList" + $scope.Name);

        mcService.disableContextMenu(view);
    } else {

    }

    return view;
}
"use strict";

function custommenuController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.CustomMenu;

    var angElement = document.getElementById($scope.Name);
    var view       = null;
    var canChange  = true;

    var defTemplate = {
        "rootname" : "Custom menu",
        "rooticon" : 196,
        "items"    : 7,
        "item1" : {
            "name" : "Blue flag (server script)",
            "icon" : 172,
            "type" : "server-script",
            "data" : "OpenPrivateSupport",
            "params" : "%username% :)"
        },
        "item2" : {
            "name" : "Green flag (open link)",
            "icon" : 173,
            "type" : "open-link",
            "data" : "https://nsoft-s.com"
        },
        "item3" : {
            "type" : "hr"
        },
        "item4" : {
            "name" : "Tree example"
        },
        "item5" : {
            "parent" : "item4",
            "name" : "Red flag (action link)",
            "icon" : 177,
            "type" : "exec-action",
            "data" : "about",
            "params" : ""
        },
        "item6" : {
            "parent" : "item4",
            "name" : "Pill icon (Open help topic)",
            "icon" : 185,
            "type" : "open-help",
            "data" : "mychatclientwindows"
        },
        "item7" : {
            "name"   : "Disable item",
            "enable" : false
        }
    };

    $scope.mcLEB = new window.mcWidgets.ListEditButtons($rootScope);

    var groupList = [];

    function getGroupList(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_user_groups,
            mcConst.SessionID,

            function( data ){
                groupList = data;

                if ($scope.customMenuList.count()){
                    $scope.customMenuList.select($scope.customMenuList.getFirstId());
                }
            }
        ]);
    }

    // =============================================

    var _back = null; // fucking shit hack

    $scope.groupContainerBack = function(cb){
        if (cb) {
            _back = cb;
        } else {
            if (_back) _back();
        }
    };

    $scope.groupsActions = {
        preview: function (field) {
            var list = mcService.transformDataObject(webix.copy(groupList), [['Name', 'value'], ['ID', 'id']]);
            // var list = mcService.transformDataObject(webix.copy(groupList), [['ConfName', 'value'], ['ID', 'id']]);

            field.define('options', list);
            field.refresh();
            list[0] && field.setValue(list[0].id);
        },

        save: function (val) {
            var id = val.getValue();
            var menuItem = $scope.customMenuList.getSelectedItem();

            if (id != '' && !$scope.groupList.getItem(id)) {
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst._CMD_.cs_adm_add_group_to_custom_menu,
                    mcConst.SessionID,

                    menuItem.ID, // UID
                    id,

                    function () {
                        $scope.groupList.add({
                            ID: id,
                            id: id.toString(),
                            Name: val.getText()
                            // ConfName: val.getText()
                        });


                        if (!menuItem.GroupsList) {
                            menuItem.GroupsList = [id.toString()];
                        } else {
                            menuItem.GroupsList.push(id.toString());
                        }

                        // var item = $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId());
                        //
                        // if (mcService.isString(item.InviteGroups)) {
                        //     item = item.InviteGroups.split(',');
                        //
                        //     $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId()).InviteGroups = item;
                        // }
                        //
                        // item.InviteGroups.push(id);
                    }
                ]);

                return true;
            } else {
                $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",

                return false;
            }
        },

        del: function (_item) {
            var menuItem = $scope.customMenuList.getSelectedItem();

            if (menuItem){
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst._CMD_.cs_remove_groups_from_custom_menu,
                    mcConst.SessionID,

                    menuItem.ID,
                    _item.ID
                ]);

                menuItem.GroupsList.splice(menuItem.GroupsList.indexOf(_item.ID), 1);
            }

            // var item = $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId());
            //
            // if (mcService.isString(item.InviteGroups)) {
            //     item = item.InviteGroups.split(',');
            //
            //     $scope.autoChannelsList.getItem($scope.autoChannelsList.getSelectedId()).InviteGroups = item;
            // }
            //
            // var id = mcService.inArrayNoStrict(_item.ID, item.InviteGroups);
            //
            // if (id !== -1) {
            //     item.InviteGroups[id] = '';
            // }
        }
    };

    $scope.menuListActions = {
        save: function (_name){
            var name = mcService.trim(_name.getValue());
            var list = $scope.customMenuList.serialize();

            if (name != "" && mcService.findItemInArrayOfObj(list, name, 'MenuName', true) === -1) {
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_custom_menu_create,
                    mcConst.SessionID,

                    name,
                    JSON.stringify(defTemplate),

                    function (data) {
                        $scope.customMenuList.add(data);
                        $scope.customMenuList.select($scope.customMenuList.getLastId());
                        $scope.customMenuList.scrollTo(0, 9999);
                    }
                ]);
            } else {
                $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",

                return true;
            }
        },
        
        del: function (item){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_remove_custom_menu_list,
                mcConst.SessionID,

                item.ID,

                function(){
                    $scope.customMenuList.remove($scope.customMenuList.getSelectedId());

                    var lastID = $scope.customMenuList.getFirstId();

                    if (lastID) {
                        $scope.customMenuList.select(lastID);
                    } else {
                        // $scope.autoChannelInfo.hide();
                    }
                }
            ]);
        }
    };

    $scope.showApplyPanel = function (newV, oldV){
        var menuItem = $scope.customMenuList.getSelectedItem();

        if (canChange && ($scope.menuCodeText.getValue() !== menuItem.BodyJSON || $scope.menuNameEdit.getValue() !== menuItem.MenuName)) {
            canChange = false;

            var toSave = {
                data: {
                    ShowDesc : true,
                },
                onApply: function (){
                    var body     = $scope.menuCodeText.getValue();
                    var menuName = $scope.menuNameEdit.getValue();
                    var res      = false;
                    var allMenu  = $scope.customMenuList.serialize();

                    if (!mcService.trim(menuName) || (menuName !== menuItem.MenuName && mcService.findItemInArrayOfObj(allMenu, menuName, "MenuName") >= 0)){
                        $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",
                    } else

                    try {
                        JSON.parse(body);

                        menuItem.BodyJSON = body;
                        menuItem.MenuName = menuName;

                        $scope.customMenuList.updateItem(menuItem.id, menuItem);

                        $scope.editMenuListBtn.enable();
                        $scope.customMenuList.enable();

                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst.lockInterface,
                            mcConst._CMD_.cs_adm_modify_custom_menu,
                            mcConst.SessionID,

                            menuItem.ID,
                            menuName,
                            body
                        ]);

                        res = true;
                    } catch (e){
                        webix.alert({
                            type : "alert-error",
                            ok   : mcLang(12), // "12" : "Закрыть",
                            text : e.message,
                            callback: function(){
                                setTimeout(function(){
                                    var errTxt = e.message.split(' ');
                                    var idx = errTxt.indexOf('position');

                                    if (idx !== -1){
                                        var pos = errTxt[idx + 1];

                                        $scope.menuCodeText.focus();

                                        mcService.setCaretPosition($scope.menuCodeText.getInputNode(), pos, 1);
                                    }
                                }, 20);
                            }
                        })
                    }

                    setTimeout(function (){
                        canChange = true;
                    }, 100);

                    return res;
                },
                onClose: function (){
                    var menuItem = $scope.customMenuList.getSelectedItem();

                    $scope.editMenuListBtn.enable();
                    $scope.customMenuList.enable();

                    $scope.menuCodeText.setValue(JSON.stringify(JSON.parse(menuItem.BodyJSON), undefined, 2));
                    $scope.menuNameEdit.setValue(menuItem.MenuName);

                    setTimeout(function (){
                        canChange = true;
                    }, 100);
                }
            };

            $scope.editMenuListBtn.disable();
            $scope.customMenuList.disable();

            $rootScope.$broadcast('show' + mcConst.dataModels.ApplyPanel, [toSave]);
        }

        // $scope.rcPresetList   .disable();
        // $scope.rcAddPresetList.disable();
        // $scope.rcDelPresetList.disable();
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_custom_menu_list,
            mcConst.SessionID,

            function (data){
                data.forEach(function (item){
                    if (mcService.isString(item.GroupsList)){
                        item.GroupsList = item.GroupsList.split(',');
                    }

                    item.BodyJSON   = JSON.stringify(JSON.parse(item.BodyJSON), undefined, 2);
                });

                $scope.customMenuList.clearAll();
                $scope.customMenuList.parse(data);

                $scope.groupContainerBack();
                getGroupList();
            }
        ]);
    };

    $scope.selectMenu = function (){
        var item = $scope.customMenuList.getSelectedItem();

        $scope.groupList.clearAll();
        
        if (item){
            canChange = false;

            $scope.menuCodeText.setValue(JSON.stringify(JSON.parse(item.BodyJSON), undefined, 2));
            $scope.menuDetailsWrapper.show();

            $scope.menuNameEdit.setValue(item.MenuName);

            setTimeout(function (){
                canChange = true;

                $scope.menuCodeText.getInputNode().onpaste = function() {
                    setTimeout(function (){
                        $scope.showApplyPanel();
                    }, 100);
                };
            }, 100);
        }

        if (item.GroupsList){
            var res = [];

            for (var i = 0; i < item.GroupsList.length; i++)
                if (item.GroupsList[i].length !== 0){
                    var newItem = groupList[mcService.findItemInArrayOfObj(groupList, item.GroupsList[i], 'ID')];

                    if (newItem) {
                        newItem.id = item.GroupsList[i];
                        res.push(newItem);
                    }
                }

            $scope.groupList.parse(res);
        }

        $scope.groupContainerBack();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        view = initCustomMenu($scope);

        mcService.initResize(view, $scope.Name);

        view.adjust();
    };

    $scope.$on('hide' + $scope.Name, function() {
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function() {
        $scope.show();
        $scope.getData();
    });

}
function initTestport($scope){
    "use strict";

    var _view = $$($scope.Name);
    var labelWidth   = 380;
    var blockWidth   = 600;

    if (!_view){
        _view = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view: "template", type: "header", template: mcService.Lang(2225) }, // "2225":"Тест портов",
                    { view: "toolbar", width: 36, cols: [
                        { view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type: 'layout', padding: 5, cols: [
                    { rows : [
                        { template: mcService.insertIco("fa-info-circle") + mcLang(2114), width: blockWidth, autoheight: true, borderless: true, css: "_info"}, // "2114":"Проверка доступности вашего сервера из интернета.<br><br>В процессе проверки будет отправлен запрос на mychat-server.com для теста ваших портов.",
                        { id: "stgCheckBtn", view: "button", value: mcLang(926), click: $scope.checkExternalConnections}, // "926":"Проверить подключение",
                        { id: "stgCheckConnectionsResult", template: "&nbsp;", css: "monospace selectable", width: blockWidth, autoheight: true, hidden: true, onClick : $scope.gotoSettings}
                    ]},
                    {}
                ]},
            ]
        });

        $scope.stgCheckBtn               = $$("stgCheckBtn");
        $scope.stgCheckConnectionsResult = $$("stgCheckConnectionsResult");
    }

    return _view;
}

function testportController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.Testport;

    var element = document.getElementById($scope.Name);
    var view = null;

    $scope.checkExternalConnections = function (){
        if ($rootScope.mcStorage.SettingsNetwork.ExternalIP) {
            $rootScope.$broadcast(mcConst.lockInterface);

            $scope.stgCheckConnectionsResult.show();

            var url = "http" + ($rootScope.mcStorage.SettingsNetwork.WEBUseSSL ? "s" : "") + "://mychat-server.com" + ($rootScope.mcStorage.SettingsNetwork.WEBUseSSL ? ":8484" : "");

            var turnPort = $rootScope.mcStorage.SettingsNetwork.TURNPortTCP;

            if (!$rootScope.mcStorage.SettingsNetwork.TURNUseAutoConfig){
                var configFile = $rootScope.mcStorage.SettingsNetwork.TURNFullTextConfig;

                if (mcService.isString(configFile)){
                    configFile = configFile.replace(/\r/g, "").split('\n');

                    for (var i=0; i < configFile.length; i++){
                        var line = mcService.trim(configFile[i]);

                        if (line.indexOf("listening-port") === 0){
                            turnPort = line.split("=")[1];
                            turnPort = parseInt(turnPort);

                            break;
                        }
                    }
                }
            }

            var outData = {
                HOST : $rootScope.mcStorage.SettingsNetwork.ExternalIP,
                SSL  : $rootScope.mcStorage.SettingsNetwork.WEBUseSSL,
                WEB  : $rootScope.mcStorage.SettingsNetwork.WEBTCPPort,
                CORE : $rootScope.mcStorage.SettingsNetwork.TCPPort,
                TURN : isNaN(turnPort) ? $rootScope.mcStorage.SettingsNetwork.TURNPortTCP : turnPort,
                FTP  : $rootScope.mcStorage.SettingsNetwork.FTPPort,
                VER  : window.__serverVer
            };

            url = url + "/checkMyPorts?q=" + encodeURI(JSON.stringify(outData));

            $rootScope.SendCMDToServer([
                mcConst.lockInterface,
                mcConst._CMD_.checkPush,
                mcConst.SessionID,

                function (push) {
                    mcService.jsonp(url, function (result) {
                        $rootScope.$broadcast("hide" + mcConst.lockInterface);

                        var input = "Result: " + result + "<br><br>URL: " + url + "<br><br>Request: " + JSON.stringify(outData);

                        if (result === "incorrect data") {
                            $scope.stgCheckConnectionsResult.define("template", input);
                        } else {
                            var data = mcService.StringToObj(result);

                            if (mcService.isObject(data)) {
                                $scope.stgCheckConnectionsResult.define("template", mcService.myReplaceFormated(
                                    "#{HOST}<br>" +
                                    "#{SSL} <br>" +
                                    "#{WEB} <br>" +
                                    "#{CORE}<br>" +
                                    "#{TURN}<br>" +
                                    "#{PUSH}<br>" +
                                    "#{FTP} <br><br>" +
                                    "Request: " + JSON.stringify(outData),
                                    {
                                        HOST: "HOST: " + (data.HOST === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2117) // "2117":"Внешний адрес доступен",
                                            : mcService.insertIco("fa-close", "red") + data.HOST + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortExternalHostError.htm", mcLang(1592))), // "1592":"Справка",
                                        SSL: "SSL : " + ($rootScope.mcStorage.SettingsNetwork.WEBUseSSL ? (data.SSL === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2118) // "2118":"Сертификат проверен",
                                            : mcService.insertIco("fa-close", "red") + data.SSL + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortHTTPSError.htm", mcLang(1592))) : (mcLang(2123) + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortHTTPSError.htm", mcLang(1592)))), // "2123":"Не используется",
                                        WEB: "WEB : " + (data.WEB === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2119) // "2119":"Web-сервер доступен",
                                            : mcService.insertIco("fa-close", "red") + data.WEB + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortWebServerError.htm", mcLang(1592))),
                                        CORE: "CORE: " + (data.CORE === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2120) // "2120":"MyChat доступен",
                                            : mcService.insertIco("fa-close", "red") + data.CORE + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortCoreError.htm", mcLang(1592))),
                                        TURN: "TURN: " + (data.TURN === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2121) // "2121":"TURN для звонков доступен",
                                            : mcService.insertIco("fa-close", "red") + data.TURN + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortTurnError.htm", mcLang(1592))),
                                        FTP: "FTP : " + (data.FTP === true
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2122) // "2122":"файловый сервер доступен",
                                            : mcService.insertIco("fa-close", "red") + data.FTP + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortFTPError.htm", mcLang(1592))),
                                        PUSH: "PUSH: " + (push === true && !data.NOPUSH
                                            ? mcService.insertIco("fa-check", "green") + mcLang(2124) // "2124":"Отправка PUSH сообщений",
                                            : !data.NOPUSH
                                                ? mcService.insertIco("fa-close", "red") + push + " " + mcService.getHelpLink("/serverhelp/index.html?MyChatServerTestPortPushError.htm", mcLang(1592))
                                                : mcService.insertIco("fa-close", "red") + "Your MyChat server is out of date, PUSH notifications will not work. Please, update the server to the latest version")
                                    }
                                ));
                            } else {
                                $scope.stgCheckConnectionsResult.define("template", input);
                            }
                        }

                        $scope.stgCheckConnectionsResult.refresh();
                    }, function () {
                        $rootScope.$broadcast("hide" + mcConst.lockInterface);

                        $scope.stgCheckConnectionsResult.define("template", mcLang(2116)); // "2116":"Нет доступа к mychat-server.com",
                        $scope.stgCheckConnectionsResult.refresh();
                    });
                }
            ]);
        } else {
            $scope.stgCheckConnectionsResult.show();
            $scope.stgCheckConnectionsResult.define("template", mcLang(2115) + " \"" + mcLang(931) + "\"<br><a class='goToNetworkSettings finger linkItem blue'>" + mcLang(1690) + "</a>"); // "2115":"Не указан", "931":"IP или Host адрес сервера для внешних клиентов", "1690":"Перейти в раздел редактирования настроек",
            $scope.stgCheckConnectionsResult.refresh();
        }
    };

    $scope.gotoSettings = {
        "goToNetworkSettings" : function(){
            $rootScope.$broadcast('setLocation', ['/navSettings/SettingsNetwork/']);
            $rootScope.$broadcast('changeLocation', []);
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, element);

        view = initTestport($scope);

        mcService.initResize(view, $scope.Name);
    };

    //===================================================

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(element);
    });

    $scope.$on('show' + $scope.Name, function(){
        mcService.getMcSettings($rootScope, $scope.show, true);
    });
}


function toolGeoIpView(geoip, $scope) {
    var view = { id: "view_" + geoip.name, hidden: $scope.shovedView !== geoip.name, rows: [
        { id: "note" + geoip.name, template: "&nbsp;", css: "_info selectable", autoheight: true },

        {}
    ]};

    geoip.initView = function () {
        if (geoip.initialized) return;
        
        geoip.note  = $$("note" + geoip.name);

        geoip.initialized = true;
    };

    return view;
}

function ToolGeoIP($scope, $rootScope, options) {
    var geoip     = this;

    function fillOptions(opts){
        Object.keys(opts).forEach(function (item) {
            geoip[item] = opts[item];
        });
    }

    //========================================================

    fillOptions(options);

    //========================================================

    geoip.fillOptions = fillOptions;

    geoip.fillTool = function () {
        var link = mcService.getLocalHostPath(true) + "/serverhelp/index.html?integrationapigeoip.htm";

        if (geoip.enabled) {
            geoip.note.define('template', mcService.insertIco("fa-info-circle") + " " + mcLang(1939, [link])); // "1939":"Интеграция с GeoIP включена!",
        } else {
            var path = "C:\\ProgramData\\MyChat Server\\integrations\\geoip\\";

            geoip.note.define('template', mcService.insertIco("fa-info-circle") + " " + mcLang(1940, [path, link])); // "1940":"Интеграция с GeoIP отключена!
        }

        geoip.note.refresh();
    };

    geoip.saveData = function(){
        return {};
    };

    geoip.getView = function () {
        return toolGeoIpView(geoip, $scope);
    };
}

function toolIcqView(icq, $scope) {
    var view = { id: "view_" + icq.name, hidden: $scope.shovedView !== icq.name, rows: [
        { view: "checkbox", id: "enable" + icq.name, value: icq.enabled, labelWidth: 0, css: "finger",
            labelRight: mcService.Lang(1753, "ICQ"), // "1753":"Включить интеграцию с %s",
            on: { onItemClick: $scope.change }
        },

        { height: 5},

        { template: mcService.insertIco("fa-info-circle") + " ", css: "_info selectable", autoheight: true},

        { height: 5},

        { id: "UsersList" + icq.name, view: "datatable",
            editable       : true,
            resizeColumn   : true,
            checkboxRefresh:true,
            columns        : [

            ]
        }
    ]};

    icq.initView = function () {
        if (icq.initialized) return;

        icq.enableICQ  = $$("enable" + icq.name);

        icq.initialized = true;
    };

    return view;
}

function ToolIcq($scope, $rootScope, options) {
    var icq     = this;

    function fillOptions(opts){
        Object.keys(opts).forEach(function (item) {
            icq[item] = opts[item];
        });
    }

    //========================================================

    fillOptions(options);

    //========================================================

    icq.fillOptions = fillOptions;

    icq.fillTool = function () {
        icq.enableICQ.setValue(icq.enabled);
    };

    icq.saveData = function(){
        return {};
    };

    icq.getView = function () {
        return toolIcqView(icq, $scope);
    };
}
function toolPhpbbView(phpbb, $scope) {
    "use strict";

    function fillList(obj) {
        var res = "";

        if (obj.UIN) { // users
            res = obj.DisplayName + " <span class='toRight'>(UIN: " + obj.UIN + ")</span>";
        } else
        if (obj.UID) { // groups
            res = obj.ConfName + " <span class='toRight'>(UID: " + obj.UID + ")</span>";
        } else
        if (obj.ID) {  // confs
            res = obj.Name;
        }

        return res;
    }

    var view = { id: "view_" + phpbb.name, hidden: $scope.shovedView !== phpbb.name, rows: [
        { view: "checkbox", id: "enable" + phpbb.name, value: '', labelWidth: 0, css: "finger",
            labelRight: mcService.Lang(1753, 'phpBB 3'), // "1753":"Включить интеграцию с %s",
            on: { onItemClick: $scope.change }
        },

        { height: 5},

        { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1747), css: "_info selectable", autoheight: true}, // "1747":"<b>Информация</b

        { height: 2},

        { template: mcService.Lang(1741), borderless: true, autoheight: true }, // "1741":"Шаблон сообщения:",

        { id: 'pattern_' + phpbb.name, view: "textarea", value: "", css: 'textArea',
            on: { onTimedKeyPress: function () {
                if (this.getValue() !== phpbb.pattern) {
                    $scope.change();
                }
            }}
        },

        { view: "resizer", borderless: true},

        { cols: [
            { rows: [
                { cols: [
                    { template: mcLang(1743), type: "header", borderless: true}, // "1743":"Список получателей",
                    { view: "toolbar", borderless: true, width: 160, cols: [
                        { id: "btnAddDel" + phpbb.Name, view: "button", value: mcLang(50), popup: "listPopup" + phpbb.name} // "50" : "Добавить", "1752":"Добавить/удалить",
                    ]}
                ]},

                { id: "itemList_" + phpbb.name, view: "activeList" , data: [], // unitlist
                    activeContent:{
                        deleteButton: { view: "button", type: "icon", icon: "trash-o", width: 26, height: 25, css: "toRight", click: phpbb.deleteItem,
                            tooltip: mcLang(52) // "52" : "Удалить", "1754":"Удалить элемент",
                        }
                    },

                    uniteBy: function (obj) {
                        var res = "";

                        if (obj.UIN) { // users
                            res = mcLang(16); // "16" : "Пользователи",
                        } else
                        if (obj.UID) { // groups
                            res = mcLang(31); // "31" : "Конференции",
                        } else
                        if (obj.ID) {  // confs
                            res = mcLang(1722); // "1722":"Группы пользователей",
                        }

                        return res;
                    },

                    template: function (obj, common) {
                        var res = "";

                        if (obj.UIN) { // users
                            res = obj.DisplayName + common.deleteButton(obj, common) + " <span class='toRight'>(UIN: " + obj.UIN + ")</span>";
                        } else
                        if (obj.UID) { // groups
                            res = obj.ConfName + common.deleteButton(obj, common) + " <span class='toRight'>(UID: " + obj.UID + ")</span>";
                        } else
                        if (obj.ID) {  // confs
                            res = obj.Name + " " + common.deleteButton(obj, common);
                        }

                        return res;
                    }
                }
            ]},

            { width: 7},
            { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1742), css: "_info selectable"} // "1742":"<b>Константы</b>:
        ]}
    ]};

    phpbb.initView = function () {
        if (phpbb.initialized) return;

        webix.ui({
            view  : "popup",
            id    : "listPopup" + phpbb.name,
            width : 170,
            height: 84,
            padding: 0,
            body  : {
                view: "list", data: [
                    { id: "users",  value: mcLang(1744)}, // "1744":"Пользователя",
                    { id: "groups", value: mcLang(1745)}, // "1745":"Группу пользователей",
                    { id: "confs",  value: mcLang(1746)}  // "1746":"Конференцию",
                ],
                scroll: false,
                select: true,
                on: {
                    onAfterSelect: function (val) {
                        var pp = this.getTopParentView();

                        pp.hide();
                        pp.getChildViews()[0].unselectAll();

                        phpbb.php_fillAllItemList(val);
                    },
                    onShow: function () {
                        $scope.regShowWindow(mcService.RandomHash(4), this);
                    }
                }
            }
        }).hide();

        phpbb.selectWindow = webix.ui({
            view    : "window",
            position: "center",
            modal   : true,
            head    : false,
            width   : 600,
            height  : 500,
            body    : { padding: 5, rows: [
                { cols: [
                        { view: "label", label: mcLang(1749), align: "center"}, // "1749":"Выбранные",
                        { view: "label", label: mcLang(1748), align: "center"}, // "1748":"Доступны для выбора",
                        { view: "button", type: 'icon', width: 28, icon: 'times', css: "button_transparent", tooltip: mcLang(12), click: function () { //"12" : "Закрыть",
                            this.getTopParentView().hide();
                        }}
                    ]},

                { cols: [
                    { width: 1},
                    { rows: [
                        new mcService.FilterFiled({
                            listName : "currentItemList" + phpbb.Name,
                            filterParams : [
                                "DisplayName",
                                "ConfName",
                                "Name",
                                "UIN",
                                "UID",
                                "ID"
                            ]
                        }),
                        { id: "currentItemList" + phpbb.Name,
                            view       : "list",
                            template   : fillList,
                            select     : true,
                            drag       : true,
                            multiselect: "touch",
                            onContext  : {}
                        }
                        // { id: "currentItemList" + phpbb.Name,
                        //     headerRowHeight: 25,
                        //     minColumnWidth : 70,
                        //     view           : "datatable",
                        //     resizeColumn   : true,
                        //     drag           : true,
                        //     select         : "row",
                        //     multiselect    : true,
                        //     navigation     : false,
                        //     onContext      : {}
                        // }
                    ]},

                    { width: 4},
                    { width: 30, rows: [
                        {},
                        { view: "button", type: "prev", value: "<", click: function () {
                            phpbb.moveByButton("allItemList", "currentItemList");
                        }},

                        { height: 20},

                        { view: "button", type: "next", value: ">", click: function () {
                            phpbb.moveByButton("currentItemList", "allItemList");
                        }},
                        {}
                    ]},
                    { width: 4},

                    { rows: [
                        new mcService.FilterFiled({
                            listName : "allItemList" + phpbb.Name,
                            filterParams : [
                                "DisplayName",
                                "ConfName",
                                "Name",
                                "UIN",
                                "UID",
                                "ID"
                            ]
                        }),
                        { id : "allItemList" + phpbb.Name,
                            headerRowHeight: 25,
                            minColumnWidth : 70,
                            view           : "datatable",
                            resizeColumn   : true,
                            drag           : true,
                            select         : "row",
                            multiselect    : true,
                            navigation     : false,
                            onContext      : {}
                        }
                    ]}
                ]},

                { height: 7},

                { cols: [
                    // { view: "button", label: mcLang(103), type: "danger", click: function () { // "103": "Отмена",
                    //     this.getTopParentView().hide();
                    // }},

                    // { width: 38},
                    { gravity: 2 },

                    { view: "button", value: mcLang(104), click: function () { // "104": "Сохранить",
                        phpbb.update();

                        this.getTopParentView().hide();
                    }}
                ]}
            ]},
            on : {
                onShow: function () {
                    phpbb.regHotKeys();
                },
                onHide: function () {
                    phpbb.removeHotKeys();
                }
            }
        });

        phpbb.currentItemList = $$("currentItemList" + phpbb.Name);
        phpbb.allItemList     = $$("allItemList"     + phpbb.Name);

        new mcService.ContextMenu(phpbb.currentItemList, null, null, function(){
            $scope.regShowWindow(this.config.id, this);
        });

        new mcService.ContextMenu(phpbb.allItemList, null, null, function(){
            $scope.regShowWindow(this.config.id, this);
        });

        phpbb.pattern_phpbb3  = $$("pattern_"  + phpbb.name);
        phpbb.itemList_phpbb3 = $$("itemList_" + phpbb.name);
        phpbb.enablePhpbb3    = $$("enable"    + phpbb.name);
        phpbb.btnAddDel       = $$("btnAddDel" + phpbb.Name);

        phpbb.initialized = true;
    };

    return view;
}

function ToolPhpBB($scope, $rootScope, options) {
    var phpbb     = this;
    var PHPHOTKEY = "PHPHOTKEY";

    function fillOptions(opts){
        /*
         "name"     : "phpbb3",     // название инструмента, от него зависит набор настроек
         "enabled"  : true,         // включен или выключен интеграционный инструмент
         "template" : "bla-bla-bla" // текст шаблона сообщения
         "uins"     : "17,3,4",     // список UIN-ов пользователей, которым будет отправляться сообщение, через запятую
         "uids"     : "",           // список UID-ов автосоздаваемых конференций, в которых будет отправляться сообщение, через запятую
         "groupids" : ""            // список ID групп пользователей, для которых будет отправляться сообщение, через запятую
        */

        Object.keys(opts).forEach(function (item) {
            phpbb[item] = opts[item];
        });

        phpbb.pattern         = opts.template;

        phpbb.itemList.confs  = opts.uids     === "" ? [] : opts.uids;
        phpbb.itemList.groups = opts.groupids === "" ? [] : opts.groupids;
        phpbb.itemList.users  = opts.uins     === "" ? [] : opts.uins;

        if (phpbb.itemList.confs && phpbb.itemList.confs.length) {
            phpbb.itemList.confs.forEach(function (conf) {
                conf.ConfName = conf.Name;
            });
        }
    }

    function removeExcess(itemList, itemName, param) {
        var res = webix.copy(itemList).map(function (item) {
            return mcService.findItemInArrayOfObj(phpbb.itemList[itemName], item[param], param) === -1 ? item : undefined;
        });

        res.sort(function (a, b) {
            return mcService.sortAB(a[param], b[param]);
        });

        if (res.length){
            while (res[res.length - 1] === undefined){
                res.pop();
            }
        }

        return res;
    }

    function phpbb3_fillAndShowSelectWindow(left, right) {
        phpbb.selectWindow.show();

        phpbb.currentItemList.clearAll();
        phpbb.currentItemList.parse(left);

        phpbb.allItemList.clearAll();

        switch (phpbb.changing) {
            case "users":
                phpbb.allItemList.refreshColumns([
                    { id:"UIN",         header:"UIN", width: 55,     sort:"int"},
                    { id:"DisplayName", header:mcService.Lang(1895), sort:"string", fillspace: true}, // "1895":"Отображаемое имя",
                ]);
            break;

            case "confs":
                phpbb.allItemList.refreshColumns([
                    { id:"UID",      header:"UID", width: 55,     sort:"int"},
                    { id:"ConfName", header:mcService.Lang(1088), sort:"string", fillspace: true}, // "1088":"Названия конференций",
                ]);
            break;

            case "groups":
                phpbb.allItemList.refreshColumns([
                    { id:"ID",   header:"ID", width: 55,      sort:"int"},
                    { id:"Name", header:mcService.Lang(1722), sort:"string", fillspace: true}, // "1722":"Группы пользователей",
                ]);
            break;
        }

        phpbb.allItemList.parse(right);

        $scope.regShowWindow(mcService.RandomHash(4),phpbb.selectWindow);
    }

    //========================================================

    fillOptions(options);

    //========================================================

    phpbb.regHotKeys = function(){
        $rootScope.hotKeyDispatcher.addPreset(PHPHOTKEY, [{
            key:  mcConst.keyCodes.esc,
            func: function(){
                phpbb.selectWindow.hide();
            }
        }, {
            key:  mcConst.keyCodes.enter,
            func: function(){
                phpbb.update();
                phpbb.selectWindow.hide();
            }
        }], document);
    };

    phpbb.removeHotKeys = function(){
        $rootScope.hotKeyDispatcher.removePreset(PHPHOTKEY);
    };

    phpbb.php_fillAllItemList = function (listName) {
        switch (listName){
            case "users":
                mcService.getAllUserWithParams(function (itemList) {
                    phpbb.changing = "users";

                    phpbb3_fillAndShowSelectWindow(phpbb.itemList.users, removeExcess(itemList, phpbb.changing, 'UIN'));
                }, $rootScope, "All");
            break;

            case "confs":
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_auto_conf_list,
                    mcConst.SessionID,
                    function( itemList ){
                        phpbb.changing = "confs";

                        phpbb3_fillAndShowSelectWindow(phpbb.itemList.confs, removeExcess(itemList, phpbb.changing, 'UID'));
                    }
                ]);
            break;

            case "groups":
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_user_groups,
                    mcConst.SessionID,
                    function( itemList ){
                        phpbb.changing = "groups";

                        phpbb3_fillAndShowSelectWindow(phpbb.itemList.groups, removeExcess(itemList, phpbb.changing, 'ID'));
                    }
                ]);
            break;
        }
    };

    phpbb.moveByButton = function(from, to){
        var selectedItems = phpbb[from].getSelectedItem();
        var uList = [];

        if (mcService.isObject(selectedItems)){
            selectedItems = [selectedItems];
        }

        if (selectedItems){
            for (var i = 0; i < selectedItems.length; i++){
                uList.push(phpbb[from].getItem(selectedItems[i].id || selectedItems[i]));
            }

            phpbb[to].parse(uList);
            phpbb[from].remove(phpbb[from].getSelectedId());
        }
    };

    phpbb.deleteItem = function () {
        var idx  = this.getNode().parentNode.getAttribute("webix_item_id");
        var item = phpbb.itemList_phpbb3.getItem(idx);

        if (item.UIN) {
            phpbb.itemList.users.splice(mcService.findItemInArrayOfObj(phpbb.itemList.users, item.UIN, "UIN"), 1);
        } else
        if (item.UID){
            phpbb.itemList.confs.splice(mcService.findItemInArrayOfObj(phpbb.itemList.confs, item.UID, "UID"), 1);
        } else
        if (item.ID){
            phpbb.itemList.groups.splice(mcService.findItemInArrayOfObj(phpbb.itemList.groups, item.ID, "ID"), 1);
        }

        phpbb.itemList_phpbb3.remove(idx);

        $scope.saveData(phpbb.name);
    };

    phpbb.fillOptions = fillOptions;

    phpbb.saveData = function(){
        return {
            // название инструмента, от него зависит набор настроек
            name     : phpbb.name,

            // включен или выключен интеграционный инструмент
            enabled  : mcService.convertIntToBool(phpbb.enablePhpbb3.getValue()),

            // текст шаблона сообщения
            template : phpbb.pattern_phpbb3.getValue(),

            // список UIN-ов пользователей, которым будет отправляться сообщение, через запятую
            uins     : (phpbb.itemList.users.map(function (item) {
                return item.UIN;
            })).join(','),

            // список UID-ов автосоздаваемых конференций, в которых будет отправляться сообщение, через запятую
            uids     : (phpbb.itemList.confs.map(function (item) {
                return item.UID;
            })).join(','),

            // список ID групп пользователей, для которых будет отправляться сообщение, через запятую
            groupids : (phpbb.itemList.groups.map(function (item) {
                return item.ID;
            })).join(',')
        };
    };

    phpbb.fillTool = function(){
        phpbb.pattern_phpbb3.setValue(phpbb.pattern);
        phpbb.enablePhpbb3.setValue(phpbb.enabled);

        phpbb.itemList_phpbb3.clearAll();
        phpbb.itemList_phpbb3.parse([]
            .concat(webix.copy(phpbb.itemList.confs))
            .concat(webix.copy(phpbb.itemList.groups))
            .concat(webix.copy(phpbb.itemList.users))
        );
    };

    phpbb.update = function () {
        var list = phpbb.currentItemList.serialize();

        list.forEach(function (item) {
            if (item.id) {
                delete item.id;
            }

            Object.keys(item).forEach(function (sub) {
                if (sub[0] === "$"){
                    delete item[sub];
                }
            })
        });

        phpbb.itemList[phpbb.changing] = list;

        $scope.saveData(phpbb.name);
    };

    phpbb.getView = function () {
        return toolPhpbbView(phpbb, $scope);;
    };
}

function toolQuizView(quiz, $scope) {
    var labelWidth = 450;

    var view = { id: "view_" + quiz.name, hidden: $scope.shovedView !== quiz.name, cols: [
        { id: "mainView" + quiz.name,  hidden: !quiz.db, rows: [
            { view: "checkbox", id: "enable" + quiz.name, value: quiz.enabled, labelWidth: 0, css: "finger",
                labelRight: mcService.Lang(1998), // "1998":"Включить викторину",
                on: { onItemClick: $scope.change }
            },

            { height: 5},

            { cols: [
                { id:'ConfID' + quiz.name, width: labelWidth + 102, view: "combo", label: mcLang(1033) + ":", labelWidth: 150, value: quiz.ConfID, options: quiz.chList, keyPressTimeout: 100, // "1033":"Конференция",
                    on: { onChange: $scope.change }
                },
                {}
            ]},

            { cols: [
                { width: labelWidth + 110, rows: [
                    { id: "TimeAnswer" + quiz.name, view: "counter", value: quiz.TimeAnswer, step: 1, min: 1, max: 9999, labelWidth: labelWidth,
                        label: mcLang(1999), // "1999":"Время для ответа",
                        on: {
                            onChange: $scope.change, onKeyPress: mcService.checkNumbersCounter
                        }},

                    { id: "TimePauseAfterCorrectAnswer" + quiz.name, view: "counter", value: quiz.TimePauseAfterCorrectAnswer, labelWidth: labelWidth, step: 1, min: 1, max: 999,
                        label: mcLang(2001), // "2001":"Пауза после правильного ответа",
                        on: {
                            onChange: $scope.change, onKeyPress: mcService.checkNumbersCounter
                        }},

                    { id: "StopAfterNFails" + quiz.name, view: "counter", value: quiz.StopAfterNFails, labelWidth: labelWidth, step: 1, min: 1, max: 999, //width: 100,
                        label: mcLang(2002), // "2002":"Остановка викторины после",
                        on: {
                            onChange: $scope.change, onKeyPress: mcService.checkNumbersCounter
                        }},

                    { id: "MinPlayersCount" + quiz.name, view: "counter", value: quiz.MinPlayersCount, labelWidth: labelWidth, step: 1, min: 1, max: 999, //width: 100,
                        label: mcLang(2003), // "2003":"Минимальное количество игроков",
                        on: {
                            onChange: $scope.change, onKeyPress: mcService.checkNumbersCounter
                        }},

                    { id: "TimePauseAfterStart" + quiz.name, view: "counter", value: quiz.TimePauseAfterStart, labelWidth: labelWidth, step: 1, min: 1, max: 999, //width: 100,
                        label: mcLang(2004), // "2004":"Пауза после запуска",
                        on: {
                            onChange: $scope.change, onKeyPress: mcService.checkNumbersCounter
                        }},

                    { id: "TimePauseAfterNoAnswers" + quiz.name, value: quiz.TimePauseAfterNoAnswers, view: "counter", labelWidth: labelWidth, step: 1, min: 1, max: 999, //width: 100,
                        label: mcLang(2005), // "2005":"Пауза после сообщения об отсутствии правильного ответа",
                        on: {
                            onChange: $scope.change, onKeyPress: mcService.checkNumbersCounter
                        }},
                ]},
                { rows: [
                        { view: "label", label: mcLang(1379)}, // "1379":"секунд",
                        { view: "label", label: mcLang(1379)}, // "1379":"секунд",
                        { view: "label", label: mcLang(2013)}, // "2013":"неправильных ответов",
                        { view: "label", label: ""}, //
                        { view: "label", label: mcLang(1379)}, // "1379":"секунд",
                        { view: "label", label: mcLang(1379)}  // "1379":"секунд",
                ]}
            ]},

            { id: "ShowAnswers" + quiz.name, view: "checkbox", value: quiz.ShowAnswers, labelWidth: 0, css: "finger",
                labelRight: mcService.Lang(2006), // "2006":"Показывать ответ, если никто не ответил правильно",
                on: { onItemClick: $scope.change }
            },

            { id: "ShowQuestionNumbers" + quiz.name, view: "checkbox", value: quiz.ShowQuestionNumbers, labelWidth: 0, css: "finger",
                labelRight: mcService.Lang(2007), // "2007":"Указывать номер вопроса",
                on: { onItemClick: $scope.change }
            },

            { id: "EnableHints" + quiz.name, view: "checkbox", value: quiz.EnableHints, labelWidth: 0, css: "finger",
                labelRight: mcService.Lang(2008), // "2008":"Разрешить подсказки",
                on: { onItemClick: $scope.change }
            },

            { height: 10},

            { cols: [
                { id: "stat" + quiz.name, template: mcService.insertIco("fa-info-circle") + "", css: "_info", autoheight: true, width: labelWidth + 97},
                {}
            ]},

            { height: 10},

            { cols: [
                { id: "question" + quiz.name, view: "text", width: labelWidth, placeholder: mcLang(2014), // "2014":"Вопрос",
                    on: { onKeyPress: quiz.enterQuestion}
                },
                { view: "button", value: mcLang(2015), width: 102, click: quiz.findQuestion }, // "2015":"найти",
                { id: "clearQ" + quiz.name, view: "button", value: mcLang(619).toLowerCase(), width: 102, click: quiz.clear, disabled: true }, // "619": "Очистить",
                {}
            ]},

            { id: "", cols: [
                { view: "label", label: mcLang(2017), width: 70}, // "2017":"Ответ:",
                { id: "answer" + quiz.name, view: "text", width: labelWidth + 102 - 70},
                {}
            ]},

            { cols: [
                { id: "questionNumb" + quiz.name, view: "label", label: mcLang(2016) + " "}, // "2016":"Номер вопроса",
                { gravity: 0}
            ]},

            { id: "", cols: [
                { id: "addQ" + quiz.name,  view: "button", value: mcLang(50), width: (labelWidth + 102) / 3, click: quiz.addQuestion},                  // "50" : "Добавить",
                { id: "editQ" + quiz.name, view: "button", value: mcLang(51), width: (labelWidth + 102) / 3, click: quiz.editQuestion, disabled: true}, // "51" : "Изменить",
                { id: "delQ" + quiz.name,  view: "button", value: mcLang(52), width: (labelWidth + 102) / 3, click: quiz.delQuestion, disabled: true }, // "52" : "Удалить",
                {}
            ]},
                
            {}
        ]},

        { id: "downloadView" + quiz.name, hidden: quiz.db, rows: [
            { template: mcService.insertIco("fa-info-circle") + mcLang(2011), autoheight: true, css: "_info" }, // "2011":"Нет базы данных с вопросами",
            { height: 5},
                
            { cols: [
                { width: 300, rows: [
                    { view: "button", value: mcLang(2012), click: quiz.downloadBD}, // "2012":"Как установить?",
                ]},
                {}
            ]},

            {}
        ]},

        { gravity: 0}
    ]};

    quiz.initView = function () {
        if (quiz.initialized) return;

        quiz.ConfList       = $$('ConfID' + quiz.name);
        quiz.downloadView   = $$("downloadView" + quiz.name);
        quiz.mainView       = $$("mainView" + quiz.name);
        quiz.question       = $$("question" + quiz.name);
        quiz.answer         = $$("answer" + quiz.name);
        quiz.questionNumb   = $$("questionNumb" + quiz.name);
        quiz.addQ           = $$("addQ" + quiz.name);
        quiz.editQ          = $$("editQ" + quiz.name);
        quiz.delQ           = $$("delQ" + quiz.name);
        quiz.clearQ         = $$("clearQ" + quiz.name);
        quiz.stat           = $$("stat" + quiz.name);

        quiz.initialized = true;
    };

    return view;
}

/*
          - кнопка для скачивания базы данных с вопросами

 - кнопка "Получить ответ на вопрос"
 - раздел с краткой инфой о роботе (на жёлтом фоне, описалово)
 - удалить вопрос
 - изменить вопрос
 - добавить вопрос
 - очистить базу вопросов
 - импорт из файла
*/


function ToolQuiz($scope, $rootScope, options) {
    var quiz          = this;
    var curQuestionID = "";

    this.chList = {};

    function fillOptions(opts){
        Object.keys(opts).forEach(function (item) {
            quiz[item] = opts[item];
        });
    }

    function getStat() {
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_integration_quiz_get_stat,
            mcConst.SessionID,

            function (stat) {
                // "Questions"        : 78,    // вопросов задано
                // "Answers"          : 14,    // правильных ответов получено
                // "TotalQuestions"   : 14000, // всего вопросов в базе
                // "Players"          : 30,    // всего игроков
                // "LastMonthPlayers" : 21,    // игроков за последний месяц
                // "ServID"           : "ASDQ",// идентификатор сервера, текстовая строка
                // "Registered"       : false  // если робот-викторина не зарегистрирован
                // "AdminEmail"

                var statList = []
                    .concat(stat.Registered ? [] : [mcLang(2026, [mcLang(2032) + stat.ServID + (stat.AdminEmail ? "&email=" + stat.AdminEmail : "")])]) // "2026":"Викторина не зарегистрирована!", "2032":"https://nsoft-s.com/buymychat.html?ID=",
                    .concat([mcLang(2027, [stat.Questions])])       // "2027":"Вопросов задано",
                    .concat([mcLang(2028, [stat.Answers])])         // "2028":"Правильных ответов:",
                    .concat([mcLang(2029, [stat.TotalQuestions])])  // "2029":"Всего вопросов в базе:",
                    .concat([mcLang(2030, [stat.Players])])         // "2030":"Всего игроков:",
                    .concat([mcLang(2031, [stat.LastMonthPlayers])])// "2031":"Игроков за последний месяц:",
                ;

                quiz.stat.define("template", statList.join("<br>"));
                quiz.stat.refresh();
            }
        ]);
    }

    //========================================================

    fillOptions(options);

    //========================================================

    quiz.enterQuestion = function(code){
        if (code === mcConst.keyCodes.enter) {
            quiz.findQuestion();
        } else
        if (code === mcConst.keyCodes.esc) {
            quiz.clear();
        } else
        if (quiz.question.getValue()){
            quiz.clearQ.enable();
        }
    };

    quiz.clear = function(){
        quiz.questionNumb.define("template", mcLang(2016) + " ");
        quiz.questionNumb.refresh();

        quiz.delQ.disable();
        quiz.editQ.disable();
        quiz.clearQ.disable();

        quiz.addQ.enable();

        setTimeout(function () {
            quiz.answer.setValue("");
            quiz.answer.$setValue("");

            quiz.question.setValue("");
            quiz.question.$setValue("");
        }, 100);
    };

    quiz.delQuestion = function(){
        if (curQuestionID){
            $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                type  : "confirm-warning",
                text  : mcLang(2022, [mcService.trim(quiz.question.getValue().replace("?", "")), "#" + curQuestionID]), // "2022":"Удалить вопрос %s?",
                ok    : mcLang(114), // "114": "да",
                cancel: mcLang(113), // "113": "нет",
                callback:function(yes) {
                    if (yes) {
                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.cs_adm_integration_quiz_del_question,
                            mcConst.SessionID,

                            curQuestionID,

                            function() {
                                webix.message(mcLang(2023)); // "2023":"Вопрос удален!",

                                quiz.clear();
                            }
                        ]);
                    }
                }
            }));
        }
    };

    quiz.editQuestion = function(){
        var question = mcService.trim(quiz.question.getValue());
        var answer   = mcService.trim(quiz.answer.getValue());

        if (curQuestionID){
            if (question && answer){
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst._CMD_.cs_adm_integration_quiz_modify_question,
                    mcConst.SessionID,

                    curQuestionID,
                    question,
                    answer,

                    function () {
                        webix.message(mcLang(2025)); // "2025":"Вопрос изменен!",
                    }
                ]);
            } else {
                webix.alert(mcLang(2018)); // "2018":"Вопрос и ответ не могут быть пустыми",
            }
        }
    };

    quiz.addQuestion = function(){
        var question = mcService.trim(quiz.question.getValue());
        var answer   = mcService.trim(quiz.answer.getValue());

        if (question && answer){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_integration_quiz_add_question,
                mcConst.SessionID,

                question,
                answer
            ]);
        } else {
            webix.alert(mcLang(2018)); // "2018":"Вопрос и ответ не могут быть пустыми",
        }
    };

    quiz.findQuestion = function(){
        var question = quiz.question.getValue();

        question = (new RegExp(/^\s*\d+\s*$/)).test(question) ? mcService.trim(question) : question;

        if (question) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_integration_quiz_check_question,
                mcConst.SessionID,

                question,      // Кому Красная Шапочка несла пирожки ?

                function(data) {
                    // "ID" : 82, // идентификатор вопроса (номер, число > 0). Если ID = -1, значит, вопрос не найден
                    // "Question" : "bla-bla-bla?", // текст вопроса
                    // "Answer" : "bla-bla" // текст ответа

                    var answr = "";

                    if (data.ID !== -1){
                        answr         = data.Answer;
                        curQuestionID = data.ID;
                        question      = data.Question;

                        quiz.delQ.enable();
                        quiz.editQ.enable();
                        quiz.addQ.disable();
                    } else {
                        curQuestionID = "";
                        
                        webix.message(mcLang(2020)); // "2020":"Такого вопроса нет!",
                    }

                    quiz.question.setValue(question);
                    quiz.answer.setValue(answr);

                    quiz.questionNumb.define("template", mcLang(2016) + (curQuestionID ? " #" + curQuestionID : " "));
                    quiz.questionNumb.refresh();
                }
            ]);
        } else {
            webix.message(mcLang(2021)); // "2021":"Вопрос не может быть пустым!",
        }
    };

    quiz.downloadBD = function(){
        mcService.goToHelp("/serverhelp/" + (mcConst.Lang === "uk" ? "ua" : mcConst.Lang) + "/index.html?toolsintegrationsquizhowtosetup.htm", true);
    };

    quiz.fillOptions = fillOptions;

    quiz.fillView = function(cb){
        if (quiz.db){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_get_all_text_confs,
                mcConst.SessionID,
                function(data){
                    quiz.chList = {
                        filter    : function(item, value){
                            return item.value.toString().toLowerCase().indexOf(value.toLowerCase()) !== -1;
                        },
                        body      : {
                            template: function (obj) {
                                return obj.value;
                            },
                            data: [{
                                id   : -1,
                                value: mcLang(2010) // "2010":"Создать конференцию \"Викторина\"",
                            }]
                        }
                    };

                    for (var i in data){
                        quiz.chList.body.data.push({
                            id   : i.toString(),
                            value: data[i].Name
                        })
                    }

                    quiz.ConfList.define('options', quiz.chList);
                    quiz.ConfList.refresh();

                    getStat();

                    if (cb) {
                        cb();
                    }
                }
            ]);
        }
    };

    quiz.fillTool = function () {
        $$("enable"                      + quiz.name).setValue(quiz.enabled);
        $$("TimeAnswer"                  + quiz.name).setValue(quiz.TimeAnswer);
        $$("TimePauseAfterCorrectAnswer" + quiz.name).setValue(quiz.TimePauseAfterCorrectAnswer);
        $$("StopAfterNFails"             + quiz.name).setValue(quiz.StopAfterNFails);
        $$("MinPlayersCount"             + quiz.name).setValue(quiz.MinPlayersCount);
        $$("TimePauseAfterStart"         + quiz.name).setValue(quiz.TimePauseAfterStart);
        $$("TimePauseAfterNoAnswers"     + quiz.name).setValue(quiz.TimePauseAfterNoAnswers);
        $$("ShowAnswers"                 + quiz.name).setValue(mcService.convertIntToBool(quiz.ShowAnswers));
        $$("ShowQuestionNumbers"         + quiz.name).setValue(mcService.convertIntToBool(quiz.ShowQuestionNumbers));
        $$("EnableHints"                 + quiz.name).setValue(mcService.convertIntToBool(quiz.EnableHints));
        $$("ConfID"                      + quiz.name).setValue(quiz.ConfID);

        if (quiz.db){
            quiz.downloadView.hide();
            quiz.mainView    .show();
        } else {
            quiz.mainView    .hide();
            quiz.downloadView.show();
        }
    };

    quiz.saveData = function(){
        return {
            name            : quiz.name,
            enabled         : mcService.convertIntToBool($$("enable" + quiz.name).getValue()),

            TimeAnswer                  : $$("TimeAnswer"                  + quiz.name).getValue(),
            TimePauseAfterCorrectAnswer : $$("TimePauseAfterCorrectAnswer" + quiz.name).getValue(),
            StopAfterNFails             : $$("StopAfterNFails"             + quiz.name).getValue(),
            MinPlayersCount             : $$("MinPlayersCount"             + quiz.name).getValue(),
            TimePauseAfterStart         : $$("TimePauseAfterStart"         + quiz.name).getValue(),
            TimePauseAfterNoAnswers     : $$("TimePauseAfterNoAnswers"     + quiz.name).getValue(),
            ShowAnswers                 : mcService.convertIntToBool($$("ShowAnswers"         + quiz.name).getValue()),
            ShowQuestionNumbers         : mcService.convertIntToBool($$("ShowQuestionNumbers" + quiz.name).getValue()),
            EnableHints                 : mcService.convertIntToBool($$("EnableHints"         + quiz.name).getValue()),
            ConfID                      : $$("ConfID"                      + quiz.name).getValue()
        };
    };

    quiz.getView = function () {
        return toolQuizView(quiz, $scope);
    };

    $scope.$on('quiz_question_added', function () {
        if (quiz){
            webix.message(mcLang(2024)); // "2024":"Вопрос добавлен в базу!",

            quiz.findQuestion();
        }
    });

    $scope.$on('quiz_stat', function () {
        if (quiz){

        }
    });

}

function toolTelegramView(telegram, $scope) {
    function custom_checkbox(obj, common, value){
        return "<div class='webix_table_checkbox" + (value ? " checked green'> " + mcLang(114) : " notchecked red'> " + mcLang(113)) + " </div>";
    }

    var view  = { id: "view_" + telegram.name, hidden: $scope.shovedView !== telegram.name, rows: [
        { view: "checkbox", id: "enable" + telegram.name, value: telegram.enabled, labelWidth: 0, css: "finger",
            labelRight: mcService.Lang(1753, "Telegram"), // "1753":"Включить интеграцию с %s",
            on: { onItemClick: $scope.change }
        },

        { height: 5},

        { template: mcService.insertIco("fa-info-circle") + mcService.Lang(1857), css: "_info selectable", autoheight: true}, // "1857":"Что такое Telegram бот

        { height: 5},

        { id: "isConnectedBot" + telegram.name, template: mcLang(telegram.bot ? 1862 : 1861, telegram.bot), autoheight: true, borderless: true}, // "1861":"Нет подключенных ботов", "1862":"Telegram бот ID: %s",

        { id: "botID" + telegram.name, view: "text", label: mcLang(1858), labelWidth: 200, // "1858":"Ключ авторизации (токен)",
            on: { onTimedKeyPress: function () {
                if (telegram.botToken.getValue() !== telegram.bot) {
                    $scope.change.apply(this, arguments);
                }
            }}
        },

        { cols:[
            { width: 200},
            { id: "btnConnectBot" + telegram.name, view: "button", value: mcLang(1860), width: 300, click: telegram.connectBot }, // "1860":"Подключить бота",
            // { view: "button", value: "KILL ALL", width: 300, click: _data.clearallusers }, // "1860":"Подключить бота",
            {}
        ]},

        { id: "wrapLogWebHookConnect" + telegram.name, hidden: true, rows: [
            { height: 5},

            { cols: [
                { template: mcService.Lang(1867), autoheight: true, width: 200, borderless: true }, // "1867":"Протокол подключения",
                { id: "logWebHookConnect" + telegram.name, template: " ", autoheight: true, css: "selectable" }
            ]}
        ]},

        { cols:[
            { width: 200},
            { rows: [
                { view: "checkbox", id: "auto_create" + telegram.name, value: telegram.auto_create, labelWidth: 0, css: "finger",
                    labelRight: mcService.Lang(1918), // "1918":"Авто-регистрация пользователя MyChat",
                    on: { onItemClick: $scope.change }
                },
                { view: "checkbox", id: "auto_activate" + telegram.name, value: telegram.auto_activate, labelWidth: 0, css: "finger",
                    labelRight: mcService.Lang(1919), // "1919":"Авто-активация",
                    on: { onItemClick: $scope.change }
                }
            ]},
            {}
        ]},

        { height: 5},

        { id: "telegramUsersList" + telegram.name, view: "datatable",
            editable       : true,
            resizeColumn   : true,
            checkboxRefresh: true,
            columns        : [
                { id: "active",      header: mcLang(1863), width: 70, sort: "string", css: "grid_area",
                    template: function (obj, common) {
                        return "<div class='byCenter finger'>" + custom_checkbox.apply(null, arguments) + "</div>";
                    }, editor: "inline-checkbox"
                },

                { id: "Register",    header: mcLang(1133), width: 145, sort: "string", css: "grid_area", // "1133":"Дата регистрации",
                    template: function (obj) {
                        return mcService.sortableDate(obj.dt_reg_utc);
                    }
                },

                { id: "TelegramID",  header: mcLang(1864), fillspace: true, sort: "string", css: "grid_area", // "1864":"Telegram ID",
                    template: function (obj) {
                        return  obj.user_id + " : " + (obj.user_nickname ? "@" + obj.user_nickname : "") + " " + obj.user_firstname + " " + obj.user_lastname;
                    }
                },

                { id: "__saveUser", header: "", width: 30, css: "finger", template: function (obj) {
                    var style = "\"display:" + (obj.__changed ? "inline-block" : "none") + "; margin-left: -4px;\"";

                    return mcService.insertIco("fa-check green", "", {
                        title: mcLang(104),                                             // "104": "Сохранить"
                        style: style
                    });
                }},

                { id: "DisplayName", header: mcLang(1865), fillspace: true, sort: "string", css: "grid_area", editor: "selectUser", options: [], // "1865":"MyChat пользователь",
                    template: function (obj) {
                        if (obj.DisplayName && obj.DisplayName.uin){
                            obj.mychat_displayname = obj.DisplayName.name;
                            obj.mychat_uin = obj.DisplayName.uin;
                        }

                        return obj.mychat_displayname.indexOf('UIN') > 0
                            ? obj.mychat_displayname
                            : obj.mychat_displayname + " (UIN: " + obj.mychat_uin + ")";
                    }
                },

                { id: "__removeUser", header: "", width: 30, css: "finger", template: function () {
                    return mcService.insertIco("fa-trash", "", { title: mcLang(52) }); // "52" : "Удалить",
                }}
            ],
            data: [],
            on: {
                onItemClick     : telegram.clickByUser,
                onBeforeEditStop: telegram.editUser,
                onCheck         : telegram.editUser
            }
        }
    ]};

    telegram.initView = function () {
        if (telegram.initialized) return;

        telegram.enableTelegram        = $$("enable" + telegram.name);
        telegram.auto_createTelegram   = $$("auto_create" + telegram.name);
        telegram.auto_activateTelegram = $$("auto_activate" + telegram.name);
        telegram.botToken              = $$("botID" + telegram.name);
        telegram.btnConnectBot         = $$("btnConnectBot" + telegram.name);
        telegram.isConnectedBot        = $$("isConnectedBot" + telegram.name);
        telegram.logWebHookConnect     = $$("logWebHookConnect" + telegram.name);
        telegram.wrapLogWebHookConnect = $$("wrapLogWebHookConnect" + telegram.name);
        telegram.telegramUsersList     = $$("telegramUsersList" + telegram.name);

        telegram.initialized = true;
    };

    return view;
}

function ToolTelegram($scope, $rootScope, options) {
    var _telegram    = this;
    var apiURL       = MC_RESOURCE.URLs && MC_RESOURCE.URLs.ApiTelegram
        ? MC_RESOURCE.URLs.ApiTelegram
        : "https://api.telegram.org/";

    function isConnectedBot() {
        _telegram.isConnectedBot.setHTML(mcLang(
            _telegram.connected ? 1862 : 1861,
            [_telegram.botName ?  "@" + _telegram.botName + " &#151;" : "", _telegram.connected]
        )); // "1861":"Нет подключенных ботов", "1862":"Telegram бот ID: %s",

        webix.html.removeCss(_telegram.isConnectedBot.getNode(), "red");
        webix.html.removeCss(_telegram.isConnectedBot.getNode(), "green");

        webix.html.addCss(_telegram.isConnectedBot.getNode(), _telegram.connected ? "green" : "red");
    }

    function findDouble(uin){
        var users = _telegram.telegramUsersList.serialize();
        var res = false;

        if (uin >= 0) {
            for (var i = 0; i < users.length; i++){
                if (users[i].mychat_uin == uin){
                    res = users[i].user_id;

                    break;
                }
            }
        }

        return res;
    }

    function clearAllUsers() {
        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_integration_telegram_clear_users_list,
            mcConst.SessionID,

            function () {
                _telegram.telegramUsersList.clearAll();
            }
        ]);
    }

    function fillOptions(opts){
        Object.keys(opts).forEach(function (item) {
            _telegram[item] = opts[item];
        });
    }

    //========================================================

    fillOptions(options);
    
    //========================================================

    _telegram.getView = function(){
        return toolTelegramView(_telegram, $scope);
    };

    _telegram.fillOptions = fillOptions;

    _telegram.saveData = function (){
        var outData = {
            // название инструмента, от него зависит набор настроек
            name     : _telegram.name,

            // включен или выключен интеграционный инструмент
            enabled       : mcService.convertIntToBool(_telegram.enableTelegram.getValue()),
            auto_create   : mcService.convertIntToBool(_telegram.auto_createTelegram.getValue()),
            auto_activate : mcService.convertIntToBool(_telegram.auto_activateTelegram.getValue()),

            botName  : _telegram.botName,
            bot      : mcService.trim(_telegram.botToken.getValue()),
            connected: _telegram.connected,
            users    : []
        };

        if (!_telegram.connected) {
            clearAllUsers();
        }

        return outData;
    };

    _telegram.fillTool = function(){
        _telegram.enableTelegram.setValue(_telegram.enabled);
        _telegram.auto_createTelegram.setValue(_telegram.auto_create);
        _telegram.auto_activateTelegram.setValue(_telegram.auto_activate);

        _telegram.botToken.setValue(_telegram.bot);

        isConnectedBot();
    };

    _telegram.fillView = function(done){
        /*
         "name"    : "telegram",
         "enabled" : true,
         "bot"     : "8e75cyn8745ycv78r5cnb87",
         "botName" : "test_mc",
         "script"  : ID,
         "users"   : [{
             Active      : true,
             TelergamID  : "fdihdfuigh",
             UIN         : 3,
             DisplayName : "Gifer",
             BotID       : "8e75cyn8745ycv78r5cnb87",
             Other       : "fgjhbgfgkj gjbf fgb ifgb ngb"
         }, ...]
        */

        _telegram.wrapLogWebHookConnect.hide();

        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_script_event_states,
            mcConst.SessionID,

            done
        ]);

        $rootScope.SendCMDToServer([
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_integration_telegram_users,
            mcConst.SessionID,

            function (userList) {
                /*{
                    "active"             : false,                 // юзер включен или нет?
                    "dt_reg_utc"         : "08.05.2013.12.54.34"  // дата регистрации Telegram пользователя, в формате "дд.мм.гггг.чч.мм.сс". UTC
                    "user_id"            : "72364528347",         // внутренний Telegram ID пользователя
                    "user_firstname"     : "John",                // имя пользователя Telegram (может быть пустым)
                    "user_lastname"      : "Connor",              // фамилия пользователя Telegram (может быть пустым)
                    "user_nickname"      : "Commandor",           // ник пользователя Telegram (может быть пустым)
                    "mychat_uin"         : "-1",                  // назначенный UIN для связки с пользователем MyChat. Если не назначен, то -1
                    "mychat_displayname" : ""                     // отображаемое имя пользователя MyChat
                }*/

                _telegram.telegramUsersList.clearAll();
                _telegram.telegramUsersList.parse(userList);

                _telegram.getWebhookInfo();
            }
        ]);
    };

    _telegram.getWebhookInfo = function(){
        function result(text, check) {
            _telegram.logWebHookConnect.setHTML(
                "<div style='word-break: break-all;'><b>Webhook info</b>: " + text + "<br><br>" +
                "<b>Check on Telegram:</b>" + check + "</div>"
            );

            isConnectedBot();
        }

        var bot = _telegram.botToken.getValue();

        if (bot !== ""){
            _telegram.wrapLogWebHookConnect.show();

            webix.ajax(apiURL + "bot" + bot + "/getWebhookInfo", {
                success: function (check) {
                    webix.ajax(apiURL + "bot" + bot + "/getMe", {
                        success: function (text) {
                            try {
                                _telegram.botName = JSON.parse(text).result.username;
                            } catch (e){}

                            result(text, check);
                        },
                        error: function (text) {
                            result(text, check);
                        }
                    });
                },
                error: function (text) {
                    result(text, check);
                }
            });
        }
    };

    _telegram.connectBot  = function (btn) {
        function result(text, host, check) {
            _telegram.logWebHookConnect.setHTML(
                "<div style='word-break: break-all;'><b>Webhook</b>: " + host + "<br><br>" +
                "<b>Result:</b>" + text + "<br><br>" +
                "<b>Check on Telegram:</b>" + check + "</div>"
            );

            isConnectedBot();
        }

        function setBot() {
            webix.message(mcLang(1871)); // "1871":"Вебхук успещно назначен",

            _telegram.connected = bot;

            $scope.change();
        }

        var bot    = _telegram.botToken.getValue();

        if (bot !== ""){
            mcService.getMcSettings($rootScope, function () {
                var host = $rootScope.mcStorage[mcConst.dataModels.SettingsNetwork].ExternalIP;
                var port = $rootScope.mcStorage[mcConst.dataModels.SettingsNetwork].WEBTCPPort;

                var name = "Telegram";

                if (host){
                    host =
                        ($rootScope.mcStorage[mcConst.dataModels.SettingsNetwork].WEBUseSSL ? "https://" : "http://") +
                        host + ($rootScope.mcStorage[mcConst.dataModels.SettingsNetwork].WEBUseSSL && port == 443
                            ? ""
                            : ($rootScope.mcStorage[mcConst.dataModels.SettingsNetwork].WEBUseSSL === false && port == 80
                                    ? ""
                                    : ":" + port
                            )
                        ) + "/rest/" +
                        name + "/" +
                        bot + "/"
                    ;

                    if (btn === "btnConnectBottelegram") {
                        _telegram.wrapLogWebHookConnect.show();

                        webix.ajax(apiURL + "bot" + bot + "/setWebhook?url=" + host, {
                            success: function (text) {
                                var data = JSON.parse(text);

                                if (data.ok && data.result) {
                                    webix.ajax(apiURL + "bot" + bot + "/getWebhookInfo", {
                                        success: function (check) {
                                            webix.ajax(apiURL + "bot" + bot + "/getMe", {
                                                success: function (info) {
                                                    try {
                                                        _telegram.botName = JSON.parse(info).result.username;
                                                    } catch (e){}

                                                    result(text, host, check);
                                                },
                                                error: function (text) {
                                                    result(text, host, "");
                                                }
                                            });
                                        },
                                        error: function (text) {
                                            result(text, host, "");
                                        }
                                    });

                                    if (bot === _telegram.connected || !_telegram.connected) {
                                        setBot();
                                    } else {
                                        $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                                            type  : "confirm-warning",
                                            text  : mcLang(1874), // "1874":"Вы подключаете другого бота, все пользователи будут удалены. Продолжить?",
                                            ok    : mcService.Lang(581), // "581": "Удалить",
                                            cancel: mcService.Lang(103), // "103": "Отмена",
                                            callback:function(yes){
                                                if (yes){
                                                    clearAllUsers();

                                                    setBot();
                                                } else {
                                                    $rootScope.$broadcast('hide' + mcConst.dataModels.ApplyPanel, []);

                                                    $scope.changedData.onClose();
                                                }
                                            }
                                        }));
                                    }
                                } else {
                                    webix.message(mcLang(1872), "error"); // "1872":"Вебхук не подключен!",

                                    _telegram.connected = "";

                                    result(text, host, "");
                                }
                            },
                            error: function (text) {
                                webix.message(mcLang(1872), "error"); // "1872":"Вебхук не подключен!",

                                _telegram.connected = "";

                                result(text, host, "");
                            }
                        });
                    } else {
                        return host;
                    }
                } else

                if (btn === "btnConnectBottelegram"){
                    webix.message(mcLang(1869), "", 20000); //"1869":"Нет назначенного IP адреса для внешних клиентов",
                }
            }, true);
        } else

        if (btn === "btnConnectBottelegram"){
            if (bot === "") {
                webix.message(mcLang(1870)); // "1870":"Укажите \"Ключ авторизации (токен)\"",
            }
        }
    };

    _telegram.clickByUser = function (item) {
        var user = this.getItem(item);

        switch (item.column) {
            case "__removeUser": // Remove User
                $scope.regShowWindow(mcService.RandomHash(4), webix.confirm({
                    type  : "confirm-warning",
                    text  : mcLang(1071, user.user_id + " : " + (user.user_nickname ? "@" + user.user_nickname : "") + " " + user.user_firstname + " " + user.user_lastname), // "1071":"Удалить пользователя<br><b>%s</b><br>из списка?",
                    ok    : mcService.Lang(581), // "581": "Удалить",
                    cancel: mcService.Lang(103), // "103": "Отмена",
                    callback:function(yes){
                        if (yes){
                            $rootScope.SendCMDToServer([
                                mcConst.lockInterface,
                                mcConst._CMD_.cs_adm_integration_telegram_delete_user,
                                mcConst.SessionID,
                                user.user_id,

                                function() {
                                    _telegram.telegramUsersList.remove(item.row);
                                }
                            ]);
                        }
                    }
                }));
            break;

            case "__saveUser":
                if (user.__changed){
                    user.__changed = false;
                    user.__oldUIN  = void(0);

                    _telegram.telegramUsersList.updateItem(user.id, user);

                    $rootScope.SendCMDToServer([
                        mcConst._CMD_.cs_adm_integration_telegram_modify_user,
                        mcConst.SessionID,

                        user.user_id,      // внутренний Telegram ID пользователя
                        user.active,       // юзер включен или нет?
                        user.mychat_uin    // назначенный UIN для связки с пользователем MyChat. Если не назначен, то -1
                    ]);
                }
            break;
        }
    };

    _telegram.editUser    = function (obj, field) {
        var user = _telegram.telegramUsersList.getItem(field.row || obj);
        var uin  = obj.value && obj.value.uin !== undefined
            ? obj.value.uin
            : user.mychat_uin;
        var find = findDouble(uin);

        if (!find || find === user.user_id){
            var active = mcService.isNumber(user.active)
                ? mcService.convertIntToBool(user.active)
                : user.active;

            if ((active && uin == -1 && !obj.value) || (active && uin != -1 && user.__oldUIN && user.__oldUIN == -1)){
                webix.message(mcLang(1875)); // "1875":"Подключите пользователя, чтобы активировать",
                user.active = false;
            } else {
                if (uin == -1) {
                    user.active = false;
                }

                if (field && field.column === "DisplayName") {
                    user.__changed = user.__oldUIN == void(0) ? user.__oldUIN != uin : user.mychat_uin != uin;
                    
                    if (user.__oldUIN == void(0)) {
                        user.__oldUIN  = user.mychat_uin;
                    }
                }

                $rootScope.SendCMDToServer([
                    mcConst._CMD_.cs_adm_integration_telegram_modify_user,
                    mcConst.SessionID,

                    user.user_id, // внутренний Telegram ID пользователя
                    active,       // юзер включен или нет?
                    uin           // назначенный UIN для связки с пользователем MyChat. Если не назначен, то -1
                ]);
            }
        } else {
            obj.value.uin = -1;
            obj.value.name = mcLang(140);

            field.setValue(-1);

            webix.alert(mcLang(1873)); // "1873":"Нельзя назначить пользователя, он уже есть в списке!",
        }
    };

    _telegram.clearallusers = clearAllUsers;

    _telegram.update = function () {

    };

    //========================================================

    $scope.$on('telegram_user_added', function (e, args) {
        if (view){
            _telegram.telegramUsersList.add(args[0]);
        }
    });

    //========================================================

    webix.editors.selectUser = webix.extend({
        setValue:function(value){
            this._initial_value = value && value.uin ? value.uin : value;

            if (this.config.suggest){
                var sobj = webix.$$(this.config.suggest);
                var data =  this.config.collection || this.config.options;

                if (data){
                    sobj.getList().data.importData(data);
                }

                var uin = value && value.uin ? value.uin : value;

                this._initial_text = uin >= 0 ? sobj.getItemText(uin) : mcLang(140) + " (UIN: -1)";

                this.getInputNode(this.node).value = this._initial_text;
            }
        },
        getValue:function(){
            var uin = webix.$$(this.config.suggest).getSuggestion();

            return {
                name: uin >= 0 ? this.getInputNode().value : mcLang(140) + " (UIN: -1)",
                uin: uin
            };
        },
        showPopup:function(){
            var popup = this.getPopup();
            var list = popup.getList();
            var input = this.getInputNode();
            var value = this.getValue();

            popup.show(input);
            input.setAttribute("aria-expanded", "true");

            if (value && value.uin && list.exists(value.uin)){
                list.select(value.uin);
                list.showItem(value.uin);
            } else {
                list.unselect();
                list.showItem(list.getFirstId());
            }

            popup._last_input_target = input;
        },
        afterRender:function(){
            var editItem = this;

            if (editItem.config.options && editItem.config.options.length){
                editItem.showPopup();
            } else {
                mcService.getAllUserWithParams(function (users) {
                    var item = _telegram.telegramUsersList.getItem(editItem.row);
                    var body = editItem.getPopup();
                    var list = body.getList();

                    if (editItem.config.width < 300){
                        body.config.fitMaster = false;
                        body.config.minWidth = 300;
                        body.resize();
                    }

                    editItem.config.options = [{id: '-1', value: mcLang(140)}]; // "140": "Ничего не выбрано",

                    users.sort(function (a, b) {
                        return mcService.sortAB(a.DisplayName, b.DisplayName);
                    });

                    users.forEach(function (item) {
                        editItem.config.options.push({
                            id   : item.UIN,
                            value: item.DisplayName
                        });
                    });

                    list.define("template", "#value# (UIN: #id#)");
                    list.parse (editItem.config.options);
                    list.select(item.mychat_uin);

                    editItem.setValue(item.mychat_uin);
                    editItem.showPopup();
                }, $rootScope, { Filters: "UIN,DISPLAYNAME" });
            }
        }
    }, webix.editors.combo);

    // telegramView = toolTelegramView(_telegram, $scope);
}

function toolAsteriskView(asterisk, $scope) {
    var lbWidth = 250;
    var view = { id: "view_" + asterisk.name, hidden: $scope.shovedView !== asterisk.name,
        cols: [{ minWidth: 500, maxWeight: 1000, rows: [
            { view: "checkbox", id: "enable" + asterisk.name, value: '', labelWidth: 0, css: "finger",
                labelRight: mcService.Lang(1753, 'Asterisk'), // "1753":"Включить интеграцию с %s",
                on: { onItemClick: function (){
                    $scope.change();
                }}
            },

            { cols: [
                { template: mcLang(1513), borderless: true, autoheight: true, width: lbWidth }, // "1513":"Состояние",
                { id: "status" + asterisk.name, template: mcLang(2135), borderless: true, autoheight: true }, // "2134":"подключено к Asterisk", "2135":"<span class='red bolder'>отключено от Asterisk</span>",
            ]},

            { height: 5},

            { template: mcService.insertIco("fa-info-circle") + mcService.Lang(2136), css: "_info selectable", autoheight: true }, // "2136":"Интеграция работает через <a href='https://wiki.asterisk.org/wiki/display/AST/The+Asterisk+Manager+TCP+IP+API' target='_blank'>Asterisk Manager Interface (AMI)</a>",

            { height: 5},

            { cols: [
                { rows: [
                    { view: "text", id: "Username" + asterisk.name, value: asterisk.Username, label: "Username",   labelWidth: lbWidth, on: { onTimedKeyPress: function () {
                        if (this.getValue() !== asterisk.Username) {
                            $scope.change();
                            asterisk.view_connect.disable();
                        }
                    }} },

                    { cols: [
                        { view: "text", id: "Secret"   + asterisk.name, value: asterisk.Secret,   label: "Secret",     labelWidth: lbWidth, on: { onTimedKeyPress: function () {
                            if (this.getValue() !== asterisk.Secret)   {
                                $scope.change();
                                asterisk.view_connect.disable();
                            }
                        }}, type: "password" },

                        { view: "toggle", width: 30, offIcon: "eye", onIcon: "eye-slash",  type:"icon", css: "noBG", tooltip: mcLang(1100) + "/" + mcLang(1099).toLowerCase(), // "1100":"Скрыть", "1099":"Показать",
                            on: { onChange: function (val) {
                                var pwd = asterisk.view_Secret;

                                if (val) {
                                    pwd.define('type', 'text');
                                } else {
                                    pwd.define('type', 'password');
                                }

                                pwd.refresh();
                                pwd.getInputNode().setAttribute("autocomplete", "new-password");
                            }}
                        }
                    ]},

                    { view: "text", id: "Host"     + asterisk.name, value: asterisk.Host,     label: mcLang(2130), labelWidth: lbWidth, on: { onTimedKeyPress: function () { // "2130":"Host адрес Asterisk",
                        if (this.getValue() !== asterisk.Host)     {
                            $scope.change();
                            asterisk.view_connect.disable();
                        }
                    }} },
                    { view: "text", id: "Port"     + asterisk.name, value: asterisk.Port,     label: mcLang(593),  labelWidth: lbWidth, on: { onTimedKeyPress: function () { // "593": "TCP порт",
                        if (this.getValue() !== asterisk.Port)     {
                            $scope.change();
                            asterisk.view_connect.disable();
                        }
                    }} },
                    { view: "text", id: "Context"  + asterisk.name, value: asterisk.Context,  label: "Context",    labelWidth: lbWidth, on: { onTimedKeyPress: function () {
                        if (this.getValue() !== asterisk.Context)  {
                            $scope.change();
                            asterisk.view_connect.disable();
                        }
                    }} },

                    { view: "select",id: "Channel" + asterisk.name, value: asterisk.Channel,  label: "Channel", labelWidth: lbWidth,
                        on: { onChange: function () {
                            $scope.change();
                            asterisk.view_connect.disable();
                        }},
                        options: [
                            { id: "SIP",   value: "SIP"},
                            { id: "PJSIP", value: "PJSIP"},
                            { id: "Local", value: "Local"},
                            { id: "IAX",   value: "IAX"},
                            { id: "IAX2",  value: "IAX2"}
                        ]},

                    { view: "slider", id: "Priority" + asterisk.name, value: asterisk.Priority, labelWidth: lbWidth, label: "Priority", // "2129":"Время жизни файла в кеше (часов)",
                        height: 37, name: "Priority", moveTitle: true, title: "" + asterisk.Priority,  min: 1, max: 100, step: 1,
                        on: { onSliderDrag:function(){
                            this.define("title", "" + this.getValue());
                            this.refresh();

                            $scope.change.apply(this, arguments);
                            asterisk.view_connect.disable();
                        }}
                    },

                    { view: "slider", id: "Timeout" + asterisk.name, value: asterisk.Timeout, labelWidth: lbWidth, label: "Timeout", // "2129":"Время жизни файла в кеше (часов)",
                        height: 37, name: "Timeout", moveTitle: true, title: "" + asterisk.Timeout,  min: 1, max: 60, step: 1,
                        on: { onSliderDrag:function(){
                            this.define("title", "" + this.getValue());
                            this.refresh();

                            $scope.change.apply(this, arguments);
                            asterisk.view_connect.disable();
                        }}
                    },

                    { cols: [
                        { view: "button", id: "connect"    + asterisk.name, value: mcLang(1546), width: lbWidth, click: asterisk.connectAsterisk, disabled: true }, // "1546":"Подключиться",
                        { view: "button", id: "disconnect" + asterisk.name, type: "danger", value: mcLang(2137), width: lbWidth, click: asterisk.disconnectAsterisk, hidden: true }, // "2137":"Отключиться",
                        {}
                    ]},
                ]},
            ]},

            { height: 15 },

            { template: mcService.insertIco("fa-info-circle") + mcService.Lang(2147), css: "_info selectable", autoheight: true }, // "2147":"Группы пользователей, подклученные к другим Asterisk",

            { height: 15 },

            { cols: [
                { view: "button", value: mcLang(50), click: asterisk.addGroupPrefix}, // "50" : "Добавить",
                { view: "button", id: "deleteUserGroup" + asterisk.name, value: mcLang(52), click: asterisk.delGroupPrefix}, // "52" : "Удалить",
                {}
            ]},

            { height: 5 },

            { cols: [
                { id: "ServersList" + asterisk.name, view: "datatable", scroll: 'y',
                    editable       : true,
                    editaction     : "dblclick",
                    select         : "row",
                    resizeColumn   : true,
                    checkboxRefresh: true,
                    tooltip        : true,
                    columns        : [
                        { id: "UserGroup",  header: mcLang(1722), fillspace: true, sort: "string", css: "grid_area", editor: "selectGroup", options: [], // "1722":"Группы пользователей",
                            tooltip : mcLang(2145), // "2145":"Двойной клик, для изменения",
                            template: function (obj) {
                                return  obj.UserGroup.value || mcLang(140);
                                // return  obj.UserGroup.value ? obj.UserGroup.value + " (ID: " + obj.UserGroup.id + ")" : (mcLang(140) + " (ID: -1)");
                            }
                        },

                        { id: "Prefix", header: "Phone channel", width: 200, sort: "string", css: "grid_area", editor: "text", tooltip : mcLang(2145)},  // "1865":"MyChat пользователь", // "2145":"Двойной клик, для изменения",
                    ],
                    data: [],
                    on: {
                        onAfterEditStart: function () {
                            asterisk.view_deleteUserGroup.disable();
                            $scope.change();
                        },
                        onAfterEditStop: function () {
                            asterisk.view_deleteUserGroup.enable();
                        }
                        // onItemClick     : asterisk.clickByUser,
                        // onBeforeEditStop: asterisk.editUser,
                        // onCheck         : asterisk.editUser
                    }
                },
            ]},
        ]}, { width: 15 }, {
            rows: [
                { template: mcService.Lang(2132), borderless: true, autoheight: true }, // "2132":"Протокол работы Asterisk:",

                { view: "template", id: "logs" + asterisk.name, template: "<div id='asterisk_log_container' style='word-break: break-all;'></div>", css: "selectable scrollMenu"},

                { view: "resizer"},

                { cols: [
                    { view: "textarea", id: "command" + asterisk.name, height: 150, value: "", placeholder: mcLang(2131)}, // "2131":"Команда",
                    { rows: [
                        { view: "button", id: "sendCMD" + asterisk.name, value: mcLang(2133), width: 110, height: 40, click: function () {asterisk.clickSendCMD()}, tooltip: "CTRL+ENTER"},
                        {},

                        { view: "button", id: "sendPING" + asterisk.name, value: "PING", width: 110, height: 27, click: function () {
                            asterisk.clickSendCMD("action: ping");
                        }},
                        { view: "button", id: "sendList" + asterisk.name, value: "Commands", width: 110, height: 27, click: function () {
                            asterisk.clickSendCMD("action: ListCommands");
                        }}
                    ]}
                ]},
            ]
        }]
    };

    asterisk.initView = function () {
        if (asterisk.initialized) return;

        asterisk.view_enable     = $$("enable"  + asterisk.name);
        asterisk.view_logs       = $$("logs"    + asterisk.name);
        asterisk.view_command    = $$("command" + asterisk.name);
        asterisk.view_connect    = $$("connect" + asterisk.name);
        asterisk.view_disconnect = $$("disconnect" + asterisk.name);
        asterisk.view_sendCMD    = $$("sendCMD"  + asterisk.name);
        asterisk.view_sendPING   = $$("sendPING" + asterisk.name);
        asterisk.view_sendList   = $$("sendList" + asterisk.name);
        asterisk.view_deleteUserGroup = $$("deleteUserGroup" + asterisk.name);

        asterisk.view_status     = $$("status"   + asterisk.name);
        asterisk.view_Username   = $$("Username" + asterisk.name);
        asterisk.view_Secret     = $$("Secret"   + asterisk.name);
        asterisk.view_Host       = $$("Host"     + asterisk.name);
        asterisk.view_Port       = $$("Port"     + asterisk.name);
        asterisk.view_Context    = $$("Context"  + asterisk.name);
        asterisk.view_Channel    = $$("Channel"  + asterisk.name);
        asterisk.view_Timeout    = $$("Timeout"  + asterisk.name);
        asterisk.view_Priority   = $$("Priority" + asterisk.name);
        asterisk.view_ServersList= $$("ServersList" + asterisk.name);

        asterisk.asterisk_log_container = document.getElementById("asterisk_log_container");
        
        asterisk.initialized = true;

        asterisk.registerHotKeys();
    };

    return view;
}

function ToolAsterisk($scope, $rootScope, options) {
    var asterisk  = this;
    var OFFLINE   = 0;
    var ONLINE    = 1;
    var RECONNECT = 2;

    function fillOptions(opts){
        Object.keys(opts).forEach(function (item) {
            asterisk[item] = opts[item];
        });
    }

    function sendCMD(cmd){
        if (mcService.trim(cmd)) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_asterisk_send_command,
                mcConst.SessionID,
                cmd
            ]);
        }
    }

    function fieldLock(){
        if (asterisk.State === ONLINE || asterisk.State === RECONNECT) {
            asterisk.view_Username.disable();
            asterisk.view_Secret  .disable();
            asterisk.view_Host    .disable();
            asterisk.view_Port    .disable();
            asterisk.view_sendCMD .enable();
            asterisk.view_sendPING.enable();
            asterisk.view_sendList.enable();

            asterisk.view_connect   .hide();
            asterisk.view_disconnect.show();

            if (asterisk.State === ONLINE) {
                asterisk.view_status.define("template", mcLang(2134));
            } else {
                asterisk.view_status.define("template", mcLang(2140)); // "2140":"<span class='blue'>восстановление связи Asterisk</span>",
            }
        } else {
            asterisk.view_Username.enable();
            asterisk.view_Secret  .enable();
            asterisk.view_Host    .enable();
            asterisk.view_Port    .enable();
            asterisk.view_sendCMD .disable();
            asterisk.view_sendPING.disable();
            asterisk.view_sendList.disable();


            asterisk.view_connect   .show();
            asterisk.view_disconnect.hide();

            asterisk.view_status.define("template", mcLang(2135));
        }

        asterisk.view_status.refresh();
    }

    function setLog(log){
        setTimeout(function (){
            asterisk.asterisk_log_container.innerHTML += log;
            asterisk.view_logs.getNode().scroll({
                top     : asterisk.asterisk_log_container.clientHeight,
                left    : 0,
                behavior: 'smooth'
            });
        }, 50);
    }

    function fillServersList(){
        var list = asterisk.ServersList.split(mcConst.CRLF);
        var out  = [];

        asterisk.grData && list.forEach(function (item, id){
            var elm = item.split("|");
            var idx = mcService.findItemInArrayOfObj(asterisk.grData, elm[0], "ID");

            if (idx !== -1){
                out.push({
                    UserGroup: {
                        id   : elm[0],
                        value: asterisk.grData[idx].Name
                    },
                    Prefix: elm[1]
                });
            }
        });

        asterisk.view_ServersList.clearAll();
        asterisk.view_ServersList.parse(out);
    }

    //========================================================

    asterisk.registerHotKeys = function(){
        $rootScope.hotKeyDispatcher.removePreset("ASTERISK_INTEGRATION");

        $rootScope.hotKeyDispatcher.addPreset("ASTERISK_INTEGRATION", [{
            key    :  mcConst.keyCodes.enter,
            ctrlKey: true,
            func   : function () {
                asterisk.clickSendCMD()
            }
        }], asterisk.view_command.getNode(), true);
    };

    asterisk.connectAsterisk = function (){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_asterisk_do_connect,
            mcConst.SessionID
        ]);
    };

    asterisk.disconnectAsterisk = function (){
        var cmd = "Action: logoff";
        
        sendCMD(cmd);

        var dt = mcService.formatDate(new Date(), "[yyyy-mm-dd hh:nn:ss] ");

        asterisk.view_command.setValue("");

        setLog("<div class='brown'>" + dt + cmd + "</div>");
    };

    asterisk.fillOptions = fillOptions;

    // var link = mcService.getLocalHostPath(true) + "/serverhelp/index.html?integrationapigeoip.htm";

    asterisk.fillTool = function () {
        asterisk.view_enable  .setValue(asterisk.enabled);
        asterisk.view_Username.setValue(asterisk.Username);
        asterisk.view_Secret  .setValue(asterisk.Secret);
        asterisk.view_Host    .setValue(asterisk.Host);
        asterisk.view_Port    .setValue(asterisk.Port);
        asterisk.view_Context .setValue(asterisk.Context);
        asterisk.view_Channel .setValue(asterisk.Channel);
        asterisk.view_Timeout .setValue(asterisk.Timeout + "");
        asterisk.view_Priority.setValue(asterisk.Priority + "");

        asterisk.view_Timeout .define("title", "" + asterisk.Timeout);
        asterisk.view_Priority.define("title", "" + asterisk.Priority);
        asterisk.view_Timeout .refresh();
        asterisk.view_Priority.refresh();

        fieldLock();

        if (asterisk.Username && asterisk.Secret && asterisk.Host && asterisk.Port){
            asterisk.view_connect.enable();
        } else {
            asterisk.view_connect.disable();
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_user_groups,
            mcConst.SessionID,

            function(data) {
                asterisk.grData = data || [];

                fillServersList();
            }
        ]);
    };

    asterisk.saveData = function(){
        asterisk.view_ServersList.editStop();
        asterisk.view_ServersList.refresh();
        
        var list    = asterisk.view_ServersList.serialize();
        var outList = [];

        list.forEach(function (item){
            if (item.UserGroup && item.UserGroup.id != -1){
                outList.push(item.UserGroup.id + "|" + item.Prefix);
            }
        });

        // if (list.length){
            asterisk.ServersList = outList.join(mcConst.CRLF);
        // }

        var res = {
            name     : $scope.iNames.ASTERISK,
            enabled  : mcService.convertIntToBool(asterisk.view_enable.getValue()),
            Username : asterisk.view_Username.getValue(),
            Secret   : asterisk.view_Secret  .getValue(),
            Host     : asterisk.view_Host    .getValue(),
            Port     : asterisk.view_Port    .getValue(),
            Channel  : asterisk.view_Channel .getValue(),
            Context  : asterisk.view_Context .getValue(),
            Priority : asterisk.view_Priority.getValue(),
            Timeout  : asterisk.view_Timeout .getValue(),
            ServersList: asterisk.ServersList
        };

        asterisk = mcService.Marge(asterisk, res);

        fillServersList();

        if (asterisk.Username && asterisk.Secret && asterisk.Host && asterisk.Port){
            asterisk.view_connect.enable();
        } else {
            asterisk.view_connect.disable();
        }

        return res;
    };

    asterisk.clickSendCMD = function (_cmd) {
        var cmd = _cmd || asterisk.view_command.getValue()
        var dt  = mcService.formatDate(new Date(), "[yyyy-mm-dd hh:nn:ss] ");

        if (cmd){
            sendCMD(cmd);

            asterisk.view_command.setValue("");
            asterisk.view_command.$setValue("");

            setLog("<div class='brown'>" + dt + cmd.replace(/\n/g, "<br>") + "</div>");
        }
    }

    asterisk.getView = function () {
        return toolAsteriskView(asterisk, $scope);
    };

    asterisk.addGroupPrefix = function (){
        var list = asterisk.view_ServersList.serialize();
        var canAdd = true;

        list.forEach(function (item){
            if (!item.UserGroup || (item.UserGroup && item.UserGroup.id < 0)) {
                canAdd = false;
            }
        });

        if (canAdd) {
            asterisk.view_ServersList.add({
                UserGroup: "",
                Prefix   : ""
            }, 0);

            asterisk.view_ServersList.select(asterisk.view_ServersList.getFirstId());
            asterisk.view_ServersList.editCell(asterisk.view_ServersList.getFirstId(), "UserGroup");

            $scope.change();
        } else {
            webix.message(mcLang(2146)); // "2146":"Уже есть пустая группа",
        }
    };

    asterisk.delGroupPrefix = function (){
        var selected = asterisk.view_ServersList.getSelectedId();

        if (selected){
            asterisk.view_ServersList.remove(selected);

            $scope.change();
        }
    };

    //========================================================

    $scope.$on('asterisk_commands_log', function (e, args){
        var data = args[0];

        if (asterisk.initialized){
            if (data.status <= 0){
                asterisk.State = OFFLINE;
            } else
            if (data.status == 1) {
                asterisk.State = RECONNECT;
            } else
            if (data.status >= 2) {
                asterisk.State = ONLINE;
            }

            if (asterisk.State === ONLINE || asterisk.State === RECONNECT) {
                asterisk.view_connect   .hide();
                asterisk.view_disconnect.show();
                asterisk.view_sendCMD   .enable();
                asterisk.view_sendPING  .enable();
                asterisk.view_sendList  .enable();
            } else {
                asterisk.view_connect   .show();
                asterisk.view_disconnect.hide();
                asterisk.view_sendCMD   .disable();
                asterisk.view_sendPING  .disable();
                asterisk.view_sendList  .disable();
            }

            fieldLock();

            setLog("<div>" + data.Log.replace(/\n/g, "<br/>") + "</div>");
        }
    });

    //========================================================

    fillOptions(options);

    webix.editors.selectGroup = webix.extend({
        setValue:function(value){
            this._initial_value = value && value.id ? value.id : value;

            if (this.config.suggest){
                var sobj = webix.$$(this.config.suggest);
                var data =  this.config.collection || this.config.options;

                if (data){
                    sobj.getList().data.importData(data);
                }

                var id = value && value.id ? value.id : value;

                this._initial_text = id >= 0 ? sobj.getItemText(id) : mcLang(140);// + " (ID: -1)";

                this.getInputNode(this.node).value = this._initial_text;
            }
        },
        getValue:function(){
            var id = webix.$$(this.config.suggest).getSuggestion();

            return {
                value: id >= 0 ? this.getInputNode().value : mcLang(140),// + " (ID: -1)",
                id   : id
            };
        },
        showPopup:function(){
            var popup = this.getPopup();
            var list = popup.getList();
            var input = this.getInputNode();
            var value = this.getValue();

            popup.show(input);
            input.setAttribute("aria-expanded", "true");

            if (value && value.id && list.exists(value.id)){
                list.select(value.id);
                list.showItem(value.id);
            } else {
                list.unselect();
                list.showItem(list.getFirstId());
            }

            popup._last_input_target = input;
        },
        afterRender:function(){
            var editItem = this;

            if (editItem.config.options && editItem.config.options.length){
                editItem.showPopup();
            } else {
                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_get_user_groups,
                    mcConst.SessionID,
                    
                    function(data){
                        asterisk.grData = data || [];

                        var ListItem = asterisk.view_ServersList.getItem(editItem.row);
                        var body = editItem.getPopup();
                        var list = body.getList();

                        if (editItem.config.width < 300){
                            body.config.fitMaster = false;
                            body.config.minWidth = 300;
                            body.resize();
                        }

                        editItem.config.options = [{id: '-1', value: mcLang(140)}]; // "140": "Ничего не выбрано",

                        asterisk.grData.sort(function (a, b) {
                            return mcService.sortAB(a.Name, b.Name);
                        });

                        asterisk.grData.forEach(function (itm) {
                            editItem.config.options.push({
                                id   : itm.ID,
                                value: itm.Name
                            });
                        });

                        list.define("template", "#value#"); //  (ID: #id#)
                        list.parse (editItem.config.options);
                        list.select(ListItem.UserGroup.id);

                        editItem.setValue(ListItem.UserGroup.id);
                        editItem.showPopup();
                    }
                ]);
            }
        }
    }, webix.editors.combo);
}

function toolTurbosmsView(turbosms, $scope) {
    var placeholderUA = "(11) 222-33-44";
    var patternUA     = { mask:"(##) ###-##-##", allow:/[0-9]/g };
    var placeholderRU = "(111) 222-33-44";
    var patternRU     = { mask:"(###) ###-##-##", allow:/[0-9]/g };

    var countries = [
        {id: 380, value: "UA +380"},
        {id: 7,   value: "RU +7"},
        {id: 375, value: "BY +375"}
    ];

    var view =
    { id: "view_" + turbosms.name, hidden: $scope.shovedView !== turbosms.name, rows: [
        { view: "checkbox", id: "enable" + turbosms.name, value: '', labelWidth: 0, css: "finger",
            labelRight: mcService.Lang(1753, 'TurboSMS'), // "1753":"Включить интеграцию с %s",
            on: { onItemClick: $scope.change }
        },

        { height: 5},

        { cols: [
            { maxWidth: 500, minWidth: 400, rows: [
                { template: mcService.insertIco("fa-info-circle") + mcLang(2157), css: "_info selectable", autoheight: true}, // "2157":"<a href='https://nsoft-s.com/mcserverhelp/index.html?toolsintegrationsturbosms.htm' target='_blank'>TurboSMS</a> — это сервис для отправки SMS или Viber сообщений в Украине, России и Беларуси. Сообщения отправляются с <a href='https://nsoft-s.com/mcserverhelp/index.html?scriptsfuncintegrationsturbosms.htm' target='_blank'>помощью скриптов</a>.",

                { view: "text", id: "Sender" + turbosms.name, value: turbosms.sender, label: "Sender",  labelWidth: 100, on: { onTimedKeyPress: function () {
                    if (this.getValue() !== turbosms.sender) {
                        $scope.change();
                        // asterisk.view_connect.disable();
                    }
                }} },

                { view: "text", id: "Token" + turbosms.name, value: turbosms.token, label: "Token",  labelWidth: 100, on: { onTimedKeyPress: function () {
                    if (this.getValue() !== turbosms.token) {
                        $scope.change();
                        // asterisk.view_connect.disable();
                    }
                }} },

                { cols: [
                    {width: 4},
                    { view: "label", label: mcLang(2156), width: 73}, // "2156":"Баланс",
                    { id: "refresh" + turbosms.name, view: "button", icon: "refresh", type: "icon", width: 30, disable: turbosms.enabled, click: function () { // "53" : "Обновить",
                        turbosms.checkBalance(true);
                    }},
                    { view: "label", id: "balance" + turbosms.name, label: " ", width: 100, align: "left"},
                ]},

                { height: 10 },

                { template: mcLang(2154), autoheight: true, borderless: true}, // "2154":"Тестовая отправка сообщения",

                { cols: [
                    { view: "label", label: mcLang(2155), width: 150},
                    { view: "select", value: 380, options: countries, width: 100, on: {onChange: function (id){
                        switch (id){
                            case 380: case 375:
                                turbosms.viewTel.define("placeholder", placeholderUA);
                                turbosms.viewTel.define("pattern", patternUA);
                                turbosms.viewTel.refresh();
                            break;

                            case 7:
                                turbosms.viewTel.define("placeholder", placeholderRU);
                                turbosms.viewTel.define("pattern", patternRU);
                                turbosms.viewTel.refresh();
                            break;
                        }

                        turbosms.prefix = id;
                    }}},
                        
                    { view: "text", id: "Tel" + turbosms.name, placeholder: placeholderUA, pattern: patternUA, labelWidth: 0 }, // "2155":"Номер телефона",
                ]},

                { height: 5 },

                { cols: [
                    { id: "sms"   + turbosms.name, view: "button", value: "SMS",   disable: turbosms.enabled, click: turbosms.sendSMS},
                    { id: "viber" + turbosms.name, view: "button", value: "Viber", disable: turbosms.enabled, click: turbosms.sendViber}
                ]},

                { height: 10 },

                { view: "template", id: "logs" + turbosms.name, template: "<div id='turbosms_log_container' style='word-break: break-all;'></div>", css: "selectable scrollMenu"},
            ]},
            {}
        ]},

        // {}
    ]};

    turbosms.initView = function () {
        if (turbosms.initialized) {
            turbosms.checkBalance();

            return;
        }

        turbosms.viewEnable  = $$("enable" + turbosms.name);
        turbosms.viewTel     = $$("Tel"    + turbosms.name);
        turbosms.viewToken   = $$("Token"  + turbosms.name);
        turbosms.viewSender  = $$("Sender" + turbosms.name);
        turbosms.viewLogs    = $$("logs"   + turbosms.name);
        turbosms.viewbalance = $$("balance"+ turbosms.name);
                             
        turbosms.btnSms      = $$("sms"    + turbosms.name);
        turbosms.btnViber    = $$("viber"  + turbosms.name);
        turbosms.btnRefresh  = $$("refresh"+ turbosms.name);

        turbosms.turbosms_log_container = document.getElementById("turbosms_log_container");

        turbosms.initialized = true;
    };

    return view;
}

function ToolTurbosms($scope, $rootScope, options) {
    var turbosms     = this;
    var hasBalance   = false;

    function fillOptions(opts){
        Object.keys(opts).forEach(function (item) {
            turbosms[item] = opts[item];
        });
    }

    function setLog(log){
        if (!turbosms.turbosms_log_container) {
            turbosms.turbosms_log_container = document.getElementById("turbosms_log_container");
        }

        setTimeout(function (){
            turbosms.turbosms_log_container.innerHTML += log;
            turbosms.viewLogs.getNode().scroll({
                top     : turbosms.turbosms_log_container.clientHeight,
                left    : 0,
                behavior: 'smooth'
            });
        }, 50);
    }

    //========================================================

    fillOptions(options);

    //========================================================

    turbosms.checkBalance = function (checkNow){
        if (turbosms.enabled && turbosms.initialized && !hasBalance || checkNow){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_integration_turbosms_check_balance,
                mcConst.SessionID,

                function(data) {
                    hasBalance = true;

                    if (data.response_result && data.response_result.hasOwnProperty("balance")) {
                        turbosms.viewbalance.setValue(data.response_result.balance);
                    }

                    setLog("<div>" + JSON.stringify(data) + "</div>"); // .replace(/\n/g, "<br/>")
                }
            ]);
        }
    }

    turbosms.fillOptions = fillOptions;

    turbosms.fillTool = function () {
        // var link = mcService.getLocalHostPath(true) + "/serverhelp/index.html?integrationapigeoip.htm";
        turbosms.viewEnable.setValue(turbosms.enabled);
        turbosms.viewToken .setValue(turbosms.token);
        turbosms.viewSender.setValue(turbosms.sender);

        if (!turbosms.enabled){
            turbosms.btnSms    .disable();
            turbosms.btnViber  .disable();
            turbosms.btnRefresh.disable();
        } else {
            turbosms.checkBalance();

            turbosms.btnSms    .enable();
            turbosms.btnViber  .enable();
            turbosms.btnRefresh.enable();
        }
    };

    turbosms.saveData = function() {
        var res = {
            name     : $scope.iNames.TURBOSMS,
            enabled  : mcService.convertIntToBool(turbosms.viewEnable.getValue()),
            token    : turbosms.viewToken.getValue(),
            sender   : turbosms.viewSender.getValue()
        };

        hasBalance = false;

        turbosms = mcService.Marge(turbosms, res);

        return res;
    };

    turbosms.getView = function () {
        return toolTurbosmsView(turbosms, $scope);
    };

    turbosms.sendSMS = function (){
        if (turbosms.enabled){
            var tel = turbosms.viewTel.getValue();

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_integration_turbosms_send_message,
                mcConst.SessionID,

                turbosms.prefix + tel,
                "sms",

                function(data) {
                    setLog("<div>" +JSON.stringify(data) + "</div>"); // .replace(/\n/g, "<br/>")
                }
            ]);
        }
    };

    turbosms.sendViber = function (){
        if (turbosms.enabled){
            var tel = turbosms.viewTel.getValue();

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_integration_turbosms_send_message,
                mcConst.SessionID,

                turbosms.prefix + tel,
                "viber",

                function(data) {
                    setLog("<div>" + JSON.stringify(data) + "</div>"); // .replace(/\n/g, "<br/>")
                }
            ]);
        }
    };

    // =========================================================================

    $scope.$on('turbosms_commands_log', function (e, args){
        var data = args[0];

        if (turbosms.initialized){
            setLog("<div>" + JSON.stringify(data) + "</div>");

            if (data.response_code != "0" || data.response_code != "1"){
                turbosms.viewEnable.setValue(false);
            }
        }
    });

    // =========================================================================
}
function initLicenseMyChat($scope){
    "use strict";

    var _view = $$($scope.Name);

    if (_view){
        _view.destructor();
    }

    var license = "";

    if ($scope.data.register) {
        license = "<span style='font-size: 110%'>" + mcService.Lang(947) + //"947":"MyChat Server зарегистрирован на: ",
                  "<br><span style='color: green'>" + $scope.data.license + "</span></span>";
    } else {
        license = "<span style='font-size: 110%'>" + mcService.Lang(949) + "</span>"; // + // "949":"Бесплатная версия MyChat Server",
    }

    _view = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(946) }, // "946":"Лицензии MyChat Server",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5, cols : [
                { rows : [{
                    autoheight: true,
                    borderless: true,
                    template : license
                }, {
                    view: "button", value: mcService.Lang(948), // "948":"Ввести лицензионный ключ",
                    hidden : $scope.data.register,
                    disabled: _gLock.License || false,
                    maxWidth : 370,
                    click : $scope.showDialog
                }, {
                    view: "button", value: mcService.Lang(1010), // "1010":"Показать лицензионный ключ",
                    hidden : !$scope.data.register,
                    disabled: _gLock.License || false,
                    maxWidth : 370,
                    click : $scope.showRegKey
                }, {
                    borderless: true,
                    template : mcService.insertIco('fa-shopping-cart') + '<a href="' + mcLang(1788) + '" target="_blank">' + mcService.Lang(1012) + '</a>' , // "1012":"Купить лицензию", "1788":"https://nsoft-s.com/buymychat.html",
                    hidden   : $scope.data.register,
                    height   : 35
                }
                ]}, {}
            ]},
            { type: 'layout', padding: 5, hidden: !$scope.data.register, cols: [
                { rows: [
                    /*{ view: "button", maxWidth: 370, disabled: _gLock.License || false, value: mcService.Lang(950), click : function() {// "950":"Ввести ключ расширения лицензии",
                     $scope.showDialog();
                     }},*/
                    { view: "button", maxWidth: 370, disabled: _gLock.License || false, value: mcService.Lang(948), click : function() {// "948":"Ввести лицензионный ключ",
                        $scope.showDialog();
                    }},
                    { borderless: true, height: 35, template : mcService.insertIco('fa-shopping-cart') + '<a href="' + mcLang(1788) + '" target="_blank">' + mcService.Lang(1012) + '</a>'} // "1012":"Купить лицензию", "1788":"https://nsoft-s.com/ua/buymychat.html",
                ]},
                {}
            ]},
            { type: 'layout', padding: 5, hidden: !$scope.data.register, cols: [
                { width: 10 },
                { width: 180, rows: [
//                { template: mcService.Lang(1102), autoheight: true, borderless: true, css: "byRight"  }, // "1102":"MyChat зарегистрирован на:",
                    { template: mcService.Lang(1103), autoheight: true, borderless: true, css: "byRight"  }, // "1103":"Дата покупки сервера:",
                    { template: mcService.Lang(1104), autoheight: true, borderless: true, css: "byRight"  }, // "1104":"Обновления можно до:",
                    { template: mcService.Lang(20)+":", autoheight: true, borderless: true, css: "byRight"  }  // "20" : "Количество подключений" 'Connections'
                ]},
                { rows: [
//                { template: $scope.data.owner,      css: "bolder", autoheight: true, borderless: true },
                    { template: $scope.data.saleDate,   css: "bolder", autoheight: true, borderless: true },
                    { template: $scope.data.updateEnd,  css: "bolder", autoheight: true, borderless: true },
                    { template: $scope.data.MaxConnects,css: "bolder", autoheight: true, borderless: true }
                ]}
            ]},
            {   template  : '<iframe width="640" height="360" src="https://www.youtube.com/embed/fqMbanFfi8c?rel=0" frameborder="0" allowfullscreen></iframe>',
                borderless: true,
                css       : "noBG",
                id        : "mcGuestVideo" + $scope.Name,
                height    : 370
            }
        ]
    });

    mcService.disableContextMenu(_view);

    return _view;
}
function licenseMyChatController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.LicenseMyChat;
    $scope.data = {};
    $scope.showDialog   = null;
    $scope.dialogWindow = null;

    var angElement = document.getElementById($scope.Name);
    var mcKey  = "";
    var mcName = "";

    $scope.showDialog = function (){
        if ($scope.dialogWindow){
            $scope.dialogWindow.destructor();
        }

        var body = {
            view : 'form',
            elements : [{
                view     : "text",
                label    : mcService.Lang(952), // "952":"Лицензионный ключ",
                name     : 'Key',
                required : "true",
                labelPosition : 'top',
                on: {
                    onKeyPress: function(code , e){
                        if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                            var isValid = this.getFormView().validate();

                            if (isValid){
                                $scope.sendMcKey();
                                $scope.dialogWindow.hide();
                            }

                            return false;
                        }
                    }
                }
            }, {
                cols : [{
                    view  : "button",
                    value : mcService.Lang(104), // "104": "Сохранить",
                    click : function() {
                        var isValid = this.getFormView().validate();

                        if (isValid){
                            $scope.sendMcKey();
                            $scope.dialogWindow.hide();
                        }
                    }
                }, {
                    view  : "button",
                    type  : "danger",
                    value : mcService.Lang(103), // "103": "Отмена",
                    click : function(){
                        $scope.dialogWindow.hide();
                    }
                }]
            }]
        };

        if ($scope.data.license != ""){
            body.rules = {
                "Key"    : $scope.checkKey,
                "Name"   : $scope.checkName
            };

            body.elements.unshift({
                view     : "text",
                label    : mcService.Lang(1808), // "1808":"Регистрационное имя",
                name     : 'Name',
                required : "true",
                labelPosition : 'top'
            });
        }

        $scope.dialogWindow = webix.ui({
            view     : "window",
            position : "center",
            modal    : true,
            width    : 470,
            head     : mcService.Lang(946), // "946":"Лицензии MyChat Server",
            body     : body,
            on : {
                onShow : function(){
                    this.getChildViews()[1].getChildViews()[0].setValue($scope.data.license == "-" ? "" : $scope.data.license);

                    if ($scope.data.license == "-") {
                        this.getChildViews()[1].getChildViews()[0].focus();
                    } else {
                        this.getChildViews()[1].getChildViews()[1].focus();
                    }

                    $scope.regShowWindow(this.config.id, this);
                }
            }
        });

        $scope.dialogWindow.show();
    };

    $scope.showRegKey = function(){
        webix.ui({
            view     : "window",
            position : "center",
            modal    : true,
            height   : 100,
            width    : 450,
            head     : mcService.Lang(952), // "952":"Лицензионный ключ",
            body     : {
                padding : 5,
                rows    : [
                    { template: $scope.data.regKey, css: "selectable licenseKey", borderless: true},
                    { height: 5 },

                    { cols: [
                        { view: "button", value: mcService.Lang(12), // "12" : "Закрыть",
                            click : function() {
                                this.getTopParentView().hide();
                            }
                        },

                        { view: "button", value: mcService.Lang(1806), // "1806":"Скопировать ключ",
                            click : function() {
                                var emailLink = document.querySelector('.licenseKey');
                                var range = document.createRange();

                                range.selectNode(emailLink);
                                window.getSelection().addRange(range);

                                try {
                                    // Now that we've selected the anchor text, execute the copy command
                                    var successful = document.execCommand('copy');
                                    var msg = successful ? 'successful' : 'unsuccessful';

                                    console.log('Copy key command was ' + msg);
                                } catch(err) {
                                    console.log('Oops, unable to copy');
                                }

                                window.getSelection().removeAllRanges();

                                webix.message(mcLang(1807)); // "1807":"Ключ скопирован в буффер обмена",
                            }
                        }
                    ]}
                ]
            },
            on: { onShow: function(){ $scope.regShowWindow(this.config.id, this); } }
        }).show();
    };

    $scope.checkKey = function(key) {
        mcKey = mcService.checkLicenseKey(key.toUpperCase());

        if (mcKey == false && mcService.oldLicenseKey(key.toUpperCase())){
            webix.alert({
                width : "400px",
                text  : mcService.Lang(1101) // "1101":"Вы ввели старый ключ,
            });
        }

        return mcKey;
    };

    $scope.checkName = function(name){
        var res = mcService.trim(name) != '';

        if (res) {
            mcName = mcService.trim(name);
        }

        return res;
    };

    $scope.sendMcKey = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_enter_mychat_reg_data,
            mcConst.SessionID,
            mcName,
            mcKey
        ]);

        mcConst.restartOptions[0] = mcConst.restartItems.MyChat;

        $rootScope.$broadcast('NeedRestartServer', []);

        webix.alert({text: mcService.Lang(953), width: 350}); // "953":"Ключ сохранен. <br>Пожалуйста, перезапустите MyChat Server",
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initLicenseMyChat($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_licenses,
            mcConst.SessionID,
            function (data){
                if (_gLock.License) data.ServerLicenseKey = "";

                mcConst.LicenseInfo = data;

                $scope.data.register  =!data.IsFree;
                $scope.data.license   = data.ServerRegisteredBy;
                $scope.data.regKey    = data.ServerLicenseKey || "AAAA-BBBB-1111-2222-3333-4444-FFFF";
                $scope.data.owner     = data.ServerRegisteredBy;
                $scope.data.updateEnd = data.ServerUpdatesEndDate;
                $scope.data.saleDate  = data.ServerKeySaleDate;
                $scope.data.MaxConnects = $rootScope.mcStorage.ServerInfo.MaxConnects;

                $scope.show(data);
            }
        ]);
    });
}

function initLicenseGuest($scope){
    "use strict";

    var _view = $$($scope.Name);

    if (_view){
        _view.destructor();
    }

    var license = "";

    if ($scope.data.IsMyChatGuestRegistered) {
        license = "<span style='font-size: 110%; color: green'>" + mcService.Lang(945) + // "945":"MyChat Guest",
                  " &#151; " + mcService.Lang(939) + "</span>";                          // "939":"сервис активирован",
    } else {
        license = "<span style='font-size: 110%; color: red'>" + mcService.Lang(945) +   // "945":"MyChat Guest",
                  " &#151; " + mcService.Lang(1007) + "</span>";                         // "1007":"необходима активация",
    }

    _view = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(955) }, // "955":"Лицензия MyChat Guest",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5, cols : [
                { rows : [{
                    autoheight : true,
                    borderless : true,
                    template   : license
                }, {
                    view     : "button",
                    value    : mcService.Lang(948), // "948":"Ввести лицензионный ключ",
                    hidden   : $scope.data.IsMyChatGuestRegistered,
                    disabled : _gLock.License || false,
                    maxWidth : 350,
                    click    : function() {
                        $scope.showDialog();
                    }
                }, {
                    borderless: true,
                    template : mcService.insertIco('fa-shopping-cart') + '<a href="' + mcLang(1788) + '" target="_blank">' + mcService.Lang(1721) + '</a>' , // "1721":"Купить лицензию", "1788":"https://nsoft-s.com/ua/buymychat.html",
                    hidden   : $scope.data.IsMyChatGuestRegistered,
                    height   : 35
                }
                ]}, {}
            ]},
            { type: 'layout', padding: 5, hidden: $scope.data.IsMyChatGuestRegistered, cols : [
                { rows: [{
                    height : 30,
                    borderless: true,
                    template: mcService.Lang(1011, $scope.invites) // "1011":"Отправлено бесплатных приглашений MyChat Guest %s из 25",
                }]}, {}
            ]},
            {   template  : '<iframe width="640" height="360" src="//www.youtube.com/embed/r66BSA7JbPw" frameborder="0" allowfullscreen></iframe>',
                borderless: true,
                css       : "noBG",
                id        : "mcGuestVideo" + $scope.Name,
                height    : 370
            }
        ]
    });

    if (!$scope.showDialog){
        $scope.showDialog = function (){
            if ($scope.dialogWindow){
                $scope.dialogWindow.destructor();
            }

            var body = {
                view  : 'form',
                rules : {
                    "Key"    : $scope.checkKey
                },
                elements : [{
                    view     : "text",
                    label    : mcService.Lang(952), // "952":"Лицензионный ключ",
                    name     : 'Key',
                    required : "true",
                    labelPosition : 'top',
                    on: {
                        onKeyPress: function(code , e){
                            if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                                var isValid = this.getFormView().validate();

                                if (isValid){
                                    $scope.sendMcKey();
                                    $scope.dialogWindow.hide();
                                }

                                return false;
                            }
                        }
                    }
                }, {
                    cols : [{
                        view  : "button",
                        value : mcService.Lang(104), // "104": "Сохранить",
                        click : function() {
                            var isValid = this.getFormView().validate();

                            if (isValid){
                                $scope.sendKey();
                                $scope.dialogWindow.hide();
                            }
                        }
                    }, {
                        view  : "button",
                        type  : "danger",
                        value : mcService.Lang(103), // "103": "Отмена",
                        click : function(){
                            $scope.dialogWindow.hide();
                        }
                    }]
                }]
            };

            $scope.dialogWindow = webix.ui({
                view     : "window",
                position : "center",
                modal    : true,
                width    : 350,
                head     : mcService.Lang(945),
                body     : body,
                on: { onShow: function(){ $scope.regShowWindow(this.config.id, this); } }
            });

            $scope.dialogWindow.show();
        }
    }

    mcService.disableContextMenu(_view);

    return _view;
}
function licenseGuestController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.LicenseGuest;
    $scope.data = {};
    $scope.showDialog   = null;
    $scope.dialogWindow = null;

    var angElement = document.getElementById($scope.Name);
    var mcKey  = "";

    $scope.checkKey = function(key) {
        mcKey = mcService.checkGuestKey(key.toUpperCase());

        return mcKey;
    };

    $scope.sendKey = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_enter_mychat_guest_reg_data,
            mcConst.SessionID,
            mcKey
        ]);

        mcConst.restartOptions[0] = mcConst.restartItems.MyChat;

        $rootScope.$broadcast('NeedRestartServer', []);

        webix.alert(mcService.Lang(953)); // "953":"Ключ сохранен. Пожалуста, завершите работу MyChat Server и запустите его заново",
    };

    $scope.show = function(data){
        $scope.data    = data || mcConst.LicenseInfo;
        $scope.invites = $rootScope.mcStorage.ServerInfo.MyChatGuestInvites + "";

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initLicenseGuest($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.generateKey = function(){
        var key = $$("stgIntegrationAPIKey");
        var val = mcService.RandomHash(20);

        key.define('value', val);
        key.refresh();

        $scope.change.apply(key, [val]);
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        $$("mcGuestVideo" + $scope.Name).destructor();
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_server_info,
            mcConst.SessionID,
            function( _data ){
                $rootScope.mcStorage.ServerInfo = _data;

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst._CMD_.cs_adm_get_licenses,
                    mcConst.SessionID,
                    function (data){
                        mcConst.LicenseInfo = data;

                        $scope.show(data);
                    }
                ]);
            }
        ]);
    });
}

function initLicenseClear($scope){
    "use strict";

    var _view = $$($scope.Name);

    if (_view){
        _view.destructor();
    }

    var license = "";

    if ($scope.data.IsMyChatGuestRegistered) {
        license = "<span style='font-size: 110%; color: green'>" + mcService.Lang(1958) + // "1958":"MyChat Clear",
                  " &#151; " + mcService.Lang(939) + "</span>";                          // "939":"сервис активирован",
    } else {
        license = "<span style='font-size: 110%; color: red'>" + mcService.Lang(1958) +   // "1958":"MyChat Clear",
                  " &#151; " + mcService.Lang(1007) + "</span>";                         // "1007":"необходима активация",
    }

    _view = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(1959) }, // "1959":"Лицензия MyChat Clear",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5, cols : [
                { rows : [{
                    autoheight : true,
                    borderless : true,
                    template   : license
                }, {
                    view     : "button",
                    value    : mcService.Lang(948), // "948":"Ввести лицензионный ключ",
                    hidden   : $scope.data.IsMyChatClearRegistered,
                    disabled : _gLock.License || false,
                    maxWidth : 350,
                    click    : function() {
                        $scope.showDialog();
                    }
                }, {
                    borderless: true,
                    template : mcService.insertIco('fa-shopping-cart') + '<a href="' + mcLang(1788) + '" target="_blank">' + mcService.Lang(1721) + '</a>' , // "1721":"Купить лицензию", "1788":"https://nsoft-s.com/ua/buymychat.html",
                    hidden   : $scope.data.IsMyChatClearRegistered,
                    height   : 35
                }
                ]}, {}
            ]}
        ]
    });

    if (!$scope.showDialog){
        $scope.showDialog = function (){
            if ($scope.dialogWindow){
                $scope.dialogWindow.destructor();
            }

            var body = {
                view  : 'form',
                rules : {
                    "Key"    : $scope.checkKey
                },
                elements : [{
                    view     : "text",
                    label    : mcService.Lang(952), // "952":"Лицензионный ключ",
                    name     : 'Key',
                    required : "true",
                    labelPosition : 'top',
                    on: {
                        onKeyPress: function(code , e){
                            if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                                var isValid = this.getFormView().validate();

                                if (isValid){
                                    $scope.sendMcKey();
                                    $scope.dialogWindow.hide();
                                }

                                return false;
                            }
                        }
                    }
                }, {
                    cols : [{
                        view  : "button",
                        value : mcService.Lang(104), // "104": "Сохранить",
                        click : function() {
                            var isValid = this.getFormView().validate();

                            if (isValid){
                                $scope.sendKey();
                                $scope.dialogWindow.hide();
                            }
                        }
                    }, {
                        view  : "button",
                        type  : "danger",
                        value : mcService.Lang(103), // "103": "Отмена",
                        click : function(){
                            $scope.dialogWindow.hide();
                        }
                    }]
                }]
            };

            $scope.dialogWindow = webix.ui({
                view     : "window",
                position : "center",
                modal    : true,
                width    : 350,
                head     : mcService.Lang(945),
                body     : body,
                on: { onShow: function(){ $scope.regShowWindow(this.config.id, this); } }
            });

            $scope.dialogWindow.show();
        }
    }

    mcService.disableContextMenu(_view);

    return _view;
}
function licenseClearController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.LicenseClear;
    $scope.data = {};
    $scope.showDialog   = null;
    $scope.dialogWindow = null;

    var angElement = document.getElementById($scope.Name);
    var mcKey  = "";

    $scope.checkKey = function(key) {
        mcKey = mcService.checkGuestKey(key.toUpperCase());

        return mcKey;
    };

    $scope.sendKey = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_enter_mychat_guest_reg_data,
            mcConst.SessionID,
            mcKey
        ]);

        mcConst.restartOptions[0] = mcConst.restartItems.MyChat;

        $rootScope.$broadcast('NeedRestartServer', []);

        webix.alert(mcService.Lang(953)); // "953":"Ключ сохранен. Пожалуста, завершите работу MyChat Server и запустите его заново",
    };

    $scope.show = function(data){
        $scope.data    = data || mcConst.LicenseInfo;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initLicenseClear($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_server_info,
            mcConst.SessionID,
            function( _data ){
                $rootScope.mcStorage.ServerInfo = _data;

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst._CMD_.cs_adm_get_licenses,
                    mcConst.SessionID,
                    function (data){
                        mcConst.LicenseInfo = data;

                        $scope.show(data);
                    }
                ]);
            }
        ]);
    });
}

"use strict";

function initLicenseQuiz($scope){
    var _view = $$($scope.Name);

    if (_view){
        _view.destructor();
    }

    var license = "";

    if ($scope.data.QuizRegistered) {
        license = "<span style='font-size: 110%; color: green'>" + mcService.Lang(2033) + // "2033":"MyChat викторина",
                  " &#151; " + mcService.Lang(939) + "</span>";                          // "939":"сервис активирован",
    } else {
        license = "<span style='font-size: 110%; color: red'>" + mcService.Lang(2033) +   // "2033":"MyChat викторина",
                  " &#151; " + mcService.Lang(1007) + "</span>";                         // "1007":"необходима активация",
    }

    _view = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(2034) }, // "2034":"Лицензия MyChat викторина",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type: 'layout', padding: 5, cols : [
                { rows : [{
                    autoheight : true,
                    borderless : true,
                    template   : license
                }, {
                    view     : "button",
                    value    : mcService.Lang(948), // "948":"Ввести лицензионный ключ",
                    hidden   : $scope.data.QuizRegistered,
                    disabled : _gLock.License || false,
                    maxWidth : 350,
                    click    : function() {
                        $scope.showDialog();
                    }
                }, {
                    borderless: true,
                    template : mcService.insertIco('fa-shopping-cart') + '<a href="' + mcLang(2032) + mcConst.UserInfo.ServID + '" target="_blank">' + mcService.Lang(1721) + '</a>' , // "1721":"Купить лицензию", "2032":"https://nsoft-s.com/buyvictorinabot.html?ID=",
                    hidden   : $scope.data.QuizRegistered,
                    height   : 35
                }
                ]}, {}
            ]}
        ]
    });

    if (!$scope.showDialog){
        $scope.showDialog = function (){
            if ($scope.dialogWindow){
                $scope.dialogWindow.destructor();
            }

            var body = {
                view  : 'form',
                rules : {
                    "Key"    : $scope.checkKey
                },
                elements : [{
                    view     : "text",
                    label    : mcService.Lang(952), // "952":"Лицензионный ключ",
                    name     : 'Key',
                    required : "true",
                    labelPosition : 'top',
                    on: {
                        onKeyPress: function(code , e){
                            if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
                                var isValid = this.getFormView().validate();

                                if (isValid){
                                    $scope.sendKey();
                                    $scope.dialogWindow.hide();
                                }

                                return false;
                            }
                        }
                    }
                }, {
                    cols : [{
                        view  : "button",
                        value : mcService.Lang(104), // "104": "Сохранить",
                        click : function() {
                            var isValid = this.getFormView().validate();

                            if (isValid){
                                $scope.sendKey();
                                $scope.dialogWindow.hide();
                            }
                        }
                    }, {
                        view  : "button",
                        type  : "danger",
                        value : mcService.Lang(103), // "103": "Отмена",
                        click : function(){
                            $scope.dialogWindow.hide();
                        }
                    }]
                }]
            };

            $scope.dialogWindow = webix.ui({
                view     : "window",
                position : "center",
                modal    : true,
                width    : 350,
                head     : mcService.Lang(2033), // "2033":"MyChat викторина",
                body     : body,
                on: { onShow: function(){ $scope.regShowWindow(this.config.id, this); } }
            });

            $scope.dialogWindow.show();

            $scope.dialogWindow.getChildViews()[1].elements["Key"].focus();
        }
    }

    mcService.disableContextMenu(_view);

    return _view;
}
"use strict";

function licenseQuizController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.LicenseQuiz;
    $scope.data = {};
    $scope.showDialog   = null;
    $scope.dialogWindow = null;

    var angElement = document.getElementById($scope.Name);
    var mcKey  = "";

    function getLicenseInfo(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_licenses,
            mcConst.SessionID,
            function (data){
                mcConst.LicenseInfo = data;

                $scope.show(data);
            }
        ]);
    }

    $scope.checkKey = function(key) {
        mcKey = mcService.checkQuizKey(key.toUpperCase());

        return mcKey;
    };

    $scope.sendKey = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_enter_quiz_reg_data,
            mcConst.SessionID,
            mcKey,

            getLicenseInfo
        ]);
    };

    $scope.show = function(data){
        $scope.data    = data || mcConst.LicenseInfo;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initLicenseQuiz($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_server_info,
            mcConst.SessionID,
            function( _data ){
                $rootScope.mcStorage.ServerInfo = _data;

                getLicenseInfo();
            }
        ]);
    });
}

"use strict";

function initAntiflood($scope){
    var labelWidth   = 350;

    var settings = $$($scope.Name);

    if (!settings){
        settings = webix.ui({
            type       : "space",
            padding    : 5,
            container  : $scope.Name,
            id         : $scope.Name,
            borderless : true,
            rows       : [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(1057) }, // "1057":"Антифлуд",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type : 'layout', padding : 5, rows : [
                    { view: "checkbox",id: "atfAntiFloodEnabled", value: $scope.data.AntiFloodEnabled, labelRight: mcService.Lang(1062), labelWidth: 0, css: "finger", on: {onChange: $scope.change}} // "1062":"Включить защиту от флуда",
                ]},
                { type : 'layout', padding : 5, rows: [
                    { view: "counter", id: "atfCriticalEventsCount",value: $scope.data.CriticalEventsCount, labelWidth: labelWidth, label: mcService.Lang(1063), step: 1, min: 1, max: 100,
                        on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }, //""1063":"Критическое количество событий",
                    { view: "counter", id: "atfBySeconds",          value: $scope.data.BySeconds, labelWidth: labelWidth, label: mcService.Lang(1064), step: 1, min: 1, max: 100,
                        on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} }, //"1064":"В еденицу времени (секунды):",
                    { view: "counter", id: "atfIgnoreFlooderSec",   value: $scope.data.IgnoreFlooderSec, labelWidth: labelWidth, label: mcService.Lang(1065), step: 1, min: 1, max: 600,
                        on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} } //"1065":"Игнорировать флудера (в секунду):",
                ]},
                { type: 'layout', padding: 5, rows: [
                    { view: "checkbox",id: "atfUseRecurringEvents", value: $scope.data.UseRecurringEvents, labelRight: mcService.Lang(1066), labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "1066":"Считать флудом повторяющиеся слова и смайлики в одном сообщении",
                    { view: "counter", id: "atfMaxRecurringWords",  value: $scope.data.MaxRecurringWords, labelWidth: labelWidth, label: mcService.Lang(1067), step: 1, min: 1, max: 100, 
                        on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} } //"1067":"Количество повторений:",
                ]},
                { type: 'layout', padding: 5, rows: [
                    { view: "checkbox",id: "atfUseRecurringImages", value: $scope.data.UseRecurringImages, labelRight: mcService.Lang(1068), labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "1068":"Считать флудом повторяющиеся изображения",
                    { view: "counter", id: "atfMaxRecurringImages", value: $scope.data.MaxRecurringImages, labelWidth: labelWidth, label: mcService.Lang(1067), step: 1, min: 1, max: 100, 
                        on: {onChange: $scope.change, onTimedKeyPress: $scope.changeExc} } //"1067":"Количество повторений:",
                ]},
                { type: "header", template: mcService.Lang(1069)}, // "1069":"Список пользователей, которых не касаються ограничения",
                { type: 'layout', padding: 5, cols: [
                    { rows: [
                        new mcService.ListButtonSet({
                            type   : '3',
                            actions: $scope.antifloodActions,
                            list   : "atfExceptUsers",
                            selectedItem: "value",
                            regShowWindow: $scope.regShowWindow
                        }),
                        { view: "list", id: "atfExceptUsers", select: true, template: "#value# (UIN: #id#)" }
                    ]}, {}
                ]}
            ]
        });

        $scope.exceptUserList    = $$('atfExceptUsers');

        mcService.disableContextMenu(settings);
    } else {

    }

    return settings;
}

"use strict";

function filterAntifloodController($scope, $rootScope){
    $scope.Name               = mcConst.dataModels.FilterAntiflood;
    $scope.exceptUserList     = null;
    $scope.exceptUserListData = [];
    $scope.antifloodActions   = {};

    var angElement = document.getElementById($scope.Name);
    var _view = null;

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_antiflood_filter_data, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    }, mcConst.dataModels.FilterAntiflood);

    $scope.antifloodActions.preview = function(field){
        mcService.getAllUserForFillList($scope.exceptUserListData, function fill_uList (data){
            $scope.exceptUserListData = mcService.transformDataObject(webix.copy(data), [['DisplayName', 'value'], ['UIN', 'id']]);

            field.define('options', $scope.exceptUserListData);
            field.getList().define('template', "#value# (#id#)");
            field.refresh();
            field.setValue($scope.exceptUserListData[0].id);
        }, $rootScope);

        if ($scope.exceptUserListData[0]){
            field.setValue($scope.exceptUserListData[0].id);
        }
    };

    $scope.antifloodActions.save = function(field){
        var uin = mcService.trim(field.getValue());
        var nick = uin !== "" ? mcService.trim(field.getList().getItem(uin).value) : "";

        if (uin !== "" && nick !== "" && !$scope.exceptUserList.getItem(uin)){
            var data = $scope.exceptUserList.serialize();

            for (var i = 0; i < data.length; i++){
                data[i] = data[i].id;
            }

            data.push(uin);

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_modify_flood_except_users,
                mcConst.SessionID,
                data.join(',')
            ]);

            $scope.exceptUserList.add({
                id: uin,
                value: nick
            });

            return true;
        }
    };

    $scope.antifloodActions.del = function(selectedItem, _list){
        var newList = [];
        var list    = _list.serialize();

        for (var i = 0; i < list.length; i++){
            if ( list[i].id != selectedItem.id ) {
                newList.push(list[i].id);
            }
        }

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_modify_flood_except_users,
            mcConst.SessionID,
            newList.join(',')
        ]);
    };

    $scope.antifloodActions.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_modify_flood_except_users,
            mcConst.SessionID,
            ""
        ]);

        return true;
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(data){
        $scope.data = data || {};

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        _view = initAntiflood($scope);

        mcService.initResize(_view, $scope.Name);

        _view.adjust();
    };

    $scope.getData = function(){
        var task = new mcService.TaskList();

        task.AddTask(function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_antiflood_filter_data,
                mcConst.SessionID,
                function(data){
                    $scope.show(data);

                    task.Next();
                }
            ]);
        });

        task.AddTask(function(){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_flood_except_users_list,
                mcConst.SessionID,
                function (data){
                    data = mcService.transformDataObject(data, [['DisplayName', 'value'], ['UIN', 'id']]);

                    $scope.exceptUserList.define('data', data);
                    $scope.exceptUserList.refresh();
                }
            ]);
        });

        task.Run();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.getData();
    });
}
function initFilterBadWords($scope){
    "use strict";

    var settings = $$($scope.Name);

    if (settings){
        settings.destructor();
    }

    settings = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { type: "layout", rows: [
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(1058) }, // "1058":"Плохие слова",
                    { view: "toolbar", width: 36, cols: [
                        {view: "button", type: "icon", icon: "question", click: function () {
                            mcService.goToHelp();
                        }, width: 30}
                    ]}
                ]},

                { type : 'layout', padding : 5, rows : [
                    { view: "checkbox",id: "bdwEnableFilter", value: $scope.data.EnableFilter, labelRight: mcService.Lang(1085), labelWidth: 0, css: "finger", on: {onChange: $scope.change}} // "1085":"Включить фильтр плохих слов",
                ]}
            ]},


            { cols : [
                { view : "template", type : "header", template : mcService.Lang(1086) }, // "1086":"Где использовать фильтр плохих слов?",
                { view : "template", type : "header", template : mcService.Lang(1091) } // "1091":"Что делать с плохими словами?",
            ]},
            { type : 'layout', padding : 5, cols: [
                { rows: [
                    { view: "checkbox", id: "bdwFilterConfTopics",value: $scope.data.FilterConfTopics,labelRight: mcService.Lang(1087),labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "1087":"Темы конференций",
                    { view: "checkbox", id: "bdwFilterConfNames", value: $scope.data.FilterConfNames, labelRight: mcService.Lang(1088),labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "1088":"Названия конференций",
                    { view: "checkbox", id: "bdwFilterUserNicks", value: $scope.data.FilterUserNicks, labelRight: mcService.Lang(1089),labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "1089":"Ники пользователей",
                    { view: "checkbox", id: "bdwFilterPrivates",  value: $scope.data.FilterPrivates,  labelRight: mcService.Lang(1090),labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "1090":"Приватные диалоги",
                    { view: "checkbox", id: "bdwFilterBroadcasts",value: $scope.data.FilterBroadcasts,labelRight: mcService.Lang(822), labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "822":"Оповещения",
                    { view: "checkbox", id: "bdwFilterBBS",       value: $scope.data.FilterBBS,       labelRight: mcService.Lang(32),  labelWidth: 0, css: "finger", on: {onChange: $scope.change}}, // "32" : "Доска объявлений",
                    { view: "checkbox", id: "bdwFilterConf",      value: $scope.data.FilterConf,      labelRight: mcService.Lang(1098),  labelWidth: 0, css: "finger", on: {onChange: $scope.change}}  // "1098":"Сообщения в конференциях",
                ]},
                { rows: [
                    { view: "radio", id: "bdwChangeBadWordsTo", value: $scope.data.ChangeBadWordsTo, label: mcService.Lang(1096), labelPosition: 'top', vertical: true, height: 100, options: [ // "1096":"Варианты замены:",
                        { id: '0', value: mcService.Lang(1092) + $scope.shitIMG }, // "1092":"Заменить плохие слова символом \"*\"",
                        { id: '1', value: mcService.Lang(1093) }, // "1093":"Игнорировать сообщение целиком",
                        { id: '2', value: mcService.Lang(1094) }  // "1094":"Заменять плохие слова строкой:",
                    ], css: "finger", on: {onChange: $scope.change}},
                    { view: "text", id: "bdwTextForChange", value: $scope.data.TextForChange, on: {onTimedKeyPress: $scope.change}}
                ]}
            ]},

            { cols: [
                { view : "template", type : "header", template : mcService.Lang(1095) }, // "1095":"Конференции, в которых фильтр отключен:",
                { cols: [
                    { view : "template", type : "header", template : mcService.Lang(1097) }, // "1097":"Список плохих слов:",
                    { view   : "toolbar",
                        padding: 2,
                        width  : 100,
                        cols   : [{
                            view    : "toggle",
                            id      : "toggleSettings" + $scope.Name,
                            onLabel : mcService.Lang(1100), // "1100":"Скрыть",
                            offLabel: mcService.Lang(1099), // "1099":"Показать",
                            value   : false,
                            align   : "right",
                            click   : $scope.showBadWords
                        }]
                    }
                ]}
            ]},
            { type : 'layout', padding : 5, cols: [
                { rows : [
                    new mcService.ListButtonSet({
                        type   : 'combo',
                        actions: $scope.confs,
                        list   : "bdwConfList",
                        regShowWindow: $scope.regShowWindow
                    }),

                    new mcService.FilterFiled({listName : "bdwConfList"}),
                        
                    { view: "list", id: "bdwConfList", select: true,
                        template: function (obj) {
                            return obj.id === -1
                                ? "<span style='text-align: center; font-weight: bold; width: 100%; display: inline-block;'>" + obj.value + "</span>"
                                : obj.value + " <span style='float:right'>(UID: " + obj.id + ")</span>"
                        }
                    }
                ]},
                { width: 20},

                { id: "bdwWrap", hidden: true, rows: [
                    new mcService.ListButtonSet({
                        type   : 'text',
                        actions: $scope.badWord,
                        list   : "bdwBadWordsList",
                        regShowWindow: $scope.regShowWindow
                    }),

                    new mcService.FilterFiled({listName : "bdwBadWordsList" }),

                    { view: "list", id: "bdwBadWordsList", select: true },

                    { cols: [
                        { view: "button", value: mcLang(2272), click: $scope.importList}, // "2272":"Імпорт",
                        { view: "button", value: mcLang(55),   click: $scope.exportList}, // "55" : "Експорт",
                    ]}
                ]},
                { id: "bdwEmpty"}
            ]}
        ]
    });

    $scope.bdwBadWordsList = $$('bdwBadWordsList');
    $scope.bdwConfList     = $$('bdwConfList');

    mcService.disableContextMenu(settings);

    return settings;
}


function filterBadWordsController($scope, $rootScope){
    "use strict";

    $scope.Name = mcConst.dataModels.FilterBadWords;

    var angElement = document.getElementById($scope.Name);

    mcService.initChangesApplyForSettings($scope, $rootScope, mcConst._CMD_.cs_adm_set_bad_words_filter_data, function(){
        return mcService.Lang(669); // "669": "Настройки сохранены!"
    }, mcConst.dataModels.FilterBadWords);

    $scope.bdwBadWordsList = null;
    $scope.bdwConfList     = null;
    $scope.confBadWord     = [];

    $scope.badWord = {};
    $scope.confs   = {};

    // === BadWords ===

    $scope.badWord.del = function(item){
        if (item.value){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_del_bad_word_from_filters,
                mcConst.SessionID,

                item.value
            ]);

            return true;
        } else {
            return false;
        }
    };

    $scope.badWord.save = function(val){
        var _val = mcService.trim(val.getValue());

        if (_val && !$scope.bdwBadWordsList.getItem(_val)) {

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_bad_word_to_filters,
                mcConst.SessionID,
                _val
            ]);

            $scope.bdwBadWordsList.add({
                id   : _val,
                value: _val
            });

            $scope.bdwBadWordsList.scrollTo(0, 9999);

            return true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084), "nohelp"]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return false;
        }
    };

    $scope.badWord.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_bad_words_list,
            mcConst.SessionID
        ]);

        return true;
    };

    // === Conf List ===

    $scope.confs.preview = function(field){
        if ($scope.confBadWord[0]){
            field.setValue($scope.confBadWord[0].id);
        } else {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_auto_conf_list,
                mcConst.SessionID,
                function( data ){
                    $scope.confBadWord = mcService.transformDataObject(webix.copy(data), [['Name', 'value'], ['UID', 'id']]);

                    field.define('options', $scope.confBadWord);
                    field.getList().define('template', "#value#");
                    field.refresh();
                    field.setValue($scope.confBadWord[0].id);
                }
            ]);
        }
    };

    $scope.confs.save = function(list){
        var item = list.getList().getItem(list.getValue());

        if (item && !$scope.bdwConfList.getItem(item.id)) {
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_badwords_except_conf,
                mcConst.SessionID,
                item.id
            ]);

            $scope.bdwConfList.add({
                id   : item.id,
                value: $scope.allConfs[item.id].Name
            });

            $scope.bdwConfList.scrollTo(0, 9999);

            return true;
        } else {
            if (item){
                $rootScope.$broadcast('ErrorMsg', [131, mcService.Error(131, [$scope.allConfs[item.id].Name]), "nohelp"]); // "131": "така назва конференції (%s) вже існує в списку виключень фільтра",
            } else {
                $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084), "nohelp"]); // "1084":"Название не может быть пустым или совпадать с существующим",
            }

            return false;
        }
    };

    $scope.confs.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_del_badwords_except_conf,
            mcConst.SessionID,
            item.id
        ]);
    };

    $scope.confs.preview = function(field){
        if (!field.getPopup().getBody().serialize().length){
            field.define('options', $scope.channelListData);
            field.refresh();
        }

        field.focus();
    };

    $scope.confs.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_badwords_except_confs,
            mcConst.SessionID
        ]);

        return true;
    };

    // ===

    $scope.importList = function (){
        var input    = document.createElement('input');
        input.type   = 'file';
        input.accept = '.txt';

        input.onchange = function (e){
            var file = e.target.files[0];

            var reader = new FileReader();
            reader.readAsText(file,'UTF-8');

            reader.onload = function (readerEvent) {
                var content = readerEvent.target.result; // this is the content!

                $rootScope.$broadcast('SendCMDToServer', [
                    mcConst.lockInterface,
                    mcConst._CMD_.cs_adm_upload_badword_list,
                    mcConst.SessionID,

                    mcService.Base64.encode(content) + "=",

                    function(data){
                        // "Total"    : 179, // всего слов в базе
                        // "New"      : 73,  // слов в списке, который мы пытались добавить
                        // "Imported" : 5    // всего слов, которые были добавлены в общий фильтр нецензурных выражений

                        webix.alert(mcLang(2274, [data.Total, data.Imported])); // "2274":"Всего слов %s<br>импортировано %s слов",

                        $scope.bdwBadWordsList.clearAll();

                        $rootScope.$broadcast('SendCMDToServer', [
                            mcConst._CMD_.cs_adm_get_bad_words_list,
                            mcConst.SessionID,
                            function(data){
                                $scope.bdwBadWordsList.define('data', data);
                            }
                        ]);
                    }
                ]);
            }
        };

        input.click();
    };

    $scope.exportList = function () {
        var words = $scope.bdwBadWordsList.serialize();

        words = words.map(function (item) {
            return item.value;
        }).join(mcConst.CRLF)

        mcService.copyTextToClipboard(words, mcLang(2273)); // "2273":"Список скопирован в буфер обмена",
    };

    $scope.showBadWords = function(){
        if (!this.getValue()) {
            $$("bdwEmpty").hide();
            $$("bdwWrap").show();

            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_bad_words_list,
                mcConst.SessionID,
                function(data){
                    $scope.bdwBadWordsList.define('data', data);
                }
            ]);
        } else {
            $$("bdwWrap").hide();
            $$("bdwEmpty").show();
        }
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.show = function(data){
        $scope.data = data;

        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        $scope.shitIMG = '<img src="' + mcConst.imagesPath.all + '1F4A9.png" style="height: 17px;" alt="">';

        var settings = initFilterBadWords($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_get_all_text_confs,
            mcConst.SessionID,

            function(data){
                $scope.allConfs = data;
                $scope.channelListData = [];

                for (var i in data){
                    $scope.channelListData.push({id: i, value: "<span style='word-break: break-all' title='" + data[i].Name + " UID:" + i + "'>" + data[i].Name + " <span style='float:right'>(UID: <b>" + i + "</b>)</span></span>"});
                }
            }
        ]);

        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_load_badwords_except_confs,
            mcConst.SessionID,
            function(data){
                if (data && data.length) {
                    data = data.map(function (item) {
                        return {
                            id   : item.UID,
                            value: item.ConfName
                        };
                    });
                }
                
                $scope.bdwConfList.define('data', data);
            }
        ]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_bad_words_filters_data,
            mcConst.SessionID,
            function (data){
                $rootScope.mcStorage[mcConst.dataModels.FilterBadWords] = data;

                $scope.show(data);

                $scope.getData();
            }
        ]);
    });
}
"use strict";

function initFilterIP($scope){
    var settings = $$($scope.Name);

    if (settings){
        settings.destructor();
    }

    var clientTypes = [
        {id: "web",       value: mcLang(1533)}, // "1533":"Веб чат",
        {id: "win32",     value: mcLang(1535)}, // "1535":"MyChat клиент win32",
        {id: "admin",     value: mcLang(1538)}, // "1538":"Доступ к панели управления",
        {id: "websupport",value: mcLang(1534)}, // "1534":"Веб-поддержка",
        {id: "ftp",       value: mcLang(1539)}, // "1539":"Доступ к FTP",
        {id: "common",    value: mcLang(1537)}, // "1537":"Общий доступ",
        {id: "integrationapi", value: mcLang(1536)},  // "1536":"Integration API",
        {id: "updates",   value: "Updates"},
        {id: "kanban",    value: "Kanban"},
        {id: "forum",     value: "Forum"},
        {id: "android",   value: "Android Client"},
        {id: "linux",     value: "Linux Client"},
        {id: "macos",     value: "macOS Client"},
        {id: "mcguest",   value: "MyChat Guest"}
    ];

    var buttonAccept = mcService.ListButtonSet({
        type   : 'textRichselectCommentEdit',
        actions: $scope.accept,
        list   : "ipfAcceptList",
        selectedItem: "IP",
        regShowWindow: $scope.regShowWindow,
        hideSearchField: "searchIpAcceptList",
        listData: clientTypes,
        text : {
            field1 : mcService.Lang(1075), // "1075":"Введите IP, маску или диапазон",
            field2 : mcService.Lang(1532), // "1532":"Тип клиентского приложения",
            field3 : mcService.Lang(1032)  // "1032":"Комментарий:",
        }
    });

    var buttonBlock = mcService.ListButtonSet({
        type   : 'textRichselectCommentEdit',
        actions: $scope.block,
        list   : "ipfBlockedList",
        selectedItem: "IP",
        regShowWindow: $scope.regShowWindow,
        hideSearchField: "searchIpfBlockedList",
        listData: clientTypes,
        text : {
            field1 : mcService.Lang(1075), // "1075":"Введите IP, маску или диапазон",
            field2 : mcService.Lang(1532), // "1532":"Тип клиентского приложения",
            field3 : mcService.Lang(1032)  // "1032":"Комментарий:",
        }
    });

    var searchBarAccept = new mcService.FilterFiled({
        listName : "ipfAcceptList",
        id       : "searchIpAcceptList",
        filterParams : [
            "IP",
            "Comment"
        ]
    });

    var searchBarBlock = new mcService.FilterFiled({
        listName : "ipfBlockedList",
        id       : "searchIpfBlockedList",
        filterParams : [
            "IP",
            "DisplayName",
            "UIN",
            "Date",
            "Comment"
        ]
    });

    settings = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(1073) }, // "1073":"Разрешенные IP адреса",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, rows : [
                { cols: [
                    { width: 700, rows: [
                        buttonAccept,
                        searchBarAccept
                    ]}, {}
                ]},

                { view : "datatable",
                    resizeColumn: true,
                    id          : "ipfAcceptList",
                    select      : "row",
                    navigation  : false,
                    columns     : [
                        { id:"id",        adjust: "data", header: "ID",                 sort: "int",    minWidth: 30,  width: 40,  css: "grid_area"},
                        { id:"IP",        adjust: "data", header: "IP",                 sort: "string", minWidth: 130, width: 220, css: "grid_area"},
                        { id:"ClientType",adjust: "data", header: mcService.Lang(1532), sort: "string", minWidth: 220, width: 220, css: "grid_area"}, //"1532":"Тип клиентского приложения",
                        { id:"Comment",   header: mcService.Lang(1032), sort: "string", minWidth: 169, css: "grid_area", fillspace: true} // "1032":"Комментарий",
                    ],
                    on: {
                        onItemDblClick: function () {
                            buttonAccept.emit.edit();
                        }
                    }
                }
            ]},

            { view : "template", type : "header", template : mcService.Lang(1074) }, // "1074":"Зблокированные IP адреса",
            { type : 'layout', padding : 5, rows : [
                { cols: [
                    { width: 700, rows: [
                        buttonBlock,
                        searchBarBlock
                    ]}, {}
                ]},

                { view : "datatable",
                    resizeColumn: true,
                    id          : "ipfBlockedList",
                    select      : "row",
                    navigation  : false,
                    columns     : [
                        { id:"id",      adjust: "data", header: "ID",                 sort: "int",    minWidth: 30,  width: 40,  css: "grid_area"},
                        { id:"IP",      adjust: "data", header: "IP",                 sort: "string", minWidth: 130, width: 220, css: "grid_area"},
                        { id:"Who",     adjust: "data", header: mcService.Lang(1083), sort: "string", minWidth: 179, width: 179, css: "grid_area", template: "#DisplayName# (UIN #UIN#)"},
                        { id:"Date",    adjust: "data", header: mcService.Lang(873),  sort: "text",   minWidth: 190, width: 190, css: "grid_area",
                            template: function(obj){
                                return mcService.sortableDate(obj.Date);
                            }
                        }, // "873":"Дата и время",
                        { id:"ClientType",adjust: "data", header: mcService.Lang(1532), sort: "string", minWidth: 220, width: 220, css: "grid_area"}, //"1532":"Тип клиентского приложения",
                        { id:"Comment", header: mcService.Lang(1032), sort: "string", minWidth: 200, css: "grid_area", fillspace: true} // "1032":"Комментарий",
                    ],
                    on: {
                        onItemDblClick: function () {
                            buttonBlock.emit.edit();
                        }
                    }
                }
            ]}
        ]
    });

    $scope.ipfAcceptList  = $$("ipfAcceptList");
    $scope.ipfBlockedList = $$("ipfBlockedList");

    mcService.disableContextMenu(settings);

    return settings;
}
"use strict";

function filterIPController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.FilterIP;

    $scope.ipfAcceptList = null;
    $scope.ipfBlockedList = null;

    $scope.accept = {};
    $scope.block  = {};

    var angElement = document.getElementById($scope.Name);

    // ======= Error Actions ==========

    $rootScope.ErrorActions[45] = function(){ // "45"  : "Этот IP адрес (%s) уже заблокирован",
        $scope.ipfBlockedList.remove($scope.ipfBlockedList.getLastId());
    };

    $rootScope.ErrorActions[124] = function(){ // "124" : "Такой IP адрес (%s) уже есть в списке разрешённых адресов",
        $scope.ipfAcceptList.remove($scope.ipfAcceptList.getLastId());
    };

    // ====== Accept ======

    $scope.accept.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_delete_allow_ip,
            mcConst.SessionID,
            item.IP,
            item.ClientType
        ]);
    };

    $scope.accept.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_allow_ip_list,
            mcConst.SessionID
        ]);

        return true;
    };

    $scope.accept.save = function(_ip, _clientType, _comment, _id){
        var ip         = mcService.trim(_ip.getValue());
        var clientType = mcService.trim(_clientType.getValue()) || "common";
        var comment    = mcService.trim(_comment.getValue());
        var ID         = _id;
        var params     = [
             ip,
             comment,
             clientType
        ];
        var cb         = null;

        if (ip === '127.0.0.1'){
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1909)]); // "1909":"Нельзя добавить адрес \"127.0.0.1\"",
        } else
        if (mcService.isValidIpAddress  (ip) ||
            mcService.isValidIpAddressV6(ip) ||
            mcService.isValidIpRange    (ip) ||
            mcService.isValidIpMask     (ip)) {

            // console.log(ip);
            // console.log("isValidIpAddress  : " + mcService.isValidIpAddress  (ip));
            // console.log("isValidIpAddressV6: " + mcService.isValidIpAddressV6(ip));
            // console.log("isValidIpRange    : " + mcService.isValidIpRange    (ip));
            // console.log("isValidIpMask     : " + mcService.isValidIpMask     (ip));

            if (ID){
                params.unshift(ID);

                cb = function () {
                    var item = $scope.ipfAcceptList.getItem(ID);

                    item = mcService.Marge(item, {
                        IP        : ip,
                        Comment   : comment,
                        ClientType: clientType
                    });

                    $scope.ipfAcceptList.updateItem(ID, item);

                    mcConst.restartOptions[1] = mcConst.restartItems.WEB;

                    $rootScope.$broadcast('NeedRestartServer', []);
                };
            } else {
                cb = function (data) {
                    $scope.ipfAcceptList.add({
                        id        : data.ID,
                        ID        : data.ID,
                        IP        : ip,
                        Comment   : comment,
                        ClientType: clientType
                    });

                    mcConst.restartOptions[1] = mcConst.restartItems.WEB;

                    $rootScope.$broadcast('NeedRestartServer', []);
                };
            }

            $rootScope.$broadcast('SendCMDToServer',
                [
                    ID ? mcConst._CMD_.cs_adm_modify_allow_ip : mcConst._CMD_.cs_adm_add_new_ip_to_allow_list,
                    mcConst.SessionID
                ]
                .concat(params)
                .concat([cb])
            );

            return true
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(7) + ": " + mcService.Lang(141)]); // "7"  : "Неправильно введены данные", "141":"IP адрес",

            return false;
        }
    };

    // ====== Blocked ======

    $scope.block.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_delete_blocked_ip,
            mcConst.SessionID,
            item.IP,
            item.ClientType
        ]);
    };

    $scope.block.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_blocked_ip_list,
            mcConst.SessionID
        ]);

        return true;
    };

    $scope.block.save = function(_ip, _clientType, _comment, _id){
        var ip         = mcService.trim(_ip.getValue());
        var clientType = mcService.trim(_clientType.getValue()) || "common";
        var comment    = mcService.trim(_comment.getValue());
        var ID         = _id;
        var params     = [
            ip,
            comment,
            clientType
        ];
        var cb         = null;


        if (ip === '127.0.0.1'){
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1909)]); // "1909":"Нельзя добавить адрес \"127.0.0.1\"",
        } else
        if (mcService.isValidIpAddress  (ip) ||
            mcService.isValidIpAddressV6(ip) ||
            mcService.isValidIpRange    (ip) ||
            mcService.isValidIpMask     (ip)) {

            var format = webix.Date.dateToStr("%d.%m.%Y.%H.%i.%s");

            // console.log(ip);
            // console.log("isValidIpAddress  : " + mcService.isValidIpAddress  (ip));
            // console.log("isValidIpAddressV6: " + mcService.isValidIpAddressV6(ip));
            // console.log("isValidIpRange    : " + mcService.isValidIpRange    (ip));
            // console.log("isValidIpMask     : " + mcService.isValidIpMask     (ip));

            if (ID){
                params.unshift(ID);

                cb = function () {
                    var item = $scope.ipfBlockedList.getItem(ID);
                    
                    item = mcService.Marge(item, {
                        IP         : ip,
                        Comment    : comment,
                        DisplayName: mcConst.UserInfo.Nick,
                        UIN        : mcConst.UserInfo.UIN,
                        ClientType : clientType,
                        Date       : format(new Date())
                    });

                    $scope.ipfBlockedList.updateItem(ID, item);
                };
            } else {
                cb = function (data) {
                    $scope.ipfBlockedList.add({
                        id         : data.ID,
                        ID         : data.ID,
                        IP         : ip,
                        Comment    : comment,
                        DisplayName: mcConst.UserInfo.Nick,
                        UIN        : mcConst.UserInfo.UIN,
                        ClientType : clientType,
                        Date       : format(new Date())
                    });
                };
            }

            $rootScope.$broadcast('SendCMDToServer',
                [
                    ID ? mcConst._CMD_.cs_adm_modify_blocked_ip : mcConst._CMD_.cs_adm_add_ip_to_block_list,
                    mcConst.SessionID
                ]
                .concat(params)
                .concat([cb])
            );

            return true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(7) + ": " + mcService.Lang(141)]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return false;
        }
    };

    // ===================

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initFilterIP($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.getData = function(){
        var task = new mcService.TaskList();

        task.AddTask(function(){ // получение списка разрешенных адресов
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_allow_ip_list,
                mcConst.SessionID,
                function(data){
                    data.forEach(function (item) {
                        item.id = item.ID;
                    });

                    $scope.ipfAcceptList.define('data', data);

                    task.Next();
                }
            ]);
        });

        task.AddTask(function(){ // получение списка запрещенных адресов
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_blocked_ip_list,
                mcConst.SessionID,
                function(data){
                    data.forEach(function (item) {
                        item.id = item.ID;
                    });

                    $scope.ipfBlockedList.define('data', data);
                }
            ]);
        });

        task.Run();
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $scope.show();
        $scope.getData();
    });
}
"use strict";

function initFilterMAC($scope){
    var settings = $$($scope.Name);

    if (settings){
        settings.destructor();
    }

    var buttonMAC = new mcService.ListButtonSet({
        type   : '1',
        actions: $scope.mac,
        list   : "macBlockedList",
        selectedItem: "MAC",
        regShowWindow: $scope.regShowWindow,
        hideSearchField: "searchMACAcceptList",
        text : {
            field1 : mcService.Lang(1080), // "1080":"Введите MAC адрес",
            field2 : mcService.Lang(1032)  // "1032":"Комментарий:",
        }
    });

    var searchBar = new mcService.FilterFiled({
        listName : "macBlockedList",
        id       : "searchMACAcceptList",
        filterParams : [
            "MAC",
            "DisplayName",
            "UIN",
            "Date",
            "Comment"
        ]
    });

    settings = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(1079) }, // "1079":"Заблокированные MAC адреса",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, rows : [
                { cols: [
                    { width: 700, rows: [
                        buttonMAC,
                        searchBar
                    ]}, {}
                ]},

                { view : "datatable",
                    resizeColumn: true,
                    id          : "macBlockedList",
                    select      : "row",
                    navigation  : true,
                    columns     : [
                        { id:"MAC",     adjust: "data", header: "MAC",                sort: "string", minWidth: 130, width: 130, css: "grid_area"},
                        { id:"Who",     adjust: "data", header: mcService.Lang(1083), sort: "string", minWidth: 179, width: 179, css: "grid_area", template: "#DisplayName# (UIN #UIN#)"},
                        { id:"Date",    adjust: "data", header: mcService.Lang(873),  sort: "text", minWidth: 190, width: 190, css: "grid_area",
                            template: function(obj){
                                return mcService.sortableDate(obj.Date);
                            }
                        },
                        { id:"Comment", header: mcService.Lang(1032), sort: "string", minWidth: 200, css: "grid_area", fillspace: true}
                    ]
                }
            ]}
        ]
    });

    $scope.macBlockedList = $$("macBlockedList");

    mcService.disableContextMenu(settings);

    return settings;
}
"use strict";

function filterMACController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.FilterMAC;

    $scope.macBlockedList = null;

    $scope.mac = {};

    var angElement = document.getElementById($scope.Name);

    // ======= Error Actions ==========

    $rootScope.ErrorActions[46] = function(){ // "46"  : "Этот MAC адрес (%s) уже заблокирован",
        $scope.macBlockedList.remove($scope.macBlockedList.getLastId());
    };

    // ====== Accept ======

    $scope.mac.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_delete_blocked_mac,
            mcConst.SessionID,
            item.MAC
        ]);
    };

    $scope.mac.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_blocked_mac_list,
            mcConst.SessionID
        ]);

        return true;
    };

    $scope.mac.save = function(_mac, _comment){
        var mac     = mcService.trim(_mac.getValue());
        var comment = mcService.trim(_comment.getValue());

        if (mcService.isValidMACAddress(mac)){
            mac = mac.replace(/:/g, "-");
            
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_mac_to_block_list,
                mcConst.SessionID,
                mac,
                comment
            ]);

            var format = webix.Date.dateToStr("%d.%m.%Y.%H.%i.%s");

            $scope.macBlockedList.add({
                MAC     : mac,
                UIN     : mcConst.UserInfo.UIN,
                Date    : format(new Date()),
                Comment : comment,
                DisplayName : mcConst.UserInfo.Nick
            });

            return true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(7) + ": " + mcService.Lang(142)]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return false;
        }
    };

    // ===================

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initFilterMAC($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_blocked_mac_list,
            mcConst.SessionID,
            function(data){
                $scope.macBlockedList.define('data', data);
            }
        ]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(e, args){
        $scope.show();
        $scope.getData();
    });
}
"use strict";

function initFilterHardware($scope){
    var settings = $$($scope.Name);

    if (settings){
        settings.destructor();
    }

    var buttonHRD = new mcService.ListButtonSet({
        type   : '1',
        actions: $scope.hrd,
        list   : "hrdBlockedList",
        selectedItem: "HardwareID",
        regShowWindow: $scope.regShowWindow,
        hideSearchField: "searchHWIDAcceptList",
        text : {
            field1 : mcService.Lang(1912), // "1912":"Введите Hardware номер",
            field2 : mcService.Lang(1032)  // "1032":"Комментарий:",
        }
    });

    var searchBar = new mcService.FilterFiled({
        listName : "hrdBlockedList",
        id       : "searchHWIDAcceptList",
        filterParams : [
            "HardwareID",
            "DisplayName",
            "UIN",
            "Date",
            "Comment"
        ]
    });

    settings = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view: "template", type : "header", template : mcService.Lang(1913) }, // "1913":"Заблокированные Hardware номера",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, rows : [
                { cols: [
                    { width: 700, rows: [
                        buttonHRD,
                        searchBar
                    ]}, {}
                ]},

                { view : "datatable",
                    resizeColumn: true,
                    id          : "hrdBlockedList",
                    select      : "row",
                    navigation  : true,
                    columns     : [
                        { id:"HardwareID",              header: "HardwareID",         sort: "string", minWidth: 130, width: 230, css: "grid_area"},
                        { id:"Who",     adjust: "data", header: mcService.Lang(1083), sort: "string", minWidth: 179, width: 179, css: "grid_area", template: "#DisplayName# (UIN #UIN#)"},
                        { id:"Date",    adjust: "data", header: mcService.Lang(873),  sort: "text",   minWidth: 190, width: 190, css: "grid_area"},
                        { id:"Comment", header: mcService.Lang(1032), sort: "string", minWidth: 200, css: "grid_area", fillspace: true}
                    ]
                }
            ]}
        ]
    });

    $scope.hrdBlockedList = $$("hrdBlockedList");

    mcService.disableContextMenu(settings);

    return settings;
}
"use strict";

function filterHardwareController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.FilterHardware;

    $scope.hrdBlockedList = null;

    $scope.hrd = {};

    var angElement = document.getElementById($scope.Name);

    // ======= Error Actions ==========

    $rootScope.ErrorActions[240] = function(){ // "240": "такой HardwareID (\"%s\") уже есть в списке заблокированных"
        $scope.hrdBlockedList.remove($scope.hrdBlockedList.getLastId());
    };

    // ====== Accept ======

    $scope.hrd.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_delete_blocked_hwid,
            mcConst.SessionID,
            item.HardwareID
        ]);
    };

    $scope.hrd.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_blocked_hwid_list,
            mcConst.SessionID
        ]);

        return true;
    };

    $scope.hrd.save = function(_hrd, _comment){
        var hrd     = mcService.trim(_hrd.getValue());
        var comment = mcService.trim(_comment.getValue());

        if (mcService.isString(hrd) && hrd !== ""){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_hwid_to_block_list,
                              
                mcConst.SessionID,
                hrd,
                comment
            ]);

            var format = webix.Date.dateToStr("%d.%m.%Y.%H.%i.%s");

            $scope.hrdBlockedList.add({
                HardwareID  : hrd,
                UIN         : mcConst.UserInfo.UIN,
                Date        : mcService.sortableDate(format(new Date())),
                Comment     : comment,
                DisplayName : mcConst.UserInfo.Nick
            });

            return true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(7) + ": " + mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return false;
        }
    };

    // ===================

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initFilterHardware($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.getData = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst.lockInterface,
            mcConst._CMD_.cs_adm_get_blocked_hwid_list,
            mcConst.SessionID,
            function(data){
                data.forEach(function (t) {
                    t.Date = mcService.formatDate(mcService.utcTime(t.Date), 'yyyy.mm.dd hh:nn:ss')
                });

                $scope.hrdBlockedList.define('data', data);
            }
        ]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
        $scope.getData();
    });
}
"use strict";

function initFilterNames($scope){
    var settings = $$($scope.Name);

    if (settings){
        settings.destructor();
    }

    var buttonSetNick = new mcService.ListButtonSet({
        type   : '2',
        actions: $scope.names,
        list   : "nmfNickList",
        regShowWindow: $scope.regShowWindow
    });

    var buttonSetChannel = new mcService.ListButtonSet({
        type   : '2',
        actions: $scope.channel,
        list   : "nmfChannelList",
        regShowWindow: $scope.regShowWindow
    });

    var searchBarNick = new mcService.FilterFiled({
        listName : "nmfNickList"
    });

    var searchBarChannel = new mcService.FilterFiled({
        listName : "nmfChannelList"
    });

    settings = webix.ui({
        type       : "space",
        padding    : 5,
        container  : $scope.Name,
        id         : $scope.Name,
        borderless : true,
        rows       : [
            { cols: [
                { view : "template", type : "header", template : mcService.Lang(1081) }, // "1081":"Список запрещенных ников",
                { view: "toolbar", width: 36, cols: [
                    {view: "button", type: "icon", icon: "question", click: function () {
                        mcService.goToHelp();
                    }, width: 30}
                ]}
            ]},

            { type : 'layout', padding : 5, cols : [
                { rows : [
                    buttonSetNick,
                    searchBarNick,
                    { view: "list", width: 700, id: "nmfNickList", select: true }
                ]}, {}
            ]},
            { view : "template", type : "header", template : mcService.Lang(1082) }, // "1082":"Список запрещенных названий конференций",
            { type : 'layout', padding : 5, cols : [
                { rows : [
                    buttonSetChannel,
                    searchBarChannel,
                    { view: "list", width: 700, id: "nmfChannelList", select: true }
                ]}, {}
            ]}
        ]
    });

    $scope.nmfNickList = $$("nmfNickList");
    $scope.nmfChannelList = $$("nmfChannelList");


    mcService.disableContextMenu(settings);

    return settings;
}

"use strict";

function filterNamesController($scope, $rootScope){
    $scope.Name = mcConst.dataModels.FilterNames;

    $scope.data = {};

    $scope.nmfNickList    = null;
    $scope.nmfChannelList = null;

    $scope.names   = {};
    $scope.channel = {};

    var angElement = document.getElementById($scope.Name);

    // ======= Error Actions ==========

    $rootScope.ErrorActions[126] = function(){ // "126" : "Такой ник (%s) уже есть в списке запрещённых ников",
        $scope.nmfNickList.remove($scope.nmfNickList.getLastId());
    };

    $rootScope.ErrorActions[128] = function(){ // "128" : "Такое название конференции (%s) уже есть в списке запрещёных",
        $scope.nmfChannelList.remove($scope.nmfChannelList.getLastId());
    };

    // ====== Nick ======

    $scope.names.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_delete_deny_nick,
            mcConst.SessionID,
            item.value
        ]);
    };

    $scope.names.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_deny_nicks_list,
            mcConst.SessionID
        ]);

        return true;
    };

    $scope.names.save = function(_nick){
        var nick = mcService.trim(_nick.getValue());

        if (nick != '' && !$scope.nmfNickList.getItem(nick)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_deny_nick,
                mcConst.SessionID,
                nick
            ]);

            $scope.nmfNickList.add({
                value : nick
            });

            return true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return false;
        }
    };

    // ====== Channel ======

    $scope.channel.del = function(item){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_delete_deny_conf,
            mcConst.SessionID,
            item.value
        ]);
    };

    $scope.channel.clear = function(){
        $rootScope.$broadcast('SendCMDToServer', [
            mcConst._CMD_.cs_adm_clear_deny_conf_list,
            mcConst.SessionID
        ]);

        return true;
    };

    $scope.channel.save= function(_val){
        var channel = mcService.trim(_val.getValue()).toLowerCase();

        if (channel != '' && !$scope.nmfNickList.getItem(channel)){
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst._CMD_.cs_adm_add_deny_conf,
                mcConst.SessionID,
                channel
            ]);

            $scope.nmfChannelList.add({
                value : channel
            });

            return true;
        } else {
            $rootScope.$broadcast('ErrorMsg', ['client', mcService.Lang(1084)]); // "1084":"Название не может быть пустым или совпадать с существующим",

            return false;
        }
    };

    // ===================

    $scope.show = function(){
        mcService.showCurrentView($scope.Name, $rootScope, angElement);

        var settings = initFilterNames($scope);

        mcService.initResize(settings, $scope.Name);

        settings.adjust();
    };

    $scope.getData = function(){
        var task = new mcService.TaskList();

        task.AddTask(function(){ // получение списка разрешенных адресов
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_deny_nicks_list,
                mcConst.SessionID,
                function(data){
                    $scope.data.nick = data;

                    $scope.nmfNickList.define('data', $scope.data.nick);

                    task.Next();
                }
            ]);
        });

        task.AddTask(function(){ // получение списка запрещенных адресов
            $rootScope.$broadcast('SendCMDToServer', [
                mcConst.lockInterface,
                mcConst._CMD_.cs_adm_get_deny_conf_list,
                mcConst.SessionID,
                function(data){
                    $scope.data.conf = data;

                    $scope.nmfChannelList.define('data', $scope.data.conf);
                    $scope.nmfChannelList.refresh();
                }
            ]);
        });

        task.Run();
    };

    $scope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    $scope.$on('hide' + $scope.Name, function(){
        mcService.hideView(angElement);
    });

    $scope.$on('show' + $scope.Name, function(){
        $scope.show();
        $scope.getData();
    });
}
function mainController($scope, $rootScope, mcCmdParser, /*mcCmdLoop,*/ $http, $location, mcConnect){
    "use strict";

    function setWindowSize() {
        $rootScope.wndSize = mcService.getWindowSize();

        for (var i = 0; i < resizeWndCb.length; i++){
            resizeWndCb[i]($rootScope.wndSize.width, $rootScope.wndSize.height);
        }
    }

    var resizeWndCb = [];

    webix.require.disabled = true;
    webix.codebase = "/mctools/codemirror/";

    // ============================================================

    window.idMcPingTimer = null;

    var pingOptions =  {
        onError : null,
        onStop  : null,
        onWarn  : null
    };

    function StartPingTimer(_time, opt){
        pingOptions = opt;

        if (mcConst.SessionID) {
            window.idMcPingTimer = setInterval(function(){
                if (mcConst.SessionID) {
                    $rootScope.SendCMDToServer([mcConst._CMD_.Ping, mcConst.SessionID]);
                } else {
                    console.error("mcConst.SessionID is not defined. StopPingTimer()");

                    StopPingTimer();
                }
            }, _time);
        }

        function RunCMD(CMD_Block, debug) {
            if (debug) {
                console.log("CMD_Block:\n" + CMD_Block);
            }

            if (CMD_Block && CMD_Block.length > 0){
                CMD_Block = mcService.StringToObj(CMD_Block);

                for (var CMD_Numb in CMD_Block){
                    $rootScope.ProcessCMD([CMD_Numb, CMD_Block[CMD_Numb]]);
                }
            }
        }

        mcConnect.ClearAllCallBackFunctionByCMD();
        mcConnect.LeaveCallBacks = true;

        mcConnect.SetCallBackFunctionByCMD(mcConst._CMD_.Ping, function(){
            var data = this;

            if ((data !== "{}") && (data.length > 0)) {
                RunCMD(data);
            }
        });

        mcConnect.OnError = function(err){
            if (console) {
                console.warn('An error occurred: Ping-Timer has been Stopped');
            }

            StopPingTimer();

            if (pingOptions.onError){
                pingOptions.onError(err);
            }
        };

        return window.idMcPingTimer;
    }

    function StopPingTimer(){
        if (window.idMcPingTimer !== null){
            clearInterval(window.idMcPingTimer);

            window.idMcPingTimer = null;

            mcConnect.ClearAllCallBackFunctionByCMD();

            if (pingOptions.onStop) {
                pingOptions.onStop();
            }
        }
    }

    // ============================================================

    function runCmd(cmd, args){
        if (mcService.isArray(args)){
            var cmdNumb = args.shift();

            if (mcCmdParser[cmd][cmdNumb]){
                mcCmdParser[cmd][cmdNumb].apply(null, args);
            } else {
                console.warn(mcService.myReplace(mcService.Lang(9), [cmd, cmdNumb])); // "10" : "%s: %s not found!"
            }
        } else {
            throw new Error(mcService.myReplace(mcService.Lang(8), [cmd])); // "8" : "%s: нет входящих аргументов"
        }
    }

    function initLockWindow(){
        // webix.ready(function(){
            if (lockWindow){
                lockWindow.destructor();
            }

            lockWindow = webix.ui({
                view     : "window",
                modal    : true,
                head     : mcService.Lang(72), // "72" : "Обработка запроса"
                position : "center",
                width    : 220,
                height   : mcConst.lockWindowHeight, // 65
                body     : {
                    template : "<div align='center'><img src='" + mcConst.imagesPath.loadingImg + "'></div>",
                    borderless: true
                }
            });
        // });
    }

    function displayError(txtCode, txt, txtParam, callback){
        $scope.errorMessagesIsShowed = true;

        var opt = txtParam === "nohelp"
            ? {
                type   : "alert",
                ok     : mcLang(12),  // "12" : "Закрыть",
                padding: 12,
                text   : mcService.myReplace(txt, [].concat(txtParam)),
                callback: function (){
                    $scope.errorMessagesIsShowed = false;
                }
            }
            : {
            title  : (txtCode === 'client') ? mcService.Lang(1386) : mcService.Lang(11, txtCode), // mcService.Lang(11, err.ErrNum), // "11" : "Ошибка №" "1386":"Ошибка",
            ok     : mcLang(1882),// "1882": "Помощь",
            cancel : mcLang(12),  // "12" : "Закрыть",
            type   : "alert-error",
            padding: 12,
            text   : mcService.myReplace(txt, [].concat(txtParam)),
            callback: function(res) {
                if (res){
                    if (txtCode === 'client') {
                        mcService.goToHelp("/serverhelp/", true);
                    } else {
                        var code = ['0','0','0','0'];
                        var cLen = txtCode.toString().length - 1;
                        var anchor = "";

                        for (var i = 3; i >= 0; i--){
                            if (cLen < 0) {
                                break;
                            }

                            code[i] = txtCode.toString()[cLen];
                            cLen --;
                        }

                        code = code.join('');

                        if (code == "0165"){
                            anchor = "#" + txtParam[0];
                        }

                        if (txtCode == mcConst._CMD_.Errors.Disconnected) {
                            mcService.goToHelp("https://nsoft-s.com/" + (mcConst.Lang === "ru" ? "" : (mcConst.Lang === "uk" ? "ua/" : "en/")) + "mcserverhelp/index.html?mychatclienterrors" + code + ".htm" + anchor, true);
                        } else {
                            mcService.goToHelp("/serverhelp/" + (mcConst.Lang === "uk" ? "/ua" : "/" + mcConst.Lang) + "/index.html?mychatclienterrors" + code + ".htm" + anchor, true);
                        }
                    }
                }

                if (callback){
                    callback();
                }

                var args = $scope.errorMessages.shift();

                if (args !== undefined){
                    setTimeout(function(){
                        displayError.apply(null, args);
                    }, 20);
                } else {
                    $scope.errorMessagesIsShowed = false;
                }
            }
        };

        webix[txtParam === "nohelp" ? "alert" : "confirm"](opt);
    }

    function sendCMD(args){
        if (args[0] === mcConst.lockInterface){
            args.shift();

            $scope.$emit(mcConst.lockInterface, []);
        }

        if (mcService.isFunction(args[args.length - 1])){
            if (!$rootScope.customCallBack[args[0]]){
                $rootScope.customCallBack[args[0]] = [];
            }

            $rootScope.customCallBack[args[0]].push(args.pop());
        }

        if (mcCmdParser.MultiSender.apply(null , args)){
            runCmd('SendCMDToServer', args);
        }
    }

    function receiveCMD(args) {
        if (mcCmdParser.MultiParser.apply(null, args)){
            runCmd('ProcessCMD', args);
        }
    }

    var lockWindow = null;
    var GOHELP     = "gohelp";

    // ========= Отправка клиентских логов (browser) на сервер ===========
    if (window.cLog){
        cLog(mcConst._CMD_.cLog, sendCMD, true);
    }
    // ===================================================================

    window.moment = moment || {};

    $scope.lockCount = 0;
    $scope.lockTimer = null;
    $scope.errorMessages = [];
    $scope.errorMessagesIsShowed = false;

    $rootScope.mcStorage = mcService.Marge({}, mcConst.dataModels);
    mcService.clearPlaneObj($rootScope.mcStorage);

    $rootScope.customCallBack   = {};
    $rootScope.showSpecificView = true;
    $rootScope.watchCallBack    = null;
    $rootScope.watchItem        = '';
    $rootScope.Purl             = purl();

    $rootScope.adminOptions    = {};

    $rootScope.SendCMDToServer = sendCMD;
    $rootScope.ProcessCMD      = receiveCMD;

    $rootScope.chatAliases = {
        Conf  : "ConfUserList",
        UIN   : "UIN",
        UID   : "UID",
        Forum : "Forum",
        Privat: "PrivateInfo",
        Kanban: "Kanban",
        BBS   : "BBS"
    };

    $rootScope.currentRootPath = 'navServerInfo';

    $http('first.login')
        .then(function(){
            $rootScope.firstLogin = true;
        })
        .catch(function () {})
    ;

    // =============================================================

    $rootScope.hotKeyDispatcher = new mcService.HotkeyManager();

    $rootScope.hotKeyDispatcher.addPreset(GOHELP, [{
        key    :  mcConst.keyCodes.f1,
        func   : function () {
            mcService.goToHelp();
        }
    }], document);

    // =============================================================

    $scope.$on('SendCMDToServer', function(e, args){
        sendCMD(args);
    });

    $scope.$on('ProcessCMD', function(e, args){
        receiveCMD(args);
    });

    $scope.$on('StartPingTimer', function(){
        mcConst.PingTimer = /*new mcCmdLoop*/StartPingTimer(mcConst.PingInterval, /*mcConst.SessionID,*/ {
            onError : function(){
                $scope.$emit('ErrorMsg', [mcConst._CMD_.Errors.Disconnected, mcService.Lang(14), '', function(){
                    if (mcConst.changeProtocol !== location.protocol ||
                        ($rootScope.mcStorage.SettingsNetwork && $rootScope.mcStorage.SettingsNetwork.WEBTCPPort && $rootScope.mcStorage.SettingsNetwork.WEBTCPPort != location.port)){

                        window.location.href = mcConst.changeProtocol + "//" + location.hostname + ":" + $rootScope.mcStorage.SettingsNetwork.WEBTCPPort +
                                        location.pathname + location.hash;
                    } else {
                        location.search = "";
                    }

                    mcService.reloadOrChangeProtocol();
                }]);
            }
        });
    });

    $scope.$on('StopPingTimer', function(){
        /*mcConst.PingTimer.*/StopPingTimer();
    });

    $scope.$on('ChangLanguage', function(e, args){
        var locale = args[0];
        var lang   = $location.param('lang') || args[1];

        setLocalizations();

        if (!mcService.inArrayB(lang, ['ua', 'ru', 'en', 'uk'])){
            lang = 'en';
        }

        if (lang.toLowerCase() === 'ua') {
            lang = 'uk';
        }

        moment.locale(lang);

        mcConst.Lang = lang;

        webix.Date.startOnMonday = mcConst.Lang !== 'en';

        $http(MC_RESOURCE.TextSource.errors.server + lang + '.errors.srv.json').success(function(txt){
            mcConst.SrvErrorText = mcService.isObject(txt) ? txt : JSON.parse(txt);                // серверные ошибки
        });

        $http(MC_RESOURCE.TextSource.mslHints + lang + '.pascalHints.json').success(function(txt){
            window.extraPascalHints = mcService.isObject(txt) ? txt : JSON.parse(txt);           // подсказки в автокомплите скриптов
        });

        $http(MC_RESOURCE.TextSource.errors.client + lang + '.errors.json').success(function(txt){
            mcConst.ErrorText = mcService.isObject(txt) ? txt : JSON.parse(txt);                   // клиентские ошибки
        });

        $http(MC_RESOURCE.TextSource.system + lang + '.system.json').success(function(txt){
            mcConst.LMSG_system = mcService.isObject(txt) ? txt : JSON.parse(txt);
            // mcConst.SYSLOG["0001"] = "%s &gt; %s: %s"; // серверные внутренние ошибки
        });

        $http(MC_RESOURCE.TextSource.presets).success(function(txt){
            mcConst.LogServerPresets = mcService.isObject(txt) ? txt : JSON.parse(txt);
        });

        $http(MC_RESOURCE.TextSource.languages + lang + '.languages.json').success(function(txt){
            mcConst.LanguagesList = mcService.isObject(txt) ? txt : JSON.parse(txt);               // список стран и языков
        });

        $http(MC_RESOURCE.TextSource.www.admin + lang + '.json').success(function(txt){
            mcConst.LMSG_admin = mcConst.LMSG = mcService.isObject(txt) ? txt : JSON.parse(txt);                        // локализация интерфейса

            $scope.$broadcast('show' + mcConst.dataModels.Login, [lang]);

            initLockWindow();

            webix.i18n.setLocale(lang);
        });
    });

    $scope.$on(mcConst.lockInterface, function(){
        if ($scope.lockCount === 0){
            $scope.lockTimer = setTimeout(function(){
                if (lockWindow) {
                    lockWindow.show();

                    mcService.getElementByClass('webix_modal')[0].className += ' noLockScreen';
                }
            }, 100);
        }

        $scope.lockCount ++;
    });

    $scope.$on('hide' + mcConst.lockInterface, function(){
        if ($scope.lockCount > 0) {
            $scope.lockCount --;
        }

        if ($scope.lockCount === 0 || !mcConst.PingTimer) {
            clearTimeout($scope.lockTimer);

            lockWindow.hide();
        }
    });

    $scope.$on('ErrorMsg', function(e, args){
        if ($scope.errorMessagesIsShowed){
            $scope.errorMessages.push(args);
        } else {
            displayError.apply(null, args);
        }
    });

    $rootScope.regShowWindow = function(id, link){
        $rootScope.$broadcast('addShowedWindow', [id, link]);
    };

    // =============================================================

    $scope.$emit('ChangLanguage', mcService.detectLang(mcService.StringToObj(window.localStorage.getItem('admLang'))));

    webix.event(window, "resize", function(){
        if (mcConst.scrResize && mcConst.isShowed !== '') mcConst.scrResize.adjust();
        if (mcConst.navResize) mcConst.navResize.adjust();
    });

    mcConst.LoginInfo = mcService.LoadSessionSettings();

    webix.editors.fastselect = webix.extend({
        render:function(){
            /*call original render*/
            var node = webix.editors.select.render.apply(this, arguments);

            /*attach custom handler*/
            webix.event(node.firstChild, "change", function(){
                /*cancel edit operaton on option selection*/
                webix.callEvent("onEditEnd",[this.value]);
            });

            return node;
        }
    }, webix.editors.select);

    webix.rules.isNotEmpty = function(val){
        return mcService.trim(val) != '';
    };

    window.onunload = function(){
        if (mcConst.LoggedIn) {
            sendCMD([
                mcConst._CMD_.cs_quit,
                mcConst.SessionID
            ]);
        }
    };

    webix.protoUI({
        name:"activeList"
    }, webix.ui.unitlist, webix.ActiveContent);

    webix.protoUI({
        name:"suggest",
        defaults:{
            filter:function(item,value){
                return item.value.toString().toLowerCase().indexOf(value.toLowerCase()) !== -1;
            }
        }
    }, webix.ui.suggest);

    webix.skin.compact.barHeight = 34;
    webix.skin.compact.tabbarHeight = 34;
    webix.skin.compact.rowHeight = 25;
    webix.skin.compact.listItemHeight = 27;
    webix.skin.compact.inputHeight = 28;
    webix.skin.compact.layoutMargin.wide = 5;
    webix.skin.compact.layoutMargin.space = 5;
    webix.skin.compact.layoutPadding.space = 5;
    //
    webix.skin.set('compact');

    setWindowSize();
}

function setLocalizations(){
    webix.i18n.parseFormat = '%d.%m.%Y';
    webix.i18n.locales["en"] = webix.i18n.locales["en-US"];

    webix.i18n.locales["ru"]={
        groupDelimiter:",",
        groupSize:3,
        decimalDelimeter:".",
        decimalSize:2,

        dateFormat:"%d.%m.%Y",
        timeFormat:"%h:%i %A",
        longDateFormat:"%d %F %Y",
        fullDateFormat:"%d/%m/%Y %h:%i %A",

        price:"${obj}",
        priceSettings:null, //use number defaults


        fileSize: ["b","Kb","Mb","Gb","Tb","Pb","Eb"],

        calendar: {
            monthFull  : ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь" ],
            monthShort : ["Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек" ],
            dayFull    : ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"],
            dayShort   : ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
            hours      : "Час",
            minutes    : "Минут",
            done       : "Готово",
            clear      : "Очистить",
            today      : "Сегодня"
        }
    };

    webix.i18n.locales["uk"]={
        groupDelimiter:",",
        groupSize:3,
        decimalDelimeter:".",
        decimalSize:2,

        dateFormat:"%d.%m.%Y",
        timeFormat:"%h:%i %A",
        longDateFormat:"%d %F %Y",
        fullDateFormat:"%d/%m/%Y %h:%i %A",

        price:"${obj}",
        priceSettings:null, //use number defaults


        fileSize: ["b","Kb","Mb","Gb","Tb","Pb","Eb"],

        calendar: {
            monthFull  : ["Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень" ],
            monthShort : ["Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру" ],
            dayFull    : ["Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота"],
            dayShort   : ["Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
            hours      : "Годинн",
            minutes    : "Хвилин",
            done       : "Готово",
            clear      : "Очистити",
            today      : "Сьогодні"
        }
    };
}

"use strict";

/** @namespace window.old_IE */
if (!window.old_IE){
    var units   = []
        .concat({ module: 'mcConnect',   args: ['$http', '$rootScope']})
        //.concat({ module: 'mcCmdLoop',   args: ['mcConnect', '$rootScope']})
        .concat({ module: 'mcCmdParser', args: ['mcConnect', '$rootScope']})
        .concat({ module: 'userQrCode',  args: ['$rootScope']})

        .concat({ module: 'loginController',           args: ['$scope', '$rootScope', '$location']})
        .concat({ module: 'mainController',            args: ['$scope', '$rootScope', 'mcCmdParser', /*'mcCmdLoop',*/ '$http', '$location', 'mcConnect']})
        .concat({ module: 'navController',             args: ['$scope', '$rootScope']})
        .concat({ module: 'applyPanelController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'serverInfoController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'onlineUsersController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'userProfileController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'userManagerController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'usersImportsController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'groupRightsController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'groupUsersController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'webSupportController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'mychatGuestController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'historyController',         args: ['$scope', '$rootScope']})
        .concat({ module: 'licenseMyChatController',   args: ['$scope', '$rootScope']})
        .concat({ module: 'licenseGuestController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'licenseClearController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'licenseQuizController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'contactsController',        args: ['$scope', '$rootScope']})
        .concat({ module: 'operatorsController',       args: ['$scope', '$rootScope']})
        .concat({ module: 'bansController',            args: ['$scope', '$rootScope']})
        .concat({ module: 'activeDirectoryController', args: ['$scope', '$rootScope']})
        .concat({ module: 'updatesController',         args: ['$scope', '$rootScope']})
        .concat({ module: 'userGroupsController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'nssServiceController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'supportForumController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'pluginAccessController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'botsController',            args: ['$scope', '$rootScope']})
        .concat({ module: 'totalClearController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'forumController',           args: ['$scope', '$rootScope']})
        .concat({ module: 'terminalController',        args: ['$scope', '$rootScope']})
        .concat({ module: 'personalGroupsController',  args: ['$scope', '$rootScope']})
        .concat({ module: 'custommenuController',      args: ['$scope', '$rootScope']})
        .concat({ module: 'testportController',        args: ['$scope', '$rootScope']})

        .concat({ module: 'settingsNetworkController', args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsInfoController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsLogsController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsFTPController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsWEBController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsWebCacheController',args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsBackupController',  args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsServiceController', args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsAPIController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsSMTPController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsGpsController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'adDomainsController',       args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsFoldersController', args: ['$scope', '$rootScope']})
        .concat({ module: 'settingsPluginsController', args: ['$scope', '$rootScope']})

        .concat({ module: 'othersController',          args: ['$scope', '$rootScope']})
        .concat({ module: 'autoChannelsController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'activeChannelsController',  args: ['$scope', '$rootScope']})
        .concat({ module: 'bbsController',             args: ['$scope', '$rootScope']})
        .concat({ module: 'workTimeController',        args: ['$scope', '$rootScope']})
        .concat({ module: 'mcScriptsController',       args: ['$scope', '$rootScope']})
        .concat({ module: 'rebootController',          args: ['$scope', '$rootScope']})
        .concat({ module: 'integrationsController',    args: ['$scope', '$rootScope']})
        .concat({ module: 'relocationController',      args: ['$scope', '$rootScope']})

        .concat({ module: 'filterAntifloodController', args: ['$scope', '$rootScope']})
        .concat({ module: 'filterBadWordsController',  args: ['$scope', '$rootScope']})
        .concat({ module: 'filterIPController',        args: ['$scope', '$rootScope']})
        .concat({ module: 'filterMACController',       args: ['$scope', '$rootScope']})
        .concat({ module: 'filterHardwareController',  args: ['$scope', '$rootScope']})
        .concat({ module: 'filterNamesController',     args: ['$scope', '$rootScope']})
        .concat({ module: 'remoteSettingsController',  args: ['$scope', '$rootScope']})
        .concat({ module: 'presetManagerController',   args: ['$scope', '$rootScope']})
        .concat({ module: 'workPositionsController',   args: ['$scope', '$rootScope']})
    ;

    window.mcService = servicesController('admin');
    window.mcLang    = mcService.Lang;
    window.adblock   = getElementByClass('ad-detect')[0].style.display === "none";

    mcComponents.units(units).start();
}

